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 nthiery, 7 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 
    2222from sage.categories.dual import DualObjectsCategory
    2323from sage.categories.tensor import TensorProductsCategory, tensor
    2424from sage.categories.morphism import SetMorphism
     25from sage.categories.modules import Modules
    2526from sage.categories.rings import Rings
    26 from sage.categories.modules import Modules
    2727from sage.misc.cachefunc import cached_method
    2828from sage.structure.sage_object import have_same_parent
    2929
  • 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 
    9898from sage.misc.abstract_method import abstract_method, abstract_methods_of_class
    9999from sage.misc.lazy_attribute import lazy_attribute
    100100from sage.misc.cachefunc import cached_method, cached_function
    101 from sage.misc.c3 import C3_algorithm, C3_algorithm_set
     101from sage.misc.c3 import C3_algorithm
     102from sage.misc.unknown import Unknown
    102103#from sage.misc.misc import attrcall
    103104
    104105from sage.structure.sage_object import SageObject
    class Category(UniqueRepresentation, Sag 
    606607#         """
    607608#         return hash(self.__category) # Any reason not to use id?
    608609
    609     def _subcategory_hook_(self, C):
     610    def _subcategory_hook_(self, category):
    610611        """
    611612        Quick subcategory check.
    612613
    613614        INPUT:
    614615
    615         ``C`` - a category
     616        - ``category`` -- a category
    616617
    617618        OUTPUT:
    618619
    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 determine
    622           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.
    623624
    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`.
    625635
    626636        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``.
    628638        Currently (as of trac ticket #11900) this is a complete
    629639        subcategory test. But this will change with trac ticket #11935.
    630640
    631         The aim of this method is to offer a framework to add
    632         a cheap test for subcategories. When doing
    633         ``C.is_subcategory(self)`` (note the reverse order of
    634         ``self`` and ``C``), this method is usually called first.
    635         Only if it returns ``NotImplemented``,
    636         :meth:`is_subcategory` will determine the list of super
    637         categories of ``C``.
    638 
    639         It is not needed to deal with the case that ``C`` is
    640         ``self``, because this is the first test that is done
    641         in :meth:`is_subcategory`.
    642 
    643         OUTPUT:
    644 
    645         - ``True``, if it is certain that ``C`` is a subcategory
    646           of self.
    647         - ``False``, if it is certain that ``C`` is no subcategory
    648           of self.
    649         - ``NotImplemented``, if the question whether ``C`` is
    650           a subcategory of self shall be answered by studying the
    651           list of super-categories of ``C``.
    652 
    653641        EXAMPLE::
    654642
    655643            sage: Rings()._subcategory_hook_(Rings())
    656644            True
    657645        """
    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)
    664647
    665648    def __contains__(self, x):
    666649        """
    class Category(UniqueRepresentation, Sag 
    773756    @abstract_method
    774757    def super_categories(self):
    775758        """
    776         Returns the immediate super categories of ``self``
     759        Returns the *immediate* super categories of ``self``
     760
     761        Every category should implement this method.
    777762
    778763        EXAMPLES::
    779764
    class Category(UniqueRepresentation, Sag 
    781766            [Category of monoids]
    782767            sage: Objects().super_categories()
    783768            []
     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.
    784786        """
    785787
    786     @cached_method
    787     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.
    790792
    791         TEST::
     793        Since :trac:`11943`, the order of super categories is
     794        determined by Python's method resolution order C3 algorithm.
    792795
    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,
    795809             Category of commutative additive monoids,
    796810             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,
    800813             Category of semigroups,
    801814             Category of magmas,
    802815             Category of sets,
    803816             Category of sets with partial maps,
    804817             Category of objects]
     818        """
     819        return C3_algorithm(self,'_super_categories','_all_super_categories',False)
    805820
     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]
    806850        """
    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:]
    812852
    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.
    819881
    820882        INPUT:
    821883
    822          - ``proper``: a boolean; defaults to False.  Whether to exclude this category.
     884         - ``proper`` -- a boolean (default: ``False``); whether to exclude this category.
    823885
    824         FIXME:
     886        Since :trac:`11943`, the order of super categories is
     887        determined by Python's method resolution order C3 algorithm.
    825888
    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.
    828897
    829898        EXAMPLES::
    830899
    class Category(UniqueRepresentation, Sag 
    858927             Category of sets,
    859928             Category of sets with partial maps,
    860929             Category of objects]
    861         """
    862         return C3_algorithm(self,'_super_categories','_all_super_categories',False)
    863 
    864     @lazy_attribute
    865     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 categories
    872         is determined by the C3 algorithm.
    873 
    874         EXAMPLES::
    875 
    876             sage: C = GradedHopfAlgebrasWithBasis(QQ).abstract_category(); C
    877             Category of abstract graded hopf algebras with basis over Rational Field
    878             sage: C._all_super_categories_proper
    879             [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_attribute
    892     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             True
    905         """
    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 categories
    918         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 developers
    927         are advised to use the lazy attribute ``_all_super_categories``
    928         or ``_all_super_categories_proper`` when asking for the super
    929         categories - simply because a lazy attribute is much faster
    930         than any method.
    931 
    932         EXAMPLE::
    933930
    934931            sage: Sets().all_super_categories()
    935932            [Category of sets, Category of sets with partial maps, Category of objects]
    class Category(UniqueRepresentation, Sag 
    948945    @lazy_attribute
    949946    def _super_categories(self):
    950947        """
    951         Returns the immediate super categories of this category.
     948        The immediate super categories of this category.
    952949
    953         NOTE:
     950        This lazy attributes caches the result of the mandatory method
     951        :meth:`super_categories` for speed.
    954952
    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]
    960962        """
    961963        return self.super_categories()
    962964
    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 the
    970         same way as the order of base classes of a Python class
    971         matters. In fact, by trac ticket #11943, the category
    972         framework of Sage uses the same algorithm for determining the
    973         order on the list of *all* super categories that Python is
    974         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 use
    979         the lazy attribute ``_super_categories``. While
    980         ``super_categories()`` must be provided, but it should not be
    981         called, for the sake of speed.
    982         """
    983         raise NotImplementedError
    984 
    985965    def _test_category_graph(self, **options):
    986966        """
    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
    988968
    989         NOTE:
     969        .. note::
    990970
    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.
    994975
    995         TODO:
     976        .. todo:: currently, this won't work for hom categories.
    996977
    997         Currently, it won't work for hom categories.
    998 
    999         EXAMPLE::
     978        EXAMPLES::
    1000979
    1001980            sage: C = HopfAlgebrasWithBasis(QQ)
    1002981            sage: C.parent_class.mro() == [X.parent_class for X in C._all_super_categories] + [object]
    class Category(UniqueRepresentation, Sag 
    11521131        if c is self:
    11531132            return True
    11541133        subcat_hook = c._subcategory_hook_(self)
    1155         if subcat_hook is NotImplemented:
     1134        if subcat_hook is Unknown:
    11561135            return c in self._set_of_super_categories
    11571136        return subcat_hook
    11581137
    def category_graph(categories = None): 
    15181497        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 ]
    15191498    cats = set()
    15201499    for category in categories:
    1521         for cat in category._all_super_categories:
     1500        for cat in category.all_super_categories():
    15221501            cats.add(cat)
    15231502
    15241503    categories = cats
    def category_graph(categories = None): 
    15261505    for cat in categories:
    15271506        g.add_vertex(cat._repr_object_names())
    15281507        for source in categories:
    1529             for target in source._super_categories:
     1508            for target in source.super_categories():
    15301509                g.add_edge([source._repr_object_names(), target._repr_object_names()])
    15311510    return g
    15321511
    class JoinCategory(Category): 
    16801659        """
    16811660        return self._super_categories
    16821661
    1683     def _subcategory_hook_(self, C):
     1662    def _subcategory_hook_(self, category):
    16841663        """
    1685         Tells whether this join category contains another category as a subcategory.
     1664        Returns whether ``category`` is a subcategory of this join category
    16861665
    16871666        INPUT:
    16881667
    1689         ``C`` -- a category.
     1668        - ``category`` -- a category.
    16901669
    1691         OUTPUT:
     1670        .. note::
    16921671
    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.
    16991675
    17001676        EXAMPLE::
    17011677
    17021678            sage: QQ['x'].category().is_subcategory(Category.join([Rings(), VectorSpaces(QQ)]))  # indirect doctest
    17031679            True
    1704 
    17051680        """
    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)
    17101682
    17111683    def _repr_(self):
    17121684        """
  • 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 
    1414#                  http://www.gnu.org/licenses/
    1515#*****************************************************************************
    1616
    17 from sage.misc.cachefunc import cached_method
    1817from sage.misc.latex import latex
    1918from category import Category
    2019from 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 
    357357        return Category.join([getattr(cat, cls._functor_category)(*args) for cat in category._super_categories])
    358358
    359359    def is_subcategory(self, C):
     360        """
     361        .. todo:: doctests + explain why this method is needed
     362        """
    360363        if C is self:
    361364            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)
    366366
    367367    def __init__(self, category, *args):
    368368        """
    class CovariantConstructionCategory(Cate 
    370370
    371371            sage: from sage.categories.covariant_functorial_construction import CovariantConstructionCategory
    372372            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))
    375376            sage: C
    376             Category of foo bars of modules with basis over Rational Field
     377            Category of foo bars of modules with basis over Integer Ring
    377378            sage: C.base_category()
    378             Category of modules with basis over Rational Field
     379            Category of modules with basis over Integer Ring
    379380            sage: latex(C)
    380             \mathbf{FooBars}(\mathbf{ModulesWithBasis}_{\Bold{Q}})
     381            \mathbf{FooBars}(\mathbf{ModulesWithBasis}_{\Bold{Z}})
    381382            sage: import __main__; __main__.FooBars = FooBars # Fake FooBars being defined in a python module
    382383            sage: TestSuite(C).run()
    383384        """
  • sage/categories/magmas.py

    diff --git a/sage/categories/magmas.py b/sage/categories/magmas.py
    a b class Magmas(Category_singleton): 
    3434    TESTS::
    3535
    3636        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()
    4338    """
    4439    def super_categories(self):
    4540        """
  • sage/categories/primer.py

    diff --git a/sage/categories/primer.py b/sage/categories/primer.py
    a b of some other category. This determines  
    621621A category *may* provide methods that can be used by all its objects,
    622622respectively by all elements of its objects.
    623623
    624 Each category *should* come with a good example, in sage.categories.examples.
     624Each category *should* come with a good example, in :mod:`sage.categories.examples`.
    625625
    626626Inserting the new category into the category graph
    627627..................................................
    of *all* super categories of `C`, by usi 
    633633that is also used for the method resolution order of new-style classes
    634634in Python (see trac ticket #11943).
    635635
    636 Of course, if you know that your new category `C` is immediate
    637 super category of an existing category `D`, then you should modify
     636Of course, if you know that your new category `C` is an immediate
     637super category of some existing category `D`, then you should modify
    638638`D`'s ``super_categories`` method so that `C` is included.
    639639
    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`.
     640The order between the super categories does influence the inheritance
     641of methods for parents and elements. Namely, if `P` is an object in
     642the 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
     646categories should not be mathematically relevant, and code should not
     647rely on any specific order, as it it subject to later change.
    647648
    648649Also, the C3 algorithm will only be able to determine a consistent order
    649650on the list of all super categories if the orders on the different lists
    This gives the following order:: 
    700701     Category of sets with partial maps,
    701702     Category of objects]
    702703
    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.
     704Subcategory hook (advanced optimization feature)
     705................................................
    709706
    710 If such a short-path is known, one can implement a method
     707The default implementation of the method ``C.is_subcategory(D)`` is to
     708look up whether `D` appears in ``C.all_super_categories()``. However,
     709building the list of all the super categories of `C` is an expensive
     710operation 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
     712knows right away that they can not be subcategories of each other.
     713
     714When such a short-path is known, one can implement a method
    711715``_subcategory_hook_``. ``C.is_subcategory(D)`` first calls
    712 ``D._subcategory_hook_(C)``. If this returns ``NotImplemented``, then
     716``D._subcategory_hook_(C)``. If this returns ``Unknown``, then
    713717``C.is_subcategory(D)`` tries to find ``D`` in
    714718``C.all_super_categories()``. Otherwise, ``C.is_subcategory(D)``
    715719returns 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: 
    99
    1010- Simon King (2011-11): initial version.
    1111"""
     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#******************************************************************************
    1218
    1319include "../ext/python.pxi"
    1420
    1521cpdef list C3_algorithm(object start, str bases, str attribute, bint proper):
    1622    """
    17     The C3 algorithm.
     23    An implementation of the C3 algorithm.
    1824
    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.
    2028
    21     This implementation is used to order the list of super categories of a
    22     category; see :meth:`~sage.categories.category.Category.all_super_categories`.
    23     By consequence, the list of super categories exactly corresponds to the
    24     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 different
    26     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
    2836    INPUT:
    2937
    30     - ``start`` (object): The returned list is built upon data
     38    - ``start`` -- an object; the returned list is built upon data
    3139      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``
    3341      providing a list of objects.
    34     - ``attribute`` (string): The name of an attribute of the
    35       objects provided in ``getattr(start,bases)``. That attribute
    36       is supposed 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.
    3745
    3846    ASSUMPTIONS:
    3947
    cpdef list C3_algorithm(object start, st 
    4755
    4856    EXAMPLES:
    4957
    50     We start with an example of categories with an inconsistent
    51     base classes of a new class::
     58    We start with some categories having an inconsistent inheritance
     59    order::
    5260
    5361        sage: class X(Category):
    5462        ...    def super_categories(self):
    5563        ...        return [Objects()]
    56         sage: class X(Category):
    57         ...    def super_categories(self):
    58         ...        return [Objects()]
    5964        sage: class Y(Category):
    6065        ...    def super_categories(self):
    6166        ...        return [Objects()]
    6267        sage: class A(Category):
    6368        ...    def super_categories(self):
    64         ...        return [X(),Y()]
     69        ...        return [X(), Y()]
    6570        sage: class B(Category):
    6671        ...    def super_categories(self):
    67         ...        return [Y(),X()]
     72        ...        return [Y(), X()]
    6873        sage: class Foo(Category):
    6974        ...    def super_categories(self):
    70         ...       return [A(),B()]
     75        ...       return [A(), B()]
    7176        sage: F = Foo()
    7277
    7378    Python is not able to create a consistent method resolution order
    cpdef list C3_algorithm(object start, st 
    7782        Traceback (most recent call last):
    7883        ...
    7984        TypeError: Cannot create a consistent method resolution
    80         order (MRO) for bases X.parent_class, Y.parent_class
     85        order (MRO) for bases ....parent_class, ....parent_class
    8186
    8287    Since the C3 algorithm is used for determining the list of
    8388    all super categories (by trac ticket #11943), a similar error
    cpdef list C3_algorithm(object start, st 
    9398
    9499        sage: C = Category.join([HopfAlgebrasWithBasis(QQ), FiniteEnumeratedSets()])
    95100        sage: from sage.misc.c3 import C3_algorithm
    96         sage: C3_algorithm(C,'_super_categories','_all_super_categories',True)==C._all_super_categories_proper
     101        sage: C3_algorithm(C,'_super_categories','_all_super_categories',True) == C._all_super_categories_proper
    97102        True
    98         sage: C3_algorithm(C,'_super_categories','_all_super_categories',False)==C._all_super_categories
     103        sage: C3_algorithm(C,'_super_categories','_all_super_categories',False) == C._all_super_categories
    99104        True
    100105
    101106    By trac ticket #11943, the following consistency tests are part
    cpdef list C3_algorithm(object start, st 
    182187                curr_set.remove(O)
    183188            except IndexError:
    184189                tails[i] = None
    185            
     190
    186191            i = -1
    187192    # Either we need to raise an error, or the list is done.
    188193    if tails.count(None)<lenargs:
    189194        raise ValueError, "Can not merge the items %s."%', '.join([repr(heads[i]) for i,t in enumerate(tails) if t is not None])
    190195    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 all
    199         super categories of a category. Since a containment test is
    200         much faster for sets than for lists, this provides some
    201         speed-up for the category framework. See trac ticket #11943::
    202 
    203             sage: Rings()._set_of_super_categories
    204             frozenset([...])
    205             sage: Rings()._set_of_super_categories == frozenset(Rings().all_super_categories(proper=True))
    206             True
    207 
    208     """
    209     return frozenset(C3_algorithm(start,bases,attribute,proper))