X-Git-Url: https://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Fcone%2Fcone.py;h=adba809cf26722f52b0ec75432b2e6068683c3d9;hb=a9af5fd329a524faba3071c52fcc52122e8cf631;hp=d62ffa22a70151ba2044b5e52c136604805e1d82;hpb=f7c24573f7cb25b1af2ff589a945d74f3554758c;p=sage.d.git diff --git a/mjo/cone/cone.py b/mjo/cone/cone.py index d62ffa2..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,19 +354,25 @@ 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 @@ -363,11 +380,14 @@ def positive_operator_gens(K): description of its generators:: 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: 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: 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 @@ -381,7 +401,10 @@ 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).lineality() + 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() @@ -393,7 +416,8 @@ def positive_operator_gens(K): 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]).lineality() + sage: pi_cone = Cone([p.list() for p in pi_of_K], check=False) + sage: actual = pi_cone.lineality() sage: actual == 2 True @@ -401,10 +425,12 @@ def positive_operator_gens(K): 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 """ @@ -420,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): @@ -484,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 @@ -494,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 """ @@ -537,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() @@ -549,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)