M2
M2 copied to clipboard
LeftIdeal as a Module
This is an alternative to #2912 and #3020 which implements the following:
- adds
LeftIdealas a type ofModule - forces the constructor
idealto return aLeftIdealif the ring is a Weyl algebra - implements a handful of methods of
Idealwhich are not defined forModule - reimplements a handful of methods that are different from
Ideal
I mostly wanted to see if this was feasible, but it was pretty straightforward (thanks to Anton and Mike's fixes to Dmodules, which I more or less copied), so I figured I'd turn it into a PR to present this option.
Pros:
Idealis intact
Cons:
- some duplication because
LeftIdealandIdealare now unrelated
@antonleykin @mikestillman this is now passing all tests, and by virtue of inheriting from Module, I believe everything else should work out of the box.
Incidentally, I think it would also make a lot of sense to have Ideal inherit from Module. The only real difference is between HashTable currently and MutableHashTable if we make this change, which would only affect hash-related behavior.
Let me know what you think!
Having Ideal inherit from Module doesn't seem appropriate, because an instance of Module is a right module and and instance of Ideal is to be a 2-sided ideal. At least as proposed by Anton.
Why is an instance of Module a right module necessarily?
Why is an instance of Module a right module necessarily?
Because when representing a map between free modules as a matrix, the matrix acts on the left side of the vector.
This sounds like programming detail that can be fixed by introducing covectors. Regardless, this is irrelevant to this PR.
Well, no, it's an argument for introducing LeftModule and RightModule, so that LeftIdeal can inherit from LeftModule.
This PR isn't introducing LeftModule or RightModule, and there are no maps between LeftIdeals, so there can be no confusion here.
But if LeftIdeal inherits from Module, as is the case in your PrR, then when I and J are two left ideals, Hom(I,J) will try to do something, because they will both be modules.
Thanks, I'll add Hom methods for LeftIdeal to give a "not yet implemented" error.
Or better, just don't make a left ideal a type of module.
All ideals are modules.
Then Hom(I,J) should work.
Do you expect me to implement everything in one PR? Later, when left and right modules are in place, you can change one line and have LeftIdeal inherit from LeftModule instead, with Him(I, J) working as expected.
You're the one who said "All ideals are modules."
Why is an instance of Module a right module necessarily?
Because when representing a map between free modules as a matrix, the matrix acts on the left side of the vector.
not related to this PR but: I'm confused about this. I know this has been discussed many times already, but multiplication is on the right, not on the left? as in
i1 : needsPackage "AssociativeAlgebras"
o1 = AssociativeAlgebras
o1 : Package
i2 : R=QQ<|a,b|>
o2 = R
o2 : FreeAlgebra
i3 : a*b
o3 = a*b
o3 : R
i4 : matrix{{a}}*matrix{{b}}
o4 = | ba |
1 1
o4 : Matrix R <-- R
I'm torn about whether Ideal should inherit from Module (or any of the various Left/Right iterations).
Mathematically, yes, an ideal of $R$ is an $R$-module. So it makes perfect sense.
But in Macaulay2, certain methods have different behaviors when passed an Ideal object v. a Module object. For example, res I gives us the resolution of $R/I$ as an $R$-module and not $I$. So we'd violate the Liskov substitution principle if Ideal inherited from Module.
For example, res I gives us the resolution of $R/I$ as an $R$-module and not $I$. So we'd violate the Liskov substitution principle if Ideal inherited from Module.
I think situations like this are rare enough that they can be considered exceptions forced by mathematical conventions.
Also, I'm not necessarily suggesting that everything under the sun that has a module structure should inherit from modules, but for ideals in particular, almost every method turns the input into a module and sometimes the output back into an ideal.
I have a few comments here.
Why is an instance of Module a right module necessarily?
Because when representing a map between free modules as a matrix, the matrix acts on the left side of the vector.
This is not quite correct I think, as we have changed multiplication of matrices to use the opposite side. We did this precisely so people could have left modules (e.g. people working with D-modules are pretty used to thinking in these terms). See @pzinn 's comments above.
Also
Then Hom(I,J) should work.
Why is this? In general, Hom only returns a result over the center of the ring, if the modules do not have extra bi-module structure?
I'm torn about whether
Idealshould inherit fromModule(or any of the variousLeft/Rightiterations).Mathematically, yes, an ideal of R is an R-module. So it makes perfect sense.
But in Macaulay2, certain methods have different behaviors when passed an
Idealobject v. aModuleobject. For example,res Igives us the resolution of R/I as an R-module and not I. So we'd violate the Liskov substitution principle ifIdealinherited fromModule.
In commutative algebra it is fairly confusing to have some operations on ideals work as if for the corresponding quotient module (e.g. depth, free resolution even, etc). But the difference is so ingrained it is hard to change these notions. And from an efficiency view, these are almost always better than treating an ideal as a module directly. I think I am against making an ideal be a module directly (although I could be convinced perhaps).
@mahrud Are there really alot of cases where Ideal's are considered as Module's directly? I haven't gone to look, but I would think it is fairly small (Hom, tensor are the ones I think of).
One reason I am against it is more pedagogical: I don't want to make people learning, e.g. undergraduates in a first class, need to know about these things completely. Ideals are just simpler than modules (I know that they will still see free modules, etc., and I used to think that this was not a good argument. Until I tried teaching younger undergraduates using Macaulay2).
(Here is another thing we don't want to do: just make all modules into complexes? )
Like I said, I'm not suggesting turning everything to inherit from the most general type.
Re: pedagogy, I also didn't learn what a Groebner basis of an ideal is by first learning what a Groebner basis of a module is, but here we are:
i1 : code(gb, Ideal)
o1 = -- code for method: gb(Ideal)
../linuxbrew/.linuxbrew/share/Macaulay2/Core/gb.m2:307:35-307:57: --source code:
gb Ideal := GroebnerBasis => opts -> I -> gb (module I, opts)
Re: efficiency, I think operations for ideals and submodules of R^1 should be identical in efficiency, since they are mathematically the same, no? I don't see why having them also be programatically the same would slow things down.
The biggest reason I'm advocating for LeftIdeals inheriting from Modules (and, eventually, perhaps all Ideals, though that's not the point of this PR) is that there will be much less code duplication, therefore the code will be simpler to read and easier to maintain, because you only need to explicitly implement the methods where LeftIdeals are special, not every method.
wrong thread sry
@antonleykin I couldn't attend the meeting because of the MSRI workshop, could you summarize your objections to this approach? I don't think it's possible to switch back without significant confusion in the future.
@antonleykin I couldn't attend the meeting because of the MSRI workshop, could you summarize your objections to this approach? I don't think it's possible to switch back without significant confusion in the future.
We haven't discussed this PR in any detail, but my personal opinion is that one should lay out a strategic vision of what one would do after this PR. Creating LeftIdeal as a type derived from the de-facto right Module (seems to be hacky) but does achieve a local goal. What is your global vision?
Please post to zulipchat in "M2internals:Noncommutativity".
Maybe I don't understand what you mean by a "strategic vision". The vision is the same as yours, only the implementation is different.
LeftIdeal being derived from Module is a temporary solution until we have LeftModule and RightModule types that are truly differentiated. Currently I have:
LeftIdeal = new Type of Module -- or LeftModule, or ImmutableType?
Which can be simply changed when we have that type. Like I said above, given the portion of func(Ideal) methods that simply call func(module I) I think this is much less work than your solution.
(I'll elaborate in zulip, but wanted to give a quick answer here)