Dear David, dear Andrew, Sorry, for having introduced confusion here by going straight to the details without explaining the general structure. What you describe is essentially what we want to achieve, though with a different layout. And I am very glad to see that we agree on the fundamental principles.
This layout is at the core of MuPAD-Combinat, and has been used intensively for eight years. It has proven to be robust and practical there, so I am pretty confident in replicating it into Sage. My poll is more about syntactical details within this layout. Let me try to restate the layout, this time on symmetric functions because this gives more bases to play with. Also they are more familiar objects. Let me postpone the syntax details for the moment, and just use one of the possible options. David: please, let me know if there are some issues raised in your e-mail which are not addressed below. I kepts a record of your +1 / -1 when they applied. General layout: --------------- So we have (or should have, since it is not yet implemented this way in Sage): sage: S = SymmetricFunctions(QQ) The abstract ring of symmetric functions This is a parent, though an abstract one which has no elements by itself. From this you can construct: sage: S.schur() The ring of symmetric functions, with elements expanded in the Schur basis sage: S.powersum() The ring of symmetric functions, with elements expanded in the powersum basis sage: S.elementary() The ring of symmetric functions, with elements expanded in the elementary basis ... Those are again parents. Each of them models a concrete representation of the ring of symmetric functions. In particular they are (among other things) free modules. So we have: sage: S.elementary().basis() A family of elements of S.elementary(), indexed by partitions They are also algebras. So we have: sage: S.elementary().algebra_generators() A family of elements of S.elementary(), indexed by positive integers > Or one can create a class of homomorphisms and set up an isomorphism > between an Hecke algebra in one basis to one in the other. Yes. All the concrete representations are connected by isomorphisms (though one certainly does not want to implement all binomial(b,2) isomorphisms, since the number b of basis is >> 10). Those isomorphisms are handled by the coercion system, which takes care of transitivity. Note: if s is a symmetric function expanded in the powersum basis, then s.parent() is S.powersum(), not S. Among other things, this is necessary to give the appropriate information to the coercion system. > The module basis is also a set of ring generators, hence there is > some ambiguity which of these two roles the basis elements are > playing. Yes, having no ambiguity is essential. Note that, in the layout above, all the roles are clearly distinguished: - abstract algebra - concrete algebra - canonical basis of a concrete algebra - canonical algebra generators of a concrete algebra So, now on to the rationale for the layout. Why is it important to have this abstract ring of symmetric function: sage: S = SymmetricFunctions() rather than just creating each basis independently? Essentially because this gives a name to the abstract ring of symmetric functions. Naming something is taking power over it :-) In particular: (1)One can use introspection to get the list of available basis. Note that the existence of certain basis may depend on the actual ground ring for example. (2)One can use S(something) to coerce something into a symmetric functions, when we just want the result to be a symmetric function, without caring (3)One can use S[x] to define univariate polynomials with mixed coefficients which are all symmetric functions, but possibly expressed in different bases. (4)One can store common information (cache for example) about symmetric functions in S. (5)One can query general information about S without creating concrete representations. (6)S is a natural place to declare most of the isomorphisms between the different basis. In fact, with Florent, we view S essentially as a database of mathematical informations: what are the concrete representations, what are the canonical isomorphisms. And speaking of that, there is also a category behind the scene in which all the concrete representations are; whether S and this category should coincide or not is left for future discussions. (7)The parameters (base ring, Cartan type for Hecke algebras, variables for symmetric polynomials) only need to be specified once at the creation of S (usual Don't Repeat Yourself principle which among other things guarantees that all the bases are created consistently). (8)cross references: each basis just needs to be aware of S; then they can easily refer to each other. Let me use this occasion to thank Teresa Gomez-Diaz for her brilliant idea, in MuPAD-Combinat and in connection with (3), of upgrading S from merely a parametrized library/module (i.e. a computer science object) into a full featured algebra (i.e. a mathematical object). > Mathematically one might consider A and H to be canonically equal > (the object being independent of the definition). This can be > acknowledged by defining A == H to be True, and supporting canonical > coercions from one to the other. Hmmm. Whether we should have S == S.elementary() == S.powersum() == ... is an open question. My feeling is no. But most likely we do not really care for now, and can postpone this decision until some practical experience/application tells us what's right. About short/long notations: --------------------------- The examples above illustrate that the plan is to have long explicit names for everything, including the various representations of an algebra. This was not apparent in my example with the Hecke algebra because, as far as I know, the (long) mathematical name for the T basis is ... T. Yeah, that's bad, but that's how it is, and users will be looking for this name. About shorthands: ----------------- > > (4) Define a shorthand gadget, so that the user can do something like: > > > > sage: H = HeckeAlgebra(...).shorthand > > sage: H.T( 3 + (2 * H.KL[2,1,2] + H.C[w])) > > > > A variant for symmetric functions: > > > > sage: S = SymmetricFunctions(QQ).shorthand > > sage: h = S.h; e = S.e > > sage: e( S.s[3] * S.m[3,1] ) + 3*h[4,1] > > > > Such gadgets have full freedom to do play all the dirty > > tricks they wants, leaving the main code clean and robust. > > > > Votes: > > -1 -- shorthand notation should be long (enough to read). Let me be precise. The purpose here is to support the analogue of what we do everyday when writing mathematics, namely explicitly defining shorthand notations before a calculation in order to have concise and readable formulas: Using the notations of Macdonald, one has: s[3,2] = p( 1 + e[2,2,1] + ...). > Instead, the user can do: > > ss = S.symmetric_sum > pp = S.power_sum > for n in range(16): > for m in range(n): > sum([ (-1)**k*pp(n,k)*ss(n,m-k) for k in range(m+1) ]) == 0 -1 We have had repeated (and strong!) requests from users of symmetric functions for a one liner for getting the usual shortcuts for all the classical bases. For once, the mathematical notations are quite standardized in the community, and we ourselves found this very practical: there are 5/10 of them, so redefining them all each time is a pain. In fact, I'd love to be able to do: from SymmetricFunctions(QQ).shorthands import * Furthermore, providing the user with (optional but easy to load) shorthands promotes their standardization among all users. This makes it much easier for them to share worksheets / little calculations / ... We could even have alternative sets of shorthands: from SymmetricFunctions(QQ).macdonald_shorthands import * or: from SymmetricFunctions(QQ).lascoux_shorthands import * Again in mathematics, one often writes "by abuse of notation, we denote by T both the family (T_i)_{i=1,...,n} of generators and the basis (T_w)_{w\in W}". This is quite essential to get concise notations without too many symbols. And this is perfectly safe when done in a well defined context. Of course, the user wants to do the same when interactively typing in formulas into Sage. Implementing such magical shorthands can be a bit tricky, if not treacherous, and is certainly not a one-liner. So we want to make them available, upon request, to the user. About the syntactical details: ------------------------------ Accessing the generators of an algebra/module. Here are some options, taking for example A = S.elementary(): (1)A.gens(ModulesWithBasis(QQ)) # module generators A.gens(Algebras(QQ)) # algebra generators A.gens() # algebra generators by default? (2)A.basis() # module generators A.algebra_generators() # algebra generators I actually would vote for combining the two. That is implementing (2), and having A.gens(category) call them. Indeed (2) is much more practical to implement: in particular it allows for subclasses to easily override one of them without touching (or not even being aware of) the other. Also, that's where the user will most likely find them when there are standard mathematical names like basis. On the other hand, it is nice to be able to ask generically for the generators of A for a given category. Oh, by the way: I never answered your e-mail about standardizing the return type when querying for generators. ++1 on the principle. > I write i as tuples (1,2,1) or (3,2,3,1) since they are immutable, Yes, you are perfectly right. We should be using tuples systematically. Sorry, I am still under the influence of MuPAD there :-) Cheers, Nicolas -- Nicolas M. Thiéry "Isil" <nthi...@users.sf.net> http://Nicolas.Thiery.name/ --~--~---------~--~----~------------~-------~--~----~ To post to this group, send email to sage-devel@googlegroups.com To unsubscribe from this group, send email to sage-devel-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/sage-devel URLs: http://www.sagemath.org -~----------~----~----~----~------~----~------~--~---