> > > Then I can think of the set of Tableaux as the parent and lists of > objects > > as elements. > > You say that you "think of the *set* of Tableaux" as the parent? That > doesn't > sound promising at all. Although I don't know which notion you are using, > it seems likely to me that rather the *set* of all tableaux forms a > category, > which means that each individual tableau is an object in that category. > And "parent" is just another word for "object of a sub-cateogory of the > category of sets". So, if there is a category of tableaux and if each > tableau has elements, then a tableau is a parent and its elements are, > well, its elements. > > This is the wrong viewpoint. The set of Tableaux should be the parent in the category of (enumerated?) sets since the elements are a Tableau. Most combinatorial objects should not be categories because the morphisms that people are typically interested in are bijections. A good smallish example to look at is the implementation of Gelfand-Tsetlin patterns (see src/sage/combinat/gelfand_tsetlin_patterns.py).
Do *NOT* use Posets as an example. Those are special because of the extra structure with the < and are naturally sets (hence parents). Posets are naturally a category because the morphisms have to preserve the structure. > I have struggled to find complete examples in the > > combinat source code. As I understand it the key > > components are Parent.__init__ Element.__init__ _element_constructor_ > but > > I don't understand what these do or how they > > work together. > > In a nutshell: > > - If you implement a parent FOO, then FOO will be a subclass of > sage.structure.parent.Parent, and at some point during FOO.__init__ the > .__init__ methods of the base classes of FOO should of course be called. > Hence, at some point, Parent.__init__(self, ...) will be called (maybe > indirectly), and this is where the category of your new instance of FOO > has to be declared. > - Similarly, if you are implementing the elements of FOO instance in a > class BAR, then of course BAR will be a subclass of > sage.structure.element.Element, and at some point during BAR.__init__ > also Element.__init__(self, P) has to be called (maybe indirectly), > where P is the instance of FOO which `self` will be element of. > Nothing more specific needs to be done in BAR.__init__ regarding the > category framework. > - You did not mention another key component: Your class FOO has to have > BAR assigned to a class attribute called "Element". > - FOO._element_constructor_ is a method that takes some arguments and > returns an element of FOO. If P is an instance of FOO, then it ought > to return an instance of P.element_class. Here, P.element_class is > automatically created by Sage's category framework: It is a sub-class > of both P.Element (i.e., BAR) and of P.category().parent_class (which > is why FOO.__init__ needs to declare which category is to be used). > It is in fact not always needed to implement FOO._element_constructor_ > explicitly: There is a default implementation, and having > `FOO.Element=BAR` > may be sufficient to make it work. But if there is particular input that > BAR.__init__ won't handle then FOO._element_constructor_ is where you > would implement a conversion. > In that sense, _element_constructor_ is less of a key component than > the `Element` attribute. > - Also, if your element class BAR implements arithmetic operations > then you should be aware that some of Python's magic arithmetic > methods such as __add__ or __mul__ have default implementations in > Sage's base classe (sage.rings.ring.Ring etc), and these should *not* > be overridden! Instead, you may implement the corresponding single > underscore method (_add_, _mul_, _lmul_). The same holds for __repr__ > versus _repr_. Moreover, _add_ and _mul_ shouldn't just return instances > of BAR, but of P.element_class (if P is the parent of the result of the > arithmetic operation). > - Another key component: If there are canonical morphisms from other > algebraic structures to your tableaux, then you may want to use them > for automatic conversions (also known as "coercion map"). If a canonical > morphism from `S` to `P` exists, then `P._coerce_map_from_(S)` should > return True (it is also possible that it return the morphism to be used > for automatic conversion). But be aware that this is only possible if > the system of canonical morphisms is consistent: The identity map from > P to P is a coercion map; there is at most one coercion map from S to > P; and the composition of two coercion maps is a coercion map. > > You can find a more detailed account on the category and coercion > framework including parents and elements in > > http://doc.sagemath.org/html/en/thematic_tutorials/coercion_and_categories.html > > > For most combinatorial objects, the main things you want to implement are: - An __init__ for the parent that calls Parent.__init__(self, category=cat), with cat either Sets(), EnumeratedSets(), EnumeratedSets().Finite(), EnumeratedSets().Infinite(), etc. - An __init__ for the element that takes the parent as the first argument that calls Element.__init__(self, parent) or whatever the reasonable base class is. - Set the parent "Element" class level *attribute* to the corresponding element class. - All elements with data D of a parent P you construct should be though either P(D) or the more direct P.element_class(P, D). - An __iter__ for the parent if you know how to iterate over objects. The default _element_constructor_ is sufficient to handle the rest unless you need some extra preprocessing that cannot be done in the element class's __init__. However, see Simon's very good response for more specific details. Best, Travis -- You received this message because you are subscribed to the Google Groups "sage-combinat-devel" group. To unsubscribe from this group and stop receiving emails from it, send an email to sage-combinat-devel+unsubscr...@googlegroups.com. To post to this group, send email to sage-combinat-devel@googlegroups.com. Visit this group at https://groups.google.com/group/sage-combinat-devel. For more options, visit https://groups.google.com/d/optout.