Ticket #8988: trac_8988_add_support_for_toric_varieties.2.patch

File trac_8988_add_support_for_toric_varieties.2.patch, 71.4 KB (added by novoselt, 12 years ago)
  • doc/en/reference/schemes.rst

    # HG changeset patch
    # User Andrey Novoseltsev <novoselt@gmail.com>
    # Date 1274174310 21600
    # Node ID 8578850e8965e4f9c0816985f9e1398d7206117b
    # Parent  c76b58eb918eebb329fc9e8c90a7266a1bca0869
    Trac 8988: Add support for toric varieties.
    
    diff -r c76b58eb918e -r 8578850e8965 doc/en/reference/schemes.rst
    a b  
    1616   sage/schemes/generic/ambient_space
    1717   sage/schemes/generic/affine_space
    1818   sage/schemes/generic/projective_space
     19   sage/schemes/generic/toric_variety
    1920   sage/schemes/generic/algebraic_scheme
    2021   sage/schemes/generic/hypersurface
    2122
  • sage/schemes/generic/all.py

    diff -r c76b58eb918e -r 8578850e8965 sage/schemes/generic/all.py
    a b  
    77from morphism         import is_SchemeMorphism
    88from projective_space import ProjectiveSpace, is_ProjectiveSpace
    99from scheme           import is_Scheme, is_AffineScheme
     10from toric_variety import AffineToricVariety, ToricVariety
    1011from hypersurface     import ProjectiveHypersurface, AffineHypersurface
    1112
    1213
  • new file sage/schemes/generic/toric_variety.py

    diff -r c76b58eb918e -r 8578850e8965 sage/schemes/generic/toric_variety.py
    - +  
     1r"""
     2Toric varieties
     3
     4This module provides support for (normal) toric varieties, corresponding to
     5:class:`rational polyhedral fans <sage.geometry.fan.RationalPolyhedralFan>`.
     6See also :mod:`~sage.schemes.generic.fano_toric_variety` for a more
     7restrictive class of (weak) Fano toric varieties.
     8
     9An **excellent reference on toric varieties** is the book "Toric Varieties" by
     10David A. Cox, John B. Little, and Hal Schenck [CLS]_. Its draft **is freely
     11available** at
     12http://www.cs.amherst.edu/~dac/toric.html
     13**but will be removed** from this site once it is published, so hurry up!
     14
     15The interface to this module is provided through functions
     16:func:`AffineToricVariety` and :func:`ToricVariety`, although you may also be
     17interested in :func:`normalize_names`.
     18
     19.. NOTE::
     20
     21    We do NOT build "general toric varieties" from affine toric varieties.
     22    Instead, we are using the quotient representation of toric varieties with
     23    the homogeneous coordinate ring (a.k.a. Cox's ring or the total coordinate
     24    ring). This description works best for simplicial fans of the full
     25    dimension.
     26   
     27REFERENCES:
     28
     29..  [CLS]
     30    David A. Cox, John B. Little,  Hal Schenck,
     31    "Toric Varieties", Graduate Studies in Mathematics,
     32    Amer. Math. Soc., Providence, RI, to appear.
     33
     34AUTHORS:
     35
     36- Andrey Novoseltsev (2010-05-17): initial version.
     37
     38EXAMPLES:
     39
     40We start with constructing the affine plane as an affine toric variety. First,
     41we need to have a corresponding cone::
     42
     43    sage: quadrant = Cone([(1,0), (0,1)])
     44   
     45If you don't care about variable names and the base field, that's all we need
     46for now::
     47
     48    sage: A2 = AffineToricVariety(quadrant)
     49    sage: A2
     50    Toric variety of dimension 2
     51    sage: origin = A2(0,0)
     52    sage: origin
     53    [0 : 0]
     54
     55Only affine toric varieties have points whose (homogeneous) coordinates
     56are all zero. ::
     57
     58    sage: parent(origin)
     59    Set of Rational Points of Toric variety of dimension 2
     60
     61As you can see, by default toric varieties live over the field of rational
     62numbers::
     63
     64    sage: A2.base_ring()
     65    Rational Field
     66   
     67While usually toric varieties are considered over the field of complex
     68numbers, for computational purposes it is more convenient to work with fields
     69that have exact representation on computers. You can also always do ::
     70
     71    sage: C2 = AffineToricVariety(quadrant, base_field=CC)
     72    sage: C2.base_ring()
     73    Complex Field with 53 bits of precision
     74    sage: C2(1,2+i)
     75    [1.00000000000000 : 2.00000000000000 + 1.00000000000000*I]
     76       
     77or even ::
     78
     79    sage: F = CC["a, b"].fraction_field()
     80    sage: F.inject_variables()
     81    Defining a, b
     82    sage: A2 = AffineToricVariety(quadrant, base_field=F)
     83    sage: A2(a,b)
     84    [a : b]
     85
     86OK, if you need to work only with affine spaces,
     87:func:`~sage.schemes.generic.affine_space.AffineSpace` may be a better way to
     88construct them. Our next example is the product of two projective lines
     89realized as the toric variety associated to the
     90:func:`face fan <sage.geometry.fan.FaceFan>` of the "diamond"::
     91
     92    sage: diamond = lattice_polytope.octahedron(2)
     93    sage: diamond.vertices()
     94    [ 1  0 -1  0]
     95    [ 0  1  0 -1]   
     96    sage: fan = FaceFan(diamond)
     97    sage: P1xP1 = ToricVariety(fan)
     98    sage: P1xP1
     99    Toric variety of dimension 2
     100    sage: P1xP1.fan().ray_matrix()
     101    [ 1  0 -1  0]
     102    [ 0  1  0 -1]   
     103    sage: P1xP1.gens()
     104    (z0, z1, z2, z3)
     105   
     106We got four coordinates - two for each of the projective lines, but their
     107names are perhaps not very well chosen. Let's make `(x,y)` to be coordinates
     108on the first line and `(s,t)` on the second one::
     109
     110    sage: P1xP1 = ToricVariety(fan, coordinate_names="x s y t")
     111    sage: P1xP1.gens()
     112    (x, s, y, t)
     113   
     114Now, if we want to define subschemes of this variety, the defining polynomials
     115must be homogeneous in each of these pairs::
     116
     117    sage: P1xP1.inject_variables()
     118    Defining x, s, y, t
     119    sage: P1xP1.subscheme(x)
     120    Closed subscheme of Toric variety of dimension 2 defined by:
     121      x
     122    sage: P1xP1.subscheme(x^2 + y^2)
     123    Closed subscheme of Toric variety of dimension 2 defined by:
     124      x^2 + y^2   
     125    sage: P1xP1.subscheme(x^2 + s^2)
     126    Traceback (most recent call last):
     127    ...
     128    ValueError: x^2 + s^2 is not homogeneous
     129    on Toric variety of dimension 2!   
     130    sage: P1xP1.subscheme([x^2*s^2 + x*y*t^2 +y^2*t^2, s^3 + t^3])
     131    Closed subscheme of Toric variety of dimension 2 defined by:
     132      x^2*s^2 + x*y*t^2 + y^2*t^2,
     133      s^3 + t^3   
     134     
     135While we don't build toric varieties from affine toric varieties, we still can
     136access the "building pieces"::
     137
     138    sage: patch = P1xP1.affine_patch(2)
     139    sage: patch
     140    Toric variety of dimension 2
     141    sage: patch.fan().ray_matrix()
     142    [1 0]
     143    [0 1]
     144    sage: patch.embedding_morphism()
     145    Scheme morphism:
     146      From: Toric variety of dimension 2
     147      To:   Toric variety of dimension 2
     148      Defn: Defined on coordinates by sending [x : s] to
     149            [x : s : 1 : 1]
     150
     151The patch above was specifically chosen to coincide with our representation of
     152the affine plane before, but you can get the other three patches as well.
     153(While any cone of a fan will correspond to an affine toric variety, the main
     154interest is usually in the generating fans as "the biggest" affine
     155subvarieties, and these are precisely the patches that you can get from
     156:meth:`~ToricVariety_field.affine_patch`.)
     157
     158All two-dimensional toric varieties are "quite nice" because any
     159two-dimensional cone is generated by exactly two rays. From the point of view
     160of the corresponding toric varieties, this means that they have at worst
     161quotient singularities::
     162
     163    sage: P1xP1.is_orbifold()
     164    True
     165    sage: P1xP1.is_smooth()
     166    True
     167    sage: TV = ToricVariety(NormalFan(diamond))
     168    sage: TV.fan().ray_matrix()
     169    [-1  1 -1  1]
     170    [ 1  1 -1 -1]   
     171    sage: TV.is_orbifold()
     172    True
     173    sage: TV.is_smooth()
     174    False
     175   
     176In higher dimensions worse things can happen::
     177
     178    sage: TV3 = ToricVariety(NormalFan(lattice_polytope.octahedron(3)))
     179    sage: TV3.fan().ray_matrix()
     180    [-1  1 -1  1 -1  1 -1  1]
     181    [-1 -1  1  1 -1 -1  1  1]
     182    [ 1  1  1  1 -1 -1 -1 -1]   
     183    sage: TV3.is_orbifold()
     184    False
     185   
     186Fortunately, we can perform a (partial) resolution::
     187
     188    sage: TV3_res = TV3.resolve_to_orbifold()
     189    sage: TV3_res.is_orbifold()
     190    True
     191    sage: TV3_res.fan().ngenerating_cones()
     192    12
     193    sage: TV3.fan().ngenerating_cones()
     194    6
     195   
     196In this example we had to double the number of affine patches. The result is
     197still singular::
     198
     199    sage: TV3_res.is_smooth()
     200    False
     201   
     202You can resolve it further using :meth:`~ToricVariety_field.resolve` method,
     203but (at least for now) you will have to specify which rays should be inserted
     204into the fan. See also
     205:func:`~sage.schemes.generic.fano_toric_variety.FanoToricVariety`,
     206which can construct some other "nice partial resolutions."
     207
     208Below you will find detailed descriptions of available functions. If you are
     209familiar with toric geometry, you will likely see that many important objects
     210and operations are unavailable. However, this module is under active
     211development and hopefully will improve in future releases of Sage. If there
     212are some particular features that you would like to see implemented ASAP,
     213please consider reporting them to the Sage Development Team or even
     214implementing them on your own as a patch for inclusion!
     215"""
     216
     217
     218#*****************************************************************************
     219#       Copyright (C) 2010 Andrey Novoseltsev <novoselt@gmail.com>
     220#       Copyright (C) 2010 William Stein <wstein@gmail.com>
     221#
     222#  Distributed under the terms of the GNU General Public License (GPL)
     223#
     224#                  http://www.gnu.org/licenses/
     225#*****************************************************************************
     226
     227
     228from sage.geometry.all import Cone, Fan
     229from sage.matrix.all import matrix
     230from sage.misc.all import latex
     231from sage.modules.free_module_element import vector
     232from sage.rings.all import PolynomialRing, QQ, is_Field, is_FractionField
     233from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme
     234from sage.schemes.generic.ambient_space import AmbientSpace
     235from sage.schemes.generic.homset import SchemeHomset_coordinates
     236from sage.schemes.generic.morphism import (SchemeMorphism_coordinates,
     237                                           SchemeMorphism_on_points,
     238                                           is_SchemeMorphism)
     239from sage.schemes.generic.scheme import is_Scheme
     240from sage.structure.sequence import Sequence
     241
     242
     243# Default prefix for indexed coordinates
     244DEFAULT_PREFIX = "z"
     245
     246
     247def is_ToricVariety(x):
     248    r"""
     249    Check if ``x`` is a toric variety.
     250   
     251    INPUT:
     252   
     253    - ``x`` -- anything.
     254   
     255    OUTPUT:
     256   
     257    - ``True`` if ``x`` is a :class:`toric variety <ToricVariety_field>` and
     258      ``False`` otherwise.
     259   
     260    .. NOTE::
     261   
     262        While projective spaces are toric varieties mathematically, they are
     263        not toric varieties in Sage due to efficiency considerations, so this
     264        function will return ``False``.
     265   
     266    EXAMPLES::
     267   
     268        sage: from sage.schemes.generic.toric_variety import is_ToricVariety
     269        sage: is_ToricVariety(1)
     270        False
     271        sage: fan = FaceFan(lattice_polytope.octahedron(2))
     272        sage: P = ToricVariety(fan)
     273        sage: P
     274        Toric variety of dimension 2
     275        sage: is_ToricVariety(P)
     276        True
     277        sage: is_ToricVariety(ProjectiveSpace(2))
     278        False
     279    """
     280    return isinstance(x, ToricVariety_field)
     281
     282
     283def ToricVariety(fan,
     284                 coordinate_names=None,
     285                 coordinate_indices=None,
     286                 base_field=QQ):
     287    r"""
     288    Construct a toric variety.
     289   
     290    INPUT:
     291   
     292    - ``fan`` -- :class:`rational polyhedral fan
     293      <sage.geometry.fan.RationalPolyhedralFan>`;
     294   
     295    - ``coordinate_names`` -- names of variables for the coordinate ring, see
     296      :func:`normalize_names` for acceptable formats. If not given, indexed
     297      variable names will be created automatically;
     298   
     299    - ``coordinate_indices`` -- list of integers, indices for indexed
     300      variables. If not given, the index of each variable will coincide with
     301      the index of the corresponding ray of the fan;
     302   
     303    - ``base_field`` -- base field of the toric variety (default: `\QQ`).
     304   
     305    OUTPUT:
     306   
     307    - :class:`toric variety <ToricVariety_field>`.
     308   
     309    EXAMPLES:
     310   
     311    We will create the product of two projective lines::
     312   
     313        sage: fan = FaceFan(lattice_polytope.octahedron(2))
     314        sage: fan.ray_matrix()
     315        [ 1  0 -1  0]
     316        [ 0  1  0 -1]
     317        sage: P1xP1 = ToricVariety(fan)
     318        sage: P1xP1.gens()
     319        (z0, z1, z2, z3)
     320       
     321    Let's create some points::
     322   
     323        sage: P1xP1(1,1,1,1)
     324        [1 : 1 : 1 : 1]
     325        sage: P1xP1(0,1,1,1)
     326        [0 : 1 : 1 : 1]
     327        sage: P1xP1(0,1,0,1)
     328        Traceback (most recent call last):
     329        ...
     330        TypeError: coordinates (0, 1, 0, 1)
     331        are in the exceptional set!
     332   
     333    We cannot set to zero both coordinates of the same projective line!
     334   
     335    Let's change the names of the variables. We have to re-create our toric
     336    variety::
     337   
     338        sage: P1xP1 = ToricVariety(fan, "x s y t")
     339        sage: P1xP1.gens()
     340        (x, s, y, t)
     341       
     342    Now `(x, y)` correspond to one line and `(s, t)` to the other one. ::
     343   
     344        sage: P1xP1.inject_variables()
     345        Defining x, s, y, t
     346        sage: P1xP1.subscheme(x*s-y*t)
     347        Closed subscheme of Toric variety of dimension 2 defined by:
     348          x*s - y*t       
     349    """
     350    if not is_Field(base_field):
     351        raise TypeError("need a field to construct a toric variety!\n Got %s"
     352                        % base_field)
     353    return ToricVariety_field(fan, coordinate_names, coordinate_indices,
     354                             base_field)
     355
     356
     357def AffineToricVariety(cone, *args, **kwds):
     358    r"""
     359    Construct an affine toric variety.
     360   
     361    INPUT:
     362   
     363    - ``cone`` -- :class:`strictly convex rational polyhedral cone
     364      <sage.geometry.cone.ConvexRationalPolyhedralCone>`.
     365     
     366    This cone will be used to construct a :class:`rational polyhedral fan
     367    <sage.geometry.fan.RationalPolyhedralFan>`, which will be passed to
     368    :func:`ToricVariety` with the rest of positional and keyword arguments.
     369   
     370    OUTPUT:
     371   
     372    - :class:`toric variety <ToricVariety_field>`.
     373   
     374    .. NOTE::
     375   
     376        The generating rays of the fan of this variety are guaranteed to be
     377        listed in the same order as the rays of the original cone.
     378   
     379    EXAMPLES:
     380   
     381    We will create the affine plane as an affine toric variety::
     382   
     383        sage: quadrant = Cone([(1,0), (0,1)])
     384        sage: A2 = AffineToricVariety(quadrant)
     385        sage: origin = A2(0,0)
     386        sage: origin
     387        [0 : 0]
     388        sage: parent(origin)
     389        Set of Rational Points of Toric variety of dimension 2
     390
     391    Only affine toric varieties have points whose (homogeneous) coordinates
     392    are all zero.
     393    """
     394    if not cone.is_strictly_convex():
     395        raise ValueError("affine toric varieties are defined for strictly "
     396                         "convex cones only!")
     397    # We make sure that Fan constructor does not meddle with the order of
     398    # rays, this is very important for affine patches construction
     399    fan = Fan([tuple(range(cone.nrays()))], cone.rays(),
     400              check=False, normalize=False)
     401    return ToricVariety(fan, *args, **kwds)
     402
     403
     404class ToricVariety_field(AmbientSpace):
     405    r"""
     406    Construct a toric variety associated to a rational polyhedral fan.
     407   
     408    .. WARNING::
     409   
     410        This class does not perform any checks of correctness of input. Use
     411        :func:`ToricVariety` and :func:`AffineToricVariety` to construct toric
     412        varieties.
     413   
     414    INPUT:
     415   
     416    - ``fan`` -- :class:`rational polyhedral fan
     417      <sage.geometry.fan.RationalPolyhedralFan>`;
     418   
     419    - ``coordinate_names`` -- names of variables, see :func:`normalize_names`
     420      for acceptable formats. If ``None``, indexed variable names will be
     421      created automatically;
     422   
     423    - ``coordinate_indices`` -- list of integers, indices for indexed
     424      variables. If ``None``, the index of each variable will coincide with
     425      the index of the corresponding ray of the fan;
     426   
     427    - ``base_field`` -- base field of the toric variety.
     428   
     429    OUTPUT:
     430   
     431    - :class:`toric variety <ToricVariety_field>`.
     432   
     433    TESTS::
     434   
     435        sage: fan = FaceFan(lattice_polytope.octahedron(2))
     436        sage: P1xP1 = ToricVariety(fan)
     437    """
     438   
     439    def __init__(self, fan, coordinate_names, coordinate_indices, base_field):
     440        r"""
     441        See :class:`ToricVariety_field` for documentation.
     442   
     443        TESTS::
     444       
     445            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     446            sage: P1xP1 = ToricVariety(fan)
     447        """
     448        self._fan = fan
     449        super(ToricVariety_field, self).__init__(fan.ambient_dim(),
     450                                                 base_field)
     451        self._torus_factor_dim = fan.ambient_dim() - fan.dim()
     452        coordinate_names = normalize_names(coordinate_names,
     453                        fan.nrays() + self._torus_factor_dim, DEFAULT_PREFIX,
     454                        coordinate_indices, return_prefix=True)
     455        # Save the prefix for use in resolutions
     456        self._coordinate_prefix = coordinate_names.pop()
     457        self._assign_names(names=coordinate_names, normalize=False)
     458
     459    def __cmp__(self, right):
     460        r"""
     461        Compare ``self`` and ``right``.
     462       
     463        INPUT:
     464       
     465        - ``right`` -- anything.
     466       
     467        OUTPUT:
     468       
     469        - 0 if ``right`` is of the same type as ``self``, their fans are the
     470          same, names of variables are the same and stored in the same order,
     471          and base fields are the same. 1 or -1 otherwise.
     472       
     473        TESTS::
     474       
     475            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     476            sage: P1xP1 = ToricVariety(fan)
     477            sage: P1xP1a = ToricVariety(fan, "x s y t")
     478            sage: P1xP1b = ToricVariety(fan)
     479            sage: cmp(P1xP1, P1xP1a)
     480            1
     481            sage: cmp(P1xP1a, P1xP1)
     482            -1
     483            sage: cmp(P1xP1, P1xP1b)
     484            0
     485            sage: P1xP1 is P1xP1b
     486            False
     487            sage: cmp(P1xP1, 1)
     488            -1
     489        """
     490        c = cmp(type(self), type(right))
     491        if c:
     492            return c
     493        return cmp([self.fan(),
     494                    self.variable_names(),
     495                    self.base_ring()],
     496                   [right.fan(),
     497                    right.variable_names(),
     498                    right.base_ring()])
     499
     500    def _an_element_(self):
     501        r"""
     502        Construct an element of ``self``.
     503       
     504        This function is needed (in particular) for the test framework.
     505       
     506        OUTPUT:
     507       
     508        - a point of ``self`` with coordinates [1 : 2: ... : n].
     509       
     510        TESTS::
     511       
     512            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     513            sage: P1xP1 = ToricVariety(fan)
     514            sage: P1xP1._an_element_()
     515            [1 : 2 : 3 : 4]       
     516        """       
     517        return self(range(1, self.ngens() + 1))
     518
     519    def _check_satisfies_equations(self, coordinates):
     520        r"""
     521        Check if ``coordinates`` define a valid point of ``self``.
     522       
     523        INPUT:
     524       
     525        - ``coordinates`` -- list of elements of the base field of ``self``.
     526       
     527        OUTPUT:
     528       
     529        - ``True`` if ``coordinates`` do define a valid point of ``self``,
     530          otherwise a ``TypeError`` or ``ValueError`` exception is raised.
     531           
     532        TESTS::
     533       
     534            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     535            sage: P1xP1 = ToricVariety(fan)
     536            sage: P1xP1._check_satisfies_equations([1,1,1,1])
     537            True
     538            sage: P1xP1._check_satisfies_equations([0,0,1,1])
     539            True
     540            sage: P1xP1._check_satisfies_equations([0,1,0,1])
     541            Traceback (most recent call last):
     542            ...
     543            TypeError: coordinates (0, 1, 0, 1)
     544            are in the exceptional set!           
     545            sage: P1xP1._check_satisfies_equations([1,1,1])
     546            Traceback (most recent call last):
     547            ...
     548            TypeError: coordinates (1, 1, 1) must have 4 components!           
     549            sage: P1xP1._check_satisfies_equations(1)
     550            Traceback (most recent call last):
     551            ...
     552            TypeError: 1 can not be used as coordinates!
     553            Use a list or a tuple.           
     554            sage: P1xP1._check_satisfies_equations([1,1,1,fan])
     555            Traceback (most recent call last):
     556            ...
     557            TypeError: coordinate Rational polyhedral fan
     558            in a 2-dimensional lattice
     559            is not an element of Rational Field!                   
     560        """
     561        try:
     562            coordinates = tuple(coordinates)
     563        except TypeError:
     564            raise TypeError("%s can not be used as coordinates! "
     565                            "Use a list or a tuple." % coordinates)
     566        n = self.ngens()
     567        if len(coordinates) != n:
     568            raise TypeError("coordinates %s must have %d components!"
     569                            % (coordinates, n))
     570        base_field = self.base_ring()
     571        for coordinate in coordinates:
     572            if coordinate not in base_field:
     573                raise TypeError("coordinate %s is not an element of %s!"
     574                                % (coordinate, base_field))       
     575        zero_positions = frozenset(position
     576                            for position, coordinate in enumerate(coordinates)
     577                            if coordinate == 0)
     578        if not zero_positions:
     579            return True
     580        for i in range(n - self._torus_factor_dim, n):
     581            if i in zero_positions:
     582                raise ValueError("coordinates on the torus factor cannot be "
     583                                 "zero! Got %s" % str(coordinates))
     584        if len(zero_positions) == 1:
     585            return True
     586        if self.fan().containing_cones(zero_positions):
     587                return True     # All zeros are inside one generating cone
     588        raise TypeError("coordinates %s are in the exceptional set!"
     589                        % str(coordinates)) # Need str, coordinates is a tuple
     590
     591    def _homset_class(self, *args, **kwds):
     592        r"""
     593        Construct a `Hom`-space for ``self``.
     594       
     595        INPUT:
     596       
     597        - same as for :class:`SchemeHomset_toric_coordinates_field`.
     598       
     599        OUPUT:
     600       
     601        - :class:`SchemeHomset_toric_coordinates_field`.
     602       
     603        TESTS::
     604       
     605            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     606            sage: P1xP1 = ToricVariety(fan)
     607            sage: P1xP1._homset_class(P1xP1, P1xP1.base_ring())
     608            Set of Rational Points of Toric variety of dimension 2
     609        """
     610        return SchemeHomset_toric_coordinates_field(*args, **kwds)
     611
     612    def _latex_(self):
     613        r"""
     614        Return a LaTeX representation of ``self``.
     615       
     616        OUTPUT:
     617       
     618        - string.
     619       
     620        TESTS::
     621       
     622            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     623            sage: P1xP1 = ToricVariety(fan)
     624            sage: P1xP1._latex_()
     625            '\\mathbb{P}_{\\Sigma^{2}}'       
     626        """
     627        return r"\mathbb{P}_{%s}" % latex(self.fan())
     628
     629    def _latex_generic_point(self, coordinates=None):
     630        """
     631        Return a LaTeX representation of a point of ``self``.
     632       
     633        INPUT:
     634       
     635        - ``coordinates`` -- list of coordinates of a point of ``self``.
     636          If not given, names of coordinates of ``self`` will be used.
     637           
     638        OUTPUT:
     639       
     640        - string.
     641       
     642        EXAMPLES::
     643       
     644            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     645            sage: P1xP1 = ToricVariety(fan)
     646            sage: P1xP1._latex_generic_point()
     647            '\\left[z_{0} : z_{1} : z_{2} : z_{3}\\right]'
     648            sage: P1xP1._latex_generic_point([1,2,3,4])
     649            '\\left[1 : 2 : 3 : 4\\right]'
     650        """
     651        if coordinates is None:
     652            coordinates = self.gens()
     653        return r"\left[%s\right]" % (" : ".join(str(latex(coord))
     654                                                for coord in coordinates))
     655
     656    def _point_class(self, *args, **kwds):
     657        r"""
     658        Construct a point of ``self``.
     659       
     660        INPUT:
     661       
     662        - same as for :class:`SchemeMorphism_toric_coordinates_field`.
     663       
     664        OUPUT:
     665       
     666        - :class:`SchemeMorphism_toric_coordinates_field`.
     667           
     668        TESTS::
     669       
     670            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     671            sage: P1xP1 = ToricVariety(fan)
     672            sage: P1xP1._point_class(P1xP1, [1,2,3,4])
     673            [1 : 2 : 3 : 4]
     674        """
     675        return SchemeMorphism_toric_coordinates_field(*args, **kwds)
     676
     677    def _point_morphism_class(self, *args, **kwds):
     678        r"""
     679        Construct a morphism determined by action on points of ``self``.
     680       
     681        INPUT:
     682       
     683        - same as for :class:`SchemeMorphism_on_points_toric_variety`.
     684       
     685        OUPUT:
     686       
     687        - :class:`SchemeMorphism_on_points_toric_variety`.
     688           
     689        TESTS::
     690       
     691            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     692            sage: P1xP1 = ToricVariety(fan)
     693            sage: P1xP1.inject_variables()
     694            Defining z0, z1, z2, z3
     695            sage: P1 = P1xP1.subscheme(z0-z2)
     696            sage: H = P1xP1.Hom(P1)
     697            sage: P1xP1._point_morphism_class(H, [z0,z1,z0,z3])
     698            Scheme morphism:
     699              From: Toric variety of dimension 2
     700              To:   Closed subscheme of Toric variety
     701                    of dimension 2 defined by:
     702              z0 - z2
     703              Defn: Defined on coordinates by sending
     704                    [z0 : z1 : z2 : z3] to [z0 : z1 : z0 : z3]           
     705        """
     706        return SchemeMorphism_on_points_toric_variety(*args, **kwds)
     707
     708    def _repr_(self):
     709        r"""
     710        Return a string representation of ``self``.
     711       
     712        OUTPUT:
     713       
     714        - string.
     715       
     716        TESTS::
     717       
     718            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     719            sage: P1xP1 = ToricVariety(fan)
     720            sage: P1xP1._repr_()
     721            'Toric variety of dimension 2'       
     722        """
     723        return "Toric variety of dimension %s" % self.dimension_relative()
     724
     725    def _repr_generic_point(self, coordinates=None):
     726        r"""
     727        Return a string representation of a point of ``self``.
     728       
     729        INPUT:
     730       
     731        - ``coordinates`` -- list of coordinates of a point of ``self``.
     732          If not given, names of coordinates of ``self`` will be used.
     733           
     734        OUTPUT:
     735       
     736        - string.
     737       
     738        EXAMPLES::
     739       
     740            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     741            sage: P1xP1 = ToricVariety(fan)
     742            sage: P1xP1._repr_generic_point()
     743            '[z0 : z1 : z2 : z3]'
     744            sage: P1xP1._repr_generic_point([1,2,3,4])
     745            '[1 : 2 : 3 : 4]'
     746        """
     747        if coordinates is None:
     748            coordinates = self.gens()
     749        return "[%s]" % (" : ".join(str(coord) for coord in coordinates))
     750   
     751    def _validate(self, polynomials):
     752        """
     753        Check if ``polynomials`` define valid functions on ``self``.
     754       
     755        Since this is a toric variety, polynomials must be homogeneous in the
     756        total coordinate ring of ``self``.
     757       
     758        INPUT:
     759       
     760        - ``polynomials`` -- list of polynomials in the coordinate ring of
     761          ``self`` (this function does not perfrom any conversions).
     762           
     763        OUTPUT:
     764       
     765        - ``polynomials`` (the input parameter without any modifications) if
     766          ``polynomials`` do define valid polynomial functions on ``self``,
     767          otherwise a ``ValueError`` exception is raised.
     768         
     769        TESTS:
     770       
     771        We will use the product of two projective lines with coordinates
     772        `(x, y)` for one and `(s, t)` for the other::
     773
     774            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     775            sage: fan.ray_matrix()
     776            [ 1  0 -1  0]
     777            [ 0  1  0 -1]
     778            sage: P1xP1 = ToricVariety(fan, "x s y t")
     779            sage: P1xP1.inject_variables()
     780            Defining x, s, y, t
     781            sage: P1xP1._validate([x - y, x*s + y*t])
     782            [x - y, x*s + y*t]
     783            sage: P1xP1._validate([x + s])
     784            Traceback (most recent call last):
     785            ...
     786            ValueError: x + s is not homogeneous on
     787            Toric variety of dimension 2!
     788        """
     789        for p in polynomials:
     790            if not self.is_homogeneous(p):
     791                raise ValueError("%s is not homogeneous on %s!" % (p, self))
     792        return polynomials
     793
     794    def affine_patch(self, i):
     795        r"""
     796        Return the ``i``-th affine patch of ``self``.
     797       
     798        INPUT:
     799       
     800        - ``i`` -- integer, index of a generating cone of the fan of ``self``.
     801       
     802        OUTPUT:
     803       
     804        - affine :class:`toric variety <ToricVariety_field>` corresponding to
     805          the ``i``-th generating cone of the fan of ``self``.
     806         
     807        The result is cached, so the ``i``-th patch is always the same object
     808        in memory.
     809       
     810        EXAMPLES::
     811       
     812            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     813            sage: P1xP1 = ToricVariety(fan, "x s y t")
     814            sage: patch0 = P1xP1.affine_patch(0)
     815            sage: patch0
     816            Toric variety of dimension 2
     817            sage: patch0.embedding_morphism()
     818            Scheme morphism:
     819              From: Toric variety of dimension 2
     820              To:   Toric variety of dimension 2
     821              Defn: Defined on coordinates by sending [x : t] to
     822                    [x : 1 : 1 : t]           
     823            sage: patch1 = P1xP1.affine_patch(1)
     824            sage: patch1.embedding_morphism()
     825            Scheme morphism:
     826              From: Toric variety of dimension 2
     827              To:   Toric variety of dimension 2
     828              Defn: Defined on coordinates by sending [y : t] to
     829                    [1 : 1 : y : t]           
     830            sage: patch1 is P1xP1.affine_patch(1)
     831            True
     832        """
     833        i = int(i)   # implicit type checking
     834        try:
     835            return self._affine_patches[i]
     836        except AttributeError:
     837            self._affine_patches = dict()
     838        except KeyError:
     839            pass
     840        cone = self.fan().generating_cone(i)
     841        names = self.variable_names()
     842        # Number of "honest fan coordinates"
     843        n = self.fan().nrays()
     844        # Number of "torus factor coordinates"
     845        t = self._torus_factor_dim
     846        names = [names[ray] for ray in cone.fan_rays()] + list(names[n:])
     847        patch = AffineToricVariety(cone, names, base_field=self.base_ring())
     848        embedding_coordinates = [1] * n
     849        for k, ray in enumerate(cone.fan_rays()):
     850            embedding_coordinates[ray] = patch.gen(k)
     851        if t > 0: # Passing "-0" gives unintended result
     852            embedding_coordinates.extend(patch.gens()[-t:])
     853        patch._embedding_morphism = patch.hom(embedding_coordinates, self)
     854        self._affine_patches[i] = patch
     855        return patch
     856
     857    def change_ring(self, F):
     858        r"""
     859        Return a toric variety over ``F`` and otherwise the same as ``self``.
     860
     861        INPUT:
     862
     863        - ``F`` -- field.
     864
     865        OUTPUT:
     866
     867        - :class:`toric variety <ToricVariety_field>` over ``F``.
     868
     869        .. NOTE::
     870
     871            There is no need to have any relation between ``F`` and the base
     872            field of ``self``. If you do want to have such a relation, use
     873            :meth:`base_extend` instead.
     874
     875        EXAMPLES::
     876       
     877            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     878            sage: P1xP1 = ToricVariety(fan)
     879            sage: P1xP1.base_ring()
     880            Rational Field
     881            sage: P1xP1_RR = P1xP1.change_ring(RR)
     882            sage: P1xP1_RR.base_ring()
     883            Real Field with 53 bits of precision
     884            sage: P1xP1_QQ = P1xP1_RR.change_ring(QQ)
     885            sage: P1xP1_QQ.base_ring()
     886            Rational Field
     887            sage: P1xP1_RR.base_extend(QQ)
     888            Traceback (most recent call last):
     889            ...
     890            ValueError: no natural map from the base ring
     891            (=Real Field with 53 bits of precision)
     892            to R (=Rational Field)!           
     893        """
     894        if self.base_ring() == F:
     895            return self
     896        else:
     897            return ToricVariety(self.fan(), self.variable_names(),
     898                                base_field=F)
     899                               
     900    def coordinate_ring(self):
     901        r"""
     902        Return the coordinate ring of ``self``.
     903       
     904        For toric varieties this is the homogeneous coordinate ring (a.k.a.
     905        Cox's ring and total ring).
     906       
     907        OUTPUT:
     908       
     909        - polynomial ring.
     910       
     911        EXAMPLES::
     912       
     913            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     914            sage: P1xP1 = ToricVariety(fan)
     915            sage: P1xP1.coordinate_ring()
     916            Multivariate Polynomial Ring in z0, z1, z2, z3
     917            over Rational Field
     918        """
     919        if "_coordinate_ring" not in self.__dict__:
     920            self._coordinate_ring = PolynomialRing(self.base_ring(),
     921                                                   self.variable_names())
     922        return self._coordinate_ring
     923   
     924    def embedding_morphism(self):
     925        r"""
     926        Return the default embedding morphism of ``self``.
     927       
     928        Such a morphism is always defined for an affine patch of a toric
     929        variety (which is also a toric varieties itself).
     930       
     931        OUTPUT:
     932       
     933        - :class:`scheme morhphism <SchemeMorphism_on_points_toric_variety>`
     934          if the default embedding morphism was defined for ``self``,
     935          otherwise a ``ValueError`` exception is raised.
     936       
     937        EXAMPLES::
     938       
     939            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     940            sage: P1xP1 = ToricVariety(fan, "x s y t")
     941            sage: P1xP1.embedding_morphism()
     942            Traceback (most recent call last):
     943            ...
     944            ValueError: no default embedding was
     945            defined for this toric variety!
     946            sage: patch = P1xP1.affine_patch(0)
     947            sage: patch
     948            Toric variety of dimension 2
     949            sage: patch.embedding_morphism()
     950            Scheme morphism:
     951              From: Toric variety of dimension 2
     952              To:   Toric variety of dimension 2
     953              Defn: Defined on coordinates by sending [x : t] to
     954                    [x : 1 : 1 : t]           
     955        """
     956        try:
     957            return self._embedding_morphism
     958        except AttributeError:
     959            raise ValueError("no default embedding was defined for this "
     960                             "toric variety!")
     961       
     962    def fan(self):
     963        r"""
     964        Return the underlying fan of ``self``.
     965       
     966        OUTPUT:
     967       
     968        - :class:`rational polyhedral fan
     969          <sage.geometry.fan.RationalPolyhedralFan>`.
     970         
     971        EXAMPLES::
     972       
     973            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     974            sage: P1xP1 = ToricVariety(fan)
     975            sage: P1xP1.fan()
     976            Rational polyhedral fan in a 2-dimensional lattice
     977            sage: P1xP1.fan() is fan
     978            True
     979        """
     980        return self._fan
     981   
     982    def inject_coefficients(self, scope=None, verbose=True):
     983        r"""
     984        Inject generators of the base field of ``self`` into ``scope``.
     985       
     986        This function is useful if the base field is the field of rational
     987        functions.
     988       
     989        INPUT:
     990       
     991        - ``scope`` -- namespace (default: global);
     992       
     993        - ``verbose`` -- if ``True`` (default), names of injected generators
     994          will be printed.
     995         
     996        OUTPUT:
     997       
     998        - none.
     999       
     1000        EXAMPLES::
     1001       
     1002            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1003            sage: P1xP1 = ToricVariety(fan)
     1004            sage: P1xP1.inject_coefficients()
     1005           
     1006        The last command does nothing, since ``P1xP1`` is defined over `\QQ`.
     1007        Let's construct a toric variety over a more complicated field::
     1008       
     1009            sage: F = QQ["a, b"].fraction_field()
     1010            sage: P1xP1 = ToricVariety(fan, base_field=F)
     1011            sage: P1xP1.inject_coefficients()
     1012            Defining a, b
     1013        """
     1014        if is_FractionField(self.base_ring()):
     1015            self.base_ring().inject_variables(scope, verbose)
     1016   
     1017    def is_homogeneous(self, polynomial):
     1018        r"""
     1019        Check if ``polynomial`` is homogeneous.
     1020       
     1021        The coordinate ring of a toric variety is multigraded by relations
     1022        between generating rays of the underlying fan.
     1023       
     1024        INPUT:
     1025       
     1026        - ``polynomial`` -- polynomial in the coordinate ring of ``self``.
     1027       
     1028        OUTPUT:
     1029       
     1030        - ``True`` if ``polynomial`` is homogeneous and ``False`` otherwise.
     1031       
     1032        EXAMPLES:
     1033       
     1034        We will use the product of two projective lines with coordinates
     1035        `(x, y)` for one and `(s, t)` for the other::
     1036
     1037            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1038            sage: fan.ray_matrix()
     1039            [ 1  0 -1  0]
     1040            [ 0  1  0 -1]
     1041            sage: P1xP1 = ToricVariety(fan, "x s y t")
     1042            sage: P1xP1.inject_variables()
     1043            Defining x, s, y, t
     1044            sage: P1xP1.is_homogeneous(x - y)
     1045            True
     1046            sage: P1xP1.is_homogeneous(x*s + y*t)
     1047            True
     1048            sage: P1xP1.is_homogeneous(x - t)
     1049            False
     1050        """
     1051        if "_relation_matrix" not in self.__dict__:
     1052            m = self.fan().ray_matrix().transpose().kernel().matrix()
     1053            # We ignore degrees of torus factor coordinates
     1054            m = m.augment(matrix(m.nrows(), self._torus_factor_dim))
     1055            self._relation_matrix = m
     1056        relation_matrix = self._relation_matrix
     1057        monomials = polynomial.monomials()
     1058        if not monomials:
     1059            return True
     1060        degree = relation_matrix * vector(monomials[0].degrees())
     1061        for monomial in monomials:
     1062            if relation_matrix * vector(monomial.degrees()) != degree:
     1063                return False
     1064        return True
     1065
     1066    def is_isomorphic(self, another):
     1067        r"""
     1068        Check if ``self`` is isomorphic to ``another``.
     1069       
     1070        INPUT:
     1071       
     1072        - ``another`` - :class:`toric variety <ToricVariety_field>`.
     1073       
     1074        OUTPUT:
     1075       
     1076        - ``True`` if ``self`` and ``another`` are isomorphic,
     1077          ``False`` otherwise.
     1078         
     1079        EXAMPLES::
     1080       
     1081            sage: fan1 = FaceFan(lattice_polytope.octahedron(2))
     1082            sage: TV1 = ToricVariety(fan1)
     1083            sage: fan2 = NormalFan(lattice_polytope.octahedron(2))
     1084            sage: TV2 = ToricVariety(fan2)
     1085           
     1086        Only the most trivial case is implemented so far::
     1087       
     1088            sage: TV1.is_isomorphic(TV1)
     1089            True
     1090            sage: TV1.is_isomorphic(TV2)
     1091            Traceback (most recent call last):
     1092            ...
     1093            NotImplementedError:
     1094            isomorphism check is not yet implemented!           
     1095        """
     1096        if self is another:
     1097            return True
     1098        if not is_ToricVariety(another):
     1099            raise TypeError(
     1100                "only another toric variety can be checked for isomorphism! "
     1101                "Got %s" % another)
     1102        raise NotImplementedError("isomorphism check is not yet implemented!")
     1103       
     1104    def is_complete(self):
     1105        r"""
     1106        Check if ``self`` is complete.
     1107       
     1108        OUTPUT:
     1109       
     1110        - ``True`` if ``self`` is complete and ``False`` otherwise.
     1111       
     1112        EXAMPLES::
     1113       
     1114            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1115            sage: P1xP1 = ToricVariety(fan)
     1116            sage: P1xP1.is_complete()
     1117            True
     1118            sage: P1xP1.affine_patch(0).is_complete()
     1119            False
     1120        """
     1121        return self.fan().is_complete()
     1122       
     1123    def is_orbifold(self):
     1124        r"""
     1125        Check if ``self`` has only quotient singularities.
     1126       
     1127        OUTPUT:
     1128       
     1129        - ``True`` if ``self`` has only quotient singularities, ``False``
     1130          otherwise.
     1131       
     1132        EXAMPLES::
     1133       
     1134            sage: fan1 = FaceFan(lattice_polytope.octahedron(2))
     1135            sage: P1xP1 = ToricVariety(fan1)
     1136            sage: P1xP1.is_orbifold()
     1137            True
     1138            sage: fan2 = NormalFan(lattice_polytope.octahedron(3))
     1139            sage: TV = ToricVariety(fan2)
     1140            sage: TV.is_orbifold()
     1141            False
     1142        """
     1143        return self.fan().is_simplicial()
     1144       
     1145    def is_smooth(self):
     1146        r"""
     1147        Check if ``self`` is smooth.
     1148       
     1149        OUTPUT:
     1150       
     1151        - ``True`` if ``self`` is smooth and ``False`` otherwise.
     1152       
     1153        EXAMPLES::
     1154           
     1155            sage: diamond = lattice_polytope.octahedron(2)
     1156            sage: fan1 = FaceFan(diamond)
     1157            sage: P1xP1 = ToricVariety(fan1)
     1158            sage: P1xP1.is_smooth()
     1159            True
     1160            sage: fan2 = NormalFan(lattice_polytope.octahedron(2))
     1161            sage: TV = ToricVariety(fan2)
     1162            sage: TV.is_smooth()
     1163            False
     1164        """
     1165        return self.fan().is_smooth()
     1166
     1167    def kaehler_cone(self):
     1168        r"""
     1169        Return the Kaehler cone of ``self``.
     1170       
     1171        OUTPUT:
     1172       
     1173        - matrix.
     1174       
     1175        EXAMPLES::
     1176       
     1177            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1178            sage: P1xP1 = ToricVariety(fan)
     1179            sage: P1xP1.kaehler_cone().ray_matrix()
     1180            [0 1]
     1181            [1 0]           
     1182        """
     1183        if "_kaehler_cone" not in self.__dict__:
     1184            fan = self.fan()
     1185            GT = fan.gale_transform().columns()
     1186            n = fan.nrays()
     1187            K = None
     1188            for cone in fan:
     1189                sigma = Cone(GT[i] for i in range(n)
     1190                                   if i not in cone.fan_rays())
     1191                K = K.intersection(sigma) if K is not None else sigma
     1192            self._kaehler_cone = K
     1193        return self._kaehler_cone
     1194       
     1195    def resolve(self, **kwds):
     1196        r"""
     1197        Construct a toric variety whose fan subdivides the fan of ``self``.
     1198       
     1199        The name of this function reflects the fact that usually such
     1200        subdivisions are done for resolving singularities of the original
     1201        variety.
     1202       
     1203        INPUT:
     1204       
     1205        This function accepts only keyword arguments, none of which are
     1206        mandatory.
     1207       
     1208        - ``coordinate_names`` -- names for coordinates of the new variety. If
     1209          not given, will be constructed from the coordinate names of ``self``
     1210          and necessary indexed ones. See :func:`normalize_names` for the
     1211          description of acceptable formats;
     1212       
     1213        - ``coordinate_indices`` -- coordinate indices which should be used
     1214          for indexed variables of the new variety;
     1215       
     1216        - all other arguments will be passed to
     1217          :meth:`~sage.geometry.fan.RationalPolyhedralFan.subdivide` method of
     1218          the underlying :class:`rational polyhedral fan
     1219          <sage.geometry.fan.RationalPolyhedralFan>`, see its documentation
     1220          for the available options.
     1221         
     1222        OUTPUT:
     1223       
     1224        - :class:`toric variety <ToricVariety_field>`.
     1225       
     1226        EXAMPLES:
     1227       
     1228        First we will "manually" resolve a simple orbifold singularity::
     1229       
     1230            sage: cone = Cone([(1,1), (-1,1)])
     1231            sage: fan = Fan([cone])
     1232            sage: TV = ToricVariety(fan)
     1233            sage: TV.is_smooth()
     1234            False
     1235            sage: TV_res = TV.resolve(new_rays=[(0,1)])
     1236            sage: TV_res.is_smooth()
     1237            True
     1238            sage: TV_res.fan().ray_matrix()
     1239            [-1  1  0]
     1240            [ 1  1  1]           
     1241            sage: [cone.fan_rays() for cone in TV_res.fan()]
     1242            [(1, 2), (0, 2)]
     1243           
     1244        Now let's "automatically" partially resolve a more complicated fan::
     1245       
     1246            sage: fan = NormalFan(lattice_polytope.octahedron(3))
     1247            sage: TV = ToricVariety(fan)
     1248            sage: TV.is_smooth()
     1249            False
     1250            sage: TV.is_orbifold()
     1251            False
     1252            sage: TV.fan().nrays()
     1253            8
     1254            sage: TV.fan().ngenerating_cones()
     1255            6
     1256            sage: TV_res = TV.resolve(make_simplicial=True)
     1257            sage: TV_res.is_smooth()
     1258            False
     1259            sage: TV_res.is_orbifold()
     1260            True
     1261            sage: TV_res.fan().nrays()
     1262            8
     1263            sage: TV_res.fan().ngenerating_cones()
     1264            12
     1265            sage: TV.gens()
     1266            (z0, z1, z2, z3, z4, z5, z6, z7)
     1267            sage: TV_res.gens()
     1268            (z0, z1, z2, z3, z4, z5, z6, z7)
     1269            sage: TV_res = TV.resolve(coordinate_names="x+",
     1270            ...                       make_simplicial=True)
     1271            sage: TV_res.gens()       
     1272            (x0, x1, x2, x3, x4, x5, x6, x7)
     1273        """
     1274        # If you are changing this function, check out resolve in Fano toric
     1275        # varieties to see if it should be changed too
     1276        #
     1277        # Currently the resolution of fans works for full-dimensional ones
     1278        # only, so there is no point to deal with the general case here, since
     1279        # we will not be able to check that it works.
     1280        coordinate_names = kwds.pop("coordinate_names", None)
     1281        coordinate_indices = kwds.pop("coordinate_indices", None)
     1282        fan = self.fan()
     1283        if fan.dim() != fan.ambient_dim():
     1284            raise NotImplementedError("resolution of toric varieties with "
     1285                                      "torus factors is not yet implemented!")
     1286            # When it is implemented, should be carefull with the torus factor
     1287        rfan = fan.subdivide(**kwds)
     1288        if coordinate_names is None:
     1289            coordinate_names = list(self.variable_names())
     1290            if coordinate_indices is None:
     1291                coordinate_indices = range(fan.nrays(), rfan.nrays())
     1292            else:
     1293                coordinate_indices = coordinate_indices[fan.nrays():]
     1294            coordinate_names.extend(normalize_names(
     1295                                    ngens=rfan.nrays() - fan.nrays(),
     1296                                    indices=coordinate_indices,
     1297                                    prefix=self._coordinate_prefix))
     1298            coordinate_names.append(self._coordinate_prefix + "+")
     1299        resolution = ToricVariety(rfan, coordinate_names=coordinate_names,
     1300                                  coordinate_indices=coordinate_indices,
     1301                                  base_field=self.base_ring())
     1302        R = self.coordinate_ring()
     1303        R_res = resolution.coordinate_ring()
     1304        resolution_map = resolution.hom(R.hom(R_res.gens()[:R.ngens()]), self)
     1305        resolution._resolution_map = resolution_map
     1306        # The above map does not have (yet) public methods to access it.
     1307        # While this map is defined correctly, base classes of schemes and
     1308        # morhpisms do not treat it as they should. The plan is to fix this
     1309        # situation soon and to be able to use this map!
     1310        return resolution
     1311       
     1312    def resolve_to_orbifold(self, **kwds):
     1313        r"""
     1314        Construct an orbifold whose fan subdivides the fan of ``self``.
     1315       
     1316        It is a synonym for :meth:`resolve` with ``make_simplicial=True``
     1317        option.
     1318       
     1319        INPUT:
     1320       
     1321        - this function accepts only keyword arguments. See :meth:`resolve`
     1322          for documentation.
     1323       
     1324        OUTPUT:
     1325       
     1326        - :class:`toric variety <ToricVariety_field>`.
     1327       
     1328        EXAMPLES::
     1329
     1330            sage: fan = NormalFan(lattice_polytope.octahedron(3))
     1331            sage: TV = ToricVariety(fan)
     1332            sage: TV.is_orbifold()
     1333            False
     1334            sage: TV.fan().nrays()
     1335            8
     1336            sage: TV.fan().ngenerating_cones()
     1337            6
     1338            sage: TV_res = TV.resolve_to_orbifold()
     1339            sage: TV_res.is_orbifold()
     1340            True
     1341            sage: TV_res.fan().nrays()
     1342            8
     1343            sage: TV_res.fan().ngenerating_cones()
     1344            12
     1345        """
     1346        return self.resolve(make_simplicial=True, **kwds)
     1347       
     1348    def subscheme(self, polynomials):
     1349        r"""
     1350        Return the subscheme of ``self`` defined by ``polynomials``.
     1351       
     1352        INPUT:
     1353       
     1354        - ``polynomials`` -- list of polynomials in the coordinate ring of
     1355          ``self``.
     1356         
     1357        OUTPUT:
     1358       
     1359        - :class:`subscheme of a toric variety
     1360          <AlgebraicScheme_subscheme_toric>`.
     1361       
     1362        EXAMPLES:
     1363       
     1364        We will construct a subscheme of the product of two projective lines
     1365        with coordinates `(x, y)` for one and `(s, t)` for the other::
     1366
     1367            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1368            sage: fan.ray_matrix()
     1369            [ 1  0 -1  0]
     1370            [ 0  1  0 -1]
     1371            sage: P1xP1 = ToricVariety(fan, "x s y t")
     1372            sage: P1xP1.inject_variables()
     1373            Defining x, s, y, t
     1374            sage: X = P1xP1.subscheme([x*s + y*t, x^3+y^3])
     1375            sage: X
     1376            Closed subscheme of Toric variety of dimension 2 defined by:
     1377              x*s + y*t,
     1378              x^3 + y^3
     1379            sage: X.defining_polynomials()
     1380            (x*s + y*t, x^3 + y^3)
     1381            sage: X.defining_ideal()
     1382            Ideal (x*s + y*t, x^3 + y^3)
     1383            of Multivariate Polynomial Ring in x, s, y, t
     1384            over Rational Field
     1385            sage: X.base_ring()
     1386            Rational Field
     1387            sage: X.base_scheme()
     1388            Spectrum of Rational Field
     1389            sage: X.structure_morphism()
     1390            Scheme morphism:
     1391              From: Closed subscheme of
     1392              Toric variety of dimension 2 defined by:
     1393              x*s + y*t,
     1394              x^3 + y^3
     1395              To:   Spectrum of Rational Field
     1396              Defn: Structure map           
     1397        """
     1398        return AlgebraicScheme_subscheme_toric(self, polynomials)
     1399
     1400
     1401class AlgebraicScheme_subscheme_toric(AlgebraicScheme_subscheme):
     1402    r"""
     1403    Construct an algebraic subscheme of a toric variety.
     1404   
     1405    .. WARNING::
     1406   
     1407        You should not create objects of this class directly. The preferred
     1408        method to construct such subschemes is to use
     1409        :meth:`~ToricVariety_field.subscheme` method of
     1410        :class:`toric varieties <ToricVariety_field>`.
     1411   
     1412    INPUT:
     1413   
     1414    - ``toric_variety`` -- ambient :class:`toric variety
     1415      <ToricVariety_field>`;
     1416   
     1417    - ``polynomials`` -- single polynomial, list, or ideal of defining
     1418      polynomials in the coordinate ring of ``toric_variety``.
     1419   
     1420    OUTPUT:
     1421   
     1422    - :class:`algebraic subscheme of a toric variety
     1423      <AlgebraicScheme_subscheme_toric>`.
     1424   
     1425    TESTS::
     1426   
     1427        sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1428        sage: P1xP1 = ToricVariety(fan, "x s y t")
     1429        sage: P1xP1.inject_variables()
     1430        Defining x, s, y, t
     1431        sage: import sage.schemes.generic.toric_variety as tv       
     1432        sage: X = tv.AlgebraicScheme_subscheme_toric(
     1433        ...         P1xP1, [x*s + y*t, x^3+y^3])
     1434        sage: X
     1435        Closed subscheme of Toric variety of dimension 2 defined by:
     1436          x*s + y*t,
     1437          x^3 + y^3
     1438         
     1439    A better way to construct the same scheme as above::
     1440   
     1441        sage: P1xP1.subscheme([x*s + y*t, x^3+y^3])
     1442        Closed subscheme of Toric variety of dimension 2 defined by:
     1443          x*s + y*t,
     1444          x^3 + y^3
     1445    """
     1446   
     1447    def __init__(self, toric_variety, polynomials):
     1448        r"""
     1449        See :class:`AlgebraicScheme_subscheme_toric` for documentation.
     1450       
     1451        TESTS::
     1452       
     1453            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1454            sage: P1xP1 = ToricVariety(fan, "x s y t")
     1455            sage: P1xP1.inject_variables()
     1456            Defining x, s, y, t
     1457            sage: import sage.schemes.generic.toric_variety as tv           
     1458            sage: X = tv.AlgebraicScheme_subscheme_toric(
     1459            ...         P1xP1, [x*s + y*t, x^3+y^3])
     1460            sage: X
     1461            Closed subscheme of Toric variety of dimension 2 defined by:
     1462              x*s + y*t,
     1463              x^3 + y^3
     1464        """
     1465        # Just to make sure that keyword arguments will be passed correctly
     1466        super(AlgebraicScheme_subscheme_toric, self).__init__(toric_variety,
     1467                                                              polynomials)
     1468   
     1469    def _point_morphism_class(self, *args, **kwds):
     1470        r"""
     1471        Construct a morphism determined by action on points of ``self``.
     1472       
     1473        INPUT:
     1474       
     1475        - same as for :class:`SchemeMorphism_on_points_toric_variety`.
     1476       
     1477        OUPUT:
     1478       
     1479        - :class:`SchemeMorphism_on_points_toric_variety`.
     1480           
     1481        TESTS::
     1482       
     1483            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1484            sage: P1xP1 = ToricVariety(fan)
     1485            sage: P1xP1.inject_variables()
     1486            Defining z0, z1, z2, z3
     1487            sage: P1 = P1xP1.subscheme(z0-z2)
     1488            sage: H = P1.Hom(P1xP1)
     1489            sage: P1._point_morphism_class(H, [z0,z1,z0,z3])
     1490            Traceback (most recent call last):
     1491            ...
     1492            AttributeError: 'QuotientRingElement'
     1493            object has no attribute 'degrees'
     1494           
     1495        TODO: Fix the above (projective spaces have the same issue).
     1496        """
     1497        return SchemeMorphism_on_points_toric_variety(*args, **kwds)
     1498
     1499    def affine_patch(self, i):
     1500        r"""
     1501        Return the ``i``-th affine patch of ``self``.
     1502       
     1503        INPUT:
     1504       
     1505        - ``i`` -- integer, index of a generating cone of the fan of the
     1506          ambient space of ``self``.
     1507       
     1508        OUTPUT:
     1509       
     1510        - subscheme of an affine :class:`toric variety <ToricVariety_field>`
     1511          corresponding to the pullback of ``self`` by the embedding morphism
     1512          of the ``i``-th :meth:`affine patch of the ambient space
     1513          <ToricVariety_field.affine_patch>` of ``self``.
     1514         
     1515        The result is cached, so the ``i``-th patch is always the same object
     1516        in memory.
     1517       
     1518        EXAMPLES::
     1519       
     1520            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1521            sage: P1xP1 = ToricVariety(fan, "x s y t")
     1522            sage: patch1 = P1xP1.affine_patch(1)
     1523            sage: patch1.embedding_morphism()
     1524            Scheme morphism:
     1525              From: Toric variety of dimension 2
     1526              To:   Toric variety of dimension 2
     1527              Defn: Defined on coordinates by sending [y : t] to
     1528                    [1 : 1 : y : t]           
     1529            sage: P1xP1.inject_variables()
     1530            Defining x, s, y, t
     1531            sage: P1 = P1xP1.subscheme(x-y)
     1532            sage: subpatch = P1.affine_patch(1)
     1533            Traceback (most recent call last):
     1534            ...
     1535            NotImplementedError: affine patches
     1536            of toric subschemes are not yet implemented!           
     1537        """
     1538        # There are some errors relating to checking homogenuity in quotient
     1539        # rings, probably related to the error in _point_morphism class.
     1540        # Untill it is resolved, we block this code
     1541        raise NotImplementedError("affine patches of toric subschemes are "
     1542                                  "not yet implemented!")
     1543        # But in principle the stuff below should work
     1544        i = int(i)   # implicit type checking
     1545        try:
     1546            return self._affine_patches[i]
     1547        except AttributeError:
     1548            self._affine_patches = dict()
     1549        except KeyError:
     1550            pass
     1551        ambient_patch = self.ambient_space().affine_patch(i)       
     1552        phi_p = ambient_patch.embedding_morphism().defining_polynomials()
     1553        patch = ambient_patch.subscheme(
     1554                            [p(phi_p) for p in self.defining_polynomials()])
     1555        patch._embedding_morphism = patch.hom(phi_p, self)
     1556        self._affine_patches[i] = patch
     1557        return patch
     1558
     1559    def dimension(self):
     1560        """
     1561        Return the dimension of ``self``.
     1562       
     1563        .. NOTE::
     1564       
     1565            Currently the dimension of subschemes of toric varieties can be
     1566            returned only if it was somehow set before.
     1567       
     1568        OUTPUT:
     1569       
     1570        - integer.
     1571       
     1572        EXAMPLES::
     1573       
     1574            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1575            sage: P1xP1 = ToricVariety(fan)
     1576            sage: P1xP1.inject_variables()
     1577            Defining z0, z1, z2, z3
     1578            sage: P1 = P1xP1.subscheme(z0-z2)
     1579            sage: P1.dimension()
     1580            Traceback (most recent call last):
     1581            ...
     1582            NotImplementedError:
     1583            cannot compute dimension of this scheme!
     1584        """
     1585        if "_dimension" not in self.__dict__:
     1586            raise NotImplementedError(
     1587                                "cannot compute dimension of this scheme!")
     1588        return self._dimension
     1589
     1590
     1591class SchemeHomset_toric_coordinates_field(SchemeHomset_coordinates):
     1592    """
     1593    Construct the `Hom`-space of morphisms given on coordinates.
     1594   
     1595    .. WARNING::
     1596   
     1597        You should not create objects of this class directly.
     1598   
     1599   
     1600    INPUT:
     1601   
     1602    - same as for :class:`sage.schemes.generic.SchemeHomset_coordinates`.
     1603   
     1604    OUPUT:
     1605   
     1606    - :class:`SchemeHomset_toric_coordinates_field`.
     1607   
     1608    TESTS::
     1609   
     1610        sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1611        sage: P1xP1 = ToricVariety(fan)
     1612        sage: import sage.schemes.generic.toric_variety as tv
     1613        sage: tv.SchemeHomset_toric_coordinates_field(P1xP1, QQ)
     1614        Set of Rational Points of Toric variety of dimension 2
     1615       
     1616    A better way to construct the same `Hom`-space as above::
     1617   
     1618        sage: P1xP1(QQ)
     1619        Set of Rational Points of Toric variety of dimension 2
     1620    """
     1621    # Mimicking SchemeHomset_projective_coordinates_field,
     1622    # affine spaces implement only "except" case
     1623    def __call__(self, *arg):
     1624        r"""
     1625        Construct a morphism from given parameters.
     1626       
     1627        INPUT:
     1628       
     1629        - data determining a morphism.
     1630       
     1631        TESTS::
     1632       
     1633            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1634            sage: P1xP1 = ToricVariety(fan)
     1635            sage: import sage.schemes.generic.toric_variety as tv
     1636            sage: H = tv.SchemeHomset_toric_coordinates_field(P1xP1, QQ)
     1637            sage: H(1,2,3,4)
     1638            [1 : 2 : 3 : 4]
     1639        """
     1640        # This may break for one-dimensional varieties.
     1641        if len(arg) == 1:
     1642            arg = arg[0]
     1643        X = self.codomain()
     1644        try:
     1645            return X._point_class(X, arg)
     1646        except AttributeError:  # should be very rare
     1647            return SchemeMorphism_toric_coordinates_field(self, arg)
     1648
     1649
     1650class SchemeMorphism_toric_coordinates_field(SchemeMorphism_coordinates):
     1651    """
     1652    Construct a morphism determined by giving coordinates in a field.
     1653   
     1654    .. WARNING::
     1655   
     1656        You should not create objects of this class directly.
     1657       
     1658    INPUT:
     1659   
     1660    - ``X`` -- subscheme of a toric variety.
     1661   
     1662    - ``coordinates`` -- list of coordinates in the base field of ``X``.
     1663   
     1664    - ``check`` -- if ``True`` (default), the input will be checked for
     1665      correctness.
     1666   
     1667    OUTPUT:
     1668   
     1669    - :class:`SchemeMorphism_toric_coordinates_field`.
     1670   
     1671    TESTS::
     1672   
     1673        sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1674        sage: P1xP1 = ToricVariety(fan)
     1675        sage: P1xP1(1,2,3,4)
     1676        [1 : 2 : 3 : 4]
     1677    """
     1678    # Mimicking affine/projective classes
     1679    def __init__(self, X, coordinates, check=True):
     1680        r"""
     1681        See :class:`SchemeMorphism_toric_coordinates_field` for documentation.
     1682       
     1683        TESTS::
     1684       
     1685            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1686            sage: P1xP1 = ToricVariety(fan)
     1687            sage: P1xP1(1,2,3,4)
     1688            [1 : 2 : 3 : 4]
     1689        """
     1690        # Convert scheme to its set of points over the base ring
     1691        if is_Scheme(X):
     1692            X = X(X.base_ring())
     1693        super(SchemeMorphism_toric_coordinates_field, self).__init__(X)
     1694        if check:
     1695            # Verify that there are the right number of coords
     1696            # Why isn't it done in the parent?
     1697            if is_SchemeMorphism(coordinates):
     1698                coordinates = list(coordinates)
     1699            if not isinstance(coordinates, (list, tuple)):
     1700                raise TypeError("coordinates must be a scheme point, list, "
     1701                                "or tuple. Got %s" % coordinates)
     1702            d = X.codomain().ambient_space().ngens()
     1703            if len(coordinates) != d:
     1704                raise ValueError("there must be %d coordinates! Got only %d: "
     1705                                 "%s" % (d, len(coordinates), coordinates))
     1706            # Make sure the coordinates all lie in the appropriate ring
     1707            coordinates = Sequence(coordinates, X.value_ring())
     1708            # Verify that the point satisfies the equations of X.
     1709            X.codomain()._check_satisfies_equations(coordinates)
     1710        self._coords = coordinates
     1711
     1712
     1713class SchemeMorphism_on_points_toric_variety(SchemeMorphism_on_points):
     1714    """
     1715    Construct a morphism determined by action on points.
     1716   
     1717    .. WARNING::
     1718   
     1719        You should not create objects of this class directly.
     1720       
     1721    INPUT:
     1722   
     1723    - same as for :class:`sage.schemes.generic.SchemeMorphism_on_points`.
     1724   
     1725    OUPUT:
     1726   
     1727    - :class:`SchemeMorphism_on_points_toric_variety`.
     1728       
     1729    TESTS::
     1730   
     1731        sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1732        sage: P1xP1 = ToricVariety(fan)
     1733        sage: P1xP1.inject_variables()
     1734        Defining z0, z1, z2, z3
     1735        sage: P1 = P1xP1.subscheme(z0-z2)
     1736        sage: H = P1xP1.Hom(P1)
     1737        sage: import sage.schemes.generic.toric_variety as tv       
     1738        sage: tv.SchemeMorphism_on_points_toric_variety(H, [z0,z1,z0,z3])
     1739        Scheme morphism:
     1740          From: Toric variety of dimension 2
     1741          To:   Closed subscheme of Toric variety
     1742                of dimension 2 defined by:
     1743          z0 - z2
     1744          Defn: Defined on coordinates by sending
     1745                [z0 : z1 : z2 : z3] to [z0 : z1 : z0 : z3]           
     1746    """
     1747   
     1748    def __init__(self, parent, polynomials, check=True):
     1749        r"""
     1750        See :class:`SchemeMorphism_on_points_toric_variety` for documentation.
     1751       
     1752        TESTS::
     1753       
     1754            sage: fan = FaceFan(lattice_polytope.octahedron(2))
     1755            sage: P1xP1 = ToricVariety(fan)
     1756            sage: P1xP1.inject_variables()
     1757            Defining z0, z1, z2, z3
     1758            sage: P1 = P1xP1.subscheme(z0-z2)
     1759            sage: H = P1xP1.Hom(P1)
     1760            sage: import sage.schemes.generic.toric_variety as tv
     1761            sage: tv.SchemeMorphism_on_points_toric_variety(H, [z0,z1,z0,z3])
     1762            Scheme morphism:
     1763              From: Toric variety of dimension 2
     1764              To:   Closed subscheme of Toric variety
     1765                    of dimension 2 defined by:
     1766              z0 - z2
     1767              Defn: Defined on coordinates by sending
     1768                    [z0 : z1 : z2 : z3] to [z0 : z1 : z0 : z3]                   
     1769        """
     1770        SchemeMorphism_on_points.__init__(self, parent, polynomials, check)
     1771        if check:
     1772            # Check that defining polynomials are homogeneous (degrees can be
     1773            # different if the target uses weighted coordinates)
     1774            for p in self.defining_polynomials():
     1775                if not self.domain().ambient_space().is_homogeneous(p):
     1776                    raise ValueError("%s is not homogeneous!" % p)
     1777       
     1778
     1779def normalize_names(names=None, ngens=None, prefix=None, indices=None,
     1780                    return_prefix=False):
     1781    r"""
     1782    Return a list of names in the standard form.
     1783   
     1784    INPUT:
     1785   
     1786    All input parameters are optional.
     1787   
     1788    - ``names`` -- names given either as a single string (with individual
     1789      names separated by commas or spaces) or a list of strings with each
     1790      string specifying a name. If the last name ends with the plus sign,
     1791      "+", this name will be used as ``prefix`` (even if ``prefix`` was
     1792      given explicitly);
     1793   
     1794    - ``ngens`` -- number of names to be returned;
     1795       
     1796    - ``prefix`` -- prefix for the indexed names given as a string;
     1797   
     1798    - ``indices`` -- list of integers (default: ``range(ngens)``) used as
     1799      indices for names with ``prefix``. If given, must be of length
     1800      ``ngens``;
     1801       
     1802    - ``return_prefix`` -- if ``True``, the last element of the returned list
     1803      will contain the prefix determined from ``names`` or given as the
     1804      parameter ``prefix``. This is useful if you may need more names in the
     1805      future.
     1806   
     1807    OUTPUT:
     1808   
     1809    - list of names given as strings.
     1810   
     1811    These names are constructed in the following way:
     1812   
     1813    #. If necessary, split ``names`` into separate names.
     1814    #. If the last name ends with "+", put it into ``prefix``.
     1815    #. If ``ngens`` was given, add to the names obtained so far as many
     1816       indexed names as necessary to get this number. If the ``k``-th name of
     1817       the *total* list of names is indexed, it is
     1818       ``prefix + str(indices[k])``. If there were already more names than
     1819       ``ngens``, discard "extra" ones.
     1820    #. Check if constructed names are valid. See :func:`certify_names` for
     1821       details.
     1822    #. If the option ``return_prefix=True`` was given, add ``prefix`` to the
     1823       end of the list.
     1824       
     1825    EXAMPLES:
     1826   
     1827    As promised, all parameters are optional::
     1828   
     1829        sage: from sage.schemes.generic.toric_variety import normalize_names
     1830        sage: normalize_names()
     1831        []
     1832       
     1833    One of the most common uses is probably this one::
     1834   
     1835        sage: normalize_names("x+", 4)
     1836        ['x0', 'x1', 'x2', 'x3']
     1837       
     1838    Now suppose that you want to enumerate your variables starting with one
     1839    instead of zero::
     1840   
     1841        sage: normalize_names("x+", 4, indices=range(1,5))
     1842        ['x1', 'x2', 'x3', 'x4']
     1843       
     1844    You may actually have an arbitrary enumeration scheme::
     1845   
     1846        sage: normalize_names("x+", 4, indices=[1, 10, 100, 1000])
     1847        ['x1', 'x10', 'x100', 'x1000']
     1848       
     1849    Now let's add some "explicit" names::
     1850   
     1851        sage: normalize_names("x y z t+", 4)
     1852        ['x', 'y', 'z', 't3']
     1853       
     1854    Note that the "automatic" name is ``t3`` instead of ``t0``. This may seem
     1855    weird, but the reason for this behaviour is that the fourth name in this
     1856    list will be the same no matter how many explicit names were given::
     1857   
     1858        sage: normalize_names("x y t+", 4)
     1859        ['x', 'y', 't2', 't3']
     1860       
     1861    This is especially useful if you get ``names`` from a user but want to
     1862    specify all default names::
     1863   
     1864        sage: normalize_names("x, y", 4, prefix="t")
     1865        ['x', 'y', 't2', 't3']
     1866       
     1867    In this format, the user can easily override your choice for automatic
     1868    names::
     1869   
     1870        sage: normalize_names("x y s+", 4, prefix="t")
     1871        ['x', 'y', 's2', 's3']
     1872       
     1873    Let's now use all parameters at once::
     1874       
     1875        sage: normalize_names("x, y, s+", 4, prefix="t",
     1876        ...       indices=range(1,5), return_prefix=True)
     1877        ['x', 'y', 's3', 's4', 's']
     1878       
     1879    Note that you still need to give indices for all names, even if some of
     1880    the first ones will be "wasted" because of the explicit names. The reason
     1881    is the same as before - this ensures consistency of automatically
     1882    generated names, no matter how many explicit names were given.
     1883       
     1884    The prefix is discarded if ``ngens`` was not given::
     1885   
     1886        sage: normalize_names("alpha, beta, gamma, zeta+")
     1887        ['alpha', 'beta', 'gamma']
     1888       
     1889    Finally, let's take a look at some possible mistakes::
     1890   
     1891        sage: normalize_names("123")
     1892        Traceback (most recent call last):
     1893        ...
     1894        ValueError: name must start with a letter! Got 123
     1895       
     1896    A more subtle one::
     1897   
     1898        sage: normalize_names("x1", 4, prefix="x")
     1899        Traceback (most recent call last):
     1900        ...
     1901        ValueError: names must be distinct! Got: ['x1', 'x1', 'x2', 'x3']   
     1902    """
     1903    if names is None:
     1904        names = []
     1905    elif isinstance(names, str):
     1906        names = names.replace(",", " ").split()
     1907    else:
     1908        try:
     1909            names = list(names)
     1910        except TypeError:
     1911            raise TypeError(
     1912                    "names must be a string or a list or tuple of them!")
     1913        for name in names:
     1914            if not isinstance(name, str):
     1915                raise TypeError(
     1916                    "names must be a string or a list or tuple of them!")
     1917    if names and names[-1].endswith("+"):
     1918        prefix = names.pop()[:-1]
     1919    if ngens is None:
     1920        ngens = len(names)
     1921    if len(names) < ngens:
     1922        if prefix is None:
     1923            raise IndexError("need %d names but only %d are given!"
     1924                             % (ngens, len(names)))
     1925        if indices is None:
     1926            indices = range(ngens)
     1927        elif len(indices) != ngens:
     1928            raise ValueError("need exactly %d indices, but got %d!"
     1929                             % (ngens, len(indices)))
     1930        names += [prefix + str(i) for i in indices[len(names):]]
     1931    if len(names) > ngens:
     1932        names = names[:ngens]
     1933    # Check that all given and constructed names are valid
     1934    certify_names(names)
     1935    if return_prefix:
     1936        names.append(prefix)
     1937    return names
     1938
     1939
     1940def certify_names(names):
     1941    r"""
     1942    Make sure that ``names`` are valid in Python.
     1943   
     1944    INPUT:
     1945   
     1946    - ``names`` -- list of strings.
     1947   
     1948    OUTPUT:
     1949   
     1950    - none, but a ``ValueError`` exception is raised if ``names`` are invalid.
     1951   
     1952    Each name must satisfy the following requirements:
     1953   
     1954    * Be non-empty.
     1955    * Contain only (Latin) letters, digits, and underscores ("_").
     1956    * Start with a letter.
     1957   
     1958    In addition, all names must be distinct.
     1959   
     1960    EXAMPLES::
     1961   
     1962        sage: from sage.schemes.generic.toric_variety import certify_names
     1963        sage: certify_names([])
     1964        sage: certify_names(["a", "x0", "x_45"])
     1965        sage: certify_names(["", "x0", "x_45"])
     1966        Traceback (most recent call last):
     1967        ...
     1968        ValueError: name must be nonempty!
     1969        sage: certify_names(["a", "0", "x_45"])
     1970        Traceback (most recent call last):
     1971        ...
     1972        ValueError: name must start with a letter! Got 0
     1973        sage: certify_names(["a", "x0", "Щ_45"])
     1974        Traceback (most recent call last):
     1975        ...
     1976        ValueError: name must be alphanumeric! Got Щ_45
     1977        sage: certify_names(["a", "x0", "x0"])
     1978        Traceback (most recent call last):
     1979        ...
     1980        ValueError: names must be distinct! Got: ['a', 'x0', 'x0']
     1981    """
     1982    for name in names:
     1983        if not name:
     1984            raise ValueError("name must be nonempty!")
     1985        if not name.isalnum() and not name.replace("_","").isalnum():
     1986            # Must be alphanumeric except for non-leading '_'
     1987            raise ValueError("name must be alphanumeric! Got %s" % name)
     1988        if not name[0].isalpha():
     1989            raise ValueError("name must start with a letter! Got %s" % name)
     1990    if len(set(names)) != len(names):
     1991        raise ValueError("names must be distinct! Got: %s" % names)