Here's an Action
class:
from sage.categories.action import Action
from sage.groups.matrix_gps.matrix_group import is_MatrixGroup
from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing
class InverseLinearMapSubstitutionAction(Action):
def __init__(self, G, S):
if not is_MatrixGroup(G):
raise TypeError("Not a matrix group: %s" % G)
if not is_MPolynomialRing(S):
raise TypeError("Not a multivariate polynomial ring: %s" % S)
if not G.degree() == S.ngens():
raise ValueError("Degree of matrix group (%d) does not match number of generators of polynomial ring (%d)" % (G.degree(), S.ngens()))
if not S.base_ring().has_coerce_map_from(G.base_ring()):
raise ValueError("Base rings not compatible")
super().__init__(G, S, is_left=True, op=operator.mul)
def _act_(self, g, f):
return f(*(g.inverse() * vector(self.domain(), self.domain().gens())))
def _repr_name_(self):
return "inverse linear map substitution action"
It works:
sage: R.<x,y> = PolynomialRing(QQ)
sage: G = GL(2, QQ)
sage: a = InverseLinearMapSubstitutionAction(G, R); a
Left inverse linear map substitution action by General Linear Group of degree 2 over Rational Field on Multivariate Polynomial Ring in x, y over Rational Field
sage: M = Matrix(QQ, [[0,-1],[1,0]])
sage: f = x + y
sage: a(M, f)
-x + y
The next step to get the notation M*f
working would be to call register_action
on R
. However M*f
is already defined to be a matrix over the polynomial ring, and I don't know how to undo or get around this.