Rational polyhedral fans

This module was designed as a part of the framework for toric varieties (toric_variety, fano_toric_variety). While the emphasis is on complete full-dimensional fans, arbitrary fans are supported. Work with distinct lattices. The default lattice is ToricLattice N of the appropriate dimension. The only case when you must specify lattice explicitly is creation of a 0-dimensional fan, where dimension of the ambient space cannot be guessed.

A rational polyhedral fan is a finite collection of strictly convex rational polyhedral cones, such that the intersection of any two cones of the fan is a face of each of them and each face of each cone is also a cone of the fan.

AUTHORS:

  • Andrey Novoseltsev (2010-05-15): initial version.
  • Andrey Novoseltsev (2010-06-17): substantial improvement during review by Volker Braun.

EXAMPLES:

Use Fan() to construct fans “explicitly”:

sage: fan = Fan(cones=[(0,1), (1,2)],
...             rays=[(1,0), (0,1), (-1,0)])
sage: fan
Rational polyhedral fan in 2-d lattice N

In addition to giving such lists of cones and rays you can also create cones first using Cone() and then combine them into a fan. See the documentation of Fan() for details.

Instead of building a fan from scratch, for this tutorial we will use an easy way to get two fans assosiated to lattice polytopes: FaceFan() and NormalFan():

sage: fan1 = FaceFan(lattice_polytope.octahedron(3))
sage: fan2 = NormalFan(lattice_polytope.octahedron(3))

Given such “automatic” fans, you may wonder what are their rays and cones:

sage: fan1.rays()
(N(1, 0, 0), N(0, 1, 0), N(0, 0, 1),
 N(-1, 0, 0), N(0, -1, 0), N(0, 0, -1))
sage: fan1.ray_matrix()
[ 1  0  0 -1  0  0]
[ 0  1  0  0 -1  0]
[ 0  0  1  0  0 -1]
sage: fan1.generating_cones()
(3-d cone of Rational polyhedral fan in 3-d lattice N,
 3-d cone of Rational polyhedral fan in 3-d lattice N,
 3-d cone of Rational polyhedral fan in 3-d lattice N,
 3-d cone of Rational polyhedral fan in 3-d lattice N,
 3-d cone of Rational polyhedral fan in 3-d lattice N,
 3-d cone of Rational polyhedral fan in 3-d lattice N,
 3-d cone of Rational polyhedral fan in 3-d lattice N,
 3-d cone of Rational polyhedral fan in 3-d lattice N)

The last output is not very illuminating. Let’s try to improve it:

sage: for cone in fan1: print cone.rays()
(N(1, 0, 0), N(0, 1, 0), N(0, 0, -1))
(N(0, 1, 0), N(-1, 0, 0), N(0, 0, -1))
(N(1, 0, 0), N(0, -1, 0), N(0, 0, -1))
(N(-1, 0, 0), N(0, -1, 0), N(0, 0, -1))
(N(1, 0, 0), N(0, 1, 0), N(0, 0, 1))
(N(0, 1, 0), N(0, 0, 1), N(-1, 0, 0))
(N(1, 0, 0), N(0, 0, 1), N(0, -1, 0))
(N(0, 0, 1), N(-1, 0, 0), N(0, -1, 0))

You can also do

sage: for cone in fan1: print cone.ambient_ray_indices()
(0, 1, 5)
(1, 3, 5)
(0, 4, 5)
(3, 4, 5)
(0, 1, 2)
(1, 2, 3)
(0, 2, 4)
(2, 3, 4)

to see indices of rays of the fan corresponding to each cone.

While the above cycles were over “cones in fan”, it is obvious that we did not get ALL the cones: every face of every cone in a fan must also be in the fan, but all of the above cones were of dimension three. The reason for this behaviour is that in many cases it is enough to work with generating cones of the fan, i.e. cones which are not faces of bigger cones. When you do need to work with lower dimensional cones, you can easily get access to them using cones():

sage: [cone.ambient_ray_indices() for cone in fan1.cones(2)]
[(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (0, 4), 
 (2, 4), (3, 4), (1, 5), (3, 5), (4, 5), (0, 5)]

In fact, you don’t have to type .cones:

sage: [cone.ambient_ray_indices() for cone in fan1(2)]
[(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (0, 4),
 (2, 4), (3, 4), (1, 5), (3, 5), (4, 5), (0, 5)]

You may also need to know the inclusion relations between all of the cones of the fan. In this case check out cone_lattice():

sage: L = fan1.cone_lattice()
sage: L
Finite poset containing 28 elements
sage: L.bottom()
0-d cone of Rational polyhedral fan in 3-d lattice N
sage: L.top()
Rational polyhedral fan in 3-d lattice N
sage: cone = L.level_sets()[2][0]
sage: cone
2-d cone of Rational polyhedral fan in 3-d lattice N
sage: L.hasse_diagram().neighbors(cone)
[3-d cone of Rational polyhedral fan in 3-d lattice N,
 3-d cone of Rational polyhedral fan in 3-d lattice N,
 1-d cone of Rational polyhedral fan in 3-d lattice N,
 1-d cone of Rational polyhedral fan in 3-d lattice N]

Note, that while cone above seems to be a “cone”, it is not:

sage: cone.rays()
Traceback (most recent call last):
...
AttributeError: 'PosetElement' object has no attribute 'rays'

To get your hands on the “real” cone, you need to do one more step:

sage: cone = cone.element
sage: cone.rays()
(N(1, 0, 0), N(0, 1, 0))

You can check how “good” a fan is:

sage: fan1.is_complete()
True
sage: fan1.is_simplicial()
True
sage: fan1.is_smooth()
True

The face fan of the octahedron is really good! Time to remember that we have also constructed its normal fan:

sage: fan2.is_complete()
True
sage: fan2.is_simplicial()
False
sage: fan2.is_smooth()
False

This one does have some “problems,” but we can fix them:

sage: fan3 = fan2.make_simplicial()
sage: fan3.is_simplicial()
True
sage: fan3.is_smooth()
False

Note that we had to save the result of make_simplicial() in a new fan. Fans in Sage are immutable, so any operation that does change them constructs a new fan.

We can also make fan3 smooth, but it will take a bit more work:

sage: cube = lattice_polytope.octahedron(3).polar()
sage: sk = cube.skeleton_points(2)
sage: rays = [cube.point(p) for p in sk]
sage: fan4 = fan3.subdivide(new_rays=rays)
sage: fan4.is_smooth()
True

Let’s see how “different” are fan2 and fan4:

sage: fan2.ngenerating_cones()
6
sage: fan2.nrays()
8
sage: fan4.ngenerating_cones()
48
sage: fan4.nrays()
26

Smoothness does not come for free!

Please take a look at the rest of the available functions below and their complete descriptions. If you need any features that are missing, feel free to suggest them. (Or implement them on your own and submit a patch to Sage for inclusion!)

class sage.geometry.fan.Cone_of_fan(ambient, ambient_ray_indices)

Bases: sage.geometry.cone.ConvexRationalPolyhedralCone

Construct a cone belonging to a fan.

Warning

This class does not check that the input defines a valid cone of a fan. You must not construct objects of this class directly.

In addition to all of the properties of “regular” cones, such cones know their relation to the fan.

INPUT:

  • ambient – fan whose cone is constructed;
  • ambient_ray_indices – increasing list or tuple of integers, indices of rays of ambient generating this cone.

OUTPUT:

  • cone of ambient.

EXAMPLES:

The intended way to get objects of this class is the following:

sage: P1xP1 = FaceFan(lattice_polytope.octahedron(2))
sage: cone = P1xP1.generating_cone(0)
sage: cone
2-d cone of Rational polyhedral fan in 2-d lattice N
sage: cone.ambient_ray_indices()
(0, 3)
sage: cone.star_generator_indices()
(0,)
star_generator_indices()

Return indices of generating cones of the “ambient fan” containing self.

OUTPUT:

  • increasing tuple of integers.

EXAMPLES:

sage: P1xP1 = FaceFan(lattice_polytope.octahedron(2))
sage: cone = P1xP1.generating_cone(0)
sage: cone.star_generator_indices()
(0,)

TESTS:

A mistake in this function used to cause the problem reported in Trac 9782. We check that now everything is working smoothly:

sage: f = Fan([(0, 2, 4),
...            (0, 4, 5),
...            (0, 3, 5),
...            (0, 1, 3),
...            (0, 1, 2),
...            (2, 4, 6),
...            (4, 5, 6),
...            (3, 5, 6),
...            (1, 3, 6),
...            (1, 2, 6)],
...           [(-1, 0, 0),
...            (0, -1, 0),
...            (0, 0, -1), 
...            (0, 0, 1),
...            (0, 1, 2),
...            (0, 1, 3),
...            (1, 0, 4)])
sage: f.is_complete()
True
sage: X = ToricVariety(f)
sage: X.fan().is_complete()
True
star_generators()

Return indices of generating cones of the “ambient fan” containing self.

OUTPUT:

  • increasing tuple of integers.

EXAMPLES:

sage: P1xP1 = FaceFan(lattice_polytope.octahedron(2))
sage: cone = P1xP1.generating_cone(0)
sage: cone.star_generators()
(2-d cone of Rational polyhedral fan in 2-d lattice N,)
sage.geometry.fan.FaceFan(polytope, lattice=None)

Construct the face fan of the given lattice polytope.

INPUT:

  • polytopelattice polytope;
  • latticeToricLattice, \ZZ^n, or any other object that behaves like these. If not specified, an attempt will be made to determine an appropriate toric lattice automatically.

OUTPUT:

See also NormalFan().

EXAMPLES:

Let’s construct the fan corresponding to the product of two projective lines:

sage: diamond = lattice_polytope.octahedron(2)
sage: P1xP1 = FaceFan(diamond)
sage: P1xP1.ray_matrix()
[ 1  0 -1  0]
[ 0  1  0 -1]
sage: for cone in P1xP1: print cone.rays()
(N(1, 0), N(0, -1))
(N(-1, 0), N(0, -1))
(N(1, 0), N(0, 1))
(N(0, 1), N(-1, 0))
sage.geometry.fan.Fan(cones, rays=None, lattice=None, check=True, normalize=True, is_complete=None, discard_warning=True)

Construct a rational polyhedral fan.

Note

Approximate time to construct a fan consisting of n cones is n^2/5 seconds. That is half an hour for 100 cones. This time can be significantly reduced in the future, but it is still likely to be \sim n^2 (with, say, /500 instead of /5). If you know that your input does form a valid fan, use check=False option to skip consistency checks.

INPUT:

  • cones – list of either Cone objects or lists of integers interpreted as indices of generating rays in rays;
  • rays – list of rays given as list or vectors convertible to the rational extension of lattice. If cones are given by Cone objects rays may be determined automatically. You still may give them explicitly to ensure a particular order of rays in the fan. In this case you must list all rays that appear in cones. You can give “extra” ones if it is convenient (e.g. if you have a big list of rays for several fans), but all “extra” rays will be discarded;
  • latticeToricLattice, \ZZ^n, 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 intersection of any two given cones is a face of each) and generating cones will be selected. If you know for sure that the input is the set of generating cones of a fan, you may significantly decrease construction time using check=False option;
  • normalize – you can further speed up construction using normalize=False option. In this case cones must be a list of sorted tuples and rays must be immutable primitive vectors in lattice. 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;
  • is_complete – every fan can determine on its own if it is complete or not, however it can take quite a bit of time for “big” fans with many generating cones. On the other hand, in some situations it is known in advance that a certain fan is complete. In this case you can pass is_complete=True option to speed up some computations. You may also pass is_complete=False option, although it is less likely to be beneficial. Of course, passing a wrong value can compromise the integrity of data structures of the fan and lead to wrong results, so you should be very careful if you decide to use this option;
  • discard_warning – by default, the fan constructor will show a warning the first time you try to construct a fan from non-generating cones, in which case some of them will be automatically discarded. If you are writing a code where it is reasonable to expect extra cones as input, you may pass discard_warning=False option to suppress this warning.

OUTPUT:

EXAMPLES:

Let’s construct a fan corresponding to the projective plane in several ways:

sage: cone1 = Cone([(1,0), (0,1)])
sage: cone2 = Cone([(0,1), (-1,-1)])
sage: cone3 = Cone([(-1,-1), (1,0)])
sage: P2 = Fan([cone1, cone2, cone2]) # random output (warning)
sage: P2.ngenerating_cones()
2

Oops! There was a typo and the second cone2 got discarded (you will actually see a warning the first time you do such a thing yourself, i.e. provide a non-minimal generating set of cones of a fan). Let’s fix it:

sage: P2 = Fan([cone1, cone2, cone3])
sage: P2.ngenerating_cones()
3

Looks better. An alternative way is

sage: rays = [(1,0), (0,1), (-1,-1)]
sage: cones = [(0,1), (1,2), (2,0)]
sage: P2a = Fan(cones, rays)
sage: P2a.ngenerating_cones()
3
sage: P2 == P2a
False

That may seem wrong, but it is not:

sage: P2.is_equivalent(P2a)
True

See is_equivalent() for details.

Yet another way to construct this fan is

sage: P2b = Fan(cones, rays, check=False)
sage: P2b.ngenerating_cones()
3
sage: P2a == P2b
True

If you try the above examples, you are likely to notice the difference in speed, so when you are sure that everything is correct, it is a good idea to use check=False option. On the other hand, it is usually NOT a good idea to use normalize=False option:

sage: P2c = Fan(cones, rays, check=False, normalize=False)
Traceback (most recent call last):
...
AttributeError: 'tuple' object has no attribute 'parent'

Yet another way is to use functions FaceFan() and NormalFan() to construct fans from lattice polytopes.

We have not yet used lattice argument, since if was determined automatically:

sage: P2.lattice()
2-d lattice N
sage: P2b.lattice()
2-d lattice N

However, it is necessary to specify it explicitly if you want to construct a fan without rays or cones:

sage: Fan([], [])
Traceback (most recent call last):
...
ValueError: you must specify the lattice
when you construct a fan without rays and cones!
sage: F = Fan([], [], lattice=ToricLattice(2, "L"))
sage: F
Rational polyhedral fan in 2-d lattice L
sage: F.lattice_dim()
2
sage: F.dim()
0
sage.geometry.fan.NormalFan(polytope, lattice=None)

Construct the normal fan of the given lattice polytope.

INPUT:

  • polytopelattice polytope;
  • latticeToricLattice, \ZZ^n, or any other object that behaves like these. If not specified, an attempt will be made to determine an appropriate toric lattice automatically.

OUTPUT:

See also FaceFan().

EXAMPLES:

Let’s construct the fan corresponding to the product of two projective lines:

sage: square = lattice_polytope.octahedron(2).polar()
sage: P1xP1 = NormalFan(square)
sage: P1xP1.ray_matrix()
[ 1  0 -1  0]
[ 0  1  0 -1]
sage: for cone in P1xP1: print cone.rays()
(N(1, 0), N(0, -1))
(N(-1, 0), N(0, -1))
(N(1, 0), N(0, 1))
(N(0, 1), N(-1, 0))
class sage.geometry.fan.RationalPolyhedralFan(cones, rays, lattice, is_complete=None)

Bases: sage.geometry.cone.IntegralRayCollection, _abcoll.Callable, _abcoll.Container

Create a rational polyhedral fan.

Warning

This class does not perform any checks of correctness of input nor does it convert input into the standard representation. Use Fan() to construct fans from “raw data” or FaceFan() and NormalFan() to get fans associated to polytopes.

Fans are immutable, but they cache most of the returned values.

INPUT:

  • cones – list of generating cones of the fan, each cone given as a list of indices of its generating rays in rays;
  • rays – list of immutable primitive vectors in lattice consisting of exactly the rays of the fan (i.e. no “extra” ones);
  • latticeToricLattice, \ZZ^n, or any other object that behaves like these. If None, it will be determined as parent() of the first ray. Of course, this cannot be done if there are no rays, so in this case you must give an appropriate lattice directly.
  • is_complete – if given, must be True or False depending on whether this fan is complete or not. By default, it will be determined automatically if necessary.

OUTPUT:

  • rational polyhedral fan.
Gale_transform()

Return the Gale transform of self.

OUTPUT:

A matrix over ZZ.

EXAMPLES:

sage: fan = FaceFan(lattice_polytope.octahedron(2))
sage: fan.Gale_transform()
[ 1  0  1  0 -2]
[ 0  1  0  1 -2]
sage: _.base_ring()
Integer Ring
Stanley_Reisner_ideal(ring)

Return the Stanley-Reisner ideal.

INPUT:

  • A polynomial ring in self.nrays() variables.

OUTPUT:

  • The Stanley-Reisner ideal in the given polynomial ring.

EXAMPLES:

sage: fan = Fan([[0,1,3],[3,4],[2,0],[1,2,4]], [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)])
sage: fan.Stanley_Reisner_ideal( PolynomialRing(QQ,5,'A, B, C, D, E') )
Ideal (A*E, C*D, A*B*C, B*D*E) of Multivariate Polynomial Ring in A, B, C, D, E over Rational Field
cartesian_product(other, lattice=None)

Return the Cartesian product of self with other.

INPUT:

  • other – a rational polyhedral fan;
  • lattice – (optional) the ambient lattice for the Cartesian product fan. By default, the direct sum of the ambient lattices of self and other is constructed.

OUTPUT:

  • a fan whose cones are all pairwise Cartesian products of the cones of self and other.

EXAMPLES:

sage: K = ToricLattice(1, 'K')
sage: fan1 = Fan([[0],[1]],[(1,),(-1,)], lattice=K)
sage: L = ToricLattice(2, 'L')
sage: fan2 = Fan(rays=[(1,0),(0,1),(-1,-1)],
...          cones=[[0,1],[1,2],[2,0]], lattice=L)
sage: fan1.cartesian_product(fan2)
Rational polyhedral fan in 3-d lattice K+L
sage: _.ngenerating_cones()
6
cone_containing(*points)

Return the smallest cone of self containing all given points.

INPUT:

  • either one or more indices of rays of self, or one or more objects representing points of the ambient space of self, or a list of such objects (you CANNOT give a list of indices).

OUTPUT:

Note

We think of the origin as of the smallest cone containing no rays at all. If there is no ray in self that contains all rays, a ValueError exception will be raised.

EXAMPLES:

sage: cone1 = Cone([(0,-1), (1,0)])
sage: cone2 = Cone([(1,0), (0,1)])
sage: f = Fan([cone1, cone2])
sage: f.rays()
(N(0, 1), N(0, -1), N(1, 0))
sage: f.cone_containing(0)  # ray index
1-d cone of Rational polyhedral fan in 2-d lattice N
sage: f.cone_containing(0, 1) # ray indices
Traceback (most recent call last):
...
ValueError: there is no cone in
Rational polyhedral fan in 2-d lattice N
containing all of the given rays! Rays: (N(0, 1), N(0, -1))
sage: f.cone_containing(0, 2) # ray indices
2-d cone of Rational polyhedral fan in 2-d lattice N
sage: f.cone_containing((0,1))  # point
1-d cone of Rational polyhedral fan in 2-d lattice N
sage: f.cone_containing([(0,1)]) # point
1-d cone of Rational polyhedral fan in 2-d lattice N
sage: f.cone_containing((1,1))
2-d cone of Rational polyhedral fan in 2-d lattice N
sage: f.cone_containing((1,1), (1,0))
2-d cone of Rational polyhedral fan in 2-d lattice N
sage: f.cone_containing()
0-d cone of Rational polyhedral fan in 2-d lattice N
sage: f.cone_containing((0,0))
0-d cone of Rational polyhedral fan in 2-d lattice N
sage: f.cone_containing((-1,1))
Traceback (most recent call last):
...
ValueError: there is no cone in
Rational polyhedral fan in 2-d lattice N
containing all of the given points! Points: [N(-1, 1)]

TESTS:

sage: fan = Fan(cones=[(0,1,2,3), (0,1,4)],
...       rays=[(1,1,1), (1,-1,1), (1,-1,-1), (1,1,-1), (0,0,1)])
sage: fan.cone_containing(0).rays()
(N(1, 1, 1),)
cone_lattice()

Return the cone lattice of self.

This lattice will have the origin as the bottom (we do not include the empty set as a cone) and the fan itself as the top.

OUTPUT:

  • finite poset <sage.combinat.posets.posets.FinitePoset of cones of fan, behaving like “regular” cones, but also containing the information about their relation to this fan, namely, the contained rays and containing generating cones. The top of the lattice will be this fan itself (which is not a cone of fan).

See also cones().

EXAMPLES:

Cone lattices can be computed for arbitrary fans:

sage: cone1 = Cone([(1,0), (0,1)])
sage: cone2 = Cone([(-1,0)])
sage: fan = Fan([cone1, cone2])
sage: fan.ray_matrix()
[ 0  1 -1]
[ 1  0  0]
sage: for cone in fan: print cone.ambient_ray_indices()
(0, 1)
(2,)
sage: L = fan.cone_lattice()
sage: L
Finite poset containing 6 elements

These 6 elements are the origin, three rays, one two-dimensional cone, and the fan itself. Since we do add the fan itself as the largest face, you should be a little bit careful with this last element:

sage: for face in L: print face.element.ambient_ray_indices()
Traceback (most recent call last):
...
AttributeError: 'RationalPolyhedralFan'
object has no attribute 'ambient_ray_indices'
sage: L.top()
Rational polyhedral fan in 2-d lattice N

For example, you can do

sage: for l in L.level_sets()[:-1]:
...       print [f.element.ambient_ray_indices() for f in l]
[()]
[(0,), (1,), (2,)]
[(0, 1)]

If the fan is complete, its cone lattice is atomic and coatomic and can (and will!) be computed in a much more efficient way, but the interface is exactly the same:

sage: fan = FaceFan(lattice_polytope.octahedron(2))
sage: L = fan.cone_lattice()
sage: for l in L.level_sets()[:-1]:
...       print [f.element.ambient_ray_indices() for f in l]
[()]
[(0,), (1,), (2,), (3,)]
[(0, 1), (1, 2), (0, 3), (2, 3)]

Let’s also consider the cone lattice of a fan generated by a single cone:

sage: fan = Fan([cone1])
sage: L = fan.cone_lattice()
sage: L
Finite poset containing 5 elements

Here these 5 elements correspond to the origin, two rays, one generating cone of dimension two, and the whole fan. While this single cone “is” the whole fan, it is consistent and convenient to distinguish them in the cone lattice.

cones(dim=None, codim=None)

Return the specified cones of self.

INPUT:

  • dim – dimension of the requested cones;
  • codim – codimension of the requested cones.

Note

You can specify at most one input parameter.

OUTPUT:

  • tuple of cones of self of the specified (co)dimension, if either dim or codim is given. Otherwise tuple of such tuples for all existing dimensions.

EXAMPLES:

sage: cone1 = Cone([(1,0), (0,1)])
sage: cone2 = Cone([(-1,0)])
sage: fan = Fan([cone1, cone2])
sage: fan(dim=0)
(0-d cone of Rational polyhedral fan in 2-d lattice N,)
sage: fan(codim=2)
(0-d cone of Rational polyhedral fan in 2-d lattice N,)
sage: for cone in fan.cones(1): cone.ray(0)
N(0, 1)
N(1, 0)
N(-1, 0)
sage: fan.cones(2)
(2-d cone of Rational polyhedral fan in 2-d lattice N,)

You cannot specify both dimension and codimension, even if they “agree”:

sage: fan(dim=1, codim=1)
Traceback (most recent call last):
...
ValueError: dimension and codimension
cannot be specified together!

But it is OK to ask for cones of too high or low (co)dimension:

sage: fan(-1)
()
sage: fan(3)
()
sage: fan(codim=4)
()
contains(cone)

Check if a given cone is equivalent to a cone of the fan.

INPUT:

  • cone – anything.

OUTPUT:

  • False if cone is not a cone or if cone is not equivalent to a cone of the fan. True otherwise.

Note

Recall that a fan is a (finite) collection of cones. A cone is contained in a fan if it is equivalent to one of the cones of the fan. In particular, it is possible that all rays of the cone are in the fan, but the cone itself is not.

If you want to know whether a point is in the support of the fan, you should use support_contains().

EXAMPLES:

We first construct a simple fan:

sage: cone1 = Cone([(0,-1), (1,0)])
sage: cone2 = Cone([(1,0), (0,1)])
sage: f = Fan([cone1, cone2])

Now we check if some cones are in this fan. First, we make sure that the order of rays of the input cone does not matter (check=False option ensures that rays of these cones will be listed exactly as they are given):

sage: f.contains(Cone([(1,0), (0,1)], check=False))
True
sage: f.contains(Cone([(0,1), (1,0)], check=False))
True

Now we check that a non-generating cone is in our fan:

sage: f.contains(Cone([(1,0)]))
True
sage: Cone([(1,0)]) in f   # equivalent to the previous command
True

Finally, we test some cones which are not in this fan:

sage: f.contains(Cone([(1,1)]))
False
sage: f.contains(Cone([(1,0), (-0,1)]))
True

A point is not a cone:

sage: n = f.lattice()(1,1); n
N(1, 1)
sage: f.contains(n)
False
embed(cone)

Return the cone equivalent to the given one, but sitting in self.

You may need to use this method before calling methods of cone that depend on the ambient structure, such as ambient_ray_indices() or facet_of(). The cone returned by this method will have self as ambient. If cone does not represent a valid cone of self, ValueError exception is raised.

Note

This method is very quick if self is already the ambient structure of cone, so you can use without extra checks and performance hit even if cone is likely to sit in self but in principle may not.

INPUT:

OUTPUT:

  • a cone of fan, equivalent to cone but sitting inside self.

EXAMPLES:

Let’s take a 3-d fan generated by a cone on 4 rays:

sage: f = Fan([Cone([(1,0,1), (0,1,1), (-1,0,1), (0,-1,1)])])

Then any ray generates a 1-d cone of this fan, but if you construct such a cone directly, it will not “sit” inside the fan:

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 part of the fan, we need to embed it first:

sage: e_ray = f.embed(ray)
sage: e_ray
1-d cone of Rational polyhedral fan in 3-d lattice N
sage: e_ray.rays()
(N(0, -1, 1),)
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 cone of Rational polyhedral fan in 3-d lattice N,
 1-d cone of Rational polyhedral fan in 3-d lattice N)
sage: e_ray.ambient()
Rational polyhedral fan in 3-d lattice N

Not every cone can be embedded into a fixed fan:

sage: f.embed(Cone([(0,0,1)]))
Traceback (most recent call last):
...
ValueError: 1-d cone in 3-d lattice N does not belong
to Rational polyhedral fan in 3-d lattice N!
sage: f.embed(Cone([(1,0,1), (-1,0,1)]))
Traceback (most recent call last):
...
ValueError: 2-d cone in 3-d lattice N does not belong
to Rational polyhedral fan in 3-d lattice N!
generating_cone(n)

Return the n-th generating cone of self.

INPUT:

  • n – integer, the index of a generating cone.

OUTPUT:

EXAMPLES:

sage: fan = FaceFan(lattice_polytope.octahedron(2))
sage: fan.generating_cone(0)
2-d cone of Rational polyhedral fan in 2-d lattice N
generating_cones()

Return generating cones of self.

OUTPUT:

EXAMPLES:

sage: fan = FaceFan(lattice_polytope.octahedron(2))
sage: fan.generating_cones()
(2-d cone of Rational polyhedral fan in 2-d lattice N,
 2-d cone of Rational polyhedral fan in 2-d lattice N,
 2-d cone of Rational polyhedral fan in 2-d lattice N,
 2-d cone of Rational polyhedral fan in 2-d lattice N)
sage: cone1 = Cone([(1,0), (0,1)])
sage: cone2 = Cone([(-1,0)])
sage: fan = Fan([cone1, cone2])
sage: fan.generating_cones()
(2-d cone of Rational polyhedral fan in 2-d lattice N,
 1-d cone of Rational polyhedral fan in 2-d lattice N)
is_complete()

Check if self is complete.

A rational polyhedral fan is complete if its cones fill the whole space.

OUTPUT:

  • True if self is complete and False otherwise.

EXAMPLES:

sage: fan = FaceFan(lattice_polytope.octahedron(2))
sage: fan.is_complete()
True
sage: cone1 = Cone([(1,0), (0,1)])
sage: cone2 = Cone([(-1,0)])
sage: fan = Fan([cone1, cone2])
sage: fan.is_complete()
False
is_equivalent(other)

Check if self is “mathematically” the same as other.

INPUT:

  • other - fan.

OUTPUT:

  • True if self and other define the same fans as collections of equivalent cones in the same lattice, False otherwise.

There are three different equivalences between fans F_1 and F_2 in the same lattice:

  1. They have the same rays in the same order and the same generating cones in the same order. This is tested by F1 == F2.
  2. They have the same rays and the same generating cones without taking into account any order. This is tested by F1.is_equivalent(F2).
  3. They are in the same orbit of GL(n,\ZZ) (and, therefore, correspond to isomorphic toric varieties). This is tested by F1.is_isomorphic(F2).

EXAMPLES:

sage: fan1 = Fan(cones=[(0,1), (1,2)],
...              rays=[(1,0), (0,1), (-1,-1)],
...              check=False)
sage: fan2 = Fan(cones=[(2,1), (0,2)],
...              rays=[(1,0), (-1,-1), (0,1)],
...              check=False)
sage: fan3 = Fan(cones=[(0,1), (1,2)],
...              rays=[(1,0), (0,1), (-1,1)],
...              check=False)
sage: fan1 == fan2
False
sage: fan1.is_equivalent(fan2)
True
sage: fan1 == fan3
False
sage: fan1.is_equivalent(fan3)
False
is_isomorphic(other)

Check if self is in the same GL(n, \ZZ)-orbit as other.

INPUT:

  • other - fan.

OUTPUT:

  • True if self and other are in the same GL(n, \ZZ)-orbit, False otherwise.

There are three different equivalences between fans F_1 and F_2 in the same lattice:

  1. They have the same rays in the same order and the same generating cones in the same order. This is tested by F1 == F2.
  2. They have the same rays and the same generating cones without taking into account any order. This is tested by F1.is_equivalent(F2).
  3. They are in the same orbit of GL(n,\ZZ) (and, therefore, correspond to isomorphic toric varieties). This is tested by F1.is_isomorphic(F2).

EXAMPLES:

These fans are “mirrors” of each other:

sage: fan1 = Fan(cones=[(0,1), (1,2)],
...              rays=[(1,0), (0,1), (-1,-1)],
...              check=False)
sage: fan2 = Fan(cones=[(0,1), (1,2)],
...              rays=[(1,0), (0,-1), (-1,1)],
...              check=False)
sage: fan1 == fan2
False
sage: fan1.is_equivalent(fan2)
False
sage: fan1.is_isomorphic(fan2)
Traceback (most recent call last):
...
NotImplementedError: fan isomorphism is not implemented yet!
is_simplicial()

Check if self is simplicial.

A rational polyhedral fan is simplicial if all of its cones are, i.e. primitive vectors along generating rays of every cone form a part of a rational basis of the ambient space.

OUTPUT:

  • True if self is simplicial and False otherwise.

EXAMPLES:

sage: fan = FaceFan(lattice_polytope.octahedron(2))
sage: fan.is_simplicial()
True
sage: cone1 = Cone([(1,0), (0,1)])
sage: cone2 = Cone([(-1,0)])
sage: fan = Fan([cone1, cone2])
sage: fan.is_simplicial()
True

In fact, any fan in a two-dimensional ambient space is simplicial. This is no longer the case in dimension three:

sage: fan = NormalFan(lattice_polytope.octahedron(3))
sage: fan.is_simplicial()
False
sage: fan.generating_cone(0).nrays()
4
is_smooth()

Check if self is smooth.

A rational polyhedral fan is smooth if all of its cones are, i.e. primitive vectors along generating rays of every cone form a part of an integral basis of the ambient space. (In this case the corresponding toric variety is smooth.)

OUTPUT:

  • True if self is smooth and False otherwise.

EXAMPLES:

sage: fan = FaceFan(lattice_polytope.octahedron(2))
sage: fan.is_smooth()
True
sage: cone1 = Cone([(1,0), (0,1)])
sage: cone2 = Cone([(-1,0)])
sage: fan = Fan([cone1, cone2])
sage: fan.is_smooth()
True
sage: fan = NormalFan(lattice_polytope.octahedron(2))
sage: fan.is_smooth()
False
sage: fan.generating_cone(0).rays()
(N(-1, 1), N(-1, -1))
sage: fan.generating_cone(0).ray_matrix().det()
2
linear_equivalence_ideal(ring)

Return the ideal generated by linear relations

INPUT:

  • A polynomial ring in self.nrays() variables.

OUTPUT:

Returns the ideal, in the given ring, generated by the linear relations of the rays. In toric geometry, this corresponds to rational equivalence of divisors.

EXAMPLES:

sage: fan = Fan([[0,1,3],[3,4],[2,0],[1,2,4]], [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)])
sage: fan.linear_equivalence_ideal( PolynomialRing(QQ,5,'A, B, C, D, E') )
Ideal (-3*A + 3*C - D + E, -2*A - 2*C - D - E, A + B + C + D + E) of Multivariate Polynomial Ring in A, B, C, D, E over Rational Field
make_simplicial(**kwds)

Construct a simplicial fan subdividing self.

It is a synonym for subdivide() with make_simplicial=True option.

INPUT:

  • this functions accepts only keyword arguments. See subdivide() for documentation.

OUTPUT:

EXAMPLES:

sage: fan = NormalFan(lattice_polytope.octahedron(3))
sage: fan.is_simplicial()
False
sage: fan.ngenerating_cones()
6
sage: new_fan = fan.make_simplicial()
sage: new_fan.is_simplicial()
True
sage: new_fan.ngenerating_cones()
12
ngenerating_cones()

Return the number of generating cones of self.

OUTPUT:

  • integer.

EXAMPLES:

sage: fan = FaceFan(lattice_polytope.octahedron(2))
sage: fan.ngenerating_cones()
4
sage: cone1 = Cone([(1,0), (0,1)])
sage: cone2 = Cone([(-1,0)])
sage: fan = Fan([cone1, cone2])
sage: fan.ngenerating_cones()
2
plot(**options)

Plot self.

INPUT:

OUTPUT:

  • a plot.

EXAMPLES:

sage: fan = toric_varieties.dP6().fan()
sage: fan.plot()
primitive_collections()

Return the primitive collections.

OUTPUT:

Returns the subsets \{i_1,\dots,i_k\} \subset \{ 1,\dots,n\} such that

  • The points \{p_{i_1},\dots,p_{i_k}\} do not span a cone of the fan.
  • If you remove any one p_{i_j} from the set, then they do span a cone of the fan.

Note

By replacing the multiindices \{i_1,\dots,i_k\} of each primitive collection with the monomials x_{i_1}\cdots
x_{i_k} one generates the Stanley-Reisner ideal in \ZZ[x_1,\dots].

REFERENCES:

V.V. Batyrev, On the classification of smooth projective toric varieties, Tohoku Math.J. 43 (1991), 569-585

EXAMPLES:

sage: fan = Fan([[0,1,3],[3,4],[2,0],[1,2,4]], [(-3, -2, 1), (0, 0, 1), (3, -2, 1), (-1, -1, 1), (1, -1, 1)])
sage: fan.primitive_collections()
[frozenset([0, 4]), frozenset([2, 3]), frozenset([0, 1, 2]), frozenset([1, 3, 4])]
subdivide(new_rays=None, make_simplicial=False, algorithm='default', verbose=False)

Construct a new fan subdividing self.

INPUT:

  • new_rays - list of new rays to be added during subdivision, each ray must be a list or a vector. May be empty or None (default);
  • make_simplicial - if True, the returned fan is guaranteed to be simplicial, default is False;
  • algorithm - string with the name of the algorithm used for subdivision. Currently there is only one available algorithm called “default”;
  • verbose - if True, some timing information may be printed during the process of subdivision.

OUTPUT:

Currently the “default” algorithm corresponds to iterative stellar subdivison for each ray in new_rays.

EXAMPLES:

sage: fan = NormalFan(lattice_polytope.octahedron(3))
sage: fan.is_simplicial()
False
sage: fan.ngenerating_cones()
6
sage: fan.nrays()
8
sage: new_fan = fan.subdivide(new_rays=[(1,0,0)])
sage: new_fan.is_simplicial()
False
sage: new_fan.ngenerating_cones()
9
sage: new_fan.nrays()
9
support_contains(*args)

Check if a point is contained in the support of the fan.

The support of a fan is the union of all cones of the fan. If you want to know whether the fan contains a given cone, you should use contains() instead.

INPUT:

  • *args – an element of self.lattice() or something that can be converted to it (for example, a list of coordinates).

OUTPUT:

  • True if point is contained in the support of the fan, False otherwise.

TESTS:

sage: cone1 = Cone([(0,-1), (1,0)])
sage: cone2 = Cone([(1,0), (0,1)])
sage: f = Fan([cone1, cone2])

We check if some points are in this fan:

sage: f.support_contains(f.lattice()(1,0))
True
sage: f.support_contains(cone1)    # a cone is not a point of the lattice
False
sage: f.support_contains((1,0))
True
sage: f.support_contains(1,1)
True
sage: f.support_contains((-1,0))
False
sage: f.support_contains(f.lattice().dual()(1,0)) #random output (warning)
False
sage: f.support_contains(f.lattice().dual()(1,0))
False
sage: f.support_contains(1)
False
sage: f.support_contains(0)   # 0 converts to the origin in the lattice
True
sage: f.support_contains(1/2, sqrt(3))
True
sage: f.support_contains(-1/2, sqrt(3))
False
sage.geometry.fan.is_Fan(x)

Check if x is a Fan.

INPUT:

  • x – anything.

OUTPUT:

  • True if x is a fan and False otherwise.

EXAMPLES:

sage: from sage.geometry.fan import is_Fan
sage: is_Fan(1)
False
sage: fan = FaceFan(lattice_polytope.octahedron(2))
sage: fan
Rational polyhedral fan in 2-d lattice N
sage: is_Fan(fan)
True

Previous topic

Convex rational polyhedral cones

Next topic

Morphisms between toric lattices compatible with fans

This Page