X-Git-Url: https://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Fcone%2Fcone.py;h=adba809cf26722f52b0ec75432b2e6068683c3d9;hb=a9af5fd329a524faba3071c52fcc52122e8cf631;hp=332d4b24ed93ce9daac2a5779df94068d6479838;hpb=75d8908c2da5a64ab289dcdfbc03e72d7878f58d;p=sage.d.git diff --git a/mjo/cone/cone.py b/mjo/cone/cone.py index 332d4b2..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,38 +331,106 @@ 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 - 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 dimensions:: + + 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.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: 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], check=False).dim() + sage: actual == 3 + True + + 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) + 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 - The cone ``K`` is proper if and only if the cone of positive - operators on ``K`` is proper:: + The trivial cone, full space, and half-plane all give rise to the + expected linealities:: + + 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: actual = Cone([p.list() for p in pi_of_K], lattice=L).lineality() + 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 + + 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 """ @@ -370,16 +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.. - 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): @@ -433,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 @@ -443,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 """ @@ -486,9 +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.. - 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() @@ -497,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)