Ticket #12017: coerce_key.patch

File coerce_key.patch, 17.4 KB (added by David Roe, 11 years ago)
  • sage/categories/homset.py

    # HG changeset patch
    # User David Roe <roed@math.harvard.edu>
    # Date 1321139825 25200
    # Node ID 371c5db855123d4eff48b3f0fbfd0a9f5f899eb2
    # Parent  3490b78a3f51c5be3daf0c06563e00200ee7ab28
    [mq]: coerce_key.patch
    
    diff --git a/sage/categories/homset.py b/sage/categories/homset.py
    a b  
    300300        return "Set of Morphisms from %s to %s in %s"%(
    301301            self._domain, self._codomain, self.__category)
    302302   
    303     def __hash__(self):
     303    def _hash_(self):
    304304        """
    305305        TESTS::
    306306       
  • sage/rings/complex_double.pyx

    diff --git a/sage/rings/complex_double.pyx b/sage/rings/complex_double.pyx
    a b  
    181181    def __richcmp__(left, right, int op):
    182182        return (<Parent>left)._richcmp_helper(right, op)
    183183       
    184     cdef int _cmp_c_impl(left, Parent right) except -2:
    185         # There is only one CDF.
    186         return cmp(type(left),type(right))
    187    
    188184    def __hash__(self):
    189185        """
    190186        TEST::
     
    259255        """
    260256        return r"\Bold{C}"
    261257   
    262     def _cmp_(self, x):
     258    cpdef int _cmp_(self, Parent other) except -2:
    263259        """
    264260        EXAMPLES::
    265261       
     
    268264            sage: loads(dumps(CDF)) == CDF
    269265            True
    270266        """
    271         if PY_TYPE_CHECK(x, ComplexDoubleField_class):
    272             return 0
    273         return cmp(type(self), type(x))
     267        # type comparison is done by __cmp__ and _richcmp_helper
     268        return 0
    274269
    275270    def __call__(self, x, im=None):
    276271        """
  • sage/rings/contfrac.py

    diff --git a/sage/rings/contfrac.py b/sage/rings/contfrac.py
    a b  
    9191        ParentWithGens.__init__(self, self)
    9292        self._assign_names(('x'),normalize=False)
    9393
    94     def __cmp__(self, right):
     94    def _cmp_(self, right):
    9595        """
    9696        EXAMPLES::
    9797       
     
    102102            sage: loads(dumps(CFF)) == CFF
    103103            True
    104104        """
    105         return cmp(type(self), type(right))
     105        # A this point we're guaranteed the types are the same, and there's only one CFF.
     106        return 0
    106107
    107108    def __iter__(self):
    108109        """
  • sage/rings/finite_rings/element_ntl_gf2e.pyx

    diff --git a/sage/rings/finite_rings/element_ntl_gf2e.pyx b/sage/rings/finite_rings/element_ntl_gf2e.pyx
    a b  
    684684            False
    685685            sage: k3 = k1._finite_field_ext_pari_()
    686686            sage: k1 == k3
    687             True
     687            False
    688688        """
    689689        return (<Parent>left)._richcmp_helper(right, op)
    690690     
  • sage/rings/finite_rings/finite_field_base.pyx

    diff --git a/sage/rings/finite_rings/finite_field_base.pyx b/sage/rings/finite_rings/finite_field_base.pyx
    a b  
    229229        sib.cache(self, v, name)
    230230        return v
    231231
    232     def _cmp_(left, Parent right):
     232    cpdef int _cmp_(left, Parent right) except -2:
    233233        """
    234234        Compares this finite field with other.
    235235
     
    250250            sage: FiniteField(3**2, 'c') == FiniteField(3**2, 'd')
    251251            False
    252252        """
    253         if not PY_TYPE_CHECK(right, FiniteField):
    254             return cmp(type(left), type(right))
    255253        c = cmp(left.characteristic(), right.characteristic())
    256254        if c: return c
    257255        c = cmp(left.degree(), right.degree())
  • sage/rings/finite_rings/integer_mod_ring.py

    diff --git a/sage/rings/finite_rings/integer_mod_ring.py b/sage/rings/finite_rings/integer_mod_ring.py
    a b  
    920920        if to_ZZ is not None:
    921921            return integer_mod.Integer_to_IntegerMod(self) * to_ZZ
    922922   
    923     def __cmp__(self, other):
     923    def _cmp_(self, other):
    924924        """
    925925        EXAMPLES::
    926926       
     
    935935            sage: Z11 == Z11, Z11 == Z12, Z11 == Z13, Z11 == F
    936936            (True, False, False, False)
    937937        """
    938         if type(other) is not type(self):   # so that GF(p) =/= Z/pZ
    939             return cmp(type(self), type(other))
    940938        return cmp(self.__order, other.__order)
    941939
    942940    # The following __unit_gens functions are here since I just factored
  • sage/rings/integer_ring.pyx

    diff --git a/sage/rings/integer_ring.pyx b/sage/rings/integer_ring.pyx
    a b  
    263263    def __richcmp__(left, right, int op):
    264264        return (<Parent>left)._richcmp_helper(right, op)
    265265     
    266     def _cmp_(left, right):
    267         if isinstance(right,IntegerRing_class):
    268             return 0
    269         if isinstance(right, sage.rings.rational_field.RationalField):
    270             return -1
    271         return cmp(type(left), type(right))
     266    cpdef int _cmp_(left, Parent right):
     267        # type comparison is done in __cmp__ and _richcmp_helper
     268        return 0
    272269
    273270    def _repr_(self):
    274271        return "Integer Ring"
  • sage/rings/quotient_ring.py

    diff --git a/sage/rings/quotient_ring.py b/sage/rings/quotient_ring.py
    a b  
    618618        """
    619619        return self.cover_ring().has_coerce_map_from(R)
    620620   
    621     def __cmp__(self, other):
     621    def _cmp_(self, other):
    622622        r"""
    623623        Only quotients by the *same* ring and same ideal (with the same
    624624        generators!!) are considered equal.
     
    639639            sage: R.quotient_ring(x^2 + y^2) == R.quotient_ring(-x^2 - y^2)
    640640            False
    641641        """
    642         if not isinstance(other, QuotientRing_generic):
    643             return cmp(type(self), type(other))
    644642        return cmp((self.cover_ring(), self.defining_ideal().gens()),
    645643                   (other.cover_ring(), other.defining_ideal().gens()))
    646644
  • sage/structure/factory.pyx

    diff --git a/sage/structure/factory.pyx b/sage/structure/factory.pyx
    a b  
    11import weakref, types, copy_reg
    22
    33from sage_object cimport SageObject
     4from parent cimport Parent
    45
    56cdef sage_version
    67from sage.version import version as sage_version
     
    105106            Making object (1, 2, 4)
    106107            False
    107108        """
     109        if kwds.has_key("coerce_key"):
     110            coerce_key = kwds.pop("coerce_key")
     111        else:
     112            coerce_key = None
    108113        key, kwds = self.create_key_and_extra_args(*args, **kwds)
    109114        version = self.get_version(sage_version)
    110         return self.get_object(version, key, kwds)
     115        return self.get_object(version, key, kwds, coerce_key)
    111116       
    112     cpdef get_object(self, version, key, extra_args):
     117    cpdef get_object(self, version, key, extra_args, coerce_key=None):
    113118        """
    114119        Returns the object corresponding to key, creating it with extra_args
    115120        if necessary (for example, it isn't in the cache or it is unpickling
     
    130135            False
    131136        """
    132137        try:
    133             obj = self._cache[version, key]()
     138            if coerce_key is None:
     139                obj = self._cache[version, key]()
     140            else:
     141                obj = self._cache[version, (coerce_key, key)]()
    134142            if obj is not None:
    135143                return obj
    136144        except KeyError:
    137145            pass
    138146        obj = self.create_object(version, key, **extra_args)
    139         self._cache[version, key] = weakref.ref(obj)
     147        if coerce_key is not None:
     148            obj = coerce_key(obj) # allow the coerce_key to modify the class of the new object, for example.
     149        original_key = key
    140150        try:
    141151            other_keys = self.other_keys(key, obj)
    142152            for key in other_keys:
    143153                try:
    144                     new_obj = self._cache[version, key]()
     154                    if coerce_key is None:
     155                        new_obj = self._cache[version, key]()
     156                    else:
     157                        new_obj = self._cache[version, (coerce_key, key)]()
    145158                    if new_obj is not None:
    146159                        obj = new_obj
    147160                        break
    148161                except KeyError:
    149162                    pass
    150163            for key in other_keys:
    151                 self._cache[version, key] = weakref.ref(obj)
    152             obj._factory_data = self, version, key, extra_args
     164                if coerce_key is None:
     165                    self._cache[version, key] = weakref.ref(obj)
     166                else:
     167                    self._cache[version, (coerce_key, key)] = weakref.ref(obj)
     168            if coerce_key is None:
     169                obj._factory_data = self, version, key, extra_args
     170            else:
     171                obj._factory_data = self, version, key, extra_args, coerce_key
    153172            if obj.__class__.__reduce__.__objclass__ is object:
    154173                # replace the generic object __reduce__ to use this one
    155174                obj.__reduce_ex__ = types.MethodType(generic_factory_reduce, obj)
    156175        except AttributeError:
    157176            pass
     177        if coerce_key is None:
     178            self._cache[version, original_key] = weakref.ref(obj)
     179        else:
     180            emb = coerce_key.embedding(obj)
     181            if emb is not None:
     182                obj.register_embedding(emb)
     183            for f in coerce_key.coerce_list(obj):
     184                obj.register_coercion(f)
     185            for A in coerce_key.action_list(obj):
     186                obj.register_action(A)
     187            for f in coerce_key.convert_list(obj):
     188                obj.register_conversion(f)
     189            self._cache[version, (coerce_key, original_key)] = weakref.ref(obj)
    158190        return obj
    159191       
    160192    cpdef get_version(self, sage_version):
     
    353385        print "Making object", key
    354386        return A()
    355387
     388class CoerceKey(SageObject):
     389    def __hash__(self):
     390        raise NotImplementedError
     391    def __cmp__(self, other):
     392        raise NotImplementedError
     393
     394    def __call__(self, new_object):
     395        cdef Parent ans = <Parent?>self.modify_object(new_object)
     396        cdef int h = ans._hash_()
     397        ans._hashvalue = h + hash(self)
     398        return ans
     399
     400    def modify_object(self, new_object):
     401        return new_object
     402
     403    def coerce_list(self, new_object):
     404        return []
     405
     406    def action_list(self, new_object):
     407        return []
     408
     409    def convert_list(self, new_object):
     410        return []
     411
     412    def embedding(self, new_object):
     413        return None
    356414test_factory = UniqueFactoryTester('sage.structure.factory.test_factory')
  • sage/structure/parent.pxd

    diff --git a/sage/structure/parent.pxd b/sage/structure/parent.pxd
    a b  
    2121    cdef public _initial_action_list
    2222    cdef public _initial_convert_list
    2323    cdef readonly bint _coercions_used
     24
     25    cdef readonly _hashvalue
    2426   
    2527    cpdef register_coercion(self, mor)
    2628    cpdef register_action(self, action)
     
    2830    cpdef register_embedding(self, embedding)
    2931
    3032    cpdef bint _richcmp_helper(left, right, int op) except -2
     33    cpdef int _cmp_(left, Parent right) except -2
     34    cpdef bint _allow_equal_to_other_type(self)
     35
    3136    cpdef bint is_exact(self) except -2
    3237
    3338    # Called from the __init__ method to set up coercion.
  • sage/structure/parent.pyx

    diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
    a b  
    12361236            sage: ZZ < QQ
    12371237            True
    12381238        """
    1239         cdef int r
    1240 
    1241         if not PY_TYPE_CHECK(right, Parent) or not PY_TYPE_CHECK(left, Parent):
    1242             # One is not a parent -- use arbitrary ordering
    1243             if (<PyObject*>left) < (<PyObject*>right):
    1244                 r = -1
    1245             elif (<PyObject*>left) > (<PyObject*>right):
    1246                 r = 1
    1247             else:
    1248                 r = 0
    1249            
    1250         else:
    1251             # Both are parents -- but need *not* have the same type.
     1239        print "helPing!"
     1240        cdef bint left_has_coerce_key, right_has_coerce_key
     1241        cdef int r = cmp(type(left), type(right))
     1242        if (r == 0 and left is not right) or left._allow_equal_to_other_type():
     1243            print "equal types"
    12521244            if HAS_DICTIONARY(left):
     1245                print "dictionary found!"
    12531246                r = left.__cmp__(right)
    12541247            else:
    1255                 r = left._cmp_(right)
    1256 
     1248                print "no dictionary found.  :-("
     1249                r = (<Parent>left)._cmp_(<Parent>right)
     1250            if r == 0:
     1251                left_has_coerce_key = hasattr(left, "_factory_data") and PY_TYPE_CHECK(left._factory_data, tuple) and len(left._factory_data) == 5
     1252                right_has_coerce_key = hasattr(right, "_factory_data") and PY_TYPE_CHECK(left._factory_data, tuple) and len(right._factory_data) == 5
     1253                if left_has_coerce_key:
     1254                    if right_has_coerce_key:
     1255                        r = cmp(left._factory_data[4], right._factory_data[4])
     1256                    else:
     1257                        r = -1
     1258                elif right_has_coerce_key:
     1259                    r = 1
    12571260        if op == 0:  #<
    12581261            return r  < 0
    12591262        elif op == 2: #==
     
    12671270        elif op == 5: #>=
    12681271            return r >= 0
    12691272
     1273    def __cmp__(left, right):
     1274        cdef int r = cmp(type(left), type(right))
     1275        if r != 0 and not left._allow_equal_to_other_type(): return r
     1276        r = (<Parent>left)._cmp_(<Parent>right)
     1277        if r != 0 or left is right: return r
     1278        cdef bint left_has_coerce_key, right_has_coerce_key
     1279        left_has_coerce_key = hasattr(left, "_factory_data") and PY_TYPE_CHECK(left._factory_data, tuple) and len(left._factory_data) == 5
     1280        right_has_coerce_key = hasattr(right, "_factory_data") and PY_TYPE_CHECK(left._factory_data, tuple) and len(right._factory_data) == 5
     1281        if left_has_coerce_key:
     1282            if right_has_coerce_key:
     1283                return cmp(left._factory_data[4], right._factory_data[4])
     1284            else:
     1285                return -1
     1286        elif right_has_coerce_key:
     1287            return 1
     1288        else:
     1289            return 0
     1290
     1291    cpdef bint _allow_equal_to_other_type(self):
     1292        return False
     1293
     1294    cpdef int _cmp_(left, Parent right) except -2:
     1295        """
     1296        """
     1297        cdef int r = left.__hash__() - right.__hash__()
     1298        if r != 0: return r
     1299        if (<PyObject*>left) < (<PyObject*>right):
     1300            return -1
     1301        elif (<PyObject*>left) > (<PyObject*>right):
     1302            return 1
     1303        else:
     1304            return 0
     1305
     1306    def __hash__(self):
     1307        if self._hashvalue is not None:
     1308            return self._hashvalue
     1309        self._hashvalue = self._hash_()
     1310        return self._hashvalue
     1311
     1312    def _hash_(self):
     1313        return id(self)
     1314
     1315    def __richcmp__(left, right, int op):
     1316        return (<Parent>left)._richcmp_helper(right, op)
     1317
    12701318    # Should be moved and merged into the EnumeratedSets() category
    12711319    def __len__(self):
    12721320        """
     
    16711719            sage: G((1, 2)) * t
    16721720            2*x + y + 3*z
    16731721        """
    1674         assert not self._coercions_used, "coercions must all be registered up before use"
    16751722        from sage.categories.action import Action
    16761723        if isinstance(action, Action):
    16771724            if action.actor() is self:
     1725                assert not (self._coercions_used and (action.domain(), action.operation(), action.is_left()) in self._action_hash), "coercions must all be registered up before use"
    16781726                self._action_list.append(action)
    16791727                self._action_hash[action.domain(), action.operation(), action.is_left()] = action
    16801728            elif action.domain() is self:
     1729                assert not (self._coercions_used and (action.actor(), action.operation(), not action.is_left()) in self._action_hash), "coercions must all be registered up before use"
    16811730                self._action_list.append(action)
    16821731                self._action_hash[action.actor(), action.operation(), not action.is_left()] = action
    16831732            else:
     
    17051754            ...
    17061755            TypeError: ...
    17071756        """
    1708         assert not self._coercions_used, "coercions must all be registered up before use"
    17091757        if isinstance(mor, map.Map):
     1758            assert not (self._coercions_used and mor.domain() in self._convert_from_hash), "coercions must all be registered up before use"
    17101759            if mor.codomain() is not self:
    17111760                raise ValueError, "Map's codomain must be self"
    17121761            self._convert_from_list.append(mor)
    17131762            self._convert_from_hash[mor.domain()] = mor
    17141763        elif PY_TYPE_CHECK(mor, Parent) or PY_TYPE_CHECK(mor, type):
     1764            assert not (self._coercions_used and mor in self._convert_from_hash), "coercions must all be registered up before use"
    17151765            t = mor
    17161766            mor = self._generic_convert_map(mor)
    17171767            self._convert_from_list.append(mor)
     
    26142664        """
    26152665        return -hash(self._type)
    26162666       
    2617     cpdef int _cmp_(self, other) except -100:
     2667    cpdef bint _allow_equal_to_other_type(self):
     2668        return True
     2669
     2670    cpdef int _cmp_(left, Parent right) except -2:
    26182671        """
    26192672        Two Python type sets are considered the same if they contain the same
    26202673        type.
     
    26272680            sage: S == sage.structure.parent.Set_PythonType(float)
    26282681            False
    26292682        """
    2630         if self is other:
     2683        if left is right:
    26312684            return 0
    2632         if isinstance(other, Set_PythonType_class):
    2633             return cmp(self._type, other._type)
     2685        if isinstance(right, Set_PythonType_class):
     2686            return cmp(left._type, right._type)
    26342687        else:
    2635             return cmp(self._type, other)
     2688            return cmp(left._type, right)
    26362689           
    26372690    def __contains__(self, x):
    26382691        """