Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

modules with basis/map coefficients #37766

86 changes: 67 additions & 19 deletions src/sage/categories/modules_with_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from sage.categories.fields import Fields
from sage.categories.modules import Modules
from sage.categories.poor_man_map import PoorManMap
from sage.categories.map import Map
from sage.structure.element import Element, parent


Expand Down Expand Up @@ -173,7 +174,7 @@ def _call_(self, x):
if M.base_ring() != self.base_ring():
M = M.change_ring(self.base_ring())
except (TypeError, AttributeError) as msg:
raise TypeError("%s\nunable to coerce x (=%s) into %s" % (msg,x,self))
raise TypeError("%s\nunable to coerce x (=%s) into %s" % (msg, x, self))
return M

def is_abelian(self):
Expand Down Expand Up @@ -581,7 +582,7 @@ def module_morphism(self, on_basis=None, matrix=None, function=None,
return ModuleMorphismByLinearity(
domain=self, on_basis=on_basis, **keywords)
else:
return ModuleMorphismFromFunction( # Or just SetMorphism?
return ModuleMorphismFromFunction( # Or just SetMorphism?
domain=self, function=function, **keywords)

_module_morphism = module_morphism
Expand Down Expand Up @@ -1264,7 +1265,7 @@ def _apply_module_morphism(self, x, on_basis, codomain=False):
except Exception:
raise ValueError('codomain could not be determined')

if hasattr( codomain, 'linear_combination' ):
if hasattr(codomain, 'linear_combination'):
mc = x.monomial_coefficients(copy=False)
return codomain.linear_combination((on_basis(key), coeff)
for key, coeff in mc.items())
Expand All @@ -1288,8 +1289,8 @@ def _apply_module_endomorphism(self, x, on_basis):
2*s[2, 1] + 2*s[3]
"""
mc = x.monomial_coefficients(copy=False)
return self.linear_combination( (on_basis(key), coeff)
for key, coeff in mc.items())
return self.linear_combination((on_basis(key), coeff)
for key, coeff in mc.items())

def dimension(self):
"""
Expand Down Expand Up @@ -2062,17 +2063,26 @@ def trailing_term(self, *args, **kwds):
"""
return self.parent().term(*self.trailing_item(*args, **kwds))

def map_coefficients(self, f):
def map_coefficients(self, f, new_base_ring=None):
"""
Mapping a function on coefficients.
Return the element obtained by applying ``f`` to the non-zero
coefficients of ``self``.

If ``f`` is a :class:`sage.categories.map.Map`, then the resulting
polynomial will be defined over the codomain of ``f``. Otherwise, the
resulting polynomial will be over the same ring as ``self``. Set
``new_base_ring`` to override this behaviour.

An error is raised if the coefficients cannot be
converted to the new base ring.

INPUT:

- ``f`` -- an endofunction on the coefficient ring of the
free module
- ``f`` -- a callable that will be applied to the
coefficients of ``self``

Return a new element of ``self.parent()`` obtained by applying the
function ``f`` to all of the coefficients of ``self``.
- ``new_base_ring`` -- (optional) if given, the resulting element
will be defined over this ring

EXAMPLES::

Expand All @@ -2096,8 +2106,42 @@ def map_coefficients(self, f):
sage: a = s([2,1]) + 2*s([3,2]) # needs sage.combinat sage.modules
sage: a.map_coefficients(lambda x: x * 2) # needs sage.combinat sage.modules
2*s[2, 1] + 4*s[3, 2]

We can map into a different base ring::

sage: F = CombinatorialFreeModule(QQ, ['a','b','c'])
sage: B = F.basis()
sage: a = 1/2*(B['a'] + 3*B['c']); a
1/2*B['a'] + 3/2*B['c']
sage: b = a.map_coefficients(lambda c: 2*c, ZZ); b
B['a'] + 3*B['c']
sage: b.parent()
Free module generated by {'a', 'b', 'c'} over Integer Ring
sage: b.map_coefficients(lambda c: 1/2*c, ZZ)
Traceback (most recent call last):
...
TypeError: no conversion of this rational to integer

Coefficients are converted to the new base ring after
applying the map::

sage: B['a'].map_coefficients(lambda c: 2*c, GF(2))
0
sage: B['a'].map_coefficients(lambda c: GF(2)(c), QQ)
B['a']

"""
return self.parent().sum_of_terms( (m, f(c)) for m,c in self )
R = self.parent()
if isinstance(f, Map):
B = f.codomain()
else:
B = self.base_ring()
if new_base_ring is not None:
B = new_base_ring
if B is not self.base_ring():
R = R.change_ring(B)
mc = self.monomial_coefficients(copy=False)
return R.sum_of_terms((m, B(f(c))) for m, c in mc.items())

def map_support(self, f):
"""
Expand Down Expand Up @@ -2139,7 +2183,7 @@ def map_support(self, f):
sage: y.parent() is B # needs sage.modules
True
"""
return self.parent().sum_of_terms( (f(m), c) for m,c in self )
return self.parent().sum_of_terms((f(m), c) for m, c in self)

def map_support_skip_none(self, f):
"""
Expand Down Expand Up @@ -2173,7 +2217,9 @@ def map_support_skip_none(self, f):
sage: y.parent() is B # needs sage.modules
True
"""
return self.parent().sum_of_terms( (fm,c) for (fm,c) in ((f(m), c) for m,c in self) if fm is not None)
return self.parent().sum_of_terms((fm, c)
for fm, c in ((f(m), c) for m, c in self)
if fm is not None)

def map_item(self, f):
"""
Expand Down Expand Up @@ -2207,7 +2253,7 @@ def map_item(self, f):
sage: a.map_item(f) # needs sage.combinat sage.modules
2*s[2, 1] + 2*s[3]
"""
return self.parent().sum_of_terms( f(m,c) for m,c in self )
return self.parent().sum_of_terms(f(m, c) for m, c in self)

def tensor(*elements):
"""
Expand Down Expand Up @@ -2543,11 +2589,13 @@ def apply_multilinear_morphism(self, f, codomain=None):
except AttributeError:
codomain = f(*[module.zero() for module in modules]).parent()
if codomain in ModulesWithBasis(K):
return codomain.linear_combination((f(*[module.monomial(t) for (module,t) in zip(modules, m)]), c)
for m,c in self)
return codomain.linear_combination((f(*[module.monomial(t)
for module, t in zip(modules, m)]), c)
for m, c in self)
else:
return sum((c * f(*[module.monomial(t) for (module,t) in zip(modules, m)])
for m,c in self),
return sum((c * f(*[module.monomial(t)
for module, t in zip(modules, m)])
for m, c in self),
codomain.zero())

class DualObjects(DualObjectsCategory):
Expand Down
Loading