>
>
> > change "To coerce from the category down to the parent" --> "To coerce 
> from 
> > the abstraction layer to the parent". In this abstraction layer (which 
> is 
> > close to the categories now available, but not quite the same), we would 
> > have a list of methods for the parent class and the element class of a 
> > Category C. Now say you have parentA and parentB both implementing the 
> same 
> > category C. As part of its definition, parentA c/should tell how to 
> > initialize it using exclusively methods from this abstraction layer. But 
> > parentB implements some of these methods. With any luck there might be 
> > enough overlap that we automatically get a coercion from parentB -> 
> parentA. 
> > This would work by going from parentB "up" to the abstraction layer's 
> method 
> > and then "down" onto parentA. I mean up and down not in the sense of 
> class 
> > hierarchy but in terms of abstraction level. 
>
> Sounds interesting, lets make this idea concrete. So, lets assume we 
> have the category of Rings, and we want to define the category of 
> (univariate?) polynomials over a Ring that extends (literally or not) 
> the category of Rings. What (additional) contract on Parents would you 
> require/enforce? For example, one could require a method converting 
> from a list/dict of ring elements to the polynomial, and the inverse. 
> A constant map (which of course could be implemented in terms of the 
> above)? GCD if the basering is a field? 
>

You are asking about a different kind of coercion from the one I was 
talking about (that's part of my point: some are are purely at the 
concrete/Parents level -when the category does not change, I think these 
are called conversions as well-, some are purely at the abstract/category 
level, while some others are compositions of these two "pure" kinds of 
coercions). 

Let's use decorators to describe the two "pure" kinds of coercions, with 
prototype of the code that would run: 
1) Purely concrete level - the kind I was talking about - the category 
stays the same, but the implementation (i.e. parents) changes. Even in this 
case this is dealt with by specifying in terms of the category what 
arguments the constructor takes in each of the parents.

class CategoryC(Category):
    class ElementMethods:
        def invariantM(self):
            pass
        ....
        def invariantX(self):
            pass
        def invariantZ(self):
            pass

class Parent1(Parent, category = CategoryC):                         # 
unrelated point: for me it makes more sense to specify the category here.
                                                                            
                # syntax like this is made possible because this is 
specified in a module where the metaclass
                                                                            
                # used knows how to deal with the category keyword in the 
"bases".
    @from_category(lambda self: type_expected_for_arg1(self.invariantM()), 
lambda self: type_expected_for_arg2(self.invariantN()))   # syntax to 
improve
              # means that arg1 below results from applying the first 
function to any object of the same category CategoryC (if possible)
              # similar for arg2
    def _element_constructor_(self, arg1, arg2):
        pass

class Element1(Parent1.Element)
    def invariantM(self):
        pass
    def invariantN(self):
        pass
    def invariantO(self):
        pass
    def invariantP(self):
        pass

So CategoryC has many invariants, M to Z. 
Parent1 has a constructor for the elements that takes as input the 
invariants M and N in some specified types, and its element is then able to 
compute invariants O and P (let's say in some standardized types, but maybe 
these methods could be decorated as well with type specifications). 
Parent2 (unshown) takes as input the invariants O, P and computes Q, R, and 
so on for a bunch of Parents
One way to look ar this is that Parent1 provides the following conversions:
     - the composite (CategoryC.invariantM, CategoryC.invariantN) 
to  (CategoryC.invariantO)
     - the composite (CategoryC.invariantM, CategoryC.invariantN) 
to  (CategoryC.invariantP)
     - the composite (CategoryC.invariantM, CategoryC.invariantN) to the 
composite (CategoryC.invariantO, CategoryC.invariantP)

Parent2 provides different ones, and so on for the other Parents.
All together this could make for a full strategy to recover some set of 
invariants from some other set. 
Coercions would allow here to construct a composite parent from many 
different parents sharing the same category. 

It might feel artificial, but for the sage+databases workshop in Edinburgh 
in January, I am thinking along those lines. A Parent would still 
correspond to a specific implementation. Not of code, but rather an 
implementation of a specific schema for a subset of the invariants of the 
category being modeled. People come up with many schemas for math data, and 
actually it would even make sense to consider them to be dynamic. I want to 
avoid at all costs forcing people to look at each other's  data formats 
(unreasonable burden) to create conversions. That's why I am looking at the 
categories framework as providing a common abstract layer while staying 
sufficiently generic and expressive.

(Note that doing things this way would make it possible to generate 
systematic tests that the results of computing invariants in different 
implementations are the same).

2) Now, this is the kind you were asking about: coercions between Parents 
with different underlying categories. 
You said: 

 So, lets assume we have the category of Rings, and we want to define the 
category of (univariate?) polynomials over a Ring that extends (literally 
or not) the category of Rings. What (additional) contract on Parents would 
you  require/enforce? 

For this coercion, nothing would be required of the Parents: it has nothing 
to do with them!
Someone would have to say in the category framework that there is always a 
morphism from a ring R to a graded algebra over that ring R, and register 
this as a coercion (This would have to happen in a GradedAlgebra functor 
analogous to the Algebra functor). 

Is this unrealistic? Does some of this already happen?

Paul
 

>
> >> A while ago, I have created a public worksheet on "how to implement 
> >> basic algebraic structures in Sage", using category framework and 
> >> coercion. 
> >> I think at some point it was supposed to become part of the 
> >> documentation, but I think we lost momentum. 
> > 
> > I just found what you posted a year ago. That's great! As I said, 
> exactly 
> > this should be available somewhere official and marked as current. 
> > 
> > 
> >> 
> >> Both decorators and metaclasses are used in Sage. Note one problem, 
> >> though: 
> >> If you want to create a new class inheriting from classes with distinct 
> >> metaclasses, then Python complains. 
> > 
> > Yes. Yes. 
> > 
> >> 
> >> I had experimental code to overcome that problem, namely by using 
> >> meta-metaclasses that dynamically create a new common metaclass out of 
> any 
> >> list of metaclasses. Hence, if A and B are classes with metaclasses MA 
> and 
> >> MB, then you can define 
> >>  class C(A,B) 
> >> so that C gets a dynamically created metaclass MC that is a sub-class 
> of 
> >> both MA and MB. The idea is that both MA and MB (which *are* 
> >> metaclasses) have a common meta-metaclass MM, and MM is able to create 
> a 
> >> new metaclass MC out of MA and MB. 
> > 
> > Yes. Since these metaclasses are there to specifically abstract some 
> > concerns's implementation details, these metaclasses are aspects. Then 
> this 
> > step is aspect weaving. 
> > 
> >> 
> >> In that way, you could have metaclasses for different purposes, and can 
> >> freely combine them: You want a class that is pickled by construction 
> >> and whose instances are cached? Then simply combine 
> >> DynamicMetaclass and ClasscallMetaclass. No need to separately/manually 
> >> define DynamicClasscallMetaclass anymore - the meta-metaclass would do 
> >> that for you. 
> > 
> > Yes. I was thinking along the same lines. Do you think the ordering of 
> the 
> > metaclasses should matter? 
> > 
> >> 
> >> But it seems people found the idea of meta-metaclasses a bit 
> confusing... 
> > 
> > Well, it is, but I think it's a valid solution. And 95% of people won't 
> have 
> > to worry about these meta metaclasses: the interface could be a 
> customizable 
> > MagicObject for instance. The cost is on the side of the metaclass, 
> whose 
> > complexity is fairly high. The reward is that the decorators are trivial 
> to 
> > use. 
> > 
> >> 
> >> 
> >> >  - "This will slow down the one class I am using a lot": Not if it's 
> >> > done 
> >> > right. In fact, if it's done very right it would speed up 
> considerably 
> >> > everything, 
> >> 
> >> +1. 
> >> 
> >> One example: One can write a FastHashMetaclass. If you then take a 
> >> python class A that has a `__hash__` method, and apply to A the 
> >> FastHashMetaclass, then A.__hash__ would automatically be turned into a 
> >> fast Cython hash that moreover is cached (so that the hash value does 
> >> not need to be computed repeatedly). 
> >> 
> >> Best regards, 
> >> Simon 
> >> 
> >> 
> > -- 
> > You received this message because you are subscribed to the Google 
> Groups 
> > "sage-devel" group. 
> > To post to this group, send email to 
> > sage-...@googlegroups.com<javascript:>. 
>
> > To unsubscribe from this group, send email to 
> > sage-devel+...@googlegroups.com <javascript:>. 
> > Visit this group at http://groups.google.com/group/sage-devel?hl=en. 
> > 
> > 
>

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To post to this group, send email to sage-devel@googlegroups.com.
To unsubscribe from this group, send email to 
sage-devel+unsubscr...@googlegroups.com.
Visit this group at http://groups.google.com/group/sage-devel?hl=en.


Reply via email to