from sage.all import * def is_lyapunov_like(L,K): r""" Determine whether or not ``L`` is Lyapunov-like on ``K``. We say that ``L`` is Lyapunov-like on ``K`` if `\left\langle L\left\lparenx\right\rparen,s\right\rangle = 0` for all pairs `\left\langle x,s \right\rangle` in the complementarity set of ``K``. It is known [Orlitzky]_ that this property need only be checked for generators of ``K`` and its dual. There are faster ways of checking this property. For example, we could compute a `lyapunov_like_basis` of the cone, and then test whether or not the given matrix is contained in the span of that basis. The value of this function is that it works on symbolic matrices. INPUT: - ``L`` -- A linear transformation or matrix. - ``K`` -- A polyhedral closed convex cone. OUTPUT: ``True`` if it can be proven that ``L`` is Lyapunov-like on ``K``, and ``False`` otherwise. .. WARNING:: If this function returns ``True``, then ``L`` is Lyapunov-like on ``K``. However, if ``False`` is returned, that could mean one of two things. The first is that ``L`` is definitely not Lyapunov-like on ``K``. The second is more of an "I don't know" answer, returned (for example) if we cannot prove that an inner product is zero. REFERENCES: M. Orlitzky. The Lyapunov rank of an improper cone. http://www.optimization-online.org/DB_HTML/2015/10/5135.html EXAMPLES: 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: 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: R = K.lattice().vector_space().base_ring() sage: L = zero_matrix(R, K.lattice_dim()) sage: is_lyapunov_like(L,K) True 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: all([ is_lyapunov_like(L,K) for L in K.lyapunov_like_basis() ]) True """ return all([(L*x).inner_product(s) == 0 for (x,s) in K.discrete_complementarity_set()]) def LL_cone(K): gens = K.lyapunov_like_basis() L = ToricLattice(K.lattice_dim()**2) return Cone([ g.list() for g in gens ], lattice=L, check=False) def Sigma_cone(K): gens = K.cross_positive_operator_gens() L = ToricLattice(K.lattice_dim()**2) return Cone([ g.list() for g in gens ], lattice=L, check=False) def Z_cone(K): gens = K.Z_operator_gens() L = ToricLattice(K.lattice_dim()**2) return Cone([ g.list() for g in gens ], lattice=L, check=False) def pi_cone(K1, K2=None): if K2 is None: K2 = K1 gens = K1.positive_operator_gens(K2) L = ToricLattice(K1.lattice_dim()*K2.lattice_dim()) return Cone([ g.list() for g in gens ], lattice=L, check=False)