Closed catanzaromj closed 2 years ago
By the way, if we wanted separate classes for degree zero maps and maps of arbitrary degree, then vector_presentation
would make sense for the zero map in the degree zero case: you would just get the zero matrix of the appropriate size.
A more practical question: if we don't allow maps of nonzero degree in Hom, then how do we construct maps? Currently the easiest way to construct them is Hom(M,N)(...values...)
, but that won't work if we change Hom
. Hom
does take an extra argument, category
, so we could use a different category to allow nonzero degree maps, although I'm not sure what that category should be called.
Replying to @dimpase:
maybe
sage.combinat.free_module
ought to be extended to accommodate for the needs of this ticket?
+1 and we can likely use a lot of the stuff from the category, which means just implementing stuff at the parent level. It might be a bit slower than directly implementing it, but it might not be the bottleneck.
I find it surprising that
sage.combinat.free_module
has no concept of grading.
It is all in the category, which get then you implement for the corresponding parent. Perhaps we could extend CFM that takes an optional grading
parameter, but so far, every use-case of this required us to subclass for other functionality too.
Replying to @tscrim:
Replying to @dimpase:
maybe
sage.combinat.free_module
ought to be extended to accommodate for the needs of this ticket?+1 and we can likely use a lot of the stuff from the category, which means just implementing stuff at the parent level. It might be a bit slower than directly implementing it, but it might not be the bottleneck.
Although CombinatorialFreeModule
is not exactly right for the modules here. At least in the free module case (which is as far as I've gotten), you only care about the degrees of the generators, you don't want to give them names, so there is no named basis. A typical element is listed as <a1, a2, ...>
which means the sum of a_i * generator_i
, and this looks like a pretty efficient way to describe elements. We could create names, but they would be artificial.
Note that sage.modules.free_module
is not suited for this, either: if you try to use it to create a free module over, say, the Steenrod algebra, you get
UserWarning: You are constructing a free module
over a noncommutative ring. Sage does not have a concept
of left/right and both sided modules, so be careful.
It's also not guaranteed that all multiplications are
done from the right side.
I find it surprising that
sage.combinat.free_module
has no concept of grading.It is all in the category, which get then you implement for the corresponding parent. Perhaps we could extend CFM that takes an optional
grading
parameter, but so far, every use-case of this required us to subclass for other functionality too.
Replying to @jhpalmieri:
This may be more a question for Travis. Should the category be
GradedModules
orGradedModulesWithBasis
?
If there is a distinguished basis for the module, then GradedModulesWithBasis
. Otherwise just GradedModules
.
Maybe if we're working over an algebra with a distinguished basis, the module should inherit that basis, at least in the case of a free module.
I would think that depends on the construction. However, having a distinguished basis means you can do linear algebra, which gives you a lot more functionality.
I'm not sure, though, and I really don't know what to do about non-free modules. (I haven't gotten that far in my modifications: I've just been dealing with free modules.)
Since we don't have much if any support for nonfree modules in Sage, you are out there on your own to figure out what the best practice should be.
I'm a little puzzled by the category setup in this context. Does "with basis" refer to a basis over the algebra over which we're working, or over the base field for that algebra? Consider this:
sage: R.<x> = QQ[] sage: R Univariate Polynomial Ring in x over Rational Field sage: M = FreeModule(R, ['a', 'b']) sage: M.category() Category of finite dimensional modules with basis over Univariate Polynomial Ring in x over Rational Field
The "finite dimensional" part of that sounds odd unless you interpret it as meaning "free and finitely generated".
Perhaps it would be a bit better to call it the category of "finite rank free modules", but that is something you are best discussing with Nicholas about.
sage: M.basis() Finite family {'a': B['a'], 'b': B['b']}
So this is viewing the basis as being over the polynomial ring.
Agreed.
On the other hand:
sage: A = GradedModulesWithBasis(QQ).example() sage: A An example of a graded module with basis: the free module on partitions over Rational Field sage: A.homogeneous_component_basis(4) Lazy family (Term map from Partitions to An example of a graded module with basis: the free module on partitions over Rational Field(i))_{i in Partitions of the integer 4} sage: list(A.homogeneous_component_basis(4)) [P[4], P[3, 1], P[2, 2], P[2, 1, 1], P[1, 1, 1, 1]]
So
homogeneous_component_basis(...)
allows access to the vector space basis.It looks like "with basis" means over the ring or algebra connected to the module, not the ground field.
Yes, that is correct, it is the base ring R
, not any underlying ground ring/field that might be used to construct R
.
So maybe it should be in the categories
GradedModulesWithBasis(A)
only in the case of free modulesGradedModulesWithBasis(A.base_ring())
for all modules, assuming we can determine a basis of each homogeneous piece, and this should be possible as long as the algebra has a distinguished basis. Does that make sense?
This sounds like more of a question with the underlying mathematics that I can't answer.
Replying to @jhpalmieri:
Replying to @tscrim:
Replying to @dimpase:
maybe
sage.combinat.free_module
ought to be extended to accommodate for the needs of this ticket?+1 and we can likely use a lot of the stuff from the category, which means just implementing stuff at the parent level. It might be a bit slower than directly implementing it, but it might not be the bottleneck.
Although
CombinatorialFreeModule
is not exactly right for the modules here. At least in the free module case (which is as far as I've gotten), you only care about the degrees of the generators, you don't want to give them names, so there is no named basis. A typical element is listed as<a1, a2, ...>
which means the sum ofa_i * generator_i
, and this looks like a pretty efficient way to describe elements. We could create names, but they would be artificial.
I don't think there is anything wrong with having an artificial name for the basis elements. This is just implicit in Sage's R^n
version of free modules, but we give a name to the basis all the time in math once we want to start working with a basis. However, using CFM is generally slower because its implementation is in Python, always sparse, and has some extra overhead because it allows more generic basis indices. Yet, you do gain the ability to handle infinite dimensional objects.
Note that
sage.modules.free_module
is not suited for this, either: if you try to use it to create a free module over, say, the Steenrod algebra, you getUserWarning: You are constructing a free module over a noncommutative ring. Sage does not have a concept of left/right and both sided modules, so be careful. It's also not guaranteed that all multiplications are done from the right side.
Let S
be the Steenrod algebra over a (commutative) ring R
. Perhaps we should think of the free module as a representation of S
over R
, something you alluded to in your other comments. Internally, this seems to be how it is storing elements, as an infinite dimensional R
-module
Replying to @jhpalmieri:
A more practical question: if we don't allow maps of nonzero degree in Hom, then how do we construct maps? Currently the easiest way to construct them is
Hom(M,N)(...values...)
, but that won't work if we changeHom
.Hom
does take an extra argument,category
, so we could use a different category to allow nonzero degree maps, although I'm not sure what that category should be called.
Strictly speaking, I think a map that shifts degree should not live in the category of graded modules. You are always fine using a larger category, such as the category of modules. However, we could potentially allow a slight abuse here and extend the correspondingHomset
to take nonzero degree maps.
For now I am going to allow maps of nonzero degree, just because it makes it much easier to construct such maps.
I've created #32505 and I will push a branch there soon.
Comments on some changes made from here to #32505:
CombinatorialFreeModule
for the modules, IndexedFreeModuleElement
for the elements. The finitely presented modules are not free over the corresponding algebras, but they are of course free over the base fields, and that's good enough for me.__init__
methods.Dependencies: #32505
Marking as "needs work" because we should deal with #32505 first, then build this on top of that.
Branch pushed to git repo; I updated commit sha1. This was a forced push. Last 10 new commits:
72e455e | We do not require the base algebra's base ring to be a field. |
11b3725 | trac 32505: allow the resolution to be made up of maps between |
fcce24d | Merge branch 'public/modules/free_graded_modules-32505' of git://trac.sagemath.org/sage into public/modules/free_graded_modules-32505 |
2e0518f | Using free modules where possible and improved compatibility. |
6c1ab8d | trac 32505: more fixes |
6cf6d14 | Merge branch 'public/modules/free_graded_modules-32505' of git://trac.sagemath.org/sage into public/modules/free_graded_modules-32505 |
5074464 | Some last fixes and removing redundancy. |
ffe7179 | trac 32505: replace "PlusInfinity()" with "infinity" |
a1a9467 | trac 32505: remove redundant "zero" and "identity" methods |
4ed74b9 | trac 30680: rebased on top of 32505. |
Here is a branch so that we can start working on this, now that #32505 is positively reviewed. I did some clean-up on the old code, and it's almost all working, but not quite. I think that the problem is this: morphisms between finitely presented modules over the Steenrod algebra (the class of modules is currently called FPA_Module
) is not quite behaving the way I want, and in particular, some of the time, domains and codomains of such morphisms are not in the class FPA_Module
anymore. It is important that they be in this class because the code is using special properties of the Steenrod algebra to determine, for example, whether a morphism is injective: given two finitely presented modules, one can find a finite-dimensional subalgebra B such that a morphism as A-modules is injective if and only if it is injective as a B-module map. The case over the finite subalgebra is tractable.
But if we can't remember where the objects live, then we lose these special methods for A-modules, and so we get doctest failures. I'm seeing a few failures in module.py
, I think all due to this.
By the way, I rewrote lots of profile.py
and added a few doctests for odd primes, although we don't have any odd primary examples in the rest of the code. The new version of find_min_profile
is about 10 times faster than the old version. When I get around to it, I will try some odd primary examples of modules and morphisms. Should I expect those to work?
The first two doctest failures:
sage -t --random-seed=52206228944996655655996976540735053542 src/sage/modules/fp_graded/steenrod/module.py
**********************************************************************
File "src/sage/modules/fp_graded/steenrod/module.py", line 484, in sage.modules.fp_graded.steenrod.module
Failed example:
h.is_injective() # Is ker(f) contained in K ?
Exception raised:
Traceback (most recent call last):
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/doctest/forker.py", line 694, in _run
self.compile_and_execute(example, compiler, test.globs)
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/doctest/forker.py", line 1088, in compile_and_execute
exec(compiled, globs)
File "<doctest sage.modules.fp_graded.steenrod.module[94]>", line 1, in <module>
h.is_injective() # Is ker(f) contained in K ?
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/morphism.py", line 1634, in is_injective
j0 = self._resolve_kernel(top_dim, verbose)
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/morphism.py", line 1752, in _resolve_kernel
raise ValueError('a top dimension must be specified for this calculation to terminate')
ValueError: a top dimension must be specified for this calculation to terminate
**********************************************************************
File "src/sage/modules/fp_graded/steenrod/module.py", line 540, in sage.modules.fp_graded.steenrod.module
Failed example:
res = Hko.resolution(6, verbose=True)
Exception raised:
Traceback (most recent call last):
File "sage/misc/cachefunc.pyx", line 1943, in sage.misc.cachefunc.CachedMethodCaller.__call__ (build/cythonized/sage/misc/cachefunc.c:10347)
return cache[k]
KeyError: ((2,), ())
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/vector_space_homspace.py", line 395, in __call__
v = [C(a) for a in A]
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/vector_space_homspace.py", line 395, in <listcomp>
v = [C(a) for a in A]
File "sage/structure/parent.pyx", line 898, in sage.structure.parent.Parent.__call__ (build/cythonized/sage/structure/parent.c:9388)
return mor._call_(x)
File "sage/structure/coerce_maps.pyx", line 161, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4665)
raise
File "sage/structure/coerce_maps.pyx", line 156, in sage.structure.coerce_maps.DefaultConvertMap_unique._call_ (build/cythonized/sage/structure/coerce_maps.c:4557)
return C._element_constructor(x)
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/free_module.py", line 5769, in _element_constructor_
return FreeModule_generic_field._element_constructor_(self, e, *args, **kwds)
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/free_module.py", line 1118, in _element_constructor_
return self.element_class(self, x, coerce, copy)
File "sage/modules/vector_mod2_dense.pyx", line 200, in sage.modules.vector_mod2_dense.Vector_mod2_dense.__init__ (build/cythonized/sage/modules/vector_mod2_dense.cpp:3952)
raise TypeError("x must be a list of the right length")
TypeError: x must be a list of the right length
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/doctest/forker.py", line 694, in _run
self.compile_and_execute(example, compiler, test.globs)
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/doctest/forker.py", line 1088, in compile_and_execute
exec(compiled, globs)
File "<doctest sage.modules.fp_graded.steenrod.module[105]>", line 1, in <module>
res = Hko.resolution(Integer(6), verbose=True)
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/steenrod/module.py", line 1049, in resolution
res = FPModule.resolution(
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/module.py", line 1269, in resolution
ret_complex.append(f._resolve_kernel(top_dim=top_dim,
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/morphism.py", line 1768, in _resolve_kernel
self_n = self.vector_presentation(n)
File "sage/misc/cachefunc.pyx", line 1948, in sage.misc.cachefunc.CachedMethodCaller.__call__ (build/cythonized/sage/misc/cachefunc.c:10483)
w = self._instance_call(*args, **kwds)
File "sage/misc/cachefunc.pyx", line 1824, in sage.misc.cachefunc.CachedMethodCaller._instance_call (build/cythonized/sage/misc/cachefunc.c:9949)
return self.f(self._instance, *args, **kwds)
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/morphism.py", line 913, in vector_presentation
return Hom(D_n, C_n)([C_n.zero() if e.is_zero() else e.vector_presentation()
File "/Users/palmieri/Desktop/Sage/sage_builds/TESTING/sage-9.5/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/vector_space_homspace.py", line 399, in __call__
raise ArithmeticError(msg)
ArithmeticError: some proposed image is not in the codomain, because
x must be a list of the right length
(There are others which fail because res
is not defined after line 540 fails.)
The first failure is definitely because of the issue I mentioned above: the code should auto-detect an appropriate finite-dimensional algebra to work over, in which case we should not have to specify a top dimension, but clearly something is going wrong. I think that one of the morphisms is in the class FPMorphism
rather than the Steenrod-specific FPA_Morphism
. An example:
sage: from sage.modules.fp_graded.steenrod.module import FPA_Module
sage: A = SteenrodAlgebra()
sage: Hko = FPA_Module(A, [0], [[Sq(2)], [Sq(1)]])
sage: gen = Hko.generator(0)
sage: homspace = Hom(Hko, Hko)
sage: values = [Sq(0, 0, 1)*gen]
sage: f = homspace(values)
sage: # Good so far:
sage: type(f)
<class 'sage.modules.fp_graded.steenrod.homspace.FPA_ModuleHomspace_with_category_with_equality_by_id.element_class'>
sage: k = f.kernel_inclusion()
sage: type(k)
<class 'sage.modules.fp_graded.steenrod.homspace.FPA_ModuleHomspace_with_category_with_equality_by_id.element_class'>
sage: coker = k.cokernel_projection()
sage: type(coker)
<class 'sage.modules.fp_graded.steenrod.homspace.FPA_ModuleHomspace_with_category_with_equality_by_id.element_class'>
sage: # But this is a problem:
sage: type(coker.codomain())
<class 'sage.modules.fp_graded.module.FPModule_with_category'>
It should be FPA_Module_with_category
. I don't know why this codomain is not in the right class.
I can fix the first problem by defining a method cokernel_projection
for FPA_Morphism
, just reproducing the code for FPMorphism
. I don't know if there is a better solution. I'm now working on the other doctest failure.
Branch pushed to git repo; I updated commit sha1. New commits:
a9741cb | trac 30680: bug fixes |
Okay, I found a bug and fixed it, and that took care of most of the problems. Something like the first issue I mentioned is still occurring: I don't know how to naturally force a morphism to be in the right class. The remaining failure comes from this doctest:
sage: def is_exact(res):
....: for i in range(len(res)-1):
....: h = res[i].homology(res[i+1])
....: if not h.codomain().is_trivial():
....: return False
....: return True
sage: is_exact(res)
True
The problem is that the maps in res
are maps of FreeGradedModules
, so they are not in the Steenrod-specific world, so the homology
computation doesn't work.
In case you're interested, the bug is a subtle one in the code from #32505: to compute the coefficients of an element in a free module, we were using
return self.dense_coefficient_list()
but the default ordering for the coefficients is in increasing order of degree, not the specified order for the generators. We were hitting a situation in which this mattered, and changing to this fixed it:
order = self.parent()._indices
return self.dense_coefficient_list(order)
I will add some doctests that capture this.
Branch pushed to git repo; I updated commit sha1. This was a forced push. New commits:
67e78ed | trac 30680: bug fixes |
Branch pushed to git repo; I updated commit sha1. This was a forced push. New commits:
fb130d2 | trac 30680: bug fixes |
We should now be at 100% coverage and one doctest failure. I'm sure there are typos and plenty of room for other improvements, but just about everything is now working. I still haven't tried odd primes.
One quick thought is to add an attribute or someway to let the morphism code know what type of modules to create. It might work by using type(self.codomain())
or similar (with perhaps some care to make sure it is not the category-mangled object). This would avoid a lot of code and documentation duplication with making it more future-proof.
I am quite surprised by this bug and slightly worried because it should not matter about the order (as long as internally each class knows how to go back and forth between consistently).
Branch pushed to git repo; I updated commit sha1. This was a forced push. New commits:
bf9fcdb | trac 30680: bug fixes |
I wonder if there is some simple modification to the code for resolution
for Steenrod algebra modules:
def resolution(self, k, top_dim=None, verbose=False):
"""
(documentation omitted)
"""
algebra = self.base_ring()
finite_algebra = SteenrodAlgebra_generic(algebra.prime(), profile=self.profile())
# Change rings to the finite algebra, and call the base class
# implementation of this function.
res = FPModule.resolution(
self.change_ring(finite_algebra),
k,
top_dim=top_dim,
verbose=verbose)
# Change rings back to the original Steenrod algebra.
return [j.change_ring(self.base_ring()) for j in res]
Something at the end that does more than just change the ring, but also forces the morphism to have the right class. This code explicitly calls FPModule.resolution
, and that's probably the root of the problem. We could completely duplicate the general resolution code to the Steenrod algebra setting, but there must be a better way.
By the way, although A
is a standard thing for homotopy theorists to call the Steenrod algebra, FPA_Module
is not the most evocative name, I think. SteenrodModule
? SteenrodFPModule
? What should we call the class? (Have to get a jump on the bike-shedding.)
Replying to @jhpalmieri:
I wonder if there is some simple modification to the code for
resolution
for Steenrod algebra modules:Something at the end that does more than just change the ring, but also forces the morphism to have the right class. This code explicitly calls
FPModule.resolution
, and that's probably the root of the problem.
We could, for example, change each map by reconstructing each domain and codomain, using FPA_Module to instantiate them, and then reconstructing each morphism. It should be easy to write a method or a private function that does this.
Replying to @tscrim:
I am quite surprised by this bug and slightly worried because it should not matter about the order (as long as internally each class knows how to go back and forth between consistently).
Indeed, my "fix" has broken something. This works:
sage: from sage.modules.fp_graded.free_module import FreeGradedModule
sage: F.<x,y> = FreeGradedModule(A, (2, 0))
sage: x.degree()
2
sage: y.degree()
0
This doesn't:
sage: from sage.modules.fp_graded.module import FPModule
sage: A = SteenrodAlgebra()
sage: M.<x,y> = FPModule(A, (2, 0))
sage: x.degree()
0
sage: y.degree()
2
To compute the degree of an element of an FPModule
, it first computes a lift to a free module and then computes the degree there, but when computing that lift, it mixes up the order of the generators.
sage: x.lift_to_free()
y
This is somehow due to imposing the order in coefficients
.
This fixes some of these problems, although I think I still need to specify the order in dense_coefficient_list
:
diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py
index 87f52b759a..51d48f405e 100755
--- a/src/sage/modules/fp_graded/element.py
+++ b/src/sage/modules/fp_graded/element.py
@@ -122,7 +122,7 @@ class FPElement(IndexedFreeModuleElement):
sage: y.coefficients()
[0, Sq(2)]
"""
- return [self[i] for i in sorted(self.parent().indices())]
+ return [self[i] for i in self.parent().indices()]
def _lmul_(self, a):
Let's work on the bugs in finitely presented modules in #33275 (I hope quickly) and then deal with the issues specific to the Steenrod algebra here.
Changed dependencies from #32505 to #32505, #33275
Branch pushed to git repo; I updated commit sha1. This was a forced push. New commits:
ba19b0b | trac 30680: rebased on top of #33275 |
Branch pushed to git repo; I updated commit sha1. New commits:
47b3ce8 | trac 30680: use dense_coefficient_list |
I don't know for your other questions off the top of my head (I am out the door to go back home now), but I am a big +1 for renaming to something like SteenrodFPModule
. I will think about the other questions and reply tomorrow.
Branch pushed to git repo; I updated commit sha1. New commits:
a2dc039 | trac 30680: use "SteenrodFPModule" etc for class names |
Thank you.
Okay, so I have two ways out of this issue of not having the correct class specified when building, e.g., the resolution:
_graded_module_class()
(that takes a parameter free
) that returns the corresponding class.type(self.codomain())
and attach, via an attribute, the free module class to each FP module.I am maybe slightly preferential towards 2 since it is local to the module implementation (which is what needs this information) rather than more global to the algebras. We might have some consistency issues to address (such as the free modules not taking a morphism as defining information), but these will likely improve the overall quality and robustness of the code.
To make sure we're on the same page, there are (I think) two problems with resolution
: (a) if M
is an instance of SteenrodFPModule
, then M.resolution(...)
forgets that and returns morphisms that come from FPModule
(or FreeGradedModule
) rather than SteenrodFPModule
. Then (b) if I fix that by converting all of the morphism back to SteenrodFPModuleMorphism
, the resulting objects are not recognized as free, so for example they will be described in the string representation as being "finitely presented."
I think that since we used FreeGradedModule
more than was originally planned by the authors in #32505, we may now need SteenrodFreeModule
and similar classes for morphisms and homspaces.
Here is what I'm currently using to convert the maps:
diff --git a/src/sage/modules/fp_graded/steenrod/module.py b/src/sage/modules/fp_graded/steenrod/module.py
index c74ed1535ca..9a19a87f65f 100755
--- a/src/sage/modules/fp_graded/steenrod/module.py
+++ b/src/sage/modules/fp_graded/steenrod/module.py
@@ -827,6 +827,7 @@ AUTHORS:
# https://www.gnu.org/licenses/
# ****************************************************************************
+from sage.categories.homset import Hom
from sage.rings.infinity import infinity
from sage.algebras.steenrod.steenrod_algebra import SteenrodAlgebra_generic
from sage.modules.fp_graded.module import FPModule
@@ -1056,7 +1057,7 @@ class SteenrodFPModule(FPModule):
verbose=verbose)
# Change rings back to the original Steenrod algebra.
- return [j.change_ring(self.base_ring()) for j in res]
+ return [convert_map(j.change_ring(self.base_ring())) for j in res]
def export_module_definition(self, powers_of_two_only=True):
@@ -1181,3 +1182,21 @@ class SteenrodFPModule(FPModule):
len(values),
" ".join(["%d" % x for x in values])))
element_index += 1
+
+
+def convert_map(f):
+ if f.domain().has_relations():
+ D = SteenrodFPModule(f.domain()._j)
+ else:
+ try:
+ D = SteenrodFPModule(f.domain()._free_module())
+ except AttributeError:
+ D = SteenrodFPModule(f.domain().base_ring(), f.domain()._generator_degrees)
+ if f.codomain().has_relations():
+ C = SteenrodFPModule(f.codomain()._j)
+ else:
+ try:
+ C = SteenrodFPModule(f.codomain()._free_module())
+ except AttributeError:
+ C = SteenrodFPModule(f.codomain().base_ring(), f.codomain()._generator_degrees)
+ return Hom(D, C)(f.values())
This package implements finitely presented modules over the mod p Steenrod algebra. We define classes for such finitely presented modules, their elements, and morphisms between them. Methods are provided for doing some homological algebra, e.g., computing kernels and images of morphisms, and finding free resolutions of modules.
Depends on #32505 Depends on #33275 Depends on #33323
CC: @sverre320 @sagetrac-kvanwoerden @jhpalmieri @tscrim @rrbruner @cnassau
Component: algebra
Keywords: Steenrod algebra, modules, homological algebra
Author: Bob Bruner, Michael Catanzaro, Sverre Lunøe-Nielsen, Koen van Woerden
Branch/Commit:
7035ae5
Reviewer: John Palmieri, Travis Scrimshaw
Issue created by migration from https://trac.sagemath.org/ticket/30680