Last time I meet non virtually with Jean-Christophe, he told me that he will need to implement in the near future a new combinatorial algebra. We spent some time with Nicolas to try to design a standard interface for combinatorial Hopf algebra on several basis. I've written this week-end an implementation for the algebraic part (addition and products are dealt with, but co-product are not supported, for the moment). Here is a short description. Please do beta-tests and comments.

I've created a new category Cat::ModuleWithSeveralBases.

This category provide a simple way to declare bases change. Here is a excerpt from the code

///////////////////////////////////////////////////////////////////////// // Basis change control ////// tableBasisChanges := toBeDefined; // The table of the changes of basis. // tableBasisChanges is an hash table of associations of the type // (basSource, basTarget) = basSourceTobasTargetChange // where basSourceTobasTargetChange is of the type // proc(x : basSource::basisIndices) : basTarget // and returns the image of the element basSource(x) expressed in basTarget. // * WARNING: to quickly take care of linearity, x is an *index* whereas // basSourceTobasTargetChange(x) is and *element* of the domain basTarget. // * Only the explicit change of basis must be declared here, // those who are computed by transitivity are being take care of // by the overloading mechanism. // * These functions can be built using the following default implementation // dom::invertBasisChange // invert a change of basis // dom::transposeBasisChange // transpose a change of basis ////// autoDefineBasisChanges := TRUE; // If autoDefineBasisChanges is TRUE, the system defines automatically the // inverse basis changes of each given basis changes and the transpose of // all basis changes for dual bases. /////////////////////////////////////////////////////////////////////////

This later feature is particularly nice for experimental code. For production code, I prefer to set explicitly all needed basis change.

I've also done the necessary job so that there is nothing more to do if
we want to define not only modules but algebras. So for the moment
there is no need for a category Cat::?__AlgebraWithSeveralBases__. Does
anybody see any usage ?

NicolasThiéry: not me, at least not yet

We will most likely encounter situations where it will be easier to define a basis change directly, and not by linearity (i.e. as a function dom1 -> dom2 instead of dom1::basis -> dom2). Think about basis change defined by some elimination process. What about having two tables, say tableBasisChanges and tableBasisChangesBasis?

FlorentHivert: Yes, I was thinking about something like that. Note that in my opinion, the two table should be filled coherently, for example this is needed for tensor product of bases changes.

What about basisChanges instead of tableBasisChanges? why not.

About transposeBasisChange: maybe this utility should be extended to deal with the dual of a linear map between any two domains? Typical application: define a coproduct A -> (A tensor A) by transposing a product mu: (A tensor A) -> A.

FlorentHivert: I think it works as such with the current implementation !!!

I've also tried to deal with duality. This is done in several step:

- each basis module contains now an entries called dom::dual which is the domain of the module of the dual basis.
- a method called dualityScalarProduct is defined if dual is defined, operators::scalar is overloaded according to.

All these entries can be set once for all automatically by providing to ModuleWithSeveralBases the two following entries:

dual := ???; // dual ModuleWithSeveralBases. dualBasesPairs := {[base1,baseDual1]};

Moreover, all these can be set "at run time" with the following three methods:

- addBasis
- addBasisChange
- declareDualBases

(NicolasThiéry: what about declareBasis instead of addBasis? this sounds more uniform with the declare* functions from the operators library). Ok done...

It is a little bit tricky, but this will allow in the future for
automatically defining bases by specifying the scalar product with a
known basis, like macdonald functions defined in Stembridge SF package
with a command dual_basis(newBasis, oldBasis, salarProduct)). Any
comment about this particular point ? I insist that I modify some
entries of some domain from the **outside**, after the domain has been
created... Do you consider it as a good programming technique ?

NicolasThiéry: I try to avoid doing this technique, but there are cases where it's so much practical that it's worth using it, instead of some ugly contorsioning. What do you think of the following rule of thumb?

- In stable library code, avoid such external modifications outside
of the initialization phase (including the execution of the initDomain
methods). As an example, for S:=examples::?
__SymmetricFunctions__(), both S::p::initDomain() and S::initDomain() would be allowed to do external modifications to S::p. - When prototyping at the user level, use it whenever it's practical.

This provides highly configurable modules. I've written a full example which is in

lib/EXAMPLE/SubsetsSpace.mu -> example::SubsetsSpace.

I manage to define a full algebra with 3 bases and a scalar product in a highly commented code ;-) in less than 100 lines !!!

Here Is the full code for further comments:

////////////////////////////////////////////////////////////////////////// // This file demonstrate how to build a free module with several bases. // ////////////////////////////////////////////////////////////////////////// // First we define some shortcut : alias(SubSp = examples::SubsetsSpace); // The name of the space itself. alias(SubSpT = examples::SubsetsSpaceTools); // The name of the tools placeholder. // The domain SubSpt=examples::SubsetsSpaceTools is just a placeholder // for containing the different bases. For technical reasons, these bases // must be created *before* the module SubsetsSpace itself. So they cannot // simply be placed in it. // SubSpt can also be used to store other utilities, such as the combinatorial // class of the indices, if it's not really useful outside of the definition of // this free module (this is not the case here). domain SubSpT info := "Helper tools for the domain 'examples::SubsetsSpace'"; end_domain: // We define now the module expanded on its the different bases. // The fundamental basis. It will be declared as Self Dual. domain SubSpT::Fundamental(TheSet, Ring) category Cat::AlgebraWithBasis(Ring); inherits Dom::FreeModule(Ring, combinat::subClass(combinat::subsets, TheSet)); // Put here the methods particular to this basis. info := "Domain for the subset space on the fundamental basis"; basisName := hold(F); mult2Basis := proc(s1: dom::basisIndices, s2: dom::basisIndices) begin dom::term(s1 intersect s2); end_proc; end_domain: // Another basis. We will furter declare the following basis change : // In_Set = \sum_{X \subset Set} F_X domain SubSpT::In(TheSet, Ring) category Cat::AlgebraWithBasis(Ring); inherits Dom::FreeModule(Ring, combinat::subClass(combinat::subsets, TheSet)); info := "Domain for the subset space on the 'In' basis"; basisName := hold(In); // The product is computed by overloading so there is nothing to do. end_domain: // The dual basis of In. The basis change is // Out_Set = \sum_{Set\subset X} (-1)^(nops(X)-nops(Set)) F_X // It will be computed automatically. domain SubSpT::Out(TheSet, Ring) category Cat::AlgebraWithBasis(Ring); inherits Dom::FreeModule(Ring, combinat::subClass(combinat::subsets, TheSet)); info := "Domain for the subset space on the 'Out' basis"; basisName := hold(Out); // The product is computed by overloading so there is nothing to do. end_domain: // The definition of the module itself. /////////////////////////////////////// // We now place all these bases together, and declare the basis changes. domain SubSp(TheSet : DOM_SET, Ring = Dom::Rational : DOM_DOMAIN) category Cat::ModuleWithSeveralBases(Ring); inherits Dom::BaseDomain; info := "examples::SubsetsSpace -- Example of use of ModuleWithSeveralBases"; // ut here the bases. Fundamental := SubSpT::Fundamental(TheSet, Ring); In := SubSpT::In(TheSet, Ring); Out := SubSpT::Out(TheSet, Ring); // some useful shortcuts for bases. F := dom::Fundamental; // We declare the known basis changes. autoDefineBasisChanges := TRUE; // The undefined basis change are computed by // tansposition or inversion of matrices. For experimental purposes. tableBasisChanges := table( (dom::In, dom::F) = // subsetInABC(Set) = \sum_{X \subset Set} X proc(set : dom::In::basisIndices) : dom::F local xSet; begin dom::F::plus(dom::F::term(xSet) $ xSet in combinat::subsets::list(set)); end_proc); // We deal now with the duality scalar product. dual := dom; // The dual of this space. // The pairs of dual bases. // The pair [dom::Out, dom::In] will be automatically declared. dualBasesPairs := {[dom::F, dom::F], [dom::In, dom::Out]}; end_domain: ///////////////////////// // Thats all folks !!! // /////////////////////////

What remains to do is :

- write the doc (in progress);
- do it for tensor products and co-products;
- update the already hand-crafted domains like ?
__SymmetricFunctions__and ?__LodayRoncoAlgebra__according to; large parts of the code are likely to disappear. Probably, it's a good idea to do the previous item before this one. - beta test and incorporate improvements.

As an improvement, I realize that if the user provide an entry called form example

basesShortcut = {"s", "h", "p"};

it is possible using DOM::s::domainWrapper to allow very simply the creation of element with such command

SymmetricFunction(s[1,3] + p[2]*p[2]).

And thus allow partially for copy paste. Note that this shortcut can be directly extracted out from the entry basisName of all the bases. Do you think this is a good idea ?

NicolasThiéry: YES, even if this won't work very well with non commutative algebras, and with fields which cannot be embeded into Dom::?__ExpressionField__
(say Dom::?__IntegerMod__(3)).

It might be a good idea as well to provide a way for the user to define
automatically the variables s, p, ... at the toplevel as the corresponding domainWrappers. Maybe export(?__SymmetricFunctions__) should do this?

Page Execution took real: 5.069, user: 2.110, sys: 0.280 seconds |