On Wed, Jun 4, 2008 at 1:54 PM, Robert Bradshaw wrote:
>
> On Jun 4, 2008, at 4:07 AM, Bill Page wrote:
> ...
>>
>> 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.
>

So is this essentially an admission that the concept of 'parent' is
superfluous and could have in fact been implemented just at Python
'type'? I am not sure that I would actually advocate this now, but for
argument's sake: Why not do it this way all of the time? Python
classes all end up as (potential) parents. I think that this more or
less is what at least some Magma developers had in mind. E.g. We read
in the preface to the Magma HTML Help Document:

http://magma.maths.usyd.edu.au/magma/htmlhelp/preface.htm

"Every object created during the course of a computation is associated
with a unique parent algebraic structure. The type of an object is
then simply its parent structure."

> ...
> 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.)
>

The lack of multiple inheritance in Cython seems to be a major design
obstacle. Although a C struct is not a real class, it is not clear to
me why this is not adequate in compiled code. Wouldn't it be
sufficient to merge (flatten) the components of the multiple ancesters
into one struct? If not (e.g. if it is necessary to retain some
knowledge of their origins), why not provide nested structs? But I
suppose that this is quite off-topic...

> 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]
>

Hmmm... what I think I see here is multiple Python types (_int,
_int64, _gmp) being used for the *same* parent, i.e. "Ring of integers
modulo n" (for some parameter n). Simple inheritance should make this
easy, no?

> 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]
>

"SymbolicRing" is another thing that worries me a little. Exactly what
(mathematically) is a symbolic ring? E.g. Why is it a ring and not a
field? Operations like 'sin(sin(sin(x))).parent()' doesn't look much
like a ring to me. Probably most other computer algebra systems would
just call this an "expression tree" or AST or something like that. Why
do we need different types (sub-classes)?

>> 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.
> ...
> 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.
>

To the best of my knowledge, the formal concept of "representation" in
a computer algebra systems is unique to Axiom. Each domain has a
specified 'Rep'consisting of some domain expression. E.g.

   Rep == Integer

or

   Rep == Union(Record(car:%, cdr:%), "nil")

% stands for "this domain", so this definition amounts to some
recursive structure. Of course recursively defined classes are also
possible in Python but they require much more discipline on the part
of the programmer.

Now there are two operators 'rep' and 'per' that provide coercion to
and from Rep. So we might say for example that some operation * in
this domain is implemented by * from Rep:

  x * y == per( rep(x) * rep(y) )

The trouble is: I don't see anything here that could be called a
"parent". Or perhaps, they are all "parents" except for those initial
domains for which we never explicitly specify a Rep.

>
> 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
>

Ah, I think that is very useful. Does the "Category of fields" inherit
any generic operations from "Rings()"?

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

That sounds good. So does this mean that the 'category' method now
returns a list?

> ... 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.
> ...
>>
>> 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
>

Excellent. But, hmm... this is supposed to be a morphism in some
category. What category?

sage: category(Zmod(7))
Category of rings
sage: category(FiniteField(7))
Category of fields
sage: category(FiniteField(7)).is_subcategory(category(Zmod(7)))
True
------

Ok, good. We just need the injection.

>> ...
>> 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?
>>...
>
> 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.

Ok, it is an object in some category. Maybe a good name would be the
category "VectorSpace"? (Q-modules is ok). What makes them a
MatrixSpace?

> In the case of square matrices, it is actually an algebra
> over its basering, and its category is the category of Q-algebras.
>

Anyway, I suppose this taxonomy is not such a big deal. One only needs
to learn the language - of course it has turned out in Axiom that this
is not that simple a problem - hence interactive tools for querying
and navigating the domain and category hierarchies (hyperdoc).

> ...

Thanks for continuing the discussion.

Regards,
Bill Page.

--~--~---------~--~----~------------~-------~--~----~
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