X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=mjo%2Fcone%2Fcone.py;h=a5f5f2f4fcf1ac603a9d8d48a75a0924003bd8cf;hb=cd746d047748a9aa56c51bb78c3db9882ea16a16;hp=f78c27e7e8ba748274b968601fff61c4701a98c1;hpb=5b7044f0fad38851282ffdc07b55b98c11b7f78e;p=sage.d.git diff --git a/mjo/cone/cone.py b/mjo/cone/cone.py index f78c27e..a5f5f2f 100644 --- a/mjo/cone/cone.py +++ b/mjo/cone/cone.py @@ -40,14 +40,14 @@ def is_lyapunov_like(L,K): The identity is always Lyapunov-like in a nontrivial space:: sage: set_random_seed() - sage: K = random_cone(min_ambient_dim = 1, max_ambient_dim = 8) + sage: K = random_cone(min_ambient_dim=1, max_ambient_dim=8) sage: L = identity_matrix(K.lattice_dim()) sage: is_lyapunov_like(L,K) True As is the "zero" transformation:: - sage: K = random_cone(min_ambient_dim = 1, max_ambient_dim = 8) + sage: K = random_cone(min_ambient_dim=1, max_ambient_dim=8) sage: R = K.lattice().vector_space().base_ring() sage: L = zero_matrix(R, K.lattice_dim()) sage: is_lyapunov_like(L,K) @@ -56,7 +56,7 @@ def is_lyapunov_like(L,K): Everything in ``K.lyapunov_like_basis()`` should be Lyapunov-like on ``K``:: - sage: K = random_cone(min_ambient_dim = 1, max_ambient_dim = 6) + sage: K = random_cone(min_ambient_dim=1, max_ambient_dim=6) sage: all([ is_lyapunov_like(L,K) for L in K.lyapunov_like_basis() ]) True @@ -99,27 +99,46 @@ def random_element(K): sage: random_element(K) (0, 0, 0) + A random element of the nonnegative orthant should have all + components nonnegative:: + + sage: set_random_seed() + sage: K = Cone([(1,0,0),(0,1,0),(0,0,1)]) + sage: all([ x >= 0 for x in random_element(K) ]) + True + TESTS: - Any cone should contain an element of itself:: + Any cone should contain a random element of itself:: sage: set_random_seed() - sage: K = random_cone(max_rays = 8) + sage: K = random_cone(max_ambient_dim=8) sage: K.contains(random_element(K)) True + A strictly convex cone contains no lines, and thus no negative + multiples of any of its elements besides zero:: + + sage: set_random_seed() + sage: K = random_cone(max_ambient_dim=8, strictly_convex=True) + sage: x = random_element(K) + sage: x.is_zero() or not K.contains(-x) + True + + The sum of random elements of a cone lies in the cone:: + + sage: set_random_seed() + sage: K = random_cone(max_ambient_dim=8) + sage: K.contains(sum([random_element(K) for i in range(10)])) + True + """ V = K.lattice().vector_space() - F = V.base_ring() - coefficients = [ F.random_element().abs() for i in range(K.nrays()) ] - vector_gens = map(V, K.rays()) - scaled_gens = [ coefficients[i]*vector_gens[i] - for i in range(len(vector_gens)) ] + scaled_gens = [ V.base_field().random_element().abs()*V(r) for r in K ] # Make sure we return a vector. Without the coercion, we might # return ``0`` when ``K`` has no rays. - v = V(sum(scaled_gens)) - return v + return V(sum(scaled_gens)) def positive_operator_gens(K): @@ -176,7 +195,8 @@ def positive_operator_gens(K): A positive operator on a cone should send its generators into the cone:: - sage: K = random_cone(max_ambient_dim = 6) + sage: set_random_seed() + sage: K = random_cone(max_ambient_dim=5) sage: pi_of_K = positive_operator_gens(K) sage: all([K.contains(p*x) for p in pi_of_K for x in K.rays()]) True @@ -184,16 +204,41 @@ def positive_operator_gens(K): The dimension of the cone of positive operators is given by the corollary in my paper:: - sage: K = random_cone(max_ambient_dim = 6) + sage: set_random_seed() + sage: K = random_cone(max_ambient_dim=5) sage: n = K.lattice_dim() sage: m = K.dim() sage: l = K.lineality() sage: pi_of_K = positive_operator_gens(K) - sage: actual = Cone([p.list() for p in pi_of_K]).dim() - sage: expected = n**2 - l*(n - l) - (n - m)*m + sage: L = ToricLattice(n**2) + sage: actual = Cone([p.list() for p in pi_of_K], lattice=L).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:: + + sage: set_random_seed() + sage: K = random_cone(max_ambient_dim=5) + 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: 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:: + + sage: set_random_seed() + sage: K = random_cone(max_ambient_dim=5) + 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: K.is_proper() == pi_cone.is_proper() + True """ # Matrices are not vectors in Sage, so we have to convert them # to vectors explicitly before we can find a basis. We need these @@ -270,7 +315,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=6) 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 @@ -280,12 +325,33 @@ 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: 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: 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: 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.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: 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_star.linear_subspace() == z_star.linear_subspace() + True """ # Matrices are not vectors in Sage, so we have to convert them # to vectors explicitly before we can find a basis. We need these @@ -314,3 +380,18 @@ def Z_transformation_gens(K): # not cross-positive ones. M = MatrixSpace(F, n) return [ -M(v.list()) for v in Sigma_cone.rays() ] + + +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) + +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)