Ticket #5891: categories-framework-nt.patch

File categories-framework-nt.patch, 145.6 KB (added by nthiery, 10 years ago)
  • doc/en/reference/categories.rst

    #5891: Categories for the working mathematics programmer
    
    This (series of) patch(es) extends the Sage category framework as a
    design pattern for organizing generic code.
    
    (with special thanks to Robert Bradshaw, Mike Hansen, Florent Hivert,
    David Roe, William Stein, ... for design discussions).
    
    The latest version of the patches are available from:
    http://combinat.sagemath.org/patches/file/
    
    Small technical patches the category patch depends on:
    
     - #5449: cached_in_parent_method-5449-submitted.patch        (positive review)
     - #5783: lazy_attributes-fixes-5783-final.patch              (closed)
     - #5120: unique_representation-5120-submitted.patch          (closed)
     - #5967: element_wrapper-5967-submitted.patch                (positive review; parent as first argument?)
     - #5979: parent-element_constructor-fix-5979-submitted.patch (robert)
     - #5985: cPickle-5985-import-submitted.patch, cPickle-5985-copy_reg_classes-submitted.patch (positive review)
     - #5986: cPickle-5986-nested-classes-submitted.patch         (Craig)
     - #5991: dynamic_class-5991-submitted.patch                  (positive review)
     - #5598: 5598-coerce-declare.patch
     - #5483: explain-pickle-v1.patch			      (with patch, needs review)
     - #6000: transitive_ideal-6000-submitted.patch               (positive review)
     - #6097: abstract_method-6097-nt.patch                       (with patch, needs review)
    
    Main patches #5891:
    
     - categories-framework-nt.patch          (reviewer: David)
     - categories-categories-nt.patch         (reviewer: Craig)
     - categories-fixsagelib-nt.patch         (reviewer: Robert)
       updates to the sage library (import fixes, ...)
     - categories-enumeratedsets-nt.patch     (reviewer: )
     - categories-combinat-nt.patch           ()
     - categories-numberfield_homset-nt.patch (reviewer: David)
    
    Related patches which will need to be applied after to recover 100% doctest pass:
    
    
    Other related patches:
    
     - categories-freemodules-nt.patch(bumped for later)
       updates to combinatorial free modules
     - family_enumset-fh.patch
     - enumset_unions-fh.patch
     - categories-sf-nt.patch 	Symmetric functions
     - categories-symmetric_group_algebra-nt.patch
     - #4326: root_systems-4326-nt.patch
    
    Current status:
    
     - All test pass (except sage_object, unpickling, see below)
    
     - Documentation:
      - sage.categories?         Category quickref card
      - sage.categories.primer?  Element/Parent/Category primer (in writing)
      - Category?                Technical background on categories
      - Semigroups().example()?? A template of semigroup
      - See also the discussion on sage-devel in November 2009:
        http://groups.google.com/group/sage-devel/msg/d4065154e2e8cbd9
    
     - Real life applications:
       - categories-ncsf-nt.patch		Non commutative Symmetric Functions
       - automatic monoids, ...
    
     - Categories:
      - Infrastructure:
        * sage.categories.category (500 lines of code)
        * sage.structure.parent (100 lines of code)
        * class manipulation: (25 lines of code)
      - All the mathematical categories of Axiom and MuPAD (Courtesy of Teresa Gomez Diaz)
        (except *WithSeveralBases which are not needed anymore; see .abstract_category())
      - (Infinite/Finite)EnumeratedSets (with example) (Courtesy of Florent Hivert)
      - Semigroups                      (with example, basic methods, subquotients)
      - FiniteSemigroups                (with example, cayley graphs, basic representation theory, ...)
      - ModulesWithBasis                (with example, morphisms)
      - HopfAlgebras & friends          (with a couple examples)
      - Cleanup:
        - Have unique representation by default (no need to inherit from Category_uniq)
        - Have construction / reduce by default
    
     - Functorial constructions:
      - cartesian product (todo)
      - subquotient, subset, quotient (in progress)
      - direct sum
      - tensor product
      - dual (very preliminary)
      - isomorphism type (very preliminary)
    
     - Homomorphisms:
      - Integrates with current sage morphisms
      - Adds morphisms for some categories
      - Some general infrastructure
      - Hom:
        - Simplification of the logic. Hopefuly completely compatible.
        - X._Hom_(Y, category) may now return NotImplemented
        - failed attempt at using cached_function (to be pursued)
      - Systematic use of category = ... instead of cat =
        This may be backward incompatible.
    
     - Generic test framework:
       Functional. See Todo's in Sets.Parent.check? for possible improvements
    
     - Lazy attributes:
       Non essential, and essentially invisible from the user interface
       Powerful tool for:
        - Conditionaly defined methods
        - Enriched methods
    
     - Pickling:
       Works; the strategy could be improved at some point; see also below
    
     - Categories and Cython:
       Proof-of-concept for Cython classes to inherit code from categories
       See: sage.categories.examples.semigroups_cython
    
     - Reorganization of the Sage library to start using the category framework:
      * Combinatorial free modules
        * Have unique representation, use coercion, are more robust
        * Improved _repr_
        * Handle combinatorial classes that can't be sorted as indices
      * Groups:
        * AbelianGroup_class.__init__ was missing a call to Groups.__init__
        * NAME CONFLICT: AbelianGroups are *not* in AbelianGroups()
          With the current conventions:
           - AbelianGroups is about additive abelian groups
           - AbelianGroup  is about multiplicative abelian group
        * Support for Group.__init__(category = ...)
      * NumberFields: bug fix (categories-numberfield_homset-nt.patch / needs review):
        Hom(SomeNumberField,SomeVectorSpace) returned a numberfield homset
      * Fixed some import loops
      * Added temporary list() methods to:
        - FreeModule_generic
        - MatrixSpace_generic
        - Set_object_enumerated
        - ParentWithAdditiveAbelianGens
        - ParentWithMultiplicativeAbelianGens
        They should eventually be inherited from the EnumeratedSets() category
      * Added sage.sets.finite_enumerated_set
      * Added aliases one = one_element, zero = zero_element to start the transition (to be discussed)
      * Naming conventions and cleanup:
        * parent.product(x,y)   parent.product    parent.product_on_basis
          (was: multiply, _multiply, multiply_basis, _multiply_basis)
        * parent.summation(x,y) parent.summation        # risk of confusion with infinite summation / ...
    
        * parent.sum ([x,y,z,y])
        * parent.prod([x,y,z,y])
    
        * parent.coproduct, parent.coproduct_on_basis, parent.coproduct_on_generators
        * parent.antipode, parent.antipode_on_basis, parent.antipode_on_generators
        * cat.example()  cat.counter_example()
        * A.one() A.zero() a.is_one() a.is_zero()   A(1) A(0) when it makes sense
          A.one_element() A.zero_element() deprecated in the doc; fully deprecated later
        * Use class.an_instance() whenever meaningful
        * parent.an_element() parent.some_elements(); possibly parent.example() parent.counterexample()
        * all_weakly_super_categories -> all_super_categories(proper=False)
    
     - Todo before integration of this patch:
    
      * Documentation cleanup (HELP!):
        * Get to 100% doctests
        * Fix ReST incorrectness
        * Check and put appropriate entry points
    
      * Add more examples of parents (HELP!):
        Ultimately, this should be for all categories,
        Those are needed urgently:
        * Modules (for doctests for __mul__ / __rmul__ / ...)
        * Algebras (for doctests for __mul__ / __rmul__ / ...)
        * AbelianSemigroups (for doctesting __add__ /  __sub__ / ...)
    
      * Fixes:
        * sage -t  "devel/sage/sage/structure/sage_object.pyx"
          Pickling from old sage: technically feasible. HELP!
    
    - Todo for after:
      * AbelianGroups -> CommutativeAdditiveGroups (idem for the others)
      * Allow for super classes to also provide .Element
      * Get nice category graph pictures! HELP!
      * Make sure that ? and ?? on categories / examples / ... point to the right place
        e.g.: Semigroups??, Semigroups().example()??
        Semigroups().parent_class?, Semigroups.element_class?
      * abstract / isomorphism type / with_several_representations
    
    
     - Long run discussions:
      * __init_add__
      * Writing and linking to generic documentation
      * ToDedefined code stubs
      * Standardize the functorial constructions, and streamline with
        variants (finite / finite dimensional / graded / abstract / ...)
      * Hom is *not* a functorial construction. This works for now, but
        the design and user interface needs to be discussed for the long
        run implementation.
      * Support for multivariate morphims, i.e. morphisms (A x B) -> C
        where the specializations (A x b) -> C and and (a x B) -> C are
        morphisms for possibly different categories
      * Defining new inline operators, at least within the sage interpreter
      * Convention for the order in super_categories (see primer)
      * Cythonification, and merging of the code with sage.structure.element.*Element?
      * Inheritance from existing parents
      * How to specify the category of a parent (overloading of method / argument to __init__)
    
    diff --git a/doc/en/reference/categories.rst b/doc/en/reference/categories.rst
    a b Category Theory 
    66.. toctree::
    77   :maxdepth: 2
    88
     9   sage/categories/primer
    910   sage/categories/category
    1011   sage/categories/homset
    1112   sage/categories/morphism
    12    sage/categories/functor
    13  No newline at end of file
     13   sage/categories/functor
  • sage/categories/__init__.py

    diff --git a/sage/categories/__init__.py b/sage/categories/__init__.py
    a b  
     1__doc__ = r"""
     2Sage categories quickref
     3------------------------
     4
     5- sage.categories.primer?             A primer on Elements, Parents, and Categories
     6- Category?                           Technical background on categories
     7- Sets() Semigroups() Algebras(QQ)    Some categories
     8- SemiGroups().example()??            Sample implementation of a semigroup
     9- Hom(A, B), End(A, Algebras())       Homomorphisms sets
     10
     11Module layout:
     12
     13- sage.categories.basic:              the basic categories
     14- sage.categories.all:                all categories
     15- sage.categories.semigroups:         the Semigroups() category
     16- sage.categories.examples.semigroups the example of Semigroups()
     17- sage.categories.homset, map,
     18                  morphism, functors: morphisms, ...
     19- sage.categories.direct_sum, tensor,
     20                  dual:               functorial constructions
     21
     22
     23Todo: put the quickref in quickref.py, and only some pointers here?
     24
     25"""
     26
     27import primer
  • new file sage/categories/primer.py

    diff --git a/sage/categories/primer.py b/sage/categories/primer.py
    new file mode 100644
    - +  
     1r"""
     2Elements, parents, and categories in Sage: a primer
     3
     4Abstract
     5--------
     6
     7    The purpose of categories in Sage is to translate the mathematical
     8    concept of categories (category of groups, of vector spaces, ...)
     9    into a concrete software engineering design pattern for:
     10
     11    - organizing and promoting generic code
     12    - fostering consistency across the Sage library (naming conventions, doc, tests)
     13    - putting mathematical knowledge into the system
     14
     15    This design pattern is largely inspired from Axiom and its
     16    followers (Aldor, Fricas, MuPAD, ...). It differs from those by:
     17
     18    - blending in the Magma inspired concept of Parent/Element
     19
     20    - being built on top of (and not into) the standard python object
     21      oriented and class hierarchy mechanism. This did not require
     22      changing the language, and could in principle be implemented in
     23      any language allowing for dynamically creating new classes.
     24
     25
     26
     27
     28Introduction
     29------------
     30
     31Goal: mathematical computations
     32
     33Requires to model mathematical objects and operations in the computer
     34
     35Examples:
     36
     37- An integer:               +, *, factorization
     38
     39- A matrix:                 +, *, determinant
     40
     41- A word:                   pattern matching, ...
     42
     43- The permutations of 5, the rational points of an elliptic curve: counting, listing, random generation
     44
     45- A Language (set of words): rationality testing, counting elements, generating series
     46
     47- A finite semigroup: left/right ideals, center, representation theory
     48
     49- A vector space, an algebra: direct sum, tensor product, quotient
     50
     51- The category of algebras: what's its initial object? its super categories? its dual category?
     52
     53
     54Object oriented programming paradigm
     55------------------------------------
     56
     57A mathematical object is modeled by an *instance* of a *class*.
     58
     59The class implements:
     60 - a *data structure*: which describes how the mathematical object is stored
     61 - *methods*: which describe the operations on the mathematical object
     62
     63For example, an integer in Sage is an instance of the class Integer
     64(and knows it!)::
     65
     66    sage: i = 12
     67    sage: type(i)
     68    <type 'sage.rings.integer.Integer'>
     69
     70Applying an operation is generally done by *calling a method*::
     71
     72    sage: i.factor()
     73    2^2 * 3
     74
     75    sage: type(x^2+2*x+1)
     76    <class 'sage.calculus.calculus.SymbolicArithmetic'>
     77    sage: (x^2+2*x+1).factor()
     78    (x + 1)^2
     79
     80This illustrates *polymorphism*, *data abstraction*, *encapsulation*
     81
     82Let us be curious::
     83
     84    sage: i.is_one??            # todo: not implemented
     85    sage: i.__add__??           # todo: not implemented
     86    sage: i._add_??             # todo: not implemented
     87
     88Some examples of mathematical sets and operations on them::
     89
     90    sage: ZZ.one_element()
     91    1
     92
     93    sage: R = QQ['x,y']
     94    sage: R.krull_dimension()
     95    2
     96    sage: A = R.quotient( R.ideal(x^2 - 2) )
     97    sage: A.krull_dimension() # todo: not implemented
     98
     99Elements, Parents, Categories
     100-----------------------------
     101
     102Philosophy: *Building mathematical information into the system yields
     103more expressive, more conceptual and, at the end, easier to maintain
     104and faster code*.
     105
     106(within a programming context; this would not necessarily apply to
     107specialized libraries like gmp!)
     108
     109Example of mathematical information::
     110
     111        sage: i.parent()
     112        Integer Ring
     113
     114        sage: i.parent().category()
     115        Category of commutative rings
     116        sage: i.parent().categories()
     117        [Category of commutative rings,
     118         Category of rings,
     119         Category of rngs,
     120         Category of abelian groups,
     121         Category of abelian monoids,
     122         Category of abelian semigroups,
     123         Category of monoids,
     124         Category of semigroups,
     125         Category of sets,
     126         Category of objects]
     127
     128        sage: CommutativeRings().category_graph().plot(talk = True)
     129
     130Relations between mathematical objects::
     131- element <-> parent
     132- parent  <-> category
     133- subcategory <-> super category
     134
     135(Todo: include a picture!)
     136
     137Let us look at a semigroup::
     138
     139    sage: S = FiniteSemigroups().example()
     140    sage: S?                    # todo: not implemented
     141
     142Where do all the operations come from?
     143
     144    sage: x = S('a')
     145
     146``_repr_`` is a technical method which comes with the data structure (ElementWrapper)::
     147
     148    sage: x._repr_??            # todo: not implemented
     149
     150``is_idempotent`` is a mathematical method provided by the parent (which
     151knows that all its elements are idempotents!)::
     152
     153    sage: x.is_idempotent??     # todo: not implemented
     154
     155``__pow__`` is a generic method for all finite semigroups::
     156
     157    sage: x.__pow__??           # todo: not implemented
     158
     159``_mul_`` delegates the work to the parent (if you don't know what to do, ask your parent)::
     160
     161    sage: x.__mul__??           # todo: not implemented
     162
     163``cayley_graph`` is a generic method on the parent, provided by finite semigroups
     164
     165    sage: S.cayley_graph??      # todo: not implemented
     166
     167Consider the implementation of the semigroup::
     168
     169    sage: S??                   # todo: not implemented
     170
     171This implementation specifies a data structure for the parents and the
     172elements, and makes a promise: the implemented parent is a
     173semigroup. Then it fullfills the promise by implemented the basic
     174operations ``product`` and ``semigroup_generators``. In exchange of
     175this promise, S and its elements receive generic implementations of
     176all the other operations. S may override any of the operations by more
     177efficient ones, like for ``is_idempotent``.
     178
     179There is the code for the finite semigroups category::
     180
     181    sage: FiniteSemigroups??    # todo: not implemented
     182
     183Wrapup: the mathematical relations between elements, parents, and
     184categories translates into *inheritance* between classes::
     185
     186    sage: FiniteSemigroups().all_super_categories()
     187    [Category of finite semigroups,
     188     Category of semigroups,
     189     Category of finite enumerated sets,
     190     Category of enumerated sets,
     191     Category of sets,
     192     Category of objects]
     193    sage: S.__class__.mro()
     194    [<class 'sage.categories.examples.finite_semigroups.LRBand_with_category'>,
     195     <class 'sage.categories.examples.finite_semigroups.LRBand'>,
     196     <class 'sage.structure.unique_representation.UniqueRepresentation'>,
     197     <type 'sage.structure.parent.Parent'>,
     198     <type 'sage.structure.category_object.CategoryObject'>,
     199     <type 'sage.structure.sage_object.SageObject'>,
     200     <class 'sage.categories.finite_semigroups.FiniteSemigroups.parent_class'>,
     201     <class 'sage.categories.semigroups.Semigroups.parent_class'>,
     202     <class 'sage.categories.finite_enumerated_sets.FiniteEnumeratedSets.parent_class'>,
     203     <class 'sage.categories.enumerated_sets.EnumeratedSets.parent_class'>,
     204     <class 'sage.categories.sets_cat.Sets.parent_class'>,
     205     <class 'sage.categories.objects.Objects.parent_class'>,
     206     <type 'object'>]
     207    sage: x.__class__.mro()
     208    [<class 'sage.categories.examples.finite_semigroups.LRBand_with_category.element_class'>,
     209     <class 'sage.categories.examples.finite_semigroups.Element'>,
     210     <class 'sage.structure.element_wrapper.ElementWrapper'>,
     211     <type 'sage.structure.element.Element'>,
     212     <type 'sage.structure.sage_object.SageObject'>,
     213     <class 'sage.categories.category.FiniteSemigroups.element_class'>,
     214     <class 'sage.categories.semigroups.Semigroups.element_class'>,
     215     <class 'sage.categories.category.FiniteEnumeratedSets.element_class'>,
     216     <class 'sage.categories.enumerated_sets.EnumeratedSets.element_class'>,
     217     <class 'sage.categories.sets_cat.Sets.element_class'>,
     218     <class 'sage.categories.objects.Objects.element_class'>,
     219     <type 'object'>]
     220
     221Tests:
     222------
     223
     224    sage: S=FiniteSemigroups().example(alphabet=('a', 'b'))
     225    sage: S.check(verbose = True)
     226    running test_an_element ... done
     227    running test_associativity ... done
     228    running test_element_pickling ... done
     229    running test_enumerated_set_contains ... done
     230    running test_enumerated_set_iter_cardinality ... done
     231    running test_enumerated_set_iter_list ... done
     232    running test_pickling ... done
     233    running test_some_elements ... done
     234    sage: S.test_associativity?? # todo: not implemented
     235    sage: S.test_associativity(elements=S)
     236
     237Let us break the code::
     238
     239    sage: %pdb                  # todo: not implemented
     240    sage: S.test_associativity()
     241
     242Wrapup:
     243 - Categories category bring not only code, but also testing tools
     244 - This enforces robustness and consistency (despite using an interpreted language)
     245
     246Advanced algebraic structures:
     247------------------------------
     248
     249    sage: HopfAlgebrasWithBasis(QQ)?? # todo: not implemented
     250    sage: HopfAlgebrasWithBasis(QQ).category_graph().plot()
     251
     252Functorial constructions
     253------------------------
     254
     255    sage: A = AlgebrasWithBasis(QQ).example(); A.rename("A")
     256    sage: B = HopfAlgebrasWithBasis(QQ).example(); B.rename("B")
     257    sage: C = direct_sum([A, B, B]); C
     258    A (+) B (+) B
     259    sage: C.one()
     260    B[(0, ())] + B[(1, ())] + B[(2, ())]
     261    sage: direct_sum([A.one(), B.one(), B.one()])
     262    B[(0, ())] + B[(1, ())] + B[(2, ())]
     263    sage: C.one??               # todo: not implemented
     264    sage: C.product??           # todo: not implemented
     265    sage: C.categories()
     266    [Join of Category of direct sums of algebras with basis over Rational Field and Category of direct sums of modules with basis over Rational Field and Category of direct sums of algebras over Rational Field,
     267     Category of direct sums of algebras with basis over Rational Field,
     268     Category of algebras with basis over Rational Field,
     269     Category of direct sums of modules with basis over Rational Field,
     270     Category of modules with basis over Rational Field,
     271     Category of vector spaces over Rational Field,
     272     Category of direct sums of algebras over Rational Field,
     273     Category of algebras over Rational Field,
     274     Category of rings,
     275     Category of rngs,
     276     Category of monoids,
     277     Category of semigroups,
     278     Category of modules over Rational Field,
     279     Category of bimodules over Rational Field on the left and Rational Field on the right,
     280     Category of left modules over Rational Field,
     281     Category of right modules over Rational Field,
     282     Category of abelian groups,
     283     Category of abelian monoids,
     284     Category of abelian semigroups,
     285     Category of sets,
     286     Category of objects]
     287
     288Wrapup:
     289 - All the mathematical information about algebras with basis is
     290   gathered in AlgebrasWithBasis
     291
     292Hierarchies for categories and classes
     293--------------------------------------
     294
     295In which class should be direct_sum([A, B]) ?
     296 - A vector space, or not
     297 - An algebra, or not
     298 - A coalgebra, or not
     299 - A differential module, or not
     300 - finite dimensional, graded, or nothing
     301
     302Other functorial constructions:
     303
     304 - cartesian product
     305 - quotient / sub / subquotient
     306 - direct sum
     307 - tensor product
     308 - dual
     309
     310 - morphisms
     311
     312Flavors of categories:
     313 - finite dimensional / graded / graded connected
     314 - finite / infinite
     315
     316Wrapup:
     317 - There is a combinatorial explosion of potential classes
     318 - This explosion can be controlled by implementing "few" building
     319   blocks, and using dynamic classes to *compose* them together,
     320   lazily, according to the needs.
     321
     322
     323Writing new categories
     324----------------------
     325
     326Each category should come with a good example, in examples/....
     327
     328The order between super categories should not be mathematically
     329relevant (otherwise this usually means the caregory hierarchy is
     330wrong). One the other hand, it should be consistent, to help python
     331build the method resolution order for the generated classes (it always
     332respect inheritance, and tries to respect the order of the bases).
     333
     334The current convention is to order them lexicographically w.r.t. the
     335following criterions:
     336
     337 - Graded... or Finite dimensional... first
     338 - ...WithBasis first
     339 - Algebras before Coalgebras
     340 - Modules first
     341
     342This gives the following order:
     343
     344    sage: GradedHopfAlgebrasWithBasis(QQ).all_super_categories()
     345    [Category of graded hopf algebras with basis over Rational Field,
     346     Category of graded bialgebras with basis over Rational Field,
     347     Category of graded algebras with basis over Rational Field,
     348     Category of graded coalgebras with basis over Rational Field,
     349     Category of graded modules with basis over Rational Field,
     350     Category of graded hopf algebras over Rational Field,
     351     Category of graded bialgebras over Rational Field,
     352     Category of graded algebras over Rational Field,
     353     Category of graded coalgebras over Rational Field,
     354     Category of graded modules over Rational Field,
     355     Category of hopf algebras with basis over Rational Field,
     356     Category of bialgebras with basis over Rational Field,
     357     Category of algebras with basis over Rational Field,
     358     Category of coalgebras with basis over Rational Field,
     359     Category of modules with basis over Rational Field,
     360     Category of vector spaces over Rational Field,
     361     Category of hopf algebras over Rational Field,
     362     Category of bialgebras over Rational Field,
     363     Category of algebras over Rational Field,
     364     Category of rings,
     365     Category of rngs,
     366     Category of monoids,
     367     Category of semigroups,
     368     Category of coalgebras over Rational Field,
     369     Category of modules over Rational Field,
     370     Category of bimodules over Rational Field on the left and Rational Field on the right,
     371     Category of left modules over Rational Field,
     372     Category of right modules over Rational Field,
     373     Category of abelian groups,
     374     Category of abelian monoids,
     375     Category of abelian semigroups,
     376     Category of sets,
     377     Category of objects]
     378
     379Todo: any better convention? Maybe we should further specify that subcategories of Modules() go first?
     380
     381"""
  • sage/categories/category.py

    diff --git a/sage/categories/category.py b/sage/categories/category.py
    a b Categories 
    33
    44AUTHORS:
    55
    6 - David Kohel and William Stein
     6- David Kohel, William Stein and Nicolas M. Thiery
    77
    88Every Sage object lies in a category. Categories in Sage are
    99modeled on the mathematical idea of category, and are distinct from
    category to which `x` belongs. If `C` is 
    1414and `x` is any object, `C(x)` tries to make an
    1515object in `C` from `x`.
    1616
     17See Category? for more details.
     18
    1719EXAMPLES: We create a couple of categories.
    1820
    1921::
    example, 
    4446#*****************************************************************************
    4547#  Copyright (C) 2005 David Kohel <kohel@maths.usyd.edu> and
    4648#                     William Stein <wstein@math.ucsd.edu>
     49#                     Nicolas M. Thiery <nthiery at users.sf.net>
    4750#
    4851#  Distributed under the terms of the GNU General Public License (GPL)
    4952#
    example, 
    5760#                  http://www.gnu.org/licenses/
    5861#*****************************************************************************
    5962
    60 __doc_exclude = ['k', 'uniq', 'uniq1', 'latex', \
     63__doc_exclude = ['k', 'latex', \
    6164                 'Category', 'Category_ideal', 'Category_in_ambient', \
    6265                 'Category_module', 'Category_over_base', \
    6366                 'Category_over_base_ring','SageObject']
    6467
    65 import weakref
    6668from sage.misc.latex import latex
    6769from sage.structure.sage_object import SageObject
     70from sage.structure.unique_representation import UniqueRepresentation
     71from sage.structure.dynamic_class import dynamic_class
    6872
     73from sage import graphs
     74from sage.misc.lazy_attribute import lazy_attribute
     75from sage.misc.cachefunc import cached_function, cached_method
     76from sage.misc.misc import attrcall
    6977
    70 class Category(SageObject):
    71     """
    72     The base class for all categories.
     78class SageObjectHack(SageObject):  # Ugly temporary? workaround; see doc of UniqueRepresentation
     79    __new__ = object.__new__
     80
     81class Category(UniqueRepresentation, SageObjectHack):
     82    r"""
     83    The base class for all categories in Sage.
     84
     85    .. rubric:: Purpose
     86
     87    The purpose of categories in Sage is to translate the mathematical
     88    concept of categories (category of groups, of vector spaces, ...)
     89    into a concrete software engineering design pattern for:
     90    - organizing and promoting generic code
     91    - fostering consistency across the Sage library (naming conventions, doc, tests)
     92    - putting mathematical knowledge into the system
     93
     94    This design pattern is largely inspired from Axiom and its
     95    followers (Aldor, Fricas, MuPAD, ...). It differs from those by:
     96
     97    - blending in the Magma inspired concept of Parent/Element
     98
     99    - being built on top of (and not into) the standard python object
     100      oriented and class hierarchy mechanism. This did not require
     101      changing the language, and could in principle be implemented in
     102      any language allowing for dynamically creating new classes.
     103   
     104    .. rubric:: Implementation
     105   
     106    A category in Sage models a mathematical category. It is dictinct
     107    from Python classes, which are a programming construct.  Here are
     108    some examples:
     109
     110    \begin{description}
     111    \item[Groups()] the category of groups
     112    \item[EuclideanRings()] the category of euclidean rings
     113    \item[VectorSpaces(QQ)] the category of vector spaces over the field of rational
     114    \end{description}
     115
     116    Technically, a category is an instance of the class
     117    :class:`Category` of some of its subclasses. Some categories, like
     118    VectorSpaces, are parametrized: ``VectorSpaces(QQ)`` is one of
     119    many instances of the class :class:`VectorSpaces`. On the other
     120    hand, ``EuclideanRings()`` is the single instance of the class
     121    :class:`EuclideanRings`.
     122
     123    Recall that an algebraic structure (say the ring QQ[x]) is
     124    modelled in Sage by an object which is called a parent. This
     125    object belongs to certain categories (here EuclideanRings() and
     126    Algebras()). The elements of the ring are themselves objects.
     127   
     128    The class of a category (say EuclideanRings) can define simultaneously:
     129    \begin{itemize}
     130    \item Operations on the category itself (what are its super categories, its category of
     131      morphisms?, its dual category)
     132    \item Generic operations on parents in this category, like the ring QQ[x]
     133    \item Generic operations on elements (Euclide algorithm for computing gcds)
     134    \end{itemize}
     135
     136    This is achieved as follows:
     137
     138      sage: from sage.categories.all import Category
     139      sage: class EuclideanRings(Category):
     140      ...       # operations on the category itself
     141      ...       def super_categories(self):
     142      ...           [Rings()]
     143      ...
     144      ...       def dummy(self): # TODO: find some good examples
     145      ...            pass
     146      ... 
     147      ...       class ParentMethods: # holds the generic operations on parents
     148      ...            # find a good example of operation
     149      ...            pass
     150      ... 
     151      ...       class ElementMethods:# holds the generic operations on elements
     152      ...            def gcd(x,y):
     153      ...                # Euclid algorithms
     154      ...                pass
     155
     156    Note that the EuclideanRings.ParentMethods and .Element class above do
     157    not inherit from anything. They are merely containers of
     158    operations. The hierarchy between the different categories is
     159    defined once at the level of the categories. Behind the scene, a
     160    parallel hierarchy of classes is built automatically from all the
     161    .ParentMethods classes. Then, a parent in a category receives the
     162    appropriate operations from all the super categories by usual
     163    class inheritance. Similarly, a third hierarchy of classes is
     164    built for elements from the .Elements.
     165
     166    EXAMPLES:
     167
     168    We define a hierarchy of four categories As(), Bs(), Cs(), Ds()
     169    with a diamond inheritance. Think for example:
     170    \begin{description}
     171    \item[As()] the category of sets
     172    \item[Bs()] the category of additive groups
     173    \item[Cs()] the category of multiplicative monoids
     174    \item[Ds()] the category of rings
     175    \end{description}
     176      sage: from sage.categories.all import Category
     177      sage: from sage.misc.lazy_attribute import lazy_attribute
     178      sage: class As (Category):
     179      ...       @cached_method
     180      ...       def super_categories(self):
     181      ...           return []
     182      ...
     183      ...       class ParentMethods:
     184      ...           def fA(self):
     185      ...               return "A"
     186      ...           f = fA
     187      ...
     188      sage: class Bs (Category):
     189      ...       @cached_method
     190      ...       def super_categories(self):
     191      ...           return [As()]
     192      ...
     193      ...       class ParentMethods:
     194      ...           def fB(self):
     195      ...               return "B"
     196      ...
     197      sage: class Cs (Category):
     198      ...       @cached_method
     199      ...       def super_categories(self):
     200      ...           return [As()]
     201      ...
     202      ...       class ParentMethods:
     203      ...           def fC(self):
     204      ...               return "C"
     205      ...           f = fC
     206      ...
     207      sage: class Ds (Category):
     208      ...       @cached_method
     209      ...       def super_categories(self):
     210      ...           return [Bs(),Cs()]
     211      ...
     212      ...       class ParentMethods:
     213      ...           def fD(self):
     214      ...               return "D"
     215      ...                                                           
     216
     217    Categories should always have uniq representation. We check
     218    this before proceeding:
     219
     220      sage: id(As()) == id(As())
     221      True
     222      sage: As().parent_class == As().parent_class
     223      True
     224
     225    We construct a parent in the category Ds() (that is an instance of
     226    Ds().parent_class, and check that it has access to all the
     227    methods provided by all the categories, with the appropriate
     228    inheritance order.
     229
     230      sage: D = Ds().parent_class()
     231      sage: [ D.fA(), D.fB(), D.fC(), D.fD() ]
     232      ['A', 'B', 'C', 'D']
     233      sage: D.f()
     234      'C'
     235
     236      sage: C = Cs().parent_class()
     237      sage: [ C.fA(), C.fC() ]
     238      ['A', 'C']
     239      sage: C.f()
     240      'C'
     241
     242    Here is the parallel hierarchy of classes which has been built
     243    automatically, together with the method resolution order (.mro()):
     244
     245      sage: As().parent_class
     246      <class '__main__.As.parent_class'>
     247      sage: As().parent_class.__bases__
     248      (<type 'object'>,)
     249      sage: As().parent_class.mro()
     250      [<class '__main__.As.parent_class'>, <type 'object'>]
     251
     252      sage: Bs().parent_class
     253      <class '__main__.Bs.parent_class'>
     254      sage: Bs().parent_class.__bases__
     255      (<class '__main__.As.parent_class'>,)
     256      sage: Bs().parent_class.mro()
     257      [<class '__main__.Bs.parent_class'>, <class '__main__.As.parent_class'>, <type 'object'>]
     258
     259      sage: Cs().parent_class
     260      <class '__main__.Cs.parent_class'>
     261      sage: Cs().parent_class.__bases__
     262      (<class '__main__.As.parent_class'>,)
     263      sage: Cs().parent_class.__mro__
     264      (<class '__main__.Cs.parent_class'>, <class '__main__.As.parent_class'>, <type 'object'>)
     265
     266      sage: Ds().parent_class
     267      <class '__main__.Ds.parent_class'>
     268      sage: Ds().parent_class.__bases__
     269      (<class '__main__.Bs.parent_class'>, <class '__main__.Cs.parent_class'>)
     270      sage: Ds().parent_class.mro()
     271      [<class '__main__.Ds.parent_class'>, <class '__main__.Bs.parent_class'>, <class '__main__.Cs.parent_class'>, <class '__main__.As.parent_class'>, <type 'object'>]
     272
     273    Note that that two categories in the same class need not have the
     274    same super_categories. For example, Algebras(QQ) has
     275    VectorSpaces(QQ) as super category, whereas Algebras(ZZ) only has
     276    Modules(ZZ) as super category. In particular, the constructed
     277    parent_class and element_class will differ (inheriting, or not,
     278    methods specific for vector spaces). On the other hand, caching
     279    ensures that two identical hierarchy of classes are built only
     280    once:
     281      # TODO: redo the same with Algebras
     282      # and show the mro for Algebras(QQ) w.r.t Algebras(ZZ)
     283      # 2009/03/11: this feature is temporarily broken, due to the current work around for pickling
     284      sage: Coalgebras(QQ).parent_class is Coalgebras(FractionField(QQ[x])).parent_class # todo: not implemented
     285      True
     286
     287    We now construct a parent in the usual way:
     288
     289      sage: class myparent(Parent):
     290      ...       def __init__(self):
     291      ...           Parent.__init__(self, category=Ds())
     292      ...       def g(self):
     293      ...           return "myparent"
     294      ...       class Element:
     295      ...           pass
     296      sage: D = myparent()
     297      sage: D.__class__
     298      <class '__main__.myparent_with_category'>
     299      sage: D.__class__.__bases__
     300      (<class '__main__.myparent'>, <class '__main__.Ds.parent_class'>)
     301      sage: D.__class__.mro()
     302      [<class '__main__.myparent_with_category'>,
     303       <class '__main__.myparent'>,
     304       <type 'sage.structure.parent.Parent'>,
     305       <type 'sage.structure.category_object.CategoryObject'>,
     306       <type 'sage.structure.sage_object.SageObject'>,
     307       <class '__main__.Ds.parent_class'>,
     308       <class '__main__.Bs.parent_class'>,
     309       <class '__main__.Cs.parent_class'>,
     310       <class '__main__.As.parent_class'>,
     311       <type 'object'>]
     312      sage: D.fA()
     313      'A'
     314      sage: D.fB()
     315      'B'
     316      sage: D.fC()
     317      'C'
     318      sage: D.fD()
     319      'D'
     320      sage: D.f()
     321      'C'
     322      sage: D.g()
     323      'myparent'
     324
     325      sage: D.element_class
     326      <class '__main__.myparent_with_category.element_class'>
     327      sage: D.element_class.mro()
     328      [<class '__main__.myparent_with_category.element_class'>,
     329       <class __main__.Element at ...>,
     330       <class 'sage.categories.category.Ds.element_class'>,
     331       <class 'sage.categories.category.Bs.element_class'>,
     332       <class 'sage.categories.category.Cs.element_class'>,
     333       <class 'sage.categories.category.As.element_class'>,
     334       <type 'object'>]
     335
     336
     337    TESTS:
     338        sage: import __main__
     339        sage: __main__.myparent = myparent
     340        sage: __main__.As = As
     341        sage: __main__.Bs = Bs
     342        sage: __main__.Cs = Cs
     343        sage: __main__.Ds = Ds
     344        sage: loads(dumps(Ds)) is Ds
     345        True
     346        sage: loads(dumps(Ds())) is Ds()
     347        True
     348        sage: loads(dumps(Ds().element_class)) is Ds().element_class
     349        True
     350
    73351    """
    74352    def __init__(self, s=None):
    75353        if s is None:  # figure out from the type name!
    class Category(SageObject): 
    105383        return "\\mathbf{%s}"%self.__label
    106384
    107385    def __hash__(self):
    108         return hash(self.__category)
     386        return hash(self.__category) # Any reason not to use id?
    109387
    110388    def short_name(self):
    111389        return ''.join([x.capitalize() for x in self.__category.split()])
    class Category(SageObject): 
    120398    def is_abelian(self):
    121399        return False
    122400
     401    def category_graph(self):
     402         r"""
     403         Returns the graph of all super categories of this category
     404         """
     405         done = set()
     406         categories = self.all_super_categories()
     407         def name(cat):
     408             return repr(cat)[12:]
     409         g = graphs.graph.DiGraph()
     410         for cat in categories:
     411             g.add_vertex(name(cat))
     412         for source in categories:
     413             for target in source.super_categories():
     414                 g.add_edge([name(source), name(target)])
     415         return g
     416
     417    @cached_method
     418    def all_super_categories(self, proper = False):
     419        r"""
     420        INPUT:
     421         - ``proper``: a boolean; defaults to False
     422       
     423        Returns a linear extension (topological sort) of all the
     424        (proper) super categories of this category, and cache the
     425        result.
     426
     427        FIXME: make sure that this is compatible with the python
     428        algorithm for method resolution and make it O(n+m)
     429        """
     430#            done = set()
     431        all_categories = []
     432        def add_successors(cat): # Factor this out!
     433#                if cat in done:
     434#                    return;
     435#                done.add(cat)
     436            for super in cat.super_categories():
     437                all_categories.append(super)
     438                add_successors(super)
     439        add_successors(self)
     440        all_categories.reverse()
     441        done = set()
     442        linear_extension = []
     443        for cat in all_categories:
     444            if not cat in done:
     445                done.add(cat)
     446                linear_extension.append(cat)
     447        linear_extension.reverse()
     448        if proper:
     449            return linear_extension
     450        else:
     451            return [self] + linear_extension
     452
     453    def construction(self):
     454        return (self.__class__,)
     455
     456#    def __reduce__(self):
     457#        construction = self.construction()
     458#        return (construction[0], construction[1:])
     459
     460    class ParentMethods:
     461        pass
     462
     463    class ElementMethods:
     464        pass
     465
     466    @lazy_attribute
     467    def parent_class(self):
     468        return dynamic_class("%s.parent_class"%self.__class__.__name__,
     469                             tuple(cat.parent_class for cat in self.super_categories()),
     470                             self.ParentMethods,
     471                             reduction = (getattr, (self, "parent_class")))
     472
     473    @lazy_attribute
     474    def element_class(self):
     475        return dynamic_class("%s.element_class"%self.__class__.__name__,
     476                             (cat.element_class for cat in self.super_categories()),
     477                             self.ElementMethods,
     478                             reduction = (getattr, (self, "element_class"))
     479                             )
     480
     481    # Operations on the lattice of categories
     482
    123483    def is_subcategory(self, c):
    124484        """
    125485        Returns True if self is naturally embedded as a subcategory of c.
    class Category(SageObject): 
    142502            sage: M9 = VectorSpaces(FiniteField(9, 'a'))
    143503            sage: M3.is_subcategory(M9)
    144504            False
     505
     506        TODO: handle join categories properly::
     507       
     508            sage: Rings().is_subcategory(Category.join(AbelianGroups(), SemiGroups())) # todo: not implemented
     509            True
     510
     511           
    145512        """
    146         if not isinstance(c, Category):
    147             raise TypeError, "Argument c (= %s, type = %s) must be a category"%(c, type(c))
    148         if self == c: return True
    149         from category_types import category_hierarchy
    150         if category_hierarchy.has_key(self.__class__):
    151             S = category_hierarchy[self.__class__]
    152             if not c.__class__ in S:
    153                 return False
    154             return c._parameters().issubset(self._parameters())
    155         return False
     513        assert(isinstance(c, Category))
     514#        print "%s in %s: %s"%(self, c, c in self.all_super_categories())
     515        return c in self.all_super_categories()
    156516
    157517    def _is_subclass(self, c,):
    158         from category_types import category_hierarchy
     518        """
     519        Same as is_subcategory, but c may also be the class of a
     520        category instead of a category.
     521
     522        EXAMPLE:
     523            sage: Fields()._is_subclass(Rings)
     524            True
     525            sage: Algebras(QQ)._is_subclass(Modules)
     526            True
     527            sage: Algebras(QQ)._is_subclass(ModulesWithBasis)
     528            False
     529        """
     530        assert( isinstance(c, Category) or (issubclass(c.__class__, type) and issubclass(c, Category)) )
    159531        if isinstance(c, Category):
    160532            return self.is_subcategory(c)
    161         if self.__class__ == c:
    162             return True
    163         return c in category_hierarchy[self.__class__]
     533        else:
     534            return any(isinstance(cat, c) for cat in self.all_super_categories())
    164535
    165     def __eq__(self, c):
    166         if self is c:
    167             return True
    168         return False
     536    def meet(self, other):
     537        """
     538        Returns the largest common subcategory of self and other:
     539
     540        EXAMPLES:
     541            sage: Monoids().meet(Monoids())
     542            Category of monoids
     543            sage: Rings().meet(Rings())
     544            Category of rings
     545            sage: Rings().meet(Monoids())
     546            Category of monoids
     547            sage: Monoids().meet(Rings())
     548            Category of monoids
     549
     550        Currently this is only implemented if one of the two is a
     551        subcategory of the other.
     552
     553        Note: abstractly, the category poset is a distributive
     554        lattice, so this is well defined; however, the subset of those
     555        categories actually implemented is not: we need to also
     556        include their join-categories.
     557
     558        For example, the category of rings is *not* the join of the
     559        category of abelian groups and that of semi groups, just a
     560        subcategory of there join, since rings further require
     561        distributivity.
     562
     563        For the meet computation, there may be several lowest common
     564        sub categories of self and other, in which case, we need to
     565        take the join of them all.
     566       
     567        # FIXME: if A is a subcategory of B, A has *more* structure
     568        # than B, but then *less* objects in there. We should choose
     569        # an appropriate convention for A<B.
     570        # using subcategory calls for A<B, but the current meet and join
     571        # call for A>B
     572        """
     573        if self is other:
     574            return self
     575        elif self.is_subcategory(other):
     576            return other
     577        elif other.is_subcategory(self):
     578            return self
     579        else:
     580            raise NotImplementedError, "computation of the meet of incomparable categories"
     581
     582    def join(*categories, **options):
     583        """
     584        Returns the join of the input categories in the lattice of categories
     585
     586        INPUT:
     587         - a sequence of categories (FIXME: should this be a list or iterable?)
     588         - as_list: a boolean, False by default
     589
     590        EXAMPLES:
     591            sage: J = Category.join(Groups(), AbelianMonoids()); J
     592            Join of Category of groups and Category of abelian monoids
     593            sage: J.super_categories()
     594            [Category of groups, Category of abelian monoids]
     595            sage: J.all_super_categories(proper = True)
     596            [Category of groups, Category of monoids, Category of semigroups, Category of abelian monoids, Category of abelian semigroups, Category of sets, Category of objects]
     597
     598        This is an associative operation:
     599            sage: Category.join(Objects(), Sets(), Category.join(Monoids(), Sets(), Monoids()), Category.join(Objects(), AbelianGroups()))
     600            Join of Category of monoids and Category of abelian groups
     601
     602        The join of a single category is the category itself:
     603            sage: Category.join(Monoids())
     604            Category of monoids
     605
     606        Similarly, the join of several mutually comparable categories is the smallest one:
     607            sage: Category.join(Sets(), Rings(), Monoids())
     608            Category of rings
     609
     610        If the optional parameter as_list is True, then just return
     611        the super categories of the join as a list, without
     612        constructing the join category:
     613
     614            sage: Category.join(Groups(), AbelianMonoids(), as_list=True)
     615            [Category of groups, Category of abelian monoids]
     616            sage: Category.join(Sets(), Rings(), Monoids(), as_list=True)
     617            [Category of rings]
     618
     619        """
     620
     621        # Since Objects() is the top category, it is the neutral element of join
     622        if len(categories) == 0:
     623            from objects import Objects
     624            return Objects()
     625       
     626        # Ensure associativity by flattening JoinCategory's
     627        # Invariant: the super categories of a JoinCategory are not JoinCategories themselves
     628        categories = sum( (tuple(category.super_categories()) if isinstance(category, JoinCategory) else (category,)
     629                           for category in categories), ())
     630
     631        # remove redundant categories which are super categories of others
     632        result = []
     633        for category in categories:
     634            if any(cat.is_subcategory(category) for cat in result):
     635                continue
     636            result = [ cat for cat in result if not category.is_subcategory(cat) ]
     637            result.append(category)
     638        if "as_list" in options and options["as_list"]:
     639            return result
     640        if len(result) == 1:
     641            return result[0]
     642        else:
     643            return JoinCategory(*result)
    169644
    170645    def _parameters(self):
    171646        return set([])
    172647
    173648    def category(self):
     649        """
     650        Returns the category of this category. So far all categories
     651        are in the category of objects.
     652       
     653        EXAMPLES:
     654            sage: Sets().category()
     655            Category of objects
     656            sage: VectorSpaces(QQ).category()
     657            Category of objects
     658        """
     659        from objects import Objects
    174660        return Objects()
    175661
     662    def hom_category(self):
     663        """
     664        Returns the category for homsets between objects this category.
     665
     666        A category which needs to give specific information about this
     667        category should provide a HomCategory class.
     668
     669        To avoid generating billions of categories, if there is
     670        nothing specific for homsets of this category, then this just
     671        returns the join of the categories of homsets of the super
     672        categories.
     673
     674        EXAMPLES:
     675            sage: Sets().hom_category()
     676            Category of hom sets of Category of sets
     677
     678        """
     679        if hasattr(self, "HomCategory"):
     680            return self.HomCategory(self)
     681        else:
     682            return Category.join(*[category.hom_category() for category in self.super_categories()])
     683
     684    def abstract_category(self):
     685        """
     686        An abstract parent is a parent which models an abstract
     687        algebraic structure which has several concrete representations.
     688
     689        This returns a mostly technical category which provides
     690        support tools for handling the different representation, and
     691        in particular the coercions between them.
     692
     693        Typically, ``FiniteDimensionalModulesWithBasis(QQ).abstract_category()``
     694        will be in charge, whenever a coercion `\phi: A\mapsto B` is
     695        registered, to register `\phi^{-1}` as coercion `B \mapsto A`
     696        if there is none defined yet.
     697
     698        This is the analog of the *WithSeveralBases in MuPAD-Combinat
     699
     700        TODO: find a better name!
     701
     702        The hierarchy of all abstract categories is built in parallel
     703        to that of their base categories, optimizing away those
     704        categories which do not have an AbstractCategory.
     705
     706        Design question: currently ``self.abstract_category()`` is a
     707        subcategory of self by default. Is this desirable? For example,
     708        ``Algebras(QQ).abstract_category()`` should definitely be a
     709        subcategory of ``Algebras(QQ)``. On the other hand,
     710        ``AlgebrasWithBasis(QQ).abstract_category()`` should be a
     711        subcategory of ``Algebras(QQ)``, but not of
     712        ``AlgebrasWithBasis(QQ)``. This is because
     713        ``AlgebrasWithBasis(QQ)`` is specifying something about the
     714        concrete representation.
     715
     716        EXAMPLES::
     717
     718            sage: Semigroups().abstract_category()
     719            Category of semigroups
     720            sage: C = GradedHopfAlgebrasWithBasis(QQ).abstract_category(); C
     721            Category of abstract graded hopf algebras with basis over Rational Field
     722            sage: C.all_super_categories()
     723            [Category of abstract graded hopf algebras with basis over Rational Field,
     724             Category of graded hopf algebras over Rational Field,
     725             Category of graded bialgebras over Rational Field,
     726             Category of graded algebras over Rational Field,
     727             Category of graded coalgebras over Rational Field,
     728             Category of graded modules over Rational Field,
     729             Category of hopf algebras over Rational Field,
     730             Category of bialgebras over Rational Field,
     731             Category of algebras over Rational Field,
     732             ...]
     733
     734        """
     735        if hasattr(self, "AbstractCategory"):
     736            return self.AbstractCategory(self)
     737        else:
     738            return Category.join(*([self]+[category.abstract_category() for category in self.super_categories()]))
     739
     740    def example(self, *args, **keywords):
     741        """
     742        Returns an object in this category. Most of the time, this is a parent.
     743
     744        This serves three purposes:
     745         - Give a typical example to better explain what the category is all about.
     746           (and by the way prove that the category is non empty :-) )
     747         - Provide a minimal template for implementing other objects in this category
     748         - Provide an object on which to test generic code implemented by the category
     749
     750        For all those applications, the implementation of the object
     751        shall be kept to a strict minimum. The object is therefore not
     752        meant to be used for other applications; most of the time a
     753        full featured version is available elsewhere in Sage, and
     754        should be used insted.
     755
     756        Technical note: by default FooBar(...).example() is
     757        constructed by looking up
     758        sage.categories.examples.foo_bar.Example and calling it as
     759        ``Example(category = FooBar)``. Extra positional or named
     760        parameters are also passed down. Categories are welcome to
     761        override this.
     762
     763        """
     764        module_name = self.__module__.replace("sage.categories", "sage.categories.examples")
     765        import sys
     766        try:
     767            __import__(module_name)
     768            module = sys.modules[module_name]
     769        except ImportError:
     770            return NotImplemented
     771        try:
     772            cls = module.Example
     773        except AttributeError:
     774            return NotImplemented
     775        return cls(*args, **keywords)
     776       
     777
    176778def is_Category(x):
    177779    """
    178780    Returns True if x is a category.
    179781    """
    180782    return isinstance(x, Category)
    181783
     784#############################################################
     785# Homsets categories
     786#############################################################
     787
     788class HomCategory(Category):
     789    """
     790    An abstract base class for all categories of homsets
     791
     792    The hierarchy of homset categories is built in parallel to that of
     793    their base categories (which is plain wrong!!!)
     794
     795    """
     796    def __init__(self, category, name=None):
     797        Category.__init__(self, name)
     798        self.base_category = category
     799
     800    def _repr_(self): # improve?
     801        """
     802        EXAMPLES::
     803       
     804            sage: Sets().hom_category()
     805            Category of hom sets of Category of sets
     806        """
     807        return "Category of hom sets of %s"%self.base_category
     808        # possible variant:
     809        # s = repr(self.base_category)
     810        # return s[:11]+" hom sets"+s[11:]
     811
     812    def construction(self):
     813        return (attrcall("hom_category"), self.base_category)
     814
     815    @cached_method
     816    def super_categories(self):
     817        return Category.join(as_list=True,
     818                             *(self.extra_super_categories() +
     819                               [category.hom_category()
     820                                for category in self.base_category.super_categories()]))
     821    @cached_method
     822    def extra_super_categories(self):
     823        """
     824        The super categories of self that are not derived from the
     825        inheritance diagram of the base category, as a list
     826        """
     827        return []
     828
    182829
    183830#############################################################
    184 # ...
     831# Categories of abstract parents
    185832#############################################################
    186 cache = {}
    187 class uniq(object):
    188     def __new__(cls):
    189         global cache
    190         if cache.has_key(cls):
    191             return cache[cls]
    192         O = object.__new__(cls)
    193         cache[cls] = O
    194         return O
    195833
     834class AbstractCategory(Category):
     835    """
     836    An abstract base class for all categories of abstract parents
    196837
    197 cache1 = {}
    198 class uniq1(object):
    199     def __new__(cls, arg1):
    200         global cache1
    201         key = (cls, arg1)
    202         if cache1.has_key(key):
    203             X = cache1[key]()
    204             if X: return X
    205         O = object.__new__(cls)
    206         cache1[key] = weakref.ref(O)
    207         return O
     838    See Category.abstract_category.
     839    """
     840    def __init__(self, category, name=None):
     841        Category.__init__(self, name)
     842        self.base_category = category
     843
     844    def _repr_(self):
     845        s = repr(self.base_category)
     846        return s[:11]+" abstract"+s[11:]
     847
     848    def construction(self):
     849        return (attrcall("abstract_category"), self.base_category)
     850
     851    @cached_method
     852    def super_categories(self):
     853        return Category.join(as_list=True,
     854                             *(self.extra_super_categories() +
     855                               [category.hom_category()
     856                                for category in self.base_category.super_categories()]))
     857    @cached_method
     858    def extra_super_categories(self):
     859        """
     860        The super categories of self that are not derived from the
     861        inheritance diagram of the base category, as a list.
     862        """
     863        return [self.base_category()]
     864
    208865
    209866
    210867#############################################################
    211 # Unique category
     868# Join of several categories
    212869#############################################################
    213 class Category_uniq(uniq, Category):
    214     pass
     870
     871class JoinCategory(Category):
     872    """
     873    A class for joins of several categories. Do not use directly;
     874    see Category.join instead.
     875
     876    EXAMPLES:
     877        sage: from sage.categories.category import JoinCategory
     878        sage: J = JoinCategory(Groups(), AbelianMonoids()); J
     879        Join of Category of groups and Category of abelian monoids
     880        sage: J.super_categories()
     881        [Category of groups, Category of abelian monoids]
     882        sage: J.all_super_categories(proper = True)
     883        [Category of groups, Category of monoids, Category of semigroups, Category of abelian monoids, Category of abelian semigroups, Category of sets, Category of objects]
     884
     885     TESTS:
     886        sage: from sage.categories.category import JoinCategory
     887        sage: C = JoinCategory(Groups(), AbelianMonoids())
     888        sage: loads(C.dumps()) == C
     889        True
     890    """
     891
     892    def __init__(self, *super_categories):
     893        assert(len(super_categories) >= 2)
     894        assert(all(not isinstance(category, JoinCategory) for category in super_categories))
     895        Category.__init__(self)
     896        self._super_categories = list(super_categories)
     897
     898    def super_categories(self):
     899        return self._super_categories
     900
     901    def _repr_(self):
     902        return "Join of %s"%(" and ".join(str(cat) for cat in self.super_categories()))
    215903
    216904#############################################################
    217 # Sets
     905# Covariant functors
     906# TODO: find a more appropriate names
    218907#############################################################
    219908
    220 class Sets(Category_uniq):
     909class CovariantFunctor(SageObject):
    221910    """
    222     The category of sets.
    223911
    224     EXAMPLES:
    225         sage: Sets()
    226         Category of sets
     912    An abstract class for functors F (say F = cartesian product,
     913    tensor product, direct sum, ...) such that:
     914
     915     - Each category Cat (say Cat=Groups()) can provide a category
     916       FOf(Cat)for parents constructed via this functor (say
     917       FOf(Cat) = CartesianProductsOf(Groups())).
     918
     919     - For parents A, B, C respectively in the categories CatA, CatB,
     920       CatC, the category of F(A,B,C) is defined by taking the join of
     921       FOf(CatD) for every common super category of CatA, CatB, CatC.
     922
     923
     924    Note: CartesianProductsOf(Groups) needs not to specify that it is
     925    a subcategory of CartesianProductsOf(Monoids). This part of the
     926    hierarchy is taken care automatically.
     927
     928    FIXME: Rework entirely the internal mechanism. In particular,
     929    CartesianProductsOf(Monoids) should be added automatically to the
     930    super_categories of CartesianProductsOf(Monoids).
     931
     932    Should FOf(Cat) be simply written F(Cat)? I.e. do we want to use
     933    the syntax tensor(Groups())
     934       
    227935    """
    228     def __call__(self, X):
     936
     937    def category_from_parents(self, parents):
    229938        """
    230         EXAMPLES:
    231             sage: Sets()(ZZ)
    232             Set of elements of Integer Ring
     939        INPUT:
     940         - self: a functor F
     941         - parents: a list (or iterable) of categories
     942
     943        Returns the category of F(parents).
    233944        """
    234         import sage.sets.all
    235         return sage.sets.all.Set(X)
     945        from sage.structure.parent import Parent
     946        assert(all(isinstance(parent, Parent) for parent in parents))
     947        return self.category_from_categories(tuple(set(parent.category() for parent in parents)))
    236948
    237     def __reduce__(self):
     949    @cached_method
     950    def category_from_categories(self, categories):
    238951        """
    239         For pickling.
    240        
    241         TESTS:
    242             sage: loads(dumps(Sets())) is Sets()
    243             True
     952        INPUT:
     953         - self: a functor `F`
     954         - categories: a tuple of categories
     955
     956        Returns the category of `F(A,B,C)` for `A,B,C` parents in the given categories
    244957        """
    245         return Sets, tuple([])
     958        assert(len(categories) > 0)
     959
     960        super_categories_of_first  = categories[0].all_super_categories()
     961        super_categories_of_others = [set(category.all_super_categories())
     962                                      for category in categories[1:len(categories)] ]
     963
     964        return Category.join(*(getattr(category, self.functor_category)()
     965                               for category in super_categories_of_first
     966                               if isinstance(category, self.FunctorialCategory) and
     967                               all(category in categories for categories in super_categories_of_others)))
     968
     969    def __call__(self, args):
     970        """
     971        INPUT:
     972         - self: a functor `F`
     973         - args: a tuple (or iterable) of parents or elements
     974
     975        Returns `F(args)`
     976        """
     977        args = tuple(args) # a bit brute force; let's see if this becomes a bottleneck later
     978        assert(all( hasattr(arg, self.functor_name) for arg in args))
     979        assert(len(args) > 0)
     980        return getattr(args[0].__class__, self.functor_name)(*args)
  • sage/categories/category_types.py

    diff --git a/sage/categories/category_types.py b/sage/categories/category_types.py
    a b  
    1 """
     1"""
    22Specific category classes.
    33
    44This is placed in a separate file from categories.py to avoid circular imports
    This is placed in a separate file from c 
    2121#                  http://www.gnu.org/licenses/
    2222#*****************************************************************************
    2323
     24from sage.misc.cachefunc import cached_method
    2425from category import *
    2526from sage.rings.ring import is_Ring
    2627from sage.rings.field import is_Field
    27 from sage.algebras.algebra import is_Algebra
     28"""
    2829
     30#*****************************************************************************
     31#  Copyright (C) 2005 David Kohel <kohel@maths.usyd.edu> and
     32#                     William Stein <wstein@math.ucsd.edu>
     33#
     34#  Distributed under the terms of the GNU General Public License (GPL)
     35#
     36#    This code is distributed in the hope that it will be useful,
     37#    but WITHOUT ANY WARRANTY; without even the implied warranty
     38#    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     39#
     40#  See the GNU General Public License for more details; the full text
     41#  is available at:
     42#
     43#                  http://www.gnu.org/licenses/
     44#*****************************************************************************
    2945
     46from category import *
     47from sage.rings.ring import is_Ring
     48from sage.rings.field import is_Field
     49(as morphisms must be very low in the hierarchy with the new coercion model).
     50"""
     51
     52#*****************************************************************************
     53#  Copyright (C) 2005 David Kohel <kohel@maths.usyd.edu> and
     54#                     William Stein <wstein@math.ucsd.edu>
     55#
     56#  Distributed under the terms of the GNU General Public License (GPL)
     57#
     58#    This code is distributed in the hope that it will be useful,
     59#    but WITHOUT ANY WARRANTY; without even the implied warranty
     60#    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     61#
     62#  See the GNU General Public License for more details; the full text
     63#  is available at:
     64#
     65#                  http://www.gnu.org/licenses/
     66#*****************************************************************************
     67
     68from category import *
     69from sage.rings.ring import is_Ring
     70from sage.rings.field import is_Field
    3071
    3172
    3273####################################################################
    from sage.algebras.algebra import is_Alg 
    3677#############################################################
    3778# Category of elements of some object
    3879#############################################################
    39 class Elements(uniq1, Category):
     80class Elements(Category):
    4081    """
    4182    The category of all elements of a given object.
    4283
    class Elements(uniq1, Category): 
    67108            (1, 2, 3)
    68109            sage: w.category()
    69110            Category of elements of Vector space of dimension 3 over Rational Field
     111
     112          TODO: check that this is what we want:
     113            sage: C.super_categories()
     114            [Category of objects]
    70115        """
    71116        return self.__object(x)
    72117
     118    @cached_method
     119    def super_categories(self):
     120        """
     121        EXAMPLES::
     122
     123            sage: Sets().category()
     124            Category of objects
     125
     126        """
     127        from objects import Objects
     128        return [Objects()]
     129
    73130    def object(self):
    74131        return self.__object
    75132
    class Elements(uniq1, Category): 
    91148
    92149
    93150#############################################################
    94 # Category of sequences of elements of some objects
     151# Category of sequences of elements of objects
    95152#############################################################
    96 class Sequences(uniq1, Category):
     153class Sequences(Category):
    97154    """
    98     The category of all elements of a given object.
     155    The category of sequences of elements of a given object.
    99156
    100     EXAMPLES:
     157    This category is deprecated
     158
     159    EXAMPLES::
     160
    101161        sage: v = Sequence([1,2,3]); v
    102162        [1, 2, 3]
    103163        sage: C = v.category(); C
    class Sequences(uniq1, Category): 
    111171        Category.__init__(self)
    112172        self.__object = object
    113173
     174    @cached_method
     175    def super_categories(self):
     176        """
     177        EXAMPLES::
     178
     179            sage: Sequences(ZZ).category()
     180            Category of objects
     181
     182        """
     183        from objects import Objects
     184        return [Objects()]  # Almost FiniteEnumeratedSets() except for possible repetitions
     185
    114186    def _call_(self, x):
    115187        """
    116188        EXAMPLES:
    class Sequences(uniq1, Category): 
    148220#############################################################
    149221# Category of objects over some base object
    150222#############################################################
    151 class Category_over_base(uniq1, Category):
     223class Category_over_base(Category):
    152224    def __init__(self, base, name=None):
    153225        Category.__init__(self, name)
    154226        self.__base = base
    class Category_over_base(uniq1, Category 
    165237
    166238    def _latex_(self):
    167239        return "\\mathbf{%s}_{%s}"%(self.__label, latex(self.__base))
    168    
     240
     241    def construction(self):
     242        return (self.__class__, self.__base)
     243
     244# How to deal with HomsetWithBase
     245#     def _homset(self, X, Y):
     246#         """
     247#         Given two objects X and Y in this category, returns the
     248#         collection of the morphisms of this category between X and Y
     249#         """
     250#         assert(X in self and Y in self)
     251#         from sage.categories.homset import Homset, HomsetWithBase
     252#         if X._base is not X and X._base is not None: # does this ever fail?
     253#             return HomsetWithBase(X, Y, self)
     254#         else:
     255#             return Homset(X, Y, self)
    169256
    170257#############################################################
    171258# Category of objects over some base ring
    class Category_over_base_ring(Category_o 
    184271        """
    185272        return self.base()
    186273
    187     def _parameters(self):
    188         return set([self.__base])
    189 
    190 
    191274class AbelianCategory:
    192275    def is_abelian(self):
    193276        return True
    194277
     278    @cached_method
     279    def super_categories(self):
     280        return[Groups(), AbelianMonoids()]
    195281
    196282#############################################################
    197283# Category of objects in some ambient object
    198284#############################################################
    199 class Category_in_ambient(uniq1, Category):
     285class Category_in_ambient(Category):
    200286    def __init__(self, ambient, name=None):
    201287        Category.__init__(self, name)
    202288        self.__ambient = ambient
    class Category_in_ambient(uniq1, Categor 
    211297    def _repr_(self):
    212298        return Category._repr_(self) + " in %s"%self.__ambient
    213299
    214     def _parameters(self):
    215         return set([self.__ambient])
    216 
     300    def construction(self):
     301        return (self.__class__, self.__ambient)
    217302
    218303class Category_module(Category_over_base_ring, AbelianCategory):
    219304    def __init__(self,  base, name=None):
    class Category_ideal(Category_in_ambient 
    244329            return v
    245330        return self.ring().ideal(v)
    246331
    247 
    248 
    249 
    250 ####################################################################
    251 # Actual categories (below)
    252 ####################################################################
    253        
    254 
    255 #############################################################
    256 # Generic category (default when requesting category of
    257 # an object using misc.functional.category
    258 #############################################################
    259 class Objects(Category_uniq):
    260     """
    261     The category of all Sage objects.
    262 
    263     EXAMPLES:
    264         sage: Objects()
    265         Category of objects
    266     """
    267     def __reduce__(self):
    268         return Objects, tuple([])
    269 
    270     def __contains__(self, x):
    271         return True
    272 
    273 #############################################################
    274 # Pointed Sets
    275 #############################################################
    276 
    277 class PointedSets(Category_uniq):
    278     """
    279     The category of pointed sets.
    280 
    281     EXAMPLES:
    282         sage: PointedSets()
    283         Category of pointed sets
    284     """
    285     def __call__(self, X, pt):
    286         import sage.sets.all
    287         return sage.sets.all.Set(X, pt)
    288 
    289     def __reduce__(self):
    290         return PointedSets, tuple([])
    291 
    292 #############################################################
    293 # Sets with Partial Maps
    294 #############################################################
    295 
    296 class SetsWithPartialMaps(Category_uniq):
    297     """
    298     The category whose objects are sets and whose morphisms are
    299     maps that are allowed to raise a ValueError on some inputs.
    300 
    301     This category is equivalent to the category of pointed sets,
    302     via the equivalence sending an object X to X union {error},
    303     a morphism f to the morphism of pointed sets that sends x
    304     to f(x) if f does not raise an error on x, or to error if it
    305     does.
    306 
    307     EXAMPLES:
    308         sage: SetsWithPartialMaps()
    309         Category with objects Sets and morphisms partially defined maps
    310     """
    311     def __call__(self, X, pt):
    312         import sage.sets.all
    313         return sage.sets.all.Set(X, pt)
    314 
    315     def __reduce__(self):
    316         return SetsWithPartialMaps, tuple([])
    317 
    318     def __repr__(self):
    319         return "Category with objects Sets and morphisms partially defined maps"
    320 
    321 #############################################################
    322 # GSets
    323 #     $G$-Sets play an important role in permutation groups.
    324 #############################################################
    325 class GSets(uniq1, Category):
    326     """
    327     The category of $G$-sets, for a group $G$.
    328 
    329     EXAMPLES:
    330         sage: S = SymmetricGroup(3)
    331         sage: GSets(S)
    332         Category of G-sets for SymmetricGroup(3)
    333     """
    334     def __init__(self, G):
    335         Category.__init__(self, "G-sets")
    336         self.__G = G
    337 
    338     def __repr__(self):
    339         return "Category of G-sets for %s"%self.__G
    340        
    341     def __reduce__(self):
    342         """
    343         EXAMPLES:
    344             sage: S8 = SymmetricGroup(8)
    345             sage: C = GSets(S8)
    346             sage: loads(C.dumps()) == C
    347             True
    348         """
    349         return GSets, (self.__G, )
    350 
    351 
    352 #############################################################
    353332# SimplicialComplex
    354333#############################################################
    355 class SimplicialComplexes(Category_uniq):
     334class SimplicialComplexes(Category):
    356335    """
    357336    The category of simplicial complexes.
    358337
    class SimplicialComplexes(Category_uniq) 
    371350        return SimplicialComplexes, tuple([])
    372351
    373352#############################################################
    374 # Semigroup
    375 #############################################################
    376 
    377 class Semigroups(Category_uniq):
    378     """
    379     The category of all semigroups.
    380 
    381     EXAMPLES:
    382         sage: Semigroups()
    383         Category of semigroups
    384     """
    385     def __reduce__(self):
    386         """
    387         EXAMPLES:
    388             sage: C = Semigroups()
    389             sage: loads(C.dumps()) == C
    390             True
    391         """
    392         return Semigroups, tuple([])
    393 
    394 
    395 #############################################################
    396 # Monoid
    397 #############################################################
    398 class Monoids(Category_uniq):
    399     """
    400     The category of monoids.
    401 
    402     EXAMPLES:
    403         sage: Monoids()
    404         Category of monoids
    405     """
    406 
    407     def __reduce__(self):
    408         """
    409         EXAMPLES:
    410             sage: C = Monoids()
    411             sage: loads(C.dumps()) == C
    412             True
    413         """
    414         return Monoids, tuple([])
    415    
    416 
    417 #############################################################
    418 # Groupoid
    419 #############################################################
    420 class Groupoid(uniq1, Category):
    421     """
    422     The category of groupoids, for a set (usually a group) $G$.
    423 
    424     EXAMPLES:
    425         sage: Groupoid(DihedralGroup(3))
    426         Groupoid with underlying set Dihedral group of order 6 as a permutation group
    427     """
    428     def __init__(self, G):
    429         Category.__init__(self, "Groupoid")
    430         self.__G = G
    431 
    432     def __repr__(self):
    433         return "Groupoid with underlying set %s"%self.__G
    434        
    435     def __reduce__(self):
    436         """
    437         EXAMPLES:
    438             sage: S8 = SymmetricGroup(8)
    439             sage: C = Groupoid(S8)
    440             sage: loads(C.dumps()) == C
    441             True
    442         """
    443         return Groupoid, (self.__G, )
    444    
    445 
    446 #############################################################
    447 # Group
    448 #############################################################
    449 class Groups(Category_uniq):
    450     """
    451     The category of groups.
    452 
    453     EXAMPLES:
    454         sage: Groups()
    455         Category of groups
    456     """
    457 
    458     def __reduce__(self):
    459         """
    460         EXAMPLES:
    461             sage: C = Groups()
    462             sage: loads(C.dumps()) == C
    463             True
    464         """
    465         return Groups, tuple([])
    466    
    467 
    468 
    469 #############################################################
    470 # AbelianSemigroup
    471 #############################################################
    472 class AbelianSemigroups(Category_uniq):
    473     """
    474     The category of all abelian semigroups.
    475 
    476    
    477     EXAMPLES:
    478         sage: AbelianSemigroups()
    479         Category of abelian semigroups
    480     """
    481 
    482     def __reduce__(self):
    483         """
    484         EXAMPLES:
    485             sage: C = AbelianSemigroups()
    486             sage: loads(C.dumps()) == C
    487             True
    488         """
    489         return AbelianSemigroups, tuple([])
    490    
    491 
    492 #############################################################
    493 # AbelianMonoid
    494 #############################################################
    495 class AbelianMonoids(Category_uniq):
    496     """
    497     The category of all monoids.
    498 
    499     EXAMPLES:
    500         sage: AbelianMonoids()
    501         Category of abelian monoids
    502     """
    503        
    504     def __reduce__(self):
    505         """
    506         EXAMPLES:
    507             sage: C = AbelianMonoids()
    508             sage: loads(C.dumps()) == C
    509             True
    510         """
    511         return AbelianMonoids, tuple([])
    512 
    513 
    514 #############################################################
    515 # AbelianGroup
    516 #############################################################
    517 class AbelianGroups(Category_uniq, AbelianCategory):
    518     """
    519     The category of all abelian groups.
    520 
    521     EXAMPLES:
    522         sage: AbelianGroups()
    523         Category of abelian groups
    524     """
    525 
    526     def __reduce__(self):
    527         """
    528         EXAMPLES:
    529             sage: C = AbelianGroups()
    530             sage: loads(C.dumps()) == C
    531             True
    532         """
    533         return AbelianGroups, tuple([])
    534        
    535 
    536 #############################################################
    537 # Ring
    538 #############################################################
    539 class Rings(Category_uniq):
    540     """
    541     The category of all rings.
    542 
    543     EXAMPLES:
    544         sage: Rings()
    545         Category of rings
    546     """
    547 
    548     def __reduce__(self):
    549         """
    550         EXAMPLES:
    551             sage: C = Rings()
    552             sage: loads(C.dumps()) == C
    553             True
    554         """
    555         return Rings, tuple([])
    556 
    557 
    558 #############################################################
    559 # CommutativeRing
    560 #############################################################
    561 class CommutativeRings(Category_uniq):
    562     """
    563     The category of commutative rings.
    564    
    565     EXAMPLES:
    566         sage: CommutativeRings()
    567         Category of commutative rings
    568     """
    569        
    570     def __reduce__(self):
    571         """
    572         EXAMPLES:
    573             sage: C = CommutativeRings()
    574             sage: loads(C.dumps()) == C
    575             True
    576         """
    577         return CommutativeRings, tuple([])
    578 
    579 
    580 #############################################################
    581 # Field
    582 #############################################################
    583 class Fields(Category_uniq):
    584     """
    585     The category of fields.
    586 
    587     EXAMPLES:
    588         sage: K = Fields()
    589         sage: K
    590         Category of fields
    591         sage: K(IntegerRing())
    592         Rational Field
    593         sage: K(PolynomialRing(GF(3), 'x'))
    594         Fraction Field of Univariate Polynomial Ring in x over
    595         Finite Field of size 3
    596         sage: K(RealField())
    597         Real Field with 53 bits of precision
    598     """
    599     def __contains__(self, x):
    600         return is_Field(x)
    601 
    602     def __call__(self, x):
    603         if x in self:
    604             return x
    605         try:
    606             return x.fraction_field()
    607         except AttributeError:
    608             raise TypeError, "unable to associate a field to %s"%x
    609            
    610     def __reduce__(self):
    611         """
    612         EXAMPLES:
    613             sage: C = Fields()
    614             sage: loads(C.dumps()) == C
    615             True
    616         """
    617         return Fields, tuple([])
    618 
    619 
    620 #############################################################
    621 # FiniteField
    622 #############################################################
    623 class FiniteFields(Category_uniq):
    624     """
    625     The category of all finite fields.
    626 
    627     EXAMPLES:
    628         sage: K = FiniteFields()
    629         sage: K
    630         Category of finite fields
    631         sage: FiniteField(17) in K
    632         True
    633         sage: RationalField() in K
    634         False
    635         sage: K(RationalField())
    636         Traceback (most recent call last):
    637         ...
    638         TypeError: unable to canonically associate a finite field to Rational Field
    639     """
    640     def __contains__(self, x):
    641         return is_Field(x) and x.is_finite()
    642 
    643     def __call__(self, x):
    644         if x in self:
    645             return x
    646         raise TypeError, "unable to canonically associate a finite field to %s"%x
    647         # TODO: local dvr ring?
    648 
    649     def __reduce__(self):
    650         """
    651         EXAMPLES:
    652             sage: C = FiniteFields()
    653             sage: loads(C.dumps()) == C
    654             True
    655         """
    656         return FiniteFields, tuple([])
    657 
    658 
    659 #############################################################
    660 # NumberField
    661 #############################################################
    662 class NumberFields(Category_uniq):
    663     r"""
    664     The category of number fields.
    665    
    666     EXAMPLES:
    667     We create the category of number fields.
    668         sage: C = NumberFields()
    669         sage: C
    670         Category of number fields
    671 
    672     Notice that the rational numbers $\Q$ *are* considered as
    673     an object in this category.
    674         sage: RationalField() in C
    675         True
    676 
    677     However, we can define a degree 1 extension of $\Q$, which is of
    678     course also in this category.
    679         sage: x = PolynomialRing(RationalField(), 'x').gen()
    680         sage: K = NumberField(x - 1, 'a'); K
    681         Number Field in a with defining polynomial x - 1
    682         sage: K in C
    683         True
    684 
    685     Number fields all lie in this category, regardless of the name
    686     of the variable.
    687         sage: K = NumberField(x^2 + 1, 'a')
    688         sage: K in C
    689         True
    690     """
    691     def __contains__(self, x):
    692         import sage.rings.all
    693         return sage.rings.all.is_NumberField(x)
    694 
    695     def __call__(self, x):
    696         if x in self:
    697             return x
    698         try:
    699             return x.number_field()
    700         except AttributeError:
    701             raise TypeError, "unable to canonically associate a number field to %s"%x
    702        
    703     def __reduce__(self):
    704         """
    705         EXAMPLES:
    706             sage: C = NumberFields()
    707             sage: loads(C.dumps()) == C
    708             True
    709         """
    710         return NumberFields, tuple([])
    711        
    712 
    713 #############################################################
    714 # Algebra
    715 #############################################################
    716 class Algebras(Category_over_base_ring):
    717     """
    718     The category of algebras over a fixed base ring.
    719 
    720    
    721     """
    722     def __reduce__(self):
    723         """
    724         EXAMPLES:
    725             sage: C = Algebras(ZZ)
    726             sage: loads(C.dumps()) == C
    727             True
    728         """
    729         return Algebras, (self.base(), )
    730 
    731     def __contains__(self, x):
    732         return is_Algebra(x) and x.base_field() == self.base_field()
    733 
    734     def base_field(self):
    735         """
    736         Return the base field over which the algebras of this category
    737         are all defined.
    738         """
    739         return self.base_ring()
    740 
    741 
    742 #############################################################
    743 # CommutativeAlgebra
    744 #############################################################
    745 class CommutativeAlgebras(Category_over_base_ring):
    746     """
    747     The category of commutative algebras over a given base ring.
    748 
    749     EXAMPLES:
    750         sage: M = CommutativeAlgebras(GF(19))
    751         sage: M
    752         Category of commutative algebras over Finite Field of size 19
    753     """
    754    
    755     def __reduce__(self):
    756         """
    757         EXAMPLES:
    758             sage: C = CommutativeAlgebras(ZZ)
    759             sage: loads(C.dumps()) == C
    760             True
    761         """
    762         return CommutativeAlgebras, (self.base(), )
    763 
    764 #############################################################
    765 # MonoidAlgebra
    766 #############################################################
    767 class MonoidAlgebras(Category_over_base_ring):
    768     """
    769     The category of all monoid algebras over a given base ring.
    770     EXAMPLES:
    771         sage: MonoidAlgebras(GF(2))
    772         Category of monoid algebras over Finite Field of size 2
    773     """
    774 
    775     def __reduce__(self):
    776         """
    777         EXAMPLES:
    778             sage: C = MonoidAlgebras(ZZ)
    779             sage: loads(C.dumps()) == C
    780             True
    781         """
    782         return MonoidAlgebras, (self.base(), )
    783 
    784 
    785 #############################################################
    786 # GroupAlgebra
    787 #############################################################
    788 class GroupAlgebras(Category_over_base_ring):
    789     """
    790     EXAMPLES:
    791         sage: GroupAlgebras(IntegerRing())
    792         Category of group algebras over Integer Ring
    793     """
    794 
    795     def __reduce__(self):
    796         """
    797         EXAMPLES:
    798             sage: C = GroupAlgebras(ZZ)
    799             sage: loads(C.dumps()) == C
    800             True
    801         """
    802         return GroupAlgebras, (self.base(), )
    803        
    804 
    805 
    806 #############################################################
    807 # MatrixAlgebra
    808 #############################################################
    809 class MatrixAlgebras(Category_over_base_ring):
    810     """
    811     The category of matrix algebras over a field.
    812    
    813     EXAMPLES:
    814         sage: MatrixAlgebras(RationalField())
    815         Category of matrix algebras over Rational Field
    816     """
    817 
    818     def __reduce__(self):
    819         """
    820         EXAMPLES:
    821             sage: C = MatrixAlgebras(ZZ)
    822             sage: loads(C.dumps()) == C
    823             True
    824         """
    825         return MatrixAlgebras, (self.base(), )
    826        
    827 
    828 
    829 #############################################################
    830 # RingModule
    831 #############################################################
    832 class RingModules(Category_module):
    833     """
    834     The category of all modules over a base ring.
    835 
    836     EXAMPLES:
    837         sage: Modules(RationalField())
    838         Category of ring modules over Rational Field
    839 
    840         sage: Modules(Integers(9))
    841         Category of ring modules over Ring of integers modulo 9
    842     """
    843 
    844 
    845     def __reduce__(self):
    846         """
    847         EXAMPLES:
    848             sage: C = RingModules(ZZ)
    849             sage: loads(C.dumps()) == C
    850             True
    851         """
    852         return RingModules, (self.base(), )
    853 
    854 
    855 # Synonym
    856 
    857 Modules = RingModules
    858 
    859 
    860 
    861 #############################################################
    862 # FreeModule
    863 #############################################################
    864 class FreeModules(Category_module):
    865     """
    866     The category of free modules over a base ring.
    867    
    868     EXAMPLES:
    869         sage: FreeModules(IntegerRing())
    870         Category of free modules over Integer Ring
    871     """
    872     def __init__(self, R):
    873         if not is_Ring(R):
    874             raise TypeError, "R (=%s) must be a ring"%R
    875         Category_module.__init__(self, R)
    876 
    877        
    878     def __reduce__(self):
    879         """
    880         EXAMPLES:
    881             sage: C = FreeModules(ZZ)
    882             sage: loads(C.dumps()) == C
    883             True
    884         """
    885         return FreeModules, (self.base(), )
    886        
    887     def __call__(self, x):
    888         try:
    889             M = x.free_module()
    890             if M.base_ring() != self.base_ring():
    891                 M = M.change_ring(self.base_ring())
    892         except (TypeError, AttributeError), msg:
    893             raise TypeError, "%s\nunable to coerce x (=%s) into %s"%(msg,x,self)           
    894         return M
    895 
    896     def is_abelian(self):
    897         return self.base_ring().is_field()
    898 
    899 
    900 #############################################################
    901 # VectorSpace
    902 #############################################################
    903 class VectorSpaces(Category_module):
    904     """
    905     The category of vector spaces over a specified field,
    906     with an embedding in an ambient vector space.
    907    
    908     EXAMPLES:
    909         sage: VectorSpaces(RationalField())
    910         Category of vector spaces over Rational Field
    911     """
    912     def __init__(self, K):
    913         if not is_Field(K):
    914             raise TypeError, "K (=%s) must be a field"%K
    915         Category_module.__init__(self, K)
    916        
    917     def __reduce__(self):
    918         """
    919         EXAMPLES:
    920             sage: C = QQ^10      # vector space
    921             sage: loads(C.dumps()) == C
    922             True
    923         """
    924         return VectorSpaces, (self.base(), )
    925 
    926     def __call__(self, x):
    927         try:
    928             V = x.vector_space(self.base_field())
    929             if V.base_field() != self.base_field():
    930                 V = V.change_ring(self.base_field())
    931         except (TypeError, AttributeError), msg:
    932             raise TypeError, "%s\nunable to coerce x (=%s) into %s"%(msg,x,self)
    933         return V
    934 
    935     def base_field(self):
    936         return self.base_ring()
    937 
    938    
    939 #############################################################
    940 # HeckeModules
    941 #############################################################
    942 class HeckeModules(Category_module):
    943     r"""
    944     The category of Hecke modules.
    945 
    946     A Hecke module is a module $M$ over the \emph{anemic} Hecke
    947     algebra, i.e., the Hecke algebra generated by Hecke operators
    948     $T_n$ with $n$ coprime to the level of $M$.  (Every Hecke module
    949     defines a level function, which is a positive integer.)  The
    950     reason we require that $M$ only be a module over the anemic Hecke
    951     algebra is that many natural maps, e.g., degeneracy maps,
    952     Atkin-Lehner operators, etc., are $\T$-module homomorphisms; but
    953     they are homomorphisms over the anemic Hecke algebra.
    954    
    955     EXAMPLES:
    956     We create the category of Hecke modules over $\Q$.
    957         sage: C = HeckeModules(RationalField()); C
    958         Category of Hecke modules over Rational Field
    959        
    960     Note that the base ring can be an arbitrary commutative ring.
    961         sage: HeckeModules(IntegerRing())
    962         Category of Hecke modules over Integer Ring
    963         sage: HeckeModules(FiniteField(5))
    964         Category of Hecke modules over Finite Field of size 5
    965 
    966     The base ring doesn't have to be a principal ideal domain.
    967         sage: HeckeModules(PolynomialRing(IntegerRing(), 'x'))
    968         Category of Hecke modules over Univariate Polynomial Ring in x over Integer Ring
    969     """
    970     def __init__(self, R):
    971         if not (is_Ring(R) and R.is_commutative()):
    972             raise TypeError, "R (=%s) must be a commutative ring"%R
    973         Category_module.__init__(self, R, "Hecke modules")
    974        
    975     def __reduce__(self):
    976         """
    977         EXAMPLES:
    978             sage: C = HeckeModules(ZZ)
    979             sage: loads(C.dumps()) == C
    980             True
    981         """
    982         return HeckeModules, (self.base(), )
    983 
    984 
    985 #############################################################
    986 # RingIdeal
    987 #############################################################
    988 class RingIdeals(Category_ideal):
    989     """
    990     The category of all ideals in a fixed ring.
    991    
    992     EXAMPLES:
    993         sage: Ideals(Integers(200))
    994         Category of ring ideals in Ring of integers modulo 200
    995         sage: C = Ideals(IntegerRing()); C
    996         Category of ring ideals in Integer Ring
    997         sage: I = C([8,12,18])
    998         sage: I
    999         Principal ideal (2) of Integer Ring
    1000     """
    1001     def __init__(self, R):
    1002         if not is_Ring(R):
    1003             raise TypeError, "R (=%s) must be a ring"%R
    1004         Category_ideal.__init__(self, R)
    1005 
    1006     def __reduce__(self):
    1007         """
    1008         EXAMPLES:
    1009             sage: C = RingIdeals(ZZ)
    1010             sage: loads(C.dumps()) == C
    1011             True
    1012         """
    1013         return RingIdeals, (self.ring(), )
    1014 
    1015    
    1016 Ideals = RingIdeals
    1017        
    1018 
    1019 #############################################################
    1020 # CommutativeRingIdeal
    1021 #############################################################
    1022 class CommutativeRingIdeals(Category_ideal):
    1023     """
    1024     The category of ideals in a fixed commutative ring.
    1025    
    1026     EXAMPLES:
    1027 
    1028         sage: C = CommutativeRingIdeals(IntegerRing())
    1029         sage: C
    1030         Category of commutative ring ideals in Integer Ring
    1031     """
    1032     def __init__(self, R):
    1033         import sage.rings.all
    1034         if not sage.rings.all.is_CommutativeRing(R):
    1035             raise TypeError, "R (=%s) must be a commutative ring"%R
    1036         Category_ideal.__init__(self, R)
    1037        
    1038 
    1039     def __reduce__(self):
    1040         """
    1041         EXAMPLES:
    1042             sage: C = CommutativeRingIdeals(ZZ)
    1043             sage: loads(C.dumps()) == C
    1044             True
    1045         """
    1046         return CommutativeRingIdeals, (self.ring(), )
    1047 
    1048 
    1049 
    1050 #############################################################
    1051 # AlgebraModule
    1052 #############################################################
    1053 class AlgebraModules(Category_module):
    1054     """
    1055     The category of modules over a fixed algebra $A$.
    1056     """
    1057     def __init__(self, A):
    1058         if not is_Algebra(A):
    1059             raise TypeError, "A (=%s) must be an algebra"%A
    1060         Category_module.__init__(self, A)
    1061 
    1062     def algebra(self):
    1063         return self.base_ring()
    1064 
    1065     def __reduce__(self):
    1066         """
    1067         EXAMPLES:
    1068             sage: C = AlgebraModules(FreeAlgebra(QQ,2,'a,b'))
    1069             sage: loads(C.dumps()) == C
    1070             True
    1071         """
    1072         return AlgebraModules, (self.algebra(),)
    1073 
    1074    
    1075 
    1076 #############################################################
    1077 # AlgebraIdeal
    1078 #############################################################
    1079 class AlgebraIdeals(Category_ideal):
    1080     """
    1081     The category of ideals in a fixed algebra $A$.
    1082 
    1083     EXAMPLES:
    1084         sage: C = AlgebraIdeals(FreeAlgebra(QQ,2,'a,b'))
    1085         sage: loads(C.dumps()) == C
    1086         True
    1087     """
    1088     def __init__(self, A):
    1089         if not is_Algebra(A):
    1090             raise TypeError, "A (=%s) must be an algebra"%A
    1091         Category_ideal.__init__(self, A)
    1092 
    1093     def algebra(self):
    1094         return self.ambient()
    1095 
    1096     def __reduce__(self):
    1097         return AlgebraIdeals, (self.algebra(),)
    1098 
    1099    
    1100 
    1101 #############################################################
    1102 # CommutativeAlgebraIdeal
    1103 #############################################################
    1104 class CommutativeAlgebraIdeals(Category_ideal):
    1105     """
    1106     The category of ideals in a fixed commutative algebra $A$.
    1107     """
    1108     def __init__(self, A):
    1109         if not is_CommutativeAlgebra(A):
    1110             raise TypeError, "A (=%s) must be a commutative algebra"%A
    1111         Category_in_ambient.__init__(self, A)
    1112 
    1113     def algebra(self):
    1114         return self.ambient()
    1115    
    1116 
    1117     def __reduce__(self):
    1118         """
    1119         """
    1120         return CommutativeAlgebraIdeals, (self.algebra(),)
    1121 
    1122353#############################################################
    1123354# ChainComplex
    1124355#############################################################
    class ChainComplexes(Category_module): 
    1144375            True
    1145376        """
    1146377        return ChainComplexes, (self.base(), )
    1147 
    1148 #############################################################
    1149 # Schemes over a given base scheme.
    1150 #############################################################
    1151 class Schemes_over_base(Category_over_base):
    1152     """
    1153     The category of schemes over a given base scheme.
    1154 
    1155     EXAMPLES:
    1156         sage: Schemes(Spec(ZZ))
    1157         Category of schemes over Spectrum of Integer Ring
    1158     """
    1159     def __init__(self, Y):
    1160         Category_over_base.__init__(self, Y)
    1161        
    1162     def base_scheme(self):
    1163         return self.base()
    1164    
    1165     def _repr_(self):
    1166         return "Category of schemes over %s"%self.base_scheme()
    1167 
    1168     def __reduce__(self):
    1169         """
    1170         EXAMPLES:
    1171             sage: C = Schemes(ZZ)
    1172             sage: loads(C.dumps()) == C
    1173             True
    1174         """
    1175         return Schemes_over_base, (self.base_scheme(), )
    1176 
    1177 class Schemes_abstract(Category_uniq):
    1178     """
    1179     The category of all abstract schemes.
    1180 
    1181     EXAMPLES:
    1182         sage: Schemes()
    1183         Category of Schemes
    1184     """
    1185     def __init__(self):
    1186         Category_uniq.__init__(self, "Schemes")
    1187        
    1188     def __reduce__(self):
    1189         return Schemes_abstract, ()
    1190 
    1191     def __call__(self, x):
    1192         """
    1193         EXAMPLES:
    1194         Fetch the category of schemes.
    1195             sage: S = Schemes(); S
    1196             Category of Schemes
    1197 
    1198         We create a scheme from a ring.
    1199             sage: X = S(ZZ); X
    1200             Spectrum of Integer Ring
    1201 
    1202         We create a scheme from a scheme (do nothing).
    1203             sage: S(X)
    1204             Spectrum of Integer Ring
    1205 
    1206         We create a scheme morphism from a ring homomorphism.x
    1207             sage: phi = ZZ.hom(QQ); phi
    1208             Ring Coercion morphism:
    1209               From: Integer Ring
    1210               To:   Rational Field
    1211             sage: f = S(phi); f
    1212             Affine Scheme morphism:
    1213               From: Spectrum of Rational Field
    1214               To:   Spectrum of Integer Ring
    1215               Defn: Ring Coercion morphism:
    1216                       From: Integer Ring
    1217                       To:   Rational Field
    1218 
    1219             sage: f.domain()
    1220             Spectrum of Rational Field
    1221             sage: f.codomain()
    1222             Spectrum of Integer Ring
    1223             sage: S(f)
    1224             Affine Scheme morphism:
    1225               From: Spectrum of Rational Field
    1226               To:   Spectrum of Integer Ring
    1227               Defn: Ring Coercion morphism:
    1228                       From: Integer Ring
    1229                       To:   Rational Field
    1230 
    1231         """
    1232         from sage.rings.all import is_CommutativeRing, is_RingHomomorphism
    1233         from sage.schemes.all import is_Scheme, Spec, is_SchemeMorphism
    1234         if is_Scheme(x) or is_SchemeMorphism(x):
    1235             return x
    1236         elif is_CommutativeRing(x):
    1237             return Spec(x)
    1238         elif is_RingHomomorphism(x):
    1239             A = Spec(x.codomain())
    1240             return A.hom(x)
    1241         else:
    1242             raise TypeError, "No way to create an object or morphism in %s from %s"%(self, x)
    1243 
    1244 
    1245 def Schemes(X=None):
    1246     if X is None:
    1247         return Schemes_abstract()
    1248     from sage.schemes.all import is_Scheme
    1249     if not is_Scheme(X):
    1250         X = Schemes()(X)
    1251     return Schemes_over_base(X)
    1252    
    1253 
    1254 class ModularAbelianVarieties(Category_over_base):
    1255     """
    1256     The category of modular abelian varieties over a given field.
    1257 
    1258     EXAMPLES:
    1259         sage: ModularAbelianVarieties(QQ)
    1260         Category of modular abelian varieties over Rational Field
    1261     """
    1262     def __init__(self, Y):
    1263         assert Y.is_field()
    1264         Category_over_base.__init__(self, Y)
    1265        
    1266     def base_field(self):
    1267         return self.base()
    1268    
    1269     def _repr_(self):
    1270         return "Category of modular abelian varieties over %s"%self.base_field()
    1271 
    1272     def __reduce__(self):
    1273         """
    1274         EXAMPLES:
    1275             sage: C = ModularAbelianVarieties(QQ)
    1276             sage: loads(C.dumps()) == C
    1277             True
    1278         """
    1279         return ModularAbelianVarieties, (self.base_field(), )
    1280 
    1281 ###################################################################
    1282 #
    1283 # Natural inclusions between categories.
    1284 #
    1285 ###################################################################
    1286 
    1287 category_hierarchy = {\
    1288     Objects                : [Sets],\
    1289     Sets                   : [],\
    1290     GSets                  : [Sets],\
    1291     Semigroups             : [Sets],\
    1292     Monoids                : [Semigroups, Sets],\
    1293     Groups                 : [Monoids, Semigroups, Sets],\
    1294     AbelianSemigroups      : [Semigroups, Sets],\
    1295     AbelianMonoids         : [Monoids, Sets],\
    1296     AbelianGroups          : [Groups, AbelianMonoids, AbelianSemigroups, Sets],\
    1297     Rings                  : [AbelianGroups, Sets],\
    1298     CommutativeRings       : [Rings, Sets],\
    1299     Fields                 : [CommutativeRings, Rings, Sets],\
    1300     FiniteFields           : [Fields, CommutativeRings, Rings, Sets],\
    1301     NumberFields           : [CommutativeRings, Rings, Sets, Fields],\
    1302     Algebras               : [Rings, RingModules, Sets],\
    1303     CommutativeAlgebras    : [Algebras, CommutativeRings, Rings, Sets],\
    1304     MonoidAlgebras         : [Algebras, Sets],\
    1305     GroupAlgebras          : [MonoidAlgebras, Algebras, Sets],\
    1306     MatrixAlgebras         : [Algebras, Sets],\
    1307     RingModules            : [AbelianGroups, Sets],\
    1308     FreeModules            : [RingModules, AbelianGroups, Sets],\
    1309     VectorSpaces           : [FreeModules, RingModules, AbelianGroups, Sets],\
    1310     HeckeModules           : [FreeModules, RingModules, AbelianGroups, Sets],\
    1311     AlgebraModules         : [RingModules, AbelianGroups, Sets],\
    1312     RingIdeals             : [RingModules, AbelianGroups, Sets],\
    1313     CommutativeRingIdeals  : [RingIdeals, AbelianGroups, Sets],\
    1314     AlgebraIdeals          : [AlgebraModules, AbelianGroups, Sets],\
    1315     CommutativeAlgebraIdeals:[CommutativeRingIdeals, RingIdeals, AbelianGroups, Sets], \
    1316     Elements               : [Sets], \
    1317     Sequences              : [Sets], \
    1318     Schemes_abstract       : [Sets], \
    1319     Schemes_over_base      : [Schemes_abstract, Sets], \
    1320     ModularAbelianVarieties: [Sets], \
    1321     }
    1322 
    1323 for k in category_hierarchy:
    1324     category_hierarchy[k].append(Objects)
    1325 
  • sage/structure/category_object.pyx

    diff --git a/sage/structure/category_object.pyx b/sage/structure/category_object.pyx
    a b cdef int bad_parent_warnings = 0 
    4545
    4646import generators
    4747import sage_object
     48from sage.categories.category import JoinCategory
    4849
    4950def guess_category(obj):
    5051    # this should be obsolete if things declare their categories
    5152    try:
    5253        if obj.is_field():
    53             from sage.categories.category_types import Fields
     54            from sage.categories.all import Fields
    5455            return Fields()
    5556    except:
    5657        pass
    5758    try:
    5859        if obj.is_ring():
    59             from sage.categories.category_types import CommutativeAlgebras, Algebras, CommutativeRings, Rings
     60            from sage.categories.all import CommutativeAlgebras, Algebras, CommutativeRings, Rings
    6061            if obj.is_commutative():
    6162                if obj._base is not obj:
    6263                    return CommutativeAlgebras(obj._base)
    def guess_category(obj): 
    6970                    return Rings()
    7071    except:
    7172        pass
     73#    from sage.structure.parent import Parent
     74#    if isinstance(obj, Parent):
     75#        import sys
     76#        sys.stderr.write("bla: %s"%obj)
     77#        from sage.categories.all import Sets
     78#        return Sets()
    7279    return None # don't want to risk importing stuff...
    7380   
    7481cdef class CategoryObject(sage_object.SageObject):
    7582    """
    7683    An object in some category.
    7784    """
    78     def __init__(self, category, base = None):
     85    def __init__(self, category = None, base = None):
    7986        """
    8087        Initializes an object in a category
    8188
    8289        INPUT:
    83         category - The category this object belongs to. If this object belongs to multiple categories,
    84                    pass in a join category.
     90        categories - a category or list/tuple of categories
     91
    8592        base - If this object has another object that should be considered a base in its primary category,
    8693               you can include that base here.
    8794        gens_with_names - if this object has generators, there are a number of ways of specifying them.
    8895                         
     96        FIXME: the last two arguments below have nothing to do with categories, do they?
    8997        """
    9098        if base is not None:
    9199            self._base = base
     100        self._generators = {}
     101        if category is not None:
     102            self.__init_category__(category)
     103
     104    def __init_category__(self, category):
     105        """
     106        Sets the category or categories of this object.
     107        """
    92108        if category is None:
    93109            if bad_parent_warnings:
    94110                print "No category for %s" % type(self)
    95111            category = guess_category(self) # so generators don't crash
     112        elif (type(category) == tuple or type(category) == list):
     113            assert(len(category)>0) # or we should decide of the semantic for an empty category
     114            if len(category) == 1:
     115                category = category[0]
     116            else:
     117                category = JoinCategory(*category)
    96118        self._category = category
    97         self._generators = {}
    98        
     119
    99120    def category(self):
    100121        if self._category is None:
    101122            # COERCE TODO: we shouldn't need this
    cdef class CategoryObject(sage_object.Sa 
    403424#            raise TypeError, "base extension not defined for %s" % self
    404425           
    405426    # COERCE TODO: When everything has a category, move let it be an optional arg.
    406     def base_ring(self):
     427    def base_ring(self): # This should be in a category or elsewhere, but not here
    407428        return self._base
    408429       
    409430    def base(self):
    cdef class CategoryObject(sage_object.Sa 
    559580                try:
    560581                    self._base = d['_base']
    561582                    self._names = d['_names']
    562                     from sage.categories.category_types import Objects
     583                    from sage.categories.all import Objects
    563584                    if d['_gens'] is None:
    564585                        from sage.structure.generators import Generators
    565586                        self._generators = Generators(self, None, Objects())
  • sage/structure/parent.pyx

    diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
    a b This came up in some subtle bug once. 
    1919cimport element
    2020cimport sage.categories.morphism as morphism
    2121cimport sage.categories.map as map
    22 
     22from sage.misc.lazy_attribute import lazy_attribute
     23from sage.categories.sets_cat import Sets
    2324from copy import copy
    2425
    2526cdef int bad_parent_warnings = 0
    cdef extern from *: 
    7071cdef inline Py_ssize_t PyDict_GET_SIZE(o):
    7172    return (<dict>o).ma_used
    7273
     74def is_extension_type(cls):
     75    """
     76    INPUT:
     77     - cls: a class
     78   
     79    Tests whether cls is an extension type (int, list, cython compiled classes, ...)
     80
     81    EXAMPLES
     82        sage: from sage.structure.parent import is_extension_type
     83        sage: is_extension_type(int)
     84        True
     85        sage: is_extension_type(list)
     86        True
     87        sage: is_extension_type(ZZ.__class__)
     88        True
     89        sage: is_extension_type(QQ.__class__)
     90        False
     91    """
     92    # Robert B claims that this should be robust
     93    return hasattr(cls, "__dictoffset__") and cls.__dictoffset__ == 0
     94
    7395###############################################################################
    7496#   SAGE: System for Algebra and Geometry Experimentation   
    7597#       Copyright (C) 2006 William Stein <wstein@gmail.com>
    cdef bint guess_pass_parent(parent, elem 
    118140    else:
    119141        return True
    120142
     143from sage.categories.category import Category
     144from sage.structure.dynamic_class import dynamic_class
    121145
    122146
    123147cdef class Parent(category_object.CategoryObject):
    cdef class Parent(category_object.Catego 
    132156
    133157    """
    134158   
    135     def __init__(self, base=None, *, categories=[], element_constructor=None, gens=None, names=None, normalize=True, **kwds):
    136         CategoryObject.__init__(self, categories, base)
     159    def __init__(self, base=None, *, category=None, element_constructor=None, gens=None, names=None, normalize=True, **kwds):
     160        """
     161
     162        category: a category or list/tuple of categories
     163
     164        If category is a list or tuple, a JoinCategory is created out
     165        of them.  If category is not specified, the category will be
     166        guessed (see CategoryObject), but won't be used to inherit
     167        parent's or element's code from this category.
     168
     169        FIXME: eventually, category should be Sets() by default
     170        """
     171
     172        # TODO: in the long run, we want to get rid of the element_constructor = argument
     173        # (element_constructor would always be set by inheritance)
     174        # Then, all the element_constructor logic should be moved to init_coerce.
     175
     176        CategoryObject.__init__(self, base = base)
     177        # Setting the categories is currently done in a separate
     178        # method to let some subclasses (like ParentsWithBase)
     179        # call it without calling the full constructor
     180        self.__init_category__(category)
     181
    137182        if len(kwds) > 0:
    138183            if bad_parent_warnings:
    139184                print "Illegal keywords for %s: %s" % (type(self), kwds)
    cdef class Parent(category_object.Catego 
    149194            self._assign_names(names, normalize)
    150195        self._element_constructor = element_constructor
    151196        self._element_init_pass_parent = guess_pass_parent(self, element_constructor)
    152         self._coerce_from_list = []
    153         self._coerce_from_hash = {}
    154         self._action_list = []
    155         self._action_hash = {}
    156         self._convert_from_list = []
    157         self._convert_from_hash = {}
    158         self._embedding = None
    159         self._initial_coerce_list = []
    160         self._initial_action_list = []
    161         self._initial_convert_list = []
     197        self.init_coerce(False)
     198
     199        for cls in self.__class__.mro():
     200            if hasattr(cls, "__init_extra__"):
     201                cls.__init_extra__(self)
     202
     203    def __init_category__(self, category):
     204        CategoryObject.__init_category__(self, category)
    162205       
     206        # This substitutes the class of this parent to a subclass
     207        # which also subclasses the parent_class of the category
     208       
     209        # FIXME: this class munching causes bootstraping trouble with Set_generic
     210        if category is not None: #isinstance(self._category, Category) and not isinstance(self, Set_generic):
     211            category = self._category # CategoryObject may have done some argument processing
     212            # Some parent class may readilly have their category classes attached
     213            # TODO: assert that the category is consistent
     214            from sage.categories.sets_cat import Sets
     215            if not issubclass(self.__class__, Sets().parent_class) and not is_extension_type(self.__class__):
     216                doc = self.__class__.__doc__ if hasattr(self.__class__, "__doc__") else None
     217                self.__class__     = dynamic_class("%s_with_category"%self.__class__.__name__, (self.__class__, category.parent_class, ))
     218                if doc is not None: # Tries to make S? work; what should we do for S??
     219                    self.__class__.__doc__ = doc
     220            # TODO: Design issue: should the newly created class inherit from the original class?
     221            # if not, this prevents using natural idioms like: isinstance(self, MyParent)
     222
     223    @lazy_attribute
     224    def element_class(self):
     225        """
     226        The (default) class for the elements of this parent
     227
     228        FIXME's and design issues:
     229         - If self.Element is "trivial enough", should we optimize it away with:
     230           self.element_class = dynamic_class("%s.element_class"%self.__class__.__name__, (category.element_class,), self.Element)
     231         - This should lookup for Element classes in all super classes
     232        """
     233        if hasattr(self, 'Element'):
     234            return self.__make_element_class__(self.Element, "%s.element_class"%self.__class__.__name__)
     235        else:
     236            return NotImplemented
     237
     238
     239    def __make_element_class__(self, cls, name = None, inherit = None):
     240        """
     241        A utility to construct classes for the elements of this
     242        parent, with appropriate inheritance from the element class of
     243        the category (only for pure python types so far).
     244        """
     245        if name is None:
     246            name = "%s_with_category"%cls.__name__
     247        # By default, don't fiddle with extension types yet; inheritance from
     248        # categories will probably be achieved in a different way
     249        if inherit is None:
     250            inherit = not is_extension_type(cls)
     251        if inherit:
     252            return dynamic_class(name, (cls, self.category().element_class))
     253        else:
     254            return cls
     255
     256    def category(self):
     257        if self._category is None:
     258            # COERCE TODO: we shouldn't need this
     259            from sage.categories.sets_cat import Sets
     260            self._category = Sets()
     261        return self._category
     262
     263    def categories(self):
     264        """
     265        EXAMPLES:
     266            sage: ZZ.categories()
     267            [Category of commutative rings, Category of rings, Category of rngs, Category of abelian groups, Category of abelian monoids, Category of abelian semigroups, Category of monoids, Category of semigroups, Category of sets, Category of objects]
     268        """
     269        return self.category().all_super_categories()
     270
    163271    cdef int init_coerce(self, bint warn=True) except -1:
    164272        if self._coerce_from_hash is None:
    165273            if warn:
    cdef class Parent(category_object.Catego 
    276384
    277385        We check that the invariant::
    278386
    279                 self._element_init_pass_parent == guess_pass_parent(self, self._element_constructor)
     387                self._element_init_pass_parent == guess_pass_parent(self, self._element_constructor)
    280388
    281389        is preserved (see #5979)::
    282390
    cdef class Parent(category_object.Catego 
    290398            sage: my_parent = MyParent()
    291399            sage: x = my_parent("bla")
    292400            my_parent bla
    293             sage: x.parent()         # indirect doctest
     401            sage: x.parent()         # indirect doctest
    294402            my_parent
    295403
    296404            sage: x = my_parent()    # shouldn't this one raise an error?
    cdef class Parent(category_object.Catego 
    417525        else:
    418526            return (<map.Map>mor)._call_(x)
    419527   
    420     def list(self):
     528    def _list_from_iterator_cached(self):
    421529        """
    422530        Return a list of all elements in this object, if possible (the
    423531        object must define an iterator).
    cdef class Parent(category_object.Catego 
    487595        elif op == 5: #>=
    488596            return r >= 0
    489597
     598    # Should be moved and merged into the EnumeratedSets() category
    490599    def __len__(self):
    491600        """
    492601        Returns the number of elements in self. This is the naive algorithm
    cdef class Parent(category_object.Catego 
    501610        """
    502611        return len(self.list())
    503612
     613    # Should be moved and merged into the EnumeratedSets() category
    504614    def __getitem__(self, n):
    505615        """
    506616        Returns the `n^{th}` item of self, by getting self as a list.
    cdef class Parent(category_object.Catego 
    581691            return self._Hom_(codomain, cat)
    582692        except (TypeError, AttributeError):
    583693            pass
    584         from sage.categories.all import Hom
     694        from sage.categories.homset import Hom
    585695        return Hom(self, codomain, cat)
    586696
    587697    def hom(self, im_gens, codomain=None, check=None):
    cdef class Parent(category_object.Catego 
    13511461        """
    13521462        return None
    13531463
     1464# Should be taken care of by the category Sets().
    13541465    cpdef an_element(self):
    13551466        r"""
    13561467        Implementation of a function that returns an element (often non-trivial)
    cdef class Parent(category_object.Catego 
    14581569cdef class Set_generic(Parent): # Cannot use Parent because Element._parent is Parent
    14591570    """
    14601571    Abstract base class for sets.
     1572
     1573    TESTS::
     1574       
     1575        sage: Set(QQ).category()
     1576        Category of sets
     1577
    14611578    """
    1462     def category(self):
    1463         """
    1464         The category that this set belongs to, which is the category
    1465         of all sets.
     1579#     def category(self):
     1580#         # TODO: remove once all subclasses specify their category, or
     1581#         # the constructor of Parent sets it to Sets() by default
     1582#         """
     1583#         The category that this set belongs to, which is the category
     1584#         of all sets.
    14661585
    1467         EXAMPLES::
    1468        
    1469             sage: Set(QQ).category()
    1470             Category of sets
    1471         """
    1472         import sage.categories.all
    1473         return sage.categories.all.Sets()
     1586#         EXAMPLES:
     1587#             sage: Set(QQ).category()
     1588#             Category of sets
     1589#         """
     1590#         from sage.categories.sets_cat import Sets
     1591#         return Sets()
    14741592
    14751593    def object(self):
    14761594        return self
    def Set_PythonType(theType): 
    15081626        sage: S = Set_PythonType(tuple)
    15091627        sage: S([1,2,3])
    15101628        (1, 2, 3)
     1629
     1630      S is a parent which models the set of all lists:
     1631        sage: S.category()
     1632        Category of sets
     1633
     1634    EXAMPLES:
     1635        sage: R = sage.structure.parent.Set_PythonType(int)
     1636        sage: S = sage.structure.parent.Set_PythonType(float)
     1637        sage: Hom(R, S)
     1638        Set of Morphisms from Set of Python objects of type 'int' to Set of Python objects of type 'float' in Category of sets
     1639
    15111640    """
    15121641    try:
    15131642        return _type_set_cache[theType]
    cdef class Set_PythonType_class(Set_gene 
    15201649    cdef _type
    15211650
    15221651    def __init__(self, theType):
    1523         from sage.categories.category import Sets
    1524         Set_generic.__init__(self, element_constructor=theType, categories=[Sets()])
     1652        from sage.categories.sets_cat import Sets
     1653        # FIXME: setting the category here causes:
     1654        # "A mysterious error (perphaps a memory error?) occurred, which may have crashed doctest."
     1655        Set_generic.__init__(self, element_constructor=theType, category=Sets())
    15251656        self._type = theType
    15261657
    15271658    def __call__(self, x):
    cdef class Set_PythonType_class(Set_gene 
    15371668            3.0
    15381669            sage: S(1/3)
    15391670            0.333333333333333...
     1671
    15401672        """
    15411673        return self._type(x)
    15421674
    cdef class Set_PythonType_class(Set_gene 
    16421774            import sage.rings.infinity
    16431775            return sage.rings.infinity.infinity
    16441776           
    1645     def _Hom_(self, domain, cat=None):
    1646         """
    1647         By default, create a homset in the category of sets.
     1777#     def _Hom_disabled(self, domain, cat=None):
     1778#         """
     1779#         By default, create a homset in the category of sets.
    16481780       
    1649         EXAMPLES:
    1650             sage: R = sage.structure.parent.Set_PythonType(int)
    1651             sage: S = sage.structure.parent.Set_PythonType(float)
    1652             sage: R._Hom_(S)
    1653             Set of Morphisms from Set of Python objects of type 'int' to Set of Python objects of type 'float' in Category of sets
    1654         """
    1655         from sage.categories.category import Sets
    1656         from sage.categories.homset import Homset
    1657         if cat is None:
    1658             cat = Sets()
    1659         return Homset(self, domain, cat)
     1781#         EXAMPLES:
     1782#             sage: R = sage.structure.parent.Set_PythonType(int)
     1783#             sage: S = sage.structure.parent.Set_PythonType(float)
     1784#             sage: R._Hom_(S)
     1785#             Set of Morphisms from Set of Python objects of type 'int' to Set of Python objects of type 'float' in Category of sets
     1786#         """
     1787#         from sage.categories.sets_cat import Sets
     1788#         from sage.categories.homset import Homset
     1789#         if cat is None:
     1790#             cat = Sets()
     1791#         return Homset(self, domain, cat)
    16601792
    16611793# These functions are to guarantee that user defined _lmul_, _rmul_,
    16621794# _l_action_, _r_action_ do not in turn call __mul__ on their
  • sage/structure/sage_object.pyx

    diff --git a/sage/structure/sage_object.pyx b/sage/structure/sage_object.pyx
    a b cdef class SageObject: 
    454454    def _pari_init_(self):
    455455        return self._interface_init_()
    456456
     457
     458######################################################
     459# A python-accessible version of the one in coerce.pxi
     460# Where should it be?
     461   
     462def have_same_parent(self, other):
     463    from sage.structure.coerce import parent
     464    return parent(self) == parent(other)
    457465   
    458466##################################################################
    459    
    460 
    461 
    462467
    463468def load(filename, compress=True, verbose=True):
    464469    """   
    def unpickle_all(dir, debug=False): 
    781786    print "Failed to unpickle %s objects."%j
    782787    if debug:
    783788        return tracebacks
     789
  • sage/structure/parent_old.pyx

    diff --git a/sage/structure/parent_old.pyx b/sage/structure/parent_old.pyx
    a b cdef class Parent(parent.Parent): 
    5555    in computer science.
    5656    """
    5757   
    58     def __init__(self, coerce_from=[], actions=[], embeddings=[]):
     58    def __init__(self, coerce_from=[], actions=[], embeddings=[], category=None):
    5959        # TODO: many classes don't call this at all, but __new__ crashes SAGE
    6060#        if len(coerce_from) > 0:
    6161#            print type(self), coerce_from
    cdef class Parent(parent.Parent): 
    7474       
    7575        # old
    7676        self._has_coerce_map_from = {}
    77        
     77        if category is not None:
     78            self.__init_category__(category)
     79        else:
     80            # Do not use sage.categories.all here to avoid initialization loop
     81            # See e-mail on sage-combinat-devel by S. Labbe, 15 Jan 2009 17:14:37
     82            from sage.categories.sets_cat import Sets
     83            self._category = Sets()
     84
    7885    cdef int init_coerce(self, bint warn=False) except -1:
    7986        parent.Parent.init_coerce(self, warn)
    8087
  • sage/structure/parent_base.pyx

    diff --git a/sage/structure/parent_base.pyx b/sage/structure/parent_base.pyx
    a b cdef class ParentWithBase(parent_old.Par 
    5050    """
    5151    This class is being deprecated, see parent.Parent for the new model.
    5252    """
    53     def __init__(self, base, coerce_from=[], actions=[], embeddings=[]):
     53    def __init__(self, base, coerce_from=[], actions=[], embeddings=[], category=None):
    5454        # TODO: SymbolicExpressionRing has base RR, which makes this bad
    5555#        print type(self), "base", base, coerce_from
    5656#        if base != self and not base in coerce_from:
    5757#            coerce_from.append(base)
    58         parent_old.Parent.__init__(self, coerce_from=coerce_from, actions=actions, embeddings=embeddings)
     58        parent_old.Parent.__init__(self, coerce_from=coerce_from, actions=actions, embeddings=embeddings, category=category)
    5959        self._base = base
    6060       
    6161    def _richcmp(left, right, int op):
    cdef class ParentWithBase(parent_old.Par 
    8989    ############################################################################
    9090    # Homomorphism --
    9191    ############################################################################
    92     def Hom(self, codomain, cat=None):
     92    def Hom(self, codomain, category = None):
    9393        r"""
    94         self.Hom(codomain, cat=None):
     94        self.Hom(codomain, category = None):
    9595       
    96         Return the homspace \code{Hom(self, codomain, cat)} of all
     96        Return the homspace \code{Hom(self, codomain, category)} of all
    9797        homomorphisms from self to codomain in the category cat.  The
    9898        default category is \code{self.category()}.
    9999
    cdef class ParentWithBase(parent_old.Par 
    112112            sage: QQ.Hom(ZZ, Sets())
    113113            Set of Morphisms from Rational Field to Integer Ring in Category of sets
    114114        """
     115        # NT 01-2009: what's the difference with parent.Parent.Hom???
    115116        if self._element_constructor is None:
    116             return parent.Parent.Hom(self, codomain, cat)
     117            return parent.Parent.Hom(self, codomain, category)
    117118        try:
    118             return self._Hom_(codomain, cat)
     119            return self._Hom_(codomain, category)
    119120        except (TypeError, AttributeError):
    120121            pass
    121122        from sage.categories.all import Hom
    122         return Hom(self, codomain, cat)
     123        return Hom(self, codomain, category)
    123124
  • sage/structure/parent_gens.pyx

    diff --git a/sage/structure/parent_gens.pyx b/sage/structure/parent_gens.pyx
    a b def normalize_names(int ngens, names=Non 
    237237
    238238cdef class ParentWithGens(parent_base.ParentWithBase):
    239239    # Derived class *must* call __init__ and set the base!
    240     def __init__(self, base, names=None, normalize=True):
     240    def __init__(self, base, names=None, normalize=True, category = None):
    241241        self._base = base
    242242        self._has_coerce_map_from = {}
    243243        self._assign_names(names=names, normalize=normalize)
    244244
     245        # Why does not this call ParentWithBase.__init__ ?
     246        if category is not None:
     247            self.__init_category__(category)
     248
    245249##     def x__reduce__(self):
    246250##         if self._base is self:
    247251##             base = None
    cdef class ParentWithMultiplicativeAbeli 
    468472            self._generator_orders = g
    469473            return g
    470474
     475    # This should eventually be inherited from the EnumeratedSets() category
     476    def list(self): return self._list_from_iterator_cached()
     477
    471478    def __iter__(self):
    472479        """
    473480        Return an iterator over the elements in this object.
    cdef class ParentWithAdditiveAbelianGens 
    488495            self._generator_orders = g
    489496            return g
    490497
     498    # This should eventually be inherited from the EnumeratedSets() category
     499    def list(self): return self._list_from_iterator_cached()
     500
    491501    def __iter__(self):
    492502        """
    493503        Return an iterator over the elements in this object.
  • sage/categories/homset.py

    diff --git a/sage/categories/homset.py b/sage/categories/homset.py
    a b AUTHORS: 
    88- David Joyner (2005-12-17): added examples
    99
    1010- William Stein (2006-01-14): Changed from Homspace to Homset.
     11
     12- Nicolas M. Thiery (2008-12-)
    1113"""
    1214
    1315#*****************************************************************************
    AUTHORS: 
    2729
    2830import weakref
    2931
    30 import category
     32from sage.categories.category import Category
    3133import morphism
    3234from sage.structure.parent import Parent, Set_generic
     35from sage.misc.lazy_attribute import lazy_attribute
     36from sage.misc.cachefunc import cached_function
     37
     38# FIXME: where should instancemethod and function be imported from???
     39def a_function():
     40    pass
     41function = type(a_function)
     42class DummyClass:
     43    def a_method():
     44        pass
     45instancemethod = type(DummyClass.a_method)
    3346
    3447_cache = {}
    35 def Hom(X, Y, cat=None):
     48def Hom(X, Y, category=None):
    3649    """
    37     Create the space of homomorphisms from X to Y in the category cat.
     50    Create the space of homomorphisms from X to Y in the category category.
    3851   
    3952    INPUT:
    4053   
    def Hom(X, Y, cat=None): 
    4356   
    4457    -  ``Y`` - anything
    4558   
    46     -  ``cat`` - (optional) category in which the morphisms
     59    -  ``category`` - (optional) category in which the morphisms
    4760       must be
    4861   
    4962   
    50     OUTPUT: a homset in cat
     63    OUTPUT: a homset in category
    5164   
    5265    EXAMPLES::
    5366   
    def Hom(X, Y, cat=None): 
    6174        Set of Morphisms from SymmetricGroup(3) to SymmetricGroup(3) in Category of groups
    6275        sage: Hom(ZZ, QQ, Sets())
    6376        Set of Morphisms from Integer Ring to Rational Field in Category of sets
     77
     78        sage: Hom(FreeModule(ZZ,1), FreeModule(QQ,1))
     79        Set of Morphisms from Ambient free module of rank 1 over the principal ideal domain Integer Ring to Vector space of dimension 1 over Rational Field in Category of modules with basis over Integer Ring
     80        sage: Hom(FreeModule(QQ,1), FreeModule(ZZ,1))
     81        Set of Morphisms from Vector space of dimension 1 over Rational Field to Ambient free module of rank 1 over the principal ideal domain Integer Ring in Category of vector spaces over Rational Field
     82
     83
     84    TODO: design decision: how much of the homset comes from the
     85    category of X and Y, and how much from the specific X and Y.  In
     86    particular, do we need several parent classes depending on X and
     87    Y, or does the difference only lie in the elements (i.e. the
     88    morphism), and of course how the parent calls their constructors.
     89
    6490    """
    65     if hasattr(X, '_Hom_'):
    66         return X._Hom_(Y, cat)
    6791
     92
     93    # This should use cache_function instead
     94    # However it breaks somehow the coercion (see e.g. sage -t sage.rings.real_mpfr)
     95    # To be investigated.
    6896    global _cache
    69     key = (X,Y,cat)
     97    key = (X,Y,category)
    7098    if _cache.has_key(key):
    7199        H = _cache[key]()
    72         if H: return H
     100        # What is this test for? Why does the cache ever contain a 0 value?
     101        # This actually occurs: see e.g. sage -t  sage-combinat/sage/categories/modules_with_basis.py
     102        if H:           
     103            return H
    73104
    74     if cat is None or (cat is X.category() and cat is Y.category()):
    75         try:
    76             H = X._Hom_(Y)
    77         except AttributeError:
    78             pass
     105    if hasattr(X, '_Hom_'):
     106        H = X._Hom_(Y, category)
     107        if H is not NotImplemented:
     108            return H
    79109
    80     import category_types
     110#    if category is None or (category is X.category() and category is Y.category()):
     111#        try:
     112#            H = X._Hom_(Y)
     113#        except AttributeError:
     114#            pass
     115#    import category_types
    81116
    82117    cat_X = X.category()
    83118    cat_Y = Y.category()
    84     if cat is None:
     119    if category is None:
    85120        if cat_X.is_subcategory(cat_Y):
    86             cat = cat_Y
     121            category = cat_Y
    87122        elif cat_Y.is_subcategory(cat_X):
    88             if not (cat is None) and not (cat_X is cat_Y):
     123            # NT: this "category is None" test is useless and could be removed
     124            # NT: why is there an assymmetry between X and Y?
     125            if not (category is None) and not (cat_X is cat_Y):
    89126                raise ValueError, "No unambiguous category found for Hom from %s to %s."%(X,Y)
    90             cat = cat_X
     127            category = cat_X
    91128        else:
    92             # try hard to find a suitable base category
    93             subcats_X = category_types.category_hierarchy[cat_X.__class__]
    94             subcats_Y = category_types.category_hierarchy[cat_Y.__class__]
    95             cats = set(subcats_X).intersection(set(subcats_Y))
    96             params = tuple(set(cat_X._parameters()).intersection(cat_Y._parameters()))
    97            
    98             cat = None
    99             size = -1
    100            
    101             for c in cats:
    102                 if len(category_types.category_hierarchy[c]) > size:
    103                     try:
    104                         cat = c(*params)
    105                         size = len(category_types.category_hierarchy[c])
    106                     except TypeError:
    107                         pass
    108                        
    109             if cat is None:
    110                 for c in cats:
    111                     if len(category_types.category_hierarchy[c]) > size:
    112                         try:
    113                             cat = c()
    114                             size = len(category_types.category_hierarchy[c])
    115                         except TypeError:
    116                             pass
     129            # Search for the lowest common super category
     130            subcats_X = cat_X.all_super_categories(proper = True)
     131            subcats_Y = set(cat_Y.all_super_categories(proper = True))
     132            category = None
     133            for c in subcats_X:
     134                if c in subcats_Y:
     135                    category = c
     136                    break
    117137
    118             if cat is None:
     138            if category is None:
    119139                raise TypeError, "No suitable category found for Hom from %s to %s."%(X,Y)
    120140       
    121     elif isinstance(cat, category.Category):
    122         if not isinstance(cat, category.Category):
    123             raise TypeError, "Argument cat (= %s) must be a category."%cat
    124         if not cat_X.is_subcategory(cat) \
    125                or not cat_Y.is_subcategory(cat):
     141    elif isinstance(category, Category):
     142        if not isinstance(category, Category):
     143            raise TypeError, "Argument category (= %s) must be a category."%category
     144        if not cat_X.is_subcategory(category) \
     145               or not cat_Y.is_subcategory(category):
    126146            raise TypeError, \
    127                   "Argument cat (= %s) is incompatible with %s and %s."%(cat, X, Y)
     147                  "Argument category (= %s) is incompatible with %s: %s and %s: %s."%(category, X, cat_X, Y, cat_Y)
    128148    else:
    129         raise TypeError, "Argument cat (= %s) must be a category."%cat
     149        raise TypeError, "Argument category (= %s) must be a category."%category
    130150   
    131151
    132152    # coercing would be incredibly annoying, since the domain and codomain
    133153    # are totally different objects
    134     #X = cat(X); Y = cat(Y)
     154    #X = category(X); Y = category(Y)
    135155
    136156    # construct H
    137     if cat._is_subclass(category_types.HeckeModules):
    138 
    139         from sage.modular.hecke.homspace import HeckeModuleHomspace
    140         H = HeckeModuleHomspace(X, Y)
    141        
    142     elif cat._is_subclass(category_types.FreeModules):
    143 
    144         from sage.modules.free_module_homspace import FreeModuleHomspace
    145         H = FreeModuleHomspace(X, Y, cat)
    146 
    147     elif cat._is_subclass(category_types.Rings):
    148 
    149         from sage.rings.homset import RingHomset
    150         H = RingHomset(X, Y)
    151 
    152     elif cat._is_subclass(category_types.Schemes) or cat._is_subclass(category_types.Schemes_over_base):
    153 
    154         from sage.schemes.generic.homset import SchemeHomset
    155         H = SchemeHomset(X, Y)
    156        
    157     else:  # default
    158         if hasattr(X, '_base') and X._base is not X and X._base is not None:
    159             H = HomsetWithBase(X, Y, cat)
    160         else:
    161             H = Homset(X, Y, cat)
     157    # Design question: should the Homset classes get the category or the homset category?
     158    # For the moment, this is the category, for compatibility with the current implementations
     159    # of Homset in rings, schemes, ...
     160    H = category.hom_category().parent_class(X, Y, category = category)
    162161           
    163162    ##_cache[key] = weakref.ref(H)
    164     _cache[(X, Y, cat)] = weakref.ref(H)
     163    _cache[(X, Y, category)] = weakref.ref(H)
    165164   
    166165    return H
    167166
    def hom(X, Y, f): 
    179178    """
    180179    return Hom(X,Y)(f)
    181180
    182 def End(X, cat=None):
     181def End(X, category=None):
    183182    r"""
    184     Create the set of endomorphisms of X in the category cat.
     183    Create the set of endomorphisms of X in the category category.
    185184   
    186185    INPUT:
    187186   
    188187   
    189188    -  ``X`` - anything
    190189   
    191     -  ``cat`` - (optional) category in which to coerce X
     190    -  ``category`` - (optional) category in which to coerce X
    192191   
    193192   
    194     OUTPUT: a set of endomorphisms in cat
     193    OUTPUT: a set of endomorphisms in category
    195194   
    196195    EXAMPLES::
    197196   
    def End(X, cat=None): 
    212211        sage: S.domain()
    213212        Symmetric group of order 3! as a permutation group
    214213   
    215     Homsets are *not* objects in their category. They are currently
    216     sets.
    217    
    218     ::
    219    
     214    To avoid creating superfluous categories, homsets are in the
     215    homset category of the lowest category which currently says
     216    something specific about its homsets. For example, S is not
     217    in the category of hom sets of the category of groups::
     218
    220219        sage: S.category()
    221         Category of sets
    222         sage: S.domain().category()
    223         Category of groups
     220        Category of hom sets of Category of sets
     221        sage: End(QQ).category()
     222        Category of hom sets of Category of rings
    224223    """
    225     return Hom(X,X, cat)
     224    return Hom(X,X, category)
    226225
    227226def end(X, f):
    228227    """
    class Homset(Set_generic): 
    254253        sage: loads(E.dumps()) == E
    255254        True
    256255    """
    257     def __init__(self, X, Y, cat=None, check=True):
     256    def __init__(self, X, Y, category=None, base = None, check=True):
    258257        self._domain = X
    259258        self._codomain = Y
    260         if cat is None:
    261             cat = X.category()
    262         self.__category = cat
     259        if category is None:
     260            category = X.category()
     261        self.__category = category
    263262        if check:
    264             if not isinstance(cat, category.Category):
    265                 raise TypeError, "cat (=%s) must be a category"%cat
    266             #if not X in cat:
    267             #    raise TypeError, "X (=%s) must be in cat (=%s)"%(X, cat)
    268             #if not Y in cat:
    269             #    raise TypeError, "Y (=%s) must be in cat (=%s)"%(Y, cat)
     263            if not isinstance(category, Category):
     264                raise TypeError, "category (=%s) must be a category"%category
     265            #if not X in category:
     266            #    raise TypeError, "X (=%s) must be in category (=%s)"%(X, category)
     267            #if not Y in category:
     268            #    raise TypeError, "Y (=%s) must be in category (=%s)"%(Y, category)
     269       
     270        Parent.__init__(self, base = base, category = category.hom_category())
    270271
    271272    def _repr_(self):
    272273        return "Set of Morphisms from %s to %s in %s"%(
    class Homset(Set_generic): 
    281282            from sage.categories.homset import Hom
    282283            return CallMorphism(Hom(S, self))
    283284        else:
    284             return parent.Parent._generic_convert_map(self, S)
     285            return parent.ParentMethods._generic_convert_map(self, S)
    285286
    286287    def homset_category(self):
    287288        """
    class Homset(Set_generic): 
    296297        """
    297298        return self.__category
    298299
    299     def __call__(self, x, y=None, check=True):
     300    def __call__(self, x=None, y=None, check=True, on_basis=None):
    300301        """
    301302        Construct a morphism in this homset from x if possible.
    302303       
    class Homset(Set_generic): 
    326327                      Call morphism:
    327328                      From: SymmetricGroup(6)
    328329                      To:   SymmetricGroup(7)
    329        
    330         AUTHORS:
     330
     331            sage: H = Hom(ZZ, ZZ, Sets())
     332            sage: f = H( lambda x: x + 1 )
     333            sage: f.parent()
     334            Set of Morphisms from Integer Ring to Integer Ring in Category of sets
     335            sage: f.domain()
     336            Integer Ring
     337            sage: f.codomain()
     338            Integer Ring
     339            sage: f(1), f(2), f(3)
     340            (2, 3, 4)
     341
     342            sage: H = Hom(Set([1,2,3]), Set([1,2,3]))
     343            sage: f = H( lambda x: 4-x )
     344            sage: f.parent()
     345            Set of Morphisms from {1, 2, 3} to {1, 2, 3} in Category of sets
     346            sage: f(1), f(2), f(3) # todo: not implemented
     347
    331348
    332349        - Robert Bradshaw
    333350        """
     351        # Temporary workaround: currently, HomCategory.ParentMethods's cannot override
     352        # this __call__ method because of the class inheritance order
     353        # This dispatches back the call there
     354        if on_basis is not None:
     355            return self.__call_on_basis__(on_basis = on_basis)
     356        assert x is not None
     357
    334358        if isinstance(x, morphism.Morphism):
    335359            if x.parent() is self:
    336360                return x
    class Homset(Set_generic): 
    349373                        raise TypeError, "Incompatible codomains: x (=%s) cannot be an element of %s"%(x,self)
    350374                    x = mor * x
    351375                return x
     376
     377        if isinstance(x, function) or isinstance(x, instancemethod):
     378            return self.element_class_set_morphism(self, x)
     379           
    352380        raise TypeError, "Unable to coerce x (=%s) to a morphism in %s"%(x,self)
    353381
     382    @lazy_attribute
     383    def element_class_set_morphism(self):
     384#        return morphism.SetMorphism
     385        return self.__make_element_class__(morphism.SetMorphism)
     386
    354387    def __cmp__(self, other):
    355388        if not isinstance(other, Homset):
    356389            return cmp(type(self), type(other))
    class Homset(Set_generic): 
    396429        Return the corresponding homset, but with the domain and codomain
    397430        reversed.
    398431        """
    399         return Homset(self._codomain, self._domain, self.__category)
     432        return Hom(self._codomain, self._domain, self.__category)
    400433       
    401434    ############### For compatibility with old coercion model #######################
    402435   
    class Homset(Set_generic): 
    406439    def coerce_map_from_c(self, R):
    407440        return None
    408441
     442# Really needed???
    409443class HomsetWithBase(Homset):
    410     def __init__(self, X, Y, cat=None, check=True, base=None):
    411         Homset.__init__(self, X, Y, cat, check)
     444    def __init__(self, X, Y, category=None, check=True, base=None):
    412445        if base is None:
    413             Parent.__init__(self, X.base_ring())
    414         else:
    415             Parent.__init__(self, base)
     446            base = X.base_ring()
     447        Homset.__init__(self, X, Y, check=check, category=category, base = base)
    416448       
    417449def is_Homset(x):
    418450    """
  • new file sage/categories/tensor.py

    diff --git a/sage/categories/tensor.py b/sage/categories/tensor.py
    new file mode 100644
    - +  
     1from sage.categories.category import Category, CovariantFunctor
     2from sage.misc.cachefunc import cached_method
     3import sage.structure.parent
     4import sage.structure.element
     5
     6class TensorialCategory(Category):
     7    """
     8    A TensorialCategory is a category endowed with a tensor product
     9    operation on its parents (and on its elements).
     10
     11    Technically, let CClass be a class inheriting from
     12    TensorialCategory. An instance C of CClass is a category.
     13
     14    CClass must implement a class CClass.TensorCategory whose
     15    constructor takes as parameter the category C, and builds the
     16    category of tensor products of elements of C.
     17    """
     18
     19    @cached_method
     20    def tensor_category(self):
     21        """
     22        The category of tensor products of parents in self
     23        """
     24        return self.TensorCategory(self)
     25
     26    class ParentMethods:
     27        def tensor(*parents):
     28            """
     29            Returns the tensor product of the parents
     30            """
     31
     32            return parents[0].Tensor(parents, category = tensor.category_from_parents(parents))
     33
     34    class ElementMethods:
     35        def tensor(*elements):
     36            """
     37            Returns the tensor product of its arguments, as an element of
     38            the tensor product of the parents of those elements.
     39
     40            FIXME: is this a policy that we want to enforce on all parents?
     41            """
     42            assert(all(isinstance(element, sage.structure.element.Element) for element in elements))
     43            parents = [element.parent() for element in elements]
     44            return tensor(parents).tensor_of_elements(*elements) # good name???
     45
     46
     47class TensorCategory(Category):
     48    """
     49    An abstract base class for all TensorCategory's defined in
     50    TensorialCategory's.
     51    """
     52
     53    def __init__(self, category, name=None):
     54        Category.__init__(self, name)
     55        self.base_category = category
     56
     57    def _repr_(self):
     58        """
     59        EXAMPLES::
     60
     61            sage: ModulesWithBasis(QQ).tensor_category()
     62            Category of tensor products of modules with basis over Rational Field
     63
     64        """
     65        return "Category of tensor products of %s"%repr(self.base_category)[12:]
     66
     67    def tensor_category(self):
     68        """
     69        Returns the category of tensor products of self
     70
     71        By associativity of tensor products, this is self
     72        (a tensor product of tensor products of A's is a tensor product of A's)
     73        """
     74        return self
     75
     76
     77class TensorFunctor(CovariantFunctor):
     78    """
     79    A singleton class for the tensor functor
     80    """
     81    functor_name = "tensor"
     82    functor_category = "tensor_category"
     83    FunctorialCategory = TensorialCategory
     84    symbol = " # "
     85
     86tensor = TensorFunctor()
  • new file sage/categories/direct_sum.py

    diff --git a/sage/categories/direct_sum.py b/sage/categories/direct_sum.py
    new file mode 100644
    - +  
     1from sage.categories.category import Category, CovariantFunctor
     2from sage.misc.cachefunc import cached_method
     3import sage.structure.parent
     4import sage.structure.element
     5
     6class AbelianCategory(Category):
     7    """
     8    An abelian category is a category endowed with a direct sum
     9    functor (operation on its parents and on its elements).
     10
     11    Technically, let CClass be a class inheriting from
     12    AbelianCategory. An instance C of CClass is a category.
     13
     14    CClass must implement a method C.direct_sum_category() which
     15    returns the category of direct sums of parents in C. With the
     16    default implementation of direct_sum_category, it is sufficient to
     17    provide a class CClass.DirectSumCategory whose constructor takes
     18    as parameter the category C and returns the desired category.
     19
     20    In C is a subcategory of another abelian category D,
     21    C.direct_sum_category() is automatically considered as a
     22    subcategory of D.direct_sum_category().
     23    """
     24
     25    @cached_method
     26    def direct_sum_category(self):
     27        """
     28        The category of tensor products of parents in self
     29        """
     30        return self.DirectSumCategory(self)
     31
     32    class ParentMethods:
     33        def direct_sum(*parents):
     34            """
     35            Returns the direct sum of the parents
     36            """
     37
     38            return parents[0].DirectSum(parents, category = direct_sum.category_from_parents(parents))
     39
     40    class ElementMethods:
     41        def direct_sum(*elements):
     42            """
     43            Returns the direct sum of its arguments, as an element of
     44            the direct sum of the parents of those elements.
     45
     46            FIXME: is this a policy that we want to enforce on all parents?
     47            """
     48            assert(all(isinstance(element, sage.structure.element.Element) for element in elements))
     49            parents = [element.parent() for element in elements]
     50            return direct_sum(parents).direct_sum_of_elements(elements) # good name???
     51
     52
     53class DirectSumCategory(AbelianCategory):
     54    """
     55    An abstract base class for all DirectSumCategory's defined in
     56    AbelianCategory's.
     57    """
     58
     59    def __init__(self, category, name=None):
     60        Category.__init__(self, name)
     61        self.base_category = category
     62
     63    def _repr_(self):
     64        """
     65        EXAMPLES::
     66
     67            sage: ModulesWithBasis(QQ).direct_sum_category()
     68            Category of direct sums of modules with basis over Rational Field
     69
     70        """
     71        return "Category of direct sums of %s"%repr(self.base_category)[12:]
     72
     73    def direct_sum_category(self):
     74        """
     75        Returns the category of direct sums of self
     76
     77        By associativity of direct sums, this is self (a direct_sum of
     78        direct_sums of A's is a direct sum of A's)
     79        """
     80        return self
     81
     82
     83class DirectSumFunctor(CovariantFunctor):
     84    """
     85    A singleton class for the direct_sum functor
     86    """
     87    functor_name = "direct_sum"
     88    functor_category = "direct_sum_category"
     89    FunctorialCategory = AbelianCategory
     90    symbol = " (+) "
     91
     92direct_sum = DirectSumFunctor()
  • new file sage/categories/dual.py

    diff --git a/sage/categories/dual.py b/sage/categories/dual.py
    new file mode 100644
    - +  
     1from category_types import *
     2
     3class DualityCategory(Category):
     4    """
     5    """
     6    def dual(self):
     7        """
     8        Returns the dual category
     9        """
     10        raise NotImplementedError
     11
     12# could do SelfDualCategory
  • sage/categories/map.pyx

    diff --git a/sage/categories/map.pyx b/sage/categories/map.pyx
    a b cdef class Map(Element): 
    101101       
    102102    cpdef codomain(self):
    103103        return self._codomain
    104        
     104
     105    def category_for(self):
     106        """
     107        Returns the category self is a morphism for
     108
     109        FIXME: find a better name for this method
     110        """
     111        return self.parent().homset_category()
     112
    105113    def __call__(self, x, *args, **kwds):
    106114        """
    107115        Apply this map to x.
    cdef class Map(Element): 
    166174            raise TypeError, "right (=%s) must be a map to multiply it by %s"%(right, self)
    167175        if right.codomain() != self.domain():
    168176            raise TypeError, "self (=%s) domain must equal right (=%s) codomain"%(self, right)
    169         H = homset.Hom(right.domain(), self.codomain(), self.parent().category())
    170         return self._composition_(right, H)
     177        return self._composition_(right)
    171178
    172     def _composition_(self, right, homset):
    173         return FormalCompositeMap(homset, right, self)
     179    def _composition_(self, right):
     180        # see the restrictions on Category.meet
     181        category = self.category_for().meet(right.category_for())
     182        H = homset.Hom(right.domain(), self.codomain(), category)
     183        return FormalCompositeMap(H, right, self)
    174184       
    175185    def pre_compose(self, right):
    176186        if self.domain() is not right.codomain():
    177187            right = right.extend_codomain(self.domain())
    178         H = homset.Hom(right.domain(), self.codomain(), self.parent().category())
    179         return self._composition_(right, H)
     188        return self._composition_(right)
    180189       
    181190    def post_compose(self, left):
    182         H = homset.Hom(self.domain(), left.codomain(), self.parent().category())
    183         return left._composition_(self, H)
     191        return left._composition_(self)
    184192       
    185193    def extend_domain(self, new_domain):
    186194        r"""
    cdef class Map(Element): 
    297305cdef class Section(Map):
    298306    def __init__(self, map):
    299307        from sage.categories.homset import Hom
    300         from sage.categories.category_types import SetsWithPartialMaps
     308        from sage.categories.all import SetsWithPartialMaps
    301309        Map.__init__(self, Hom(map.codomain(), map.domain(), SetsWithPartialMaps()))
    302310        self._inverse = map
    303311
  • sage/categories/morphism.pyx

    diff --git a/sage/categories/morphism.pyx b/sage/categories/morphism.pyx
    a b cdef class Morphism(Map): 
    7070    def pushforward(self, I):
    7171        raise NotImplementedError
    7272
     73    def register_as_coercion(self):
     74        self.codomain().register_coercion(self)
     75
    7376cdef class FormalCoercionMorphism(Morphism):
    7477    def __init__(self, parent):
    7578        Morphism.__init__(self, parent)
    cdef class SetMorphism(Morphism): 
    140143        -  ``function`` - a Python function that takes elements
    141144           of the domain as input and returns elements of the domain.
    142145        """
     146        Morphism.__init__(self, parent)
    143147        self._function = function
    144148
    145149    cpdef Element _call_(self, x):
    146150        return self._function(x)
    147151       
     152# class SetMorphismPython(SetMorphism):
     153#     """
     154#     Temporary workaround: this is the same as SetMorphism, but as a
     155#     python (and not cython) class
     156#     """
     157#     def __init__(self, parent, function):
     158#         """
     159#         INPUT:
     160#         parent -- a Homset
     161#         function -- a Python function that takes elements of the domain as input
     162#                     and returns elements of the domain.
     163#         """
     164#         self._function = function
     165
     166#     def Element _call_(self, x):
     167#         return self._function(x)