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