Repository navigation
Center of skew rings and kernel of RingMap to skew rings #4485
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0d4aeee
7f7aa48
6c9818c
a6a82f8
b104b84
7724ead
96a43a8
47b4aa0
d003ada
d62b77e
d1327b5
3f285ff
0b11e7f
805b2e4
c1d53d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| -* | ||
| computes the center of a ring R and returns the map from center(R) -> R | ||
|
|
||
| maybe this should just be called "center" but the term is ubiquitous across | ||
| mathematics and appears in several different. trying to merge them all into a | ||
| single method runs into the awkwardness of method options leaking out to all | ||
| the different overrides. | ||
| *- | ||
|
|
||
| center = method(Options => {Strategy => null}) | ||
| center(Ring) := RingMap => opts -> (R) -> R.cache.center ??= ( | ||
| z := runHooks((center, Ring), (opts, R), Strategy => opts.Strategy); | ||
| if z =!= null then z else error "center: no strategy for computing center of the given ring" | ||
| ) | ||
|
|
||
| addHook((center, Ring), Strategy => "isCommutative", (opts, R) -> if isCommutative R then map(R, R) else null) | ||
| addHook((center, Ring), Strategy => "isSkewAffineRing", (opts, R) -> ( | ||
| -- David Eisenbud observed this strategy for computing the center of a skew polynomial ring | ||
| if not isPolynomialRing R then return null; | ||
| if not isSkewAffineRing R then return null; | ||
|
|
||
| (R', phi) := flattenRing R; | ||
| -- get the natural prime coefficient ring | ||
| kk := coefficientRing R'; | ||
|
|
||
| x := symbol x; -- for pairs of skew variables | ||
| y := symbol y; -- for commuting variables | ||
| skews := R'.SkewCommutative; | ||
| n := #skews; | ||
| xvars := flatten for i from 0 to n - 1 list | ||
| for j from i + 1 to n - 1 list | ||
| x_{i, j}; | ||
| ximages := flatten for i from 0 to n - 1 list | ||
| for j from i + 1 to n - 1 list | ||
| R'_(skews_i) * R'_(skews_j); | ||
|
|
||
| commuters := toList (0..numgens R' - 1) - set skews; | ||
| yvars := toList(y_0..y_(#commuters - 1)); | ||
| yimages := apply(commuters, i -> R'_i); | ||
| S := kk[xvars, yvars, Degrees => apply(ximages| yimages, degree)]; | ||
|
|
||
| -- hack to lazy-load PushForward package only when this hook needs it | ||
| PushForward := needsPackage "PushForward"; | ||
| pushFwd := value PushForward.Dictionary#"pushFwd"; | ||
|
|
||
| -- the ideal defining the center is the annihilator of R^1 as a module over the polynomial ring S | ||
| K := annihilator pushFwd(map(R', S, ximages | yimages), R'^1); | ||
| Z := S/K; | ||
| Z.formation = FunctionApplication {center, R}; | ||
|
|
||
| map(R, Z, phi^-1 matrix {ximages | yimages}) | ||
| )) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,6 +80,7 @@ monomcurve.m2 | |
| fano.m2 | ||
| schubert.m2 | ||
| local.m2 | ||
| center.m2 | ||
|
|
||
| packages.m2 | ||
| document.m2 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -238,126 +238,144 @@ kernel RingMap := Ideal => opts -> (cacheValue (symbol kernel => opts)) (f -> ( | |
| -- This is a map from method keys to strategy hash tables | ||
| algorithms := new MutableHashTable from {} | ||
| algorithms#(kernel, RingMap) = new MutableHashTable from { | ||
| "Center" => (opts, f) -> ( | ||
| -- exploit the fact that any map from a commutative ring to a | ||
| -- non-commutative ring factors through the center. | ||
| (R, S) := (target f, source f); | ||
| if not isCommutative S then return null; | ||
| if isCommutative R then return null; | ||
| inc := try(center R) else return null; | ||
|
|
||
| C := source inc; | ||
| G := graphRing inc; | ||
|
|
||
| -- include R into G | ||
| includeR := map(G, R, submatrix(vars G, toList(0..(numgens R) - 1))); | ||
| -- project from G to C | ||
| projectToCenter := map(C, G, map(C^1, C^(numgens R), 0) | vars C); | ||
| kernel map(C, S, projectToCenter * (includeR * f)) | ||
| ), | ||
|
|
||
| FractionField => (opts, f) -> ( | ||
| (F, R) := (target f, source f); | ||
| C := last F.baseRings; | ||
| if not instance(F, FractionField) | ||
| or not coefficientRing R === (k := coefficientRing C) | ||
| or not(isPolynomialRing C or isQuotientOf(PolynomialRing, C)) | ||
| or not(isPolynomialRing R or isQuotientOf(PolynomialRing, R)) | ||
| then return null; | ||
|
|
||
| prs := presentation C; | ||
| B := ring prs; | ||
| images := apply(generators R, x -> ( | ||
| w := f x; | ||
| new Divide from {numerator w, denominator w} | ||
| )); | ||
|
|
||
| -- now make a common denominator for all images | ||
| images = new MutableList from images; | ||
| i := 1; | ||
| while i < #images do ( | ||
| z := syz( | ||
| matrix{{denominator images#0,denominator images#i}}, | ||
| SyzygyLimit => 1 | ||
| ); | ||
| a := -z_(0,0); | ||
| b := z_(1,0); | ||
|
|
||
| j := 0; | ||
| while j < i do ( | ||
| images#j = apply(images#j, s -> s*a); | ||
| j += 1; | ||
| ); | ||
| images#i = apply(images#i, s -> s*b); | ||
| i += 1; | ||
| ); | ||
| images = toList images; | ||
| commonDenominator := images#0#1; | ||
|
|
||
| d := symbol d; | ||
| h := symbol h; | ||
| x := symbol x; | ||
| y := symbol y; | ||
| (n1, n2) := (numgens F, numgens R); | ||
| S := k[x_1 .. x_n1, d, y_1 .. y_n2, h, | ||
| MonomialOrder => Eliminate (n1 + 1), | ||
| Degrees => join(degrees C, {{1}}, degrees R, {{1}}) | ||
| ]; | ||
|
|
||
| in1 := map(S,C,matrix {take (generators S, n1)}); | ||
| in2 := map(S,B,matrix {take (generators S, n1)}); | ||
| in3 := map(S,R,matrix {take (generators S, {n1 + 1, n1 + n2})}); | ||
| back := map(R,S,map(R^1,R^(n1 + 1),0) | vars R | 1 ); | ||
| ideal back selectInSubring( | ||
| 1, | ||
| generators gb( | ||
| in2 prs | homogenize ( | ||
| in3 vars source in3 - d * in1 matrix {apply(images, first)} | ||
| | d * in1 commonDenominator - 1, | ||
| h | ||
| ), | ||
| Strategy => LongPolynomial, | ||
| opts | ||
| ) | ||
| ) | ||
| ), | ||
| (F, R) := (target f, source f); | ||
| C := last F.baseRings; | ||
| if not instance(F, FractionField) | ||
| or not coefficientRing R === (k := coefficientRing C) | ||
| or not(isPolynomialRing C or isQuotientOf(PolynomialRing, C)) | ||
| or not(isPolynomialRing R or isQuotientOf(PolynomialRing, R)) | ||
| then return null; | ||
|
|
||
| prs := presentation C; | ||
| B := ring prs; | ||
| images := apply(generators R, x -> ( | ||
| w := f x; | ||
| new Divide from {numerator w, denominator w} | ||
| )); | ||
|
|
||
| -- now make a common denominator for all images | ||
| images = new MutableList from images; | ||
| i := 1; | ||
| while i < #images do ( | ||
| z := syz( | ||
| matrix{{denominator images#0,denominator images#i}}, | ||
| SyzygyLimit => 1 | ||
| ); | ||
| a := -z_(0,0); | ||
| b := z_(1,0); | ||
|
|
||
| j := 0; | ||
| while j < i do ( | ||
| images#j = apply(images#j, s -> s*a); | ||
| j += 1; | ||
| ); | ||
| images#i = apply(images#i, s -> s*b); | ||
| i += 1; | ||
| ); | ||
| images = toList images; | ||
| commonDenominator := images#0#1; | ||
|
|
||
| d := symbol d; | ||
| h := symbol h; | ||
| x := symbol x; | ||
| y := symbol y; | ||
| (n1, n2) := (numgens F, numgens R); | ||
| S := k[x_1 .. x_n1, d, y_1 .. y_n2, h, | ||
| MonomialOrder => Eliminate (n1 + 1), | ||
| Degrees => join(degrees C, {{1}}, degrees R, {{1}}) | ||
| ]; | ||
|
|
||
| in1 := map(S,C,matrix {take (generators S, n1)}); | ||
| in2 := map(S,B,matrix {take (generators S, n1)}); | ||
| in3 := map(S,R,matrix {take (generators S, {n1 + 1, n1 + n2})}); | ||
| back := map(R,S,map(R^1,R^(n1 + 1),0) | vars R | 1 ); | ||
| ideal back selectInSubring( | ||
| 1, | ||
| generators gb( | ||
| in2 prs | homogenize ( | ||
| in3 vars source in3 - d * in1 matrix {apply(images, first)} | ||
| | d * in1 commonDenominator - 1, | ||
| h | ||
| ), | ||
| Strategy => LongPolynomial, | ||
| opts | ||
| ) | ||
| ) | ||
| ), | ||
|
|
||
| "AffineRing" => (opts, f) -> ( | ||
| (F, R) := (target f, source f); | ||
| if not isAffineRing R | ||
| or not isAffineRing F | ||
| or not instance(ambient R, PolynomialRing) | ||
| or not instance(ambient F, PolynomialRing) | ||
| or not isField coefficientRing R | ||
| or not coefficientRing R === coefficientRing F | ||
| then return null; | ||
|
|
||
| graph := generators graphIdeal f; | ||
| assert( not isHomogeneous f or isHomogeneous graph ); | ||
| SS := ring graph; | ||
| chh := canUseHilbertHint graph; | ||
| if chh then ( | ||
| -- compare with pushNonLinear | ||
| hf := poincare module target f; | ||
| T := degreesRing SS; | ||
| hf = hf * product(degrees source graph, d -> 1 - T_d); | ||
| -- cache poincare | ||
| poincare cokernel graph = hf; | ||
| ); | ||
| n1 := numgens F; | ||
| mapback := map(R, ring graph, map(R^1, R^n1, 0) | vars R); | ||
| G := gb(graph,opts); | ||
| assert (not chh or G#?"rawGBSetHilbertFunction log"); -- ensure the Hilbert function hint was actually used in gb.m2 | ||
| ideal mapback selectInSubring(1,generators G) | ||
| ), | ||
| (F, R) := (target f, source f); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm also not seeing a change in this section either - again, it might be due to a spacing change. |
||
| if not isAffineRing R | ||
| or not isAffineRing F | ||
| or not instance(ambient R, PolynomialRing) | ||
| or not instance(ambient F, PolynomialRing) | ||
| or not isField coefficientRing R | ||
| or not coefficientRing R === coefficientRing F | ||
| then return null; | ||
|
|
||
| graph := generators graphIdeal f; | ||
| assert( not isHomogeneous f or isHomogeneous graph ); | ||
| SS := ring graph; | ||
| chh := canUseHilbertHint graph; | ||
| if chh then ( | ||
| -- compare with pushNonLinear | ||
| hf := poincare module target f; | ||
| T := degreesRing SS; | ||
| hf = hf * product(degrees source graph, d -> 1 - T_d); | ||
| -- cache poincare | ||
| poincare cokernel graph = hf; | ||
| ); | ||
| n1 := numgens F; | ||
| mapback := map(R, ring graph, map(R^1, R^n1, 0) | vars R); | ||
| G := gb(graph,opts); | ||
| assert (not chh or G#?"rawGBSetHilbertFunction log"); -- ensure the Hilbert function hint was actually used in gb.m2 | ||
| ideal mapback selectInSubring(1,generators G) | ||
| ), | ||
|
|
||
| ZZ => (opts, f) -> if source f === ZZ then ideal char target f, | ||
|
|
||
| Default => (opts, f) -> ( | ||
| (F, R) := (target f, source f); | ||
| numsame := 0; | ||
| while ( | ||
| R.baseRings#?numsame and | ||
| F.baseRings#?numsame and | ||
| R.baseRings#numsame === F.baseRings#numsame | ||
| ) do numsame = numsame + 1; | ||
| while not ( | ||
| isField F.baseRings#(numsame-1) | ||
| or | ||
| F.baseRings#(numsame-1).?isBasic | ||
| ) do numsame = numsame - 1; | ||
| k := F.baseRings#(numsame-1); | ||
| (R',p) := flattenRing(R, CoefficientRing => k); | ||
| (F',r) := flattenRing(F, CoefficientRing => k); | ||
| if R' === R and F' === F then return null; | ||
| p^-1 kernel (r * f * p^-1) | ||
| ), | ||
| (F, R) := (target f, source f); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that the only change here was the removal of a comma. |
||
| numsame := 0; | ||
| while ( | ||
| R.baseRings#?numsame and | ||
| F.baseRings#?numsame and | ||
| R.baseRings#numsame === F.baseRings#numsame | ||
| ) do numsame = numsame + 1; | ||
| while not ( | ||
| isField F.baseRings#(numsame-1) | ||
| or | ||
| F.baseRings#(numsame-1).?isBasic | ||
| ) do numsame = numsame - 1; | ||
| k := F.baseRings#(numsame-1); | ||
| (R',p) := flattenRing(R, CoefficientRing => k); | ||
| (F',r) := flattenRing(F, CoefficientRing => k); | ||
| if R' === R and F' === F then return null; | ||
| p^-1 kernel (r * f * p^-1) | ||
| ) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the only difference here the removal of the final comma?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's right. Outside of the addition of the new hook method, the only non-ws change to this file is the removal of this final comma in the definition. |
||
| } | ||
|
|
||
| -- Installing hooks for kernel RingMap | ||
| scan({Default, ZZ, "AffineRing", FractionField}, strategy -> | ||
| scan({Default, ZZ, "AffineRing", FractionField, "Center"}, strategy -> | ||
| addHook(key := (kernel, RingMap), algorithms#key#strategy, Strategy => strategy)) | ||
|
|
||
| ----------------------------------------------------------------------------- | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like there wasn't a change here - perhaps only a change to spacing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, as i said in the pr description: