]> gitweb.michael.orlitzky.com - sage.d.git/blobdiff - mjo/cone/cone.py
Remove lyapunov_rank() for inclusion in Sage.
[sage.d.git] / mjo / cone / cone.py
index 5f058ca9a8c055f972ffffaa216975517e0dc723..32e13861fdbb0cb2f806f5892cd9c90c1df051f4 100644 (file)
@@ -7,372 +7,6 @@ addsitedir(abspath('../../'))
 
 from sage.all import *
 
-
-def _restrict_to_space(K, W):
-    r"""
-    Restrict this cone a subspace of its ambient space.
-
-    INPUT:
-
-    - ``W`` -- The subspace into which this cone will be restricted.
-
-    OUTPUT:
-
-    A new cone in a sublattice corresponding to ``W``.
-
-    EXAMPLES:
-
-    When this cone is solid, restricting it into its own span should do
-    nothing::
-
-        sage: K = Cone([(1,)])
-        sage: _restrict_to_space(K, K.span()) == K
-        True
-
-    A single ray restricted into its own span gives the same output
-    regardless of the ambient space::
-
-        sage: K2 = Cone([(1,0)])
-        sage: K2_S = _restrict_to_space(K2, K2.span()).rays()
-        sage: K2_S
-        N(1)
-        in 1-d lattice N
-        sage: K3 = Cone([(1,0,0)])
-        sage: K3_S = _restrict_to_space(K3, K3.span()).rays()
-        sage: K3_S
-        N(1)
-        in 1-d lattice N
-        sage: K2_S == K3_S
-        True
-
-    TESTS:
-
-    The projected cone should always be solid::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim = 8)
-        sage: _restrict_to_space(K, K.span()).is_solid()
-        True
-
-    And the resulting cone should live in a space having the same
-    dimension as the space we restricted it to::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim = 8)
-        sage: K_P = _restrict_to_space(K, K.dual().span())
-        sage: K_P.lattice_dim() == K.dual().dim()
-        True
-
-    This function should not affect the dimension of a cone::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim = 8)
-        sage: K.dim() == _restrict_to_space(K,K.span()).dim()
-        True
-
-    Nor should it affect the lineality of a cone::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim = 8)
-        sage: K.lineality() == _restrict_to_space(K, K.span()).lineality()
-        True
-
-    No matter which space we restrict to, the lineality should not
-    increase::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim = 8)
-        sage: S = K.span(); P = K.dual().span()
-        sage: K.lineality() >= _restrict_to_space(K,S).lineality()
-        True
-        sage: K.lineality() >= _restrict_to_space(K,P).lineality()
-        True
-
-    If we do this according to our paper, then the result is proper::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim = 8)
-        sage: K_S = _restrict_to_space(K, K.span())
-        sage: K_SP = _restrict_to_space(K_S.dual(), K_S.dual().span()).dual()
-        sage: K_SP.is_proper()
-        True
-        sage: K_SP = _restrict_to_space(K_S, K_S.dual().span())
-        sage: K_SP.is_proper()
-        True
-
-    Test the proposition in our paper concerning the duals and
-    restrictions. Generate a random cone, then create a subcone of
-    it. The operation of dual-taking should then commute with
-    _restrict_to_space::
-
-        sage: set_random_seed()
-        sage: J = random_cone(max_ambient_dim = 8)
-        sage: K = Cone(random_sublist(J.rays(), 0.5), lattice=J.lattice())
-        sage: K_W_star = _restrict_to_space(K, J.span()).dual()
-        sage: K_star_W = _restrict_to_space(K.dual(), J.span())
-        sage: _basically_the_same(K_W_star, K_star_W)
-        True
-
-    """
-    # First we want to intersect ``K`` with ``W``. The easiest way to
-    # do this is via cone intersection, so we turn the subspace ``W``
-    # into a cone.
-    W_cone = Cone(W.basis() + [-b for b in W.basis()], lattice=K.lattice())
-    K = K.intersection(W_cone)
-
-    # We've already intersected K with the span of K2, so every
-    # generator of K should belong to W now.
-    K_W_rays = [ W.coordinate_vector(r) for r in K.rays() ]
-
-    L = ToricLattice(W.dimension())
-    return Cone(K_W_rays, lattice=L)
-
-
-def lyapunov_rank(K):
-    r"""
-    Compute the Lyapunov rank of this cone.
-
-    The Lyapunov rank of a cone is the dimension of the space of its
-    Lyapunov-like transformations -- that is, the length of a
-    :meth:`lyapunov_like_basis`. Equivalently, the Lyapunov rank is the
-    dimension of the Lie algebra of the automorphism group of the cone.
-
-    OUTPUT:
-
-    A nonnegative integer representing the Lyapunov rank of this cone.
-
-    If the ambient space is trivial, the Lyapunov rank will be zero.
-    Otherwise, if the dimension of the ambient vector space is `n`, then
-    the resulting Lyapunov rank will be between `1` and `n` inclusive. A
-    Lyapunov rank of `n-1` is not possible [Orlitzky]_.
-
-    ALGORITHM:
-
-    The codimension formula from the second reference is used. We find
-    all pairs `(x,s)` in the complementarity set of `K` such that `x`
-    and `s` are rays of our cone. It is known that these vectors are
-    sufficient to apply the codimension formula. Once we have all such
-    pairs, we "brute force" the codimension formula by finding all
-    linearly-independent `xs^{T}`.
-
-    REFERENCES:
-
-    .. [Gowda/Tao] M.S. Gowda and J. Tao. On the bilinearity rank of
-       a proper cone and Lyapunov-like transformations. Mathematical
-       Programming, 147 (2014) 155-170.
-
-    M. Orlitzky. The Lyapunov rank of an improper cone.
-    http://www.optimization-online.org/DB_HTML/2015/10/5135.html
-
-    G. Rudolf, N. Noyan, D. Papp, and F. Alizadeh, Bilinear
-    optimality constraints for the cone of positive polynomials,
-    Mathematical Programming, Series B, 129 (2011) 5-31.
-
-    EXAMPLES:
-
-    The nonnegative orthant in `\mathbb{R}^{n}` always has rank `n`
-    [Rudolf]_::
-
-        sage: positives = Cone([(1,)])
-        sage: lyapunov_rank(positives)
-        1
-        sage: quadrant = Cone([(1,0), (0,1)])
-        sage: lyapunov_rank(quadrant)
-        2
-       sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)])
-        sage: lyapunov_rank(octant)
-        3
-
-    The full space `\mathbb{R}^{n}` has Lyapunov rank `n^{2}`
-    [Orlitzky]_::
-
-        sage: R5 = VectorSpace(QQ, 5)
-        sage: gs = R5.basis() + [ -r for r in R5.basis() ]
-        sage: K = Cone(gs)
-        sage: lyapunov_rank(K)
-        25
-
-    The `L^{3}_{1}` cone is known to have a Lyapunov rank of one
-    [Rudolf]_::
-
-        sage: L31 = Cone([(1,0,1), (0,-1,1), (-1,0,1), (0,1,1)])
-        sage: lyapunov_rank(L31)
-        1
-
-    Likewise for the `L^{3}_{\infty}` cone [Rudolf]_::
-
-        sage: L3infty = Cone([(0,1,1), (1,0,1), (0,-1,1), (-1,0,1)])
-        sage: lyapunov_rank(L3infty)
-        1
-
-    A single ray in `n` dimensions should have Lyapunov rank `n^{2} - n
-    + 1` [Orlitzky]_::
-
-        sage: K = Cone([(1,0,0,0,0)])
-        sage: lyapunov_rank(K)
-        21
-        sage: K.lattice_dim()**2 - K.lattice_dim() + 1
-        21
-
-    A subspace (of dimension `m`) in `n` dimensions should have a
-    Lyapunov rank of `n^{2} - m\left(n - m)` [Orlitzky]_::
-
-        sage: e1 = (1,0,0,0,0)
-        sage: neg_e1 = (-1,0,0,0,0)
-        sage: e2 = (0,1,0,0,0)
-        sage: neg_e2 = (0,-1,0,0,0)
-        sage: z = (0,0,0,0,0)
-        sage: K = Cone([e1, neg_e1, e2, neg_e2, z, z, z])
-        sage: lyapunov_rank(K)
-        19
-        sage: K.lattice_dim()**2 - K.dim()*K.codim()
-        19
-
-    The Lyapunov rank should be additive on a product of proper cones
-    [Rudolf]_::
-
-        sage: L31 = Cone([(1,0,1), (0,-1,1), (-1,0,1), (0,1,1)])
-        sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)])
-        sage: K = L31.cartesian_product(octant)
-        sage: lyapunov_rank(K) == lyapunov_rank(L31) + lyapunov_rank(octant)
-        True
-
-    Two isomorphic cones should have the same Lyapunov rank [Rudolf]_.
-    The cone ``K`` in the following example is isomorphic to the nonnegative
-    octant in `\mathbb{R}^{3}`::
-
-        sage: K = Cone([(1,2,3), (-1,1,0), (1,0,6)])
-        sage: lyapunov_rank(K)
-        3
-
-    The dual cone `K^{*}` of ``K`` should have the same Lyapunov rank as ``K``
-    itself [Rudolf]_::
-
-        sage: K = Cone([(2,2,4), (-1,9,0), (2,0,6)])
-        sage: lyapunov_rank(K) == lyapunov_rank(K.dual())
-        True
-
-    TESTS:
-
-    The Lyapunov rank should be additive on a product of proper cones
-    [Rudolf]_::
-
-        sage: set_random_seed()
-        sage: K1 = random_cone(max_ambient_dim=8,
-        ....:                  strictly_convex=True,
-        ....:                  solid=True)
-        sage: K2 = random_cone(max_ambient_dim=8,
-        ....:                  strictly_convex=True,
-        ....:                  solid=True)
-        sage: K = K1.cartesian_product(K2)
-        sage: lyapunov_rank(K) == lyapunov_rank(K1) + lyapunov_rank(K2)
-        True
-
-    The Lyapunov rank is invariant under a linear isomorphism
-    [Orlitzky]_::
-
-        sage: K1 = random_cone(max_ambient_dim = 8)
-        sage: A = random_matrix(QQ, K1.lattice_dim(), algorithm='unimodular')
-        sage: K2 = Cone( [ A*r for r in K1.rays() ], lattice=K1.lattice())
-        sage: lyapunov_rank(K1) == lyapunov_rank(K2)
-        True
-
-    The dual cone `K^{*}` of ``K`` should have the same Lyapunov rank as ``K``
-    itself [Rudolf]_::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim=8)
-        sage: lyapunov_rank(K) == lyapunov_rank(K.dual())
-        True
-
-    The Lyapunov rank of a proper polyhedral cone in `n` dimensions can
-    be any number between `1` and `n` inclusive, excluding `n-1`
-    [Gowda/Tao]_. By accident, the `n-1` restriction will hold for the
-    trivial cone in a trivial space as well. However, in zero dimensions,
-    the Lyapunov rank of the trivial cone will be zero::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim=8,
-        ....:                 strictly_convex=True,
-        ....:                 solid=True)
-        sage: b = lyapunov_rank(K)
-        sage: n = K.lattice_dim()
-        sage: (n == 0 or 1 <= b) and b <= n
-        True
-        sage: b == n-1
-        False
-
-    In fact [Orlitzky]_, no closed convex polyhedral cone can have
-    Lyapunov rank `n-1` in `n` dimensions::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim=8)
-        sage: b = lyapunov_rank(K)
-        sage: n = K.lattice_dim()
-        sage: b == n-1
-        False
-
-    The calculation of the Lyapunov rank of an improper cone can be
-    reduced to that of a proper cone [Orlitzky]_::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim=8)
-        sage: actual = lyapunov_rank(K)
-        sage: K_S = _restrict_to_space(K, K.span())
-        sage: K_SP = _restrict_to_space(K_S.dual(), K_S.dual().span()).dual()
-        sage: l = K.lineality()
-        sage: c = K.codim()
-        sage: expected = lyapunov_rank(K_SP) + K.dim()*(l + c) + c**2
-        sage: actual == expected
-        True
-
-    The Lyapunov rank of a cone is the size of a :meth:`lyapunov_like_basis`::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim=8)
-        sage: lyapunov_rank(K) == len(K.lyapunov_like_basis())
-        True
-
-    We can make an imperfect cone perfect by adding a slack variable
-    (a Theorem in [Orlitzky]_)::
-
-        sage: set_random_seed()
-        sage: K = random_cone(max_ambient_dim=8,
-        ....:                 strictly_convex=True,
-        ....:                 solid=True)
-        sage: L = ToricLattice(K.lattice_dim() + 1)
-        sage: K = Cone([ r.list() + [0] for r in K.rays() ], lattice=L)
-        sage: lyapunov_rank(K) >= K.lattice_dim()
-        True
-
-    """
-    beta = 0 # running tally of the Lyapunov rank
-
-    m = K.dim()
-    n = K.lattice_dim()
-    l = K.lineality()
-
-    if m < n:
-        # K is not solid, restrict to its span.
-        K = _restrict_to_space(K, K.span())
-
-        # Non-solid reduction lemma.
-        beta += (n - m)*n
-
-    if l > 0:
-        # K is not pointed, restrict to the span of its dual. Uses a
-        # proposition from our paper, i.e. this is equivalent to K =
-        # _rho(K.dual()).dual().
-        K = _restrict_to_space(K, K.dual().span())
-
-        # Non-pointed reduction lemma.
-        beta += l * m
-
-    beta += len(K.lyapunov_like_basis())
-    return beta
-
-
-
 def is_lyapunov_like(L,K):
     r"""
     Determine whether or not ``L`` is Lyapunov-like on ``K``.