r"""
The Chow group of a toric variety
In general, the Chow group is an algebraic version of a homology
theory. That is, the objects are formal linear combinations of
submanifolds modulo relations. In particular, the objects of the Chow
group are formal linear combinations of algebraic subvarieties and the
equivalence relation is rational equivalence. There is no relative
version of the Chow group, so it is not a generalized homology
theory.
The Chow groups of smooth or mildly singular toric varieties are
almost the same as the homology groups:
* For smooth toric varieties, `A_{k}(X) = H_{2k}(X,\ZZ)`. While they
are the same, using the cohomology ring instead of the Chow group
will be much faster! The cohomology ring does not try to keep track
of torsion and uses Groebner bases to encode the cup product.
* For simplicial toric varieties, `A_{k}(X)\otimes \QQ =
H_{2k}(X,\QQ)`.
Note that in these cases the odd-dimensional (co)homology groups
vanish. But for sufficiently singular toric varieties the Chow group
differs from the homology groups (and the odd-dimensional homology
groups no longer vanish). For singular varieties the Chow group is
much easier to compute than the (co)homology groups.
The toric Chow group of a toric variety is the Chow group generated by
the toric subvarieties, that is, closures of orbits under the torus
action. These are in one-to-one correspondence with the cones of the
fan and, therefore, the toric Chow group is a quotient of the free
Abelian group generated by the cones. In particular, the toric Chow
group has finite rank. One can show [FMSS1]_ that the toric Chow
groups equal the "full" Chow group of a toric variety, so there is no
need to distinguish these in the following.
AUTHORS:
- Volker Braun (2010-08-09): Initial version
REFERENCES:
.. [wp:ChowRing]
http://en.wikipedia.org/wiki/Chow_ring
.. [FMSS1]
Fulton, MacPherson, Sottile, Sturmfels:
*Intersection theory on spherical varieties*,
J. of Alg. Geometry 4 (1995), 181-193.
http://www.math.tamu.edu/~frank.sottile/ps/spherical.ps.gz
.. [FultonChow]
Chapter 5.1 "Chow Groups" of Fulton, William:
*Introduction to Toric Varieties*,
Princeton University Press
EXAMPLES::
sage: X = toric_varieties.Cube_deformation(7)
sage: X.is_smooth()
False
sage: X.is_orbifold()
False
sage: A = X.Chow_group()
sage: A.degree()
(Z, C7, C2 x C2 x Z^5, Z)
sage: A.degree(2).ngens()
7
sage: a = sum( A.gen(i) * (i+1) for i in range(0,A.ngens()) ) # an element of A
sage: a # long time (2s on sage.math, 2011)
( 3 | 1 mod 7 | 0 mod 2, 1 mod 2, 4, 5, 6, 7, 8 | 9 )
The Chow group elements are printed as ``( a0 | a1 mod 7 | a2 mod 2,
a3 mod 2, a4, a5, a6, a7, a8 | a9 )``, which denotes the element of
the Chow group in the same basis as ``A.degree()``. The ``|``
separates individual degrees, so the example means:
* The degree-0 part is `3 \in \ZZ`.
* The degree-1 part is `1 \in \ZZ_7`.
* The torsion of the degree-2 Chow group is `(0, 1) \in
\ZZ_2\oplus\ZZ_2`.
* The free part of the degree-2 Chow group is `(4, 5, 6, 7, 8) \in
\ZZ^5`.
* The degree-3 part is `9 \in \ZZ`.
Note that the generators ``A.gens()`` are not sorted in any way. In
fact, they may be of mixed degree. Use ``A.gens(degree=d)`` to obtain
the generators in a fixed degree ``d``. See
:meth:`ChowGroup_class.gens` for more details.
Cones of toric varieties can determine their own Chow cycle::
sage: A = X.Chow_group(); A
Chow group of 3-d toric variety covered by 6 affine patches
sage: cone = X.fan(dim=2)[3]; cone
2-d cone of Rational polyhedral fan in 3-d lattice N
sage: A_cone = A(cone); A_cone
( 0 | 1 mod 7 | 0 mod 2, 0 mod 2, 0, 0, 0, 0, 0 | 0 )
sage: A_cone.degree()
1
sage: 2 * A_cone
( 0 | 2 mod 7 | 0 mod 2, 0 mod 2, 0, 0, 0, 0, 0 | 0 )
sage: A_cone + A.gen(0)
( 0 | 1 mod 7 | 0 mod 2, 1 mod 2, 0, 0, 0, 0, 0 | 0 )
Chow cycles can be of mixed degrees::
sage: mixed = sum(A.gens()); mixed
( 1 | 4 mod 7 | 1 mod 2, 1 mod 2, 1, 1, 1, 1, 1 | 1 )
sage: mixed.project_to_degree(1)
( 0 | 4 mod 7 | 0 mod 2, 0 mod 2, 0, 0, 0, 0, 0 | 0 )
sage: sum( mixed.project_to_degree(i) for i in range(0,X.dimension()+1) ) == mixed
True
"""
from sage.misc.all import flatten
from sage.modules.fg_pid.fgp_module import FGP_Module_class
from sage.modules.fg_pid.fgp_element import FGP_Element
from sage.modules.free_module import FreeModule
from sage.structure.sage_object import SageObject
from sage.structure.factory import UniqueFactory
from sage.rings.all import ZZ, QQ, Infinity
from sage.geometry.cone import is_Cone
from sage.schemes.toric.variety import is_ToricVariety
from sage.schemes.toric.divisor import is_ToricDivisor
class ChowCycle(FGP_Element):
"""
The elements of the Chow group.
.. WARNING::
Do not construct :class:`ChowCycle` objects manually. Instead,
use the parent :class:`ChowGroup<ChowGroup_class>` to obtain
generators or Chow cycles correspondig to cones of the fan.
EXAMPLES::
sage: P2 = toric_varieties.P2()
sage: A = P2.Chow_group()
sage: A.gens()
(( 1 | 0 | 0 ), ( 0 | 1 | 0 ), ( 0 | 0 | 1 ))
sage: cone = P2.fan(1)[0]
sage: A(cone)
( 0 | 1 | 0 )
sage: A( Cone([(1,0)]) )
( 0 | 1 | 0 )
"""
def __init__(self, parent, v, check=True):
r"""
Construct a :class:`ChowCycle`.
INPUT:
- ``parent`` -- a :class:`ChowGroup_class`.
- ``v`` -- a vector in the covering module, that is, with one
entry for each cone of the toric variety.
- ``check`` -- boolean (default: ``True``). Verify that ``v``
is in the covering module. Set to ``False`` if you want to
initialize from a coordinate vector.
TESTS::
sage: P2 = toric_varieties.P2()
sage: A = P2.Chow_group()
sage: from sage.schemes.toric.chow_group import ChowCycle
sage: ChowCycle(A, (0,1,2,3,11,12,13), check=False)
( 36 | 6 | 0 )
"""
FGP_Element.__init__(self, parent, v, check)
def _repr_(self):
r"""
Return a string representation of the Chow cycle.
OUTPUT:
See the module-level documentation for details.
EXAMPLES::
sage: P2 = toric_varieties.P2()
sage: A = P2.Chow_group()
sage: A.degree()
(Z, Z, Z)
sage: A.an_element()._repr_()
'( 1 | 0 | 0 )'
A more complicated example with torsion::
sage: X = toric_varieties.Cube_nonpolyhedral()
sage: A = X.Chow_group()
sage: A.degree()
(Z, 0, C2 x Z^5, Z)
sage: sum( A.gen(i) * (i+1) for i in range(0,A.ngens()) )
( 2 || 1 mod 2, 3, 4, 5, 6, 7 | 8 )
"""
A = self.parent()
s = '('
for degree in range(0,A.scheme().dimension()+1):
if degree>0:
s += '|'
generators = A.gens(degree=degree)
coefficients = A.coordinate_vector(self, degree=degree)
if len(generators)>0:
s += ' '
for i, gen in enumerate(generators):
if i>0:
s += ', '
s += str(coefficients[i])
if gen.order() != Infinity:
s += ' mod '+str(gen.order())
if len(generators)>0:
s += ' '
s += ')'
return s
def degree(self):
r"""
The degree of the Chow cycle.
OUTPUT:
Integer. The complex dimension of the subvariety representing
the Chow cycle. Raises a ``ValueError`` if the Chow cycle is a
sum of mixed degree cycles.
EXAMPLES::
sage: P2 = toric_varieties.P2()
sage: A = P2.Chow_group()
sage: [ a.degree() for a in A.gens() ]
[0, 1, 2]
"""
if '_dim' in self.__dict__:
return self._dim
ambient_dim = self.parent()._variety.dimension()
cone_dim = None
for i, cone in enumerate(self.parent()._cones):
if self.lift()[i]!=0:
if cone_dim not in [None,cone.dim()]:
raise ValueError, 'Chow cycle is not of definite degree.'
cone_dim = cone.dim()
self._dim = ambient_dim - cone_dim
return self._dim
def project_to_degree(self, degree):
r"""
Project a (mixed-degree) Chow cycle to the given ``degree``.
INPUT:
- ``degree`` -- integer. The degree to project to.
OUTPUT:
The projection of the Chow class to the given degree as a new
:class:`ChowCycle` of the same Chow group.
EXAMPLES::
sage: A = toric_varieties.P2().Chow_group()
sage: cycle = 10*A.gen(0) + 11*A.gen(1) + 12*A.gen(2)
sage: cycle
( 10 | 11 | 12 )
sage: cycle.project_to_degree(2)
( 0 | 0 | 12 )
"""
ambient_dim = self.parent()._variety.dimension()
v = list(self.lift())
for i in range(0,len(v)):
cone = self.parent()._cones[i]
if cone.dim() != ambient_dim-degree:
v[i] = 0
v = self.parent().cover()(v)
P = self.parent()
return P.element_class(P, v, check=False)
def count_points(self):
r"""
Return the number of points in the Chow cycle.
OUTPUT:
An element of ``self.base_ring()``, which is usually
`\ZZ`. The number of points in the Chow cycle.
EXAMPLES::
sage: P2 = toric_varieties.P2()
sage: A = P2.Chow_group()
sage: a = 5*A.gen(0) + 7*A.gen(1); a
( 5 | 7 | 0 )
sage: a.count_points()
5
In the case of a smooth complete toric variety, the Chow
(homology) groups are Poincare dual to the integral cohomology
groups. Here is such a smooth example::
sage: D = P2.divisor(1)
sage: a = D.Chow_cycle()
sage: aD = a.intersection_with_divisor(D)
sage: aD.count_points()
1
sage: P2.integrate( aD.cohomology_class() )
1
For toric varieties with at most orbifold singularities, the
isomorphism only holds over `\QQ`. But the normalization of
the integral is still chosen such that the intersection
numbers (which are potentially rational) computed both ways
agree::
sage: P1xP1_Z2 = toric_varieties.P1xP1_Z2()
sage: Dt = P1xP1_Z2.divisor(1); Dt
V(t)
sage: Dy = P1xP1_Z2.divisor(3); Dy
V(y)
sage: Dt.Chow_cycle(QQ).intersection_with_divisor(Dy).count_points()
1/2
sage: P1xP1_Z2.integrate( Dt.cohomology_class() * Dy.cohomology_class() )
1/2
"""
c0 = self.project_to_degree(0).lift()
return sum(c0)
def intersection_with_divisor(self, divisor):
"""
Intersect the Chow cycle with ``divisor``.
See [FultonChow]_ for a description of the toric algorithm.
INPUT:
- ``divisor`` -- a :class:`ToricDivisor
<sage.schemes.toric.divisor.ToricDivisor_generic>`
that can be moved away from the Chow cycle. For example, any
Cartier divisor. See also :meth:`ToricDivisor.move_away_from
<sage.schemes.toric.divisor.ToricDivisor_generic.move_away_from>`.
OUTPUT:
A new :class:`ChowCycle`. If the divisor is not Cartier then
this method potentially raises a ``ValueError``, indicating
that the divisor cannot be made transversal to the Chow cycle.
EXAMPLES::
sage: dP6 = toric_varieties.dP6()
sage: cone = dP6.fan().cone_containing(2); cone
1-d cone of Rational polyhedral fan in 2-d lattice N
sage: D = dP6.divisor(cone); D
V(y)
sage: A = dP6.Chow_group()
sage: A(cone)
( 0 | 0, 0, 0, 1 | 0 )
sage: intersection = A(cone).intersection_with_divisor(D); intersection
( -1 | 0, 0, 0, 0 | 0 )
sage: intersection.count_points()
-1
You can do the same computation over the rational Chow group
since there is no torsion in this case::
sage: A_QQ = dP6.Chow_group(base_ring=QQ)
sage: A_QQ(cone)
( 0 | 0, 0, 0, 1 | 0 )
sage: intersection_QQ = A_QQ(cone).intersection_with_divisor(D); intersection
( -1 | 0, 0, 0, 0 | 0 )
sage: intersection_QQ.count_points()
-1
sage: type(intersection_QQ.count_points())
<type 'sage.rings.rational.Rational'>
sage: type(intersection.count_points())
<type 'sage.rings.integer.Integer'>
TESTS:
The relations are the Chow cycles rationally equivalent to the
zero cycle. Their intersection with any divisor must be the zero cycle::
sage: [ r.intersection_with_divisor(D) for r in dP6.Chow_group().relation_gens() ]
[( 0 | 0, 0, 0, 0 | 0 ), ( 0 | 0, 0, 0, 0 | 0 ),
( 0 | 0, 0, 0, 0 | 0 ), ( 0 | 0, 0, 0, 0 | 0 ),
( 0 | 0, 0, 0, 0 | 0 ), ( 0 | 0, 0, 0, 0 | 0 ),
( 0 | 0, 0, 0, 0 | 0 )]
sage: [ r.intersection_with_divisor(D).lift() for r in dP6.Chow_group().relation_gens() ]
[(0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0),
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)]
"""
assert is_ToricDivisor(divisor), str(divisor)+' is not a toric divisor.'
A = self.parent()
X = A._variety
intersection = A(0)
coefficients = self.lift()
for sigma_idx, sigma in enumerate(A._cones):
if sigma.dim()==X.dimension():
continue
coefficient = coefficients[sigma_idx]
if coefficient==0:
continue
D = divisor.move_away_from(sigma)
for gamma in sigma.facet_of():
n = gamma.relative_quotient(sigma).gen(0).lift()
perp = sigma.relative_orthogonal_quotient(gamma).gen(0).lift()
I_gamma = set(gamma.ambient_ray_indices()) - set(sigma.ambient_ray_indices())
i = I_gamma.pop()
v_i = X.fan().ray(i)
a_i = D.coefficient(i)
s_i = (v_i*perp)/(n*perp)
b_gamma = a_i/s_i
intersection += self.base_ring()(coefficient*b_gamma) * A(gamma)
return intersection
def cohomology_class(self):
r"""
Return the (Poincare-dual) cohomology class.
Consider a simplicial cone of the fan, that is, a
`d`-dimensional cone spanned by `d` rays. Take the product of
the corresponding `d` homogeneous coordinates. This monomial
represents a cohomology classes of the toric variety `X`, see
:meth:`~sage.schemes.toric.variety.ToricVariety_field.cohomology_ring`.
Its cohomological degree is `2d`, which is the same degree as
the Poincare-dual of the (real) `\dim(X)-2d`-dimensional torus
orbit associated to the simplicial cone. By linearity, we can
associate a cohomology class to each Chow cycle of a
simplicial toric variety.
If the toric variety is compact and smooth, the associated
cohomology class actually is the Poincare dual (over the
integers) of the Chow cycle. In particular, integrals of dual
cohomology classes perform intersection computations.
If the toric variety is compact and has at most orbifold
singularities, the torsion parts in cohomology and the Chow
group can differ. But they are still isomorphic as rings over
the rationals. Moreover, the normalization of integration
(:meth:`volume_class
<sage.schemes.toric.variety.ToricVariety_field.volume_class>`)
and :meth:`count_points` are chosen to agree.
OUTPUT:
The
:class:`~sage.schemes.toric.variety.CohomologyClass`
which is associated to the Chow cycle.
If the toric variety is not simplicial, that is, has worse
than orbifold singularities, there is no way to associate a
cohomology class of the correct degree. In this case,
:meth:`cohomology_class` rasies a ``ValueError``.
EXAMPLES::
sage: dP6 = toric_varieties.dP6()
sage: cone = dP6.fan().cone_containing(2,3)
sage: HH = dP6.cohomology_ring()
sage: A = dP6.Chow_group()
sage: HH(cone)
[-w^2]
sage: A(cone)
( 1 | 0, 0, 0, 0 | 0 )
sage: A(cone).cohomology_class()
[-w^2]
Here is an example of a toric variety with orbifold
singularities, where we can also use the isomorphism with the
rational cohomology ring::
sage: WP4 = toric_varieties.P4_11169()
sage: A = WP4.Chow_group()
sage: HH = WP4.cohomology_ring()
sage: cone3d = Cone([(0,0,1,0), (0,0,0,1), (-9,-6,-1,-1)])
sage: A(cone3d)
( 0 | 1 | 0 | 0 | 0 )
sage: HH(cone3d)
[3*z4^3]
sage: D = -WP4.K() # the anticanonical divisor
sage: A(D)
( 0 | 0 | 0 | 18 | 0 )
sage: HH(D)
[18*z4]
sage: WP4.integrate( A(cone3d).cohomology_class() * D.cohomology_class() )
1
sage: WP4.integrate( HH(cone3d) * D.cohomology_class() )
1
sage: A(cone3d).intersection_with_divisor(D).count_points()
1
"""
toric_variety = self.parent().scheme()
if not toric_variety.is_orbifold():
raise(ValueError, 'The toric variety may have at most orbifold singularities!')
HH = toric_variety.cohomology_ring()
coeff = self.lift()
return sum([ HH(cone) * coeff[i] for i,cone in enumerate(self.parent()._cones) ])
class ChowGroupFactory(UniqueFactory):
"""
Factory for :class:`ChowGroup_class`.
"""
def create_key_and_extra_args(self, toric_variety, base_ring=ZZ, check=True):
"""
Create a key that uniquely determines the :class:`ChowGroup_class`.
INPUT:
- ``toric_variety`` -- a toric variety.
- ``base_ring`` -- either `\ZZ` (default) or `\QQ`. The
coefficient ring of the Chow group.
- ``check`` -- boolean (default: ``True``).
EXAMPLES::
sage: from sage.schemes.toric.chow_group import *
sage: P2 = toric_varieties.P2()
sage: ChowGroup(P2, ZZ, check=True) == ChowGroup(P2, ZZ, check=False) # indirect doctest
True
"""
if not is_ToricVariety(toric_variety):
raise ValueError, 'First argument must be a toric variety.'
if not base_ring in [ZZ,QQ]:
raise ValueError, 'Base ring must be either ZZ or QQ.'
key = tuple([toric_variety, base_ring])
extra = {'check':check}
return key, extra
def create_object(self, version, key, **extra_args):
"""
Create a :class:`ChowGroup_class`.
INPUT:
- ``version`` -- object version. Currently not used.
- ``key`` -- a key created by :meth:`create_key_and_extra_args`.
- ``**extra_args`` -- Currently not used.
EXAMPLES::
sage: from sage.schemes.toric.chow_group import *
sage: P2 = toric_varieties.P2()
sage: ChowGroup(P2) # indirect doctest
Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches
"""
toric_variety, base_ring = key
check = extra_args['check']
return ChowGroup_class(toric_variety, base_ring, check)
ChowGroup = ChowGroupFactory('ChowGroup')
class ChowGroup_class(FGP_Module_class):
r"""
The Chow group of a toric variety.
EXAMPLES::
sage: P2=toric_varieties.P2()
sage: from sage.schemes.toric.chow_group import ChowGroup_class
sage: A = ChowGroup_class(P2,ZZ,True); A
Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches
sage: A.an_element()
( 1 | 0 | 0 )
"""
Element = ChowCycle
def __init__(self, toric_variety, base_ring, check):
r"""
EXAMPLES::
sage: from sage.schemes.toric.chow_group import *
sage: P2=toric_varieties.P2()
sage: A = ChowGroup_class(P2,ZZ,True); A
Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches
sage: is_ChowGroup(A)
True
sage: is_ChowCycle(A.an_element())
True
TESTS::
sage: A_ZZ = P2.Chow_group()
sage: 2 * A_ZZ.an_element() * 3
( 6 | 0 | 0 )
sage: 1/2 * A_ZZ.an_element() * 1/3
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for '*': 'Rational Field'
and 'Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches'
sage: A_ZZ.get_action(ZZ)
Right scalar multiplication by Integer Ring on Chow group of 2-d
CPR-Fano toric variety covered by 3 affine patches
sage: A_ZZ.get_action(QQ)
You can't multiply integer classes with fractional
numbers. For that you need to go to the rational Chow group::
sage: A_QQ = P2.Chow_group(QQ)
sage: 2 * A_QQ.an_element() * 3
( 0 | 0 | 6 )
sage: 1/2 * A_QQ.an_element() * 1/3
( 0 | 0 | 1/6 )
sage: A_QQ.get_action(ZZ)
Right scalar multiplication by Integer Ring on QQ-Chow group of 2-d
CPR-Fano toric variety covered by 3 affine patches
sage: A_QQ.get_action(QQ)
Right scalar multiplication by Rational Field on QQ-Chow group of 2-d
CPR-Fano toric variety covered by 3 affine patches
"""
self._variety = toric_variety
self._cones = flatten( toric_variety.fan().cones() )
V = FreeModule(base_ring, len(self._cones))
W = self._rational_equivalence_relations(V)
super(ChowGroup_class,self).__init__(V, W, check)
def scheme(self):
r"""
Return the underlying toric variety.
OUTPUT:
A :class:`ToricVariety
<sage.schemes.toric.variety.ToricVariety_field>`.
EXAMPLES::
sage: P2 = toric_varieties.P2()
sage: A = P2.Chow_group()
sage: A.scheme()
2-d CPR-Fano toric variety covered by 3 affine patches
sage: A.scheme() is P2
True
"""
return self._variety
def _element_constructor_(self, x, check=True):
r"""
Construct a :class:`ChowCycle`.
INPUT:
- ``x`` -- a cone of the fan, a toric divisor, or a valid
input for
:class:sage.modules.fg_pid.fgp_module.FGP_Module_class`.
- ``check`` -- bool (default: ``True``). See
:class:sage.modules.fg_pid.fgp_module.FGP_Module_class`.
EXAMPLES::
sage: dP6 = toric_varieties.dP6()
sage: A = dP6.Chow_group()
sage: cone = dP6.fan(dim=1)[4]
sage: A(cone)
( 0 | 0, 1, 0, 0 | 0 )
sage: A(Cone(cone)) # isomorphic but not identical to a cone of the fan!
( 0 | 0, 1, 0, 0 | 0 )
sage: A( dP6.K() )
( 0 | -1, -2, -2, -1 | 0 )
"""
fan = self._variety.fan()
if is_Cone(x):
cone = fan.embed(x)
return self.element_class(self, self._cone_to_V(cone), False)
if is_ToricDivisor(x):
v = sum(x.coefficient(i)*self._cone_to_V(onecone)
for i,onecone in enumerate(fan(1)))
return self.element_class(self, v, False)
return super(ChowGroup_class,self)._element_constructor_(x, check)
def _coerce_map_from_(self, S):
"""
Return true if S canonically coerces to self.
EXAMPLES::
sage: A = toric_varieties.P2().Chow_group()
sage: A._coerce_map_from_(ZZ) # private method
False
sage: A.has_coerce_map_from(ZZ) # recommended usage
False
"""
return super(ChowGroup_class,self)._coerce_map_from_(S)
def _rational_equivalence_relations(self, V):
r"""
Return the rational equivalence relations between the cones of the fan.
See :meth:`relation_gens` for details.
EXAMPLES::
sage: points_mod = lambda k: matrix([[ 1, 1, 2*k+1],[ 1,-1, 1],[-1, 1, 1],[-1,-1, 1],[-1,-1,-1],[-1, 1,-1],[ 1,-1,-1],[ 1, 1,-1]])
sage: points = lambda k: matrix([[1,1,1],[1,-1,1],[-1,1,1]]).solve_left(points_mod(k)).rows()
sage: cones = [[0,1,2,3],[4,5,6,7],[0,1,7,6],[4,5,3,2],[0,2,5,7],[4,6,1,3]]
sage: X_Delta = lambda k: ToricVariety( Fan(cones=cones, rays=points(k)) )
sage: from sage.schemes.toric.chow_group import ChowGroup
sage: A = ChowGroup( X_Delta(2) )
sage: rel = A._rational_equivalence_relations(A.cover()).basis()
sage: matrix(rel).submatrix(col=0, ncols=1).elementary_divisors()
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
sage: matrix(rel).submatrix(col=1, ncols=8).elementary_divisors()
[1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
sage: matrix(rel).submatrix(col=9, ncols=12).elementary_divisors()
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0]
sage: matrix(rel).submatrix(col=21, ncols=6).elementary_divisors()
[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
"""
fan = self._variety.fan()
dim = self._variety.dimension()
relations = []
for rho in self._cones:
for u in rho.orthogonal_sublattice().gens():
rel = V.zero()
for sigma in rho.facet_of():
sigma_idx = self._cones.index(sigma)
Q = sigma.relative_quotient(rho)
for v in [n.lift() for n in Q.gens()]:
rel += (u*v) * V.gen(sigma_idx)
relations.append(rel)
return V.span(relations)
def __div__(self, other):
r"""
Return the quotient of the Chow group by a subgroup.
OUTPUT:
Currently not implemented.
EXAMPLES::
sage: A = toric_varieties.dP6().Chow_group()
sage: Asub = A.submodule([ A.gen(0), A.gen(3) ])
sage: A/Asub
Traceback (most recent call last):
...
NotImplementedError: Quotients of the Chow group are not implemented.
"""
raise NotImplementedError, 'Quotients of the Chow group are not implemented.'
def _repr_(self):
"""
Return a string representation.
EXAMPLES::
sage: P2=toric_varieties.P2()
sage: from sage.schemes.toric.chow_group import ChowGroup
sage: ChowGroup(P2,ZZ)._repr_()
'Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches'
sage: ChowGroup(P2,QQ)._repr_()
'QQ-Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches'
"""
if self.base_ring() == QQ:
return "QQ-Chow group of " + str(self._variety)
elif self.base_ring() == ZZ:
return "Chow group of " + str(self._variety)
else:
raise(ValueError, 'Base ring must be QQ or ZZ.')
def __eq__(self, other):
r"""
Comparison of two Chow groups.
INPUT:
- ``other`` -- anything.
OUTPUT:
``True`` or ``False``.
EXAMPLES::
sage: P2 = toric_varieties.P2()
sage: P2.Chow_group() == P2.Chow_group()
True
sage: P2.Chow_group(ZZ) == P2.Chow_group(QQ)
False
"""
return self is other
def _cone_to_V(self, cone):
r"""
Convert a cone into the corresponding vector in ``self._V``
INPUT:
- ``cone`` -- a :class:`sage.geometry.cone.ConvexRationalPolyhedralCone`.
OUPUT:
The corresponding element of ``self.V()``.
EXAMPLES::
sage: P2 = toric_varieties.P2()
sage: A = P2.Chow_group()
sage: cone = P2.fan(dim=1)[0]
sage: A._cone_to_V(cone)
(0, 1, 0, 0, 0, 0, 0)
"""
assert cone.ambient() is self._variety.fan()
x = [0] * len(self._cones)
x[self._cones.index(cone)] = 1
return self._V(x)
def degree(self, k=None):
r"""
Return the degree-`k` Chow group.
INPUT:
- ``k`` -- an integer or ``None`` (default). The degree of the
Chow group.
OUTPUT:
- if `k` was specified, the Chow group `A_k` as an Abelian
group.
- if `k` was not specified, a tuple containing the Chow groups
in all degrees.
.. NOTE::
* For a smooth toric variety, this is the same as the
Poincare-dual cohomology group
`H^{d-2k}(X,\ZZ)`.
* For a simplicial toric variety ("orbifold"),
`A_k(X)\otimes \QQ = H^{d-2k}(X,\QQ)`.
EXAMPLES:
Four exercises from page 65 of [FultonP65]_. First, an example
with `A_1(X)=\ZZ\oplus\ZZ/3\ZZ`::
sage: X = ToricVariety(Fan(cones=[[0,1],[1,2],[2,0]],
... rays=[[2,-1],[-1,2],[-1,-1]]))
sage: A = X.Chow_group()
sage: A.degree(1)
C3 x Z
Second, an example with `A_2(X)=\ZZ^2`::
sage: points = [[1,0,0],[0,1,0],[0,0,1],[1,-1,1],[-1,0,-1]]
sage: l = LatticePolytope(matrix(points).transpose())
sage: l.show3d()
sage: X = ToricVariety(FaceFan(l))
sage: A = X.Chow_group()
sage: A.degree(2)
Z^2
Third, an example with `A_2(X)=\ZZ^5`::
sage: cube = [[ 1,0,0],[0, 1,0],[0,0, 1],[-1, 1, 1],
... [-1,0,0],[0,-1,0],[0,0,-1],[ 1,-1,-1]]
sage: lat_cube = LatticePolytope(matrix(cube).transpose())
sage: X = ToricVariety(FaceFan((LatticePolytope(lat_cube))))
sage: X.Chow_group().degree(2)
Z^5
Fourth, a fan that is not the fan over a
polytope. Combinatorially, the fan is the same in the third
example, only the coordinates of the first point are
different. But the resulting fan is not the face fan of a
cube, so the variety is "more singular". Its Chow group has
torsion, `A_2(X)=\ZZ^5 \oplus \ZZ/2`::
sage: rays = [[ 1, 2, 3],[ 1,-1, 1],[-1, 1, 1],[-1,-1, 1],
... [-1,-1,-1],[-1, 1,-1],[ 1,-1,-1],[ 1, 1,-1]]
sage: cones = [[0,1,2,3],[4,5,6,7],[0,1,7,6],
... [4,5,3,2],[0,2,5,7],[4,6,1,3]]
sage: X = ToricVariety(Fan(cones, rays))
sage: X.Chow_group().degree(2) # long time (2s on sage.math, 2011)
C2 x Z^5
Finally, Example 1.3 of [FS]_::
sage: points_mod = lambda k: matrix([[ 1, 1, 2*k+1],[ 1,-1, 1],
... [-1, 1, 1],[-1,-1, 1],[-1,-1,-1],
... [-1, 1,-1],[ 1,-1,-1],[ 1, 1,-1]])
sage: rays = lambda k: matrix([[1,1,1],[1,-1,1],[-1,1,1]]
... ).solve_left(points_mod(k)).rows()
sage: cones = [[0,1,2,3],[4,5,6,7],[0,1,7,6],
... [4,5,3,2],[0,2,5,7],[4,6,1,3]]
sage: X_Delta = lambda k: ToricVariety(Fan(cones=cones, rays=rays(k)))
sage: X_Delta(0).Chow_group().degree() # long time (3s on sage.math, 2011)
(Z, Z, Z^5, Z)
sage: X_Delta(1).Chow_group().degree() # long time (3s on sage.math, 2011)
(Z, 0, Z^5, Z)
sage: X_Delta(2).Chow_group().degree() # long time (3s on sage.math, 2011)
(Z, C2, Z^5, Z)
sage: X_Delta(2).Chow_group(base_ring=QQ).degree() # long time (4s on sage.math, 2011)
(Q, 0, Q^5, Q)
"""
if k!=None:
return self.degree()[k]
try:
return self._degree
except AttributeError:
pass
self._degree = tuple(ChowGroup_degree_class(self,d)
for d in range(0,self._variety.dimension()+1))
return self._degree
def coordinate_vector(self, chow_cycle, degree=None, reduce=True):
r"""
Return the coordinate vector of the ``chow_cycle``.
INPUT:
- ``chow_cycle`` -- a :class:`ChowCycle`.
- ``degree`` -- None (default) or an integer.
- ``reduce`` -- boolean (default: ``True``). Whether to reduce
modulo the invariants.
OUTPUT:
* If ``degree==None`` (default), the coordinate vector
relative to the basis ``self.gens()`` is returned.
* If some integer ``degree=d`` is specified, the chow cycle is
projected to the given degree and the coordinate vector
relative to the basis ``self.gens(degree=d)`` is returned.
EXAMPLES::
sage: A = toric_varieties.P2().Chow_group()
sage: a = A.gen(0) + 2*A.gen(1) + 3*A.gen(2)
sage: A.coordinate_vector(a)
(1, 2, 3)
sage: A.coordinate_vector(a, degree=1)
(2)
"""
if degree==None:
return super(ChowGroup_class, self).coordinate_vector(chow_cycle, reduce=reduce)
a = chow_cycle.project_to_degree(degree)
return self.degree(degree).module().coordinate_vector(a, reduce=reduce)
def gens(self, degree=None):
r"""
Return the generators of the Chow group.
INPUT:
- ``degree`` -- integer (optional). The degree of the Chow
group.
OUTPUT:
- if no degree is specified, the generators of the whole Chow
group. The chosen generators may be of mixed degree.
- if ``degree=`` `k` was specified, the generators of the
degree-`k` part `A_k` of the Chow group.
EXAMPLES::
sage: A = toric_varieties.P2().Chow_group()
sage: A.gens()
(( 1 | 0 | 0 ), ( 0 | 1 | 0 ), ( 0 | 0 | 1 ))
sage: A.gens(degree=1)
(( 0 | 1 | 0 ),)
"""
if degree==None:
return super(ChowGroup_class, self).gens()
else:
return self.degree(degree).gens()
def relation_gens(self):
r"""
Return the Chow cycles equivalent to zero.
For each `d-k-1`-dimensional cone `\rho \in \Sigma^{(d-k-1)}`,
the relations in `A_k(X)`, that is the cycles equvalent to
zero, are generated by
.. MATH::
0 \stackrel{!}{=}
\mathop{\mathrm{div}}(u) =
\sum_{\rho < \sigma \in \Sigma^{(n-p)} }
\big< u, n_{\rho,\sigma} \big> V(\sigma)
,\qquad
u \in M(\rho)
where `n_{\rho,\sigma}` is a (randomly chosen) lift of the
generator of `N_\sigma/N_\rho \simeq \ZZ`. See also Exercise
12.5.7 of [CLS]_.
See also :meth:`relations` to obtain the relations as
submodule of the free module generated by the cones. Or use
``self.relations().gens()`` to list the relations in the free
module.
OUTPUT:
A tuple of Chow cycles, each rationally equivalent to zero,
that generates the rational equivalence.
EXAMPLES::
sage: P2 = toric_varieties.P2()
sage: A = P2.Chow_group()
sage: first = A.relation_gens()[0]
sage: first
( 0 | 0 | 0 )
sage: first.is_zero()
True
sage: first.lift()
(0, 1, 0, -1, 0, 0, 0)
"""
gens = self.W().gens()
return tuple( self(gen) for gen in gens )
class ChowGroup_degree_class(SageObject):
r"""
A fixed-degree subgroup of the Chow group of a toric variety.
WARNING ..
Use
:meth:`~sage.schemes.toric.chow_group.ChowGroup_class.degree`
to construct :class:`ChowGroup_degree_class` instances.
EXAMPLES::
sage: P2 = toric_varieties.P2()
sage: A = P2.Chow_group()
sage: A
Chow group of 2-d CPR-Fano toric variety covered by 3 affine patches
sage: A.degree()
(Z, Z, Z)
sage: A.degree(2)
Z
sage: type(_)
<class 'sage.schemes.toric.chow_group.ChowGroup_degree_class'>
"""
def __init__(self, A, d):
r"""
Construct a :class:`ChowGroup_degree_class`.
INPUT:
- ``A`` -- A :class:`ChowGroup_class`.
- ``d`` -- integer. The degree of the Chow group.
EXAMPLES::
sage: P2 = toric_varieties.P2()
sage: A = P2.Chow_group()
sage: from sage.schemes.toric.chow_group import ChowGroup_degree_class
sage: A2 = ChowGroup_degree_class(A,2)
sage: A2
Z
"""
self._Chow_group = A
self._degree = d
toric_variety = A.scheme()
fan = toric_variety.fan()
gens = []
for cone in fan(codim=d):
gen = A._cone_to_V(cone)
gens.append(gen)
self._module = A.submodule(gens)
self._gens = tuple([ A.element_class(A, a.lift(), False)
for a in self._module.gens() ])
def _repr_(self):
"""
Return a string representation.
OUTPUT:
String.
EXAMPLES::
sage: projective_plane = toric_varieties.P2()
sage: A2 = projective_plane.Chow_group().degree(2)
sage: A2._repr_()
'Z'
sage: A2_QQ = projective_plane.Chow_group(base_ring=QQ).degree(2)
sage: A2_QQ._repr_()
'Q'
"""
invariants = self._module.invariants()
if len(invariants)==0:
return '0'
free = filter(lambda x:x==0, invariants)
tors = filter(lambda x:x> 0, invariants)
if self._Chow_group.base_ring()==ZZ:
ring = 'Z'
elif self._Chow_group.base_ring()==QQ:
ring = 'Q'
else:
raise NotImplementedError, 'Base ring must be ZZ or QQ.'
s = ['C' + str(x) for x in tors]
if len(free)==1:
s.append(ring)
if len(free)>1:
s.append(ring + '^' + str(len(free)))
return ' x '.join(s)
def module(self):
"""
Return the submodule of the toric Chow group generated.
OUTPUT:
A :class:`sage.modules.fg_pid.fgp_module.FGP_Module_class`
EXAMPLES::
sage: projective_plane = toric_varieties.P2()
sage: A2 = projective_plane.Chow_group().degree(2)
sage: A2.module()
Finitely generated module V/W over Integer Ring with invariants (0)
"""
return self._module
def ngens(self):
"""
Return the number of generators.
OUTPUT:
An integer.
EXAMPLES::
sage: projective_plane = toric_varieties.P2()
sage: A2 = projective_plane.Chow_group().degree(2)
sage: A2.ngens()
1
"""
return len(self._gens)
def gen(self, i):
"""
Return the ``i``-th generator of the Chow group of fixed
degree.
INPUT:
- ``i`` -- integer. The index of the generator to be returned.
OUTPUT:
A tuple of Chow cycles of fixed degree generating
:meth:`module`.
EXAMPLES::
sage: projective_plane = toric_varieties.P2()
sage: A2 = projective_plane.Chow_group().degree(2)
sage: A2.gen(0)
( 0 | 0 | 1 )
"""
return self._gens[i]
def gens(self):
"""
Return the generators of the Chow group of fixed degree.
OUTPUT:
A tuple of Chow cycles of fixed degree generating
:meth:`module`.
EXAMPLES::
sage: projective_plane = toric_varieties.P2()
sage: A2 = projective_plane.Chow_group().degree(2)
sage: A2.gens()
(( 0 | 0 | 1 ),)
"""
return self._gens
def is_ChowGroup(x):
r"""
Return whether ``x`` is a :class:`ChowGroup_class`
INPUT:
- ``x`` -- anything.
OUTPUT:
``True`` or ``False``.
EXAMPLES::
sage: P2=toric_varieties.P2()
sage: A = P2.Chow_group()
sage: from sage.schemes.toric.chow_group import is_ChowGroup
sage: is_ChowGroup(A)
True
sage: is_ChowGroup('Victoria')
False
"""
return isinstance(x,ChowGroup_class)
def is_ChowCycle(x):
r"""
Return whether ``x`` is a :class:`ChowGroup_class`
INPUT:
- ``x`` -- anything.
OUTPUT:
``True`` or ``False``.
EXAMPLES::
sage: P2=toric_varieties.P2()
sage: A = P2.Chow_group()
sage: from sage.schemes.toric.chow_group import *
sage: is_ChowCycle(A)
False
sage: is_ChowCycle(A.an_element())
True
sage: is_ChowCycle('Victoria')
False
"""
return isinstance(x,ChowCycle)