Ticket #3738: 3738-1-new_parent.patch

File 3738-1-new_parent.patch, 120.4 KB (added by robertwb, 11 years ago)
  • new file sage/structure/category_object.pxd

    # HG changeset patch
    # User Robert Bradshaw <robertwb@math.washington.edu>
    # Date 1217319871 25200
    # Node ID 19b2ada8a98311c0b133eb4b9e7c51a8c7761979
    # Parent  5c038484dca0bd93a47cab8cf0c19e9a9d31d41a
    Install category object and new Parent under (old_)parent.
    
    diff -r 5c038484dca0 -r 19b2ada8a983 sage/structure/category_object.pxd
    - +  
     1###############################################################################
     2#   SAGE: System for Algebra and Geometry Experimentation   
     3#       Copyright (C) 2006 William Stein <wstein@gmail.com>
     4#  Distributed under the terms of the GNU General Public License (GPL)
     5#  The full text of the GPL is available at:
     6#                  http://www.gnu.org/licenses/
     7###############################################################################
     8
     9include '../ext/python_object.pxi'
     10include '../ext/stdsage.pxi'
     11
     12from sage.structure.sage_object cimport SageObject
     13from sage.structure.generators cimport Generators
     14# Want circular imports here to define _base as type Parent
     15# from sage.structure.parent cimport class Parent
     16
     17cdef class CategoryObject(sage_object.SageObject):
     18
     19    cdef _generators
     20    cdef _categories
     21    cdef readonly _base
     22    cdef public _cdata
     23    cdef public _names # will be _printer
     24    cdef public _factory_data
     25    cdef object __weakref__
     26   
     27    cpdef Generators gens(self, category = *)
     28    cpdef gen(self, index = *, category = *)
     29    cpdef ngens(self, category = *)
     30    cpdef base(self, category = *)
     31    cpdef base_extend(self, other, category = *)
  • new file sage/structure/category_object.pyx

    diff -r 5c038484dca0 -r 19b2ada8a983 sage/structure/category_object.pyx
    - +  
     1"""
     2Base class for objects of a category.
     3
     4CLASS HIERARCHY:
     5
     6SageObject
     7    CategoryObject
     8        Parent
     9
     10Many category objects in SAGE are equipped with generators, which are
     11usually special elements of the object.  For example, the polynomial ring
     12$\Z[x,y,z]$ is generated by $x$, $y$, and $z$.  In SAGE the $i$th
     13generator of an object \code{X} is obtained using the notation
     14\code{X.gen(i)}.  From the SAGE interactive prompt, the shorthand
     15notation \code{X.i} is also allowed.
     16
     17The following examples illustrate these functions in the context of
     18multivariate polynomial rings and free modules.
     19
     20EXAMPLES:
     21    sage: R = PolynomialRing(ZZ, 3, 'x')
     22    sage: R.ngens()
     23    3
     24    sage: R.gen(0)
     25    x0
     26    sage: R.gens()
     27    (x0, x1, x2)
     28    sage: R.variable_names()
     29    ('x0', 'x1', 'x2')
     30
     31This example illustrates generators for a free module over $\Z$.
     32
     33    sage: M = FreeModule(ZZ, 4)
     34    sage: M
     35    Ambient free module of rank 4 over the principal ideal domain Integer Ring
     36    sage: M.ngens()
     37    4
     38    sage: M.gen(0)
     39    (1, 0, 0, 0)
     40    sage: M.gens()
     41    ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))
     42"""
     43
     44cdef int bad_parent_warnings = 0
     45
     46import generators
     47import sage_object
     48
     49def guess_category(obj):
     50    # this should be obsolete if things declare their categories
     51    try:
     52        if obj.is_field():
     53            from sage.categories.category_types import Fields
     54            return Fields()
     55    except:
     56        pass
     57    try:
     58        if obj.is_ring():
     59            from sage.categories.category_types import CommutativeAlgebras, Algebras, CommutativeRings, Rings
     60            if obj.is_commutative():
     61                if obj._base is not obj:
     62                    return CommutativeAlgebras(obj._base)
     63                else:
     64                    return CommutativeRings()
     65            else:
     66                if obj._base is not obj:
     67                    return Algebras(obj._base)
     68                else:
     69                    return Rings()
     70    except:
     71        pass
     72    return None # don't want to risk importing stuff...
     73   
     74cdef class CategoryObject(sage_object.SageObject):
     75    """
     76    An object in some category.
     77    """
     78    def __init__(self, categories, base = None):
     79        """
     80        Initializes an object in a category
     81
     82        INPUT:
     83        categories - a list of leaf categories that this object belongs to
     84                     (eg you do not need to list AbelianGroups if you specify
     85                     Rings because there is a forgetful functor from AbelianGroups to Rings)
     86        base - If this object has another object that should be considered a base in its primary category,
     87               you can include that base here.
     88        gens_with_names - if this object has generators, there are a number of ways of specifying them.
     89                         
     90        """
     91        if base is not None:
     92            self._base = base
     93        if len(categories) == 0:
     94            if bad_parent_warnings:
     95                print "No categories for %s" % type(self)
     96            categories = [guess_category(self)] # so generators don't crash
     97        self._categories = list(categories)
     98        self._generators = {}
     99       
     100    def category(self):
     101        cat = self._categories[0]
     102        if cat is None:
     103            # COERCE TODO: we shouldn't need this
     104            from sage.categories.all import Objects
     105            cat = Objects()
     106        return cat
     107
     108
     109    ##############################################################################
     110    # Generators
     111    ##############################################################################
     112   
     113    def _populate_generators_(self, gens=None, names=None, normalize = True, category=None):
     114        if self._generators.has_key(category):
     115            raise ValueError, "Generators cannot be changed after object creation."
     116        if category is None:
     117            category = self._categories[0]
     118        from sage.structure.sequence import Sequence
     119        if gens is None:
     120            n = self._ngens_()
     121            from sage.rings.infinity import infinity
     122            if n is infinity:
     123                gens = generators.Generators_naturals(self, category)
     124            else:
     125                gens = generators.Generators_finite(self, self._ngens_(), None, category)
     126        elif isinstance(gens, Generators):
     127            pass
     128        elif isinstance(gens, (list, tuple, Sequence)):
     129            if names is None:
     130                names = tuple([str(x) for x in gens])
     131            gens = generators.Generators_list(self, list(gens), category)
     132        else:
     133            gens = generators.Generators_list(self, [gens], category)
     134        self._generators[category] = gens
     135        if category == self._categories[0]:
     136            if names is not None and self._names is None:
     137                self._assign_names(names, ngens=gens.count(), normalize=normalize)
     138            self._generators[category] = gens
     139
     140    cpdef Generators gens(self, category=None):
     141        if category is None:
     142            category = self._categories[0]
     143        try:
     144            return self._generators[category]
     145        except KeyError:
     146            if category == self._categories[0]:
     147                n = self._ngens_()
     148                from sage.rings.infinity import infinity
     149                if n is infinity:
     150                    gens = generators.Generators_naturals(self, category)
     151                else:
     152                    gens = generators.Generators_finite(self, self._ngens_(), None, category)
     153            else:
     154                gens = self._compute_generators_(category)
     155            self._generators[category] = gens
     156            return gens
     157           
     158    cpdef gen(self, index=0, category=None):
     159        return self.gens(category)[index]
     160
     161    cpdef ngens(self, category=None):
     162        return self.gens(category).count()
     163
     164    def _ngens_(self):
     165        return 0
     166
     167    def gens_dict(self):
     168         r"""
     169         Return a dictionary whose entries are \code{{var_name:variable,...}}.
     170         """
     171         if HAS_DICTIONARY(self):
     172            try:
     173                return self._gens_dict
     174            except AttributeError:
     175                pass
     176         v = {}
     177         for x in self.gens():
     178             v[str(x)] = x
     179         if HAS_DICTIONARY(self):
     180            self._gens_dict = v
     181         return v
     182
     183    def objgens(self):
     184        """
     185        Return self and the generators of self as a tuple.
     186
     187        INPUT:
     188            names -- tuple or string
     189
     190        OUTPUT:
     191            self  -- this object
     192            tuple -- self.gens()
     193
     194        EXAMPLES:
     195            sage: R = PolynomialRing(QQ, 3, 'x'); R
     196            Multivariate Polynomial Ring in x0, x1, x2 over Rational Field
     197            sage: R.gens()
     198            (x0, x1, x2)
     199        """
     200        return self, self.gens()
     201       
     202    def objgen(self):
     203        """
     204        Return self and the generator of self.
     205       
     206        INPUT:
     207        names -- tuple or string
     208       
     209        OUTPUT:
     210        self  -- this object
     211        an object -- self.gen()
     212       
     213        EXAMPLES:
     214        sage: R, x = PolynomialRing(QQ,'x').objgen()
     215        sage: R
     216        Univariate Polynomial Ring in x over Rational Field
     217        sage: x
     218        x
     219        """
     220        return self, self.gen()
     221
     222    def _first_ngens(self, n):
     223        """
     224        Used by the preparser for R.<x> = ...
     225        """
     226        return self.gens()[:n]
     227
     228    #################################################################################################
     229    # Names and Printers
     230    #################################################################################################
     231
     232    def _assign_names(self, names=None, normalize=True, ngens=None):
     233        """
     234        Set the names of the generator of this object.
     235       
     236        This can only be done once because objects with generators
     237        are immutable, and is typically done during creation of the object.
     238
     239
     240        EXAMPLES:
     241        When we create this polynomial ring, self._assign_names is called by the constructor:
     242
     243            sage: R = QQ['x,y,abc']; R
     244            Multivariate Polynomial Ring in x, y, abc over Rational Field
     245            sage: R.2
     246            abc
     247
     248        We can't rename the variables:
     249            sage: R._assign_names(['a','b','c'])
     250            Traceback (most recent call last):
     251            ...
     252            ValueError: variable names cannot be changed after object creation.       
     253        """
     254        # this will eventually all be handled by the printer
     255        if names is None: return
     256        if normalize:
     257            if ngens is None:
     258                if self._generators is None or len(self._generators) == 0:
     259                    # not defined yet
     260                    if isinstance(names, (tuple, list)) and names is not None:
     261                        ngens = len(names)
     262                    else:
     263                        ngens = 1
     264                else:
     265                    ngens = self.ngens()
     266            names = self.normalize_names(ngens, names)
     267        if not (self._names is None) and names != self._names:
     268            raise ValueError, 'variable names cannot be changed after object creation.'
     269        if PY_TYPE_CHECK(names, str):
     270            names = (names, )  # make it a tuple
     271        elif PY_TYPE_CHECK(names, list):
     272            names = tuple(names)
     273        elif not PY_TYPE_CHECK(names, tuple):
     274            raise TypeError, "names must be a tuple of strings"
     275        self._names = names
     276   
     277    def normalize_names(self, int ngens, names=None):
     278        if names is None:
     279            return None
     280        if ngens == 0:
     281            return ()
     282        if isinstance(names, str) and names.find(',') != -1:
     283            names = names.split(',')
     284        if isinstance(names, str) and ngens > 1 and len(names) == ngens:
     285            names = tuple(names)
     286        if isinstance(names, str):
     287            name = names
     288            import sage.misc.defaults
     289            names = sage.misc.defaults.variable_names(ngens, name)
     290            names = self._certify_names(names)
     291        else:
     292            names = self._certify_names(names)
     293            if not isinstance(names, (list, tuple)):
     294                raise TypeError, "names must be a list or tuple of strings"
     295            for x in names:
     296                if not isinstance(x,str):
     297                    raise TypeError, "names must consist of strings"
     298            if len(names) != ngens:
     299                raise IndexError, "the number of names must equal the number of generators"
     300        return names
     301
     302    def _certify_names(self, names):
     303        v = []
     304        try:
     305            names = tuple(names)
     306        except TypeError:
     307            names = [str(names)]
     308        for N in names:
     309            if not isinstance(N, str):
     310                N = str(N)
     311            N = N.strip().strip("'")
     312            if len(N) == 0:
     313                raise ValueError, "variable name must be nonempty"
     314            if not N.isalnum() and not N.replace("_","").isalnum():
     315                # We must be alphanumeric, but we make an exception for non-leading '_' characters.
     316                raise ValueError, "variable names must be alphanumeric, but one is '%s' which is not."%N
     317            if not N[0].isalpha():
     318                raise ValueError, "first letter of variable name must be a letter: %s" % N
     319            v.append(N)
     320        return tuple(v)
     321       
     322    def variable_names(self):
     323        if self._names != None:
     324            return self._names
     325        raise ValueError, "variable names have not yet been set using self._assign_names(...)"
     326
     327    def variable_name(self):
     328        return self.variable_names()[0]
     329
     330    def inject_variables(self, scope=None, verbose=True):
     331        """
     332        Inject the generators of self with their names into the
     333        namespace of the Python code from which this function is
     334        called.  Thus, e.g., if the generators of self are labeled
     335        'a', 'b', and 'c', then after calling this method the
     336        variables a, b, and c in the current scope will be set
     337        equal to the generators of self.
     338
     339        NOTE: If Foo is a constructor for a SAGE object with
     340        generators, and Foo is defined in Pyrex, then it would
     341        typically call inject_variables() on the object it
     342        creates.  E.g., PolyomialRing(QQ, 'y') does this so that the
     343        variable y is the generator of the polynomial ring.
     344        """
     345        vs = self.variable_names()
     346        gs = self.gens()
     347        if scope is None:
     348           scope = globals()
     349        if verbose:
     350           print "Defining %s"%(', '.join(vs))
     351        for v, g in zip(vs, gs):
     352           scope[v] = g
     353
     354    def injvar(self, scope=None, verbose=True):
     355        """
     356        This is a synonym for self.inject_variables(...)
     357        <<<sage.structure.parent.Parent.inject_variables>>>
     358        """
     359        return self.inject_variables(scope=scope, verbose=verbose)
     360                   
     361    #################################################################################################
     362    # Bases
     363    #################################################################################################
     364
     365    cpdef base(self, category=None):
     366        if category is None:
     367            return self._base
     368        else:
     369            return category._obj_base(self)
     370
     371    def has_base(self, category=None):
     372        if category is None:
     373            return self._base is not None
     374        else:
     375            return category._obj_base(self) is not None
     376
     377    cpdef base_extend(self, other, category=None):
     378        """
     379        EXAMPLES:
     380            sage: QQ.base_extend(GF(7))
     381            Traceback (most recent call last):
     382            ...
     383            TypeError: base extension not defined for Rational Field
     384            sage: ZZ.base_extend(GF(7))
     385            Finite Field of size 7
     386        """
     387        try:
     388            if category is None:
     389                method = self._categories[0].get_object_method("base_extend") # , self._categories[1:])
     390            else:
     391                method = category.get_object_method("base_extend")
     392            return method(self)
     393        except AttributeError:
     394            raise TypeError, "base extension not defined for %s" % self
     395           
     396    def base_ring(self):
     397        # COERCE TODO: When everything has a category, move this to the category level.
     398        return self._base
     399   
     400    #################################################################################################
     401    # Automatic lookup of methods on the category.
     402    #################################################################################################
     403
     404    def __getattr__(self, name):
     405        """
     406        Overriding the __getattr__ method allows one to define methods for objects in a particular
     407        category by writing a correpsonding method on the category.
     408
     409        In order to write a method called FOO that's automatically attached to a category object,
     410        write a method object_FOO on one of that object's categories.
     411
     412        EXAMPLES:
     413        sage: G = DirichletGroup(18); G
     414        Group of Dirichlet characters of modulus 18 over Cyclotomic Field of order 6 and degree 2
     415        sage: G.generator_orders()
     416        [1, 6]
     417        sage: G.category().object_generator_orders(G)
     418        [1, 6]
     419        """
     420        if self._categories is not None:
     421            if self._categories[0] is None:
     422                # COERCE TODO: something went wrong earlier
     423                return object.__getattribute__(self, name)
     424            for C in self._categories:
     425                attr = C.get_object_method(name)
     426                if attr is not None:
     427                    if callable(attr):
     428                        return FillFirstArg(attr, self)
     429                    else:
     430                        return attr
     431        return object.__getattribute__(self, name)
     432
     433    ############################################################################
     434    # Homomorphism --
     435    ############################################################################
     436    def Hom(self, codomain, cat=None):
     437        r"""
     438        self.Hom(codomain, cat=None):
     439       
     440        Return the homspace \code{Hom(self, codomain, cat)} of all
     441        homomorphisms from self to codomain in the category cat.  The
     442        default category is determined by \code{self.category()} and
     443        \code{codomain.category()}.
     444
     445        EXAMPLES:
     446            sage: R.<x,y> = PolynomialRing(QQ, 2)
     447            sage: R.Hom(QQ)
     448            Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Rational Field
     449
     450        Homspaces are defined for very general \sage objects, even elements of familiar rings.
     451            sage: n = 5; Hom(n,7)
     452            Set of Morphisms from 5 to 7 in Category of elements of Integer Ring
     453            sage: z=(2/3); Hom(z,8/1)
     454            Set of Morphisms from 2/3 to 8 in Category of elements of Rational Field
     455
     456        This example illustrates the optional third argument:
     457            sage: QQ.Hom(ZZ, Sets())
     458            Set of Morphisms from Rational Field to Integer Ring in Category of sets
     459        """
     460        try:
     461            return self._Hom_(codomain, cat)
     462        except (TypeError, AttributeError):
     463            pass
     464        from sage.categories.all import Hom
     465        return Hom(self, codomain, cat)
     466
     467    def latex_variable_names(self):
     468        """
     469        Returns the list of variable names suitable for latex output.
     470
     471        All '_SOMETHING' substrings are replaced by '_{SOMETHING}' recursively
     472        so that subscripts of subscripts work.
     473
     474        EXAMPLES:
     475         sage: R, x = PolynomialRing(QQ,'x',12).objgens()
     476         sage: x
     477         (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)
     478         sage: print R.latex_variable_names ()
     479         ['x_{0}', 'x_{1}', 'x_{2}', 'x_{3}', 'x_{4}', 'x_{5}', 'x_{6}', 'x_{7}', 'x_{8}', 'x_{9}', 'x_{10}', 'x_{11}']
     480         sage: f = x[0]^3 + 15/3 * x[1]^10
     481         sage: print latex(f)
     482         5 x_{1}^{10} + x_{0}^{3}
     483        """
     484        from sage.misc.latex import latex, latex_variable_name
     485        try:
     486            names = self._latex_names
     487            if names is not None:
     488                return names
     489        except AttributeError:
     490            pass
     491        # Compute the latex versions of the variable names.
     492        self._latex_names = [latex_variable_name(x) for x in self.variable_names()]
     493        return self._latex_names
     494
     495    def latex_name(self):
     496        return self.latex_variable_names()[0]
     497
     498    def _temporarily_change_names(self, names):
     499        self._names = names
     500
     501    #################################################################################
     502    # Give all objects with generators a dictionary, so that attribute setting
     503    # works.   It would be nice if this functionality were standard in Pyrex,
     504    # i.e., just define __dict__ as an attribute and all this code gets generated.
     505    #################################################################################
     506    def __getstate__(self):
     507        d = []
     508        try:
     509            d = list(self.__dict__.copy().iteritems()) # so we can add elements
     510        except AttributeError:
     511            pass
     512        d = dict(d)
     513        d['_generators'] = self._generators
     514        d['_categories'] = self._categories
     515        d['_base'] = self._base
     516        d['_cdata'] = self._cdata
     517        d['_names'] = self._names
     518        ###########
     519        # The _pickle_version ensures that the unpickling for objects created
     520        # in different versions of sage works across versions.
     521        # Update this integer if you change any of these attributes
     522        ###########
     523        d['_pickle_version'] = 1
     524        try:
     525            d['_generator_orders'] = self._generator_orders
     526        except AttributeError:
     527            pass
     528       
     529        return d
     530
     531    def __setstate__(self,d):
     532        try:
     533            version = d['_pickle_version']
     534        except KeyError:
     535            version = 0
     536        try:
     537            if version == 1:
     538                self._generators = d['_generators']
     539                self._categories = d['_categories']
     540                self._base = d['_base']
     541                self._cdata = d['_cdata']
     542                self._names = d['_names']
     543                try:
     544                    self._generator_orders = d['_generator_orders']
     545                except (AttributeError, KeyError):
     546                    pass
     547            elif version == 0:
     548                # In the old code, this functionality was in parent_gens,
     549                # but there were parents that didn't inherit from parent_gens.
     550                # If we have such, then we only need to deal with the dictionary.
     551                try:
     552                    self._base = d['_base']
     553                    self._names = d['_names']
     554                    from sage.categories.category_types import Objects
     555                    if d['_gens'] is None:
     556                        from sage.structure.generators import Generators
     557                        self._generators = Generators(self, None, Objects())
     558                    else:
     559                        from sage.structure.generators import Generator_list
     560                        self._generators = Generator_list(self, d['_gens'], Objects())
     561                    self._generator_orders = d['_generator_orders'] # this may raise a KeyError, but that's okay.
     562                    # We throw away d['_latex_names'] and d['_list'] and d['_gens_dict']
     563                except (AttributeError, KeyError):
     564                    pass
     565            try:
     566                self.__dict__ = d
     567            except AttributeError:
     568                pass
     569        except (AttributeError, KeyError):
     570            raise
     571            #raise RuntimeError, "If you change the pickling code in parent or category_object, you need to update the _pickle_version field"
     572       
     573
     574#     #################################################################################
     575#     # Morphisms of objects with generators
     576#     #################################################################################
     577
     578
     579## COERCE TODO: see categories.MultiplicativeAbelianGroups
     580
     581# cdef class ParentWithMultiplicativeAbelianGens(Parent):
     582#     def generator_orders(self):
     583#         if self._generator_orders != None:
     584#             return self._generator_orders
     585#         else:
     586#             g = []
     587#             for x in self.gens():
     588#                 g.append(x.multiplicative_order())
     589#             self._generator_orders = g
     590#             return g
     591
     592#     def __iter__(self):
     593#         """
     594#         Return an iterator over the elements in this object.
     595#         """
     596#         return gens_py.multiplicative_iterator(self)
     597
     598       
     599   
     600# cdef class ParentWithAdditiveAbelianGens(Parent):
     601#     def generator_orders(self):
     602#         if self._generator_orders != None:
     603#             return self._generator_orders
     604#         else:
     605#             g = []
     606#             for x in self.gens():
     607#                 g.append(x.additive_order())
     608#             self._generator_orders = g
     609#             return g
     610
     611#     def __iter__(self):
     612#         """
     613#         Return an iterator over the elements in this object.
     614#         """
     615#         return gens_py.abelian_iterator(self)
     616
     617
     618
     619
     620class localvars:
     621    r"""
     622    Context manager for safely temporarily changing the variables
     623    names of an object with generators.
     624
     625    Objects with named generators are globally unique in SAGE.
     626    Sometimes, though, it is very useful to be able to temporarily
     627    display the generators differently.   The new Python "with"
     628    statement and the localvars context manager make this easy and
     629    safe (and fun!)
     630
     631    Suppose X is any object with generators.  Write
     632    \begin{verbatim}
     633       with localvars(X, names[, latex_names] [,normalize=False]):
     634            some code
     635            ...
     636    \end{verbatim}
     637    and the indented code will be run as if the names in X are changed
     638    to the new names.  If you give normalize=True, then the names are
     639    assumed to be a tuple of the correct number of strings.
     640
     641    If you're writing Python library code, you currently have
     642    to put \code{from __future__ import with_statement} in your file
     643    in order to use the \code{with} statement.  This restriction will
     644    disappear in Python 2.6.
     645
     646    EXAMPLES:
     647       sage: R.<x,y> = PolynomialRing(QQ,2)
     648       sage: with localvars(R, 'z,w'):
     649       ...       print x^3 + y^3 - x*y
     650       ...
     651       z^3 + w^3 - z*w
     652
     653    NOTES: I wrote this because it was needed to print elements of the
     654    quotient of a ring R by an ideal I using the print function for
     655    elements of R.  See the code in \code{quotient_ring_element.pyx}.
     656
     657    AUTHOR: William Stein (2006-10-31)
     658    """
     659    # fix this so that it handles latex names with the printer framework.
     660    def __init__(self, obj, names, latex_names=None, normalize=True):
     661        self._obj = obj
     662        if normalize:
     663            self._names = obj.normalize_names(obj.ngens(), names)
     664        else:
     665            self._names = names
     666
     667    def __enter__(self):
     668        self._orig_names = (<CategoryObject?>self._obj)._names
     669        self._obj._temporarily_change_names(self._names)
     670
     671    def __exit__(self, type, value, traceback):
     672        self._obj._temporarily_change_names(self._orig_names)
     673
     674
     675cdef class FillFirstArg:
     676    cdef object arg, f
     677    cdef public __doc__
     678    def __init__(self, f, arg):
     679        self.arg = arg
     680        self.f = f
     681        self.__doc__ = f.__doc__
     682    def __call__(self, *args, **kwds):
     683        return self.f(self.arg, *args, **kwds)
  • sage/structure/parent.pxd

    diff -r 5c038484dca0 -r 19b2ada8a983 sage/structure/parent.pxd
    a b  
    66#                  http://www.gnu.org/licenses/
    77###############################################################################
    88
    9 cimport sage_object
    10 cdef class Parent(sage_object.SageObject):
     9#cimport sage.categories.object
     10cimport sage.structure.category_object
     11
     12
     13cdef class Parent(category_object.CategoryObject):
     14
     15    cdef public _element_class
     16    cdef public _convert_method_name
     17    cdef public bint _element_init_pass_parent
     18    cdef public _initial_coerce_list
     19    cdef public _initial_action_list
     20    cdef public _initial_convert_list
     21   
     22    # New New Coercion support functionality
     23
     24    # returns whether or not there is a Morphism from S to self
     25    cpdef bint has_coerce_map_from(self, S) except -2
     26    cpdef bint _has_coerce_map_from_(self, S) except -2
     27
     28    # returns a Morphism from S to self, or None
     29    cpdef coerce_map_from(self, S)
     30    cpdef _coerce_map_from_(self, S)
     31
     32    # returns a Map from S to self, or None
     33    cpdef convert_map_from(self, S)
     34    cpdef _convert_map_from_(self, S)
     35   
     36    # returns the Action by/on self on/by S
     37    # corresponding to op and self_on_left
     38    cpdef get_action(self, other, op=*, bint self_on_left=*)
     39    cpdef _get_action_(self, other, op, bint self_on_left)
     40   
     41    # coerce x into self
     42    cpdef coerce(self, x)
     43    cpdef an_element(self)
     44    cpdef _an_element_(self)
     45
     46
     47    # For internal use
     48    cpdef _generic_convert_map(self, S)
     49    cdef discover_coerce_map_from(self, S)
     50    cdef discover_convert_map_from(self, S)
     51    cdef discover_action(self, G, op, bint self_on_left)
    1152
    1253    # List consisting of Morphisms (from anything to self)
    1354    # and Parents for which the __call__ method of self
    cdef class Parent(sage_object.SageObject 
    2465    cdef _action_list
    2566    # Hashtable of everything we've (possibliy recursively) discovered so far.
    2667    cdef _action_hash
    27    
    28     # returns a Morphism from S to self, or None
    29     cdef coerce_map_from_c(self, S)
    30     cdef coerce_map_from_c_impl(self, S)
    31    
    32     # returns the Action by/on self on/by S
    33     # corresponding to op and self_on_left
    34     cdef get_action_c(self, S, op, bint self_on_left)
    35     cdef get_action_c_impl(self, S, op, bint self_on_left)
    36    
    37    
    3868
    39     cdef public object _has_coerce_map_from
     69    # List consisting of Morphisms (from anything to self)
     70    # and Parents for which the __call__ method of self
     71    # does not result in type errors
     72    # Initalized at ring creation.
     73    cdef _convert_from_list
     74    # Hashtable of everything we've (possibliy recursively) discovered so far.
     75    cdef _convert_from_hash
     76    # An optional single Morphism that describes a cannonical coercion out of self
     77    cdef _embedding
     78
    4079
    4180    #########################################
    42     # Canonical Coercion Methods
    43     cdef has_coerce_map_from_c(self, S)
    44     cdef has_coerce_map_from_c_impl(self, S)
    45     cdef _coerce_c(self, x)
    46     cdef _coerce_c_impl(self, x)
    47     cdef _coerce_self_c(self, x)
     81
    4882    cdef public object __an_element
    49     cdef _an_element_c_impl(self)
    50     cdef _an_element_c(self)
     83    cpdef _an_element_impl(self)
    5184
    52     ################################################
    53     # Comparison of parent objects
    54     cdef _richcmp(left, right, int op)
    55     cdef int _cmp_c_impl(left, Parent right) except -2
    56 
    57 
    58 
    59 
  • sage/structure/parent.pyx

    diff -r 5c038484dca0 -r 19b2ada8a983 sage/structure/parent.pyx
    a b CLASS HIEARCHY: 
    44CLASS HIEARCHY:
    55
    66SageObject
    7     Parent
    8         ParentWithBase
    9             ParentWithGens
     7    CategoryObject
     8        Parent
    109
    1110
    1211TESTS:
    This came up in some subtle bug once. 
    1413    sage: gp(2) + gap(3)
    1514    5     
    1615"""
     16cimport element
     17cimport sage.categories.morphism as morphism
     18
     19cdef int bad_parent_warnings = 0
     20cdef int unique_parent_warnings = 0
     21
     22# TODO: define this once?
     23
     24cdef object elt_parent = None
     25
     26cdef inline parent_c(x):
     27    if PY_TYPE_CHECK(x, element.Element):
     28        return (<element.Element>x)._parent
     29    elif hasattr(x, 'parent'):
     30        return x.parent()
     31    else:
     32        return <object>PY_TYPE(x)
     33
     34cdef _record_exception():
     35    from element import get_coercion_model
     36    get_coercion_model()._record_exception()
     37
     38cdef object _Integer
     39cdef bint is_Integer(x):
     40    global _Integer
     41    if _Integer is None:
     42        from sage.rings.integer import Integer as _Integer
     43    return PY_TYPE_CHECK_EXACT(x, _Integer) or PY_TYPE_CHECK_EXACT(x, int)
     44
     45# for override testing
     46cdef extern from "descrobject.h":
     47    ctypedef struct PyMethodDef:
     48        void *ml_meth
     49    ctypedef struct PyMethodDescrObject:
     50        PyMethodDef *d_method
     51    void* PyCFunction_GET_FUNCTION(object)
     52    bint PyCFunction_Check(object)
     53   
     54cdef extern from *:
     55    Py_ssize_t PyDict_Size(object)
     56    Py_ssize_t PyTuple_GET_SIZE(object)
     57
    1758
    1859###############################################################################
    1960#   SAGE: System for Algebra and Geometry Experimentation   
    This came up in some subtle bug once. 
    2364#                  http://www.gnu.org/licenses/
    2465###############################################################################
    2566
    26 cimport sage_object
    2767import operator
     68import weakref
     69
     70from category_object import CategoryObject
     71from generators import Generators
     72
     73# TODO: Theses should probably go in the printer module (but lots of stuff imports them from parent)
     74from category_object import localvars
     75
     76cdef object BuiltinMethodType = type(repr)
    2877
    2978include '../ext/python_object.pxi'
    3079include '../ext/python_bool.pxi'
    def is_Parent(x): 
    4392        sage: is_Parent(Primes())
    4493        True   
    4594    """
    46     return PyBool_FromLong(PyObject_TypeCheck(x, Parent))
     95    return PY_TYPE_CHECK(x, Parent)
     96   
     97
     98cdef object all_parents = [] #weakref.WeakKeyDictionary()
    4799
    48100
    49101## def make_parent_v0(_class, _dict, has_coerce_map_from):
    def is_Parent(x): 
    58110##     new_object._has_coerce_map_from = has_coerce_map_from
    59111##     return new_object
    60112
    61 cdef class Parent(sage_object.SageObject):
     113cdef class Parent(category_object.CategoryObject):
    62114    """
    63115    Parents are the SAGE/mathematical analogues of container objects
    64116    in computer science.
    65117    """
    66118   
    67     def __init__(self, coerce_from=[], actions=[], embeddings=[]):
     119    def __init__(self, base=None, *, categories=[], element_class=None, gens=None, names=None, normalize=True, **kwds):
     120        CategoryObject.__init__(self, categories, base)
     121        if len(kwds) > 0:
     122            if bad_parent_warnings:
     123                print "Illegal keywords for %s: %s" % (type(self), kwds)
    68124        # TODO: many classes don't call this at all, but __new__ crashes SAGE
    69 #        if len(coerce_from) > 0:
    70 #            print type(self), coerce_from
    71         self._coerce_from_list = list(coerce_from)
     125        if bad_parent_warnings:
     126            if element_class is None:
     127                print "coerce BUG: No element_class provided", type(self)
     128            elif not callable(element_class):
     129                print "coerce BUG: Bad element_class provided", type(self), type(element_class), element_class
     130        if gens is not None:
     131            self._populate_generators_(gens, names, normalize)
     132        elif names is not None:
     133            self._assign_names(names, normalize)
     134        self._element_class = element_class
     135        if hasattr(element_class, 'init_no_parent'):
     136            self._element_init_pass_parent = not element_class.init_no_parent
     137        elif PY_TYPE_CHECK(element_class, types.MethodType):
     138            self._element_init_pass_parent = False
     139        elif PY_TYPE_CHECK(element_class, BuiltinMethodType):
     140            self._element_init_pass_parent = element_class.__self__ is not self
     141        else:
     142            self._element_init_pass_parent = True
     143        self._coerce_from_list = []
    72144        self._coerce_from_hash = {}
    73         self._action_list = list(actions)
     145        self._action_list = []
    74146        self._action_hash = {}
     147        self._convert_from_list = []
     148        self._convert_from_hash = {}
     149        self._embedding = None
     150        self._initial_coerce_list = []
     151        self._initial_action_list = []
     152        self._initial_convert_list = []
     153        all_parents.append(self)
     154#        try:
     155#            all_parents[self] = True # this is a weak reference
     156#        except:
     157#            print "couldn't weakref", type(self)
    75158       
    76         cdef Parent other
    77         for mor in embeddings:
    78             other = mor.domain()
    79             print "embedding", self, " --> ", other
    80             print mor
    81             other.init_coerce() # TODO remove when we can
    82             other._coerce_from_list.append(mor)
    83        
    84         # old
    85         self._has_coerce_map_from = {}
    86        
    87     def init_coerce(self):
     159    def init_coerce(self, bint verbose=True):
    88160        if self._coerce_from_hash is None:
    89 #            print "init_coerce() for ", type(self)
     161            if verbose:
     162                print "init_coerce() for ", type(self)
     163                raise ZeroDivisionError, "hello"
     164            self._initial_coerce_list = []
     165            self._initial_action_list = []
     166            self._initial_convert_list = []
    90167            self._coerce_from_list = []
    91168            self._coerce_from_hash = {}
    92169            self._action_list = []
    93170            self._action_hash = {}
     171            self._convert_from_list = []
     172            self._convert_from_hash = {}
     173            self._embedding = None
     174           
     175    def _introspect_coerce(self):
     176        return {
     177            '_coerce_from_list': self._coerce_from_list,
     178            '_coerce_from_hash': self._coerce_from_hash,
     179            '_action_list': self._action_list,
     180            '_action_hash': self._action_hash,
     181            '_convert_from_list': self._convert_from_list,
     182            '_convert_from_hash': self._convert_from_hash,
     183            '_embedding': self._embedding,
     184            '_initial_coerce_list': self._initial_coerce_list,
     185            '_initial_action_list': self._initial_action_list,
     186            '_initial_convert_list': self._initial_convert_list,
     187            '_element_init_pass_parent': self._element_init_pass_parent,
    94188
     189        }
     190           
     191    def __getstate__(self):
     192        #print self._introspect_coerce()
     193        d = CategoryObject.__getstate__(self)
     194        d['_embedding'] = self._embedding
     195        d['_element_class'] = self._element_class
     196        d['_convert_method_name'] = self._convert_method_name
     197        d['_element_init_pass_parent'] = self._element_init_pass_parent
     198        d['_initial_coerce_list'] = self._initial_coerce_list
     199        d['_initial_action_list'] = self._initial_action_list
     200        d['_initial_convert_list'] = self._initial_convert_list
     201        return d
     202
     203    def __setstate__(self, d):
     204        CategoryObject.__setstate__(self, d)
     205        try:
     206            version = d['_pickle_version']
     207        except KeyError:
     208            version = 0
     209        if version == 1:
     210            self._element_class = d['_element_class']
     211            self.init_coerce(False) # Really, do we want to init this with the same initial data as before?
     212            self._populate_coercion_lists_(coerce_list=d['_initial_coerce_list'],
     213                                           action_list=d['_initial_action_list'],
     214                                           convert_list=d['_initial_convert_list'],
     215                                           embedding=d['_embedding'],
     216                                           convert_method_name=d['_convert_method_name'],
     217                                           init_no_parent=not d['_element_init_pass_parent'])
     218
     219    def __call__(self, x=0, *args, **kwds):
     220        cdef Py_ssize_t i
     221        R = parent_c(x)
     222        cdef bint no_extra_args = PyTuple_GET_SIZE(args) == 0 and PyDict_Size(kwds) == 0
     223        if R is self and no_extra_args:
     224            return x
     225        if self._coerce_from_hash is None: # this is because parent.__init__() does not always get called
     226            self.init_coerce()
     227        cdef morphism.Morphism mor = <morphism.Morphism>self.convert_map_from(R)
     228        if mor is not None:
     229            try:
     230                if no_extra_args:
     231                    return mor._call_(x)
     232                else:
     233                    return mor._call_with_args(x, args, kwds)
     234            except TypeError, msg:
     235                self._convert_from_hash.pop(mor.domain(), None)
     236                for i from 0 <= i < len(self._convert_from_list):
     237                    if self._convert_from_list[i] is mor:
     238                        self._convert_from_list = self._convert_from_list[:i] + self._convert_from_list[i+1:]
     239                        break
     240                raise
     241           
     242        raise TypeError, "No conversion defined from %s to %s"%(R, self)
    95243       
    96244    #############################################################################
    97245    # Containment testing
    cdef class Parent(sage_object.SageObject 
    124272            return bool(x2 == x)
    125273        except TypeError:
    126274            return False
     275
     276    cpdef coerce(self, x):
     277        """
     278        Return x as an element of self, if and only if there is a canonical
     279        coercion from the parent of x to self.
     280       
     281        EXAMPLES:
     282            sage: QQ.coerce(ZZ(2))
     283            2
     284            sage: ZZ.coerce(QQ(2))
     285            Traceback (most recent call last):
     286            ...
     287            TypeError: no cannonical coercion from Rational Field to Integer Ring
     288           
     289        We make an exception for zero:
     290            sage: V = GF(7)^7
     291            sage: V.coerce(0)
     292            (0, 0, 0, 0, 0, 0, 0)
     293        """
     294        mor = self.coerce_map_from(parent_c(x))
     295        if mor is None:
     296            if is_Integer(x) and not x:
     297                try:
     298                    return self(0)
     299                except:
     300                    _record_exception()
     301            raise TypeError, "no cannonical coercion from %s to %s" % (parent_c(x), self)
     302        else:
     303            return (<morphism.Morphism>mor)._call_(x)
    127304   
     305    def list(self):
     306        """
     307        Return a list of all elements in this object, if possible (the
     308        object must define an iterator).
     309        """
     310        try:
     311            if self._list is not None:
     312                return self._list
     313        except AttributeError:
     314            try:
     315                self._list = list(self.__iter__())
     316                return self._list
     317            except AttributeError:
     318                return list(self.__iter__())
     319
     320    def __len__(self):
     321        return len(self.list())
     322
     323    def __getitem__(self, n):
     324        return self.list()[n]
     325
     326    def __getslice__(self,  Py_ssize_t n,  Py_ssize_t m):
     327        return self.list()[int(n):int(m)]
    128328
    129329    #################################################################################
    130     # New Coercion support functionality
     330    # Generators and Homomorphisms
    131331    #################################################################################
    132332   
    133     def coerce_map_from(self, S):
    134         return self.coerce_map_from_c(S)
     333    def _is_valid_homomorphism_(self, codomain, im_gens):
     334       r"""
     335       Return True if \code{im_gens} defines a valid homomorphism
     336       from self to codomain; otherwise return False.
     337
     338       If determining whether or not a homomorphism is valid has not
     339       been implemented for this ring, then a NotImplementedError exception
     340       is raised.
     341       """
     342       raise NotImplementedError, "Verification of correctness of homomorphisms from %s not yet implmented."%self
     343
     344    def hom(self, im_gens, codomain=None, check=None):
     345       r"""
     346       Return the unique homomorphism from self to codomain that
     347       sends \code{self.gens()} to the entries of \code{im_gens}.
     348       Raises a TypeError if there is no such homomorphism.
     349
     350       INPUT:
     351           im_gens -- the images in the codomain of the generators of
     352                      this object under the homomorphism
     353           codomain -- the codomain of the homomorphism
     354           check -- whether to verify that the images of generators extend
     355                    to define a map (using only canonical coercisions).
     356
     357       OUTPUT:
     358           a homomorphism self --> codomain
     359
     360       \note{As a shortcut, one can also give an object X instead of
     361       \code{im_gens}, in which case return the (if it exists)
     362       natural map to X.}
     363
     364       EXAMPLE: Polynomial Ring
     365       We first illustrate construction of a few homomorphisms
     366       involving a polynomial ring.
     367     
     368           sage: R.<x> = PolynomialRing(ZZ)
     369           sage: f = R.hom([5], QQ)
     370           sage: f(x^2 - 19)
     371           6
     372
     373           sage: R.<x> = PolynomialRing(QQ)
     374           sage: f = R.hom([5], GF(7))
     375           Traceback (most recent call last):
     376           ...
     377           TypeError: images do not define a valid homomorphism
     378
     379           sage: R.<x> = PolynomialRing(GF(7))
     380           sage: f = R.hom([3], GF(49,'a'))
     381           sage: f
     382           Ring morphism:
     383             From: Univariate Polynomial Ring in x over Finite Field of size 7
     384             To:   Finite Field in a of size 7^2
     385             Defn: x |--> 3
     386           sage: f(x+6)
     387           2
     388           sage: f(x^2+1)
     389           3
     390
     391       EXAMPLE: Natural morphism
     392           sage: f = ZZ.hom(GF(5))
     393           sage: f(7)
     394           2
     395           sage: f
     396           Ring Coercion morphism:
     397             From: Integer Ring
     398             To:   Finite Field of size 5
     399
     400       There might not be a natural morphism, in which case a TypeError exception is raised.
     401           sage: QQ.hom(ZZ)
     402           Traceback (most recent call last):
     403           ...
     404           TypeError: Natural coercion morphism from Rational Field to Integer Ring not defined.
     405       """
     406       if isinstance(im_gens, Parent):
     407           return self.Hom(im_gens).natural_map()
     408       from sage.structure.all import Sequence
     409       if codomain is None:
     410           im_gens = Sequence(im_gens)
     411           codomain = im_gens.universe()
     412       if isinstance(im_gens, (Sequence, Generators)):
     413            im_gens = list(im_gens)
     414       if check is None:
     415           return self.Hom(codomain)(im_gens)
     416       else:
     417           return self.Hom(codomain)(im_gens, check=check)
    135418   
    136     cdef coerce_map_from_c(self, S):
     419    #################################################################################
     420    # New New Coercion support functionality
     421    #################################################################################
     422   
     423    def _populate_coercion_lists_(self, coerce_list=[], action_list=[], convert_list=[], embedding=None, convert_method_name=None, init_no_parent=None):
     424        """
     425        This function allows one to specify coercions, actions, conversions
     426        and embeddings involving this parent.
     427
     428        IT SHOULD ONLY BE CALLED DURING THE __INIT__ method, often at the end.
     429       
     430        INPUT:
     431            coerce_list  -- a list of coercion Morphisms to self and
     432                            parents with cannonical coercions to self
     433            action_list  -- a list of actions on and by self
     434            convert_list -- a list of conversion Morphisms to self and
     435                            parents with conversions to self
     436            embedding    -- a single Morphism from self
     437            convert_method_name -- a name to look for that other elements
     438                            can implement to create elements of self (e.g. _integer_)
     439            init_no_parent -- if True omit passing self in as the first
     440                              argument of element_class for conversion. This is
     441                              useful if parents are unique, or element_class is
     442                              a bound method.
     443        """
     444        if not PY_TYPE_CHECK(coerce_list, list):
     445            raise ValueError, "%s_populate_coercion_lists_: coerce_list is type %s, must be list" % (type(coerce_list), type(self))
     446        if not PY_TYPE_CHECK(action_list, list):
     447            raise ValueError, "%s_populate_coercion_lists_: action_list is type %s, must be list" % (type(action_list), type(self))
     448        if not PY_TYPE_CHECK(convert_list, list):
     449            raise ValueError, "%s_populate_coercion_lists_: convert_list is type %s, must be list" % (type(convert_list), type(self))
     450
     451        self._initial_coerce_list = coerce_list
     452        self._initial_action_list = action_list
     453        self._initial_convert_list = convert_list
     454       
     455        from sage.categories.morphism import Morphism
     456
     457        self._convert_method_name = convert_method_name
     458        if init_no_parent is not None:
     459            self._element_init_pass_parent = not init_no_parent
     460       
     461        for mor in coerce_list:
     462            if PY_TYPE_CHECK(mor, Morphism):
     463                if mor.codomain() is not self:
     464                    raise ValueError, "Morphism's codomain must be self (%s) is not (%s)" % (self, mor.codomain())
     465                self._coerce_from_list.append(mor)
     466                self._coerce_from_hash[mor.domain()] = mor
     467            elif PY_TYPE_CHECK(mor, Parent) or PY_TYPE_CHECK(mor, type):
     468                P = mor
     469                mor = self._generic_convert_map(mor)
     470                self._coerce_from_list.append(mor)
     471                self._coerce_from_hash[P] = mor
     472            else:
     473                raise TypeError, "entries in the coerce_list must be parents or morphisms (got %s)" % type(mor)
     474               
     475        from sage.categories.action import Action
     476        for action in action_list:
     477            if isinstance(action, Action):
     478                if action.actor() is self:
     479                    self._action_list.append(action)
     480                    self._action_list[action.domain(), action.operation(), action.is_left()] = action
     481                elif action.domain() is self:
     482                    self._action_list.append(action)
     483                    self._action_list[action.actor(), action.operation(), not action.is_left()] = action
     484                else:
     485                    raise ValueError, "Action must involve self"
     486            else:
     487                raise TypeError, "entries in the action_list must be actions"
     488               
     489        for mor in convert_list:
     490            if isinstance(mor, Morphism):
     491                if mor.codomain() is not self:
     492                    raise ValueError, "Morphism's codomain must be self"
     493                self._convert_from_list.append(mor)
     494                self._convert_from_hash[mor.domain()] = mor
     495            elif PY_TYPE_CHECK(mor, Parent) or PY_TYPE_CHECK(mor, type):
     496                mor = self._generic_convert_map(mor)
     497                self._convert_from_list.append(mor)
     498                self._convert_from_hash[mor.domain()] = mor
     499            else:
     500                raise TypeError, "entries in the convert_list must be parents or morphisms"
     501               
     502        if isinstance(embedding, Morphism):
     503            if embedding.domain() is not self:
     504                raise ValueError, "Morphism's domain must be self"
     505            self._embedding = embedding
     506        elif isinstance(embedding, Parent):
     507            self._embedding = embedding._generic_convert_map(self)
     508        elif embedding is not None:
     509            raise TypeError, "embedding must be a parent or morphism"
     510           
     511    def get_embedding(self):
     512        return self._embedding
     513           
     514    cpdef _generic_convert_map(self, S):
     515        import coerce_maps
     516        if self._convert_method_name is not None:
     517            # handle methods like _integer_
     518            if PY_TYPE_CHECK(S, type):
     519                element_class = S
     520            elif PY_TYPE_CHECK(S, Parent):
     521                element_class = (<Parent>S)._element_class
     522                if not PY_TYPE_CHECK(element_class, type):
     523                    # if element_class is not an actual class, get the element class
     524                    element_class = type(S.an_element())
     525            else:
     526                element_class = None
     527            if element_class is not None and hasattr(element_class, self._convert_method_name):
     528                return coerce_maps.NamedConvertMorphism(S, self, self._convert_method_name)
     529           
     530        if self._element_init_pass_parent:
     531            return coerce_maps.DefaultConvertMorphism(S, self)
     532        else:
     533            return coerce_maps.DefaultConvertMorphism_unique(S, self)
     534
     535    cpdef bint has_coerce_map_from(self, S) except -2:
     536        """
     537        Return True if there is a natural map from S to self.
     538        Otherwise, return False.
     539        """
     540        if S is self:
     541            return True
     542        elif S == self:
     543            if unique_parent_warnings:
     544                print "Warning: non-unique parents %s"%(type(S))
     545            return True
     546        if self._coerce_from_hash is None:
     547            self.init_coerce()
     548        if self._coerce_from_hash.has_key(S):
     549            return self._coerce_from_hash[S] is not None
     550        if PY_TYPE_CHECK(S, Parent):
     551            if (<Parent>S)._embedding is not None and (<Parent>S)._embedding.codomain() is self:
     552                return True
     553        return self._has_coerce_map_from_(S)
     554
     555    cpdef bint _has_coerce_map_from_(self, S) except -2:
     556        # We first check (using some cython trickery) to see if coerce_map_from_ has been overridden.
     557        # If it has, then we can just (by default) call it and see if it returns None or not.
     558        # Otherwise we return False by default (so that no canonical coercions exist)
     559        if HAS_DICTIONARY(self):
     560            method = (<object>self)._coerce_map_from_
     561            if PyCFunction_Check(method) and \
     562                (<PyMethodDescrObject *>(<object>Parent).coerce_map_from).d_method.ml_meth == PyCFunction_GET_FUNCTION(method):
     563                return False
     564        elif Parent._coerce_map_from_ == self._coerce_map_from_:
     565            return False
     566        # At this point we are guaranteed coerce_map_from is actually implemented
     567        return self.coerce_map_from(S) is not None
     568       
     569    cpdef coerce_map_from(self, S):
    137570        if S is self:
    138571            from sage.categories.homset import Hom
    139572            return Hom(self, self).identity()
    140         elif S == self:
    141             # non-unique parents
    142             from sage.categories.homset import Hom
    143             from sage.categories.morphism import CallMorphism
    144             return CallMorphism(Hom(S, self))
     573
    145574        elif isinstance(S, Set_PythonType_class):
    146575            return self.coerce_map_from_c(S._type)
    147576        if self._coerce_from_hash is None: # this is because parent.__init__() does not always get called
    148577            self.init_coerce()
    149578        cdef object ret
    150579        try:
    151             ret = PyObject_GetItem(self._coerce_from_hash,S)
    152             return ret
     580            return self._coerce_from_hash[S]
    153581        except KeyError:
    154582            pass
    155         if HAS_DICTIONARY(self):
    156             mor = self.coerce_map_from_impl(S)
    157         else:
    158             mor = self.coerce_map_from_c_impl(S)
    159         import sage.categories.morphism
    160         if mor is True:
    161             mor = sage.categories.morphism.CallMorphism(S, self)
    162         elif mor is False:
    163             mor = None
    164         elif mor is not None and not isinstance(mor, sage.categories.morphism.Morphism):
    165             raise TypeError, "coerce_map_from_impl must return a boolean, None, or an explicit Morphism"
     583
     584        if S == self:
     585            # non-unique parents
     586            if unique_parent_warnings:
     587                print "Warning: non-unique parents %s"%(type(S))
     588            return self._generic_convert_map(S)
     589
     590        try:
     591            _register_pair(self, S)
     592            mor = self.discover_coerce_map_from(S)
     593            #if mor is not None:
     594            #    # Need to check that this morphism doesn't connect previously unconnected parts of the coercion diagram
     595            #    if self._embedding is not None and not self._embedding.codomain().has_coerce_map_from(S):
     596            #        # The following if statement may call this function with self and S.  If so, we want to return None,
     597            #        # so that it doesn't use this path for the existence of a coercion path.
     598            #        # We disable this for now because it is too strict
     599            #        pass
     600            #        # print "embed problem: the following morphisms connect unconnected portions of the coercion graph\n%s\n%s"%(self._embedding, mor)
     601            #        # mor = None
     602            if mor is not None:
     603                # NOTE: this line is what makes the coercion detection stateful
     604                self._coerce_from_list.append(mor)
     605            self._coerce_from_hash[S] = mor
     606            _unregister_pair(self, S)
     607            return mor
     608        except NotImplementedError:
     609            _record_exception()
     610            return None
     611
     612    cdef discover_coerce_map_from(self, S):
     613        """
     614        Precedence for discovering a coercion S -> self goes as follows:
     615       
     616            1. If S has an embedding into T, look for T -> self and return composition
     617            2. If self._coerce_map_from_(S) is NOT exactly one of
     618                    - DefaultConvertMorphism
     619                    - DefaultConvertMorphism_unique
     620                    - NamedConvertMorphism
     621                return this morphism
     622            3. Traverse the coercion lists looking for the "best" morphism
     623               (including the one found at 2).
     624        """
     625        best_mor = None
     626        if PY_TYPE_CHECK(S, Parent) and (<Parent>S)._embedding is not None:
     627            if (<Parent>S)._embedding.codomain() is self:
     628                return (<Parent>S)._embedding
     629            connecting = self._coerce_map_from_((<Parent>S)._embedding.codomain())
     630            if connecting is not None:
     631                return (<Parent>S)._embedding.post_compose(connecting)
     632       
     633        cdef morphism.Morphism mor = self._coerce_map_from_(S)
    166634        if mor is not None:
    167             self._coerce_from_hash[S] = mor # TODO: if this is None, could it be non-None in the future?
    168         return mor
    169        
    170     def coerce_map_from_impl(self, S):
    171         return self.coerce_map_from_c_impl(S)
    172            
    173     cdef coerce_map_from_c_impl(self, S):
     635            from sage.categories.morphism import Morphism
     636            from coerce_maps import DefaultConvertMorphism, DefaultConvertMorphism_unique, NamedConvertMorphism
     637            if not PY_TYPE_CHECK(mor, Morphism):
     638                raise TypeError, "_coerce_map_from_ must return None or an explicit Morphism"
     639            elif (PY_TYPE_CHECK_EXACT(mor, DefaultConvertMorphism) or
     640                  PY_TYPE_CHECK_EXACT(mor, DefaultConvertMorphism_unique) or
     641                  PY_TYPE_CHECK_EXACT(mor, NamedConvertMorphism)) and not mor._force_use:
     642                # If there is something better in the list, try to return that instead
     643                # This is so, for example, has_coerce_map_from can return True but still
     644                # take advantage of the _populate_coercion_lists_ data.
     645                best_mor = mor
     646            else:
     647                return mor
    174648        import sage.categories.morphism
    175649        from sage.categories.morphism import Morphism
    176650        from sage.categories.homset import Hom
     651
     652        cdef int num_paths = 1 # this is the number of paths we find before settling on the best (the one with lowest coerce_cost).
     653                               # setting this to 1 will make it return the first path found.
     654        cdef int mor_found = 0
    177655        cdef Parent R
     656        # Recurse.  Note that if S is the domain of one of the morphisms in self._coerce_from_list,
     657        # we will have stuck the morphism into _coerce_map_hash and thus returned it already.
    178658        for mor in self._coerce_from_list:
    179             if PY_TYPE_CHECK(mor, Morphism):
    180                 R = mor.domain()
    181             else:
    182                 R = mor
    183                 mor = sage.categories.morphism.CallMorphism(Hom(R, self))
    184                 i = self._coerce_from_list.index(R)
    185                 self._coerce_from_list[i] = mor # cache in case we need it again
    186             if R is S:
    187                 return mor
    188             else:
    189                 connecting = R.coerce_map_from_c(S)
    190                 if connecting is not None:
    191                     return mor * connecting
    192                
    193         # Piggyback off the old code for now
    194         # WARNING: when working on this, make sure circular dependancies aren't introduced!
    195         if self.has_coerce_map_from_c(S):
    196             if isinstance(S, type):
    197                 S = Set_PythonType(S)
    198             return sage.categories.morphism.FormalCoercionMorphism(Hom(S, self))
    199         else:
    200             return None
    201    
    202     def get_action(self, S, op=operator.mul, self_on_left=True):
    203         return self.get_action_c(S, op, self_on_left)
    204        
    205     cdef get_action_c(self, S, op, bint self_on_left):
     659            if mor._domain is S:
     660                if best_mor is None or mor._coerce_cost < best_mor._coerce_cost:
     661                    best_mor = mor
     662                mor_found += 1
     663                if mor_found  >= num_paths:
     664                    return best_mor
     665            connecting = mor._domain.coerce_map_from(S)
     666            if connecting is not None:
     667                mor = mor * connecting
     668                if best_mor is None or mor._coerce_cost < best_mor._coerce_cost:
     669                    best_mor = mor
     670                mor_found += 1
     671                if mor_found  >= num_paths:
     672                    return best_mor
     673
     674        return best_mor
     675           
     676
     677    cpdef _coerce_map_from_(self, S):
     678        if self.has_coerce_map_from(S):
     679            return self._generic_convert_map(S)
     680        return None
     681
     682    cpdef convert_map_from(self, S):
     683        try:
     684            return self._convert_from_hash[S]
     685        except KeyError:
     686            mor = self.discover_convert_map_from(S)
     687            self._convert_from_list.append(mor)
     688            self._convert_from_hash[S] = mor
     689            return mor
     690           
     691    cdef discover_convert_map_from(self, S):
     692        cdef morphism.Morphism mor = self.coerce_map_from(S)
     693        if mor is not None:
     694            return mor
     695
     696        try:
     697            if PY_TYPE_CHECK(S, Parent):
     698                mor = S.coerce_map_from(self)
     699                if mor is not None:
     700                    mor = mor.section()
     701                    if mor is not None:
     702                        return mor
     703        except NotImplementedError:
     704            pass
     705
     706        mor = self._convert_map_from_(S)
     707        if mor is not None:
     708            return mor
     709
     710        if not PY_TYPE_CHECK(S, type) and not PY_TYPE_CHECK(S, Parent):
     711            # Sequences is used as a category and a "Parent"
     712            from sage.categories.category_types import Sequences
     713            from sage.structure.coerce_maps import ListMorphism
     714            if isinstance(S, Sequences):
     715                return ListMorphism(S, self.convert_map_from(list))
     716           
     717        mor = self._generic_convert_map(S)
     718        return mor
     719
     720    cpdef _convert_map_from_(self, S):
     721        return None
     722
     723    cpdef get_action(self, S, op=operator.mul, bint self_on_left=True):
     724        """
     725        TESTS:
     726            sage: M = QQ['y']^3
     727            sage: M.get_action(ZZ['x']['y'])
     728            Right scalar multiplication by Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Integer Ring on Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in y over Rational Field
     729            sage: M.get_action(ZZ['x']) # should be None
     730        """
    206731        try:
    207732            if self._action_hash is None: # this is because parent.__init__() does not always get called
    208733                self.init_coerce()
    209734            return self._action_hash[S, op, self_on_left]
    210735        except KeyError:
    211736            pass
    212         if HAS_DICTIONARY(self):
    213             action = self.get_action_impl(S, op, self_on_left)
    214         else:
    215             action = self.get_action_c_impl(S, op, self_on_left)
     737
     738        action = self._get_action_(S, op, self_on_left)
     739        if action is None:
     740            action = self.discover_action(S, op, self_on_left)
     741
    216742        if action is not None:
    217743            from sage.categories.action import Action
    218744            if not isinstance(action, Action):
    219745                raise TypeError, "get_action_impl must return None or an Action"
    220             self._action_hash[S, op, self_on_left] = action
     746            # We do NOT add to the list, as this would lead to errors as in
     747            # the example above.
     748
     749        self._action_hash[S, op, self_on_left] = action
    221750        return action
    222751       
    223     def get_action_impl(self, S, op, self_on_left):
    224         return self.get_action_c_impl(S, op, self_on_left)
    225            
    226     cdef get_action_c_impl(self, S, op, bint self_on_left):
     752
     753    cdef discover_action(self, S, op, bint self_on_left):
    227754        # G acts on S, G -> G', R -> S => G' acts on R (?)
     755        # NO! ZZ[x,y] acts on Matrices(ZZ[x]) but ZZ[y] does not.
     756        # What may be true is that if the action's desination is S, then this can be allowed.
    228757        import sage.categories.morphism
    229758        from sage.categories.action import Action, PrecomposedAction
    230759        from sage.categories.morphism import Morphism
    231760        from sage.categories.homset import Hom
    232         from coerce import LeftModuleAction, RightModuleAction
     761        from coerce_actions import LeftModuleAction, RightModuleAction
    233762        cdef Parent R
    234763        for action in self._action_list:
    235             if PY_TYPE_CHECK(action, Action):
     764            if PY_TYPE_CHECK(action, Action) and action.operation() is op:
    236765                if self_on_left:
    237                     if action.left() is not self: continue
    238                     R = action.right()
     766                    if action.left_domain() is not self: continue
     767                    R = action.right_domain()
    239768                else:
    240                     if action.right() is not self: continue
    241                     R = action.left()
     769                    if action.right_domain() is not self: continue
     770                    R = action.left_domain()
    242771            elif op is operator.mul:
    243772                try:
    244773                    R = action
    245774                    _register_pair(x,y) # to kill circular recursion
    246775                    if self_on_left:
    247                         action = LeftModuleAction(S, self) # self is acted on from right
     776                        action = LeftModuleAction(R, self) # self is acted on from right
    248777                    else:
    249                         action = RightModuleAction(S, self) # self is acted on from left
     778                        action = RightModuleAction(R, self) # self is acted on from left
    250779                    _unregister_pair(x,y)
    251                     i = self._action_list.index(R)
    252                     self._action_list[i] = action
     780                    ## The following two lines are diabled to prevent the following from working:
     781                    ## sage: x, y = var('x,y')
     782                    ## sage: parent(ZZ[x][y](1)*vector(QQ[y],[1,2]))
     783                    ## sage: parent(ZZ[x](1)*vector(QQ[y],[1,2]))
     784                    ## We will hopefully come up with a way to reinsert them, because they increase the scope
     785                    ## of discovered actions.
     786                    #i = self._action_list.index(R)
     787                    #self._action_list[i] = action
    253788                except TypeError:
     789                    _record_exception()
     790                    _unregister_pair(x,y)
    254791                    continue
    255792            else:
    256793                continue # only try mul if not specified
    257794            if R is S:
    258795                return action
    259796            else:
    260                 connecting = R.coerce_map_from_c(S) # S -> R
     797                connecting = R.coerce_map_from(S) # S -> R
    261798                if connecting is not None:
    262799                    if self_on_left:
    263800                        return PrecomposedAction(action, None, connecting)
    264801                    else:
    265802                        return PrecomposedAction(action, connecting, None)
    266                
    267803
    268804        if op is operator.mul and PY_TYPE_CHECK(S, Parent):
    269             from coerce import LeftModuleAction, RightModuleAction, LAction, RAction
     805            from coerce_actions import LeftModuleAction, RightModuleAction, LAction, RAction
    270806            # Actors define _l_action_ and _r_action_
    271807            # Acted-on elements define _lmul_ and _rmul_
    272808           
    273809            # TODO: if _xmul_/_x_action_ code does stuff like
    274810            # if self == 0:
    275811            #    return self
    276             # then _an_element_c() == 0 could be very bad.
     812            # then an_element() == 0 could be very bad.
    277813            #
    278             #
    279             x = self._an_element_c()
    280             y = (<Parent>S)._an_element_c()
    281 #            print "looking for action ", self, "<--->", S
    282 #            print "looking for action ", x, "<--->", y
    283            
     814
     815            x = self.an_element()
     816            y = (<Parent>S).an_element()
     817            #print "looking for action ", self, "<--->", S
     818            #print "looking for action ", x, "<--->", y
     819
    284820            _register_pair(x,y) # this is to avoid possible infinite loops
    285821            if self_on_left:
    286822                try:
    287 #                    print "RightModuleAction"
     823                    #print "RightModuleAction", S, self
    288824                    action = RightModuleAction(S, self) # this will test _lmul_
    289825                    _unregister_pair(x,y)
    290 #                    print "got", action
     826                    #print "got", action
    291827                    return action
    292828                except (NotImplementedError, TypeError, AttributeError, ValueError), ex:
    293                     pass
     829                    _record_exception()
    294830                   
    295831                try:
    296 #                    print "LAction"
     832                    #print "LAction"
    297833                    z = x._l_action_(y)
    298834                    _unregister_pair(x,y)
     835                    #print "got", z
    299836                    return LAction(self, S)
    300837                except (NotImplementedError, TypeError, AttributeError, ValueError):
    301                     pass
     838                    _record_exception()
    302839                   
    303840            else:
    304841                try:
    305 #                    print "LeftModuleAction"
     842                    #print "LeftModuleAction"
    306843                    action = LeftModuleAction(S, self) # this will test _rmul_
    307844                    _unregister_pair(x,y)
    308 #                    print "got", action
     845                    #print "got", action
    309846                    return action
    310847                except (NotImplementedError, TypeError, AttributeError, ValueError), ex:
    311                     pass
     848                    _record_exception()
    312849                   
    313850                try:
    314 #                    print "RAction"
     851                    #print "RAction"
    315852                    z = x._r_action_(y)
    316853                    _unregister_pair(x,y)
     854                    #print "got", z
    317855                    return RAction(self, S)
    318856                except (NotImplementedError, TypeError, AttributeError, ValueError):
    319                     pass
     857                    _record_exception()
    320858                   
    321859           
    322860            try:
    323861                # maybe there is a more clever way of detecting ZZ than importing here...
    324862                from sage.rings.integer_ring import ZZ
    325                 if S is ZZ and not self.has_coerce_map_from(ZZ):
    326 #                    print "IntegerMulAction"
    327                     from sage.structure.coerce import IntegerMulAction
     863                from sage.rings.ring import Ring
     864                if S is ZZ and not PY_TYPE_CHECK(self, Ring) and not self.has_coerce_map_from(ZZ):
     865                    #print "IntegerMulAction"
     866                    from sage.structure.coerce_actions import IntegerMulAction
    328867                    action = IntegerMulAction(S, self, not self_on_left)
    329 #                    print "got", action
     868                    #print "got", action
    330869                    _unregister_pair(x,y)
    331870                    return action
    332871            except (NotImplementedError, TypeError, AttributeError, ValueError):
    333                 pass
     872                _record_exception()
    334873                   
    335874            _unregister_pair(x,y)
    336875       
    337 #            print "found nothing"
     876            #print "found nothing"
    338877               
     878
     879    cpdef _get_action_(self, S, op, bint self_on_left):
     880        return None
    339881
    340882    def construction(self):
    341883        """
    cdef class Parent(sage_object.SageObject 
    344886        """
    345887        return None
    346888
    347     #################################################################################
    348     # Coercion support functionality
    349     #################################################################################
    350    
    351     def _coerce_(self, x):            # Call this from Python (do not override!)
    352         return self._coerce_c(x)
    353    
    354     cdef _coerce_c(self, x):          # DO NOT OVERRIDE THIS (call it)
    355         try:
    356             P = x.parent()   # todo -- optimize
    357             if P is self:
    358                 return x
    359         except AttributeError, msg:
    360             pass
    361         if HAS_DICTIONARY(self):
    362             return self._coerce_impl(x)
    363         else:
    364             return self._coerce_c_impl(x)
    365 
    366     cdef _coerce_c_impl(self, x):     # OVERRIDE THIS FOR SAGEX CLASES
     889    cpdef an_element(self):
     890        if self.__an_element is None:
     891            self.__an_element = self._an_element_impl()
     892        return self.__an_element
     893       
     894    cpdef _an_element_impl(self):
    367895        """
    368         Canonically coerce x in assuming that the parent of x is not
    369         equal to self.
     896        COERCE TODO
     897        Here so that I didn't have to change parent.pxd.  Should be eliminated and _an_element_ made cpdef.  Also need to change:
     898        sage/rings/real_rqdf.pyx
     899        sage/libs/pari/gen.pyx
    370900        """
    371         raise TypeError       
    372 
    373     def _coerce_impl(self, x):        # OVERRIDE THIS FOR PYTHON CLASSES
    374         """
    375         Canonically coerce x in assuming that the parent of x is not
    376         equal to self.
    377         """
    378         return self._coerce_c_impl(x)
    379 
    380     def _coerce_try(self, x, v):
    381         """
    382         Given a list v of rings, try to coerce x canonically into each
    383         one in turn.  Return the __call__ coercion of the result into
    384         self of the first canonical coercion that succeeds.  Raise a
    385         TypeError if none of them succeed.
    386 
    387         INPUT:
    388              x -- Python object
    389              v -- parent object or list (iterator) of parent objects
    390         """
    391         if not isinstance(v, list):
    392             v = [v]
    393 
    394         for R in v:
    395             try:
    396                 y = R._coerce_(x)
    397                 return self(y)
    398             except (TypeError, AttributeError), msg:
    399                 pass
    400         raise TypeError, "no canonical coercion of element into self"
    401 
    402     def _coerce_self(self, x):
    403         return self._coerce_self_c(x)
    404 
    405     cdef _coerce_self_c(self, x):
    406         """
    407         Try to canonically coerce x into self.
    408         Return result on success or raise TypeError on failure.
    409         """
    410         # todo -- optimize?
    411         try:
    412             P = x.parent()
    413             if P is self:
    414                 return x
    415             elif P == self:
    416                 return self(x)
    417         except AttributeError:
    418             pass
    419         raise TypeError, "no canonical coercion to self defined"
    420 
    421     def has_coerce_map_from(self, S):
    422         return self.has_coerce_map_from_c(S)
    423 
    424     cdef has_coerce_map_from_c(self, S):
    425         """
    426         Return True if there is a natural map from S to self.
    427         Otherwise, return False.
    428         """
    429         if self == S:
    430             return True
    431         if self._has_coerce_map_from is None:
    432             self._has_coerce_map_from = {}
    433         else:
    434             try:
    435                 return self._has_coerce_map_from[S]
    436             except KeyError:
    437                 pass
    438         if HAS_DICTIONARY(self):
    439             x = self.has_coerce_map_from_impl(S)
    440         else:
    441             x = self.has_coerce_map_from_c_impl(S)
    442         self._has_coerce_map_from[S] = x
    443         return x
    444 
    445     def has_coerce_map_from_impl(self, S):
    446         return self.has_coerce_map_from_c_impl(S)
    447 
    448     cdef has_coerce_map_from_c_impl(self, S):
    449         if not PY_TYPE_CHECK(S, Parent):
    450             return False
    451         try:
    452             self._coerce_c((<Parent>S)._an_element_c())
    453         except TypeError:
    454             return False
    455         except NotImplementedError, msg:
    456             raise NotImplementedError, "%s\nAlso, please make sure you have implemented has_coerce_map_from_impl or has_coerce_map_from_c_impl (or better _an_element_c_impl or _an_element_impl if possible) for %s"%(msg,self)
    457         return True
    458 
    459     def _an_element_impl(self):     # override this in Python
    460         r"""
    461         Implementation of a function that returns an element (often non-trivial)
    462         of a parent object.  Every parent object should implement it,
    463         unless the default implementation works.
    464 
    465         NOTE: Parent structures that are implemented in SageX should
    466         implement \code{_an_element_c_impl} instead.
    467         """
    468         return self._an_element_c_impl()
    469 
    470     cdef _an_element_c_impl(self):  # override this in SageX
     901        return self._an_element_()
     902       
     903    cpdef _an_element_(self):
    471904        """
    472905        Returns an element of self. Want it in sufficent generality
    473906        that poorly-written functions won't work when they're not
    cdef class Parent(sage_object.SageObject 
    476909        try:
    477910            return self.gen(0)
    478911        except:
     912            _record_exception()
    479913            pass
    480914           
    481915        try:
    482916            return self.gen()
    483917        except:
     918            _record_exception()
    484919            pass
    485            
     920
    486921        from sage.rings.infinity import infinity
    487922        for x in ['_an_element_', 'pi', 1.2, 2, 1, 0, infinity]:
     923            # This weird looking list is to try to get an element
     924            # which doesn't coerce other places.
    488925            try:
    489926                return self(x)
    490             except (TypeError, NameError, NotImplementedError):
     927            except (TypeError, NameError, NotImplementedError, AttributeError, ValueError):
     928                _record_exception()
    491929                pass
    492930               
    493         raise NotImplementedError, "please implement _an_element_c_impl or _an_element_impl for %s"%self
     931        raise NotImplementedError, "please implement _an_element_ for %s" % self
    494932
    495     def _an_element(self):        # do not override this (call from Python)
    496         return self._an_element_c()
    497        
    498     cdef _an_element_c(self):     # do not override this (call from SageX)
    499         if not self.__an_element is None:
    500             return self.__an_element
    501         if HAS_DICTIONARY(self):
    502             self.__an_element = self._an_element_impl()
    503         else:
    504             self.__an_element = self._an_element_c_impl()
    505         return self.__an_element
    506            
    507        
    508     ################################################
    509     # Comparison of parent objects
    510     ################################################   
    511     cdef _richcmp(left, right, int op):
     933    def is_exact(self):
    512934        """
    513         Compare left and right.
    514         """
    515         cdef int r
     935        Return True if elements of this ring are represented exactly, i.e.,
     936        there is no precision loss when doing arithmetic.
    516937
    517         if not PY_TYPE_CHECK(right, Parent) or not PY_TYPE_CHECK(left, Parent):
    518             # One is not a parent -- use arbitrary ordering
    519             if (<PyObject*>left) < (<PyObject*>right):
    520                 r = -1
    521             elif (<PyObject*>left) > (<PyObject*>right):
    522                 r = 1
    523             else:
    524                 r = 0
    525            
    526         else:
    527             # Both are parents -- but need *not* have the same type.
    528             if HAS_DICTIONARY(left):
    529                 r = left.__cmp__(right)
    530             else:
    531                 r = left._cmp_c_impl(right)
    532 
    533         if op == 0:  #<
    534             return PyBool_FromLong(r  < 0)
    535         elif op == 2: #==
    536             return PyBool_FromLong(r == 0)
    537         elif op == 4: #>
    538             return PyBool_FromLong(r  > 0)
    539         elif op == 1: #<=
    540             return PyBool_FromLong(r <= 0)
    541         elif op == 3: #!=
    542             return PyBool_FromLong(r != 0)
    543         elif op == 5: #>=
    544             return PyBool_FromLong(r >= 0)
    545 
    546 ##     ####################################################################
    547 ##     # For a derived SageX class, you **must** put the following in
    548 ##     # your subclasses, in order for it to take advantage of the
    549 ##     # above generic comparison code.  You must also define
    550 ##     # _cmp_c_impl for a SageX class.
    551 ##     #
    552 ##     # For a derived Python class, simply define __cmp__.
    553 ##     ####################################################################
    554 ##     def __richcmp__(left, right, int op):
    555 ##         return (<Parent>left)._richcmp(right, op)
    556 
    557 ##         # NOT NEEDED, since all attributes are public!
    558 ##     def __reduce__(self):
    559 ##         if HAS_DICTIONARY(self):
    560 ##             _dict = self.__dict__
    561 ##         else:
    562 ##             _dict = None
    563 ##         return (make_parent_v0, (self.__class__, _dict, self._has_coerce_map_from))
    564 
    565     cdef int _cmp_c_impl(left, Parent right) except -2:
    566         pass
    567         # this would be nice to do, but we can't since
    568         # it leads to infinite recurssions -- and is slow -- and this
    569         # stuff must be fast!
    570         #if right.has_coerce_map_from(left):
    571         #    if left.has_coerce_map_from(right):
    572         #        return 0
    573         #    else:
    574         #        return -1
    575         if (<PyObject*>left) < (<PyObject*>right):
    576             return -1
    577         elif (<PyObject*>left) > (<PyObject*>right):
    578             return 1
    579         return 0
    580 
    581 ##     def __cmp__(left, right):
    582 ##         return left._cmp_c_impl(right)   # default
    583 
    584 
    585     ############################################################################
    586     # Homomorphism --
    587     ############################################################################
    588     def Hom(self, codomain, cat=None):
    589         r"""
    590         self.Hom(codomain, cat=None):
    591        
    592         Return the homspace \code{Hom(self, codomain, cat)} of all
    593         homomorphisms from self to codomain in the category cat.  The
    594         default category is \code{self.category()}.
     938        NOTE: This defaults to true, so even if it does return True you have
     939        no guarantee (unless the ring has properly overloaded this).
    595940
    596941        EXAMPLES:
    597             sage: R.<x,y> = PolynomialRing(QQ, 2)
    598             sage: R.Hom(QQ)
    599             Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Rational Field
     942            sage: QQ.is_exact()
     943            True
     944            sage: ZZ.is_exact()
     945            True
     946            sage: Qp(7).is_exact()
     947            False
     948            sage: Zp(7, type='capped-abs').is_exact()
     949            False
     950        """
     951        return True
    600952
    601         Homspaces are defined for very general \sage objects, even elements of familiar rings.
    602             sage: n = 5; Hom(n,7)
    603             Set of Morphisms from 5 to 7 in Category of elements of Integer Ring
    604             sage: z=(2/3); Hom(z,8/1)
    605             Set of Morphisms from 2/3 to 8 in Category of elements of Rational Field
     953    cpdef base_extend(self, other, category=None):
     954        """
     955        EXAMPLES:
     956            sage: QQ.base_extend(GF(7))
     957            Traceback (most recent call last):
     958            ...
     959            TypeError: base extension not defined for Rational Field
     960            sage: ZZ.base_extend(GF(7))
     961            Finite Field of size 7
     962        """
     963        # Use the coerce map if a base extend is not defined in the category.
     964        # this is the default implementation.
     965        try:
     966            if category is None:
     967                method = self._categories[0].get_object_method("base_extend") # , self._categories[1:])
     968            else:
     969                method = category.get_object_method("base_extend")
     970            if method is not None:
     971                return method(self)
     972            elif other.has_coerce_map_from(self):
     973                return other
     974            else:
     975                raise TypeError, "base extension not defined for %s" % self
     976        except AttributeError:
     977            raise TypeError, "base extension not defined for %s" % self
    606978
    607         This example illustrates the optional third argument:
    608             sage: QQ.Hom(ZZ, Sets())
    609             Set of Morphisms from Rational Field to Integer Ring in Category of sets
    610         """
    611         try:
    612             return self._Hom_(codomain, cat)
    613         except (TypeError, AttributeError):
    614             pass
    615         from sage.categories.all import Hom
    616         return Hom(self, codomain, cat)
     979############################################################################
     980# Set baseclass --
     981############################################################################
    617982
    618983
    619     ############################################################################
    620     # Set baseclass --
    621     ############################################################################
    622 
    623 
    624 class Set_generic(Parent): # Cannot use Parent because Element._parent is ParentWithBase
     984cdef class Set_generic(Parent): # Cannot use Parent because Element._parent is Parent
    625985    """
    626986    Abstract base class for sets.
    627987    """
    class Set_generic(Parent): # Cannot use  
    6411001        return self
    6421002
    6431003
    644 cdef _set_cache = {}
    645 def Set_PythonType(t):
     1004
     1005import types
     1006cdef _type_set_cache = {}
     1007
     1008def Set_PythonType(theType):
    6461009    """
    647     The set of all object of a given type. This is primarily used to fit
    648     types (such as int, float, list) into the coercion model (as domains
    649     and codomains must be Sage Parents).
     1010    Return the (unique) Parent that represents the set of Python objects
     1011    of a specified type.
    6501012   
    6511013    EXAMPLES:
    6521014        sage: from sage.structure.parent import Set_PythonType
    653         sage: Set_PythonType(int) is Set_PythonType(int)
     1015        sage: Set_PythonType(list)
     1016        Set of Python objects of type 'list'
     1017        sage: Set_PythonType(list) is Set_PythonType(list)
    6541018        True
     1019        sage: S = Set_PythonType(tuple)
     1020        sage: S([1,2,3])
     1021        (1, 2, 3)
    6551022    """
    6561023    try:
    657         return _set_cache[t]
     1024        return _type_set_cache[theType]
    6581025    except KeyError:
    659         _set_cache[t] = s = Set_PythonType_class(t)
    660         return s
     1026        _type_set_cache[theType] = theSet = Set_PythonType_class(theType)
     1027        return theSet
    6611028
    662 class Set_PythonType_class(Set_generic):
     1029cdef class Set_PythonType_class(Set_generic):
     1030   
     1031    cdef _type
    6631032
    6641033    def __init__(self, theType):
     1034        from sage.categories.category_types import Sets
     1035        Set_generic.__init__(self, element_class=theType, categories=[Sets()])
    6651036        self._type = theType
    6661037
    6671038    def __call__(self, x):
    6681039        return self._type(x)
    6691040
    6701041    def __hash__(self):
    671         return hash(self._type)
     1042        return -hash(self._type)
    6721043       
    673     def __cmp__(self, other):
     1044    cpdef int _cmp_(self, other) except -100:
    6741045        if self is other:
    6751046            return 0
    6761047        if isinstance(other, Set_PythonType_class):
    6771048            return cmp(self._type, other._type)
    6781049        else:
    6791050            return cmp(self._type, other)
    680 
     1051           
    6811052    def __contains__(self, x):
    6821053        return isinstance(x, self._type)
    6831054
    class Set_PythonType_class(Set_generic): 
    6971068            import sage.rings.infinity
    6981069            return sage.rings.infinity.infinity
    6991070
    700 
    701 # These functions are to guerentee that user defined _lmul_, _rmul_, _l_action_, _r_action_ do
    702 # not in turn call __mul__ on their arguments, leading to an infinite loop. 
     1071# These functions are to guarantee that user defined _lmul_, _rmul_,
     1072# _l_action_, _r_action_ do not in turn call __mul__ on their
     1073# arguments, leading to an infinite loop.
    7031074
    7041075cdef object _coerce_test_list = []
    7051076
    class EltPair: 
    7081079        self.x = x
    7091080        self.y = y
    7101081    def __eq__(self, other):
    711         return type(self.x) is type(other.x) and self.x == other.x and type(self.y) is type(other.y) and self.y == other.y
     1082        return type(self.x) is type(other.x) and self.x is other.x and type(self.y) is type(other.y) and self.y is other.y
    7121083    def __repr__(self):
    7131084        return "%r (%r), %r (%r)" % (self.x, type(self.x), self.y, type(self.y))
    7141085
    cdef bint _register_pair(x, y) except -1 
    7191090#        print "Uh oh..."
    7201091#        print _coerce_test_list
    7211092#        print both
    722         raise NotImplementedError, "Infinite loop in multiplication of %s (parent %s) and %s (parent %s)!" % (x, x.parent(), y, y.parent())
     1093        xp = type(x) if PY_TYPE_CHECK(x, Parent) else parent_c(x)
     1094        yp = type(y) if PY_TYPE_CHECK(y, Parent) else parent_c(y)
     1095        #print xp, yp
     1096        raise NotImplementedError, "Infinite loop in action of %s (parent %s) and %s (parent %s)!" % (x, xp, y, yp)
    7231097    _coerce_test_list.append(both)
    7241098    return 0
    7251099
    726 cdef void _unregister_pair(x, y):
     1100cdef bint _unregister_pair(x, y) except -1:
    7271101    try:
    7281102        _coerce_test_list.remove(EltPair(x,y))
    7291103    except (ValueError, NotImplementedError):
    7301104        pass
     1105
     1106
     1107def coerce_graph(parents=None):
     1108    from sage.graphs.graph import DiGraph
     1109    G = DiGraph()
     1110    if parents is None:
     1111        parents = all_parents #.keys()
     1112    G.add_vertices(parents)
     1113    cdef Parent P
     1114    for P in parents:
     1115        for S, mor in P._coerce_from_hash.iteritems():
     1116            if S in parents:
     1117                G.add_edge(P, S, mor)
     1118    return G
     1119
     1120
     1121
     1122empty_set = Set_generic()
     1123
     1124def normalize_names(ngens, names):
     1125    return empty_set.normalize_names(ngens, names)
  • sage/structure/parent_base.pxd

    diff -r 5c038484dca0 -r 19b2ada8a983 sage/structure/parent_base.pxd
    a b  
    66#                  http://www.gnu.org/licenses/
    77###############################################################################
    88
    9 cimport parent
     9cimport parent_old
    1010
    11 cdef class ParentWithBase(parent.Parent):
    12     cdef parent.Parent _base
     11cdef class ParentWithBase(parent_old.Parent):
     12    cdef parent_old.Parent _base
    1313    # DO NOT OVERRIDE ANY OF THE FOLLOWING
    1414    cdef base_extend_recursive_c(self, ParentWithBase X)
    1515    cdef base_extend_canonical_c(self, ParentWithBase X)
  • sage/structure/parent_base.pyx

    diff -r 5c038484dca0 -r 19b2ada8a983 sage/structure/parent_base.pyx
    a b def is_ParentWithBase(x): 
    3939    """
    4040    return bool(PY_TYPE_CHECK(x, ParentWithBase))
    4141
    42 cdef class ParentWithBase(parent.Parent):
     42cdef class ParentWithBase(parent_old.Parent):
    4343    def __init__(self, base, coerce_from=[], actions=[], embeddings=[]):
    4444        # TODO: SymbolicExpressionRing has base RR, which makes this bad
    4545#        print type(self), "base", base, coerce_from
    4646#        if base != self and not base in coerce_from:
    4747#            coerce_from.append(base)
    48         parent.Parent.__init__(self, coerce_from=coerce_from, actions=actions, embeddings=embeddings)
     48        parent_old.Parent.__init__(self, coerce_from=coerce_from, actions=actions, embeddings=embeddings)
    4949        self._base = base
    5050       
    5151    cdef _coerce_c_impl(self,x):
  • new file sage/structure/parent_old.pxd

    diff -r 5c038484dca0 -r 19b2ada8a983 sage/structure/parent_old.pxd
    - +  
     1###############################################################################
     2#   SAGE: System for Algebra and Geometry Experimentation   
     3#       Copyright (C) 2006 William Stein <wstein@gmail.com>
     4#  Distributed under the terms of the GNU General Public License (GPL)
     5#  The full text of the GPL is available at:
     6#                  http://www.gnu.org/licenses/
     7###############################################################################
     8
     9cimport parent
     10cdef class Parent(parent.Parent):
     11
     12    # List consisting of Morphisms (from anything to self)
     13    # and Parents for which the __call__ method of self
     14    # results in natural coercion.
     15    # Initalized at ring creation.
     16    cdef _coerce_from_list
     17    # Hashtable of everything we've (possibliy recursively) discovered so far.
     18    cdef _coerce_from_hash
     19   
     20    # List consisting of Actions (either by or on self)
     21    # and Parents for which self._rmul_ and/or self._lmul_
     22    # do the correct thing.
     23    # Initalized at ring creation.
     24    cdef _action_list
     25    # Hashtable of everything we've (possibliy recursively) discovered so far.
     26    cdef _action_hash
     27   
     28    # returns a Morphism from S to self, or None
     29    cdef coerce_map_from_c(self, S)
     30    cdef coerce_map_from_c_impl(self, S)
     31   
     32    # returns the Action by/on self on/by S
     33    # corresponding to op and self_on_left
     34    cdef get_action_c(self, S, op, bint self_on_left)
     35    cdef get_action_c_impl(self, S, op, bint self_on_left)
     36   
     37   
     38
     39    cdef public object _has_coerce_map_from
     40
     41    #########################################
     42    # Canonical Coercion Methods
     43    cdef has_coerce_map_from_c(self, S)
     44    cdef has_coerce_map_from_c_impl(self, S)
     45    cdef _coerce_c(self, x)
     46    cdef _coerce_c_impl(self, x)
     47    cdef _coerce_self_c(self, x)
     48    cdef public object __an_element
     49    cdef _an_element_c_impl(self)
     50    cdef _an_element_c(self)
     51
     52    ################################################
     53    # Comparison of parent objects
     54    cdef _richcmp(left, right, int op)
     55    cdef int _cmp_c_impl(left, Parent right) except -2
     56
     57
     58
     59
  • new file sage/structure/parent_old.pyx

    diff -r 5c038484dca0 -r 19b2ada8a983 sage/structure/parent_old.pyx
    - +  
     1r"""
     2Base class for parent objects
     3
     4CLASS HIEARCHY:
     5
     6SageObject
     7    Parent
     8        ParentWithBase
     9            ParentWithGens
     10
     11
     12TESTS:
     13This came up in some subtle bug once.
     14    sage: gp(2) + gap(3)
     15    5     
     16"""
     17
     18###############################################################################
     19#   SAGE: System for Algebra and Geometry Experimentation   
     20#       Copyright (C) 2006 William Stein <wstein@gmail.com>
     21#  Distributed under the terms of the GNU General Public License (GPL)
     22#  The full text of the GPL is available at:
     23#                  http://www.gnu.org/licenses/
     24###############################################################################
     25
     26cimport sage_object
     27import operator
     28
     29include '../ext/python_object.pxi'
     30include '../ext/python_bool.pxi'
     31include '../ext/stdsage.pxi'
     32
     33def is_Parent(x):
     34    """
     35    Return True if x is a parent object, i.e., derives from
     36    sage.structure.parent.Parent and False otherwise.
     37
     38    EXAMPLES:
     39        sage: is_Parent(2/3)
     40        False
     41        sage: is_Parent(ZZ)
     42        True
     43        sage: is_Parent(Primes())
     44        True   
     45    """
     46    return PyBool_FromLong(PyObject_TypeCheck(x, Parent))
     47
     48
     49## def make_parent_v0(_class, _dict, has_coerce_map_from):
     50##     """
     51##     This should work for any Python class deriving from this, as long
     52##     as it doesn't implement some screwy __new__() method.
     53##     """
     54##     cdef Parent new_object
     55##     new_object = _class.__new__(_class)
     56##     if not _dict is None:
     57##         new_object.__dict__ = _dict
     58##     new_object._has_coerce_map_from = has_coerce_map_from
     59##     return new_object
     60
     61cdef class Parent(parent.Parent):
     62    """
     63    Parents are the SAGE/mathematical analogues of container objects
     64    in computer science.
     65    """
     66   
     67    def __init__(self, coerce_from=[], actions=[], embeddings=[]):
     68        # TODO: many classes don't call this at all, but __new__ crashes SAGE
     69#        if len(coerce_from) > 0:
     70#            print type(self), coerce_from
     71        self._coerce_from_list = list(coerce_from)
     72        self._coerce_from_hash = {}
     73        self._action_list = list(actions)
     74        self._action_hash = {}
     75       
     76        cdef Parent other
     77        for mor in embeddings:
     78            other = mor.domain()
     79            print "embedding", self, " --> ", other
     80            print mor
     81            other.init_coerce() # TODO remove when we can
     82            other._coerce_from_list.append(mor)
     83       
     84        # old
     85        self._has_coerce_map_from = {}
     86       
     87    def init_coerce(self):
     88        if self._coerce_from_hash is None:
     89#            print "init_coerce() for ", type(self)
     90            self._coerce_from_list = []
     91            self._coerce_from_hash = {}
     92            self._action_list = []
     93            self._action_hash = {}
     94
     95       
     96    #############################################################################
     97    # Containment testing
     98    #############################################################################
     99    def __contains__(self, x):
     100        r"""
     101        True if there is an element of self that is equal to x under ==.
     102
     103        For many structures we test this by using \code{__call__} and
     104        then testing equality between x and the result.
     105       
     106        EXAMPLES:
     107            sage: 2 in Integers(7)
     108            True
     109            sage: 2 in ZZ
     110            True
     111            sage: Integers(7)(3) in ZZ
     112            True
     113            sage: 3/1 in ZZ
     114            True
     115            sage: 5 in QQ
     116            True
     117            sage: I in RR
     118            False
     119            sage: SR(2) in ZZ
     120            True
     121        """
     122        try:
     123            x2 = self(x)
     124            return bool(x2 == x)
     125        except TypeError:
     126            return False
     127   
     128
     129    #################################################################################
     130    # New Coercion support functionality
     131    #################################################################################
     132   
     133    def coerce_map_from(self, S):
     134        return self.coerce_map_from_c(S)
     135   
     136    cdef coerce_map_from_c(self, S):
     137        if S is self:
     138            from sage.categories.homset import Hom
     139            return Hom(self, self).identity()
     140        elif S == self:
     141            # non-unique parents
     142            from sage.categories.homset import Hom
     143            from sage.categories.morphism import CallMorphism
     144            return CallMorphism(Hom(S, self))
     145        elif isinstance(S, Set_PythonType_class):
     146            return self.coerce_map_from_c(S._type)
     147        if self._coerce_from_hash is None: # this is because parent.__init__() does not always get called
     148            self.init_coerce()
     149        cdef object ret
     150        try:
     151            ret = PyObject_GetItem(self._coerce_from_hash,S)
     152            return ret
     153        except KeyError:
     154            pass
     155        if HAS_DICTIONARY(self):
     156            mor = self.coerce_map_from_impl(S)
     157        else:
     158            mor = self.coerce_map_from_c_impl(S)
     159        import sage.categories.morphism
     160        if mor is True:
     161            mor = sage.categories.morphism.CallMorphism(S, self)
     162        elif mor is False:
     163            mor = None
     164        elif mor is not None and not isinstance(mor, sage.categories.morphism.Morphism):
     165            raise TypeError, "coerce_map_from_impl must return a boolean, None, or an explicit Morphism"
     166        if mor is not None:
     167            self._coerce_from_hash[S] = mor # TODO: if this is None, could it be non-None in the future?
     168        return mor
     169       
     170    def coerce_map_from_impl(self, S):
     171        return self.coerce_map_from_c_impl(S)
     172           
     173    cdef coerce_map_from_c_impl(self, S):
     174        import sage.categories.morphism
     175        from sage.categories.morphism import Morphism
     176        from sage.categories.homset import Hom
     177        cdef Parent R
     178        for mor in self._coerce_from_list:
     179            if PY_TYPE_CHECK(mor, Morphism):
     180                R = mor.domain()
     181            else:
     182                R = mor
     183                mor = sage.categories.morphism.CallMorphism(Hom(R, self))
     184                i = self._coerce_from_list.index(R)
     185                self._coerce_from_list[i] = mor # cache in case we need it again
     186            if R is S:
     187                return mor
     188            else:
     189                connecting = R.coerce_map_from_c(S)
     190                if connecting is not None:
     191                    return mor * connecting
     192               
     193        # Piggyback off the old code for now
     194        # WARNING: when working on this, make sure circular dependancies aren't introduced!
     195        if self.has_coerce_map_from_c(S):
     196            if isinstance(S, type):
     197                S = Set_PythonType(S)
     198            return sage.categories.morphism.FormalCoercionMorphism(Hom(S, self))
     199        else:
     200            return None
     201   
     202    def get_action(self, S, op=operator.mul, self_on_left=True):
     203        return self.get_action_c(S, op, self_on_left)
     204       
     205    cdef get_action_c(self, S, op, bint self_on_left):
     206        try:
     207            if self._action_hash is None: # this is because parent.__init__() does not always get called
     208                self.init_coerce()
     209            return self._action_hash[S, op, self_on_left]
     210        except KeyError:
     211            pass
     212        if HAS_DICTIONARY(self):
     213            action = self.get_action_impl(S, op, self_on_left)
     214        else:
     215            action = self.get_action_c_impl(S, op, self_on_left)
     216        if action is not None:
     217            from sage.categories.action import Action
     218            if not isinstance(action, Action):
     219                raise TypeError, "get_action_impl must return None or an Action"
     220            self._action_hash[S, op, self_on_left] = action
     221        return action
     222       
     223    def get_action_impl(self, S, op, self_on_left):
     224        return self.get_action_c_impl(S, op, self_on_left)
     225           
     226    cdef get_action_c_impl(self, S, op, bint self_on_left):
     227        # G acts on S, G -> G', R -> S => G' acts on R (?)
     228        import sage.categories.morphism
     229        from sage.categories.action import Action, PrecomposedAction
     230        from sage.categories.morphism import Morphism
     231        from sage.categories.homset import Hom
     232        from coerce import LeftModuleAction, RightModuleAction
     233        cdef Parent R
     234        for action in self._action_list:
     235            if PY_TYPE_CHECK(action, Action):
     236                if self_on_left:
     237                    if action.left() is not self: continue
     238                    R = action.right()
     239                else:
     240                    if action.right() is not self: continue
     241                    R = action.left()
     242            elif op is operator.mul:
     243                try:
     244                    R = action
     245                    _register_pair(x,y) # to kill circular recursion
     246                    if self_on_left:
     247                        action = LeftModuleAction(S, self) # self is acted on from right
     248                    else:
     249                        action = RightModuleAction(S, self) # self is acted on from left
     250                    _unregister_pair(x,y)
     251                    i = self._action_list.index(R)
     252                    self._action_list[i] = action
     253                except TypeError:
     254                    continue
     255            else:
     256                continue # only try mul if not specified
     257            if R is S:
     258                return action
     259            else:
     260                connecting = R.coerce_map_from_c(S) # S -> R
     261                if connecting is not None:
     262                    if self_on_left:
     263                        return PrecomposedAction(action, None, connecting)
     264                    else:
     265                        return PrecomposedAction(action, connecting, None)
     266               
     267
     268        if op is operator.mul and PY_TYPE_CHECK(S, Parent):
     269            from coerce import LeftModuleAction, RightModuleAction, LAction, RAction
     270            # Actors define _l_action_ and _r_action_
     271            # Acted-on elements define _lmul_ and _rmul_
     272           
     273            # TODO: if _xmul_/_x_action_ code does stuff like
     274            # if self == 0:
     275            #    return self
     276            # then _an_element_c() == 0 could be very bad.
     277            #
     278            #
     279            x = self._an_element_c()
     280            y = (<Parent>S)._an_element_c()
     281#            print "looking for action ", self, "<--->", S
     282#            print "looking for action ", x, "<--->", y
     283           
     284            _register_pair(x,y) # this is to avoid possible infinite loops
     285            if self_on_left:
     286                try:
     287#                    print "RightModuleAction"
     288                    action = RightModuleAction(S, self) # this will test _lmul_
     289                    _unregister_pair(x,y)
     290#                    print "got", action
     291                    return action
     292                except (NotImplementedError, TypeError, AttributeError, ValueError), ex:
     293                    pass
     294                   
     295                try:
     296#                    print "LAction"
     297                    z = x._l_action_(y)
     298                    _unregister_pair(x,y)
     299                    return LAction(self, S)
     300                except (NotImplementedError, TypeError, AttributeError, ValueError):
     301                    pass
     302                   
     303            else:
     304                try:
     305#                    print "LeftModuleAction"
     306                    action = LeftModuleAction(S, self) # this will test _rmul_
     307                    _unregister_pair(x,y)
     308#                    print "got", action
     309                    return action
     310                except (NotImplementedError, TypeError, AttributeError, ValueError), ex:
     311                    pass
     312                   
     313                try:
     314#                    print "RAction"
     315                    z = x._r_action_(y)
     316                    _unregister_pair(x,y)
     317                    return RAction(self, S)
     318                except (NotImplementedError, TypeError, AttributeError, ValueError):
     319                    pass
     320                   
     321           
     322            try:
     323                # maybe there is a more clever way of detecting ZZ than importing here...
     324                from sage.rings.integer_ring import ZZ
     325                if S is ZZ and not self.has_coerce_map_from(ZZ):
     326#                    print "IntegerMulAction"
     327                    from sage.structure.coerce import IntegerMulAction
     328                    action = IntegerMulAction(S, self, not self_on_left)
     329#                    print "got", action
     330                    _unregister_pair(x,y)
     331                    return action
     332            except (NotImplementedError, TypeError, AttributeError, ValueError):
     333                pass
     334                   
     335            _unregister_pair(x,y)
     336       
     337#            print "found nothing"
     338               
     339
     340    def construction(self):
     341        """
     342        Returns a pair (functor, parent) such that functor(parent) return self.
     343        If this ring does not have a functorial construction, return None.
     344        """
     345        return None
     346
     347    #################################################################################
     348    # Coercion support functionality
     349    #################################################################################
     350   
     351    def _coerce_(self, x):            # Call this from Python (do not override!)
     352        return self._coerce_c(x)
     353   
     354    cdef _coerce_c(self, x):          # DO NOT OVERRIDE THIS (call it)
     355        try:
     356            P = x.parent()   # todo -- optimize
     357            if P is self:
     358                return x
     359        except AttributeError, msg:
     360            pass
     361        if HAS_DICTIONARY(self):
     362            return self._coerce_impl(x)
     363        else:
     364            return self._coerce_c_impl(x)
     365
     366    cdef _coerce_c_impl(self, x):     # OVERRIDE THIS FOR SAGEX CLASES
     367        """
     368        Canonically coerce x in assuming that the parent of x is not
     369        equal to self.
     370        """
     371        raise TypeError       
     372
     373    def _coerce_impl(self, x):        # OVERRIDE THIS FOR PYTHON CLASSES
     374        """
     375        Canonically coerce x in assuming that the parent of x is not
     376        equal to self.
     377        """
     378        return self._coerce_c_impl(x)
     379
     380    def _coerce_try(self, x, v):
     381        """
     382        Given a list v of rings, try to coerce x canonically into each
     383        one in turn.  Return the __call__ coercion of the result into
     384        self of the first canonical coercion that succeeds.  Raise a
     385        TypeError if none of them succeed.
     386
     387        INPUT:
     388             x -- Python object
     389             v -- parent object or list (iterator) of parent objects
     390        """
     391        if not isinstance(v, list):
     392            v = [v]
     393
     394        for R in v:
     395            try:
     396                y = R._coerce_(x)
     397                return self(y)
     398            except (TypeError, AttributeError), msg:
     399                pass
     400        raise TypeError, "no canonical coercion of element into self"
     401
     402    def _coerce_self(self, x):
     403        return self._coerce_self_c(x)
     404
     405    cdef _coerce_self_c(self, x):
     406        """
     407        Try to canonically coerce x into self.
     408        Return result on success or raise TypeError on failure.
     409        """
     410        # todo -- optimize?
     411        try:
     412            P = x.parent()
     413            if P is self:
     414                return x
     415            elif P == self:
     416                return self(x)
     417        except AttributeError:
     418            pass
     419        raise TypeError, "no canonical coercion to self defined"
     420
     421    def has_coerce_map_from(self, S):
     422        return self.has_coerce_map_from_c(S)
     423
     424    cdef has_coerce_map_from_c(self, S):
     425        """
     426        Return True if there is a natural map from S to self.
     427        Otherwise, return False.
     428        """
     429        if self == S:
     430            return True
     431        if self._has_coerce_map_from is None:
     432            self._has_coerce_map_from = {}
     433        else:
     434            try:
     435                return self._has_coerce_map_from[S]
     436            except KeyError:
     437                pass
     438        if HAS_DICTIONARY(self):
     439            x = self.has_coerce_map_from_impl(S)
     440        else:
     441            x = self.has_coerce_map_from_c_impl(S)
     442        self._has_coerce_map_from[S] = x
     443        return x
     444
     445    def has_coerce_map_from_impl(self, S):
     446        return self.has_coerce_map_from_c_impl(S)
     447
     448    cdef has_coerce_map_from_c_impl(self, S):
     449        if not PY_TYPE_CHECK(S, Parent):
     450            return False
     451        try:
     452            self._coerce_c((<Parent>S)._an_element_c())
     453        except TypeError:
     454            return False
     455        except NotImplementedError, msg:
     456            raise NotImplementedError, "%s\nAlso, please make sure you have implemented has_coerce_map_from_impl or has_coerce_map_from_c_impl (or better _an_element_c_impl or _an_element_impl if possible) for %s"%(msg,self)
     457        return True
     458
     459    def _an_element_impl(self):     # override this in Python
     460        r"""
     461        Implementation of a function that returns an element (often non-trivial)
     462        of a parent object.  Every parent object should implement it,
     463        unless the default implementation works.
     464
     465        NOTE: Parent structures that are implemented in SageX should
     466        implement \code{_an_element_c_impl} instead.
     467        """
     468        return self._an_element_c_impl()
     469
     470    cdef _an_element_c_impl(self):  # override this in SageX
     471        """
     472        Returns an element of self. Want it in sufficent generality
     473        that poorly-written functions won't work when they're not
     474        supposed to. This is cached so doesn't have to be super fast.
     475        """
     476        try:
     477            return self.gen(0)
     478        except:
     479            pass
     480           
     481        try:
     482            return self.gen()
     483        except:
     484            pass
     485           
     486        from sage.rings.infinity import infinity
     487        for x in ['_an_element_', 'pi', 1.2, 2, 1, 0, infinity]:
     488            try:
     489                return self(x)
     490            except (TypeError, NameError, NotImplementedError):
     491                pass
     492               
     493        raise NotImplementedError, "please implement _an_element_c_impl or _an_element_impl for %s"%self
     494
     495    def _an_element(self):        # do not override this (call from Python)
     496        return self._an_element_c()
     497       
     498    cdef _an_element_c(self):     # do not override this (call from SageX)
     499        if not self.__an_element is None:
     500            return self.__an_element
     501        if HAS_DICTIONARY(self):
     502            self.__an_element = self._an_element_impl()
     503        else:
     504            self.__an_element = self._an_element_c_impl()
     505        return self.__an_element
     506           
     507       
     508    ################################################
     509    # Comparison of parent objects
     510    ################################################   
     511    cdef _richcmp(left, right, int op):
     512        """
     513        Compare left and right.
     514        """
     515        cdef int r
     516
     517        if not PY_TYPE_CHECK(right, Parent) or not PY_TYPE_CHECK(left, Parent):
     518            # One is not a parent -- use arbitrary ordering
     519            if (<PyObject*>left) < (<PyObject*>right):
     520                r = -1
     521            elif (<PyObject*>left) > (<PyObject*>right):
     522                r = 1
     523            else:
     524                r = 0
     525           
     526        else:
     527            # Both are parents -- but need *not* have the same type.
     528            if HAS_DICTIONARY(left):
     529                r = left.__cmp__(right)
     530            else:
     531                r = left._cmp_c_impl(right)
     532
     533        if op == 0:  #<
     534            return PyBool_FromLong(r  < 0)
     535        elif op == 2: #==
     536            return PyBool_FromLong(r == 0)
     537        elif op == 4: #>
     538            return PyBool_FromLong(r  > 0)
     539        elif op == 1: #<=
     540            return PyBool_FromLong(r <= 0)
     541        elif op == 3: #!=
     542            return PyBool_FromLong(r != 0)
     543        elif op == 5: #>=
     544            return PyBool_FromLong(r >= 0)
     545
     546##     ####################################################################
     547##     # For a derived SageX class, you **must** put the following in
     548##     # your subclasses, in order for it to take advantage of the
     549##     # above generic comparison code.  You must also define
     550##     # _cmp_c_impl for a SageX class.
     551##     #
     552##     # For a derived Python class, simply define __cmp__.
     553##     ####################################################################
     554##     def __richcmp__(left, right, int op):
     555##         return (<Parent>left)._richcmp(right, op)
     556
     557##         # NOT NEEDED, since all attributes are public!
     558##     def __reduce__(self):
     559##         if HAS_DICTIONARY(self):
     560##             _dict = self.__dict__
     561##         else:
     562##             _dict = None
     563##         return (make_parent_v0, (self.__class__, _dict, self._has_coerce_map_from))
     564
     565    cdef int _cmp_c_impl(left, Parent right) except -2:
     566        pass
     567        # this would be nice to do, but we can't since
     568        # it leads to infinite recurssions -- and is slow -- and this
     569        # stuff must be fast!
     570        #if right.has_coerce_map_from(left):
     571        #    if left.has_coerce_map_from(right):
     572        #        return 0
     573        #    else:
     574        #        return -1
     575        if (<PyObject*>left) < (<PyObject*>right):
     576            return -1
     577        elif (<PyObject*>left) > (<PyObject*>right):
     578            return 1
     579        return 0
     580
     581##     def __cmp__(left, right):
     582##         return left._cmp_c_impl(right)   # default
     583
     584
     585    ############################################################################
     586    # Homomorphism --
     587    ############################################################################
     588    def Hom(self, codomain, cat=None):
     589        r"""
     590        self.Hom(codomain, cat=None):
     591       
     592        Return the homspace \code{Hom(self, codomain, cat)} of all
     593        homomorphisms from self to codomain in the category cat.  The
     594        default category is \code{self.category()}.
     595
     596        EXAMPLES:
     597            sage: R.<x,y> = PolynomialRing(QQ, 2)
     598            sage: R.Hom(QQ)
     599            Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Rational Field
     600
     601        Homspaces are defined for very general \sage objects, even elements of familiar rings.
     602            sage: n = 5; Hom(n,7)
     603            Set of Morphisms from 5 to 7 in Category of elements of Integer Ring
     604            sage: z=(2/3); Hom(z,8/1)
     605            Set of Morphisms from 2/3 to 8 in Category of elements of Rational Field
     606
     607        This example illustrates the optional third argument:
     608            sage: QQ.Hom(ZZ, Sets())
     609            Set of Morphisms from Rational Field to Integer Ring in Category of sets
     610        """
     611        try:
     612            return self._Hom_(codomain, cat)
     613        except (TypeError, AttributeError):
     614            pass
     615        from sage.categories.all import Hom
     616        return Hom(self, codomain, cat)
     617
     618
     619    ############################################################################
     620    # Set baseclass --
     621    ############################################################################
     622
     623
     624class Set_generic(Parent): # Cannot use Parent because Element._parent is ParentWithBase
     625    """
     626    Abstract base class for sets.
     627    """
     628    def category(self):
     629        """
     630        The category that this set belongs to, which is the category
     631        of all sets.
     632
     633        EXAMPLES:
     634            sage: Set(QQ).category()
     635            Category of sets
     636        """
     637        import sage.categories.all
     638        return sage.categories.all.Sets()
     639
     640    def object(self):
     641        return self
     642
     643
     644cdef _set_cache = {}
     645def Set_PythonType(t):
     646    """
     647    The set of all object of a given type. This is primarily used to fit
     648    types (such as int, float, list) into the coercion model (as domains
     649    and codomains must be Sage Parents).
     650   
     651    EXAMPLES:
     652        sage: from sage.structure.parent import Set_PythonType
     653        sage: Set_PythonType(int) is Set_PythonType(int)
     654        True
     655    """
     656    try:
     657        return _set_cache[t]
     658    except KeyError:
     659        _set_cache[t] = s = Set_PythonType_class(t)
     660        return s
     661
     662class Set_PythonType_class(Set_generic):
     663
     664    def __init__(self, theType):
     665        self._type = theType
     666
     667    def __call__(self, x):
     668        return self._type(x)
     669
     670    def __hash__(self):
     671        return hash(self._type)
     672       
     673    def __cmp__(self, other):
     674        if self is other:
     675            return 0
     676        if isinstance(other, Set_PythonType_class):
     677            return cmp(self._type, other._type)
     678        else:
     679            return cmp(self._type, other)
     680
     681    def __contains__(self, x):
     682        return isinstance(x, self._type)
     683
     684    def _latex_(self):
     685        return self._repr_()
     686
     687    def _repr_(self):
     688        return "Set of Python objects of %s"%(str(self._type)[1:-1])
     689
     690    def object(self):
     691        return self._type
     692
     693    def cardinality(self):
     694        if self._type is bool:
     695            return 2
     696        else:
     697            import sage.rings.infinity
     698            return sage.rings.infinity.infinity
     699
     700
     701# These functions are to guerentee that user defined _lmul_, _rmul_, _l_action_, _r_action_ do
     702# not in turn call __mul__ on their arguments, leading to an infinite loop. 
     703
     704cdef object _coerce_test_list = []
     705
     706class EltPair:
     707    def __init__(self, x, y):
     708        self.x = x
     709        self.y = y
     710    def __eq__(self, other):
     711        return type(self.x) is type(other.x) and self.x == other.x and type(self.y) is type(other.y) and self.y == other.y
     712    def __repr__(self):
     713        return "%r (%r), %r (%r)" % (self.x, type(self.x), self.y, type(self.y))
     714
     715cdef bint _register_pair(x, y) except -1:
     716    both = EltPair(x,y)
     717#    print _coerce_test_list, " + ", both
     718    if both in _coerce_test_list:
     719#        print "Uh oh..."
     720#        print _coerce_test_list
     721#        print both
     722        raise NotImplementedError, "Infinite loop in multiplication of %s (parent %s) and %s (parent %s)!" % (x, x.parent(), y, y.parent())
     723    _coerce_test_list.append(both)
     724    return 0
     725
     726cdef void _unregister_pair(x, y):
     727    try:
     728        _coerce_test_list.remove(EltPair(x,y))
     729    except (ValueError, NotImplementedError):
     730        pass
  • setup.py

    diff -r 5c038484dca0 -r 19b2ada8a983 setup.py
    a b time_series = Extension('sage.finance.ti 
    478478#####################################################
    479479
    480480ext_modules = [ \
     481
     482    Extension('sage.structure.sage_object',
     483              sources = ['sage/structure/sage_object.pyx']), \
     484
     485    Extension('sage.structure.category_object',
     486              sources = ['sage/structure/category_object.pyx']), \
     487
     488    Extension('sage.structure.parent',
     489              sources = ['sage/structure/parent.pyx']), \
     490
     491    Extension('sage.structure.parent_old',
     492              sources = ['sage/structure/parent_old.pyx']), \
     493
     494    Extension('sage.structure.parent_base',
     495              sources = ['sage/structure/parent_base.pyx']), \
     496   
     497    Extension('sage.structure.parent_gens',
     498              sources = ['sage/structure/parent_gens.pyx']), \
    481499
    482500    Extension('sage.structure.generators',
    483501              sources = ['sage/structure/generators.pyx']), \
    ext_modules = [ \ 
    671689    Extension('sage.groups.perm_gps.permgroup_element',
    672690              sources = ['sage/groups/perm_gps/permgroup_element.pyx']), \
    673691
    674     Extension('sage.structure.sage_object',
    675               sources = ['sage/structure/sage_object.pyx']), \
    676 
    677     Extension('sage.structure.parent',
    678               sources = ['sage/structure/parent.pyx']), \
    679 
    680     Extension('sage.structure.parent_base',
    681               sources = ['sage/structure/parent_base.pyx']), \
    682    
    683     Extension('sage.structure.parent_gens',
    684               sources = ['sage/structure/parent_gens.pyx']), \
    685 
    686692    Extension('sage.ext.interactive_constructors_c',
    687693              sources = ['sage/ext/interactive_constructors_c.pyx']), \
    688694
    def need_to_build(deps, f, outfile): 
    12571263    if is_newer(f, outfile):
    12581264        print '\nBuilding %s because it depends on %s.' % (outfile, f)
    12591265        return True
     1266    else:
     1267        return False
    12601268    try:
    12611269        this_deps = deps[f]
    12621270    except KeyError: