Catalog of common polyhedral convex cones¶
This module provides shortcut functions, grouped under the
globally-available cones
prefix, to create some common cones:
The downward-monotone cone,
The nonnegative orthant,
The rearrangement cone of order
p
,The Schur cone,
The trivial cone.
At the moment, only convex rational polyhedral cones are
supported—specifically, those cones that can be built using the
Cone()
constructor. As a result, each shortcut method can be
passed either an ambient dimension ambient_dim
, or a toric
lattice
(from which the dimension can be inferred) to determine
the ambient space.
Here are some typical usage examples:
sage: cones.downward_monotone(3).rays()
N( 1, 0, 0),
N( 1, 1, 0),
N( 1, 1, 1),
N(-1, -1, -1)
in 3-d lattice N
>>> from sage.all import *
>>> cones.downward_monotone(Integer(3)).rays()
N( 1, 0, 0),
N( 1, 1, 0),
N( 1, 1, 1),
N(-1, -1, -1)
in 3-d lattice N
cones.downward_monotone(3).rays()
sage: cones.nonnegative_orthant(2).rays()
N(1, 0),
N(0, 1)
in 2-d lattice N
>>> from sage.all import *
>>> cones.nonnegative_orthant(Integer(2)).rays()
N(1, 0),
N(0, 1)
in 2-d lattice N
cones.nonnegative_orthant(2).rays()
>>> from sage.all import *
>>> cones.nonnegative_orthant(Integer(2)).rays()
N(1, 0),
N(0, 1)
in 2-d lattice N
cones.nonnegative_orthant(2).rays()
sage: cones.rearrangement(2,2).rays()
N( 1, 0),
N( 1, -1),
N(-1, 1)
in 2-d lattice N
>>> from sage.all import *
>>> cones.rearrangement(Integer(2),Integer(2)).rays()
N( 1, 0),
N( 1, -1),
N(-1, 1)
in 2-d lattice N
cones.rearrangement(2,2).rays()
>>> from sage.all import *
>>> cones.rearrangement(Integer(2),Integer(2)).rays()
N( 1, 0),
N( 1, -1),
N(-1, 1)
in 2-d lattice N
cones.rearrangement(2,2).rays()
sage: cones.schur(3).rays()
N(1, -1, 0),
N(0, 1, -1)
in 3-d lattice N
>>> from sage.all import *
>>> cones.schur(Integer(3)).rays()
N(1, -1, 0),
N(0, 1, -1)
in 3-d lattice N
cones.schur(3).rays()
>>> from sage.all import *
>>> cones.schur(Integer(3)).rays()
N(1, -1, 0),
N(0, 1, -1)
in 3-d lattice N
cones.schur(3).rays()
sage: cones.trivial(3).rays()
Empty collection
in 3-d lattice N
>>> from sage.all import *
>>> cones.trivial(Integer(3)).rays()
Empty collection
in 3-d lattice N
cones.trivial(3).rays()
>>> from sage.all import *
>>> cones.trivial(Integer(3)).rays()
Empty collection
in 3-d lattice N
cones.trivial(3).rays()
To specify some other lattice, pass it as an argument to the function:
sage: K = cones.nonnegative_orthant(3)
sage: cones.schur(lattice=K.dual().lattice())
2-d cone in 3-d lattice M
>>> from sage.all import *
>>> K = cones.nonnegative_orthant(Integer(3))
>>> cones.schur(lattice=K.dual().lattice())
2-d cone in 3-d lattice M
K = cones.nonnegative_orthant(3) cones.schur(lattice=K.dual().lattice())
For more information about these cones, see the documentation for the individual functions and the references therein.
- sage.geometry.cone_catalog.downward_monotone(ambient_dim=None, lattice=None)[source]¶
The downward-monotone cone in
ambient_dim
dimensions, or living inlattice
.The elements of the downward-monotone cone are vectors whose components are arranged in non-increasing order. Vectors whose entries are arranged in the reverse (non-decreasing) order are sometimes called isotone vectors, and are used in statistics for isotonic regression.
The downward-monotone cone is the dual of the Schur cone. It is also often referred to as the downward-monotone cone.
INPUT:
ambient_dim
– nonnegative integer (default:None
); the dimension of the ambient spacelattice
– a toric lattice (default:None
); the lattice in which the cone will live
If
ambient_dim
is omitted, then it will be inferred from the rank oflattice
. If thelattice
is omitted, then the default lattice of rankambient_dim
will be used.A
ValueError
is raised if neitherambient_dim
norlattice
are specified. It is also aValueError
to specify bothambient_dim
andlattice
unless the rank oflattice
is equal toambient_dim
.OUTPUT:
A
ConvexRationalPolyhedralCone
living inlattice
whose elements’ entries are arranged in nonincreasing order. Each generating ray has the integer ring as its base ring.A
ValueError
can be raised if the inputs are incompatible or insufficient. See the INPUT documentation for details.See also
REFERENCES:
[GS2010], Section 3.1
[Niez1998], Example 2.2
EXAMPLES:
The entries of the elements of the downward-monotone cone are in non-increasing order:
sage: ambient_dim = ZZ.random_element(10) sage: K = cones.downward_monotone(ambient_dim) sage: all( x[i] >= x[i + 1] ....: for i in range(ambient_dim - 1) ....: for x in K.rays() ) True sage: x = K.random_element() sage: all( x[i] >= x[i + 1] for i in range(ambient_dim - 1) ) True
>>> from sage.all import * >>> ambient_dim = ZZ.random_element(Integer(10)) >>> K = cones.downward_monotone(ambient_dim) >>> all( x[i] >= x[i + Integer(1)] ... for i in range(ambient_dim - Integer(1)) ... for x in K.rays() ) True >>> x = K.random_element() >>> all( x[i] >= x[i + Integer(1)] for i in range(ambient_dim - Integer(1)) ) True
ambient_dim = ZZ.random_element(10) K = cones.downward_monotone(ambient_dim) all( x[i] >= x[i + 1] for i in range(ambient_dim - 1) for x in K.rays() ) x = K.random_element() all( x[i] >= x[i + 1] for i in range(ambient_dim - 1) )
A nontrivial downward-monotone cone is solid but not proper, since it contains both the vector of all ones and its negation; that, however, is the only subspace it contains:
sage: ambient_dim = ZZ.random_element(1,10) sage: K = cones.downward_monotone(ambient_dim) sage: K.is_solid() True sage: K.is_proper() False sage: K.lineality() 1
>>> from sage.all import * >>> ambient_dim = ZZ.random_element(Integer(1),Integer(10)) >>> K = cones.downward_monotone(ambient_dim) >>> K.is_solid() True >>> K.is_proper() False >>> K.lineality() 1
ambient_dim = ZZ.random_element(1,10) K = cones.downward_monotone(ambient_dim) K.is_solid() K.is_proper() K.lineality()
The dual of the downward-monotone cone is the Schur cone [GS2010] that induces the majorization preordering:
sage: ambient_dim = ZZ.random_element(10) sage: K = cones.downward_monotone(ambient_dim).dual() sage: J = cones.schur(ambient_dim, K.lattice()) sage: K.is_equivalent(J) True
>>> from sage.all import * >>> ambient_dim = ZZ.random_element(Integer(10)) >>> K = cones.downward_monotone(ambient_dim).dual() >>> J = cones.schur(ambient_dim, K.lattice()) >>> K.is_equivalent(J) True
ambient_dim = ZZ.random_element(10) K = cones.downward_monotone(ambient_dim).dual() J = cones.schur(ambient_dim, K.lattice()) K.is_equivalent(J)
- sage.geometry.cone_catalog.nonnegative_orthant(ambient_dim=None, lattice=None)[source]¶
The nonnegative orthant in
ambient_dim
dimensions, or living inlattice
.The nonnegative orthant consists of all componentwise-nonnegative vectors. It is the convex-conic hull of the standard basis.
INPUT:
ambient_dim
– nonnegative integer (default:None
); the dimension of the ambient spacelattice
– a toric lattice (default:None
); the lattice in which the cone will live
If
ambient_dim
is omitted, then it will be inferred from the rank oflattice
. If thelattice
is omitted, then the default lattice of rankambient_dim
will be used.A
ValueError
is raised if neitherambient_dim
norlattice
are specified. It is also aValueError
to specify bothambient_dim
andlattice
unless the rank oflattice
is equal toambient_dim
.OUTPUT:
A
ConvexRationalPolyhedralCone
living inlattice
and havingambient_dim
standard basis vectors as its generators. Each generating ray has the integer ring as its base ring.A
ValueError
can be raised if the inputs are incompatible or insufficient. See the INPUT documentation for details.REFERENCES:
Chapter 2 in [BV2009] (Examples 2.4, 2.14, and 2.23 in particular)
EXAMPLES:
sage: cones.nonnegative_orthant(3).rays() N(1, 0, 0), N(0, 1, 0), N(0, 0, 1) in 3-d lattice N
>>> from sage.all import * >>> cones.nonnegative_orthant(Integer(3)).rays() N(1, 0, 0), N(0, 1, 0), N(0, 0, 1) in 3-d lattice N
cones.nonnegative_orthant(3).rays()
- sage.geometry.cone_catalog.rearrangement(p, ambient_dim=None, lattice=None)[source]¶
The rearrangement cone of order
p
inambient_dim
dimensions, or living inlattice
.The rearrangement cone of order
p
inambient_dim
dimensions consists of all vectors of lengthambient_dim
whose smallestp
components sum to a nonnegative number.For example, the rearrangement cone of order one has its single smallest component nonnegative. This implies that all components are nonnegative, and that therefore the rearrangement cone of order one is the nonnegative orthant in its ambient space.
When
p
andambient_dim
are equal, all components of the cone’s elements must sum to a nonnegative number. In other words, the rearrangement cone of orderambient_dim
is a half-space.INPUT:
p
– nonnegative integer; the number of components to “rearrange”, between1
andambient_dim
inclusiveambient_dim
– nonnegative integer (default:None
); the dimension of the ambient spacelattice
– a toric lattice (default:None
); the lattice in which the cone will live
If
ambient_dim
is omitted, then it will be inferred from the rank oflattice
. If thelattice
is omitted, then the default lattice of rankambient_dim
will be used.A
ValueError
is raised if neitherambient_dim
norlattice
are specified. It is also aValueError
to specify bothambient_dim
andlattice
unless the rank oflattice
is equal toambient_dim
.It is also a
ValueError
to specify a non-integerp
.OUTPUT:
A
ConvexRationalPolyhedralCone
representing the rearrangement cone of orderp
living inlattice
, with ambient dimensionambient_dim
. Each generating ray has the integer ring as its base ring.A
ValueError
can be raised if the inputs are incompatible or insufficient. See the INPUT documentation for details.ALGORITHM:
Suppose that the ambient space is of dimension \(n\). The extreme directions of the rearrangement cone for \(1 \le p \le n-1\) are given by [Jeong2017] Theorem 5.2.3. When \(2 \le p \le n-2\) (that is, if we ignore \(p = 1\) and \(p = n-1\)), they consist of
the standard basis \(\left\{e_{1},e_{2},\ldots,e_{n}\right\}\) for the ambient space, and
the \(n\) vectors \(\left(1,1,\ldots,1\right)^{T} - pe_{i}\) for \(i = 1,2,\ldots,n\).
Special cases are then given for \(p = 1\) and \(p = n-1\) in the theorem. However in SageMath we don’t need conically-independent extreme directions. We only need a generating set, because the
Cone()
function will eliminate any redundant generators. And one can easily verify that the special-case extreme directions for \(p = 1\) and \(p = n-1\) are contained in the conic hull of the \(2n\) generators just described. The half space resulting from \(p = n\) is also covered by this set of generators, so for all valid \(p\) we simply take the conic hull of those \(2n\) vectors.REFERENCES:
[GJ2016], Section 4
[HS2010], Example 2.21
[Jeong2017], Section 5.2
EXAMPLES:
The rearrangement cones of order one are nonnegative orthants:
sage: orthant = cones.nonnegative_orthant(6) sage: cones.rearrangement(1,6).is_equivalent(orthant) True
>>> from sage.all import * >>> orthant = cones.nonnegative_orthant(Integer(6)) >>> cones.rearrangement(Integer(1),Integer(6)).is_equivalent(orthant) True
orthant = cones.nonnegative_orthant(6) cones.rearrangement(1,6).is_equivalent(orthant)
When
p
andambient_dim
are equal, the rearrangement cone is a half-space, so we expect its lineality to be one less thanambient_dim
because it will contain a hyperplane but is not the entire space:sage: cones.rearrangement(5,5).lineality() 4
>>> from sage.all import * >>> cones.rearrangement(Integer(5),Integer(5)).lineality() 4
cones.rearrangement(5,5).lineality()
Jeong’s Proposition 5.2.1 [Jeong2017] states that all rearrangement cones are proper when
p
is less thanambient_dim
:sage: all( cones.rearrangement(p, ambient_dim).is_proper() ....: for ambient_dim in range(10) ....: for p in range(1, ambient_dim) ) True
>>> from sage.all import * >>> all( cones.rearrangement(p, ambient_dim).is_proper() ... for ambient_dim in range(Integer(10)) ... for p in range(Integer(1), ambient_dim) ) True
all( cones.rearrangement(p, ambient_dim).is_proper() for ambient_dim in range(10) for p in range(1, ambient_dim) )
Jeong’s Corollary 5.2.4 [Jeong2017] states that if \(p = n-1\) in an \(n\)-dimensional ambient space, then the Lyapunov rank of the rearrangement cone is \(n\), and that for all other \(p > 1\) its Lyapunov rank is one:
sage: all( cones.rearrangement(p, ambient_dim).lyapunov_rank() ....: == ....: ambient_dim ....: for ambient_dim in range(2, 10) ....: for p in [ ambient_dim-1 ] ) True sage: all( cones.rearrangement(p, ambient_dim).lyapunov_rank() == 1 ....: for ambient_dim in range(3, 10) ....: for p in range(2, ambient_dim-1) ) True
>>> from sage.all import * >>> all( cones.rearrangement(p, ambient_dim).lyapunov_rank() ... == ... ambient_dim ... for ambient_dim in range(Integer(2), Integer(10)) ... for p in [ ambient_dim-Integer(1) ] ) True >>> all( cones.rearrangement(p, ambient_dim).lyapunov_rank() == Integer(1) ... for ambient_dim in range(Integer(3), Integer(10)) ... for p in range(Integer(2), ambient_dim-Integer(1)) ) True
all( cones.rearrangement(p, ambient_dim).lyapunov_rank() == ambient_dim for ambient_dim in range(2, 10) for p in [ ambient_dim-1 ] ) all( cones.rearrangement(p, ambient_dim).lyapunov_rank() == 1 for ambient_dim in range(3, 10) for p in range(2, ambient_dim-1) )
- sage.geometry.cone_catalog.schur(ambient_dim=None, lattice=None)[source]¶
The Schur cone in
ambient_dim
dimensions, or living inlattice
.The Schur cone in \(n\) dimensions induces the majorization preordering on the ambient space. If \(\left\{e_{1}, e_{2}, \ldots, e_{n}\right\}\) is the standard basis for the space, then its generators are \(\left\{e_{i} - e_{i+1}\ |\ 1 \le i \le n-1\right\}\). Its dual is the downward monotone cone.
INPUT:
ambient_dim
– nonnegative integer (default:None
); the dimension of the ambient spacelattice
– a toric lattice (default:None
); the lattice in which the cone will live
If
ambient_dim
is omitted, then it will be inferred from the rank oflattice
. If thelattice
is omitted, then the default lattice of rankambient_dim
will be used.A
ValueError
is raised if neitherambient_dim
norlattice
are specified. It is also aValueError
to specify bothambient_dim
andlattice
unless the rank oflattice
is equal toambient_dim
.OUTPUT:
A
ConvexRationalPolyhedralCone
representing the Schur cone living inlattice
, with ambient dimensionambient_dim
. Each generating ray has the integer ring as its base ring.A
ValueError
can be raised if the inputs are incompatible or insufficient. See the INPUT documentation for details.See also
REFERENCES:
EXAMPLES:
Verify the claim [SS2016] that the maximal angle between any two generators of the Schur cone and the nonnegative orthant in dimension five is \(\left(3/4\right)\pi\):
sage: # needs sage.rings.number_fields sage: P = cones.schur(5) sage: Q = cones.nonnegative_orthant(5) sage: G = ( g.change_ring(QQbar).normalized() for g in P ) sage: H = ( h.change_ring(QQbar).normalized() for h in Q ) sage: actual = max(arccos(u.inner_product(v)) for u in G for v in H) sage: expected = 3*pi/4 sage: abs(actual - expected).n() < 1e-12 True
>>> from sage.all import * >>> # needs sage.rings.number_fields >>> P = cones.schur(Integer(5)) >>> Q = cones.nonnegative_orthant(Integer(5)) >>> G = ( g.change_ring(QQbar).normalized() for g in P ) >>> H = ( h.change_ring(QQbar).normalized() for h in Q ) >>> actual = max(arccos(u.inner_product(v)) for u in G for v in H) >>> expected = Integer(3)*pi/Integer(4) >>> abs(actual - expected).n() < RealNumber('1e-12') True
# needs sage.rings.number_fields P = cones.schur(5) Q = cones.nonnegative_orthant(5) G = ( g.change_ring(QQbar).normalized() for g in P ) H = ( h.change_ring(QQbar).normalized() for h in Q ) actual = max(arccos(u.inner_product(v)) for u in G for v in H) expected = 3*pi/4 abs(actual - expected).n() < 1e-12
The dual of the Schur cone is the downward-monotone cone [GS2010], whose elements’ entries are in non-increasing order:
sage: ambient_dim = ZZ.random_element(10) sage: K = cones.schur(ambient_dim).dual() sage: J = cones.downward_monotone(ambient_dim, K.lattice()) sage: K.is_equivalent(J) True
>>> from sage.all import * >>> ambient_dim = ZZ.random_element(Integer(10)) >>> K = cones.schur(ambient_dim).dual() >>> J = cones.downward_monotone(ambient_dim, K.lattice()) >>> K.is_equivalent(J) True
ambient_dim = ZZ.random_element(10) K = cones.schur(ambient_dim).dual() J = cones.downward_monotone(ambient_dim, K.lattice()) K.is_equivalent(J)
- sage.geometry.cone_catalog.trivial(ambient_dim=None, lattice=None)[source]¶
The trivial cone with no nonzero generators in
ambient_dim
dimensions, or living inlattice
.INPUT:
ambient_dim
– nonnegative integer (default:None
); the dimension of the ambient spacelattice
– a toric lattice (default:None
); the lattice in which the cone will live
If
ambient_dim
is omitted, then it will be inferred from the rank oflattice
. If thelattice
is omitted, then the default lattice of rankambient_dim
will be used.A
ValueError
is raised if neitherambient_dim
norlattice
are specified. It is also aValueError
to specify bothambient_dim
andlattice
unless the rank oflattice
is equal toambient_dim
.OUTPUT:
A
ConvexRationalPolyhedralCone
representing the trivial cone with no nonzero generators living inlattice
, with ambient dimensionambient_dim
.A
ValueError
can be raised if the inputs are incompatible or insufficient. See the INPUT documentation for details.EXAMPLES:
Construct the trivial cone, containing only the origin, in three dimensions:
sage: cones.trivial(3) 0-d cone in 3-d lattice N
>>> from sage.all import * >>> cones.trivial(Integer(3)) 0-d cone in 3-d lattice N
cones.trivial(3)
If a
lattice
is given, the trivial cone will live in that lattice:sage: L = ToricLattice(3, 'M') sage: cones.trivial(3, lattice=L) 0-d cone in 3-d lattice M
>>> from sage.all import * >>> L = ToricLattice(Integer(3), 'M') >>> cones.trivial(Integer(3), lattice=L) 0-d cone in 3-d lattice M
L = ToricLattice(3, 'M') cones.trivial(3, lattice=L)