Hi,
i first want to say that i love you all, i am not deeply involved in
sage-graphs nor sage-combinat, nor representing any community. Just my
two cents about this thread and the related tickets.
- I disagree that this thread reached a consensus.
- I disagree that functionalities in Sage can not be added in relation
with external purposes. Actually, the success of Sage over both faster
and more reliable other free mathematical software (don't feed the
troll) is, imho, due to its social ability to easily include people's
contribution. Somehow, its "poor" but inclusive design allow everyone
to share its piece of code there, and i like to promote this.
The main issue is about design, not about the right to exist.
First hint
----------
I like how Sebastien explains how to design classes and i think it could
help here :
http://trac.sagemath.org/sage_trac/ticket/10519#comment:4
Shortly, we write algorithms. They answer questions. Identifying classes
containing them as methods is identifying the entities to which you ask
the question.
Let us have a look at the .to_partition() method introduced in the Graph
class.
http://trac.sagemath.org/sage_trac/attachment/ticket/14734/graph_to_partition.patch
Its name may make sense from the algebraic combinatorialist point of
view, but is definitely more cryptic than
`.connected_component_sizes_partition()`, which corresponds to its
one-line implementation. Here, the semantics about what you precisely
ask to the given graph is removed.
With such a name, one could imagine that `G.to_partition()` groups the
vertices by degrees. Each map g whose domain is the set of vertices of a
graph naturally creates a partition (the partition associated to the
equivalence relation f(u) == f(v)). We can imagine tons of such maps,
e.g. the number of triangles v belongs to, or the maximal number of
disjoint path from v to v, or the cardinal of the connected components
of its first neighborhood, such objects are not so artificial as they
actually appear in graph theory.
All those maps are interesting, but the name `.to_partition()` itself
states that this is not such a question you ask to a graph G, and that
there is a design issue (and changing the name will not solve the
issue). The name of the method `.to_partition()` is quite clear: it ask
"give me a map from the set of graphs to the set of partitions".
Let us have a look to the .to_poset() method,
http://trac.sagemath.org/sage_trac/attachment/ticket/14732/posets_to_graph.patch,
In particular, the comments
http://trac.sagemath.org/sage_trac/ticket/14732#comment:5
http://trac.sagemath.org/sage_trac/ticket/14732#comment:14 state:
<<From a pure Sage point of vue, I think it is actually a nice shortcut:
not everyone thinks of transforming the poset into a Hasse diagram.>>
<<I actually think it it makes it better, because I for example would
never think of doing Graph(P.hasse_diagram()) to transform the Poset
into a Graph.>>
If a user want the Hasse diagram of a poset, she asks the question "what
is your Hasse diagram" to the given poset. Here, the user is assumed not
to think of transforming the poset into a Hasse diagram, the user is
asking (again) the question "Is there a natural map from the class of
posets to the class of graphs?"
This is a legitimate question, some class in Sage should answer it.
To whom should the user ask those questions ? Not to a graph or to a
poset, but to a quiver (in a board sense: an organized set of arrows).
This entity knows which arrows exist between posets and graphs, between
graphs and partitions, and so on.
The current implementation asks this question to a given poset "Hey you,
3-element poset, could you tell me what maps are there from your whole
family and the set of graphs ?".
In this thread, you plan to ask the question <<Which bijections between
Dyck paths and NoncrossingSetPartitions are implemented?>>, should you
ask this question to a length-2 Dyck path ?
The same holds for the `to_partition` method : it is not assumed to
answer the question "what is the sequence of cardinals of connected
components of G", it aims to answer the question "give me an arrow
between graphs and partitions".
A class is not the domain of the method, it is the entity you ask your
question. Hence, you should not store an arrow into its domain, you
should store it into a quiver.
Second hint.
------------
- <<All we do is to decorate maps between certain combinatorial
collections to provide further information about this map.>>.
- <<I don't find a way to tell if a method is a map between
combinatorial collections very strange.>>
- <<As a simple example, one might want to know all the statistics that
are implemented for permutations>>
- <<by just registering the method somewhere else and returning the
function it received without changing it.>>
This nice idea does not correspond to what actually happens. De facto,
the proposed implementation is not a tagging system to add semantics in
existing methods: the current implementation implies creating artificial
methods that are of no use to the class they belong to.
When i say artificial, i mean that the method does not answer a question
that a user may ask to the associated object. If, given graph, i want to
find the partition corresponding to the list of cardinals of its
connected components, i will never look for an existing method achieving
that. The method only exists to host the decorator.
Perhaps adding a decorator to backlink from a method to its
corresponding arrow in the quiver might make sense in some very
particular cases, but having to create an artificial method to be able
to tag it with a decorator in order to construct an arrow is just
overkill.
This is a hint that decorators may not be appropriate to organize, and
especially to feed, your quiver.
Third hint
----------
If you read the code of the combinatorial_map() function, you get the
following example:
sage: p = Permutation([1,3,2,4])
sage: p.left_tableau
Combinatorial map: Robinson-Schensted insertion tableau
But `p.left_tableau` is NOT a map from Posets to Tableaux.
sage.combinat.permutation.Permutation_class.left_tableau is. Both are
different.
Example with a classical method:
sage: G = graphs.PetersenGraph()
sage: Graph.connected_components(G) == G.connected_components()
True
sage: Graph.connected_components == G.connected_components
False
Example with a decroated method:
sage: p = Permutation([1,3,2,4])
sage: q = Permutation([1,3,2,4,5])
sage: q.left_tableau == p.left_tableau
True
sage: q.left_tableau() == p.left_tableau()
False
sage: type(p).left_tableau == p.left_tableau
True
sage: type(p).left_tableau(p)
[[1, 2, 4], [3]]
sage: p.left_tableau(p)
...
TypeError: left_tableau() takes exactly 1 argument (2 given)
Hence, the decorator identifies object.method with type(object).method,
which are two different things (in particular their number of entries
differ by 1). There seems to be a confusion between the class of
permutationss and a given single permutation.
Also, this may confuse Python users, since it contradicts the following
paragraph :
http://docs.python.org/2/tutorial/classes.html#method-objects
You won't add a decorator @taylor_expansion to the .cos() method of a
real number.
Fourth hint.
------------
Your quiver will benefit of having more and more maps. So, it needs to
be scalable.
In the current implementation, it implies writing artificial methods for
each new map, easy to write, easy to review, easy to spread, therefore
flooding Sage code.
On the other hand, maintaining a small and coherent set of methods for a
given class asks for more work. You need to merge methods, deprecate
code, etc.
No doubt that the "be fruitful, and multiply" strategy will win. Not
sure Sage code will benefits from this.
Also, non-essential Sage features tend to be lazy_imported. It may be
hard to lazy_import each artificial method along the whole sage code,
where it will be easy to lazy_import a quiver. In the future, one may
want to build specialized parts of Sage "the_software", what about code
modularity ?
Let me give a provocative example: i am currently interested in integer
sequences, and i want to collect them.
Sage has a fibonacci() function. To add semantics, i could add an
@integer_sequence() decorator on it, and even
@integer_sequence('A000045') to improve the interface with OEIS,
therefore providing more information.
I could do this for prime numbers as well, tagging
sage.rings.arith.nth_prime() with @integer_sequence('A000040')
decorator, then posets with @integer_sequence('A000112').
I could also add @integer_sequence('A001203') for the continued fraction
expansion of pi. CFF and pi are there, so i will just add an artificial
pi_continued_fractions() function to host the decorator.
I will get stuck at some point with existing Sage functions, but the
collection benefits on being as complete as possible, so i will need to
have 'A005408' as well, the odd numbers are so natural, and indeed
important, this may be useful for some Sage users. So i will add a
trivial function odd() into Sage whose decorator will be
@integer_sequence('A005408'). OEIS currently offers me a potential of
226576 sequences. Winning strategy. People will start complaining, but
we are close to a consensus: improving semantics is good, perhaps could
changing the name of the "odd()" function be a solution, volunteers ?
Sage aims at being inclusive. There is a place for implementation of
integer sequences. But not as tagged functions spread along Sage code
for proximity.
So what ?
---------
Changing or removing two artificial methods might be sufficient to stop
a flame. But i think that everyone, and especially people interested in
combinatorial maps, could benefit in a redesign of the implementation of
combinatorial maps (not its removal).
Precise details will depends on the mid-term goal of combinatorial maps
(which questions do you plan to ask), so you may have to ask to some
sage-combinat developpers about this design.
But even a very basic implementation with tuples of the form
(domain, codomain, map, additional_information_dict)
where map could point to an existing method or be a locally defined
lambda function, seem to make more sense than the current
decorator-based implementation.
It will speed up queries, remove the need to create (and doctest) an
articifial method representing the map into the class representing the
domain, therefore making addition of new maps easier, give more symetry
between domain and codomain (then you could ask for all maps with Posets
as codomain, without having to browse the whole Sage code), is scalable
(could easily become a SQL database at some point), does not pollute
namespace, etc.
Ciao,
Thierry
> --
> You received this message because you are subscribed to the Google Groups "sage-devel" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
sage-devel+...@googlegroups.com.
> To post to this group, send email to
sage-...@googlegroups.com.
> Visit this group at
http://groups.google.com/group/sage-devel.
> For more options, visit
https://groups.google.com/groups/opt_out.
>
>