X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Fcone%2Fcone.py;h=421fb3c8f04abb23fd420271ed10e0a7e65815d4;hb=f8e779ee533992a940e1014d00960fc58c3c4b79;hp=3f5a4fed4e1c49853f00eafcf6084744223ca296;hpb=3e6f51aa1f2d6f300cb22281701901add3631904;p=sage.d.git diff --git a/mjo/cone/cone.py b/mjo/cone/cone.py index 3f5a4fe..421fb3c 100644 --- a/mjo/cone/cone.py +++ b/mjo/cone/cone.py @@ -7,90 +7,56 @@ addsitedir(abspath('../../')) from sage.all import * -def rename_lattice(L,s): - r""" - Change all names of the given lattice to ``s``. - """ - L._name = s - L._dual_name = s - L._latex_name = s - L._latex_dual_name = s -def span_iso(K): +def project_span(K): r""" - Return an isomorphism (and its inverse) that will send ``K`` into a - lower-dimensional space isomorphic to its span (and back). + Project ``K`` into its own span. - EXAMPLES: + EXAMPLES:: - The inverse composed with the isomorphism should be the identity:: - - sage: K = random_cone(max_dim=10) - sage: (phi, phi_inv) = span_iso(K) - sage: phi_inv(phi(K)) == K + sage: K = Cone([(1,)]) + sage: project_span(K) == K True - The image of ``K`` under the isomorphism should have full dimension:: - - sage: K = random_cone(max_dim=10) - sage: (phi, phi_inv) = span_iso(K) - sage: phi(K).dim() == phi(K).lattice_dim() + sage: K2 = Cone([(1,0)]) + sage: project_span(K2).rays() + N(1) + in 1-d lattice N + sage: K3 = Cone([(1,0,0)]) + sage: project_span(K3).rays() + N(1) + in 1-d lattice N + sage: project_span(K2) == project_span(K3) True - The isomorphism should be an inner product space isomorphism, and - thus it should preserve dual cones (and commute with the "dual" - operation). But beware the automatic renaming of the dual lattice. - OH AND YOU HAVE TO SORT THE CONES:: + TESTS: + + The projected cone should always be solid:: - sage: K = random_cone(max_dim=10, strictly_convex=False, solid=True) - sage: L = K.lattice() - sage: rename_lattice(L, 'L') - sage: (phi, phi_inv) = span_iso(K) - sage: sorted(phi_inv( phi(K).dual() )) == sorted(K.dual()) + sage: K = random_cone(max_dim = 10) + sage: K_S = project_span(K) + sage: K_S.is_solid() True - We may need to isomorph twice to make sure we stop moving down to - smaller spaces. (Once you've done this on a cone and its dual, the - result should be proper.) OH AND YOU HAVE TO SORT THE CONES:: - - sage: K = random_cone(max_dim=10, strictly_convex=False, solid=False) - sage: L = K.lattice() - sage: rename_lattice(L, 'L') - sage: (phi, phi_inv) = span_iso(K) - sage: K_S = phi(K) - sage: (phi_dual, phi_dual_inv) = span_iso(K_S.dual()) - sage: J_T = phi_dual(K_S.dual()).dual() - sage: phi_inv(phi_dual_inv(J_T)) == K + If we do this according to our paper, then the result is proper:: + + sage: K = random_cone(max_dim = 10) + sage: K_S = project_span(K) + sage: P = project_span(K_S.dual()).dual() + sage: P.is_proper() True """ - phi_domain = K.sublattice().vector_space() - phi_codo = VectorSpace(phi_domain.base_field(), phi_domain.dimension()) - - # S goes from the new space to the cone space. - S = linear_transformation(phi_codo, phi_domain, phi_domain.basis()) - - # phi goes from the cone space to the new space. - def phi(J_orig): - r""" - Takes a cone ``J`` and sends it into the new space. - """ - newrays = map(S.inverse(), J_orig.rays()) - L = None - if len(newrays) == 0: - L = ToricLattice(0) - - return Cone(newrays, lattice=L) + L = K.lattice() + F = L.base_field() + Q = L.quotient(K.sublattice_complement()) + vecs = [ vector(F, reversed(list(Q(r)))) for r in K.rays() ] - def phi_inverse(J_sub): - r""" - The inverse to phi which goes from the new space to the cone space. - """ - newrays = map(S, J_sub.rays()) - return Cone(newrays, lattice=K.lattice()) + newL = None + if len(vecs) == 0: + newL = ToricLattice(0) - - return (phi, phi_inverse) + return Cone(vecs, lattice=newL) @@ -341,6 +307,15 @@ def lyapunov_rank(K): sage: lyapunov_rank(octant) 3 + The full space `\mathbb{R}^{n}` has Lyapunov rank `n^{2}` + [Orlitzky/Gowda]_:: + + sage: R5 = VectorSpace(QQ, 5) + sage: gens = R5.basis() + [ -r for r in R5.basis() ] + sage: K = Cone(gens) + sage: lyapunov_rank(K) + 25 + The `L^{3}_{1}` cone is known to have a Lyapunov rank of one [Rudolf et al.]_:: @@ -354,7 +329,30 @@ def lyapunov_rank(K): sage: lyapunov_rank(L3infty) 1 - The Lyapunov rank should be additive on a product of cones + A single ray in `n` dimensions should have Lyapunov rank `n^{2} - n + + 1` [Orlitzky/Gowda]_:: + + sage: K = Cone([(1,0,0,0,0)]) + sage: lyapunov_rank(K) + 21 + sage: K.lattice_dim()**2 - K.lattice_dim() + 1 + 21 + + A subspace (of dimension `m`) in `n` dimensions should have a + Lyapunov rank of `n^{2} - m\left(n - m)` [Orlitzky/Gowda]_:: + + sage: e1 = (1,0,0,0,0) + sage: neg_e1 = (-1,0,0,0,0) + sage: e2 = (0,1,0,0,0) + sage: neg_e2 = (0,-1,0,0,0) + sage: zero = (0,0,0,0,0) + sage: K = Cone([e1, neg_e1, e2, neg_e2, zero, zero, zero]) + sage: lyapunov_rank(K) + 19 + sage: K.lattice_dim()**2 - K.dim()*(K.lattice_dim() - K.dim()) + 19 + + The Lyapunov rank should be additive on a product of proper cones [Rudolf et al.]_:: sage: L31 = Cone([(1,0,1), (0,-1,1), (-1,0,1), (0,1,1)]) @@ -380,11 +378,11 @@ def lyapunov_rank(K): TESTS: - The Lyapunov rank should be additive on a product of cones + The Lyapunov rank should be additive on a product of proper cones [Rudolf et al.]_:: - sage: K1 = random_cone(max_dim=10, max_rays=10) - sage: K2 = random_cone(max_dim=10, max_rays=10) + sage: K1 = random_cone(max_dim=10, strictly_convex=True, solid=True) + sage: K2 = random_cone(max_dim=10, strictly_convex=True, solid=True) sage: K = K1.cartesian_product(K2) sage: lyapunov_rank(K) == lyapunov_rank(K1) + lyapunov_rank(K2) True @@ -422,19 +420,42 @@ def lyapunov_rank(K): The calculation of the Lyapunov rank of an improper cone can be reduced to that of a proper cone [Orlitzky/Gowda]_:: - sage: K = random_cone(max_dim=15, solid=False, strictly_convex=False) + sage: K = random_cone(max_dim=10) sage: actual = lyapunov_rank(K) - sage: (phi1, phi1_inv) = span_iso(K) - sage: K_S = phi1(K) - sage: (phi2, phi2_inv) = span_iso(K_S.dual()) - sage: J_T = phi2(K_S.dual()).dual() - sage: phi1_inv(phi2_inv(J_T)) == K - True + sage: K_S = project_span(K) + sage: P = project_span(K_S.dual()).dual() sage: l = K.linear_subspace().dimension() sage: codim = K.lattice_dim() - K.dim() - sage: expected = lyapunov_rank(J_T) + K.dim()*(l + codim) + codim**2 + sage: expected = lyapunov_rank(P) + K.dim()*(l + codim) + codim**2 sage: actual == expected True + The Lyapunov rank of a proper cone is just the dimension of ``LL(K)``:: + + sage: K = random_cone(max_dim=10, strictly_convex=True, solid=True) + sage: lyapunov_rank(K) == len(LL(K)) + True + """ - return len(LL(K)) + beta = 0 + + m = K.dim() + n = K.lattice_dim() + l = K.linear_subspace().dimension() + + if m < n: + # K is not solid, project onto its span. + K = project_span(K) + + # Lemma 2 + beta += m*(n - m) + (n - m)**2 + + if l > 0: + # K is not pointed, project its dual onto its span. + K = project_span(K.dual()).dual() + + # Lemma 3 + beta += m * l + + beta += len(LL(K)) + return beta