#10963: More functorial constructions
-------------------------------------------------------------------------+--
       Reporter:  nthiery                                                |      
   Owner:  stumpc5                                                              
                        
           Type:  enhancement                                            |      
  Status:  needs_work                                                           
                        
       Priority:  major                                                  |     
Milestone:                                                                      
                         
      Component:  categories                                             |    
Resolution:                                                                     
                          
       Keywords:                                                         |   
Work issues:  Reduce startup time by 5%. Avoid "recursion depth exceeded 
(ignored)". Trivial doctest fixes.
Report Upstream:  N/A                                                    |     
Reviewers:  Simon King                                                          
                         
        Authors:  Nicolas M. ThiƩry                                      |     
Merged in:                                                                      
                         
   Dependencies:  #11224, #8327, #10193, #12895, #14516, #14722, #13589  |      
Stopgaps:                                                                       
                        
-------------------------------------------------------------------------+--

Comment (by SimonKing):

 If I understand correctly, the reason for creating a `JoinCategory` is to
 get the correct supercategories. But there are alternative ways to get the
 supercategories right. I could imagine to use a dynamic class instead. So,
 the aim of this post is to present an alternative approach that avoids
 joins.

 If C is a category and one wants to have `C.MyAxiom()`, then I suggest to
 create a dynamic class `cls` out of `C.__class__` (and perhaps also using
 the class `C.MyAxiom`?), and set a ''class'' attribute `cls._used_axioms`
 which is a (frozen) set formed by `C.__class__._used_axioms` and
 `"MyAxiom"`.

 Note: The order in which the axioms are given should not matter. Hence,
 the way of caching the dynamic class should be: By a class that has no
 axioms, and by `C.__class__._used_axioms`.

 We would like to call `cls` with the same `__init__` arguments that were
 used for creating `C`. So, how to get the init data? No problem, since `C`
 uses `UniqueRepresentation`!. For example:
 {{{
 sage: C = Bimodules(ZZ, QQ)
 sage: C._reduction
 (sage.categories.bimodules.Bimodules, (Integer Ring, Rational Field), {})
 }}}

 So, `C.MyAxiom()` would eventually do something like this
 {{{
    cls = dynamic_class("MyAxiom"+C.__class__.__name__, (C.__class__,
 C.MyAxiom), C.__class__, <take care of caching>)
    return cls(*(C._reduction[1][0]), **(C._reduction[1][1]))
 }}}

 Note that by way of caching the dynamic class, I guess the above would
 automatically cover the corner case that `C.__class__._used_axioms`
 contains `"MyAxiom"`. Namely, in this case, `cls is C.__class__` by means
 of caching the dynamic class, and then `cls(*..., **...)` coincides with
 C, since it is a `UniqueRepresentation`.

 By means of explicitly overloading the cache of the dynamic class, one
 could even ensure that `DivisionRings.Finite()` returns `Fields.Finite()`,
 I guess.

 Let's denote `C2=C.MyAxiom()`. And then, the critical question is: How to
 determine the super categories of `C2`?

 I guess for each axiom `A in C2.__class__._used_axioms`, we want to return
 `C2._without_axiom(A)`, and we want to return `D._with_axiom(A)` for all
 `D` is in `C2._without_axiom(A).super_categories()`, of course removing
 duplicates.

 So, there only remains to answer: What is `C2._without_axiom(A)`?

 Again, we can use `C2._reduction` to get the input data, but how to get
 the class of `D=C2._without_axiom(A)`? Note that `C2` might have several
 axioms, and we do ''not'' order the axioms.

 However, we know what `D.__class__._used_axioms` is supposed to look like:
 It is `C2.__class__._used_axiom.difference("MyAxiom")`.

 Thus, we get something like this:
 {{{
 @cached_method
 def _without_axiom(self, axiom):
     if axiom not in self.__class__._used_axioms:
         <raise some error>
     new_axioms = self.__class__._used_axioms.difference([axiom])
     for cls in self.__class__.__mro__:
         if getattr(cls, "_used_axioms", None) == new_axioms:
             break
     if cls is object:
         <raise some error>
     return cls(*(self._reduction[1][0]), **(self._reduction[1][1]))
 }}}

 Do you think this would make sense?

-- 
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/10963#comment:44>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, 
and MATLAB

-- 
You received this message because you are subscribed to the Google Groups 
"sage-trac" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sage-trac.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to