Skip to content

Commit d57bcbd

Browse files
author
Release Manager
committed
gh-35102: Introduce extension of scalars coercion of CombinatorialFreeModules <!-- ^^^^^ Please provide a concise, informative and self-explanatory title. Don't put issue numbers in there, do this in the PR body below. For example, instead of "Fixes #1234" use "Introduce new method to calculate 1+1" --> ### 📚 Description Fixes #21405 <!-- Describe your changes here in detail --> <!-- Why is this change required? What problem does it solve? --> <!-- If it resolves an open issue, please link to the issue here. For example "Closes #1337" --> ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> <!-- If your change requires a documentation PR, please link it appropriately --> <!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> - [x] I have made sure that the title is self-explanatory and the description concisely explains the PR. - [x] I have linked an issue or discussion. - [ ] I have created tests covering the changes. - [ ] I have updated the documentation accordingly. ### ⌛ Dependencies <!-- List all open pull requests that this PR logically depends on --> <!-- - #xyz: short description why this is a dependency - #abc: ... --> URL: #35102 Reported by: Matthias Köppe Reviewer(s): Kwankyu Lee
2 parents e380758 + 6dc4921 commit d57bcbd

File tree

1 file changed

+77
-7
lines changed

1 file changed

+77
-7
lines changed

src/sage/combinat/free_module.py

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,29 @@ def construction(self):
485485
return VectorFunctor(None, True, None, with_basis='standard',
486486
basis_keys=self.basis().keys()), self.base_ring()
487487

488+
def change_ring(self, R):
489+
r"""
490+
Return the base change of ``self`` to `R`.
491+
492+
EXAMPLES::
493+
494+
sage: F = CombinatorialFreeModule(ZZ, ['a','b','c']); F
495+
Free module generated by {'a', 'b', 'c'} over Integer Ring
496+
sage: F_QQ = F.change_ring(QQ); F_QQ
497+
Free module generated by {'a', 'b', 'c'} over Rational Field
498+
sage: F_QQ.change_ring(ZZ) == F
499+
True
500+
"""
501+
if R is self.base_ring():
502+
return self
503+
construction = self.construction()
504+
if construction is not None:
505+
functor, arg = construction
506+
from sage.categories.pushout import VectorFunctor
507+
if isinstance(functor, VectorFunctor):
508+
return functor(R)
509+
raise NotImplementedError('the method change_ring() has not yet been implemented')
510+
488511
# For backwards compatibility
489512
_repr_term = IndexedGenerators._repr_generator
490513
_latex_term = IndexedGenerators._latex_generator
@@ -647,16 +670,19 @@ def _element_constructor_(self, x):
647670
are systematically defined (and mathematically meaningful) for
648671
algebras.
649672
650-
Conversions between distinct free modules are not allowed any
651-
more::
673+
A coercion between free modules with the same indices exists
674+
whenever a coercion map is defined between their base rings::
652675
653676
sage: F = CombinatorialFreeModule(ZZ, ["a", "b"]); F.rename("F")
654677
sage: G = CombinatorialFreeModule(QQ, ["a", "b"]); G.rename("G")
655-
sage: H = CombinatorialFreeModule(ZZ, ["a", "b", "c"]); H.rename("H")
656678
sage: G(F.monomial("a"))
657-
Traceback (most recent call last):
658-
...
659-
TypeError: do not know how to make x (= B['a']) an element of self (=G)
679+
B['a']
680+
sage: G(-3*F.monomial("a"))
681+
-3*B['a']
682+
683+
Otherwise, there is no conversion between distinct free modules::
684+
685+
sage: H = CombinatorialFreeModule(ZZ, ["a", "b", "c"]); H.rename("H")
660686
sage: H(F.monomial("a"))
661687
Traceback (most recent call last):
662688
...
@@ -678,12 +704,13 @@ def _element_constructor_(self, x):
678704
sage: pp(a)
679705
1/4*p[1, 1] # p[1, 1] + 1/4*p[1, 1] # p[2] + 1/4*p[2] # p[1, 1] + 1/4*p[2] # p[2]
680706
681-
Extensions of the ground ring should probably be reintroduced
707+
General extensions of the ground ring should probably be reintroduced
682708
at some point, but via coercions, and with stronger sanity
683709
checks (ensuring that the codomain is really obtained by
684710
extending the scalar of the domain; checking that they share
685711
the same class is not sufficient).
686712
713+
687714
TESTS:
688715
689716
Conversion from the ground ring is implemented for algebras::
@@ -784,6 +811,49 @@ def _first_ngens(self, n):
784811
it = iter(self._indices)
785812
return tuple(B[next(it)] for i in range(n))
786813

814+
def _coerce_map_from_(self, R):
815+
"""
816+
Return ``True`` if there is a coercion map from ``R`` into ``self``.
817+
818+
There exists a coercion map from:
819+
820+
- a free module whose base ring coerces into the base ring of
821+
``self``, and which has the same indices as ``self``
822+
823+
EXAMPLES::
824+
825+
sage: C = CombinatorialFreeModule(ZZ, Set([1,2]))
826+
sage: CQ = CombinatorialFreeModule(QQ, Set([1,2]))
827+
sage: CQ.has_coerce_map_from(C)
828+
True
829+
sage: c = C.monomial(2)
830+
sage: cq = CQ(c); cq
831+
B[2]
832+
sage: cq.leading_coefficient().parent()
833+
Rational Field
834+
sage: C.has_coerce_map_from(CQ)
835+
False
836+
837+
sage: CF2 = CombinatorialFreeModule(GF(2), Set([1,2]))
838+
sage: CF2.has_coerce_map_from(C)
839+
True
840+
sage: c = C.monomial(1)
841+
sage: CF2(2*c)
842+
0
843+
sage: CF2(3*c)
844+
B[1]
845+
"""
846+
if isinstance(R, CombinatorialFreeModule):
847+
try:
848+
CR = R.base_extend(self.base_ring())
849+
except (NotImplementedError, TypeError):
850+
pass
851+
else:
852+
if CR == self:
853+
return lambda parent, x: self._from_dict(x._monomial_coefficients,
854+
coerce=True, remove_zeros=True)
855+
return super()._coerce_map_from_(R)
856+
787857
def dimension(self):
788858
"""
789859
Return the dimension of the free module (which is given

0 commit comments

Comments
 (0)