Ticket #9972: trac_9972_improve_element_constructors.2.patch

File trac_9972_improve_element_constructors.2.patch, 22.9 KB (added by vbraun, 9 years ago)

Updated patch

  • sage/geometry/cone.py

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1286564101 -3600
    # Node ID abf455584fcccb445716b88143de43fe369c54e7
    # Parent  6f92dfe39d071fe2df48d7399e3a0bdac170c16c
    Trac 9972: Make CohomologyRing._element_constructor_ accept cones as input.
    
    Also, x in fan now only checks for cones. Added method fan.support_contains(x) for support questions. "0 in fan" now returns False.
    
    diff -r 6f92dfe39d07 -r abf455584fcc sage/geometry/cone.py
    a b  
    20392039            sage: cone1.is_equivalent(cone2)
    20402040            True
    20412041        """
     2042        if self is other:
     2043            return True
    20422044        if self.lattice() != other.lattice():
    20432045            return False
    20442046        if self.ray_set() == other.ray_set():
  • sage/geometry/fan.py

    diff -r 6f92dfe39d07 -r abf455584fcc sage/geometry/fan.py
    a b  
    522522        (N(-1, 0), N(0, -1))
    523523        (N(1, 0), N(0, 1))
    524524        (N(0, 1), N(-1, 0))
    525      """
     525    """
    526526    if any(d <= 0 for d in polytope.distances([0]*polytope.dim())):
    527527        raise ValueError("face fans are defined only for polytopes containing"
    528528                         "the origin as an interior point!")
     
    583583    .. WARNING::
    584584
    585585        This class does not check that the input defines a valid cone of a
    586         fan. You should not construct objects of this class directly.
     586        fan. You must not construct objects of this class directly.
    587587
    588588    In addition to all of the properties of "regular" :class:`cones
    589589    <sage.geometry.cone.ConvexRationalPolyhedralCone>`, such cones know their
     
    727727                                    for i in self.star_generator_indices())
    728728        return self._star_generators
    729729
     730    def is_equivalent(self, other):
     731        r"""
     732        Check if ``self`` is "mathematically" the same as ``other``.
     733
     734        This method overrides
     735        :meth:`ConvexRationalPolyhedralCone.is_equivalent` with a
     736        faster test for two cones of the same ray. Please refer to the
     737        base method for a more detailed description.
     738
     739        INPUT:
     740
     741        - ``other`` - cone.
     742
     743        OUTPUT:
     744
     745        - ``True`` if ``self`` and ``other`` define the same cones as sets of
     746          points in the same lattice, ``False`` otherwise.
     747
     748        EXAMPLES::
     749
     750            sage: fan = Fan([Cone([(1,0), (-1, 3)]), Cone([(-1,0), (-1, 3)])])
     751            sage: cone0 = fan.generating_cone(0)
     752            sage: cone1 = Cone([(1,0), (-1, 3)])
     753            sage: type(cone0)
     754            <class 'sage.geometry.fan.Cone_of_fan'>
     755            sage: type(cone1)
     756            <class 'sage.geometry.cone.ConvexRationalPolyhedralCone'>
     757            sage: cone0.is_equivalent(cone0)    # fast
     758            True
     759            sage: cone0.is_equivalent(cone1)    # slower
     760            True
     761        """
     762        if isinstance(other, Cone_of_fan) and other.ambient() is self.ambient():
     763            # TODO: If we declare Cone_of_fan unique, then
     764            # return self is other
     765            return self.ambient_ray_indices() == other.ambient_ray_indices()
     766        return super(Cone_of_fan,self).is_equivalent(other)
     767
    730768
    731769class RationalPolyhedralFan(IntegralRayCollection,
    732770                            collections.Callable,
     
    899937            sage: cone1 = Cone([(0,-1), (1,0)])
    900938            sage: cone2 = Cone([(1,0), (0,1)])
    901939            sage: f = Fan([cone1, cone2])
     940            sage: f.generating_cone(0) in f
     941            True
    902942            sage: cone1 in f
    903943            True
    904             sage: (1,1) in f
    905             True
    906             sage: (-1,-1) in f
     944            sage: (1,1) in f    # not a cone
     945            False
     946            sage: "Ceci n'est pas un cone" in f
    907947            False
    908948        """
    909949        return self._contains(data)
     
    10591099            elements[labels[0]] = FanFace(tuple(range(self.nrays())), ())
    10601100            self._cone_lattice = FinitePoset(L, elements)
    10611101
    1062     def _contains(self, data):
     1102    def _contains(self, cone):
    10631103        r"""
    1064         Check if ``data`` is contained in ``self``.
     1104        Check if ``cone`` is a cone of the fan.
    10651105
    10661106        This function is called by :meth:`__contains__` and :meth:`contains`
    10671107        to ensure the same call depth for warning messages.
    10681108
    10691109        INPUT:
    10701110
    1071         - ``data`` -- anything. If it is not a cone, an attempt will be made
    1072           to convert it into a single point of the ambient space of ``self``.
    1073           If it fails, ``False`` will be returned.
     1111        - ``cone`` -- anything.
    10741112
    10751113        OUTPUT:
    10761114
    1077         - ``True`` if ``data`` is contained in ``self``, ``False`` otherwise.
    1078 
    1079         TESTS::
     1115        - ``False`` if ``cone`` is not a cone, if ``cone`` is a cone
     1116          of a different fan, or if ``cone`` is not equivalent to a
     1117          cone of the fan. ``True`` otherwise.
    10801118
    10811119        TESTS::
    10821120
     
    10851123            sage: f = Fan([cone1, cone2])
    10861124            sage: f._contains(cone1)
    10871125            True
    1088             sage: f._contains((1,1))
     1126            sage: f._contains((1,1))  # this is not a cone!
     1127            False
     1128
     1129        Note this case::
     1130
     1131            sage: cone1_f = f.generating_cone(0)
     1132            sage: cone1.is_equivalent(cone1_f)
    10891133            True
     1134            sage: cone1   in Fan([cone1, cone2])  # not a cone of any particular fan
     1135            True
     1136            sage: cone1_f in Fan([cone1, cone2])  # belongs to different fan!
     1137            False
    10901138        """
    1091         if is_Cone(data):
    1092             if data.lattice() != self.lattice():
    1093                 warnings.warn("you have checked if a fan contains a cone "
    1094                               "from another lattice, this is always False!",
    1095                               stacklevel=3)
    1096                 # We may need to take into account canonical maps, perhaps...
    1097                 return False
    1098             if (not data.is_strictly_convex()
    1099                 or not data.ray_set().issubset(self.ray_set())):
    1100                 return False
    1101             try:
    1102                 return data.is_equivalent(self.cone_containing(data.rays()))
    1103             except ValueError:  # No cone containing all these rays
    1104                 return False
    1105         # Now we try to treat data as a point
     1139        if not is_Cone(cone):
     1140            return False
     1141        if isinstance(cone, Cone_of_fan):
     1142            return self is cone.ambient()
     1143        if cone.lattice() != self.lattice():
     1144            warnings.warn("you have checked if a fan contains a cone "
     1145                          "from another lattice, this is always False!",
     1146                          stacklevel=3)
     1147            # We may need to take into account canonical maps, perhaps...
     1148            return False
     1149        if (not cone.is_strictly_convex()
     1150            or not cone.ray_set().issubset(self.ray_set())):
     1151            return False
     1152        try:
     1153            return cone.is_equivalent(self.cone_containing(cone.rays()))
     1154        except ValueError:  # No cone of then fan contains all these rays
     1155            return False
     1156
     1157    def support_contains(self, *args):
     1158        r"""
     1159        Check if a point is contained in the support of the fan.
     1160       
     1161        The support of a fan is the union of all cones of the fan. If
     1162        you want to know whether the fan contains a given cone, you
     1163        should use :meth:`contains` instead.
     1164
     1165        INPUT:
     1166
     1167        - ``*args`` -- an element of ``self.lattice()`` or something
     1168          that can be converted to it (for example, a list of
     1169          coordinates).
     1170
     1171        OUTPUT:
     1172
     1173        - ``True`` if ``point`` is contained in the support of the
     1174          fan, ``False`` otherwise.
     1175
     1176        TESTS::
     1177
     1178            sage: cone1 = Cone([(0,-1), (1,0)])
     1179            sage: cone2 = Cone([(1,0), (0,1)])
     1180            sage: f = Fan([cone1, cone2])
     1181
     1182        We check if some points are in this fan::
     1183
     1184            sage: f.support_contains(f.lattice()(1,0))
     1185            True
     1186            sage: f.support_contains(cone1)    # a cone is not a point of the lattice
     1187            False
     1188            sage: f.support_contains((1,0))
     1189            True
     1190            sage: f.support_contains(1,1)
     1191            True
     1192            sage: f.support_contains((-1,0))
     1193            False
     1194            sage: f.support_contains(f.lattice().dual()(1,0)) #random output (warning)
     1195            False
     1196            sage: f.support_contains(f.lattice().dual()(1,0))
     1197            False
     1198            sage: f.support_contains(1)
     1199            False
     1200            sage: f.support_contains(0)   # 0 converts to the origin in the lattice
     1201            True
     1202            sage: f.support_contains(1/2, sqrt(3))
     1203            True
     1204            sage: f.support_contains(-1/2, sqrt(3))
     1205            False
     1206        """
     1207        if len(args)==1:
     1208            point = args[0]
     1209        else:
     1210            point = args
     1211
    11061212        try:
    1107             data = self._ambient_space_point(data)
     1213            point = self._ambient_space_point(point)
    11081214        except TypeError, ex:
    11091215            if str(ex).endswith("have incompatible lattices!"):
    11101216                warnings.warn("you have checked if a fan contains a point "
     
    11131219            return False
    11141220        if self.is_complete():
    11151221            return True
    1116         return any(data in cone for cone in self)
     1222        return any(point in cone for cone in self)
    11171223
    11181224    def _latex_(self):
    11191225        r"""
     
    13141420        fan = Fan(cones, new_fan_rays, check=False, normalize=False)
    13151421        return fan
    13161422
     1423    def get_cone(self, cone):
     1424        r"""
     1425        Return the cone of ``self`` that is equivalent ot the given cone.
     1426
     1427        INPUT:
     1428
     1429        - ``cone`` -- A cone, but not necessarily a cone associated to
     1430          a fan.
     1431
     1432        OUTPUT:
     1433
     1434        - The corresponding :class:`cone of fan <Cone_of_fan>` whose
     1435          ambient fan is ``self``, if it exists. If there is no such
     1436          cone in ``self``, a ``ValueError`` is raised.
     1437       
     1438        EXAMPLES::
     1439
     1440            sage: c0 = Cone([(1,0),(1,1)])
     1441            sage: c1 = Cone([(0,1),(1,1)])
     1442            sage: f = Fan([c0,c1])
     1443            sage: c0.ambient_ray_indices(), f.get_cone(c0).ambient_ray_indices()
     1444            ((0, 1), (1, 2))
     1445            sage: c1.ambient_ray_indices(), f.get_cone(c1).ambient_ray_indices()
     1446            ((0, 1), (0, 2))
     1447        """
     1448        if self is cone.ambient():
     1449            return cone
     1450        for fan_cone in self.cones(dim=cone.dim()):
     1451            if fan_cone.is_equivalent(cone):
     1452                return fan_cone
     1453        raise ValueError, 'The cone '+str(cone)+\
     1454            ' is not equivalent to any cone of the fan.'
     1455
    13171456    def cone_containing(self, *points):
    13181457        r"""
    13191458        Return the smallest cone of ``self`` containing all given points.
     
    13261465
    13271466        OUTPUT:
    13281467
    1329         - :class:`cone of fan <Cone_of_fan>`.
     1468        - A :class:`cone of fan <Cone_of_fan>` whose ambient fan is
     1469          ``self``.
    13301470
    13311471        .. NOTE::
    13321472
     
    15961736        raise ValueError(
    15971737                    "dimension and codimension cannot be specified together!")
    15981738
    1599     def contains(self, *args):
     1739    def contains(self, cone):
    16001740        r"""
    1601         Check if a given point or cone is contained in ``self``.
     1741        Check if a given ``cone`` is contained in ``self``.
    16021742
    16031743        INPUT:
    16041744
    1605         - anything. If it is not a cone, an attempt will be made to convert
    1606           the input into a point of the ambient space of ``self``. If it
    1607           fails, ``False`` will be returned.
     1745        - ``cone`` -- anything.
    16081746
    16091747        OUTPUT:
    16101748
    1611         - ``True`` if the given point or cone is contained in ``self``,
    1612           ``False`` otherwise.
     1749        - ``False`` if ``cone`` is not a cone, if ``cone`` belongs to
     1750          a different fan, or if ``cone`` is not equivalent to a cone
     1751          of the fan. ``True`` otherwise.
    16131752
    16141753        .. NOTE::
    16151754
    1616             A point is contained in a fan if it is contained in its support.
    1617             A cone is contained in a fan if it is equivalent to one of the
    1618             cones of the fan, in particular, it is possible that all points of
    1619             the cone are in the fan, but the cone itself is not.
     1755            Recall that a fan is a (finite) collection of cones. A
     1756            cone is contained in a fan if it is equivalent to one of
     1757            the cones of the fan. In particular, it is possible that
     1758            all rays of the cone are in the fan, but the cone itself
     1759            is not.
     1760
     1761            If you want to know whether a point is in the support of
     1762            the fan, you should use :meth:`support_contains`.
    16201763
    16211764        EXAMPLES:
    16221765
    1623         We construct a simple fan::
     1766        We first construct a simple fan::
    16241767
    16251768            sage: cone1 = Cone([(0,-1), (1,0)])
    16261769            sage: cone2 = Cone([(1,0), (0,1)])
    16271770            sage: f = Fan([cone1, cone2])
    16281771
    1629         We check if some points are in this fan::
    1630 
    1631             sage: f.contains(f.lattice()(1,0))
    1632             True
    1633             sage: f.contains((1,0))
    1634             True
    1635             sage: f.contains(1,1)
    1636             True
    1637             sage: f.contains((-1,0))
    1638             False
    1639             sage: f.contains(f.lattice().dual()(1,0)) #random output (warning)
    1640             False
    1641             sage: f.contains(f.lattice().dual()(1,0))
    1642             False
    1643             sage: f.contains(1)
    1644             False
    1645             sage: f.contains(1/2, sqrt(3))
    1646             True
    1647             sage: f.contains(-1/2, sqrt(3))
    1648             False
    1649 
    16501772        Now we check if some cones are in this fan. First, we make sure that
    16511773        the order of rays of the input cone does not matter (``check=False``
    16521774        option ensures that rays of these cones will be listed exactly as they
     
    16611783
    16621784            sage: f.contains(Cone([(1,0)]))
    16631785            True
     1786            sage: Cone([(1,0)]) in f   # equivalent to the previous command
     1787            True
    16641788
    16651789        Finally, we test some cones which are not in this fan::
    16661790
     
    16681792            False
    16691793            sage: f.contains(Cone([(0,1), (-1,0)]))
    16701794            False
     1795
     1796        A point is not a cone::
     1797
     1798            sage: n = f.lattice()(1,1); n
     1799            N(1, 1)
     1800            sage: f.contains(n)
     1801            False
    16711802        """
    1672         data = flatten(args)
    1673         if len(data) == 1:
    1674            data = data[0]
    1675         return self._contains(data)
     1803        return self._contains(cone)
    16761804
    16771805    def Gale_transform(self):
    16781806        r"""
  • sage/schemes/generic/toric_divisor.py

    diff -r 6f92dfe39d07 -r abf455584fcc sage/schemes/generic/toric_divisor.py
    a b  
    348348            sage: TDiv = P2.toric_divisor_group()
    349349            sage: TDiv._element_constructor_([ (1,P2.gen(2)) ])
    350350            V(z)
     351            sage: TDiv( P2.fan(1)[0] )
     352            V(x)
    351353        """
    352354        if is_ToricDivisor(x):
    353355            if x.parent() is self:
     
    482484        ValueError: u + y is not a monomial!
    483485        sage: ToricDivisor(dP6, u*y)
    484486        V(u) + V(y)
    485         sage: ToricDivisor(dP6, dP6.fan(dim=1)[0] )
    486         V(x)
     487        sage: ToricDivisor(dP6, dP6.fan(dim=1)[2] )
     488        V(y)
     489        sage: cone = Cone(dP6.fan(dim=1)[2])
     490        sage: ToricDivisor(dP6, cone)
     491        V(y)
    487492        sage: N = dP6.fan().lattice()
    488493        sage: ToricDivisor(dP6, N(1,1) )
    489494        V(w)
     
    520525        arg = toric_variety.fan().cone_containing(arg)
    521526    # Divisor by a one-cone
    522527    if is_Cone(arg):
    523         if arg.dim() != 1:
     528        cone = toric_variety.fan().get_cone(arg)
     529        if cone.dim() != 1:
    524530            raise ValueError("Only 1-dimensional cones of the toric variety "
    525531                             "define divisors.")
    526         arg = arg.ambient_ray_indices()[0]
     532        arg = cone.ambient_ray_indices()[0]
    527533    # Divisor by a ray index
    528534    if arg in ZZ:
    529535        arg = [(1, toric_variety.gen(arg))]
     
    789795            (3/2, 0, 1/2)
    790796            sage: QQ_Cartier.m(triangle_cone)
    791797            M(1, 0, 1)
     798            sage: QQ_Cartier.m(Cone(triangle_cone))
     799            M(1, 0, 1)
    792800            sage: Weil = X.divisor([1,1,1,0,0])
    793801            sage: Weil.m(square_cone)
    794802            Traceback (most recent call last):
     
    808816       
    809817        X = self.parent().scheme()
    810818        M = X.fan().dual_lattice()
     819        cone = X.fan().get_cone(cone)
    811820        if cone.is_trivial():
    812821            m = M(0)
    813822            self._m[cone] = m
     
    10221031            [y + v - w]
    10231032        """
    10241033        divisor = vector(self)
    1025         return sum([divisor[i] * cone.cohomology_class()
    1026                     for i, cone in enumerate(self.parent().scheme().fan(1))])
     1034        variety = self.parent().scheme()
     1035        HH = variety.cohomology_ring()
     1036        return sum([ divisor[i] * HH.gen(i) for i in range(0,HH.ngens()) ])
    10271037
    10281038    def Chern_character(self):
    10291039        r"""
  • sage/schemes/generic/toric_variety.py

    diff -r 6f92dfe39d07 -r abf455584fcc sage/schemes/generic/toric_variety.py
    a b  
    294294        """
    295295        return self.ambient().toric_variety()
    296296
    297     def cohomology_class(self):
    298         r"""
    299         Return the cohomology class associated to the cone.
    300        
    301         OUTPUT:
    302 
    303         Returns the cohomology class of the orbit closure (a
    304         subvariety of the toric variety) associated to the cone.
    305 
    306         EXAMPLES::
    307          
    308             sage: dP6 = toric_varieties.dP6()
    309             sage: cone = dP6.fan().cone_containing(2,3); cone
    310             2-d cone of Rational polyhedral fan in 2-d lattice N
    311             sage: cone.cohomology_class()
    312             [-w^2]
    313         """
    314         if "_cohomology_class" not in self.__dict__:
    315             idx = self.ambient_ray_indices()
    316             self._cohomology_class = \
    317                 prod( self.toric_variety().cohomology_ring().gen(i) for i in idx )
    318         return self._cohomology_class
    319 
    320297
    321298class Fan_of_toric_variety(EnhancedFan):
    322299    r"""
     
    18441821                                          'implemented for orbifolds.')
    18451822            def V(cone): return abs(cone.ray_matrix().determinant())
    18461823            min_cone = min( self._fan.generating_cones(), key=V)
    1847             self._volume_class = min_cone.cohomology_class() / V(min_cone)
     1824            self._volume_class = self.cohomology_ring()(min_cone) / V(min_cone)
    18481825        if self._volume_class.is_zero():
    18491826            raise ValueError, 'Volume class does not exist.'
    18501827        return self._volume_class
     
    18681845        EXAMPLES::
    18691846
    18701847            sage: dP6 = toric_varieties.dP6()
    1871             sage: D = [ c.cohomology_class() for c in dP6.fan(dim=1) ]
     1848            sage: HH = dP6.cohomology_ring()
     1849            sage: D = [ HH(c) for c in dP6.fan(dim=1) ]
    18721850            sage: matrix([ [ D[i]*D[j] for i in range(0,6) ] for j in range(0,6) ])
    18731851            [ [w^2] [-w^2]    [0]    [0]    [0] [-w^2]]
    18741852            [[-w^2]  [w^2] [-w^2]    [0]    [0]    [0]]
     
    20882066        Lets test that the del Pezzo surface `dP_6` has degree 6, as its name implies::
    20892067
    20902068            sage: dP6 = toric_varieties.dP6()
     2069            sage: HH = dP6.cohomology_ring()
    20912070            sage: dP6.K()
    20922071            -V(x) - V(u) - V(y) - V(v) - V(z) - V(w)
    2093             sage: dP6.integrate( dP6.K().cohomology_class()^2 )
     2072            sage: dP6.integrate( HH(dP6.K())^2 )
    20942073            6
    20952074        """
    20962075        from sage.schemes.generic.toric_divisor import ToricDivisor
     
    29482927       
    29492928        INPUT::
    29502929       
    2951         - ``x`` -- something that defines a cohomology class.
     2930        - ``x`` -- something that defines a cohomology class. Either a
     2931          cohomology class, a cone of the fan, or something that can
     2932          be converted into a polynomial in the homogeneous
     2933          coordinates.
    29522934
    29532935        EXAMPLES::
     2936         
     2937            sage: dP6 = toric_varieties.dP6()
     2938            sage: H = dP6.cohomology_ring()
     2939            sage: cone = dP6.fan().cone_containing(2,3); cone
     2940            2-d cone of Rational polyhedral fan in 2-d lattice N
     2941            sage: H(cone)   # indirect doctest
     2942            [-w^2]
     2943            sage: H( Cone(cone) )
     2944            [-w^2]
     2945            sage: H( dP6.fan(0)[0] )   # trivial cone
     2946            [1]
    29542947
     2948
     2949        Numbers will be converted into the ring::
     2950           
    29552951            sage: P2 = toric_varieties.P2()
    29562952            sage: H = P2.cohomology_ring()
    29572953            sage: H._element_constructor_(1)
     
    29602956            [1]
    29612957            sage: type( H(1) )
    29622958            <class 'sage.schemes.generic.toric_variety.CohomologyClass'>
     2959            sage: P2.inject_variables()
     2960            Defining x, y, z
     2961            sage: H(1+x*y+z)
     2962            [z^2 + z + 1]
    29632963        """
     2964        if isinstance(x, CohomologyClass) and x.parent()==self:
     2965            return x
    29642966        if isinstance(x, QuotientRingElement):
    29652967            x = x.lift()
     2968        elif x in self._variety.fan():
     2969            cone = self._variety.fan().get_cone(x)
     2970            x = prod((self.cover_ring().gen(i) for i in cone.ambient_ray_indices()),
     2971                     z=self.cover_ring().one())
    29662972        else:
    2967             x = self.cover_ring()(x)
     2973            try:
     2974                # divisor, for example, know how to compute their own cohomology class
     2975                return x.cohomology_class()
     2976            except AttributeError:
     2977                # this ensures that rationals are converted to cohomology ring elements
     2978                x = self.cover_ring()(x)
    29682979        return CohomologyClass(self, x)
    29692980   
    29702981    # We definitely should not override __call__, but since our
     
    30483059    EXAMPLES::
    30493060   
    30503061        sage: P2 = toric_varieties.P2()
     3062        sage: HH = P2.cohomology_ring()
    30513063        sage: from sage.schemes.generic.toric_variety import is_CohomologyClass
    3052         sage: is_CohomologyClass( P2.cohomology_ring().one() )
     3064        sage: is_CohomologyClass( HH.one() )
    30533065        True
    3054         sage: is_CohomologyClass( (P2.fan(1)[0]).cohomology_class() )
     3066        sage: is_CohomologyClass( HH(P2.fan(1)[0]) )
    30553067        True
    30563068        sage: is_CohomologyClass('z')
    30573069        False
     
    30673079    .. WARNING::
    30683080
    30693081        You should not create instances of this class manually. The
    3070         generators of the cohomology ring can be obtained from
    3071         :meth:`ToricVariety_field.cohomology_ring`
    3072         and the cohomology class associated to cones of the fan from
    3073         :meth:`Cone_of_toric_variety.cohomology_class`
     3082        generators of the cohomology ring as well as the cohomology
     3083        classes associated to cones of the fan can be obtained from
     3084        :meth:`ToricVariety_field.cohomology_ring`.
    30743085   
    30753086    EXAMPLES::
    30763087   
    30773088        sage: P2 = toric_varieties.P2()
    3078         sage: cone = P2.fan(1)[0]
    3079         sage: cone.cohomology_class()
     3089        sage: P2.cohomology_ring().gen(0)
    30803090        [z]
    3081         sage: P2.cohomology_ring().gen(0)
     3091        sage: HH = P2.cohomology_ring()
     3092        sage: HH.gen(0)
     3093        [z]
     3094        sage: cone = P2.fan(1)[0];  HH(cone)
    30823095        [z]
    30833096    """
    30843097