X-Git-Url: https://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Fcone%2Fcone.py;h=adba809cf26722f52b0ec75432b2e6068683c3d9;hb=a9af5fd329a524faba3071c52fcc52122e8cf631;hp=43ec8f7f18f031bea3e159f2f434b72b4d05909b;hpb=75a1cc8b3affcc1ffcf4fa68572ede75873b9380;p=sage.d.git diff --git a/mjo/cone/cone.py b/mjo/cone/cone.py index 43ec8f7..adba809 100644 --- a/mjo/cone/cone.py +++ b/mjo/cone/cone.py @@ -246,7 +246,7 @@ def positive_operator_gens(K): cone into the cone:: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=5) + sage: K = random_cone(max_ambient_dim=4) sage: pi_of_K = positive_operator_gens(K) sage: all([ K.contains(P*x) for P in pi_of_K for x in K ]) True @@ -255,7 +255,7 @@ def positive_operator_gens(K): cone into the cone:: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=5) + sage: K = random_cone(max_ambient_dim=4) sage: pi_of_K = positive_operator_gens(K) sage: all([ K.contains(P*K.random_element(QQ)) for P in pi_of_K ]) True @@ -264,10 +264,12 @@ def positive_operator_gens(K): generators of the cone into the cone:: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=5) + sage: K = random_cone(max_ambient_dim=4) sage: pi_of_K = positive_operator_gens(K) sage: L = ToricLattice(K.lattice_dim()**2) - sage: pi_cone = Cone([ g.list() for g in pi_of_K ], lattice=L) + sage: pi_cone = Cone([ g.list() for g in pi_of_K ], + ....: lattice=L, + ....: check=False) sage: P = matrix(K.lattice_dim(), pi_cone.random_element(QQ).list()) sage: all([ K.contains(P*x) for x in K ]) True @@ -276,10 +278,12 @@ def positive_operator_gens(K): element of the cone into the cone:: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=5) + sage: K = random_cone(max_ambient_dim=4) sage: pi_of_K = positive_operator_gens(K) sage: L = ToricLattice(K.lattice_dim()**2) - sage: pi_cone = Cone([ g.list() for g in pi_of_K ], lattice=L) + sage: pi_cone = Cone([ g.list() for g in pi_of_K ], + ....: lattice=L, + ....: check=False) sage: P = matrix(K.lattice_dim(), pi_cone.random_element(QQ).list()) sage: K.contains(P*K.random_element(ring=QQ)) True @@ -288,10 +292,12 @@ def positive_operator_gens(K): can be computed from the lineality spaces of the cone and its dual:: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=5) + sage: K = random_cone(max_ambient_dim=4) sage: pi_of_K = positive_operator_gens(K) sage: L = ToricLattice(K.lattice_dim()**2) - sage: pi_cone = Cone([ g.list() for g in pi_of_K ], lattice=L) + sage: pi_cone = Cone([ g.list() for g in pi_of_K ], + ....: lattice=L, + ....: check=False) sage: actual = pi_cone.dual().linear_subspace() sage: U1 = [ vector((s.tensor_product(x)).list()) ....: for x in K.lines() @@ -307,13 +313,15 @@ def positive_operator_gens(K): is known from its lineality space:: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=5) + sage: K = random_cone(max_ambient_dim=4) sage: n = K.lattice_dim() sage: m = K.dim() sage: l = K.lineality() sage: pi_of_K = positive_operator_gens(K) sage: L = ToricLattice(n**2) - sage: pi_cone = Cone([p.list() for p in pi_of_K], lattice=L) + sage: pi_cone = Cone([p.list() for p in pi_of_K], + ....: lattice=L, + ....: check=False) sage: actual = pi_cone.dual().lineality() sage: expected = l*(m - l) + m*(n - m) sage: actual == expected @@ -323,13 +331,16 @@ def positive_operator_gens(K): corollary in my paper:: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=5) + sage: K = random_cone(max_ambient_dim=4) sage: n = K.lattice_dim() sage: m = K.dim() sage: l = K.lineality() sage: pi_of_K = positive_operator_gens(K) sage: L = ToricLattice(n**2) - sage: actual = Cone([p.list() for p in pi_of_K], lattice=L).dim() + sage: pi_cone = Cone([p.list() for p in pi_of_K], + ....: lattice=L, + ....: check=False) + sage: actual = pi_cone.dim() sage: expected = n**2 - l*(m - l) - (n - m)*m sage: actual == expected True @@ -343,55 +354,83 @@ def positive_operator_gens(K): True sage: L = ToricLattice(n^2) sage: pi_of_K = positive_operator_gens(K) - sage: actual = Cone([p.list() for p in pi_of_K], lattice=L).dim() + sage: pi_cone = Cone([p.list() for p in pi_of_K], + ....: lattice=L, + ....: check=False) + sage: actual = pi_cone.dim() sage: actual == n^2 True sage: K = K.dual() sage: K.is_full_space() True sage: pi_of_K = positive_operator_gens(K) - sage: actual = Cone([p.list() for p in pi_of_K], lattice=L).dim() + sage: pi_cone = Cone([p.list() for p in pi_of_K], + ....: lattice=L, + ....: check=False) + sage: actual = pi_cone.dim() sage: actual == n^2 True sage: K = Cone([(1,0),(0,1),(0,-1)]) sage: pi_of_K = positive_operator_gens(K) - sage: actual = Cone([p.list() for p in pi_of_K]).dim() + sage: actual = Cone([p.list() for p in pi_of_K], check=False).dim() sage: actual == 3 True - The cone of positive operators is solid when the original cone is proper:: + The lineality of the cone of positive operators follows from the + description of its generators:: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=5, - ....: strictly_convex=True, - ....: solid=True) + sage: K = random_cone(max_ambient_dim=4) + sage: n = K.lattice_dim() sage: pi_of_K = positive_operator_gens(K) - sage: L = ToricLattice(K.lattice_dim()**2) - sage: pi_cone = Cone([p.list() for p in pi_of_K], lattice=L) - sage: pi_cone.is_solid() + sage: L = ToricLattice(n**2) + sage: pi_cone = Cone([p.list() for p in pi_of_K], + ....: lattice=L, + ....: check=False) + sage: actual = pi_cone.lineality() + sage: expected = n**2 - K.dim()*K.dual().dim() + sage: actual == expected True - The lineality of the cone of positive operators is given by the - corollary in my paper:: + The trivial cone, full space, and half-plane all give rise to the + expected linealities:: - sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=5) - sage: n = K.lattice_dim() + sage: n = ZZ.random_element().abs() + sage: K = Cone([[0] * n], ToricLattice(n)) + sage: K.is_trivial() + True + sage: L = ToricLattice(n^2) + sage: pi_of_K = positive_operator_gens(K) + sage: pi_cone = Cone([p.list() for p in pi_of_K], + ....: lattice=L, + ....: check=False) + sage: actual = pi_cone.lineality() + sage: actual == n^2 + True + sage: K = K.dual() + sage: K.is_full_space() + True sage: pi_of_K = positive_operator_gens(K) - sage: L = ToricLattice(n**2) sage: actual = Cone([p.list() for p in pi_of_K], lattice=L).lineality() - sage: expected = n**2 - K.dim()*K.dual().dim() - sage: actual == expected + sage: actual == n^2 + True + sage: K = Cone([(1,0),(0,1),(0,-1)]) + sage: pi_of_K = positive_operator_gens(K) + sage: pi_cone = Cone([p.list() for p in pi_of_K], check=False) + sage: actual = pi_cone.lineality() + sage: actual == 2 True - The cone ``K`` is proper if and only if the cone of positive - operators on ``K`` is proper:: + A cone is proper if and only if its cone of positive operators + is proper:: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=5) + sage: K = random_cone(max_ambient_dim=4) sage: pi_of_K = positive_operator_gens(K) sage: L = ToricLattice(K.lattice_dim()**2) - sage: pi_cone = Cone([p.list() for p in pi_of_K], lattice=L) + sage: pi_cone = Cone([p.list() for p in pi_of_K], + ....: lattice=L, + ....: check=False) sage: K.is_proper() == pi_cone.is_proper() True """ @@ -407,17 +446,27 @@ def positive_operator_gens(K): W = VectorSpace(F, n**2) vectors = [ W(tp.list()) for tp in tensor_products ] - # Create the *dual* cone of the positive operators, expressed as - # long vectors. WARNING: takes forever unless we pass check=False - # to Cone(). - pi_dual = Cone(vectors, ToricLattice(W.dimension())) + check = True + if K.is_solid() or K.is_strictly_convex(): + # The lineality space of either ``K`` or ``K.dual()`` is + # trivial and it's easy to show that our generating set is + # minimal. I would love a proof that this works when ``K`` is + # neither pointed nor solid. + # + # Note that in that case we can get *duplicates*, since the + # tensor product of (x,s) is the same as that of (-x,-s). + check = False + + # Create the dual cone of the positive operators, expressed as + # long vectors. + pi_dual = Cone(vectors, ToricLattice(W.dimension()), check=check) # Now compute the desired cone from its dual... pi_cone = pi_dual.dual() # And finally convert its rays back to matrix representations. M = MatrixSpace(F, n) - return [ M(v.list()) for v in pi_cone.rays() ] + return [ M(v.list()) for v in pi_cone ] def Z_transformation_gens(K): @@ -471,7 +520,7 @@ def Z_transformation_gens(K): The Z-property is possessed by every Z-transformation:: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=6) + sage: K = random_cone(max_ambient_dim=4) sage: Z_of_K = Z_transformation_gens(K) sage: dcs = K.discrete_complementarity_set() sage: all([(z*x).inner_product(s) <= 0 for z in Z_of_K @@ -481,31 +530,43 @@ def Z_transformation_gens(K): The lineality space of Z is LL:: sage: set_random_seed() - sage: K = random_cone(min_ambient_dim=1, max_ambient_dim=6) - sage: lls = span([ vector(l.list()) for l in K.lyapunov_like_basis() ]) - sage: z_cone = Cone([ z.list() for z in Z_transformation_gens(K) ]) + sage: K = random_cone(max_ambient_dim=4) + sage: L = ToricLattice(K.lattice_dim()**2) + sage: z_cone = Cone([ z.list() for z in Z_transformation_gens(K) ], + ....: lattice=L, + ....: check=False) + sage: ll_basis = [ vector(l.list()) for l in K.lyapunov_like_basis() ] + sage: lls = L.vector_space().span(ll_basis) sage: z_cone.linear_subspace() == lls True And thus, the lineality of Z is the Lyapunov rank:: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=6) + sage: K = random_cone(max_ambient_dim=4) sage: Z_of_K = Z_transformation_gens(K) sage: L = ToricLattice(K.lattice_dim()**2) - sage: z_cone = Cone([ z.list() for z in Z_of_K ], lattice=L) + sage: z_cone = Cone([ z.list() for z in Z_of_K ], + ....: lattice=L, + ....: check=False) sage: z_cone.lineality() == K.lyapunov_rank() True The lineality spaces of pi-star and Z-star are equal: sage: set_random_seed() - sage: K = random_cone(max_ambient_dim=5) + sage: K = random_cone(max_ambient_dim=4) sage: pi_of_K = positive_operator_gens(K) sage: Z_of_K = Z_transformation_gens(K) sage: L = ToricLattice(K.lattice_dim()**2) - sage: pi_star = Cone([p.list() for p in pi_of_K], lattice=L).dual() - sage: z_star = Cone([ z.list() for z in Z_of_K], lattice=L).dual() + sage: pi_cone = Cone([p.list() for p in pi_of_K], + ....: lattice=L, + ....: check=False) + sage: pi_star = pi_cone.dual() + sage: z_cone = Cone([ z.list() for z in Z_of_K], + ....: lattice=L, + ....: check=False) + sage: z_star = z_cone.dual() sage: pi_star.linear_subspace() == z_star.linear_subspace() True """ @@ -524,10 +585,20 @@ def Z_transformation_gens(K): W = VectorSpace(F, n**2) vectors = [ W(m.list()) for m in tensor_products ] - # Create the *dual* cone of the cross-positive operators, - # expressed as long vectors. WARNING: takes forever unless we pass - # check=False to Cone(). - Sigma_dual = Cone(vectors, lattice=ToricLattice(W.dimension())) + check = True + if K.is_solid() or K.is_strictly_convex(): + # The lineality space of either ``K`` or ``K.dual()`` is + # trivial and it's easy to show that our generating set is + # minimal. I would love a proof that this works when ``K`` is + # neither pointed nor solid. + # + # Note that in that case we can get *duplicates*, since the + # tensor product of (x,s) is the same as that of (-x,-s). + check = False + + # Create the dual cone of the cross-positive operators, + # expressed as long vectors. + Sigma_dual = Cone(vectors, lattice=ToricLattice(W.dimension()), check=check) # Now compute the desired cone from its dual... Sigma_cone = Sigma_dual.dual() @@ -536,19 +607,15 @@ def Z_transformation_gens(K): # But first, make them negative, so we get Z-transformations and # not cross-positive ones. M = MatrixSpace(F, n) - return [ -M(v.list()) for v in Sigma_cone.rays() ] + return [ -M(v.list()) for v in Sigma_cone ] def Z_cone(K): gens = Z_transformation_gens(K) - L = None - if len(gens) == 0: - L = ToricLattice(0) - return Cone([ g.list() for g in gens ], lattice=L) + L = ToricLattice(K.lattice_dim()**2) + return Cone([ g.list() for g in gens ], lattice=L, check=False) def pi_cone(K): gens = positive_operator_gens(K) - L = None - if len(gens) == 0: - L = ToricLattice(0) - return Cone([ g.list() for g in gens ], lattice=L) + L = ToricLattice(K.lattice_dim()**2) + return Cone([ g.list() for g in gens ], lattice=L, check=False)