This module is a part of the framework for toric varieties (toric_variety, fano_toric_variety). Its main purpose is to provide support for working with lattice morphisms compatible with fans via FanMorphism class.
AUTHORS:
EXAMPLES:
Let’s consider the face and normal fans of the “diamond” and the projection
to the -axis:
sage: diamond = lattice_polytope.octahedron(2)
sage: face = FaceFan(diamond)
sage: normal = NormalFan(diamond)
sage: N = face.lattice()
sage: H = End(N)
sage: phi = H([N.0, 0])
sage: phi
Free module morphism defined by the matrix
[1 0]
[0 0]
Domain: 2-d lattice N
Codomain: 2-d lattice N
sage: FanMorphism(phi, normal, face)
Traceback (most recent call last):
...
ValueError: the image of generating cone #1 of the domain fan
is not contained in a single cone of the codomain fan!
Some of the cones of the normal fan fail to be mapped to a single cone of the face fan. We can rectify the situation in the following way:
sage: fm = FanMorphism(phi, normal, face, subdivide=True)
sage: fm
Fan morphism defined by the matrix
[1 0]
[0 0]
Domain fan: Rational polyhedral fan in 2-d lattice N
Codomain fan: Rational polyhedral fan in 2-d lattice N
sage: fm.domain_fan().ray_matrix()
[-1 1 -1 1 0 0]
[ 1 1 -1 -1 -1 1]
sage: normal.ray_matrix()
[-1 1 -1 1]
[ 1 1 -1 -1]
As you see, it was necessary to insert two new rays (to prevent “upper” and
“lower” cones of the normal fan from being mapped to the whole -axis).
Bases: sage.modules.free_module_morphism.FreeModuleMorphism
Create a fan morphism.
Let and
be two fans in lattices
and
respectively. Let
be a morphism (i.e. a linear map) from
to
. We say that
is compatible with
and
if every cone
is mapped by
into a single cone
, i.e.
(
may be different for different
).
By a fan morphism we understand a morphism between two lattices compatible with specified fans in these lattices. Such morphisms behave in exactly the same way as “regular” morphisms between lattices, but:
INPUT:
OUTPUT:
EXAMPLES:
Here we consider the face and normal fans of the “diamond” and the
projection to the -axis:
sage: diamond = lattice_polytope.octahedron(2)
sage: face = FaceFan(diamond)
sage: normal = NormalFan(diamond)
sage: N = face.lattice()
sage: H = End(N)
sage: phi = H([N.0, 0])
sage: phi
Free module morphism defined by the matrix
[1 0]
[0 0]
Domain: 2-d lattice N
Codomain: 2-d lattice N
sage: fm = FanMorphism(phi, face, normal)
sage: fm.domain_fan() is face
True
Note, that since phi is compatible with these fans, the returned fan is exactly the same object as the initial domain_fan.
sage: FanMorphism(phi, normal, face)
Traceback (most recent call last):
...
ValueError: the image of generating cone #1 of the domain fan
is not contained in a single cone of the codomain fan!
sage: fm = FanMorphism(phi, normal, face, subdivide=True)
sage: fm.domain_fan() is normal
False
sage: fm.domain_fan().ngenerating_cones()
6
We had to subdivide two of the four cones of the normal fan, since they were mapped by phi into non-strictly convex cones.
It is possible to omit the codomain fan, in which case the image fan will be used instead of it:
sage: fm = FanMorphism(phi, face)
sage: fm.codomain_fan()
Rational polyhedral fan in 2-d lattice N
sage: fm.codomain_fan().ray_matrix()
[ 1 -1]
[ 0 0]
Now we demonstrate a more subtle example. We take the first quadrant as our domain fan. Then we divide the first quadrant into three cones, throw away the middle one and take the other two as our codomain fan. These fans are incompatible with the identity lattice morphism since the image of the domain fan is out of the support of the codomain fan:
sage: N = ToricLattice(2)
sage: phi = End(N).identity()
sage: F1 = Fan(cones=[(0,1)], rays=[(1,0), (0,1)])
sage: F2 = Fan(cones=[(0,1), (2,3)],
... rays=[(1,0), (2,1), (1,2), (0,1)])
sage: FanMorphism(phi, F1, F2)
Traceback (most recent call last):
...
ValueError: the image of generating cone #0 of the domain fan
is not contained in a single cone of the codomain fan!
sage: FanMorphism(phi, F1, F2, subdivide=True)
Traceback (most recent call last):
...
ValueError: morphism defined by
[1 0]
[0 1]
does not map
Rational polyhedral fan in 2-d lattice N
into the support of
Rational polyhedral fan in 2-d lattice N!
The problem was detected and handled correctly (i.e. an exception was raised). However, the used algorithm requires extra checks for this situation after constructing a potential subdivision and this can take significant time. You can save about half the time using check=False option, if you know in advance that it is possible to make fans compatible with the morphism by subdividing the domain fan. Of course, if your assumption was incorrect, the result will be wrong and you will get a fan which does map into the support of the codomain fan, but is not a subdivision of the domain fan. You can test it on the example above:
sage: fm = FanMorphism(phi, F1, F2, subdivide=True,
... check=False, verbose=True)
Placing ray images...
Computing chambers...
Subdividing cone 1 of 1...
sage: fm.domain_fan().is_equivalent(F2)
True
Return the codomain fan of self.
OUTPUT:
EXAMPLES:
sage: quadrant = Cone([(1,0), (0,1)])
sage: quadrant = Fan([quadrant])
sage: quadrant_bl = quadrant.subdivide([(1,1)])
sage: fm = FanMorphism(identity_matrix(2), quadrant_bl, quadrant)
sage: fm.codomain_fan()
Rational polyhedral fan in 2-d lattice N
sage: fm.codomain_fan() is quadrant
True
Return the codomain fan of self.
OUTPUT:
EXAMPLES:
sage: quadrant = Cone([(1,0), (0,1)])
sage: quadrant = Fan([quadrant])
sage: quadrant_bl = quadrant.subdivide([(1,1)])
sage: fm = FanMorphism(identity_matrix(2), quadrant_bl, quadrant)
sage: fm.domain_fan()
Rational polyhedral fan in 2-d lattice N
sage: fm.domain_fan() is quadrant_bl
True
Return the cone of the codomain fan containing the image of cone.
INPUT:
OUTPUT:
EXAMPLES:
sage: quadrant = Cone([(1,0), (0,1)])
sage: quadrant = Fan([quadrant])
sage: quadrant_bl = quadrant.subdivide([(1,1)])
sage: fm = FanMorphism(identity_matrix(2), quadrant_bl, quadrant)
sage: fm.image_cone(Cone([(1,0)]))
1-d cone of Rational polyhedral fan in 2-d lattice N
sage: fm.image_cone(Cone([(1,1)]))
2-d cone of Rational polyhedral fan in 2-d lattice N
TESTS:
We check that complete codomain fans are handled correctly, since a different algorithm is used in this case:
sage: diamond = lattice_polytope.octahedron(2)
sage: face = FaceFan(diamond)
sage: normal = NormalFan(diamond)
sage: N = face.lattice()
sage: fm = FanMorphism(identity_matrix(2),
... normal, face, subdivide=True)
sage: fm.image_cone(Cone([(1,0)]))
1-d cone of Rational polyhedral fan in 2-d lattice N
sage: fm.image_cone(Cone([(1,1)]))
2-d cone of Rational polyhedral fan in 2-d lattice N
Return cones of the domain fan whose image_cone() is cone.
INPUT:
OUTPUT:
EXAMPLES:
sage: quadrant = Cone([(1,0), (0,1)])
sage: quadrant = Fan([quadrant])
sage: quadrant_bl = quadrant.subdivide([(1,1)])
sage: fm = FanMorphism(identity_matrix(2), quadrant_bl, quadrant)
sage: fm.preimage_cones(Cone([(1,0)]))
(1-d cone of Rational polyhedral fan in 2-d lattice N,)
sage: fm.preimage_cones(Cone([(1,0), (0,1)]))
(1-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)
TESTS:
We check that reviewer’s example from Trac #9972 is handled correctly:
sage: N1 = ToricLattice(1)
sage: N2 = ToricLattice(2)
sage: Hom21 = Hom(N2, N1)
sage: pr = Hom21([N1.0,0])
sage: P1xP1 = toric_varieties.P1xP1()
sage: f = FanMorphism(pr, P1xP1.fan())
sage: c = f.image_cone(Cone([(1,0), (0,1)]))
sage: c
1-d cone of Rational polyhedral fan in 1-d lattice N
sage: f.preimage_cones(c)
(1-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)