On Jun 4, 2008, at 4:07 AM, Bill Page wrote:

> Robert,
>
> Thanks for the elaboration. I hope that this follow-up is not too far
> off topic and I don't want to distract you (or any of the Sage
> developers) from your main tasks. I wrote this mostly as notes and
> questions to myself  - but if you or anyone else have some time or the
> inclination to correct or comment as time permits, that would be
> great.

I'm sure a lot of other people have similar questions, and it will be  
good to put it down in writing.

>
> On Tue, Jun 3, 2008 at 10:04 PM, Robert Bradshaw wrote:
>>
>> On Jun 3, 2008, at 4:50 PM, Bill Page wrote:
>>
>>> How does it [categories in Sage] relate to the
>>> concept of "parent" - which seems equally ill-defined to me?
>>
>> A Parent is an Object in the category of Sets, though in the context
>> of coercion one usually assumes one can some kind of arithmetic
>> (binary operations) on their elements.
>> ...
>> On Jun 3, 2008, at 7:11 PM, David Harvey wrote:
>> ...
>>> Don't you mean to say something more like "a parent is an object
>>> of a concrete category", i.e. a category C with a faithful functor
>>> f : C -> Set, such that the "elements" (as understood by Sage) of
>>> the parent P are exactly the elements of f(P)?
>
> Ok (and thanks also for the clarification, David). There are of course
> two different uses of "object" here: 1) object of some category, 2)
> Python object. All Python objects have a 'type', i.e. belong to some
> Python class.
>
> So in Sage 3.0.2 I observe for example:
>
> sage: type(1)
> <type 'sage.rings.integer.Integer'>
> sage: parent(1)
> Integer Ring
> sage: type(parent(1))
> <type 'sage.rings.integer_ring.IntegerRing_class'>
> sage: category(parent(1))
> Category of rings
> sage: type(category(parent(1)))
> <class 'sage.categories.category_types.Rings'>
>
> and
>
> sage: type(1.0)
> <type 'sage.rings.real_mpfr.RealNumber'>
> sage: parent(1.0)
> Real Field with 53 bits of precision
> sage: type(parent(1.0))
> <type 'sage.rings.real_mpfr.RealField'>
> sage: category(parent(1.0))
> Category of fields
> sage: type(category(parent(1.0)))
> <class 'sage.categories.category_types.Fields'>
>
> These seem consistent to me, albeit rather complex. However I am not
> sure I understand the following:
>
> sage: parent(IntegerRing())
> <type 'sage.rings.integer_ring.IntegerRing_class'>
> sage: parent(RealField())
> <type 'sage.rings.real_mpfr.RealField'>
>
> Could you explain why the parent of an object of some category is a  
> type?

David's explanation of this is right on. We need parent() to work in  
some sensible way on non-Elements (e.g. Python ints, objects from  
outside Sage) to be able do some kind of coercion reasoning on them.  
Python is a dynamically typed language, ever object has a type.

>
>>
>>> What is the relationship to inheritance in Python? Is the intention
>>> to give all mathematical objects defined in Sage some categorical
>>> structure? What about categories themselves as mathematical
>>> structures - e.g. a category is a kind of directed graph with  
>>> additional
>>> structure?
>>
>> A big push of this model is to divorce the relationship between
>> inheritance (which primarily has to do with implementation) and
>> mathematical categorization.
>
> At first blush it still seems strange to me to distinguish between the
> parent of an object and the type of an object. The instances of a type
> are often considered elements. Is the invention of 'parent' in Sage
> due to some inherent limitation of Python classes? Do you really want
> to say more abstractly that a certain type *represents* a certain
> parent? E.g. Does 'sage.rings.real_mpfr.RealNumber' represent
> 'RealField()'? Can there be other representations of 'RealField()' in
> Sage? How can I find out for example if 'sage.rings.integer.Integer'
> represents 'IntegerRing()'?

One should think of the type of an object as what specifies its  
implementation (including its internal representation). In this sense  
it is like a class in Java, C++, or any other programming language.  
(In Python there is a subtle (and mostly historical) difference  
between types and classes depending on whether or not it's written in  
C, but for the most part they can be used interchangeably). Python  
has multiple inheritance, but Cython does not (the C format of a  
compiled Python class is a C struct, so this is not so much a Cython  
limitation as a Python/C API limitation.)

Most of the time there is a 1-to-1 correspondence between Parents and  
the types of its Elements. For example, and element of the Parent RR  
(= RealField(53) is represented by sage.rings.real_mpfr.RealNumber.  
If I do RR(3) I get back an object of type  
sage.rings.real_mpfr.RealNumber representing the floating point  
number 3 to 53 bits of precision, and it's Parent is RR. RealField 
(100) is a new Parent, whose elements are again of type  
sage.rings.real_mpfr.RealNumber but to 100 bits of precision.

Sometimes, however, the same type is used for multiple parents. There  
are several integer mod types (depending on whether or not the  
modulus fits in a single word) and they are used for both generic Z/ 
nZ and prime-order finite fields. Thus we have

sage: [type(mod(-1, 100^k)) for k in [2..5]]
[<type 'sage.rings.integer_mod.IntegerMod_int'>,
  <type 'sage.rings.integer_mod.IntegerMod_int64'>,
  <type 'sage.rings.integer_mod.IntegerMod_int64'>,
  <type 'sage.rings.integer_mod.IntegerMod_gmp'>]

sage: [parent(mod(-1, 100^k)) for k in [2..5]]
[Ring of integers modulo 10000,
  Ring of integers modulo 1000000,
  Ring of integers modulo 100000000,
  Ring of integers modulo 10000000000]

On the other hand, some parents may have elements of several types.  
The "SymbolicRing" is one such example.

sage: [type(a) for a in v]
[<class 'sage.calculus.calculus.SymbolicConstant'>,
  <class 'sage.functions.constants.Pi'>,
  <class 'sage.calculus.calculus.SymbolicArithmetic'>,
  <class 'sage.calculus.calculus.SymbolicComposition'>]

sage: [parent(a) for a in v]
[Symbolic Ring, Symbolic Ring, Symbolic Ring, Symbolic Ring]

> From my experience with Axiom I am sympathetic to the separation of
> implementation and specification but in Axiom "domains" are both
> parents and types. A domain can inherit it's implementation from
> another domain (via add). A domain can also serve as the
> representation for some other domain (via Rep). For example
> IntegerMod(5) is the representation of PrimeField(5). IntegerMod(5) in
> turn is represented by SingleInteger, etc. In Axiom, at the deepest
> level all types are ultimately provided by Lisp. These types are not
> really Axiom domains and so I suppose the situation is analogous to
> Python types and Sage parents.

This sounds like the correct analogy. In Sage as well elements of  
prime finite fields are the same type as elements of Z/nZ for  
composite n, but they have different parents.

> Axiom categories on the other hand form a lattice. Domains belong to
> categories by assertion or by virtue of the subdomain relationship. In
> Axiom there is an operator named 'has' which provides the same
> information as 'category' in Sage so that:
>
>   x has y
>
> is just 'y == category(x)'. For example 'Float has Field' is  
> equivalent to:
>
> sage: Fields() == category(RealField())
> True
>
> Although in Axiom a domain may satisfy more than one category. Will
> this be possible in Sage in the future?

Categories in Sage aren't as fully developed as they could be, but  
they do form a lattice.

sage: C = category(FiniteField(13)); C
Category of fields
sage: C.is_subcategory(Rings())
True

One of the changes in this latest coercion push is to allow Parents  
to belong to several categories.

> What information does Sage actually have about a given category? For
> example, what does Sage know about the relationship between Rings()
> and Fields()? E.g. functors?

Only the bare minimum at this point.

> None of this has much to do with "category theory" as such. Categories
> in Axiom are only vaguely related to categories in Mathematics. So I
> suppose from your description that categories in Sage will play a
> similar role but will be more strongly related to the mathematical
> concept?

Yes. This will also be a place to put generic implementations of  
algorithms. For example, one has the category of Euclidian domains,  
where one can define a generic gcd algorithm that will then get  
attached (as a method) to every element of that category.

>> This will allow categories to play a larger role (though work in that
>> area can be done after the merge as it is not disruptive). For
>> example, Z/nZ[x] is implemented the same whether or not p is
>> a prime, but the category it lives in (and hence the methods one
>> can do on it) vary.
>
> Are you suggesting that Z/pZ should be considered a field just because
> p is prime?

No, it might be expensive to test for primality.

> sage: category(Zmod(7))
> Category of rings
>
> sage: Zmod(7).is_field()
> True
>
> Perhaps an alternative would be to provide a coercion to some object
> whose parent is in Fields()?

The is_field method tests whether or not this specific instance  
happens to be a field, which is true in this case. But we do provide  
a coercion

sage: F = GF(7)
sage: F.coerce_map_from(Zmod(7))

Natural morphism:
   From: Ring of integers modulo 7
   To:   Finite Field of size 7

>
>> As another example, matrix spaces are algebras iff they are square,
>> but one doesn't want to have a special class for square matrices over
>> <insert optimized type here>.
>
> I am not sure what you mean by "matrix spaces" as such but the
> category of matrices does make sense to me. See for example:
>
> http://unapologetic.wordpress.com/2008/06/02/the-category-of- 
> matrices-i
>
> Maybe it is interesting because in this category the morphisms are
> matrices and the objects are just the row and column dimensions -
> non-negative integers. How would this fit into the category model in
> Sage?
>
> There is a monoidal sub-category of square matrices.

A MatrixSpace is a parent

sage: M = matrix(QQ, 2); M
[0 0]
[0 0]
sage: parent(M)
Full MatrixSpace of 2 by 2 dense matrices over Rational Field

It is a module (via scalar multiplication) over its basering (in the  
case above, the integers) and so (should) lie in the category of Q- 
modules. In the case of square matrices, it is actually an algebra  
over its basering, and its category is the category of Q-algebras.

>> Generic algorithms can be put on the categories such
>> that if g is in category C, and C has a method x, then g.x() will
>> work.
>
> Do you mean 'category(parent(g))==C'?

Yes.

> How will such a generic method x
> of C operate on g? Do you have some example coding that implements
> this idea?

Not at the moment. Say a and b have parent P in category C. One types

a.gcd(b)

Then, a does not have a method "gcd" it will try

category(parent(a)).element_gcd(a,b)

which will be a generic implementation of the euclidean algorithm  
(assuming C is a category supporting this).

- Robert





--~--~---------~--~----~------------~-------~--~----~
To post to this group, send email to sage-devel@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/sage-devel
URLs: http://www.sagemath.org
-~----------~----~----~----~------~----~------~--~---

Reply via email to