Bug fixes for finitely presented graded modules (#32505)
Closed this issue · 24 comments
Some bug fixes for the ticket #32505.
Depends on #32505
CC: @sverre320 @sagetrac-kvanwoerden @tscrim @rrbruner @cnassau @louisng114
Component: algebra
Author: John Palmieri
Branch/Commit: 29dbd23
Reviewer: Travis Scrimshaw
Issue created by migration from https://trac.sagemath.org/ticket/33275
Branch: u/jhpalmieri/fp-module-bugs
Commit: e3d4234
Another item that I think needs to be fixed: in the resolution method:
sage: E.<x,y> = ExteriorAlgebra(QQ)
sage: triv = FPModule(E, [0], [[x], [y]]) # trivial module
sage: triv.resolution(3)
[Free module morphism:
From: Free graded left module on 1 generator over The exterior algebra of rank 2 over Rational Field
To: Finitely presented left module on 1 generator and 2 relations over The exterior algebra of rank 2 over Rational Field
Defn: g[0] |--> g[0],
Free module morphism:
From: Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field
To: Free graded left module on 1 generator over The exterior algebra of rank 2 over Rational Field
Defn: g[1, 0] |--> x*g[0]
g[1, 1] |--> y*g[0],
The first map here is not a "Free module morphism" because its codomain is not free.
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 |
e3d4234 | trac 33275: bug fixes for finitely presented graded modules. |
Dependencies: #32505
Another view of the problem above:
sage: from sage.modules.fp_graded.module import FPModule
sage: from sage.modules.fp_graded.free_module import FreeGradedModule
sage: E.<x,y> = ExteriorAlgebra(QQ)
sage: triv = FPModule(E, [0], [[x], [y]])
sage: M = FreeGradedModule(E, [0, 1])
sage: type(Hom(M, triv))
<class 'sage.modules.fp_graded.free_homspace.FreeGradedModuleHomspace_with_category_with_equality_by_id'>
sage: type(Hom(triv, M))
<class 'sage.modules.fp_graded.homspace.FPModuleHomspace_with_category_with_equality_by_id'>
It seems to be determining the type of homset from the domain, not paying attention to the codomain.
Replying to @jhpalmieri:
Another view of the problem above:
[snip]
It seems to be determining the type of homset from the domain, not paying attention to the codomain.
I thought about this, and I made a deliberate choice here (one which the code was actually already doing, it just didn't show up explicitly in the doctests). Having it be a free module homomorphism I think is the correct thing to do because we can take advantage of the fact the domain is a free module. I don't think I changed the doc for FreeGradedModuleMorphism, which only says that the codomain must be a graded module. So the output mentioned in comment:2 is correct IMO. For the code as it is now, there is no need to make a distinction based on the codomain AFAICS.
Okay. It looks a little strange, but it does mean that all of the maps in M.resolution() are composable, which is nice (and could be awkward to handle if the 0th map is of a different type than the rest). If something related to this is contributing to issues in #30680, we can revisit it.
I'll mark this as "needs review" now.
Why are you testing degree() in FPModuleElement.coefficients()? Was this meant to be in degree()?
- ``check`` -- boolean (default: ``True``); if ``True``, check
- that the morphism is well-defined.
+ that the morphism is well-definedThis is more of an optimization, but it might be better to use self.codomain().linear_combination() in __call__ instead of
value = sum((c * v for c, v in zip(x.coefficients(), self._values)),
self.codomain().zero())
If the FPModule class does not implement it, we should add it for compatibility.
I am also thinking if we should store _values for a FreeMorphism as a dict, then we could use x.monomial_coefficients(copy=False) to only get the non-zero entries. This would also make it order independent. Although then we get into issues of sparse-vs-dense implementations.
Note that coefficients() for the free module now has a different behavior than for CFM and from the category as it contains 0 entries. (Something I missed previously.) I think this should be changed and within the code we should use dense_coefficient_list() (with possibly passing the fixed order where necessary). In particular, I consider this to be a bug.
Branch pushed to git repo; I updated commit sha1. New commits:
e873dc8 | trac 33275: change "coefficients" to "dense_coefficients" |
Replying to @tscrim:
Why are you testing
degree()inFPModuleElement.coefficients()? Was this meant to be indegree()?
It was a test of the change in the coefficients method (removing the sorting), but it might make more sense in degree.
- ``check`` -- boolean (default: ``True``); if ``True``, check - that the morphism is well-defined. + that the morphism is well-defined
Done, and also got rid of an extra blank line there, too.
This is more of an optimization, but it might be better to use
self.codomain().linear_combination()in__call__instead ofvalue = sum((c * v for c, v in zip(x.coefficients(), self._values)), self.codomain().zero())If the
FPModuleclass does not implement it, we should add it for compatibility.
It's already implemented, so I used it.
I am also thinking if we should store
_valuesfor aFreeMorphismas adict, then we could usex.monomial_coefficients(copy=False)to only get the non-zero entries. This would also make it order independent. Although then we get into issues of sparse-vs-dense implementations.
I haven't done this. Things are working without it, but we could make this change. We could do the same for coefficients for elements.
Note that
coefficients()for the free module now has a different behavior than forCFMand from the category as it contains0entries. (Something I missed previously.) I think this should be changed and within the code we should usedense_coefficient_list()(with possibly passing the fixed order where necessary). In particular, I consider this to be a bug.
I changed the name to dense_coefficient_list.
Branch pushed to git repo; I updated commit sha1. This was a forced push. New commits:
f9ff665 | trac 33275: change "coefficients" to "dense_coefficient_list" |
Branch pushed to git repo; I updated commit sha1. New commits:
f550b61 | trac 33275: use linear_combination in a few more places |
Thank you for the changes.
Replying to @jhpalmieri:
Replying to @tscrim:
I am also thinking if we should store
_valuesfor aFreeMorphismas adict, then we could usex.monomial_coefficients(copy=False)to only get the non-zero entries. This would also make it order independent. Although then we get into issues of sparse-vs-dense implementations.I haven't done this. Things are working without it, but we could make this change. We could do the same for coefficients for elements.
Right now all of the examples are effectively acting like dense modules or are small rank. This would be a more invasive change, so I would postpone it for later unless you have a strong desire for it.
Hopefully the patchbot will come around, but otherwise I am happy with this ticket modulo I would use super() instead of directly calling the category in dense_coefficient_list().
Replying to @tscrim:
Hopefully the patchbot will come around, but otherwise I am happy with this ticket modulo I would use
super()instead of directly calling the category indense_coefficient_list().
I'm probably doing something stupid, but I can't figure out how to do that:
sage: from sage.modules.fp_graded.free_module import FreeGradedModule
sage: A = SteenrodAlgebra()
sage: M = FreeGradedModule(A, (0, 2))
sage: a = M.an_element()
sage: super(FiniteDimensionalModulesWithBasis, a.parent())
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-68-e3772131b543> in <module>
----> 1 super(FiniteDimensionalModulesWithBasis, a.parent())
TypeError: super(type, obj): obj must be an instance or subtype of type
sage: super(FiniteDimensionalModulesWithBasis.element_class, a)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-70-28003f3b5fda> in <module>
----> 1 super(FiniteDimensionalModulesWithBasis.element_class, a)
TypeError: super() argument 1 must be type, not lazy_attributeI've tried a few other variations, but no luck so far.
Changed branch from u/jhpalmieri/fp-module-bugs to u/tscrim/fp_module_bugs-33275
Reviewer: Travis Scrimshaw
Here we go. Just use super(). :) If my change is good, then positive review.
New commits:
29dbd23 | Last tweaks using super(). |
Great, thanks!
Changed branch from u/tscrim/fp_module_bugs-33275 to 29dbd23