- sage: set_random_seed()
- sage: K = random_cone(max_ambient_dim=4)
- sage: L = ToricLattice(K.lattice_dim()**2)
- sage: p = SymmetricGroup(K.lattice_dim()).random_element().matrix()
- sage: pK = Cone([ p*k for k in K ], K.lattice(), check=False)
- sage: pi_of_pK = positive_operator_gens(pK)
- sage: actual = Cone([t.list() for t in pi_of_pK],
- ....: lattice=L,
- ....: check=False)
- sage: pi_of_K = positive_operator_gens(K)
- sage: expected = Cone([(p*t*p.inverse()).list() for t in pi_of_K],
- ....: lattice=L,
- ....: check=False)
- sage: actual.is_equivalent(expected)
- 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
- # two values to construct the appropriate "long vector" space.
- F = K.lattice().base_field()
- n = K.lattice_dim()
-
- tensor_products = [ s.tensor_product(x) for x in K for s in K.dual() ]
-
- # Convert those tensor products to long vectors.
- W = VectorSpace(F, n**2)
- vectors = [ W(tp.list()) for tp in tensor_products ]
-
- 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 ]
-
-
-def Z_transformation_gens(K):
- r"""
- Compute generators of the cone of Z-transformations on this cone.