Hi algebraists!
At
http://groups.google.com/group/sage-devel/browse_thread/thread/bd42380368e9d4f7,
I asked about the implementation of (matrix) actions. My impression is
that currently it has high potential for improvement.
There are severall ways to look at a (group) action of a group G on a
(parent) structure S:
1) It is a map from GxS to S' (see below), subject to some axioms
2) It is a group homomorphism G -> Aut(S).
3) It is a functor from G (considered as a category) to the category
of automorphisms of the category of S: Any element g of G gives rise
to a morphism S->S' (see below).
Of course, the three definitions are not the same, as in 1) and 3) we
have an additional structure S' -- very often, we would have S==S',
but in Sage we would also like an action of G=QQ on S=ZZ[x] taking
values in S'=QQ[x].
So, the fundament of group actions in Sage should be either 1) or 3)
-- currently it is both, but only *half*:
See sage.categories.action:
The class Action is derived from Functor -- so, that looks like
definition 3).
But then, the documentation of sage.categories.action states "A group
action G x S
rightarrow S is a functor from G to Sets", and an Action is
initialised by Functor.__init__(Groupoid(G),S.category()). That does
not match definition 3), it should be
Functor.__init__(Groupoid(G),S.category().hom_category()), and "... a
functor from G to the category of set morphisms" or so.
Moreover, the class Action overrides the call method of functors. So,
when one calls an Action A, then it is *not* with a single element g
of G, returning a morphism S->S'. Instead, it is called with an
element g of G and an element s of S, returning an element of S'.
Hence, the class definition takes part of definition 3), but then
overrides the essential parts and follows definition 1).
I'd like to ask here: How do you think it should be improved (assuming
you agree that it *should* be improved)?
Approach 3) is certainly nice. But I see a huge disadvantage in the
implementation: If you have an action A of G on S and want to compute
the result of g acting on s, then first you would call A(g), which
creates a morphism f:S->S', and then you would call f(s). But creating
f would potentially be very time consuming.
If one *only* follows approach 1) then one should not pretend to
follow approach 3): Hence, Action should *not* derive from Functor.
But I wonder if it is possible to have both, as follows:
* Action derives from Functor, but of course initialised using the
correct categories.
* The call method is inherited from Functor.
* In particular, A(g) returns a morphism S->S'
* There is a new method A.act_on_element(g,s) that returns an element
of S', of course satisfying A(g)(s) == A.act_on_element(g,s).
* The coercion framework is modified so that an action returned by
G._get_action_(S) is applied using act_on_element.
Now, the user has two possibilities.
Either
one overrides A._apply_functor, so that A(g) works (thanks to the
default call method of functors), and preserves the default
implementation of A.act_on_element (so that A.act_on_element(g,s)
works as well).
Or
one overrides A.act_on_element, so that A.act_on_element(g,s) works,
and preserves the default implementation of A._apply_functor (so that
A(g) works as well).
Hence, we could leave the choice to the user whether to follow
approach 3) or 1).
What do you think?
Best regards,
Simon