Convex rational polyhedral cones¶
This module was designed as a part of framework for toric varieties
(variety
,
fano_variety
). While the emphasis is on
strictly convex cones, non-strictly convex cones are supported as well. Work
with distinct lattices (in the sense of discrete subgroups spanning vector
spaces) is supported. The default lattice is ToricLattice
of the appropriate
dimension. The only case when you must specify lattice explicitly is creation
of a 0-dimensional cone, where dimension of the ambient space cannot be
guessed.
AUTHORS:
- Andrey Novoseltsev (2010-05-13): initial version.
- Andrey Novoseltsev (2010-06-17): substantial improvement during review by Volker Braun.
- Volker Braun (2010-06-21): various spanned/quotient/dual lattice computations added.
- Volker Braun (2010-12-28): Hilbert basis for cones.
- Andrey Novoseltsev (2012-02-23): switch to PointCollection container.
EXAMPLES:
Use Cone()
to construct cones:
sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)])
sage: halfspace = Cone([(1,0,0), (0,1,0), (-1,-1,0), (0,0,1)])
sage: positive_xy = Cone([(1,0,0), (0,1,0)])
sage: four_rays = Cone([(1,1,1), (1,-1,1), (-1,-1,1), (-1,1,1)])
For all of the cones above we have provided primitive generating rays, but in
fact this is not necessary - a cone can be constructed from any collection of
rays (from the same space, of course). If there are non-primitive (or even
non-integral) rays, they will be replaced with primitive ones. If there are
extra rays, they will be discarded. Of course, this means that Cone()
has to do some work before actually constructing the cone and sometimes it is
not desirable, if you know for sure that your input is already “good”. In this
case you can use options check=False
to force Cone()
to use
exactly the directions that you have specified and normalize=False
to
force it to use exactly the rays that you have specified. However, it is
better not to use these possibilities without necessity, since cones are
assumed to be represented by a minimal set of primitive generating rays.
See Cone()
for further documentation on construction.
Once you have a cone, you can perform numerous operations on it. The most important ones are, probably, ray accessing methods:
sage: rays = halfspace.rays()
sage: rays
N( 0, 0, 1),
N( 0, 1, 0),
N( 0, -1, 0),
N( 1, 0, 0),
N(-1, 0, 0)
in 3-d lattice N
sage: rays.set()
frozenset({N(-1, 0, 0), N(0, -1, 0), N(0, 0, 1), N(0, 1, 0), N(1, 0, 0)})
sage: rays.matrix()
[ 0 0 1]
[ 0 1 0]
[ 0 -1 0]
[ 1 0 0]
[-1 0 0]
sage: rays.column_matrix()
[ 0 0 0 1 -1]
[ 0 1 -1 0 0]
[ 1 0 0 0 0]
sage: rays(3)
N(1, 0, 0)
in 3-d lattice N
sage: rays[3]
N(1, 0, 0)
sage: halfspace.ray(3)
N(1, 0, 0)
The method rays()
returns a
PointCollection
with the
-th element being the primitive integral generator of the
-th
ray. It is possible to convert this collection to a matrix with either
rows or columns corresponding to these generators. You may also change
the default
output_format()
of all point collections to be such a matrix.
If you want to do something with each ray of a cone, you can write
sage: for ray in positive_xy: print ray
N(1, 0, 0)
N(0, 1, 0)
There are two dimensions associated to each cone - the dimension of the subspace spanned by the cone and the dimension of the space where it lives:
sage: positive_xy.dim()
2
sage: positive_xy.lattice_dim()
3
You also may be interested in this dimension:
sage: dim(positive_xy.linear_subspace())
0
sage: dim(halfspace.linear_subspace())
2
Or, perhaps, all you care about is whether it is zero or not:
sage: positive_xy.is_strictly_convex()
True
sage: halfspace.is_strictly_convex()
False
You can also perform these checks:
sage: positive_xy.is_simplicial()
True
sage: four_rays.is_simplicial()
False
sage: positive_xy.is_smooth()
True
You can work with subcones that form faces of other cones:
sage: face = four_rays.faces(dim=2)[0]
sage: face
2-d face of 3-d cone in 3-d lattice N
sage: face.rays()
N(-1, -1, 1),
N(-1, 1, 1)
in 3-d lattice N
sage: face.ambient_ray_indices()
(2, 3)
sage: four_rays.rays(face.ambient_ray_indices())
N(-1, -1, 1),
N(-1, 1, 1)
in 3-d lattice N
If you need to know inclusion relations between faces, you can use
sage: L = four_rays.face_lattice()
sage: map(len, L.level_sets())
[1, 4, 4, 1]
sage: face = L.level_sets()[2][0]
sage: face.rays()
N(1, 1, 1),
N(1, -1, 1)
in 3-d lattice N
sage: L.hasse_diagram().neighbors_in(face)
[1-d face of 3-d cone in 3-d lattice N,
1-d face of 3-d cone in 3-d lattice N]
Warning
The order of faces in level sets of
the face lattice may differ from the order of faces returned by
faces()
. While the first order is
random, the latter one ensures that one-dimensional faces are listed in
the same order as generating rays.
When all the functionality provided by cones is not enough, you may want to check if you can do necessary things using polyhedra corresponding to cones:
sage: four_rays.polyhedron()
A 3-dimensional polyhedron in ZZ^3 defined as
the convex hull of 1 vertex and 4 rays
And of course you are always welcome to suggest new features that should be added to cones!
REFERENCES:
[Fulton] | (1, 2, 3, 4, 5) Wiliam Fulton, “Introduction to Toric Varieties”, Princeton University Press |
-
sage.geometry.cone.
Cone
(rays, lattice=None, check=True, normalize=True)¶ Construct a (not necessarily strictly) convex rational polyhedral cone.
INPUT:
rays
– a list of rays. Each ray should be given as a list or a vector convertible to the rational extension of the givenlattice
. May also be specified by aPolyhedron_base
object;lattice
–ToricLattice
,, or any other object that behaves like these. If not specified, an attempt will be made to determine an appropriate toric lattice automatically;
check
– by default the input data will be checked for correctness (e.g. that all rays have the same number of components) and generating rays will be constructed fromrays
. If you know that the input is a minimal set of generators of a valid cone, you may significantly decrease construction time usingcheck=False
option;normalize
– you can further speed up construction usingnormalize=False
option. In this caserays
must be a list of immutable primitive rays inlattice
. In general, you should not use this option, it is designed for code optimization and does not give as drastic improvement in speed as the previous one.
OUTPUT:
- convex rational polyhedral cone determined by
rays
.
EXAMPLES:
Let’s define a cone corresponding to the first quadrant of the plane (note, you can even mix objects of different types to represent rays, as long as you let this function to perform all the checks and necessary conversions!):
sage: quadrant = Cone([(1,0), [0,1]]) sage: quadrant 2-d cone in 2-d lattice N sage: quadrant.rays() N(1, 0), N(0, 1) in 2-d lattice N
If you give more rays than necessary, the extra ones will be discarded:
sage: Cone([(1,0), (0,1), (1,1), (0,1)]).rays() N(0, 1), N(1, 0) in 2-d lattice N
However, this work is not done with
check=False
option, so use it carefully!sage: Cone([(1,0), (0,1), (1,1), (0,1)], check=False).rays() N(1, 0), N(0, 1), N(1, 1), N(0, 1) in 2-d lattice N
Even worse things can happen with
normalize=False
option:sage: Cone([(1,0), (0,1)], check=False, normalize=False) Traceback (most recent call last): ... AttributeError: 'tuple' object has no attribute 'parent'
You can construct different “not” cones: not full-dimensional, not strictly convex, not containing any rays:
sage: one_dimensional_cone = Cone([(1,0)]) sage: one_dimensional_cone.dim() 1 sage: half_plane = Cone([(1,0), (0,1), (-1,0)]) sage: half_plane.rays() N( 0, 1), N( 1, 0), N(-1, 0) in 2-d lattice N sage: half_plane.is_strictly_convex() False sage: origin = Cone([(0,0)]) sage: origin.rays() Empty collection in 2-d lattice N sage: origin.dim() 0 sage: origin.lattice_dim() 2
You may construct the cone above without giving any rays, but in this case you must provide
lattice
explicitly:sage: origin = Cone([]) Traceback (most recent call last): ... ValueError: lattice must be given explicitly if there are no rays! sage: origin = Cone([], lattice=ToricLattice(2)) sage: origin.dim() 0 sage: origin.lattice_dim() 2 sage: origin.lattice() 2-d lattice N
Of course, you can also provide
lattice
in other cases:sage: L = ToricLattice(3, "L") sage: c1 = Cone([(1,0,0),(1,1,1)], lattice=L) sage: c1.rays() L(1, 0, 0), L(1, 1, 1) in 3-d lattice L
Or you can construct cones from rays of a particular lattice:
sage: ray1 = L(1,0,0) sage: ray2 = L(1,1,1) sage: c2 = Cone([ray1, ray2]) sage: c2.rays() L(1, 0, 0), L(1, 1, 1) in 3-d lattice L sage: c1 == c2 True
When the cone in question is not strictly convex, the standard form for the “generating rays” of the linear subspace is “basis vectors and their negatives”, as in the following example:
sage: plane = Cone([(1,0), (0,1), (-1,-1)]) sage: plane.rays() N( 0, 1), N( 0, -1), N( 1, 0), N(-1, 0) in 2-d lattice N
The cone can also be specified by a
Polyhedron_base
:sage: p = plane.polyhedron() sage: Cone(p) 2-d cone in 2-d lattice N sage: Cone(p) == plane True
TESTS:
sage: N = ToricLattice(2) sage: Nsub = N.span([ N(1,2) ]) sage: Cone(Nsub.basis()) 1-d cone in Sublattice <N(1, 2)> sage: Cone([N(0)]) 0-d cone in 2-d lattice N
-
class
sage.geometry.cone.
ConvexRationalPolyhedralCone
(rays=None, lattice=None, ambient=None, ambient_ray_indices=None, PPL=None)¶ Bases:
sage.geometry.cone.IntegralRayCollection
,_abcoll.Container
Create a convex rational polyhedral cone.
Warning
This class does not perform any checks of correctness of input nor does it convert input into the standard representation. Use
Cone()
to construct cones.Cones are immutable, but they cache most of the returned values.
INPUT:
The input can be either:
rays
– list of immutable primitive vectors inlattice
;lattice
–ToricLattice
,, or any other object that behaves like these. If
None
, it will be determined asparent()
of the first ray. Of course, this cannot be done if there are no rays, so in this case you must give an appropriatelattice
directly.
or (these parameters must be given as keywords):
ambient
– ambient structure of this cone, a biggercone
or afan
, this cone must be a face ofambient
;ambient_ray_indices
– increasing list or tuple of integers, indices of rays ofambient
generating this cone.
In both cases, the following keyword parameter may be specified in addition:
PPL
– eitherNone
(default) or aC_Polyhedron
representing the cone. This serves only to cache the polyhedral data if you know it already. The polyhedron will be set immutable.
OUTPUT:
- convex rational polyhedral cone.
Note
Every cone has its ambient structure. If it was not specified, it is this cone itself.
-
Hilbert_basis
()¶ Return the Hilbert basis of the cone.
Given a strictly convex cone
, the Hilbert basis of
is the set of all irreducible elements in the semigroup
. It is the unique minimal generating set over
for the integral points
.
If the cone
is not strictly convex, this method finds the (unique) minimial set of lattice points that need to be added to the defining rays of the cone to generate the whole semigroup
. But because the rays of the cone are not unique nor necessarily minimal in this case, neither is the returned generating set (consisting of the rays plus additional generators).
See also
semigroup_generators()
if you are not interested in a minimal set of generators.OUTPUT:
- a
PointCollection
. The rays ofself
are the firstself.nrays()
entries.
EXAMPLES:
The following command ensures that the output ordering in the examples below is independent of TOPCOM, you don’t have to use it:
sage: PointConfiguration.set_engine('internal')
We start with a simple case of a non-smooth 2-dimensional cone:
sage: Cone([ (1,0), (1,2) ]).Hilbert_basis() N(1, 0), N(1, 2), N(1, 1) in 2-d lattice N
Two more complicated example from GAP/toric:
sage: Cone([[1,0],[3,4]]).dual().Hilbert_basis() M(0, 1), M(4, -3), M(3, -2), M(2, -1), M(1, 0) in 2-d lattice M sage: cone = Cone([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]]).dual() sage: cone.Hilbert_basis() # long time M(10, -7, 0, 1), M(-5, 21, 0, -3), M( 0, -2, 0, 1), M(15, -63, 25, 9), M( 2, -3, 0, 1), M( 1, -4, 1, 1), M(-1, 3, 0, 0), M( 4, -4, 0, 1), M( 1, -5, 2, 1), M( 3, -5, 1, 1), M( 6, -5, 0, 1), M( 3, -13, 5, 2), M( 2, -6, 2, 1), M( 5, -6, 1, 1), M( 0, 1, 0, 0), M( 8, -6, 0, 1), M(-2, 8, 0, -1), M(10, -42, 17, 6), M( 7, -28, 11, 4), M( 5, -21, 9, 3), M( 6, -21, 8, 3), M( 5, -14, 5, 2), M( 2, -7, 3, 1), M( 4, -7, 2, 1), M( 7, -7, 1, 1), M( 0, 0, 1, 0), M(-3, 14, 0, -2), M(-1, 7, 0, -1), M( 1, 0, 0, 0) in 4-d lattice M
Not a strictly convex cone:
sage: wedge = Cone([ (1,0,0), (1,2,0), (0,0,1), (0,0,-1) ]) sage: wedge.semigroup_generators() (N(1, 0, 0), N(1, 1, 0), N(1, 2, 0), N(0, 0, 1), N(0, 0, -1)) sage: wedge.Hilbert_basis() N(1, 2, 0), N(1, 0, 0), N(0, 0, 1), N(0, 0, -1), N(1, 1, 0) in 3-d lattice N
Not full-dimensional cones are ok, too (see http://trac.sagemath.org/sage_trac/ticket/11312):
sage: Cone([(1,1,0), (-1,1,0)]).Hilbert_basis() N( 1, 1, 0), N(-1, 1, 0), N( 0, 1, 0) in 3-d lattice N
ALGORITHM:
The primal Normaliz algorithm, see [Normaliz].
REFERENCES:
[Normaliz] (1, 2) Winfried Bruns, Bogdan Ichim, and Christof Soeger: Normaliz. http://www.mathematik.uni-osnabrueck.de/normaliz/ - a
-
Hilbert_coefficients
(point)¶ Return the expansion coefficients of
point
with respect toHilbert_basis()
.INPUT:
point
– alattice()
point in the cone, or something that can be converted to a point. For example, a list or tuple of integers.
OUTPUT:
A
-vector of length
len(self.Hilbert_basis())
with nonnegative components.Note
Since the Hilbert basis elements are not necessarily linearly independent, the expansion coefficients are not unique. However, this method will always return the same expansion coefficients when invoked with the same argument.
EXAMPLES:
sage: cone = Cone([(1,0),(0,1)]) sage: cone.rays() N(1, 0), N(0, 1) in 2-d lattice N sage: cone.Hilbert_coefficients([3,2]) (3, 2)
A more complicated example:
sage: N = ToricLattice(2) sage: cone = Cone([N(1,0),N(1,2)]) sage: cone.Hilbert_basis() N(1, 0), N(1, 2), N(1, 1) in 2-d lattice N sage: cone.Hilbert_coefficients( N(1,1) ) (0, 0, 1)
The cone need not be strictly convex:
sage: N = ToricLattice(3) sage: cone = Cone([N(1,0,0),N(1,2,0),N(0,0,1),N(0,0,-1)]) sage: cone.Hilbert_basis() N(1, 2, 0), N(1, 0, 0), N(0, 0, 1), N(0, 0, -1), N(1, 1, 0) in 3-d lattice N sage: cone.Hilbert_coefficients( N(1,1,3) ) (0, 0, 3, 0, 1)
-
adjacent
()¶ Return faces adjacent to
self
in the ambient face lattice.Two distinct faces
and
of the same face lattice are adjacent if all of the following conditions hold:
and
have the same dimension
;
and
share a facet of dimension
;
and
are facets of some face of dimension
, unless
is the dimension of the ambient structure.
OUTPUT:
EXAMPLES:
sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)]) sage: octant.adjacent() () sage: one_face = octant.faces(1)[0] sage: len(one_face.adjacent()) 2 sage: one_face.adjacent()[1] 1-d face of 3-d cone in 3-d lattice N
Things are a little bit subtle with fans, as we illustrate below.
First, we create a fan from two cones in the plane:
sage: fan = Fan(cones=[(0,1), (1,2)], ... rays=[(1,0), (0,1), (-1,0)]) sage: cone = fan.generating_cone(0) sage: len(cone.adjacent()) 1
The second generating cone is adjacent to this one. Now we create the same fan, but embedded into the 3-dimensional space:
sage: fan = Fan(cones=[(0,1), (1,2)], ... rays=[(1,0,0), (0,1,0), (-1,0,0)]) sage: cone = fan.generating_cone(0) sage: len(cone.adjacent()) 1
The result is as before, since we still have:
sage: fan.dim() 2
Now we add another cone to make the fan 3-dimensional:
sage: fan = Fan(cones=[(0,1), (1,2), (3,)], ... rays=[(1,0,0), (0,1,0), (-1,0,0), (0,0,1)]) sage: cone = fan.generating_cone(0) sage: len(cone.adjacent()) 0
Since now
cone
has smaller dimension thanfan
, it and its adjacent cones must be facets of a bigger one, but sincecone
in this example is generating, it is not contained in any other.
-
ambient
()¶ Return the ambient structure of
self
.OUTPUT:
- cone or fan containing
self
as a face.
EXAMPLES:
sage: cone = Cone([(1,2,3), (4,6,5), (9,8,7)]) sage: cone.ambient() 3-d cone in 3-d lattice N sage: cone.ambient() is cone True sage: face = cone.faces(1)[0] sage: face 1-d face of 3-d cone in 3-d lattice N sage: face.ambient() 3-d cone in 3-d lattice N sage: face.ambient() is cone True
- cone or fan containing
-
ambient_ray_indices
()¶ Return indices of rays of the ambient structure generating
self
.OUTPUT:
- increasing
tuple
of integers.
EXAMPLES:
sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.ambient_ray_indices() (0, 1) sage: quadrant.facets()[1].ambient_ray_indices() (1,)
- increasing
-
cartesian_product
(other, lattice=None)¶ Return the Cartesian product of
self
withother
.INPUT:
other
– acone
;lattice
– (optional) the ambient lattice for the Cartesian product cone. By default, the direct sum of the ambient lattices ofself
andother
is constructed.
OUTPUT:
- a
cone
.
EXAMPLES:
sage: c = Cone([(1,)]) sage: c.cartesian_product(c) 2-d cone in 2-d lattice N+N sage: _.rays() N+N(1, 0), N+N(0, 1) in 2-d lattice N+N
-
contains
(*args)¶ Check if a given point is contained in
self
.INPUT:
- anything. An attempt will be made to convert all arguments into a
single element of the ambient space of
self
. If it fails,False
will be returned.
OUTPUT:
True
if the given point is contained inself
,False
otherwise.
EXAMPLES:
sage: c = Cone([(1,0), (0,1)]) sage: c.contains(c.lattice()(1,0)) True sage: c.contains((1,0)) True sage: c.contains((1,1)) True sage: c.contains(1,1) True sage: c.contains((-1,0)) False sage: c.contains(c.dual_lattice()(1,0)) #random output (warning) False sage: c.contains(c.dual_lattice()(1,0)) False sage: c.contains(1) False sage: c.contains(1/2, sqrt(3)) True sage: c.contains(-1/2, sqrt(3)) False
- anything. An attempt will be made to convert all arguments into a
single element of the ambient space of
-
dual
()¶ Return the dual cone of
self
.OUTPUT:
cone
.
EXAMPLES:
sage: cone = Cone([(1,0), (-1,3)]) sage: cone.dual().rays() M(0, 1), M(3, 1) in 2-d lattice M
Now let’s look at a more complicated case:
sage: cone = Cone([(-2,-1,2), (4,1,0), (-4,-1,-5), (4,1,5)]) sage: cone.is_strictly_convex() False sage: cone.dim() 3 sage: cone.dual().rays() M(7, -18, -2), M(1, -4, 0) in 3-d lattice M sage: cone.dual().dual() is cone True
We correctly handle the degenerate cases:
sage: N = ToricLattice(2) sage: Cone([], lattice=N).dual().rays() # empty cone M( 1, 0), M(-1, 0), M( 0, 1), M( 0, -1) in 2-d lattice M sage: Cone([(1,0)], lattice=N).dual().rays() # ray in 2d M(1, 0), M(0, 1), M(0, -1) in 2-d lattice M sage: Cone([(1,0),(-1,0)], lattice=N).dual().rays() # line in 2d M(0, 1), M(0, -1) in 2-d lattice M sage: Cone([(1,0),(0,1)], lattice=N).dual().rays() # strictly convex cone M(0, 1), M(1, 0) in 2-d lattice M sage: Cone([(1,0),(-1,0),(0,1)], lattice=N).dual().rays() # half space M(0, 1) in 2-d lattice M sage: Cone([(1,0),(0,1),(-1,-1)], lattice=N).dual().rays() # whole space Empty collection in 2-d lattice M
-
embed
(cone)¶ Return the cone equivalent to the given one, but sitting in
self
as a face.You may need to use this method before calling methods of
cone
that depend on the ambient structure, such asambient_ray_indices()
orfacet_of()
. The cone returned by this method will haveself
as ambient. Ifcone
does not represent a valid cone ofself
,ValueError
exception is raised.Note
This method is very quick if
self
is already the ambient structure ofcone
, so you can use without extra checks and performance hit even ifcone
is likely to sit inself
but in principle may not.INPUT:
cone
– acone
.
OUTPUT:
- a
cone
, equivalent tocone
but sitting insideself
.
EXAMPLES:
Let’s take a 3-d cone on 4 rays:
sage: c = Cone([(1,0,1), (0,1,1), (-1,0,1), (0,-1,1)])
Then any ray generates a 1-d face of this cone, but if you construct such a face directly, it will not “sit” inside the cone:
sage: ray = Cone([(0,-1,1)]) sage: ray 1-d cone in 3-d lattice N sage: ray.ambient_ray_indices() (0,) sage: ray.adjacent() () sage: ray.ambient() 1-d cone in 3-d lattice N
If we want to operate with this ray as a face of the cone, we need to embed it first:
sage: e_ray = c.embed(ray) sage: e_ray 1-d face of 3-d cone in 3-d lattice N sage: e_ray.rays() N(0, -1, 1) in 3-d lattice N sage: e_ray is ray False sage: e_ray.is_equivalent(ray) True sage: e_ray.ambient_ray_indices() (3,) sage: e_ray.adjacent() (1-d face of 3-d cone in 3-d lattice N, 1-d face of 3-d cone in 3-d lattice N) sage: e_ray.ambient() 3-d cone in 3-d lattice N
Not every cone can be embedded into a fixed ambient cone:
sage: c.embed(Cone([(0,0,1)])) Traceback (most recent call last): ... ValueError: 1-d cone in 3-d lattice N is not a face of 3-d cone in 3-d lattice N! sage: c.embed(Cone([(1,0,1), (-1,0,1)])) Traceback (most recent call last): ... ValueError: 2-d cone in 3-d lattice N is not a face of 3-d cone in 3-d lattice N!
-
face_lattice
()¶ Return the face lattice of
self
.This lattice will have the origin as the bottom (we do not include the empty set as a face) and this cone itself as the top.
OUTPUT:
finite poset
ofcones
.
EXAMPLES:
Let’s take a look at the face lattice of the first quadrant:
sage: quadrant = Cone([(1,0), (0,1)]) sage: L = quadrant.face_lattice() sage: L Finite poset containing 4 elements with distinguished linear extension
To see all faces arranged by dimension, you can do this:
sage: for level in L.level_sets(): print level [0-d face of 2-d cone in 2-d lattice N] [1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N] [2-d cone in 2-d lattice N]
For a particular face you can look at its actual rays...
sage: face = L.level_sets()[1][0] sage: face.rays() N(1, 0) in 2-d lattice N
... or you can see the index of the ray of the original cone that corresponds to the above one:
sage: face.ambient_ray_indices() (0,) sage: quadrant.ray(0) N(1, 0)
An alternative to extracting faces from the face lattice is to use
faces()
method:sage: face is quadrant.faces(dim=1)[0] True
The advantage of working with the face lattice directly is that you can (relatively easily) get faces that are related to the given one:
sage: face = L.level_sets()[1][0] sage: D = L.hasse_diagram() sage: D.neighbors(face) [2-d cone in 2-d lattice N, 0-d face of 2-d cone in 2-d lattice N]
However, you can achieve some of this functionality using
facets()
,facet_of()
, andadjacent()
methods:sage: face = quadrant.faces(1)[0] sage: face 1-d face of 2-d cone in 2-d lattice N sage: face.rays() N(1, 0) in 2-d lattice N sage: face.facets() (0-d face of 2-d cone in 2-d lattice N,) sage: face.facet_of() (2-d cone in 2-d lattice N,) sage: face.adjacent() (1-d face of 2-d cone in 2-d lattice N,) sage: face.adjacent()[0].rays() N(0, 1) in 2-d lattice N
Note that if
cone
is a face ofsupercone
, then the face lattice ofcone
consists of (appropriate) faces ofsupercone
:sage: supercone = Cone([(1,2,3,4), (5,6,7,8), ... (1,2,4,8), (1,3,9,7)]) sage: supercone.face_lattice() Finite poset containing 16 elements with distinguished linear extension sage: supercone.face_lattice().top() 4-d cone in 4-d lattice N sage: cone = supercone.facets()[0] sage: cone 3-d face of 4-d cone in 4-d lattice N sage: cone.face_lattice() Finite poset containing 8 elements with distinguished linear extension sage: cone.face_lattice().bottom() 0-d face of 4-d cone in 4-d lattice N sage: cone.face_lattice().top() 3-d face of 4-d cone in 4-d lattice N sage: cone.face_lattice().top() == cone True
TESTS:
sage: C1 = Cone([(0,1)]) sage: C2 = Cone([(0,1)]) sage: C1 == C2 True sage: C1 is C2 False
C1 and C2 are equal, but not identical. We currently want them to have non identical face lattices, even if the faces themselves are equal (see #10998):
sage: C1.face_lattice() is C2.face_lattice() False sage: C1.facets()[0] 0-d face of 1-d cone in 2-d lattice N sage: C2.facets()[0] 0-d face of 1-d cone in 2-d lattice N sage: C1.facets()[0].ambient() is C1 True sage: C2.facets()[0].ambient() is C1 False sage: C2.facets()[0].ambient() is C2 True
-
faces
(dim=None, codim=None)¶ Return faces of
self
of specified (co)dimension.INPUT:
dim
– integer, dimension of the requested faces;codim
– integer, codimension of the requested faces.
Note
You can specify at most one parameter. If you don’t give any, then all faces will be returned.
OUTPUT:
- if either
dim
orcodim
is given, the output will be atuple
ofcones
; - if neither
dim
norcodim
is given, the output will be thetuple
of tuples as above, giving faces of all existing dimensions. If you care about inclusion relations between faces, consider usingface_lattice()
oradjacent()
,facet_of()
, andfacets()
.
EXAMPLES:
Let’s take a look at the faces of the first quadrant:
sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.faces() ((0-d face of 2-d cone in 2-d lattice N,), (1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N), (2-d cone in 2-d lattice N,)) sage: quadrant.faces(dim=1) (1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N) sage: face = quadrant.faces(dim=1)[0]
Now you can look at the actual rays of this face...
sage: face.rays() N(1, 0) in 2-d lattice N
... or you can see indices of the rays of the orginal cone that correspond to the above ray:
sage: face.ambient_ray_indices() (0,) sage: quadrant.ray(0) N(1, 0)
Note that it is OK to ask for faces of too small or high dimension:
sage: quadrant.faces(-1) () sage: quadrant.faces(3) ()
In the case of non-strictly convex cones even faces of small non-negative dimension may be missing:
sage: halfplane = Cone([(1,0), (0,1), (-1,0)]) sage: halfplane.faces(0) () sage: halfplane.faces() ((1-d face of 2-d cone in 2-d lattice N,), (2-d cone in 2-d lattice N,)) sage: plane = Cone([(1,0), (0,1), (-1,-1)]) sage: plane.faces(1) () sage: plane.faces() ((2-d cone in 2-d lattice N,),)
TESTS:
Now we check that “general” cones whose dimension is smaller than the dimension of the ambient space work as expected (see trac ticket #9188):
sage: c = Cone([(1,1,1,3),(1,-1,1,3),(-1,-1,1,3)]) sage: c.faces() ((0-d face of 3-d cone in 4-d lattice N,), (1-d face of 3-d cone in 4-d lattice N, 1-d face of 3-d cone in 4-d lattice N, 1-d face of 3-d cone in 4-d lattice N), (2-d face of 3-d cone in 4-d lattice N, 2-d face of 3-d cone in 4-d lattice N, 2-d face of 3-d cone in 4-d lattice N), (3-d cone in 4-d lattice N,))
We also ensure that a call to this function does not break
facets()
method (see trac ticket #9780):sage: cone = toric_varieties.dP8().fan().generating_cone(0) sage: cone 2-d cone of Rational polyhedral fan in 2-d lattice N sage: for f in cone.facets(): print f.rays() N(1, 1) in 2-d lattice N N(0, 1) in 2-d lattice N sage: len(cone.faces()) 3 sage: for f in cone.facets(): print f.rays() N(1, 1) in 2-d lattice N N(0, 1) in 2-d lattice N
-
facet_normals
()¶ Return inward normals to facets of
self
.Note
- For a not full-dimensional cone facet normals will specify
hyperplanes whose intersections with the space spanned by
self
give facets ofself
. - For a not strictly convex cone facet normals will be orthogonal
to the linear subspace of
self
, i.e. they always will be elements of the dual cone ofself
. - The order of normals is random, but consistent with
facets()
.
OUTPUT:
If the ambient
lattice()
ofself
is atoric lattice
, the facet nomals will be elements of the dual lattice. If it is a general lattice (likeZZ^n
) that does not have adual()
method, the facet normals will be returned as integral vectors.EXAMPLES:
sage: cone = Cone([(1,0), (-1,3)]) sage: cone.facet_normals() M(0, 1), M(3, 1) in 2-d lattice M
Now let’s look at a more complicated case:
sage: cone = Cone([(-2,-1,2), (4,1,0), (-4,-1,-5), (4,1,5)]) sage: cone.is_strictly_convex() False sage: cone.dim() 3 sage: cone.linear_subspace().dimension() 1 sage: lsg = (QQ^3)(cone.linear_subspace().gen(0)); lsg (1, 1/4, 5/4) sage: cone.facet_normals() M(7, -18, -2), M(1, -4, 0) in 3-d lattice M sage: [lsg*normal for normal in cone.facet_normals()] [0, 0]
A lattice that does not have a
dual()
method:sage: Cone([(1,1),(0,1)], lattice=ZZ^2).facet_normals() (-1, 1), ( 1, 0) in Ambient free module of rank 2 over the principal ideal domain Integer Ring
We correctly handle the degenerate cases:
sage: N = ToricLattice(2) sage: Cone([], lattice=N).facet_normals() # empty cone Empty collection in 2-d lattice M sage: Cone([(1,0)], lattice=N).facet_normals() # ray in 2d M(1, 0) in 2-d lattice M sage: Cone([(1,0),(-1,0)], lattice=N).facet_normals() # line in 2d Empty collection in 2-d lattice M sage: Cone([(1,0),(0,1)], lattice=N).facet_normals() # strictly convex cone M(0, 1), M(1, 0) in 2-d lattice M sage: Cone([(1,0),(-1,0),(0,1)], lattice=N).facet_normals() # half space M(0, 1) in 2-d lattice M sage: Cone([(1,0),(0,1),(-1,-1)], lattice=N).facet_normals() # whole space Empty collection in 2-d lattice M
- For a not full-dimensional cone facet normals will specify
hyperplanes whose intersections with the space spanned by
-
facet_of
()¶ Return cones of the ambient face lattice having
self
as a facet.OUTPUT:
EXAMPLES:
sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)]) sage: octant.facet_of() () sage: one_face = octant.faces(1)[0] sage: len(one_face.facet_of()) 2 sage: one_face.facet_of()[1] 2-d face of 3-d cone in 3-d lattice N
While fan is the top element of its own cone lattice, which is a variant of a face lattice, we do not refer to cones as its facets:
sage: fan = Fan([octant]) sage: fan.generating_cone(0).facet_of() ()
Subcones of generating cones work as before:
sage: one_cone = fan(1)[0] sage: len(one_cone.facet_of()) 2
-
facets
()¶ Return facets (faces of codimension 1) of
self
.OUTPUT:
EXAMPLES:
sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.facets() (1-d face of 2-d cone in 2-d lattice N, 1-d face of 2-d cone in 2-d lattice N)
-
interior_contains
(*args)¶ Check if a given point is contained in the interior of
self
.For a cone of strictly lower-dimension than the ambient space, the interior is always empty. You probably want to use
relative_interior_contains()
in this case.INPUT:
- anything. An attempt will be made to convert all arguments into a
single element of the ambient space of
self
. If it fails,False
will be returned.
OUTPUT:
True
if the given point is contained in the interior ofself
,False
otherwise.
EXAMPLES:
sage: c = Cone([(1,0), (0,1)]) sage: c.contains((1,1)) True sage: c.interior_contains((1,1)) True sage: c.contains((1,0)) True sage: c.interior_contains((1,0)) False
- anything. An attempt will be made to convert all arguments into a
single element of the ambient space of
-
intersection
(other)¶ Compute the intersection of two cones.
INPUT:
other
-cone
.
OUTPUT:
cone
.
Raises
ValueError
if the ambient space dimensions are not compatible.EXAMPLES:
sage: cone1 = Cone([(1,0), (-1, 3)]) sage: cone2 = Cone([(-1,0), (2, 5)]) sage: cone1.intersection(cone2).rays() N(-1, 3), N( 2, 5) in 2-d lattice N
It is OK to intersect cones living in sublattices of the same ambient lattice:
sage: N = cone1.lattice() sage: Ns = N.submodule([(1,1)]) sage: cone3 = Cone([(1,1)], lattice=Ns) sage: I = cone1.intersection(cone3) sage: I.rays() N(1, 1) in Sublattice <N(1, 1)> sage: I.lattice() Sublattice <N(1, 1)>
But you cannot intersect cones from incompatible lattices without explicit conversion:
sage: cone1.intersection(cone1.dual()) Traceback (most recent call last): ... ValueError: 2-d lattice N and 2-d lattice M have different ambient lattices! sage: cone1.intersection(Cone(cone1.dual().rays(), N)).rays() N(3, 1), N(0, 1) in 2-d lattice N
-
is_equivalent
(other)¶ Check if
self
is “mathematically” the same asother
.INPUT:
other
- cone.
OUTPUT:
True
ifself
andother
define the same cones as sets of points in the same lattice,False
otherwise.
There are three different equivalences between cones
and
in the same lattice:
- They have the same generating rays in the same order.
This is tested by
C1 == C2
. - They describe the same sets of points.
This is tested by
C1.is_equivalent(C2)
. - They are in the same orbit of
(and, therefore, correspond to isomorphic affine toric varieties). This is tested by
C1.is_isomorphic(C2)
.
EXAMPLES:
sage: cone1 = Cone([(1,0), (-1, 3)]) sage: cone2 = Cone([(-1,3), (1, 0)]) sage: cone1.rays() N( 1, 0), N(-1, 3) in 2-d lattice N sage: cone2.rays() N(-1, 3), N( 1, 0) in 2-d lattice N sage: cone1 == cone2 False sage: cone1.is_equivalent(cone2) True
-
is_face_of
(cone)¶ Check if
self
forms a face of anothercone
.INPUT:
cone
– cone.
OUTPUT:
True
ifself
is a face ofcone
,False
otherwise.
EXAMPLES:
sage: quadrant = Cone([(1,0), (0,1)]) sage: cone1 = Cone([(1,0)]) sage: cone2 = Cone([(1,2)]) sage: quadrant.is_face_of(quadrant) True sage: cone1.is_face_of(quadrant) True sage: cone2.is_face_of(quadrant) False
Being a face means more than just saturating a facet inequality:
sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)]) sage: cone = Cone([(2,1,0),(1,2,0)]) sage: cone.is_face_of(octant) False
-
is_isomorphic
(other)¶ Check if
self
is in the same-orbit as
other
.INPUT:
other
- cone.
OUTPUT:
True
ifself
andother
are in the same-orbit,
False
otherwise.
There are three different equivalences between cones
and
in the same lattice:
- They have the same generating rays in the same order.
This is tested by
C1 == C2
. - They describe the same sets of points.
This is tested by
C1.is_equivalent(C2)
. - They are in the same orbit of
(and, therefore, correspond to isomorphic affine toric varieties). This is tested by
C1.is_isomorphic(C2)
.
EXAMPLES:
sage: cone1 = Cone([(1,0), (0, 3)]) sage: m = matrix(ZZ, [(1, -5), (-1, 4)]) # a GL(2,ZZ)-matrix sage: cone2 = Cone([m*r for r in cone1.rays()]) sage: cone1.is_isomorphic(cone2) True sage: cone1 = Cone([(1,0), (0, 3)]) sage: cone2 = Cone([(-1,3), (1, 0)]) sage: cone1.is_isomorphic(cone2) False
TESTS:
sage: from sage.geometry.cone import classify_cone_2d sage: classify_cone_2d(*cone1.rays()) (1, 0) sage: classify_cone_2d(*cone2.rays()) (3, 2)
-
is_proper
()¶ Return whether or not this cone is proper.
A cone is said to be proper if it is closed, convex, solid, and contains no lines. This cone is assumed to be closed and convex; therefore it is proper if it is solid and contains no lines.
OUTPUT:
True
if this cone is proper, andFalse
otherwise.See also
EXAMPLES:
The nonnegative orthant is always proper:
sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.is_proper() True sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)]) sage: octant.is_proper() True
However, if we embed the two-dimensional nonnegative quadrant into three-dimensional space, then the resulting cone no longer has interior, so it is not solid, and thus not proper:
sage: quadrant = Cone([(1,0,0), (0,1,0)]) sage: quadrant.is_proper() False
Likewise, a half-space contains at least one line, so it is not proper:
sage: halfspace = Cone([(1,0),(0,1),(-1,0)]) sage: halfspace.is_proper() False
-
is_simplicial
()¶ Check if
self
is simplicial.A cone is called simplicial if primitive vectors along its generating rays form a part of a rational basis of the ambient space.
OUTPUT:
True
ifself
is simplicial,False
otherwise.
EXAMPLES:
sage: cone1 = Cone([(1,0), (0, 3)]) sage: cone2 = Cone([(1,0), (0, 3), (-1,-1)]) sage: cone1.is_simplicial() True sage: cone2.is_simplicial() False
-
is_smooth
()¶ Check if
self
is smooth.A cone is called smooth if primitive vectors along its generating rays form a part of an integral basis of the ambient space. Equivalently, they generate the whole lattice on the linear subspace spanned by the rays.
OUTPUT:
True
ifself
is smooth,False
otherwise.
EXAMPLES:
sage: cone1 = Cone([(1,0), (0, 1)]) sage: cone2 = Cone([(1,0), (-1, 3)]) sage: cone1.is_smooth() True sage: cone2.is_smooth() False
The following cones are the same up to a
coordinate transformation:
sage: Cone([(1,0,0), (2,1,-1)]).is_smooth() True sage: Cone([(1,0,0), (2,1,1)]).is_smooth() True sage: Cone([(1,0,0), (2,1,2)]).is_smooth() True
-
is_solid
()¶ Return whether or not this cone is solid.
A cone is said to be solid if it has nonempty interior. That is, if its extreme rays span the entire ambient space.
OUTPUT:
True
if this cone is solid, andFalse
otherwise.See also
EXAMPLES:
The nonnegative orthant is always solid:
sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.is_solid() True sage: octant = Cone([(1,0,0), (0,1,0), (0,0,1)]) sage: octant.is_solid() True
However, if we embed the two-dimensional nonnegative quadrant into three-dimensional space, then the resulting cone no longer has interior, so it is not solid:
sage: quadrant = Cone([(1,0,0), (0,1,0)]) sage: quadrant.is_solid() False
-
is_strictly_convex
()¶ Check if
self
is strictly convex.A cone is called strictly convex if it does not contain any lines.
OUTPUT:
True
ifself
is strictly convex,False
otherwise.
EXAMPLES:
sage: cone1 = Cone([(1,0), (0, 1)]) sage: cone2 = Cone([(1,0), (-1, 0)]) sage: cone1.is_strictly_convex() True sage: cone2.is_strictly_convex() False
-
is_trivial
()¶ Checks if the cone has no rays.
OUTPUT:
True
if the cone has no rays,False
otherwise.
EXAMPLES:
sage: c0 = Cone([], lattice=ToricLattice(3)) sage: c0.is_trivial() True sage: c0.nrays() 0
-
lattice_polytope
()¶ Return the lattice polytope associated to
self
.The vertices of this polytope are primitive vectors along the generating rays of
self
and the origin, ifself
is strictly convex. In this case the origin is the last vertex, so the-th ray of the cone always corresponds to the
-th vertex of the polytope.
See also
polyhedron()
.OUTPUT:
EXAMPLES:
sage: quadrant = Cone([(1,0), (0,1)]) sage: lp = quadrant.lattice_polytope() doctest:...: DeprecationWarning: lattice_polytope(...) is deprecated! See http://trac.sagemath.org/16180 for details. sage: lp 2-d lattice polytope in 2-d lattice N sage: lp.vertices_pc() N(1, 0), N(0, 1), N(0, 0) in 2-d lattice N sage: line = Cone([(1,0), (-1,0)]) sage: lp = line.lattice_polytope() sage: lp 1-d lattice polytope in 2-d lattice N sage: lp.vertices_pc() N( 1, 0), N(-1, 0) in 2-d lattice N
-
line_set
()¶ Return a set of lines generating the linear subspace of
self
.OUTPUT:
frozenset
of primitive vectors in the lattice ofself
giving directions of lines that span the linear subspace ofself
. These lines are arbitrary, but fixed. See alsolines()
.
EXAMPLES:
sage: halfplane = Cone([(1,0), (0,1), (-1,0)]) sage: halfplane.line_set() doctest:...: DeprecationWarning: line_set(...) is deprecated, please use lines().set() instead! See http://trac.sagemath.org/12544 for details. frozenset({N(1, 0)}) sage: fullplane = Cone([(1,0), (0,1), (-1,-1)]) sage: fullplane.line_set() frozenset({N(0, 1), N(1, 0)})
-
linear_subspace
()¶ Return the largest linear subspace contained inside of
self
.OUTPUT:
- subspace of the ambient space of
self
.
EXAMPLES:
sage: halfplane = Cone([(1,0), (0,1), (-1,0)]) sage: halfplane.linear_subspace() Vector space of degree 2 and dimension 1 over Rational Field Basis matrix: [1 0]
- subspace of the ambient space of
-
lines
()¶ Return lines generating the linear subspace of
self
.OUTPUT:
tuple
of primitive vectors in the lattice ofself
giving directions of lines that span the linear subspace ofself
. These lines are arbitrary, but fixed. If you do not care about the order, see alsoline_set()
.
EXAMPLES:
sage: halfplane = Cone([(1,0), (0,1), (-1,0)]) sage: halfplane.lines() N(1, 0) in 2-d lattice N sage: fullplane = Cone([(1,0), (0,1), (-1,-1)]) sage: fullplane.lines() N(0, 1), N(1, 0) in 2-d lattice N
-
orthogonal_sublattice
(*args, **kwds)¶ The sublattice (in the dual lattice) orthogonal to the sublattice spanned by the cone.
Let
self.dual_lattice()
be the lattice dual to the ambient lattice of the given cone. Then, in the notation of [Fulton], this method returns the sublattice
INPUT:
- either nothing or something that can be turned into an element of this lattice.
OUTPUT:
- if no arguments were given, a
toric sublattice
, otherwise the corresponding element of it.
EXAMPLES:
sage: c = Cone([(1,1,1), (1,-1,1), (-1,-1,1), (-1,1,1)]) sage: c.orthogonal_sublattice() Sublattice <> sage: c12 = Cone([(1,1,1), (1,-1,1)]) sage: c12.sublattice() Sublattice <N(1, -1, 1), N(0, 1, 0)> sage: c12.orthogonal_sublattice() Sublattice <M(1, 0, -1)>
-
plot
(**options)¶ Plot
self
.INPUT:
- any options for toric plots (see
toric_plotter.options
), none are mandatory.
OUTPUT:
- a plot.
EXAMPLES:
sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.plot() Graphics object consisting of 9 graphics primitives
- any options for toric plots (see
-
polyhedron
()¶ Return the polyhedron associated to
self
.Mathematically this polyhedron is the same as
self
.OUTPUT:
EXAMPLES:
sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.polyhedron() A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 2 rays sage: line = Cone([(1,0), (-1,0)]) sage: line.polyhedron() A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 1 line
Here is an example of a trivial cone (see trac ticket #10237):
sage: origin = Cone([], lattice=ZZ^2) sage: origin.polyhedron() A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex
-
relative_interior_contains
(*args)¶ Check if a given point is contained in the relative interior of
self
.For a full-dimensional cone the relative interior is simply the interior, so this method will do the same check as
interior_contains()
. For a strictly lower-dimensional cone, the relative interior is the cone without its facets.INPUT:
- anything. An attempt will be made to convert all arguments into a
single element of the ambient space of
self
. If it fails,False
will be returned.
OUTPUT:
True
if the given point is contained in the relative interior ofself
,False
otherwise.
EXAMPLES:
sage: c = Cone([(1,0,0), (0,1,0)]) sage: c.contains((1,1,0)) True sage: c.relative_interior_contains((1,1,0)) True sage: c.interior_contains((1,1,0)) False sage: c.contains((1,0,0)) True sage: c.relative_interior_contains((1,0,0)) False sage: c.interior_contains((1,0,0)) False
- anything. An attempt will be made to convert all arguments into a
single element of the ambient space of
-
relative_orthogonal_quotient
(supercone)¶ The quotient of the dual spanned lattice by the dual of the supercone’s spanned lattice.
In the notation of [Fulton], if
supercone
==
self
is a cone that containsas a face, then
=
supercone.orthogonal_sublattice()
is a saturated sublattice of=
self.orthogonal_sublattice()
. This method returns the quotient lattice. The lifts of the quotient generators arelinearly independent M-lattice lattice points that, together with
, generate
.
OUTPUT:
If we call the output
Mrho
, thenMrho.cover() == self.orthogonal_sublattice()
, andMrho.relations() == supercone.orthogonal_sublattice()
.
Note
has no torsion since the sublattice
is saturated.
- In the codimension one case, (a lift of) the generator of
is chosen to be positive on
.
EXAMPLES:
sage: rho = Cone([(1,1,1,3),(1,-1,1,3),(-1,-1,1,3),(-1,1,1,3)]) sage: rho.orthogonal_sublattice() Sublattice <M(0, 0, 3, -1)> sage: sigma = rho.facets()[1] sage: sigma.orthogonal_sublattice() Sublattice <M(0, 1, 1, 0), M(0, 0, 3, -1)> sage: sigma.is_face_of(rho) True sage: Q = sigma.relative_orthogonal_quotient(rho); Q 1-d lattice, quotient of Sublattice <M(0, 1, 1, 0), M(0, 0, 3, -1)> by Sublattice <M(0, 0, 3, -1)> sage: Q.gens() (M[0, 1, 1, 0],)
Different codimension:
sage: rho = Cone([[1,-1,1,3],[-1,-1,1,3]]) sage: sigma = rho.facets()[0] sage: sigma.orthogonal_sublattice() Sublattice <M(1, 0, 2, -1), M(0, 1, 1, 0), M(0, 0, 3, -1)> sage: rho.orthogonal_sublattice() Sublattice <M(0, 1, 1, 0), M(0, 0, 3, -1)> sage: sigma.relative_orthogonal_quotient(rho).gens() (M[-1, 0, -2, 1],)
Sign choice in the codimension one case:
sage: sigma1 = Cone([(1, 2, 3), (1, -1, 1), (-1, 1, 1), (-1, -1, 1)]) # 3d sage: sigma2 = Cone([(1, 1, -1), (1, 2, 3), (1, -1, 1), (1, -1, -1)]) # 3d sage: rho = sigma1.intersection(sigma2) sage: rho.relative_orthogonal_quotient(sigma1).gens() (M[-5, -2, 3],) sage: rho.relative_orthogonal_quotient(sigma2).gens() (M[5, 2, -3],)
-
relative_quotient
(subcone)¶ The quotient of the spanned lattice by the lattice spanned by a subcone.
In the notation of [Fulton], let
be the ambient lattice and
the sublattice spanned by the given cone
. If
is a subcone, then
=
rho.sublattice()
is a saturated sublattice of=
self.sublattice()
. This method returns the quotient lattice. The lifts of the quotient generators arelinearly independent primitive lattice lattice points that, together with
, generate
.
OUTPUT:
Note
- The quotient
of spanned sublattices has no torsion since the sublattice
is saturated.
- In the codimension one case, the generator of
is chosen to be in the same direction as the image
EXAMPLES:
sage: sigma = Cone([(1,1,1,3),(1,-1,1,3),(-1,-1,1,3),(-1,1,1,3)]) sage: rho = Cone([(-1, -1, 1, 3), (-1, 1, 1, 3)]) sage: sigma.sublattice() Sublattice <N(-1, -1, 1, 3), N(1, 0, 0, 0), N(1, 1, 0, 0)> sage: rho.sublattice() Sublattice <N(-1, 1, 1, 3), N(0, -1, 0, 0)> sage: sigma.relative_quotient(rho) 1-d lattice, quotient of Sublattice <N(-1, -1, 1, 3), N(1, 0, 0, 0), N(1, 1, 0, 0)> by Sublattice <N(1, 0, -1, -3), N(0, 1, 0, 0)> sage: sigma.relative_quotient(rho).gens() (N[1, 1, 0, 0],)
More complicated example:
sage: rho = Cone([(1, 2, 3), (1, -1, 1)]) sage: sigma = Cone([(1, 2, 3), (1, -1, 1), (-1, 1, 1), (-1, -1, 1)]) sage: N_sigma = sigma.sublattice() sage: N_sigma Sublattice <N(-1, 1, 1), N(1, 2, 3), N(0, 1, 1)> sage: N_rho = rho.sublattice() sage: N_rho Sublattice <N(1, -1, 1), N(1, 2, 3)> sage: sigma.relative_quotient(rho).gens() (N[0, 1, 1],) sage: N = rho.lattice() sage: N_sigma == N.span(N_rho.gens() + tuple(q.lift() ... for q in sigma.relative_quotient(rho).gens())) True
Sign choice in the codimension one case:
sage: sigma1 = Cone([(1, 2, 3), (1, -1, 1), (-1, 1, 1), (-1, -1, 1)]) # 3d sage: sigma2 = Cone([(1, 1, -1), (1, 2, 3), (1, -1, 1), (1, -1, -1)]) # 3d sage: rho = sigma1.intersection(sigma2) sage: rho.sublattice() Sublattice <N(1, -1, 1), N(1, 2, 3)> sage: sigma1.relative_quotient(rho) 1-d lattice, quotient of Sublattice <N(-1, 1, 1), N(1, 2, 3), N(0, 1, 1)> by Sublattice <N(1, 2, 3), N(0, 3, 2)> sage: sigma1.relative_quotient(rho).gens() (N[0, 1, 1],) sage: sigma2.relative_quotient(rho).gens() (N[-1, 0, -2],)
- The quotient
-
semigroup_generators
()¶ Return generators for the semigroup of lattice points of
self
.OUTPUT:
- a
PointCollection
of lattice points generating the semigroup of lattice points contained inself
.
Note
No attempt is made to return a minimal set of generators, see
Hilbert_basis()
for that.EXAMPLES:
The following command ensures that the output ordering in the examples below is independent of TOPCOM, you don’t have to use it:
sage: PointConfiguration.set_engine('internal')
We start with a simple case of a non-smooth 2-dimensional cone:
sage: Cone([ (1,0), (1,2) ]).semigroup_generators() N(1, 1), N(1, 0), N(1, 2) in 2-d lattice N
A non-simplicial cone works, too:
sage: cone = Cone([(3,0,-1), (1,-1,0), (0,1,0), (0,0,1)]) sage: cone.semigroup_generators() (N(1, 0, 0), N(0, 0, 1), N(0, 1, 0), N(3, 0, -1), N(1, -1, 0))
GAP’s toric package thinks this is challenging:
sage: cone = Cone([[1,2,3,4],[0,1,0,7],[3,1,0,2],[0,0,1,0]]).dual() sage: len( cone.semigroup_generators() ) 2806
The cone need not be strictly convex:
sage: halfplane = Cone([(1,0),(2,1),(-1,0)]) sage: halfplane.semigroup_generators() (N(0, 1), N(1, 0), N(-1, 0)) sage: line = Cone([(1,1,1),(-1,-1,-1)]) sage: line.semigroup_generators() (N(1, 1, 1), N(-1, -1, -1)) sage: wedge = Cone([ (1,0,0), (1,2,0), (0,0,1), (0,0,-1) ]) sage: wedge.semigroup_generators() (N(1, 0, 0), N(1, 1, 0), N(1, 2, 0), N(0, 0, 1), N(0, 0, -1))
Nor does it have to be full-dimensional (see http://trac.sagemath.org/sage_trac/ticket/11312):
sage: Cone([(1,1,0), (-1,1,0)]).semigroup_generators() N( 0, 1, 0), N( 1, 1, 0), N(-1, 1, 0) in 3-d lattice N
Neither full-dimensional nor simplicial:
sage: A = matrix([(1, 3, 0), (-1, 0, 1), (1, 1, -2), (15, -2, 0)]) sage: A.elementary_divisors() [1, 1, 1, 0] sage: cone3d = Cone([(3,0,-1), (1,-1,0), (0,1,0), (0,0,1)]) sage: rays = [ A*vector(v) for v in cone3d.rays() ] sage: gens = Cone(rays).semigroup_generators(); gens (N(1, -1, 1, 15), N(0, 1, -2, 0), N(-2, -1, 0, 17), N(3, -4, 5, 45), N(3, 0, 1, -2)) sage: set(map(tuple,gens)) == set([ tuple(A*r) for r in cone3d.semigroup_generators() ]) True
TESTS:
sage: len(Cone(identity_matrix(10).rows()).semigroup_generators()) 10 sage: trivial_cone = Cone([], lattice=ToricLattice(3)) sage: trivial_cone.semigroup_generators() Empty collection in 3-d lattice N
ALGORITHM:
If the cone is not simplicial, it is first triangulated. Each simplicial subcone has the integral points of the spaned parallelotope as generators. This is the first step of the primal Normaliz algorithm, see [Normaliz]. For each simplicial cone (of dimension
), the integral points of the open parallelotope
are then computed [BrunsKoch].
Finally, the the union of the generators of all simplicial subcones is returned.
REFERENCES:
[BrunsKoch] W. Bruns and R. Koch, Computing the integral closure of an affine semigroup. Uni. Iaggelonicae Acta Math. 39, (2001), 59-70 - a
-
strict_quotient
()¶ Return the quotient of
self
by the linear subspace.We define the strict quotient of a cone to be the image of this cone in the quotient of the ambient space by the linear subspace of the cone, i.e. it is the “complementary part” to the linear subspace.
OUTPUT:
- cone.
EXAMPLES:
sage: halfplane = Cone([(1,0), (0,1), (-1,0)]) sage: ssc = halfplane.strict_quotient() sage: ssc 1-d cone in 1-d lattice N sage: ssc.rays() N(1) in 1-d lattice N sage: line = Cone([(1,0), (-1,0)]) sage: ssc = line.strict_quotient() sage: ssc 0-d cone in 1-d lattice N sage: ssc.rays() Empty collection in 1-d lattice N
-
sublattice
(*args, **kwds)¶ The sublattice spanned by the cone.
Let
be the given cone and
self.lattice()
the ambient lattice. Then, in the notation of [Fulton], this method returns the sublatticeINPUT:
- either nothing or something that can be turned into an element of this lattice.
OUTPUT:
- if no arguments were given, a
toric sublattice
, otherwise the corresponding element of it.
Note
- The sublattice spanned by the cone is the saturation of the sublattice generated by the rays of the cone.
- If you only need a
-basis, you may want to try the
basis()
method on the result ofrays()
. - The returned lattice points are usually not rays of the
cone. In fact, for a non-smooth cone the rays do not
generate the sublattice
, but only a finite index sublattice.
EXAMPLES:
sage: cone = Cone([(1, 1, 1), (1, -1, 1), (-1, -1, 1), (-1, 1, 1)]) sage: cone.rays().basis() N( 1, 1, 1), N( 1, -1, 1), N(-1, -1, 1) in 3-d lattice N sage: cone.rays().basis().matrix().det() -4 sage: cone.sublattice() Sublattice <N(-1, -1, 1), N(1, 0, 0), N(1, 1, 0)> sage: matrix( cone.sublattice().gens() ).det() 1
Another example:
sage: c = Cone([(1,2,3), (4,-5,1)]) sage: c 2-d cone in 3-d lattice N sage: c.rays() N(1, 2, 3), N(4, -5, 1) in 3-d lattice N sage: c.sublattice() Sublattice <N(1, 2, 3), N(4, -5, 1)> sage: c.sublattice(5, -3, 4) N(5, -3, 4) sage: c.sublattice(1, 0, 0) Traceback (most recent call last): ... TypeError: element [1, 0, 0] is not in free module
-
sublattice_complement
(*args, **kwds)¶ A complement of the sublattice spanned by the cone.
In other words,
sublattice()
andsublattice_complement()
together form a-basis for the ambient
lattice()
.In the notation of [Fulton], let
be the given cone and
self.lattice()
the ambient lattice. Then this method returnslifted (non-canonically) to a sublattice of
.
INPUT:
- either nothing or something that can be turned into an element of this lattice.
OUTPUT:
- if no arguments were given, a
toric sublattice
, otherwise the corresponding element of it.
EXAMPLES:
sage: C2_Z2 = Cone([(1,0),(1,2)]) # C^2/Z_2 sage: c1, c2 = C2_Z2.facets() sage: c2.sublattice() Sublattice <N(1, 2)> sage: c2.sublattice_complement() Sublattice <N(0, 1)>
A more complicated example:
sage: c = Cone([(1,2,3), (4,-5,1)]) sage: c.sublattice() Sublattice <N(1, 2, 3), N(4, -5, 1)> sage: c.sublattice_complement() Sublattice <N(0, -6, -5)> sage: m = matrix( c.sublattice().gens() + c.sublattice_complement().gens() ) sage: m [ 1 2 3] [ 4 -5 1] [ 0 -6 -5] sage: m.det() -1
-
sublattice_quotient
(*args, **kwds)¶ The quotient of the ambient lattice by the sublattice spanned by the cone.
INPUT:
- either nothing or something that can be turned into an element of this lattice.
OUTPUT:
- if no arguments were given, a
quotient of a toric lattice
, otherwise the corresponding element of it.
EXAMPLES:
sage: C2_Z2 = Cone([(1,0),(1,2)]) # C^2/Z_2 sage: c1, c2 = C2_Z2.facets() sage: c2.sublattice_quotient() 1-d lattice, quotient of 2-d lattice N by Sublattice <N(1, 2)> sage: N = C2_Z2.lattice() sage: n = N(1,1) sage: n_bar = c2.sublattice_quotient(n); n_bar N[1, 1] sage: n_bar.lift() N(1, 1) sage: vector(n_bar) (-1)
-
class
sage.geometry.cone.
IntegralRayCollection
(rays, lattice)¶ Bases:
sage.structure.sage_object.SageObject
,_abcoll.Hashable
,_abcoll.Iterable
Create a collection of integral rays.
Warning
No correctness check or normalization is performed on the input data. This class is designed for internal operations and you probably should not use it directly.
This is a base class for
convex rational polyhedral cones
andfans
.Ray collections are immutable, but they cache most of the returned values.
INPUT:
rays
– list of immutable vectors inlattice
;lattice
–ToricLattice
,, or any other object that behaves like these. If
None
, it will be determined asparent()
of the first ray. Of course, this cannot be done if there are no rays, so in this case you must give an appropriatelattice
directly. Note thatNone
is not the default value - you always must give this argument explicitly, even if it isNone
.
OUTPUT:
- collection of given integral rays.
-
cartesian_product
(other, lattice=None)¶ Return the Cartesian product of
self
withother
.INPUT:
other
– anIntegralRayCollection
;lattice
– (optional) the ambient lattice for the result. By default, the direct sum of the ambient lattices ofself
andother
is constructed.
OUTPUT:
By the Cartesian product of ray collections
and
we understand the ray collection of the form
, which is suitable for Cartesian products of cones and fans. The ray order is guaranteed to be as described.
EXAMPLES:
sage: c = Cone([(1,)]) sage: c.cartesian_product(c) # indirect doctest 2-d cone in 2-d lattice N+N sage: _.rays() N+N(1, 0), N+N(0, 1) in 2-d lattice N+N
-
dim
()¶ Return the dimension of the subspace spanned by rays of
self
.OUTPUT:
- integer.
EXAMPLES:
sage: c = Cone([(1,0)]) sage: c.lattice_dim() 2 sage: c.dim() 1
-
dual_lattice
()¶ Return the dual of the ambient lattice of
self
.OUTPUT:
- lattice. If possible (that is, if
lattice()
has adual()
method), the dual lattice is returned. Otherwise,is returned, where
is the dimension of
lattice()
.
EXAMPLES:
sage: c = Cone([(1,0)]) sage: c.dual_lattice() 2-d lattice M sage: Cone([], ZZ^3).dual_lattice() Ambient free module of rank 3 over the principal ideal domain Integer Ring
- lattice. If possible (that is, if
-
lattice
()¶ Return the ambient lattice of
self
.OUTPUT:
- lattice.
EXAMPLES:
sage: c = Cone([(1,0)]) sage: c.lattice() 2-d lattice N sage: Cone([], ZZ^3).lattice() Ambient free module of rank 3 over the principal ideal domain Integer Ring
-
lattice_dim
()¶ Return the dimension of the ambient lattice of
self
.OUTPUT:
- integer.
EXAMPLES:
sage: c = Cone([(1,0)]) sage: c.lattice_dim() 2 sage: c.dim() 1
-
nrays
()¶ Return the number of rays of
self
.OUTPUT:
- integer.
EXAMPLES:
sage: c = Cone([(1,0), (0,1)]) sage: c.nrays() 2
-
plot
(**options)¶ Plot
self
.INPUT:
- any options for toric plots (see
toric_plotter.options
), none are mandatory.
OUTPUT:
- a plot.
EXAMPLES:
sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant.plot() Graphics object consisting of 9 graphics primitives
- any options for toric plots (see
-
ray
(n)¶ Return the
n
-th ray ofself
.INPUT:
n
– integer, an index of a ray ofself
. Enumeration of rays starts with zero.
OUTPUT:
- ray, an element of the lattice of
self
.
EXAMPLES:
sage: c = Cone([(1,0), (0,1)]) sage: c.ray(0) N(1, 0)
-
rays
(*args)¶ Return (some of the) rays of
self
.INPUT:
ray_list
– a list of integers, the indices of the requested rays. If not specified, all rays ofself
will be returned.
OUTPUT:
- a
PointCollection
of primitive integral ray generators.
EXAMPLES:
sage: c = Cone([(1,0), (0,1), (-1, 0)]) sage: c.rays() N( 0, 1), N( 1, 0), N(-1, 0) in 2-d lattice N sage: c.rays([0, 2]) N( 0, 1), N(-1, 0) in 2-d lattice N
You can also give ray indices directly, without packing them into a list:
sage: c.rays(0, 2) N( 0, 1), N(-1, 0) in 2-d lattice N
-
sage.geometry.cone.
classify_cone_2d
(ray0, ray1, check=True)¶ Return
classifying the lattice cone spanned by the two rays.
INPUT:
ray0
,ray1
– two primitive integer vectors. The generators of the two rays generating the two-dimensional cone.check
– boolean (default:True
). Whether to check the input rays for consistency.
OUTPUT:
A pair
of integers classifying the cone up to
equivalence. See Proposition 10.1.1 of [CLS] for the definition. We return the unique
with minmial
, see Proposition 10.1.3 of [CLS].
EXAMPLES:
sage: ray0 = vector([1,0]) sage: ray1 = vector([2,3]) sage: from sage.geometry.cone import classify_cone_2d sage: classify_cone_2d(ray0, ray1) (3, 2) sage: ray0 = vector([2,4,5]) sage: ray1 = vector([5,19,11]) sage: classify_cone_2d(ray0, ray1) (3, 1) sage: m = matrix(ZZ, [(19, -14, -115), (-2, 5, 25), (43, -42, -298)]) sage: m.det() # check that it is in GL(3,ZZ) -1 sage: classify_cone_2d(m*ray0, m*ray1) (3, 1)
TESTS:
Check using the connection between the Hilbert basis of the cone spanned by the two rays (in arbitrary dimension) and the Hirzebruch-Jung continued fraction expansion, see Chapter 10 of [CLS]
sage: from sage.geometry.cone import normalize_rays sage: for i in range(10): ....: ray0 = random_vector(ZZ, 3) ....: ray1 = random_vector(ZZ, 3) ....: if ray0.is_zero() or ray1.is_zero(): continue ....: ray0, ray1 = normalize_rays([ray0, ray1], ZZ^3) ....: d, k = classify_cone_2d(ray0, ray1, check=True) ....: assert (d,k) == classify_cone_2d(ray1, ray0) ....: if d == 0: continue ....: frac = (k/d).continued_fraction_list("hj") ....: if len(frac)>100: continue # avoid expensive computation ....: hilb = Cone([ray0, ray1]).Hilbert_basis() ....: assert len(hilb) == len(frac) + 1
-
sage.geometry.cone.
is_Cone
(x)¶ Check if
x
is a cone.INPUT:
x
– anything.
OUTPUT:
True
ifx
is a cone andFalse
otherwise.
EXAMPLES:
sage: from sage.geometry.cone import is_Cone sage: is_Cone(1) False sage: quadrant = Cone([(1,0), (0,1)]) sage: quadrant 2-d cone in 2-d lattice N sage: is_Cone(quadrant) True
-
sage.geometry.cone.
normalize_rays
(rays, lattice)¶ Normalize a list of rational rays: make them primitive and immutable.
INPUT:
rays
– list of rays which can be converted to the rational extension oflattice
;lattice
–ToricLattice
,, or any other object that behaves like these. If
None
, an attempt will be made to determine an appropriate toric lattice automatically.
OUTPUT:
- list of immutable primitive vectors of the
lattice
in the same directions as originalrays
.
EXAMPLES:
sage: from sage.geometry.cone import normalize_rays sage: normalize_rays([(0, 1), (0, 2), (3, 2), (5/7, 10/3)], None) [N(0, 1), N(0, 1), N(3, 2), N(3, 14)] sage: L = ToricLattice(2, "L") sage: normalize_rays([(0, 1), (0, 2), (3, 2), (5/7, 10/3)], L.dual()) [L*(0, 1), L*(0, 1), L*(3, 2), L*(3, 14)] sage: ray_in_L = L(0,1) sage: normalize_rays([ray_in_L, (0, 2), (3, 2), (5/7, 10/3)], None) [L(0, 1), L(0, 1), L(3, 2), L(3, 14)] sage: normalize_rays([(0, 1), (0, 2), (3, 2), (5/7, 10/3)], ZZ^2) [(0, 1), (0, 1), (3, 2), (3, 14)] sage: normalize_rays([(0, 1), (0, 2), (3, 2), (5/7, 10/3)], ZZ^3) Traceback (most recent call last): ... TypeError: cannot convert (0, 1) to Vector space of dimension 3 over Rational Field! sage: normalize_rays([], ZZ^3) []