Ticket #11935: trac11935_weak_pickling_by_construction-nt.patch

File trac11935_weak_pickling_by_construction-nt.patch, 38.1 KB (added by nthiery, 6 years ago)
  • sage/categories/bimodules.py

    # HG changeset patch
    # User Simon King <simon.king@uni-jena.de>
    # Date 1318941258 -7200
    # Node ID 0e23d0ca3d0bb47caa234d9d1890f7c603f3ddbd
    # Parent  f5ad6657cff1a065b4192e84a96fca0bc597c2c7
    #11935: Make parent/element classes independent of base rings
    
    diff --git a/sage/categories/bimodules.py b/sage/categories/bimodules.py
    a b Bimodules 
    1111#                  http://www.gnu.org/licenses/
    1212#******************************************************************************
    1313
    14 from sage.categories.category import Category
    15 from sage.misc.cachefunc import cached_method
     14from sage.misc.unknown import Unknown
     15from sage.categories.category import Category, CategoryWithParameters
    1616from sage.categories.left_modules import LeftModules
    1717from sage.categories.right_modules import RightModules
    1818
    from sage.categories.rings import Rings 
    2020_Rings = Rings()
    2121
    2222#?class Bimodules(Category_over_base_rng, Category_over_base_rng):
    23 class Bimodules(Category):
     23class Bimodules(CategoryWithParameters):
    2424    """
    2525    The category of `(R,S)`-bimodules
    2626
    class Bimodules(Category): 
    4949        self._left_base_ring = left_base
    5050        self._right_base_ring = right_base
    5151
     52    def _make_named_class_key(self, name):
     53        r"""
     54        Return what the element/parent/... classes depend on.
     55
     56        Since :trac:`11935`, the element and parent classes of a
     57        bimodule only depend on the categories of the left and right
     58        base ring.
     59
     60        .. SEEALSO::
     61
     62            - :meth:`CategoryWithParameters`
     63            - :meth:`CategoryWithParameters._make_named_class_key`
     64
     65        EXAMPLES::
     66
     67            sage: Bimodules(QQ,ZZ)._make_named_class_key('parent_class')
     68            (Category of quotient fields, Category of euclidean domains)
     69        """
     70        return (self._left_base_ring.category(), self._right_base_ring.category())
     71
    5272    @classmethod
    5373    def an_instance(cls):
    5474        """
  • sage/categories/category.py

    diff --git a/sage/categories/category.py b/sage/categories/category.py
    a b A parent ``P`` is in a category ``C`` if 
    9595#                  http://www.gnu.org/licenses/
    9696#*****************************************************************************
    9797
     98import inspect
    9899from sage.misc.abstract_method import abstract_method, abstract_methods_of_class
    99100from sage.misc.lazy_attribute import lazy_attribute
    100101from sage.misc.cachefunc import cached_method, cached_function
    from sage.misc.unknown import Unknown 
    104105
    105106from sage.structure.sage_object import SageObject
    106107from sage.structure.unique_representation import UniqueRepresentation
    107 from sage.structure.dynamic_class import dynamic_class_internal
     108from sage.structure.dynamic_class import dynamic_class
    108109
    109110from weakref import WeakValueDictionary
    110111_join_cache = WeakValueDictionary()
    class Category(UniqueRepresentation, Sag 
    345346    same super_categories. For example, Algebras(QQ) has
    346347    VectorSpaces(QQ) as super category, whereas Algebras(ZZ) only has
    347348    Modules(ZZ) as super category. In particular, the constructed
    348     parent_class and element_class will differ (inheriting, or not,
    349     methods specific for vector spaces). On the other hand, caching
    350     ensures that two identical hierarchy of classes are built only
    351     once::
     349    parent class and element class will differ (inheriting, or not,
     350    methods specific for vector spaces)::
    352351
    353         # TODO: redo the same with Algebras
    354         # and show the mro for Algebras(QQ) w.r.t Algebras(ZZ)
    355         # 2009/03/11: this feature is temporarily broken, due to the current work around for pickling
    356         sage: Coalgebras(QQ).parent_class is Coalgebras(FractionField(QQ[x])).parent_class # todo: not implemented
     352        sage: Algebras(QQ).parent_class is Algebras(ZZ).parent_class
     353        False
     354        sage: issubclass(Algebras(QQ).parent_class, VectorSpaces(QQ).parent_class)
     355        True
     356
     357    On the other hand, identical hierarchies of classes are,
     358    preferably, built only once (e.g. for categories over a base ring)::
     359
     360        sage: Algebras(GF(5)).parent_class is Algebras(GF(7)).parent_class
     361        True
     362        sage: Coalgebras(QQ).parent_class is Coalgebras(FractionField(QQ[x])).parent_class
    357363        True
    358364
    359365    We now construct a parent in the usual way::
    class Category(UniqueRepresentation, Sag 
    430436
    431437        INPUT:
    432438
    433         - s -- A string giving the name of this category.  If None,
    434           the name is determined from the name of the class.
     439        - ``s`` -- A string giving the name of this category.
     440          If None, the name is determined from the name of the class.
    435441
    436442        EXAMPLES::
    437443
    class Category(UniqueRepresentation, Sag 
    645651        ``self``; this is the first test that is done in
    646652        :meth:`is_subcategory`.
    647653
    648         This default implementation tests whether the parent class
    649         of ``category`` is a subclass of the parent class of ``self``.
    650         Currently (as of trac ticket #11900) this is a complete
    651         subcategory test. But this will change with trac ticket #11935.
     654        This default implementation tests whether the parent class of
     655        ``category`` is a subclass of the parent class of ``self``.
     656        This is most of the time a complete subcategory test.
     657
     658        .. warning::
     659
     660            This test is incomplete for categories in
     661            :class:`CategoryWithParameters`, as introduced by
     662            :trac:`11935`. This method is therefore overwritten by
     663            :meth:`~sage.categories.category.CategoryWithParameters._subcategory_hook_`.
    652664
    653665        EXAMPLE::
    654666
    class Category(UniqueRepresentation, Sag 
    10201032        """
    10211033        pass
    10221034
     1035    def _make_named_class(self, name, method_provider, cache=False, picklable=True):
     1036        """
     1037        Construction of the parent/element/... class of self.
     1038
     1039        INPUT:
     1040
     1041        - ``name`` -- a string; the name of the class as an attribute of ``self``.
     1042          E.g. "parent_class"
     1043        - ``method_provider`` -- a string; the name of an attribute of
     1044          ``self`` that provides methods for the new class (in
     1045          addition to those coming from the super categories).
     1046          E.g. "ParentMethods"
     1047        - ``cache`` -- a boolean or ``ignore_reduction`` (default: False)
     1048          (passed down to dynamic_class; for internal use only)
     1049        - ``picklable`` -- a boolean (default: True)
     1050
     1051        ASSUMPTION:
     1052
     1053        It is assumed that this method is only called from a lazy
     1054        attribute whose name coincides with the given ``name``
     1055
     1056        OUTPUT:
     1057
     1058        A dynamic class with bases given by the corresponding named
     1059        classes of ``self``'s super_categories and methods taken from
     1060        the class ``getattr(self,method_provider)``.
     1061
     1062        .. NOTE::
     1063
     1064            In this default implementation, the reduction data of the
     1065            named class makes it depend on ``self``. Since the result
     1066            is going to be stored in a lazy attribute of ``self``
     1067            anyway, we may as well disable the caching in
     1068            ``dynamic_class`` (hence the default value ``cache=False``).
     1069
     1070            :class:`CategoryWithParameters` overrides this method so
     1071            that the same parent/element/... classes can be shared
     1072            between closely related categories.
     1073
     1074        .. SEEALSO:: :meth:`CategoryWithParameters._make_named_class`
     1075
     1076        EXAMPLES::
     1077
     1078            sage: PC = Rings()._make_named_class("parent_class", "ParentMethods"); PC
     1079            <class 'sage.categories.rings.Rings.parent_class'>
     1080            sage: type(PC)
     1081            <class 'sage.structure.dynamic_class.DynamicMetaclass'>
     1082            sage: PC.__bases__
     1083            (<class 'sage.categories.rngs.Rngs.parent_class'>, <class 'sage.categories.semirings.Semirings.parent_class'>)
     1084
     1085        Note that, by default, the result is not cached::
     1086
     1087            sage: PC is Rings()._make_named_class("parent_class", "ParentMethods")
     1088            False
     1089
     1090        Indeed this method is only meant to construct lazy attributes
     1091        like ``parent_class`` which already handle this caching::
     1092
     1093            sage: Rings().parent_class
     1094            <class 'sage.categories.rings.Rings.parent_class'>
     1095
     1096        Reduction for pickling also assumes the existence of this lazy
     1097        attribute::
     1098
     1099            sage: PC._reduction
     1100            (<built-in function getattr>, (Category of rings, 'parent_class'))
     1101            sage: loads(dumps(PC)) is Rings().parent_class
     1102            True
     1103
     1104        TESTS::
     1105
     1106            sage: class A: pass
     1107            sage: class BrokenCategory(Category):
     1108            ...       def super_categories(self): return []
     1109            ...       ParentMethods = 1
     1110            ...       class ElementMethods(A):
     1111            ...           pass
     1112            ...       class MorphismMethods(object):
     1113            ...           pass
     1114            sage: C = BrokenCategory()
     1115            sage: C._make_named_class("parent_class",   "ParentMethods")
     1116            Traceback (most recent call last):
     1117            ...
     1118            AssertionError: BrokenCategory.ParentMethods should be a class
     1119            sage: C._make_named_class("element_class",  "ElementMethods")
     1120            doctest:...: UserWarning: BrokenCategory.ElementMethods should not have a super class
     1121            <class '__main__.BrokenCategory.element_class'>
     1122            sage: C._make_named_class("morphism_class", "MorphismMethods")
     1123            <class '__main__.BrokenCategory.morphism_class'>
     1124        """
     1125        cls = self.__class__
     1126        class_name = "%s.%s"%(cls.__name__, name)
     1127        method_provider_cls = getattr(self, method_provider, None)
     1128        if method_provider_cls is None:
     1129            # If the category provides no XXXMethods class,
     1130            # point to the documentation of the category itself
     1131            doccls = cls
     1132        else:
     1133            # Otherwise, check XXXMethods
     1134            assert inspect.isclass(method_provider_cls),\
     1135                "%s.%s should be a class"%(cls.__name__, method_provider)
     1136            mro = inspect.getmro(method_provider_cls)
     1137            if len(mro) > 2 or (len(mro) == 2 and mro[1] is not object):
     1138                from warnings import warn
     1139                warn("%s.%s should not have a super class"%(cls.__name__, method_provider))
     1140            # and point the documentation to it
     1141            doccls = method_provider_cls
     1142        if picklable:
     1143            reduction = (getattr, (self, name))
     1144        else:
     1145            reduction = None
     1146        return dynamic_class(class_name,
     1147                             tuple(getattr(cat,name) for cat in self._super_categories),
     1148                             method_provider_cls, prepend_cls_bases = False, doccls = doccls,
     1149                             reduction = reduction, cache = cache)
     1150
     1151
    10231152    @lazy_attribute
    10241153    def parent_class(self):
    10251154        """
    class Category(UniqueRepresentation, Sag 
    10311160            <class 'sage.categories.algebras.Algebras.parent_class'>
    10321161            sage: type(C)
    10331162            <class 'sage.structure.dynamic_class.DynamicMetaclass'>
     1163
     1164        By :trac:`11935`, some categories share their parent
     1165        classes. For example, the parent class of an algebra only
     1166        depends on the category of the base ring. A typical example is
     1167        the category of algebras over a finite field versus algebras
     1168        over a non-field::
     1169
     1170            sage: Algebras(GF(7)).parent_class is Algebras(GF(5)).parent_class
     1171            True
     1172            sage: Algebras(QQ).parent_class is Algebras(ZZ).parent_class
     1173            False
     1174            sage: Algebras(ZZ['t']).parent_class is Algebras(ZZ['t','x']).parent_class
     1175            True
     1176
     1177        See :class:`CategoryWithParameters` for an abstract base class for
     1178        categories that depend on parameters, even though the parent
     1179        and element classes only depend on the parent or element
     1180        classes of its super categories. It is used in
     1181        :class:`~sage.categories.bimodules.Bimodules`,
     1182        :class:`~sage.categories.category_types.Category_over_base` and
     1183        :class:`sage.categories.category.JoinCategory`.
    10341184        """
    1035         # Remark:
    1036         # For now, we directly call the underlying function, avoiding the overhead
    1037         # of using a cached function. The rationale: When this lazy method is called
    1038         # then we can be sure that the parent class had not been constructed before.
    1039         # The parent and element classes belong to a category, and they are pickled
    1040         # as such. Hence, they are rightfully cached as an attribute of a category.
    1041         #
    1042         # However, we should try to "unify" parent classes. They should depend on the
    1043         # super categories, but not on the base (except when the super categories depend
    1044         # on the base). When that is done, calling the cached function will be needed again.
    1045         #return dynamic_class("%s.parent_class"%self.__class__.__name__,
    1046         #                     tuple(cat.parent_class for cat in self.super_categories),
    1047         #                     self.ParentMethods,
    1048         #                     reduction = (getattr, (self, "parent_class")))
    1049         return dynamic_class_internal.f("%s.parent_class"%self.__class__.__name__,
    1050                              tuple(cat.parent_class for cat in self._super_categories),
    1051                              self.ParentMethods,
    1052                              reduction = (getattr, (self, "parent_class")))
     1185        return self._make_named_class('parent_class', 'ParentMethods')
    10531186
    10541187    @lazy_attribute
    10551188    def element_class(self):
    class Category(UniqueRepresentation, Sag 
    10621195            <class 'sage.categories.algebras.Algebras.element_class'>
    10631196            sage: type(C)
    10641197            <class 'sage.structure.dynamic_class.DynamicMetaclass'>
     1198
     1199        By :trac:`11935`, some categories share their element
     1200        classes. For example, the element class of an algebra only
     1201        depends on the category of the base. A typical example is the
     1202        category of algebras over a field versus algebras over a
     1203        non-field::
     1204
     1205            sage: Algebras(GF(5)).element_class is Algebras(GF(3)).element_class
     1206            True
     1207            sage: Algebras(QQ).element_class is Algebras(ZZ).element_class
     1208            False
     1209            sage: Algebras(ZZ['t']).element_class is Algebras(ZZ['t','x']).element_class
     1210            True
     1211
     1212        .. SEEALSO:: :meth:`parent_class`
    10651213        """
    1066         # Remark:
    1067         # For now, we directly call the underlying function, avoiding the overhead
    1068         # of using a cached function. The rationale: When this lazy method is called
    1069         # then we can be sure that the element class had not been constructed before.
    1070         # The parent and element classes belong to a category, and they are pickled
    1071         # as such. Hence, they are rightfully cached as an attribute of a category.
    1072         #
    1073         # However, we should try to "unify" element classes. They should depend on the
    1074         # super categories, but not on the base (except when the super categories depend
    1075         # on the base). When that is done, calling the cached function will be needed again.
    1076         #return dynamic_class("%s.element_class"%self.__class__.__name__,
    1077         #                     (cat.element_class for cat in self.super_categories),
    1078         #                     self.ElementMethods,
    1079         #                     reduction = (getattr, (self, "element_class"))
    1080         #                     )
    1081         return dynamic_class_internal.f("%s.element_class"%self.__class__.__name__,
    1082                              tuple(cat.element_class for cat in self._super_categories),
    1083                              self.ElementMethods,
    1084                              reduction = (getattr, (self, "element_class")))
     1214        return self._make_named_class('element_class', 'ElementMethods')
    10851215
    10861216    def required_methods(self):
    10871217        """
    class HomCategory(Category): 
    16111741        return []
    16121742
    16131743
     1744##############################################################################
     1745# Parametrized categories whose parent/element class depend only on
     1746# the super categories
     1747##############################################################################
     1748
     1749class CategoryWithParameters(Category):
     1750    """
     1751    A parametrized category whose parent/element classes depend only on its super categories
     1752
     1753    Many categories in Sage are parametrized, like ``C=Algebras(K)``
     1754    which takes a base ring as parameter. In many cases, however, the
     1755    operations provided by ``C`` in the parent class and element class
     1756    depend only on the super categories of ``C``. For example, the
     1757    vector space operations are provided if and only if ``K`` is a
     1758    field, since ``VectorSpaces(K)`` is a super category of ``C`` only
     1759    in that case. In such cases, and as an optimization (see :trac:`11935`),
     1760    we want to use the same parent and element class for all fields.
     1761    This is the purpose of this abstract class.
     1762
     1763    Currently, :class:`~sage.categories.category.JoinCategory`,
     1764    :class:`~sage.categories.category_types.Category_over_base` and
     1765    :class:`~sage.categories.bimodules.Bimodules` inherit from this
     1766    class.
     1767
     1768    EXAMPLES::
     1769
     1770        sage: C1 = Algebras(GF(5))
     1771        sage: C2 = Algebras(GF(3))
     1772        sage: C3 = Algebras(ZZ)
     1773        sage: from sage.categories.category import CategoryWithParameters
     1774        sage: isinstance(C1, CategoryWithParameters)
     1775        True
     1776        sage: C1.parent_class is C2.parent_class
     1777        True
     1778        sage: C1.parent_class is C3.parent_class
     1779        False
     1780
     1781    """
     1782    def _make_named_class(self, name, method_provider, cache = False, **options):
     1783        """
     1784        Return the parent/element/... class of ``self``.
     1785
     1786        INPUT:
     1787
     1788        - ``name`` -- a string; the name of the class as an attribute of ``self``
     1789        - ``method_provider`` -- a string; the name of an attribute of
     1790          ``self`` that provides methods for the new class (in
     1791          addition to what comes from the super categories).
     1792
     1793        ASSUMPTION:
     1794
     1795        It is assumed that this method is only called from a lazy
     1796        attribute whose name coincides with the given ``name``
     1797
     1798        OUTPUT:
     1799
     1800        A dynamic class that has the corresponding named classes of
     1801        the super categories of ``self`` as bases and contains the
     1802        methods provided by ``getattr(self,method_provider)``.
     1803
     1804        .. NOTE::
     1805
     1806            This method overrides :meth:`Category._make_named_class`
     1807            so that the returned class *only* depends on the
     1808            corresponding named classes of the super categories and on
     1809            the provided methods. This allows for sharing the named
     1810            classes across closely related categories providing the
     1811            same code to their parents, elements and so on.
     1812
     1813        EXAMPLES::
     1814
     1815        The categories of bimodules over the fields ``CC`` or ``QQ``
     1816        provide the same methods to their parents and elements::
     1817
     1818            sage: Bimodules(ZZ,RR).parent_class is Bimodules(ZZ,RDF).parent_class #indirect doctest
     1819            True
     1820            sage: Bimodules(CC,ZZ).element_class is Bimodules(RR,ZZ).element_class
     1821            True
     1822
     1823        On the other hand, modules over a field have more methods than
     1824        modules over a ring::
     1825
     1826            sage: Modules(GF(3)).parent_class is Modules(ZZ).parent_class
     1827            False
     1828            sage: Modules(GF(3)).element_class is Modules(ZZ).element_class
     1829            False
     1830
     1831        One could possibly share those classes, but this is not
     1832        currently the case::
     1833
     1834            sage: Modules(GF(3)).parent_class is Modules(GF(2^3,'x')).parent_class
     1835            False
     1836
     1837        This is because those two fields do not have the exact same category::
     1838
     1839            sage: GF(3).category()
     1840            Join of Category of subquotients of monoids and Category of quotients of semigroups and Category of finite fields
     1841            sage: GF(2^3,'x').category()
     1842            Category of finite fields
     1843
     1844        Some other cases where one could potentially share those classes::
     1845
     1846            sage: Modules(GF(3),dispatch=False).parent_class  is Modules(ZZ).parent_class
     1847            False
     1848            sage: Modules(GF(3),dispatch=False).element_class is Modules(ZZ).element_class
     1849            False
     1850
     1851        TESTS::
     1852
     1853            sage: PC = Algebras(QQ).parent_class; PC   # indirect doctest
     1854            <class 'sage.categories.algebras.Algebras.parent_class'>
     1855            sage: type(PC)
     1856            <class 'sage.structure.dynamic_class.DynamicMetaclass'>
     1857            sage: PC.__bases__
     1858            (<class 'sage.categories.rings.Rings.parent_class'>,
     1859             <class 'sage.categories.vector_spaces.VectorSpaces.parent_class'>)
     1860            sage: loads(dumps(PC)) is PC
     1861            True
     1862        """
     1863        cls = self.__class__
     1864        key = (cls, name, self._make_named_class_key(name))
     1865        try:
     1866            return self._make_named_class_cache[key]
     1867        except KeyError:
     1868            pass
     1869        result = Category._make_named_class(self, name, method_provider,
     1870                                            cache=cache, **options)
     1871        self._make_named_class_cache[key] = result
     1872        return result
     1873
     1874
     1875    @abstract_method
     1876    def _make_named_class_key(self, name):
     1877        r"""
     1878        Return what the element/parent/... class depend on.
     1879
     1880        INPUT:
     1881
     1882        - ``name`` -- a string; the name of the class as an attribute of ``self``
     1883
     1884        .. SEEALSO::
     1885
     1886            - :meth:`_make_named_class`
     1887            - :meth:`sage.categories.category_types.Category_over_base._make_named_class_key`
     1888            - :meth:`sage.categories.bimodules.Bimodules._make_named_class_key`
     1889            - :meth:`JoinCategory._make_named_class_key`
     1890
     1891        EXAMPLES:
     1892
     1893        The parent class of an algebra depends only on the category of the base ring::
     1894
     1895            sage: Algebras(ZZ)._make_named_class_key("parent_class")
     1896            Category of euclidean domains
     1897
     1898        The morphism class of a bimodule depends only on the category
     1899        of the left and right base rings::
     1900
     1901            sage: Bimodules(QQ, ZZ)._make_named_class_key("morphism_class")
     1902            (Category of quotient fields, Category of euclidean domains)
     1903
     1904        The element class of a join category depends only on the
     1905        element class of its super categories::
     1906
     1907            sage: Category.join([Groups(), Posets()])._make_named_class_key("element_class")
     1908            (<class 'sage.categories.groups.Groups.element_class'>,
     1909             <class 'sage.categories.posets.Posets.element_class'>)
     1910        """
     1911
     1912    _make_named_class_cache = dict()
     1913
     1914    def _subcategory_hook_(self, C):
     1915        """
     1916        A quick but partial test whether ``C`` is a subcategory of ``self``
     1917
     1918        INPUT:
     1919
     1920        - ``C`` -- a category
     1921
     1922        OUTPUT:
     1923
     1924        - ``False``, if ``C.parent_class`` is not a subclass of
     1925          ``self.parent_class``, and :obj:`~sage.misc.unknown.Unknown`
     1926          otherwise.
     1927
     1928        EXAMPLES::
     1929
     1930            sage: Bimodules(QQ,QQ)._subcategory_hook_(Modules(QQ))
     1931            Unknown
     1932            sage: Bimodules(QQ,QQ)._subcategory_hook_(Rings())
     1933            False
     1934        """
     1935        if not issubclass(C.parent_class, self.parent_class):
     1936            return False
     1937        return Unknown
     1938
     1939
    16141940#############################################################
    16151941# Join of several categories
    16161942#############################################################
    16171943
    1618 class JoinCategory(Category):
     1944class JoinCategory(CategoryWithParameters):
    16191945    """
    16201946    A class for joins of several categories. Do not use directly;
    16211947    see Category.join instead.
    class JoinCategory(Category): 
    16291955        [Category of groups, Category of commutative additive monoids]
    16301956        sage: J.all_super_categories(proper=True)
    16311957        [Category of groups, Category of monoids, Category of semigroups, Category of magmas, Category of commutative additive monoids, Category of commutative additive semigroups, Category of additive magmas, Category of sets, Category of sets with partial maps, Category of objects]
     1958
     1959    By :trac:`11935`, join categories and categories over base
     1960    rings inherit from :class:`CategoryWithParameters`. This allows
     1961    for sharing parent and element classes between similar
     1962    categories. For example, since polynomial rings belong to a join
     1963    category and since the underlying implementation is the same for
     1964    all finite fields, we have::
     1965
     1966        sage: GF(3)['x'].category()
     1967        Join of Category of euclidean domains and Category of commutative algebras over Finite Field of size 3
     1968        sage: type(GF(3)['x']) is type(GF(5)['z'])
     1969        True
     1970
    16321971    """
    16331972
    16341973    def __init__(self, super_categories, **kwds):
    class JoinCategory(Category): 
    16591998            Category.__init__(self)
    16601999        self._super_categories = list(super_categories)
    16612000
     2001    def _make_named_class_key(self, name):
     2002        r"""
     2003        Return what the element/parent/... classes depend on.
     2004
     2005        Since :trac:`11935`, the element/parent classes of a join
     2006        category over base only depend on the element/parent class of
     2007        its super categories
     2008
     2009        .. SEEALSO::
     2010
     2011            - :meth:`CategoryWithParameters`
     2012            - :meth:`CategoryWithParameters._make_named_class_key`
     2013
     2014        EXAMPLES::
     2015
     2016            sage: Modules(ZZ)._make_named_class_key('element_class')
     2017            Category of euclidean domains
     2018            sage: Modules(QQ)._make_named_class_key('parent_class')
     2019            Category of quotient fields
     2020            sage: Schemes(Spec(ZZ))._make_named_class_key('parent_class')
     2021            Category of Schemes
     2022            sage: ModularAbelianVarieties(QQ)._make_named_class_key('parent_class')
     2023            Category of quotient fields
     2024        """
     2025        return tuple(getattr(cat, name) for cat in self._super_categories)
     2026
    16622027    def super_categories(self):
    16632028        """
    16642029        Returns the immediate super categories, as per :meth:`Category.super_categories`.
    class JoinCategory(Category): 
    16922057        """
    16932058        return all(category.is_subcategory(X) for X in self._super_categories)
    16942059
     2060    def is_subcategory(self, C):
     2061        """
     2062        Tell whether this join category is subcategory of another category `C`.
     2063
     2064        EXAMPLES::
     2065
     2066            sage: Category.join([Rings(),Modules(QQ)]).is_subcategory(Category.join([Rngs(),Bimodules(QQ,QQ)]))
     2067            True
     2068
     2069        """
     2070        if C is self:
     2071            return True
     2072        hook = C._subcategory_hook_(self)
     2073        if hook is Unknown:
     2074            return any(X.is_subcategory(C) for X in self._super_categories)
     2075        return hook
     2076
    16952077    def _repr_(self):
    16962078        """
    16972079        Print representation.
  • sage/categories/category_types.py

    diff --git a/sage/categories/category_types.py b/sage/categories/category_types.py
    a b This is placed in a separate file from c 
    1515#*****************************************************************************
    1616
    1717from sage.misc.latex import latex
    18 from category import Category
     18from sage.misc.unknown import Unknown
     19from category import Category, CategoryWithParameters
    1920from objects import Objects
    2021
    2122####################################################################
    class Sequences(Category): 
    197198#############################################################
    198199# Category of objects over some base object
    199200#############################################################
    200 class Category_over_base(Category):
     201class Category_over_base(CategoryWithParameters):
    201202    def __init__(self, base, name=None):
    202203        Category.__init__(self, name)
    203204        self.__base = base
    204205
     206    def _make_named_class_key(self, name):
     207        r"""
     208        Return what the element/parent/... classes depend on.
     209
     210        Since :trac:`11935`, the element and parent classes of a
     211        category over base only depend on the categories of the base
     212        ring.
     213
     214        .. SEEALSO::
     215
     216            - :meth:`CategoryWithParameters`
     217            - :meth:`CategoryWithParameters._make_named_class_key`
     218
     219        EXAMPLES::
     220
     221            sage: Modules(ZZ)._make_named_class_key('element_class')
     222            Category of euclidean domains
     223            sage: Modules(QQ)._make_named_class_key('parent_class')
     224            Category of quotient fields
     225            sage: Schemes(Spec(ZZ))._make_named_class_key('parent_class')
     226            Category of Schemes
     227            sage: ModularAbelianVarieties(QQ)._make_named_class_key('parent_class')
     228            Category of quotient fields
     229        """
     230        return self.__base.category()
     231
    205232    @classmethod
    206233    def an_instance(cls):
    207234        """
    class Category_over_base(Category): 
    234261        """
    235262        return "\\mathbf{%s}_{%s}"%(self._label, latex(self.__base))
    236263
     264    def _subcategory_hook_(self, C):
     265        """
     266        A quick test whether a category `C` may be subcategory of this category.
     267
     268        INPUT:
     269
     270        - `C` `` a category (type not tested)
     271
     272        OUTPUT:
     273
     274        a boolean if it is certain that `C` is (or is not) a
     275        subcategory of self. :obj:`~sage.misc.unknown.Unknown`
     276        otherwise.
     277
     278        EXAMPLES::
     279
     280            sage: Algebras(QQ)._subcategory_hook_(HopfAlgebras(QQ))
     281            True
     282            sage: Algebras(QQ)._subcategory_hook_(HopfAlgebras(ZZ))
     283            False
     284            sage: VectorSpaces(QQ)._subcategory_hook_(VectorSpaces(QQ).hom_category())
     285            True
     286            sage: VectorSpaces(QQ)._subcategory_hook_(Category.join([VectorSpaces(QQ).hom_category(),Rings()]))
     287            Unknown
     288
     289        """
     290        if not issubclass(C.parent_class, self.parent_class):
     291            return False
     292        try:
     293            if C.base() is self.__base:
     294                return True
     295        except AttributeError:
     296            pass
     297        return Unknown
     298
    237299#    def construction(self):
    238300#        return (self.__class__, self.__base)
    239301
  • sage/categories/examples/semigroups_cython.pyx

    diff --git a/sage/categories/examples/semigroups_cython.pyx b/sage/categories/examples/semigroups_cython.pyx
    a b from sage.categories.all import Category 
    77from sage.misc.cachefunc import cached_method
    88from sage.categories.examples.semigroups import LeftZeroSemigroup as LeftZeroSemigroupPython
    99
    10 class DummyClass:
    11     def method(self):
    12         """
    13         TESTS::
    14 
    15             sage: from sage.categories.examples.semigroups_cython import DummyClass
    16             sage: DummyClass().method()
    17         """
    18         pass
    19 
    20 cdef class DummyCClass:
    21     def method(self):
    22         """
    23         TESTS::
    24 
    25             sage: from sage.categories.examples.semigroups_cython import DummyCClass
    26             sage: DummyCClass().method()
    27         """
    28         pass
    29 
    30     cpdef cpmethod(self):
    31         """
    32         TESTS::
    33 
    34             sage: from sage.categories.examples.semigroups_cython import DummyCClass
    35             sage: DummyCClass().cpmethod()
    36         """
    37         pass
    38 
    39 instancemethod     = type(DummyClass.method)
    40 method_descriptor  = type(DummyCClass.method)
    41 
    42 cdef class IdempotentSemigroupsElement(Element):
     10cdef class IdempotentSemigroupsElementMethods:
    4311    def _pow_(self, i):
    4412        """
    4513        EXAMPLES::
    cdef class IdempotentSemigroupsElement(E 
    6432        return True
    6533
    6634class IdempotentSemigroups(Category):
    67     #@cached_method
    6835    def super_categories(self):
    6936        """
    7037        EXAMPLES::
    class IdempotentSemigroups(Category): 
    7542        """
    7643        return [Semigroups()]
    7744
    78     ElementMethods = IdempotentSemigroupsElement
     45    ElementMethods = IdempotentSemigroupsElementMethods
    7946
    8047
    8148cdef class LeftZeroSemigroupElement(Element):
    class LeftZeroSemigroup(LeftZeroSemigrou 
    179146
    180147    Comments:
    181148
    182     - nested classes seem not to be currently supported by cython
     149    - nested classes seem not to be currently supported by Cython
    183150
    184     - one cannot play ugly use class surgery tricks (as with _mul_parent)
     151    - one cannot play ugly class surgery tricks (as with _mul_parent).
    185152      available operations should really be declared to the coercion model!
    186153
    187154    EXAMPLES::
  • sage/structure/dynamic_class.py

    diff --git a/sage/structure/dynamic_class.py b/sage/structure/dynamic_class.py
    a b an inheritance can be partially emulated 
    119119from sage.misc.cachefunc import weak_cached_function
    120120from sage.structure.unique_representation import ClasscallMetaclass
    121121
    122 def dynamic_class(name, bases, cls = None, reduction = None, doccls=None):
     122def dynamic_class(name, bases, cls = None, reduction = None, doccls = None,
     123                  prepend_cls_bases = True, cache=True):
    123124    r"""
    124125    INPUT:
    125126
    def dynamic_class(name, bases, cls = Non 
    128129    - ``cls`` -- a class or None
    129130    - ``reduction`` -- a tuple or None
    130131    - ``doccls`` -- a class or None
     132    - ``prepend_cls_bases`` -- a boolean (default: True)
     133    - ``cache`` -- a boolean or "ignore_reduction" (default: True)
    131134
    132135    Constructs dynamically a new class ``C`` with name ``name``, and
    133136    bases ``bases``. If ``cls`` is provided, then its methods will be
    134     inserted into ``C`` as well. The module of ``C`` is set from the
    135     module of ``cls`` or from the first base class (``bases`` should
    136     be non empty if ``cls` is ``None``).
     137    inserted into ``C``, and its bases will be prepended to ``bases``
     138    (unless ``prepend_cls_bases`` is False).
    137139
    138     Documentation and source instrospection is taken from ``doccls``, or
    139     ``cls`` if ``doccls`` is ``None``, or ``bases[0]`` if both are ``None``.
     140    The module, documentation and source instrospection is taken from
     141    ``doccls``, or ``cls`` if ``doccls`` is ``None``, or ``bases[0]``
     142    if both are ``None`` (therefore ``bases`` should be non empty if
     143    ``cls` is ``None``).
    140144
    141145    The constructed class can safely be pickled (assuming the
    142146    arguments themselves can).
    143147
    144     The result is cached, ensuring unique representation of dynamic
    145     classes.
     148    Unless ``cache`` is False, the result is cached, ensuring unique
     149    representation of dynamic classes.
    146150
    147151    See :mod:`sage.structure.dynamic_class` for a discussion of the
    148152    dynamic classes paradigm, and its relevance to Sage.
    def dynamic_class(name, bases, cls = Non 
    200204        sage: FooBar.mro()
    201205        [<class '__main__.FooBar'>, <type 'object'>, <class __main__.Bar at ...>]
    202206
     207    .. RUBRIC:: Pickling
     208
    203209    Dynamic classes are pickled by construction. Namely, upon
    204210    unpickling, the class will be reconstructed by recalling
    205211    dynamic_class with the same arguments::
    def dynamic_class(name, bases, cls = Non 
    213219        sage: type(FooBar)
    214220        <class 'sage.structure.dynamic_class.DynamicMetaclass'>
    215221
     222
    216223    The following (meaningless) example illustrates how to customize
    217224    the result of the reduction::
    218225
    def dynamic_class(name, bases, cls = Non 
    222229        sage: loads(dumps(BarFoo))
    223230        '3'
    224231
     232    .. RUBRIC:: Caching
     233
     234    By default, the built class is cached:
     235
     236         sage: dynamic_class("FooBar", (Bar,), Foo) is FooBar
     237         True
     238         sage: dynamic_class("FooBar", (Bar,), Foo, cache=True) is FooBar
     239         True
     240
     241    and the result depends on the reduction::
     242
     243        sage: dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (3,))) is BarFoo
     244        True
     245        sage: dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (2,))) is BarFoo
     246        False
     247
     248    With ``cache=False``, a new class is created each time::
     249
     250         sage: FooBar1 = dynamic_class("FooBar", (Bar,), Foo, cache=False); FooBar1
     251         <class '__main__.FooBar'>
     252         sage: FooBar2 = dynamic_class("FooBar", (Bar,), Foo, cache=False); FooBar2
     253         <class '__main__.FooBar'>
     254         sage: FooBar1 is FooBar
     255         False
     256         sage: FooBar2 is FooBar1
     257         False
     258
     259    With ``cache="ignore_reduction"``, the class does not depend on
     260    the reduction::
     261
     262        sage: BarFoo = dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (3,)), cache="ignore_reduction")
     263        sage: dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (2,)), cache="ignore_reduction") is BarFoo
     264        True
     265
     266    In particular, the reduction used is that provided upon creating the first class::
     267
     268        sage: dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (2,)), cache="ignore_reduction")._reduction
     269        (<type 'str'>, (3,))
     270
     271    .. WARNING::
     272
     273        The behaviour upon creating several dynamic classes from the
     274        same data but with different values for ``cache`` option is
     275        currently left unspecified. In other words, for a given
     276        application, it is recommended to consistently use the same
     277        value for that option.
     278
    225279    TESTS::
    226280
    227281        sage: import __main__
    def dynamic_class(name, bases, cls = Non 
    254308    #assert(len(bases) > 0 )
    255309    assert(type(name) is str)
    256310    #    assert(cls is None or issubtype(type(cls), type) or type(cls) is classobj)
    257     return dynamic_class_internal(name, bases, cls, reduction, doccls)
     311    if cache is True:
     312        return dynamic_class_internal(name, bases, cls, reduction, doccls, prepend_cls_bases)
     313    elif cache is False:
     314        # bypass the cached method
     315        return dynamic_class_internal.f(name, bases, cls, reduction, doccls, prepend_cls_bases)
     316    else: # cache = "ignore_reduction"
     317        result = dynamic_class_internal(name, bases, cls, False, doccls, prepend_cls_bases)
     318        if result._reduction is False:
     319            result._reduction = reduction
     320        return result
     321
    258322
    259323@weak_cached_function
    260 def dynamic_class_internal(name, bases, cls = None, reduction = None, doccls = None):
     324def dynamic_class_internal(name, bases, cls = None, reduction = None, doccls = None, prepend_cls_bases=True):
    261325    r"""
    262326    See sage.structure.dynamic_class.dynamic_class? for indirect doctests.
    263327
    def dynamic_class_internal(name, bases,  
    309373        # Anything else that should not be kept?
    310374        if methods.has_key("__dict__"):
    311375            methods.__delitem__("__dict__")
    312         bases = cls.__bases__ + bases
     376        if prepend_cls_bases:
     377            bases = cls.__bases__ + bases
    313378    else:
    314379        methods = {}
    315380    if doccls is None: