#10963: More functorial constructions
-------------------------------------+-------------------------------------
       Reporter:  nthiery            |        Owner:  stumpc5
           Type:  enhancement        |       Status:  needs_review
       Priority:  major              |    Milestone:  sage-6.1
      Component:  categories         |   Resolution:
       Keywords:  days54             |    Merged in:
        Authors:  Nicolas M. Thiéry  |    Reviewers:  Simon King, Frédéric
Report Upstream:  N/A                |  Chapoton
         Branch:                     |  Work issues:
  public/ticket/10963                |       Commit:
   Dependencies:  #11224, #8327,     |  8045aa4a4b7ada735b3eb6055382f9b341a39f1e
  #10193, #12895, #14516, #14722,    |     Stopgaps:
  #13589, #14471, #15069, #15094,    |
  #11688, #13394, #15150, #15506     |
-------------------------------------+-------------------------------------

Comment (by nbruin):

 OK, I think I've pinned down what bits make me think that the current
 implementation may be a bit unnatural for (what I understand of) what is
 being
 modelled. To me it seems there are some differences between the
 implementation
 and the model. That is often necessary in practice, so they may be quite
 justified. But I see some problems popping up here that may be due to
 those
 differences.

 First: what is modelled? As I understand this is an acyclic digraph, where
 the
 vertices are categories and the edges are labelled with axioms.
 Furthermore, I
 think the assumption is that this graph is determined at build/startup
 time. The
 modelled graph is supposed to be constant throughout runtime (so Simon's
 desire
 to dynamically extend the graph would, strictly speaking, not fit in the
 model).

 There is of course information that is carried with this graph. I'm not
 sure
 what exactly the information is, but it seems to be mainly "code" (methods
 etc.), attached to the vertices.

 Instantiating the entire graph at startup is apparently too expensive (I
 can
 definitely believe so), so although the modelled graph is constant, we are
 only
 keeping part of it in memory, gradually extending it as needed.

 It seems that each category is modelled by a "class" (for code-centric
 information, this seems a reasonable choice). However, inheritance isn't
 used to
 express edges (they wouldn not be sufficient anyway, since "subclass of"
 arrows
 don't carry labels). Instead, "axioms" are indicated by class attributes
 on the
 more general category, where the name of the attribute provides the axiom
 label
 and the value is the category obtained from adding the axiom.

 '''Potential Problem:''' Implementing a labelled digraph using
 dictionaries is a
 very natural one, but here we have a bit of a mess: the outgoing edges are
 mixed
 in to a dictionary that has all kinds of other stuff in it too. For
 instance,
 getting a list of which axioms are "implemented" for a category involves
 iterating over the `class.__dict__` and filtering on which attributes are
 axioms
 and which are other methods. How do we tell the difference? By name? How
 about
 name clashes?

 '''Unusual:''' It is rare that callables are bound to an attribute that
 doesn't
 bear their (unqualified) name. It's not unheard of, though.

 The "lazy loading" requirement is implemented by choosing for every
 category a
 preferred (basecategory,axiom) pair through which it can be obtained. The
 class
 attribute corresponding to that edge is implemented by a `LazyImport` link
 rather than putting the actual class there.

 '''Question:''' At this point, it seems unnecessary to do this only for a
 preferred edge. Each `LazyImport` would need to be called once to resolve,
 but
 if the import in question has already happened then the result should just
 be
 that the LazyImport removes itself from the story (provided the LazyImport
 has
 the right references to take itself out of the relevant dictionary).

 It also seems to be useful to have a link from a category to the
 categories from
 which is can be obtained. Oddly enough, the system insists on having a
 single
 main (category,axiom) pair through which it can be obtained, even though
 the
 original graph we're modelling doesn't have any such concept

 '''Question:''' Why do we need `_base_category_and_axiom` at all? It seems
 very
 unnatural: there are many ways in which a category can be obtained by
 adding an
 extra axiom to another category. Indeed, there are
 `extra_super_categories`. Why
 are they separate? Should we just have a set of `(base_category,axiom)`
 pairs?

 '''Question:''' (for lazy loading) given that categories refer to their
 super
 categories, is it indeed the case that loading a category will imply
 loading the
 entire "inbound component" (all vertices that have a path to this one)? It
 is
 not entirely clear to me how they get that info. Is that a combination of
 a name
 mangling search and hard-wiring the connections?

 '''Question:''' Is there always just one axiom to add to go from one
 category to another?
 Wouldn't there be useless nodes in the graph then (partial axiom
 combinations
 that no-one is interested in)?

 In short, I think the current problems are mainly coming from an imposed
 asymmetry: the introduction of a "main" `(base_category,axiom)` pair.
 Additionally, the lazy loading issue only becomes complicated because the
 derived categories insist on knowing what their direct supercategories
 are. If
 we wouldn't need that then just the lazy imports would do the trick.

 If we do need categories to know their supercategories, then there is
 indeed a
 problem of how to get that information. Name mangling doesn't do the
 trick,
 because that only works for a rooted tree. We need to be able to express
 an
 (acyclic)digraph (I don't think we get any mileage out of the acyclic
 bit).

 If you really want a single point of truth, I don't see an alternative to
 Simon's suggestion a bit list of:
 {{{
 ("base category", "axiom", "resulting category")
 }}}
 triples, where the entries are indeed strings, and a nasty
 (meta?)metaclass on
 categories that looks up all the entries with base category occurring, to
 put in
 the appropriate `LazyImport` bindings and a look up of the `resulting
 category`
 entries to put the links back in the super_category attribute.

 Another point that's a little dirty presently is that the axiom callables
 are
 mixed in with all the other class attributes. That could easily cause name
 clashes. I would almost say that instead of
 {{{
 Algebras(GF(5)).FiniteDimensional()
 }}}
 it would be preferable to do
 {{{
 Algebras(GF(5)).with_axiom("FiniteDimensional")
 }}}
 since that would give the freedom to use a dedicated dictionary.

--
Ticket URL: <http://trac.sagemath.org/ticket/10963#comment:366>
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