Closed catanzaromj closed 2 years ago
Maybe you're proposing that we don't have to do an explicit conversion of the maps if we handle free modules over the Steenrod algebra differently.
I think the code is trying telling us something here. With everything being a free module (and we don't have a special class for free modules over the Steenrod algebra), we should not need to change anything with the resolution. Likely there is an incompatibility between the classes. Perhaps we just need a change_ring()
in the free module code that calls the new ring's free_graded_module()
method? Any subsequent failures likely means that we need to add methods to the free module and/or subclass it for the Steenrod algebra as per your comment:77. We might also want to consider having different tests for freeness via the has_relations()
method, which now that I think of it should be refactored to an is_free()
method (or perhaps the latter method just added).
Actually, in comment:76, we already basically have 1. with the free_graded_module()
method to the base_ring()
. We might want to actually use that instead in resolution()
.
I have an alternate proposal for some of this: change various _repr_
methods. I don't see why free module morphisms need to be written as "Free module morphism from Free module ...", so I propose changing it to "Module morphism from Free module ...". The information about the types of modules is still there in the domain and codomain.
Also, for modules which are defined as FPModule
but with no relations, why not print those as "Free graded left module on 3 generators" rather than "Finitely presented left module on 3 generators and 0 relations"? Whether they are an instance of FPModule
or FreeGradedModule
, the print representation could be the same.
Both of those are fine with me, but it could make it harder to detect incompatibilities between the objects as we would need to look at the type
rather than the printing output. Although I don't think the particular repr output for the resolution is so important though since it is just updating some doctests.
Branch pushed to git repo; I updated commit sha1. New commits:
299b7b3 | trac 30680: change free module morphism `_repr_` to use "Module morphism" |
Branch pushed to git repo; I updated commit sha1. New commits:
f7cec1d | trac 30680: change `_repr_` for a finitely presented module |
Branch pushed to git repo; I updated commit sha1. New commits:
36404aa | trac 30680: convert maps in resolution of SteenrodFPModule from maps |
Here's a patch that implements the conversion. In order to make the conversion as nice as possible, including keeping track of the names of the generators, I added an argument names
to the main Module
class (in sage/modules/module.pyx
): that class already calls Parent.__init__(...)
and Parent
can take a names
argument, so this seemed like the best way to manage names for module generators. This was already done in the free module case because CombinatorialFreeModule
handles names right, but in the non-free case we are just using Module.__init__(...)
.
Everything in sage/modules
passes tests for me. I'll run full tests, too, but meanwhile I'm marking this as "needs review".
By the way, it would be nice to add some odd primary examples. I will try to work on that, but I'm happy for suggestions/contributions, too.
The first odd primary example I tried didn't work. First I found a few bugs:
diff --git a/src/sage/modules/fp_graded/steenrod/module.py b/src/sage/modules/fp_graded/steenrod/module.py
index 5160ad7351a..21b81b10838 100755
--- a/src/sage/modules/fp_graded/steenrod/module.py
+++ b/src/sage/modules/fp_graded/steenrod/module.py
@@ -941,7 +941,8 @@ class SteenrodFPModule(FPModule):
elements = [a for a in elements if a not in (0, 1)]
- profile = enveloping_profile_elements(elements)
+ profile = enveloping_profile_elements(elements,
+ char=self.base_ring().characteristic())
# Avoid returning the zero profile because it triggers a corner case
# in FPModule.resolution().
diff --git a/src/sage/modules/fp_graded/steenrod/morphism.py b/src/sage/modules/fp_graded/steenrod/morphism.py
index c5be7ba71ff..f35ae0f1117 100755
--- a/src/sage/modules/fp_graded/steenrod/morphism.py
+++ b/src/sage/modules/fp_graded/steenrod/morphism.py
@@ -141,7 +141,8 @@ class SteenrodFPModuleMorphism(FPModuleMorphism):
elements = [a for a in elements if a not in (0, 1)]
- profile = enveloping_profile_elements(elements)
+ profile = enveloping_profile_elements(elements,
+ char=self.base_ring().characteristic())
# Avoid returning the zero profile because it triggers a corner case
# in FPModule.resolution().
Then this happens:
sage: from sage.modules.fp_graded.steenrod.module import SteenrodFPModule
sage: A3 = SteenrodAlgebra(3)
sage: M = SteenrodFPModule(A3, [0], [[A3.P(3)]])
sage: res = M.resolution(3, verbose=True)
Computing f_1 (1/3)
Computing f_2 (2/3)
Resolving the kernel in the range of dimensions [12, 76]: 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76.
Computing f_3 (3/3)
Resolving the kernel in the range of dimensions [44, 116]: 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/free_module.py in quotient(self, sub, check)
4530 try:
-> 4531 sub = self.subspace(sub)
4532 except (TypeError, ArithmeticError):
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/free_module.py in subspace(self, gens, check, already_echelonized)
4089 """
-> 4090 return self.submodule(gens, check=check, already_echelonized=already_echelonized)
4091
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/free_module.py in submodule(self, gens, check, already_echelonized)
3358 if not V.is_submodule(self):
-> 3359 raise ArithmeticError("Argument gens (= %s) does not generate a submodule of self."%gens)
3360 return V
TypeError: not all arguments converted during string formatting
During handling of the above exception, another exception occurred:
ArithmeticError Traceback (most recent call last)
<ipython-input-4-71aff3686c72> in <module>
----> 1 res = M.resolution(Integer(3), verbose=True)
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/steenrod/module.py in resolution(self, k, top_dim, verbose)
1050 # Change rings to the finite algebra, and call the base class
1051 # implementation of this function.
-> 1052 res = FPModule.resolution(
1053 self.change_ring(finite_algebra),
1054 k,
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/module.py in resolution(self, k, top_dim, verbose)
1273
1274 f = ret_complex[i-1]
-> 1275 ret_complex.append(f._resolve_kernel(top_dim=top_dim,
1276 verbose=verbose))
1277
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/morphism.py in _resolve_kernel(self, top_dim, verbose)
1786
1787 else:
-> 1788 Q_n = kernel_n.quotient(j.vector_presentation(n).image())
1789
1790 if not Q_n.rank():
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/free_module.py in quotient(self, sub, check)
4531 sub = self.subspace(sub)
4532 except (TypeError, ArithmeticError):
-> 4533 raise ArithmeticError("sub must be a subspace of self")
4534 A, L = self.__quotient_matrices(sub)
4535 from . import quotient_module
ArithmeticError: sub must be a subspace of self
If I use M = SteenrodFPModule(A3, [0], [[A3.P(1)]])
, everything seems to work, but it fails with SteenrodFPModule(A3, [0], [[A3.P(?)]])
where ?
is replaced with any number 3 or larger. Similar at the prime 5: SteenrodFPModule(A5, [0], [[A5.P(5)]]).resolution(3)
fails.
To reproduce the problem:
sage: from sage.modules.fp_graded.steenrod.module import SteenrodFPModule
sage: A3 = SteenrodAlgebra(3)
sage: F0 = SteenrodFPModule(A3, [44, 52])
sage: F1 = SteenrodFPModule(A3, [12])
sage: g12 = F1.generator(0)
sage: f = Hom(F0, F1)([A3.P(8)*g12, (A3.P(2,2) + A3.P(6,1))*g12])
sage: f
Module morphism:
From: Free graded left module on 2 generators over mod 3 Steenrod algebra, milnor basis
To: Free graded left module on 1 generator over mod 3 Steenrod algebra, milnor basis
Defn: g[44] |--> P(8)*g[12]
g[52] |--> (P(2,2)+P(6,1))*g[12]
sage: f._resolve_kernel()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/free_module.py in quotient(self, sub, check)
4530 try:
-> 4531 sub = self.subspace(sub)
4532 except (TypeError, ArithmeticError):
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/free_module.py in subspace(self, gens, check, already_echelonized)
4089 """
-> 4090 return self.submodule(gens, check=check, already_echelonized=already_echelonized)
4091
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/free_module.py in submodule(self, gens, check, already_echelonized)
3358 if not V.is_submodule(self):
-> 3359 raise ArithmeticError("Argument gens (= %s) does not generate a submodule of self."%gens)
3360 return V
TypeError: not all arguments converted during string formatting
During handling of the above exception, another exception occurred:
ArithmeticError Traceback (most recent call last)
<ipython-input-45-219e86205adc> in <module>
----> 1 f._resolve_kernel()
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/steenrod/morphism.py in _resolve_kernel(self, top_dim, verbose)
360 g[3, 1] |--> Sq(3)*g[0, 0]
361 """
--> 362 return self._action(FPModuleMorphism._resolve_kernel, verbose)
363
364
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/steenrod/morphism.py in _action(self, method, verbose)
427 # Perform the chosen action on the module after having changed rings
428 # to the finite algebra.
--> 429 fp_result = method(
430 self.change_ring(finite_algebra),
431 verbose=verbose)
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/fp_graded/morphism.py in _resolve_kernel(self, top_dim, verbose)
1793 print('im(j): {}'.format(j.vector_presentation(n).image()))
1794
-> 1795 Q_n = kernel_n.quotient(j.vector_presentation(n).image())
1796
1797 if not Q_n.rank():
~/Desktop/Sage/git/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/modules/free_module.py in quotient(self, sub, check)
4531 sub = self.subspace(sub)
4532 except (TypeError, ArithmeticError):
-> 4533 raise ArithmeticError("sub must be a subspace of self")
4534 A, L = self.__quotient_matrices(sub)
4535 from . import quotient_module
ArithmeticError: sub must be a subspace of self
Branch pushed to git repo; I updated commit sha1. New commits:
e817205 | trac 30680: documentation edits |
I have not tracked down the odd primary bug, but I did edit the documentation: minor rewordings, modified some lines that were too long, etc. I also fixed the two small bugs mentioned in comment:89.
A very slightly simpler example that fails:
sage: from sage.modules.fp_graded.steenrod.module import SteenrodFPModule
sage: A3 = SteenrodAlgebra(3)
sage: F0 = SteenrodFPModule(A3, [32, 40])
sage: F1 = SteenrodFPModule(A3, [0])
sage: g0 = F1.generator(0)
sage: f = Hom(F0, F1)([A3.P(8)*g0, (A3.P(6,1))*g0])
For what it's worth, I see the same bug if I use the original code posted to this ticket back in the dawn of time.
I want to get rid of the _convert_map
function as it is not sustainable if we start adding in other algebra specific FP modules. It also doesn't seem very efficient to me either. Anything I should pay attention to or be careful with this?
I will also look into the comment:90 / comment:93 bug too.
Replying to @tscrim:
I want to get rid of the
_convert_map
function as it is not sustainable if we start adding in other algebra specific FP modules. It also doesn't seem very efficient to me either. Anything I should pay attention to or be careful with this?
Not that I can think of.
I will also look into the comment:90 / comment:93 bug too.
I wonder if somewhere we're assuming that all nonzero field coefficients are 1, so something gets screwed up in occasional situations in characteristics other than 2. That's just a guess, though. I'm pretty sure that the problem is in _resolve_kernel
, in any case.
Making the FPModule
return the corresponding free module when it has no relations has been great for finding bugs and incompatibilities between the two objects. Right now I am at figuring this one out:
sage: A = SteenrodAlgebra(2)
sage: F = A.free_graded_module([0])
sage: G = A.free_graded_module([-1])
sage: H = Hom(G, F)
sage: H._basis_elements(0, False)
Module morphism:
From: Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis
To: Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis
Defn: g[-1] |--> 0
The exterior algebra has the same behavior:
sage: E.<x,y,z> = ExteriorAlgebra(QQ)
sage: F = E.free_graded_module([0])
sage: G = E.free_graded_module([-1])
sage: H = Hom(G, F)
sage: H._basis_elements(0, True)
[Module morphism:
From: Free graded left module on 1 generator over The exterior algebra of rank 3 over Rational Field
To: Free graded left module on 1 generator over The exterior algebra of rank 3 over Rational Field
Defn: g[-1] |--> 0]
sage: H._basis_elements(1, False)
Module morphism:
From: Free graded left module on 1 generator over The exterior algebra of rank 3 over Rational Field
To: Free graded left module on 1 generator over The exterior algebra of rank 3 over Rational Field
Defn: g[-1] |--> 0
sage: H._basis_elements(1, True)
/home/travis/sage-build/local/lib/python3.9/site-packages/sage/modules/free_module.py:236: 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.
warn("""You are constructing a free module
The last computation finished quite quickly for A
but the last one didn't finish within 1 minute on my laptop (and E
is an 8 dimensional skew-commutative algebra!). My guess is this is accidentally passing the algebra somehow rather than the underlying scalar ring for the algebra, which is why we get the warning.
I suspect the fix to the first bug is simply checking if the corresponding morphism is the zero morphism or not.
I also removed the _repr_
as I think it is useful to distinguish when someone has passed something that is secretly free but is not such a class. This is was useful for me to tell when was Hom
not being an endomorphism space despite the output suggesting it was. Since basically all things that are free will be a FreeGradedModule
(or a subclass), I think this will obtain the print representation you wanted.
There are also a few other tests failing that I don't yet know why.
I am going to get lunch now and do a little bit of other work. I will return to this later today.
New commits:
d231da7 | Removing _convert_map, docstring and bug fixes, returning free modules when free. |
Reviewer: John Palmieri, Travis Scrimshaw
I traced the problem down to this difference in behaviour:
sage: F = FPModule(A, [0], [[]])
sage: Gp = FPModule(A, [-1], [[0]])
sage: Fp = FPModule(A, [0], [[]])
sage: F = E.free_graded_module([0])
sage: G = E.free_graded_module([-1])
sage: F[G.gen(0).degree() + 0]
Vector space of dimension 0 over Rational Field
sage: Fp[Gp.gen(0).degree() + 0]
()
So I can fix the symptom easily enough by not using __getitem__
in the code (which I think is better anyways for the explicitness). However, we should (quickly) decide which behavior we want and change one of these.
Branch pushed to git repo; I updated commit sha1. New commits:
0045cbc | Fixing issue from different `__getitem__` behavior. |
I agree that we should avoid using __getitem__
in the code. I think if __getitem__(n)
should mean anything, then it should mean the n
th homogeneous piece as a vector space rather than a basis (is that what it's doing?) for that space.
Re your comment "FIXME: Do not rely on this behavior!" in profile.py: why not? It is documented Python behavior.
Replying to @jhpalmieri:
I agree that we should avoid using
__getitem__
in the code. I think if__getitem__(n)
should mean anything, then it should mean then
th homogeneous piece as a vector space rather than a basis (is that what it's doing?) for that space.
I agree as well. I will make the corresponding change.
Re your comment "FIXME: Do not rely on this behavior!" in profile.py: why not? It is documented Python behavior.
Yes, but they could decide to change it in a future version. IMO, we should avoid as much as possible treating unordered objects as having a specified order. I think this is more future-proof in case we end up doing some alteration to the dict
.
Question regarding the general graded modules: Why do we have a more interesting an_element
for the FPModuleHomset
that we override for FreeModuleHomset
(which is just the zero morphism)? (I recognize that previously they were separate classes, but the underlying question still remains why the free one is a more boring element.)
I have fixed a the __getitem__
and a number of other compatibility issues (such as not passing top_dim
along). There are still the following:
FIXME
/TODO
I have marked.With regards to the comment:90 bug, it is deeper than the Steenrod algebra:
sage: from sage.modules.fp_graded.module import FPModule
sage: s = SymmetricFunctions(QQ).s()
sage: F = s.free_graded_module([0,0])
sage: L = FPModule(s, [0,0], [[s[3],s[2,1]], [0,s[2]]])
sage: f = Hom(F, L)([L([s[2], 0]), L([0, s[2]])])
sage: f._resolve_kernel()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~/sage-build/local/lib/python3.9/site-packages/sage/modules/free_module.py in quotient(self, sub, check)
4530 try:
-> 4531 sub = self.subspace(sub)
4532 except (TypeError, ArithmeticError):
~/sage-build/local/lib/python3.9/site-packages/sage/modules/free_module.py in subspace(self, gens, check, already_echelonized)
4089 """
-> 4090 return self.submodule(gens, check=check, already_echelonized=already_echelonized)
4091
~/sage-build/local/lib/python3.9/site-packages/sage/modules/free_module.py in submodule(self, gens, check, already_echelonized)
3358 if not V.is_submodule(self):
-> 3359 raise ArithmeticError("Argument gens (= %s) does not generate a submodule of self."%gens)
3360 return V
TypeError: not all arguments converted during string formatting
During handling of the above exception, another exception occurred:
ArithmeticError Traceback (most recent call last)
<ipython-input-2-f807e560671a> in <module>
4 L = FPModule(s, [Integer(0),Integer(0)], [[s[Integer(3)],s[Integer(2),Integer(1)]], [Integer(0),s[Integer(2)]]])
5 f = Hom(F, L)([L([s[Integer(2)], Integer(0)]), L([Integer(0), s[Integer(2)]])])
----> 6 f._resolve_kernel(top_dim=Integer(10))
~/sage-build/local/lib/python3.9/site-packages/sage/modules/fp_graded/morphism.py in _resolve_kernel(self, top_dim, verbose)
1783
1784 else:
-> 1785 Q_n = kernel_n.quotient(j.vector_presentation(n).image())
1786
1787 if not Q_n.rank():
~/sage-build/local/lib/python3.9/site-packages/sage/modules/free_module.py in quotient(self, sub, check)
4531 sub = self.subspace(sub)
4532 except (TypeError, ArithmeticError):
-> 4533 raise ArithmeticError("sub must be a subspace of self")
4534 A, L = self.__quotient_matrices(sub)
4535 from . import quotient_module
ArithmeticError: sub must be a subspace of self
I am not sure how to make this smaller. Yet at least it is likely more "simple" because it for an infinite commutative graded algebra of characteristic 0 and exists without this new specific code.
New commits:
6cef6ed | Fixing more bugs, increased compatibilty, added SteenrodFreeModule and morphisms. |
eae4f80 | Making `__getitem__` uniform between free and FP modules. |
Regarding "User guide FIXME: Find a better title, possibly (re)move header": I think it is useful to have the previous section "Theoretical background," and so it is useful to have a new section to mark the end of that one. We could call it "Implementation" instead. Other ideas?
Regarding "# FIXME: This seems circular as FPModule builds a morphism": this is in the cokernel_projection
method for morphisms. I would be concerned if the __init__
method for morphisms relied on constructing modules and vice versa, but I don't see a problem with this.
It's easy to change profile.py
:
diff --git a/src/sage/modules/fp_graded/steenrod/profile.py b/src/sage/modules/fp_graded/steenrod/profile.py
index fa2f78f6d10..679ac0c23af 100755
--- a/src/sage/modules/fp_graded/steenrod/profile.py
+++ b/src/sage/modules/fp_graded/steenrod/profile.py
@@ -228,10 +228,6 @@ def find_min_profile(prof, char=2):
for i in range(1, max(P)+1):
if P[i-1] > j and newQ[j] == 2:
newQ[i+j] = 2
- # Convert the dictionary back to a list. As of Python 3.7,
- # converting values of a dictionary to a list or tuple will result
- # in the expected order:
- # https://stackoverflow.com/questions/39980323/are-dictionaries-ordered-in-python-3-6/39980744#39980744
- # FIXME: Do not rely on this behavior!
- return (P, tuple(newQ.values()))
-
+ # Convert the dictionary back to a list.
+ Q = [newQ[i] for i in sorted(newQ)]
+ return (P, tuple(Q))
By the way, I tried using all of this with instances of GradedCommutativeAlgebra
and ran into problems. It would be nice if we could use the classes here with those graded commutative algebras. (I think I fixed them by defining an alias coefficients = basis_coefficients
and defining a rank
method for those algebras.) That could wait for a followup ticket.
Changed branch from u/tscrim/fp_modules_steenrod-30680 to u/jhpalmieri/fp_modules_steenrod-30680
I made the change in profile.py
.
New commits:
e014fd8 | trac 30680: documentation edits, a little cleanup in find_min_profile |
Changed branch from u/jhpalmieri/fp_modules_steenrod-30680 to u/tscrim/fp_modules_steenrod-30680
Here is my proposal for the documentation: To move the (very nice) explanation of the modules to its own thematic tutorial. Since it is more of a walkthrough of the capabilities of the code and longer, I felt this was a more natural place for it. In part because the best title I could come up with for that section was "tutorial."
For the #FIXME
in the cokernel_projection
, I was thinking the morphism that was being created was basically the one defining the cokernel. However this is not the case when the domain is not a free module. So I removed this.
For GCAs, those are not in GradedModulesWithBasis
, so it is not so surprising to me they do not work. That being said, they are implemented essentially with a distinguished basis and are already basically in this category. (I have the same gripe about polynomial rings too.) Thus, it should be easy enough to make them work. Another thing I would like to do is rewrite it without using plural, which would likely make it a bit easier to put it in GradedModulesWithBasis
.
I tweaked the profile()
to avoid going through a dict
, so it should be faster (not that it was necessarily a bottleneck before).
I renamed min_presentation()
to minimal_presentation()
to be more explicit. I don't think we need to deprecate it since this should be merged before the next release. We can setup an (deprecated) alias if we want too.
All that is left is the _resolve_kernel
bug I believe (assuming my changes are good).
New commits:
fd174bb | Rewrite profile() to just use a list. |
d6533fe | Moving the doc to a thematic tutorial. |
cb9713c | Renaming min_presentation to minimal_presentation. |
b055dd8 | Adding minimal_presentation for free modules. |
08a92ba | Some various cleanup of doc, fixing trivial failures, adding additional doctests. |
I made some additional changes to enable working over PIDs (well, at least ZZ
). This was something we claimed to do on the base ticket, but now we have a nontrivial test and can compute resolutions of ZZ
-modules. It was some very simple tweaks (the FGP module code could benefit from a cleanup to major refactoring).
Some thoughts on other possible followup tickets (beyond John's suggestion for GCAs):
I think I understand the _resolve_kernel
bug, and it's actually in vector_presentation
for free modules: when we have a module generator g0
and algebra elements a
and b
in the same degree, then the module basis in that degree might be (a*g0, b*g0)
, but sometimes the method ends up using (b*g0, a*g0)
. So the vectors get screwed up, hence the images of the matrices are wrong. I will try to fix this by being careful about the ordering of the basis in vector_presentation
.
Or rather, when extracting the coefficients from (a+b)*g0
, the terms might arise in the wrong order because it will use the order from the basis for the algebra, not the order from the basis for the module.
I see. Do you happen to have a (small) example of this behavior?
Slightly related, I am wondering if we need to use dense_coefficient_list()
in vector_presentation()
. It seems like we just want to use _monomial_coefficients
directly since it is using a sparse implementation just unrolled into a list of indices (the sparse_coeffs
). There might be other such optimizations that can be done elsewhere. I will wait until you push your fix before doing anything more.
Here is an example:
sage: A31 = SteenrodAlgebra(3, profile=((2,1), ()))
sage: F0 = A31.free_graded_module([36, 44])
sage: F1 = A31.free_graded_module([32, 40])
sage: values = [A31.P(1)*F1.generator(0), A31.P(3)*F1.generator(0) + 2*A31.P(1)*F1.generat
....: or(1)]
sage: j = Hom(F0, F1)(values)
sage: b = [j(x) for x in j.domain().basis_elements(56)][2]
sage: b
(P(2,1)+2P(6))*g[32] + (2P(0,1)+2P(4))*g[40]
sage: a = b.dense_coefficient_list()[0]
sage: a
P(2,1) + 2 P(6)
sage: a.monomials()
[P(6), P(2,1)]
sage: a.coefficients()
[1, 2]
Note the mismatch in order in a.monomials()
compared to a.coefficients()
. Note also that this works as expected, and in particular the monomials are in a different order:
sage: d = (A31.P(2,1) + 2*A31.P(6)) * F1.generator(0) + (2*A31.P(0,1) + 2*A31.P(4)) * F1.g
....: enerator(1)
sage: c = d.dense_coefficient_list()[0]
sage: c.monomials()
[P(2,1), P(6)]
sage: c.coefficients()
[1, 2]
sage: b == d
True
sage: a == c
True
The problem with using _monomial_coefficients
is this: with b
as above,
sage: b._monomial_coefficients
{32: P(2,1) + 2 P(6), 40: 2 P(0,1) + 2 P(4)}
We need to match up P(2,1) * g[32]
, P(6) * g[32]
, etc., with the module basis elements in that dimension, so we have to split up the values anyway. We might be able to use _monomial_coefficients
, but it's not entirely trivial.
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