Ticket #11935: trac11935_weak_pickling_by_construction-nt.patch
File trac11935_weak_pickling_by_construction-nt.patch, 38.1 KB (added by , 9 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 11 11 # http://www.gnu.org/licenses/ 12 12 #****************************************************************************** 13 13 14 from sage. categories.category import Category15 from sage. misc.cachefunc import cached_method14 from sage.misc.unknown import Unknown 15 from sage.categories.category import Category, CategoryWithParameters 16 16 from sage.categories.left_modules import LeftModules 17 17 from sage.categories.right_modules import RightModules 18 18 … … from sage.categories.rings import Rings 20 20 _Rings = Rings() 21 21 22 22 #?class Bimodules(Category_over_base_rng, Category_over_base_rng): 23 class Bimodules(Category ):23 class Bimodules(CategoryWithParameters): 24 24 """ 25 25 The category of `(R,S)`-bimodules 26 26 … … class Bimodules(Category): 49 49 self._left_base_ring = left_base 50 50 self._right_base_ring = right_base 51 51 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 52 72 @classmethod 53 73 def an_instance(cls): 54 74 """ -
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 95 95 # http://www.gnu.org/licenses/ 96 96 #***************************************************************************** 97 97 98 import inspect 98 99 from sage.misc.abstract_method import abstract_method, abstract_methods_of_class 99 100 from sage.misc.lazy_attribute import lazy_attribute 100 101 from sage.misc.cachefunc import cached_method, cached_function … … from sage.misc.unknown import Unknown 104 105 105 106 from sage.structure.sage_object import SageObject 106 107 from sage.structure.unique_representation import UniqueRepresentation 107 from sage.structure.dynamic_class import dynamic_class _internal108 from sage.structure.dynamic_class import dynamic_class 108 109 109 110 from weakref import WeakValueDictionary 110 111 _join_cache = WeakValueDictionary() … … class Category(UniqueRepresentation, Sag 345 346 same super_categories. For example, Algebras(QQ) has 346 347 VectorSpaces(QQ) as super category, whereas Algebras(ZZ) only has 347 348 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):: 352 351 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 357 363 True 358 364 359 365 We now construct a parent in the usual way:: … … class Category(UniqueRepresentation, Sag 430 436 431 437 INPUT: 432 438 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. 435 441 436 442 EXAMPLES:: 437 443 … … class Category(UniqueRepresentation, Sag 645 651 ``self``; this is the first test that is done in 646 652 :meth:`is_subcategory`. 647 653 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_`. 652 664 653 665 EXAMPLE:: 654 666 … … class Category(UniqueRepresentation, Sag 1020 1032 """ 1021 1033 pass 1022 1034 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 1023 1152 @lazy_attribute 1024 1153 def parent_class(self): 1025 1154 """ … … class Category(UniqueRepresentation, Sag 1031 1160 <class 'sage.categories.algebras.Algebras.parent_class'> 1032 1161 sage: type(C) 1033 1162 <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`. 1034 1184 """ 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') 1053 1186 1054 1187 @lazy_attribute 1055 1188 def element_class(self): … … class Category(UniqueRepresentation, Sag 1062 1195 <class 'sage.categories.algebras.Algebras.element_class'> 1063 1196 sage: type(C) 1064 1197 <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` 1065 1213 """ 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') 1085 1215 1086 1216 def required_methods(self): 1087 1217 """ … … class HomCategory(Category): 1611 1741 return [] 1612 1742 1613 1743 1744 ############################################################################## 1745 # Parametrized categories whose parent/element class depend only on 1746 # the super categories 1747 ############################################################################## 1748 1749 class 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 1614 1940 ############################################################# 1615 1941 # Join of several categories 1616 1942 ############################################################# 1617 1943 1618 class JoinCategory(Category ):1944 class JoinCategory(CategoryWithParameters): 1619 1945 """ 1620 1946 A class for joins of several categories. Do not use directly; 1621 1947 see Category.join instead. … … class JoinCategory(Category): 1629 1955 [Category of groups, Category of commutative additive monoids] 1630 1956 sage: J.all_super_categories(proper=True) 1631 1957 [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 1632 1971 """ 1633 1972 1634 1973 def __init__(self, super_categories, **kwds): … … class JoinCategory(Category): 1659 1998 Category.__init__(self) 1660 1999 self._super_categories = list(super_categories) 1661 2000 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 1662 2027 def super_categories(self): 1663 2028 """ 1664 2029 Returns the immediate super categories, as per :meth:`Category.super_categories`. … … class JoinCategory(Category): 1692 2057 """ 1693 2058 return all(category.is_subcategory(X) for X in self._super_categories) 1694 2059 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 1695 2077 def _repr_(self): 1696 2078 """ 1697 2079 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 15 15 #***************************************************************************** 16 16 17 17 from sage.misc.latex import latex 18 from category import Category 18 from sage.misc.unknown import Unknown 19 from category import Category, CategoryWithParameters 19 20 from objects import Objects 20 21 21 22 #################################################################### … … class Sequences(Category): 197 198 ############################################################# 198 199 # Category of objects over some base object 199 200 ############################################################# 200 class Category_over_base(Category ):201 class Category_over_base(CategoryWithParameters): 201 202 def __init__(self, base, name=None): 202 203 Category.__init__(self, name) 203 204 self.__base = base 204 205 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 205 232 @classmethod 206 233 def an_instance(cls): 207 234 """ … … class Category_over_base(Category): 234 261 """ 235 262 return "\\mathbf{%s}_{%s}"%(self._label, latex(self.__base)) 236 263 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 237 299 # def construction(self): 238 300 # return (self.__class__, self.__base) 239 301 -
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 7 7 from sage.misc.cachefunc import cached_method 8 8 from sage.categories.examples.semigroups import LeftZeroSemigroup as LeftZeroSemigroupPython 9 9 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): 10 cdef class IdempotentSemigroupsElementMethods: 43 11 def _pow_(self, i): 44 12 """ 45 13 EXAMPLES:: … … cdef class IdempotentSemigroupsElement(E 64 32 return True 65 33 66 34 class IdempotentSemigroups(Category): 67 #@cached_method68 35 def super_categories(self): 69 36 """ 70 37 EXAMPLES:: … … class IdempotentSemigroups(Category): 75 42 """ 76 43 return [Semigroups()] 77 44 78 ElementMethods = IdempotentSemigroupsElement 45 ElementMethods = IdempotentSemigroupsElementMethods 79 46 80 47 81 48 cdef class LeftZeroSemigroupElement(Element): … … class LeftZeroSemigroup(LeftZeroSemigrou 179 146 180 147 Comments: 181 148 182 - nested classes seem not to be currently supported by cython149 - nested classes seem not to be currently supported by Cython 183 150 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). 185 152 available operations should really be declared to the coercion model! 186 153 187 154 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 119 119 from sage.misc.cachefunc import weak_cached_function 120 120 from sage.structure.unique_representation import ClasscallMetaclass 121 121 122 def dynamic_class(name, bases, cls = None, reduction = None, doccls=None): 122 def dynamic_class(name, bases, cls = None, reduction = None, doccls = None, 123 prepend_cls_bases = True, cache=True): 123 124 r""" 124 125 INPUT: 125 126 … … def dynamic_class(name, bases, cls = Non 128 129 - ``cls`` -- a class or None 129 130 - ``reduction`` -- a tuple or None 130 131 - ``doccls`` -- a class or None 132 - ``prepend_cls_bases`` -- a boolean (default: True) 133 - ``cache`` -- a boolean or "ignore_reduction" (default: True) 131 134 132 135 Constructs dynamically a new class ``C`` with name ``name``, and 133 136 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). 137 139 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``). 140 144 141 145 The constructed class can safely be pickled (assuming the 142 146 arguments themselves can). 143 147 144 The result is cached, ensuring unique representation of dynamic145 classes.148 Unless ``cache`` is False, the result is cached, ensuring unique 149 representation of dynamic classes. 146 150 147 151 See :mod:`sage.structure.dynamic_class` for a discussion of the 148 152 dynamic classes paradigm, and its relevance to Sage. … … def dynamic_class(name, bases, cls = Non 200 204 sage: FooBar.mro() 201 205 [<class '__main__.FooBar'>, <type 'object'>, <class __main__.Bar at ...>] 202 206 207 .. RUBRIC:: Pickling 208 203 209 Dynamic classes are pickled by construction. Namely, upon 204 210 unpickling, the class will be reconstructed by recalling 205 211 dynamic_class with the same arguments:: … … def dynamic_class(name, bases, cls = Non 213 219 sage: type(FooBar) 214 220 <class 'sage.structure.dynamic_class.DynamicMetaclass'> 215 221 222 216 223 The following (meaningless) example illustrates how to customize 217 224 the result of the reduction:: 218 225 … … def dynamic_class(name, bases, cls = Non 222 229 sage: loads(dumps(BarFoo)) 223 230 '3' 224 231 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 225 279 TESTS:: 226 280 227 281 sage: import __main__ … … def dynamic_class(name, bases, cls = Non 254 308 #assert(len(bases) > 0 ) 255 309 assert(type(name) is str) 256 310 # 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 258 322 259 323 @weak_cached_function 260 def dynamic_class_internal(name, bases, cls = None, reduction = None, doccls = None ):324 def dynamic_class_internal(name, bases, cls = None, reduction = None, doccls = None, prepend_cls_bases=True): 261 325 r""" 262 326 See sage.structure.dynamic_class.dynamic_class? for indirect doctests. 263 327 … … def dynamic_class_internal(name, bases, 309 373 # Anything else that should not be kept? 310 374 if methods.has_key("__dict__"): 311 375 methods.__delitem__("__dict__") 312 bases = cls.__bases__ + bases 376 if prepend_cls_bases: 377 bases = cls.__bases__ + bases 313 378 else: 314 379 methods = {} 315 380 if doccls is None: