Hi Bruce, On 2018-05-18, Bruce <brucewestb...@gmail.com> wrote: > As I understand it, in sage, the way to implement this is to have a > category.
Provided that what you are implementing does in fact form a mathematical category (https://en.wikipedia.org/wiki/Category_(mathematics)) > However it seems there are two possibilities; > I could put these methods in either ParentMethods or ElementMethods. I can > confused about which of these is preferable. If you are talking about a method shared by all objects of the category: It is ParentMethods. If you are talking about a method shared by elements of objects of the category: It is ElementMethods. > Let me be more specific. In mathematical terms I have things which I call > Tableaux. When you say that *you* call it "Tableaux": Are you talking about a new notion? Otherwise, you may find that what you want to implementing does already exist in Sage. After all, sage: search_def("tableau") gives plenty of things in Sage that have the word "tableau" in them. > 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. Is there a meaningful notion of a "morphism of tableaux" in your setting, so that a morphism between two tableaux can be described as a mapping of its elements? If there is, then it may certainly be reasonable to implement a category of tableaux, with ParentMethods for generic implementations of methods of tableaux and ElementMethods for generic implementations of methods of elements of tableaux. However, I think that this approach should really only be taken for *generic* stuff that isn't time critical. The category framework should not be used for specific implementations that depend on particular data structures. These should rather be implemented in proper base classes. And generic implementations tend to be slow, so if speed matters then it should be implemented using special data structures and perhaps written in Cython. > The other problem I have is that I don't understand the Category, Parent, > Element structure. I have read the sage documentation > and looked at the sage source code. The sage documentation seems more > focused on the needs of algebraic geometry than of combinatorics. No surprise, since the mathematical notion of a category is intensely used in algebra. > 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 > I am even confused about what the arguments are. It seems > that the arguments, or maybe just the order, > are different for new style classes and old style classes. I don't think old style classes are widely used in Sage. We talk here about subclasses of sage.structure.parent.Parent and sage.structure.element.Element, and these are of course new style classes. Best regards, Simon -- 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.