Repository navigation
Compute Hom / Ext over exterior algebra via pushforward - #4477
joel-dodge wants to merge 68 commits into
Conversation
mahrud
left a comment
There was a problem hiding this comment.
I know this is still a draft, but noticed the changes to Hom.m2 and wanted to share some early thoughts in case that's helpful at all.
| }) | ||
| DegreeLimit => null, | ||
| MinimalGenerators => true, | ||
| Strategy => null |
There was a problem hiding this comment.
Don't think the indentation needs to change, and the trailing comma is harmless, and in this case intentional in order to minimize git line changes when adding a new option.
There was a problem hiding this comment.
Makes sense. I added the comma back and moved the closing }} to be at the same indentaiton level as the options as it was before. The only other change here is turn some tabs into spaces which I think is a virtuous change to make.
| H.cache.homomorphism = f -> map(N, M, adjoint'(f, M, N), Degree => first degrees source f + degree f); | ||
| H.cache.formation = FunctionApplication { Hom, (M, N, DegreeLimit => e) }; | ||
| H) | ||
| Y#(Hom, M, N, e) ?? ( |
There was a problem hiding this comment.
I'm a fan of f(x) := x -> x.cache.blah ??= (...) for readability, but it's good to be aware that this code is not equivalent to the previous version: your new version attempts to reach Y#(Hom, M, N, e), but an internal error is returned, so then the remainder is computed, whereas previously an internal error wasn't generated. Addition of the extra indentation makes me slightly prefer rolling back this change.
There was a problem hiding this comment.
Interesting. I think that were I to rewrite this now I would replace L41 with
H = if opts.MinimalGenerators then trim H else H
and make this L36 into an??=
If I understand your explanation then I think this would make the proposed code equivalent to the original. The diversion was unintentional but I can't recall what I was thinking when this was written.
In light of this, you still prefer to keep it as it was and lose the extra indentation?
There was a problem hiding this comment.
Huh I think there's actually been a git-merge bug with trim and trim' here and the intention was something like this:
trim' := if opts.MinimalGenerators then trim else identity;
if Y#?(Hom, M, N, e) then return trim' Y#(Hom, M, N, e);
...
H = Y#(Hom, M, N, e) = ...;
H.cache.homomorphism = ...;
H.cache.formation = ...;
trim' H)(note that trim' is not used at all currently, but should be used twice).
To be honest, in a perfect world there would be no MinimalGenerators option here, we would not trim Hom (because it can be quite costly), but the user can later run trim Hom(M,N) and it would preserve the homomorphism information, which currently is not kept.
There was a problem hiding this comment.
Oh interestig. It looks like even in the current development branch that trim' is defined but not used at all. Maybe there was a merge bug at some point in the part?
Indeed I see that you are suggesting that the intention was to always store the untrimmed module in the cache (the cache key does not depend on this so that makes sense) and for trimming to be applied always just at the point that the module is returned. I think that your code would not work since trimming at the edge like that makes the homomorphism method in the cache unfindable by methods that need it (e.g. homomorphism(Matrix)). This could be addressed by making trim more aware of preserving cached structure in modules that it is trimming - a similar issue appears for all constructions like Hom, DirectSum, pushFwd, etc. but that seems like a big change that includes some m2 level philosophical concerns to me.
It feels to me like actually the Hom computation ought to be cached based on all of the options not just the degree limit and that if that change were made that the definition of trim' ought to just be removed here.
There was a problem hiding this comment.
I just pushed a couple commits to clean these things up. lmk what you think.
There was a problem hiding this comment.
Ya in this commit you can see that the use of trim' was dropped in favor of just in-lining the logic: e0ffe77 it was the PR containing this commit itself that introduced trim' though so hard to tell what was a merge error and what was just temporary draft work.
| map(Module,RingMap) := Matrix => o -> (M,p) -> map(M,,p,map(M,cover M,1),o) | ||
|
|
||
| flattenDegreeMap = method() | ||
| flattenDegreeMap(RingMap) := (f) -> ( |
There was a problem hiding this comment.
I need to think about this more, but can we not always cache the degree map in the ring map given by flattenRing? Seems simpler to me.
There was a problem hiding this comment.
I am not sure if I understand this comment.
My prototypical use case for this method is
i1 : R = kk[a..d, SkewCommutative => true];
i2 : f = flattenDegreeMap map(R, kk)
o2 = map (R, kk[], {})
o2 : RingMap R <-- kk[]
i3 : degreeGroup source f
1
o3 = ZZ
o3 : ZZ-module, free
and I don't think I see how to apply your remarks to this situation.
There was a problem hiding this comment.
I think I'm confused about the purpose of this function based on its name. This is what I thought you meant:
S := kk[...];
R := S[...]/...;
(R', f) := flattenRing R;
f.cache.DegreeMap -- I thought flattenDegreeMap gives thisThere was a problem hiding this comment.
I think that the comment on L602-606 describes what this construction is doing pretty clearly.
I was not especially happy with the name flattenDegreeMap so would be very open to changing it. I will think about this again and see what else I can come up with. Happy to entertain suggestions as well if the below description helps and something jumps out to you.
| Y#(Ext,i,M,N) ??= ( | ||
| R := ring M; | ||
| if not isCommutative R then error "'Ext' not implemented yet for noncommutative rings."; | ||
| -- if not isCommutative R then error "'Ext' not implemented yet for noncommutative rings."; |
There was a problem hiding this comment.
I know this is still a draft, but eventually this should be removed and new checks should be added (e.g. for WeylAlgebras and potentially other types of rings which may support complexes)
| AuxiliaryFiles => true | ||
| AuxiliaryFiles => true, | ||
| PackageImports => { | ||
| "Complexes" -- compute resolution for Ext |
There was a problem hiding this comment.
Would it make more sense to add a new package ExteriorAlgebras which depends on both PushForward and Complexes, and adds new pushforward hooks for exterior algebras? (and perhaps move other exterior algebra related functionality there?)
There was a problem hiding this comment.
That is a great suggestion. Let me chew on it a bit but I will probably do exactly that.
There was a problem hiding this comment.
Unpacking this suggestion, I think that you are suggesting to hookify the pushFwd methods and refactor this package to enable capturing the exterior algebra specific logic in hooks that are controlled by a new ExteriorAlgebra package. It is not clear to me what the advantage is over the current shape of things though. It doesn't seem to me like specializing to the commutative case or specializing to the skew commutative case would provide any obvious performance advantages. Do you have intuition that suggests otherwise?
|
I just added the following edit to the PR description 2026-11-01 edit:
@d-torrance do you have any suggestion for what the right way to persist the output of an investigation like this in a way which would be useful for anyone in the future who wants to understand these different hom constructions? |
This PR adds a few loosely related changes all centered around the use of the PushForward package to compute Hom and Ext of modules over exterior algebras:
If R is non-commutative, Hom_R(M, N) is not in general an R-module. If f: S -> R is a RingMap, this introduces:
Here is a short list of auxiliary changes that this PR includes:
2026-11-01 edit: