Ticket #11943: trac11943_mro_for_all_super_categories_lazy_hook-review-nt.patch
File trac11943_mro_for_all_super_categories_lazy_hook-review-nt.patch, 31.6 KB (added by , 10 years ago) |
---|
-
sage/categories/algebras.py
# HG changeset patch # User Nicolas M. Thiery <nthiery@users.sf.net> # Date 1334173460 -7200 # Node ID 48836a0aebf9f214ee9fa6c809e75f79f6b45c60 # Parent 725cc00e833e7cec1a489409701e54334dd543b5 imported patch trac11943_mro_for_all_super_categories_lazy_hook-review-nt.patch diff --git a/sage/categories/algebras.py b/sage/categories/algebras.py
a b from sage.categories.cartesian_product i 22 22 from sage.categories.dual import DualObjectsCategory 23 23 from sage.categories.tensor import TensorProductsCategory, tensor 24 24 from sage.categories.morphism import SetMorphism 25 from sage.categories.modules import Modules 25 26 from sage.categories.rings import Rings 26 from sage.categories.modules import Modules27 27 from sage.misc.cachefunc import cached_method 28 28 from sage.structure.sage_object import have_same_parent 29 29 -
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 98 98 from sage.misc.abstract_method import abstract_method, abstract_methods_of_class 99 99 from sage.misc.lazy_attribute import lazy_attribute 100 100 from sage.misc.cachefunc import cached_method, cached_function 101 from sage.misc.c3 import C3_algorithm, C3_algorithm_set 101 from sage.misc.c3 import C3_algorithm 102 from sage.misc.unknown import Unknown 102 103 #from sage.misc.misc import attrcall 103 104 104 105 from sage.structure.sage_object import SageObject … … class Category(UniqueRepresentation, Sag 606 607 # """ 607 608 # return hash(self.__category) # Any reason not to use id? 608 609 609 def _subcategory_hook_(self, C):610 def _subcategory_hook_(self, category): 610 611 """ 611 612 Quick subcategory check. 612 613 613 614 INPUT: 614 615 615 ``C``- a category616 - ``category`` -- a category 616 617 617 618 OUTPUT: 618 619 619 - True, if ``C`` is a subcategory of ``self``.620 - False, if ``C`` is not a subcategory of ``self``.621 - `` NotImplemented``, if a quick check was not enough to determine622 whether `` C`` is a subcategory of ``self`` or not.620 - ``True``, if ``category`` is a subcategory of ``self``. 621 - ``False``, if ``category`` is not a subcategory of ``self``. 622 - ``Unknown``, if a quick check was not enough to determine 623 whether ``category`` is a subcategory of ``self`` or not. 623 624 624 NOTE: 625 The aim of this method is to offer a framework to add cheap 626 tests for subcategories. When doing 627 ``category.is_subcategory(self)`` (note the reverse order of 628 ``self`` and ``category``), this method is usually called 629 first. Only if it returns ``Unknown``, :meth:`is_subcategory` 630 will build the list of super categories of ``category``. 631 632 This method need not to handle the case where ``category`` is 633 ``self``; this is the first test that is done in 634 :meth:`is_subcategory`. 625 635 626 636 This default implementation tests whether the parent class 627 of `` C`` is a subclass of the parent class of ``self``.637 of ``category`` is a subclass of the parent class of ``self``. 628 638 Currently (as of trac ticket #11900) this is a complete 629 639 subcategory test. But this will change with trac ticket #11935. 630 640 631 The aim of this method is to offer a framework to add632 a cheap test for subcategories. When doing633 ``C.is_subcategory(self)`` (note the reverse order of634 ``self`` and ``C``), this method is usually called first.635 Only if it returns ``NotImplemented``,636 :meth:`is_subcategory` will determine the list of super637 categories of ``C``.638 639 It is not needed to deal with the case that ``C`` is640 ``self``, because this is the first test that is done641 in :meth:`is_subcategory`.642 643 OUTPUT:644 645 - ``True``, if it is certain that ``C`` is a subcategory646 of self.647 - ``False``, if it is certain that ``C`` is no subcategory648 of self.649 - ``NotImplemented``, if the question whether ``C`` is650 a subcategory of self shall be answered by studying the651 list of super-categories of ``C``.652 653 641 EXAMPLE:: 654 642 655 643 sage: Rings()._subcategory_hook_(Rings()) 656 644 True 657 645 """ 658 # return True if C is a proper sub-category of self; 659 # It is not needed to consider the case "C is self". 660 # return False if C is clearly not a sub-category 661 # of self. 662 # return NotImplemented otherwise. 663 return issubclass(C.parent_class, self.parent_class) 646 return issubclass(category.parent_class, self.parent_class) 664 647 665 648 def __contains__(self, x): 666 649 """ … … class Category(UniqueRepresentation, Sag 773 756 @abstract_method 774 757 def super_categories(self): 775 758 """ 776 Returns the immediate super categories of ``self`` 759 Returns the *immediate* super categories of ``self`` 760 761 Every category should implement this method. 777 762 778 763 EXAMPLES:: 779 764 … … class Category(UniqueRepresentation, Sag 781 766 [Category of monoids] 782 767 sage: Objects().super_categories() 783 768 [] 769 770 .. note:: 771 772 Mathematically speaking, the order of the super categories 773 should be irrelevant. However, in practice, this order 774 influences the result of :meth:`all_super_categories`, and 775 accordingly of the method resolution order for parent and 776 element classes. Namely, since ticket 11943, Sage uses the 777 same `C3` algorithm for determining the order on the list 778 of *all* super categories as Python is using for the 779 method resolution order of new style classes. 780 781 .. note:: 782 783 Whenever speed matters, developers are advised to use the 784 lazy attribute :meth:`_super_categories` instead of 785 calling this method. 784 786 """ 785 787 786 @ cached_method787 def _all_super_categories _raw(self):788 """789 Return all super categories of this category, without removing duplicates.788 @lazy_attribute 789 def _all_super_categories(self): 790 r""" 791 All the super categories of this category, including this category. 790 792 791 TEST:: 793 Since :trac:`11943`, the order of super categories is 794 determined by Python's method resolution order C3 algorithm. 792 795 793 sage: Rngs()._all_super_categories_raw() 794 [Category of commutative additive groups, 796 .. seealso:: :meth:`all_super_categories` 797 798 .. note:: this attribute is likely to eventually become a tuple. 799 800 EXAMPLES:: 801 802 sage: C = Rings(); C 803 Category of rings 804 sage: C._all_super_categories 805 [Category of rings, 806 Category of rngs, 807 Category of commutative additive groups, 808 Category of semirings, 795 809 Category of commutative additive monoids, 796 810 Category of commutative additive semigroups, 797 Category of additive magmas, Category of sets, 798 Category of sets with partial maps, 799 Category of objects, 811 Category of additive magmas, 812 Category of monoids, 800 813 Category of semigroups, 801 814 Category of magmas, 802 815 Category of sets, 803 816 Category of sets with partial maps, 804 817 Category of objects] 818 """ 819 return C3_algorithm(self,'_super_categories','_all_super_categories',False) 805 820 821 @lazy_attribute 822 def _all_super_categories_proper(self): 823 r""" 824 All the proper super categories of this category. 825 826 Since :trac:`11943`, the order of super categories is 827 determined by Python's method resolution order C3 algorithm. 828 829 .. seealso:: :meth:`all_super_categories` 830 831 .. note:: this attribute is likely to eventually become a tuple. 832 833 EXAMPLES:: 834 835 sage: C = Rings(); C 836 Category of rings 837 sage: C._all_super_categories_proper 838 [Category of rngs, 839 Category of commutative additive groups, 840 Category of semirings, 841 Category of commutative additive monoids, 842 Category of commutative additive semigroups, 843 Category of additive magmas, 844 Category of monoids, 845 Category of semigroups, 846 Category of magmas, 847 Category of sets, 848 Category of sets with partial maps, 849 Category of objects] 806 850 """ 807 all_categories = [] 808 for cat in self.super_categories(): 809 all_categories.append(cat) 810 all_categories.extend(cat._all_super_categories_raw()) 811 return all_categories 851 return self._all_super_categories[1:] 812 852 813 @cached_method 814 def all_super_categories(self, proper = False): 815 r""" 816 Returns a linear extension (topological sort) of all the 817 (proper) super categories of this category, and cache the 818 result. 853 @lazy_attribute 854 def _set_of_super_categories(self): 855 """ 856 The frozen set of all proper super categories of this category. 857 858 .. note:: this is used for speeding up category containment tests. 859 860 .. seealso:: :meth:`all_super_categories` 861 862 EXAMPLES:: 863 864 sage: Groups()._set_of_super_categories 865 frozenset([...]) 866 sage: sorted(Groups()._set_of_super_categories, key=repr) 867 [Category of magmas, Category of monoids, Category of objects, Category of semigroups, 868 Category of sets, Category of sets with partial maps] 869 870 TESTS:: 871 872 sage: C = HopfAlgebrasWithBasis(GF(7)) 873 sage: C._set_of_super_categories == frozenset(C._all_super_categories_proper) 874 True 875 """ 876 return frozenset(self._all_super_categories_proper) 877 878 def all_super_categories(self, proper=False): 879 """ 880 Returns the list of all super categories of this category. 819 881 820 882 INPUT: 821 883 822 - ``proper`` : a boolean; defaults to False. Whether to exclude this category.884 - ``proper`` -- a boolean (default: ``False``); whether to exclude this category. 823 885 824 FIXME: 886 Since :trac:`11943`, the order of super categories is 887 determined by Python's method resolution order C3 algorithm. 825 888 826 - make sure that this is compatible with the python algorithm 827 for method resolution and make it O(n+m) 889 .. note:: 890 891 Whenever speed matters, the developers are advised to use 892 instead the lazy attributes :meth:`_all_super_categories`, 893 :meth:`_all_super_categories_proper`, or 894 :meth:`_set_of_all_super_categories`, as 895 appropriate. Simply because lazy attributes are much 896 faster than any method. 828 897 829 898 EXAMPLES:: 830 899 … … class Category(UniqueRepresentation, Sag 858 927 Category of sets, 859 928 Category of sets with partial maps, 860 929 Category of objects] 861 """862 return C3_algorithm(self,'_super_categories','_all_super_categories',False)863 864 @lazy_attribute865 def _all_super_categories_proper(self):866 r"""867 All proper super categories of this category.868 869 NOTE:870 871 By trac ticket #11943, the order of super categories872 is determined by the C3 algorithm.873 874 EXAMPLES::875 876 sage: C = GradedHopfAlgebrasWithBasis(QQ).abstract_category(); C877 Category of abstract graded hopf algebras with basis over Rational Field878 sage: C._all_super_categories_proper879 [Category of graded hopf algebras over Rational Field,880 Category of graded bialgebras over Rational Field,881 Category of graded algebras over Rational Field,882 Category of graded coalgebras over Rational Field,883 Category of graded modules over Rational Field,884 Category of hopf algebras over Rational Field,885 Category of bialgebras over Rational Field,886 Category of algebras over Rational Field,887 ...]888 """889 return C3_algorithm(self,'_super_categories','_all_super_categories',True)890 891 @lazy_attribute892 def _set_of_super_categories(self):893 """894 The frozen set of all proper super categories of this category.895 896 NOTE:897 898 This is used for a speed-up in category containment tests.899 900 TEST::901 902 sage: C = HopfAlgebrasWithBasis(GF(7))903 sage: C._set_of_super_categories == frozenset(C._all_super_categories_proper)904 True905 """906 try:907 return frozenset(self.__dict__['_all_super_categories_proper'])908 except KeyError:909 return frozenset(C3_algorithm_set(self,'_super_categories','_all_super_categories',True))910 911 def all_super_categories(self, proper=False):912 """913 Returns the list of all super categories of this category.914 915 NOTE:916 917 By trac ticket #11943, the order of super categories918 is determined by the :func:`~sage.misc.c3.C3_algorithm`.919 920 INPUT:921 922 - ``proper``: a boolean; defaults to False. Whether to exclude this category.923 924 NOTE:925 926 This method exists for convenience. However, the developers927 are advised to use the lazy attribute ``_all_super_categories``928 or ``_all_super_categories_proper`` when asking for the super929 categories - simply because a lazy attribute is much faster930 than any method.931 932 EXAMPLE::933 930 934 931 sage: Sets().all_super_categories() 935 932 [Category of sets, Category of sets with partial maps, Category of objects] … … class Category(UniqueRepresentation, Sag 948 945 @lazy_attribute 949 946 def _super_categories(self): 950 947 """ 951 Returns the immediate super categories of this category.948 The immediate super categories of this category. 952 949 953 NOTE: 950 This lazy attributes caches the result of the mandatory method 951 :meth:`super_categories` for speed. 954 952 955 For implementing this lazy attribute, you must provide 956 a method :meth:`super_categories`. However, the developers 957 are advised to use the lazy attribute ``_super_categories`` 958 when asking for the super categories - simply because a 959 lazy attribute is much faster than any method. 953 Whenever speed matters, developers are advised to use this 954 lazy attribute rather than calling :meth:`super_categories`. 955 956 .. note:: this attribute is likely to eventually become a tuple. 957 958 EXAMPLES:: 959 960 sage: Rings()._super_categories 961 [Category of rngs, Category of semirings] 960 962 """ 961 963 return self.super_categories() 962 964 963 def super_categories(self):964 """965 Implement this method to provide the *immediate* super categories.966 967 NOTE:968 969 The order of immediate super categories matters in exactly the970 same way as the order of base classes of a Python class971 matters. In fact, by trac ticket #11943, the category972 framework of Sage uses the same algorithm for determining the973 order on the list of *all* super categories that Python is974 using for the method resolution order of new style classes.975 976 NOTE:977 978 In order to avoid overhead, the developers are advised to use979 the lazy attribute ``_super_categories``. While980 ``super_categories()`` must be provided, but it should not be981 called, for the sake of speed.982 """983 raise NotImplementedError984 985 965 def _test_category_graph(self, **options): 986 966 """ 987 Verify that Python's method resolution coincides with the category graph.967 Check that the category graph matches with Python's method resolution order 988 968 989 NOTE:969 .. note:: 990 970 991 By trac ticket #11943, the list of categories returned by :meth:`all_super_categories` 992 is supposed to correspond to the method resolution order of the parent or element 993 classes. This method verifies it. 971 By :trac:`11943`, the list of categories returned by 972 :meth:`all_super_categories` is supposed to match with the 973 method resolution order of the parent and element 974 classes. This method checks this. 994 975 995 TODO:976 .. todo:: currently, this won't work for hom categories. 996 977 997 Currently, it won't work for hom categories. 998 999 EXAMPLE:: 978 EXAMPLES:: 1000 979 1001 980 sage: C = HopfAlgebrasWithBasis(QQ) 1002 981 sage: C.parent_class.mro() == [X.parent_class for X in C._all_super_categories] + [object] … … class Category(UniqueRepresentation, Sag 1152 1131 if c is self: 1153 1132 return True 1154 1133 subcat_hook = c._subcategory_hook_(self) 1155 if subcat_hook is NotImplemented:1134 if subcat_hook is Unknown: 1156 1135 return c in self._set_of_super_categories 1157 1136 return subcat_hook 1158 1137 … … def category_graph(categories = None): 1518 1497 categories = [ cat.an_instance() for cat in sage.categories.all.__dict__.values() if isinstance(cat, type) and issubclass(cat, Category) and cat not in abstract_classes_for_categories ] 1519 1498 cats = set() 1520 1499 for category in categories: 1521 for cat in category. _all_super_categories:1500 for cat in category.all_super_categories(): 1522 1501 cats.add(cat) 1523 1502 1524 1503 categories = cats … … def category_graph(categories = None): 1526 1505 for cat in categories: 1527 1506 g.add_vertex(cat._repr_object_names()) 1528 1507 for source in categories: 1529 for target in source. _super_categories:1508 for target in source.super_categories(): 1530 1509 g.add_edge([source._repr_object_names(), target._repr_object_names()]) 1531 1510 return g 1532 1511 … … class JoinCategory(Category): 1680 1659 """ 1681 1660 return self._super_categories 1682 1661 1683 def _subcategory_hook_(self, C):1662 def _subcategory_hook_(self, category): 1684 1663 """ 1685 Tells whether this join category contains another category as a subcategory.1664 Returns whether ``category`` is a subcategory of this join category 1686 1665 1687 1666 INPUT: 1688 1667 1689 ``C`` -- a category.1668 - ``category`` -- a category. 1690 1669 1691 OUTPUT:1670 .. note:: 1692 1671 1693 Whether ``C`` is sub-category of self or not. 1694 1695 NOTE: 1696 1697 ``C`` is sub-category of this join category if and only if it is sub-category 1698 for all super categories of this join category. 1672 ``category`` is a sub-category of this join category if 1673 and only if it is a sub-category of all super categories 1674 of this join category. 1699 1675 1700 1676 EXAMPLE:: 1701 1677 1702 1678 sage: QQ['x'].category().is_subcategory(Category.join([Rings(), VectorSpaces(QQ)])) # indirect doctest 1703 1679 True 1704 1705 1680 """ 1706 for X in self._super_categories: 1707 if not C.is_subcategory(X): 1708 return False 1709 return True 1681 return all(category.is_subcategory(X) for X in self._super_categories) 1710 1682 1711 1683 def _repr_(self): 1712 1684 """ -
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 14 14 # http://www.gnu.org/licenses/ 15 15 #***************************************************************************** 16 16 17 from sage.misc.cachefunc import cached_method18 17 from sage.misc.latex import latex 19 18 from category import Category 20 19 from objects import Objects -
sage/categories/covariant_functorial_construction.py
diff --git a/sage/categories/covariant_functorial_construction.py b/sage/categories/covariant_functorial_construction.py
a b class CovariantConstructionCategory(Cate 357 357 return Category.join([getattr(cat, cls._functor_category)(*args) for cat in category._super_categories]) 358 358 359 359 def is_subcategory(self, C): 360 """ 361 .. todo:: doctests + explain why this method is needed 362 """ 360 363 if C is self: 361 364 return True 362 for X in self._super_categories: 363 if X.is_subcategory(C): 364 return True 365 return False 365 return any(X.is_subcategory(C) for X in self._super_categories) 366 366 367 367 def __init__(self, category, *args): 368 368 """ … … class CovariantConstructionCategory(Cate 370 370 371 371 sage: from sage.categories.covariant_functorial_construction import CovariantConstructionCategory 372 372 sage: class FooBars(CovariantConstructionCategory): 373 ... pass 374 sage: C = FooBars(ModulesWithBasis(QQ)) 373 ... _functor_category = "FooBars" 374 sage: Category.FooBars = lambda self: FooBars.category_of(self) 375 sage: C = FooBars(ModulesWithBasis(ZZ)) 375 376 sage: C 376 Category of foo bars of modules with basis over Rational Field377 Category of foo bars of modules with basis over Integer Ring 377 378 sage: C.base_category() 378 Category of modules with basis over Rational Field379 Category of modules with basis over Integer Ring 379 380 sage: latex(C) 380 \mathbf{FooBars}(\mathbf{ModulesWithBasis}_{\Bold{ Q}})381 \mathbf{FooBars}(\mathbf{ModulesWithBasis}_{\Bold{Z}}) 381 382 sage: import __main__; __main__.FooBars = FooBars # Fake FooBars being defined in a python module 382 383 sage: TestSuite(C).run() 383 384 """ -
sage/categories/magmas.py
diff --git a/sage/categories/magmas.py b/sage/categories/magmas.py
a b class Magmas(Category_singleton): 34 34 TESTS:: 35 35 36 36 sage: C = Magmas() 37 sage: TestSuite(C).run(verbose=True) 38 running ._test_category() . . . pass 39 running ._test_category_graph() . . . pass 40 running ._test_not_implemented_methods() . . . pass 41 running ._test_pickling() . . . pass 42 37 sage: TestSuite(C).run() 43 38 """ 44 39 def super_categories(self): 45 40 """ -
sage/categories/primer.py
diff --git a/sage/categories/primer.py b/sage/categories/primer.py
a b of some other category. This determines 621 621 A category *may* provide methods that can be used by all its objects, 622 622 respectively by all elements of its objects. 623 623 624 Each category *should* come with a good example, in sage.categories.examples.624 Each category *should* come with a good example, in :mod:`sage.categories.examples`. 625 625 626 626 Inserting the new category into the category graph 627 627 .................................................. … … of *all* super categories of `C`, by usi 633 633 that is also used for the method resolution order of new-style classes 634 634 in Python (see trac ticket #11943). 635 635 636 Of course, if you know that your new category `C` is immediate637 super category of anexisting category `D`, then you should modify636 Of course, if you know that your new category `C` is an immediate 637 super category of some existing category `D`, then you should modify 638 638 `D`'s ``super_categories`` method so that `C` is included. 639 639 640 Although the order between super categories should not be mathematically 641 relevant, the order *is* relevant for inheritance of methods. Namely, 642 a category can provide methods for all its objects and for the elements 643 for all its objects. If `P` is an object in the category `C` and if 644 `C_1` and `C_2` are both super categories of `C` defining some method 645 ``foo``, then `P` will use `C_1`'s version of ``foo`` only if `C_1` 646 appears in ``C.all_super_categories()`` before `C_2`. 640 The order between the super categories does influence the inheritance 641 of methods for parents and elements. Namely, if `P` is an object in 642 the category `C` and if `C_1` and `C_2` are both super categories of 643 `C` defining some method ``foo``, then `P` will use `C_1`'s version of 644 ``foo`` only if `C_1` appears in ``C.all_super_categories()`` before 645 `C_2`. This is an *implementation detail*: the order between super 646 categories should not be mathematically relevant, and code should not 647 rely on any specific order, as it it subject to later change. 647 648 648 649 Also, the C3 algorithm will only be able to determine a consistent order 649 650 on the list of all super categories if the orders on the different lists … … This gives the following order:: 700 701 Category of sets with partial maps, 701 702 Category of objects] 702 703 703 When in doubt, ``C.is_subcategory(D)`` returns True if and only 704 if `D` appears in ``C.all_super_categories()``. However, 705 creating the list of all super categories is an expensive 706 operation that can sometimes be avoided. For example, if 707 both `C` and `D` are categories defined over a base, but the 708 bases differ, then they can not be subcategories of each other. 704 Subcategory hook (advanced optimization feature) 705 ................................................ 709 706 710 If such a short-path is known, one can implement a method 707 The default implementation of the method ``C.is_subcategory(D)`` is to 708 look up whether `D` appears in ``C.all_super_categories()``. However, 709 building the list of all the super categories of `C` is an expensive 710 operation that is sometimes best avoided. For example, if both `C` and 711 `D` are categories defined over a base, but the bases differ, then one 712 knows right away that they can not be subcategories of each other. 713 714 When such a short-path is known, one can implement a method 711 715 ``_subcategory_hook_``. ``C.is_subcategory(D)`` first calls 712 ``D._subcategory_hook_(C)``. If this returns `` NotImplemented``, then716 ``D._subcategory_hook_(C)``. If this returns ``Unknown``, then 713 717 ``C.is_subcategory(D)`` tries to find ``D`` in 714 718 ``C.all_super_categories()``. Otherwise, ``C.is_subcategory(D)`` 715 719 returns the result of ``D._subcategory_hook_(C)``. -
sage/misc/c3.pyx
diff --git a/sage/misc/c3.pyx b/sage/misc/c3.pyx
a b AUTHOR: 9 9 10 10 - Simon King (2011-11): initial version. 11 11 """ 12 #***************************************************************************** 13 # Copyright (C) 2011 Simon King <simon.king@uni-jena.de> 14 # 15 # Distributed under the terms of the GNU General Public License (GPL) 16 # http://www.gnu.org/licenses/ 17 #****************************************************************************** 12 18 13 19 include "../ext/python.pxi" 14 20 15 21 cpdef list C3_algorithm(object start, str bases, str attribute, bint proper): 16 22 """ 17 The C3 algorithm.23 An implementation of the C3 algorithm. 18 24 19 NOTE: 25 C3 is the algorithm used by Python to construct the method 26 resolution order for new style classes involving multiple 27 inheritance. 20 28 21 This implementation is used to order the list of super categories of a22 category; see :meth:`~sage.categories.category.Category.all_super_categories`.23 By consequence, the list of super categories exactly corresponds to the24 method resolution order of the parent or element class of a category.25 This is because Python uses the same algorithm (of course in a different26 implementation) as method resolution order for new style classes.27 29 This implementation is used to order the list of super categories 30 of a category; see 31 :meth:`~sage.categories.category.Category.all_super_categories`. 32 The purpose is to ensure that list of super categories matches 33 with the method resolution order of the parent or element classes 34 of a category. 35 28 36 INPUT: 29 37 30 - ``start`` (object): The returned list is built upon data38 - ``start`` -- an object; the returned list is built upon data 31 39 provided by certain attributes of ``start``. 32 - ``bases`` (string): The name of an attribute of ``start``40 - ``bases`` -- a string; the name of an attribute of ``start`` 33 41 providing a list of objects. 34 - ``attribute`` (string): The name of an attribute of the35 objects provided in ``getattr(start,bases)``. That attribute 36 issupposed to provide a list.42 - ``attribute`` -- a string; the name of an attribute of the 43 objects provided in ``getattr(start,bases)``. That attribute is 44 supposed to provide a list. 37 45 38 46 ASSUMPTIONS: 39 47 … … cpdef list C3_algorithm(object start, st 47 55 48 56 EXAMPLES: 49 57 50 We start with an example of categories with an inconsistent51 base classes of a new class::58 We start with some categories having an inconsistent inheritance 59 order:: 52 60 53 61 sage: class X(Category): 54 62 ... def super_categories(self): 55 63 ... return [Objects()] 56 sage: class X(Category):57 ... def super_categories(self):58 ... return [Objects()]59 64 sage: class Y(Category): 60 65 ... def super_categories(self): 61 66 ... return [Objects()] 62 67 sage: class A(Category): 63 68 ... def super_categories(self): 64 ... return [X(), Y()]69 ... return [X(), Y()] 65 70 sage: class B(Category): 66 71 ... def super_categories(self): 67 ... return [Y(), X()]72 ... return [Y(), X()] 68 73 sage: class Foo(Category): 69 74 ... def super_categories(self): 70 ... return [A(), B()]75 ... return [A(), B()] 71 76 sage: F = Foo() 72 77 73 78 Python is not able to create a consistent method resolution order … … cpdef list C3_algorithm(object start, st 77 82 Traceback (most recent call last): 78 83 ... 79 84 TypeError: Cannot create a consistent method resolution 80 order (MRO) for bases X.parent_class, Y.parent_class85 order (MRO) for bases ....parent_class, ....parent_class 81 86 82 87 Since the C3 algorithm is used for determining the list of 83 88 all super categories (by trac ticket #11943), a similar error … … cpdef list C3_algorithm(object start, st 93 98 94 99 sage: C = Category.join([HopfAlgebrasWithBasis(QQ), FiniteEnumeratedSets()]) 95 100 sage: from sage.misc.c3 import C3_algorithm 96 sage: C3_algorithm(C,'_super_categories','_all_super_categories',True) ==C._all_super_categories_proper101 sage: C3_algorithm(C,'_super_categories','_all_super_categories',True) == C._all_super_categories_proper 97 102 True 98 sage: C3_algorithm(C,'_super_categories','_all_super_categories',False) ==C._all_super_categories103 sage: C3_algorithm(C,'_super_categories','_all_super_categories',False) == C._all_super_categories 99 104 True 100 105 101 106 By trac ticket #11943, the following consistency tests are part … … cpdef list C3_algorithm(object start, st 182 187 curr_set.remove(O) 183 188 except IndexError: 184 189 tails[i] = None 185 190 186 191 i = -1 187 192 # Either we need to raise an error, or the list is done. 188 193 if tails.count(None)<lenargs: 189 194 raise ValueError, "Can not merge the items %s."%', '.join([repr(heads[i]) for i,t in enumerate(tails) if t is not None]) 190 195 return out 191 192 cpdef frozenset C3_algorithm_set(object start, str bases, str attribute, bint proper):193 """194 Return the result of :func:`C3_algorithm` as a frozen set.195 196 EXAMPLE:197 198 This function is used internally for creating the set of all199 super categories of a category. Since a containment test is200 much faster for sets than for lists, this provides some201 speed-up for the category framework. See trac ticket #11943::202 203 sage: Rings()._set_of_super_categories204 frozenset([...])205 sage: Rings()._set_of_super_categories == frozenset(Rings().all_super_categories(proper=True))206 True207 208 """209 return frozenset(C3_algorithm(start,bases,attribute,proper))