sage: S.lineality() == S.dim()
True
+ A strictly convex cone should be equal to its strictly convex component::
+
+ sage: set_random_seed()
+ sage: K = random_cone(max_ambient_dim=8, strictly_convex=True)
+ sage: (P,_) = motzkin_decomposition(K)
+ sage: K.is_equivalent(P)
+ True
+
The generators of the components are obtained from orthogonal
projections of the original generators [Stoer-Witzgall]_::
# The lines() method only returns one generator per line. For a true
# line, we also need a generator pointing in the opposite direction.
S_gens = [ direction*gen for direction in [1,-1] for gen in K.lines() ]
- S = Cone(S_gens, K.lattice())
+ S = Cone(S_gens, K.lattice(), check=False)
# Since ``S`` is a subspace, the rays of its dual generate its
# orthogonal complement.
- S_perp = Cone(S.dual(), K.lattice())
+ S_perp = Cone(S.dual(), K.lattice(), check=False)
P = K.intersection(S_perp)
return (P,S)
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: check=True is necessary even though it
- # makes Cone() take forever. For an example take
- # K = Cone([(1,0,0),(0,0,1),(0,0,-1)]).
- 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):
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: check=True is necessary
- # even though it makes Cone() take forever. For an example take
- # K = Cone([(1,0,0),(0,0,1),(0,0,-1)]).
- 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()
# 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):