From e7177205b53ac163c5bc38a128b4742c7dde72a1 Mon Sep 17 00:00:00 2001 From: pzinn Date: Wed, 18 Sep 2024 11:22:00 +1000 Subject: [PATCH 1/4] implement isPromotable --- M2/Macaulay2/m2/enginering.m2 | 37 ++++++++++++++++++++--------------- M2/Macaulay2/m2/ringmap.m2 | 2 +- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/M2/Macaulay2/m2/enginering.m2 b/M2/Macaulay2/m2/enginering.m2 index 62133d97f25..5164cf7ce17 100644 --- a/M2/Macaulay2/m2/enginering.m2 +++ b/M2/Macaulay2/m2/enginering.m2 @@ -329,6 +329,9 @@ frac EngineRing := R -> if isField R then R else if R.?frac then R.frac else ( if R.?indexSymbols then F.indexSymbols = applyValues(R.indexSymbols, r -> promote(r,F)); if R.?indexStrings then F.indexStrings = applyValues(R.indexStrings, r -> promote(r,F)); if R.?numallvars then F.numallvars=R.numallvars; + scan(R.baseRings, S -> if S.?frac and not isPromotable(S.frac,F) then + promote(S.frac,F) := (a,F) -> fraction(promote(numerator a,R),promote(denominator a,R)) + ); F) -- methods for all ring elements @@ -466,6 +469,8 @@ swap = (x,y) -> (y,x) promoterightexact = swap @@ promoteleftexact @@ swap promoterightinexact = swap @@ promoteleftinexact @@ swap +isPromotable = (R,S) -> lookup(promote,R,S) =!= null + divmod := R -> (f,g) -> ( (q,r) := rawDivMod(raw f, raw g); (new R from q, new R from r)) @@ -474,10 +479,10 @@ quotientRemainder(RingElement,RingElement) := (f,g) -> ( S := ring g; m := quotientRemainder(R,S) := ( if R === S then divmod R - else if isMember(R,S.baseRings) then ( + else if isPromotable(R,S) then ( (x,y) -> divmod(promote(x,S), y) ) - else if isMember(S,R.baseRings) then ( + else if isPromotable(S,R) then ( (x,y) -> divmod(x, promote(y,R)) ) else error "expected pair to have a method for quotientRemainder" @@ -500,10 +505,10 @@ RingElement % RingElement := RingElement => (f,g) -> ( if R === S then ( (x,y) -> new R from raw x % raw y ) - else if isMember(R,S.baseRings) then ( + else if isPromotable(R,S) then ( (x,y) -> promote(x,S) % y ) - else if isMember(S,R.baseRings) then ( + else if isPromotable(S,R) then ( (x,y) -> x % promote(y,R) ) else error "expected pair to have a method for '%'" @@ -523,10 +528,10 @@ RingElement // RingElement := RingElement => (f,g) -> ( if R === S then ( (x,y) -> new R from raw x // raw y ) - else if isMember(R,S.baseRings) then ( + else if isPromotable(R,S) then ( (x,y) -> promote(x,S) // y ) - else if isMember(S,R.baseRings) then ( + else if isPromotable(S,R) then ( (x,y) -> x // promote(y,R) ) else error "expected pair to have a method for '//'" @@ -544,10 +549,10 @@ RingElement - RingElement := RingElement => (f,g) -> ( if R === S then ( (x,y) -> new R from raw x - raw y ) - else if isMember(R,S.baseRings) then ( + else if isPromotable(R,S) then ( (x,y) -> promote(x,S) - y ) - else if isMember(S,R.baseRings) then ( + else if isPromotable(S,R) then ( (x,y) -> x - promote(y,R) ) else error "expected pair to have a method for '-'" @@ -565,10 +570,10 @@ RingElement * RingElement := RingElement => (f,g) -> ( if R === S then ( (x,y) -> new R from raw x * raw y ) - else if isMember(R,S.baseRings) then ( + else if isPromotable(R,S) then ( (x,y) -> promote(x,S) * y ) - else if isMember(S,R.baseRings) then ( + else if isPromotable(S,R) then ( (x,y) -> x * promote(y,R) ) else error "expected pair to have a method for '*'" @@ -586,10 +591,10 @@ RingElement + RingElement := RingElement => (f,g) -> ( if R === S then ( (x,y) -> new R from raw x + raw y ) - else if isMember(R,S.baseRings) then ( + else if isPromotable(R,S) then ( (x,y) -> promote(x,S) + y ) - else if isMember(S,R.baseRings) then ( + else if isPromotable(S,R) then ( (x,y) -> x + promote(y,R) ) else error "expected pair to have a method for '+'" @@ -611,10 +616,10 @@ RingElement == RingElement := (f,g) -> ( if R === S then ( (x,y) -> raw x === raw y ) - else if isMember(R,S.baseRings) then ( + else if isPromotable(R,S) then ( (x,y) -> promote(x,S) == y ) - else if isMember(S,R.baseRings) then ( + else if isPromotable(S,R) then ( (x,y) -> x == promote(y,R) ) else error "expected pair to have a method for '=='" @@ -630,10 +635,10 @@ RingElement / RingElement := RingElement => (f,g) -> ( frac R; (r,s) -> fraction (r,s) ) - else if isMember(R,S.baseRings) then ( + else if isPromotable(R,S) then ( (x,y) -> promote(x,S) / y ) - else if isMember(S,R.baseRings) then ( + else if isPromotable(S,R) then ( (x,y) -> x / promote(y,R) ) else error "expected pair to have a method for '/'" diff --git a/M2/Macaulay2/m2/ringmap.m2 b/M2/Macaulay2/m2/ringmap.m2 index ef4f978de2e..e1f5a200bf1 100644 --- a/M2/Macaulay2/m2/ringmap.m2 +++ b/M2/Macaulay2/m2/ringmap.m2 @@ -125,7 +125,7 @@ map(Ring, Ring, Matrix) := RingMap => opts -> (R, S, m) -> ( else if r < n then error ("encountered values for ", toString r, " variables, but expected ", toString n) else if r == n then ( if numgens A > 0 then ( - if A === R or isMember(A, R.baseRings) then ( + if A === R or isPromotable(A, R) then ( -- we can promote mE = mE | promote(vars A, R); if instance(A,GaloisField) and A.rawGaloisField then ( From 28bee55373cc9c5964956db11c71b8633d5fdad8 Mon Sep 17 00:00:00 2001 From: pzinn Date: Mon, 7 Oct 2024 16:51:34 +1100 Subject: [PATCH 2/4] setupPromote, setupLift, use in tensor products, selectVariables --- M2/Macaulay2/m2/enginering.m2 | 42 +++++++++++++++++-- M2/Macaulay2/m2/exports.m2 | 2 + M2/Macaulay2/m2/matrix.m2 | 6 +-- M2/Macaulay2/m2/newring.m2 | 10 ++++- M2/Macaulay2/m2/polyrings.m2 | 7 +++- M2/Macaulay2/m2/ringmap.m2 | 16 +++++-- .../packages/CotangentSchubert/cotangent.m2 | 33 ++++----------- 7 files changed, 80 insertions(+), 36 deletions(-) diff --git a/M2/Macaulay2/m2/enginering.m2 b/M2/Macaulay2/m2/enginering.m2 index 5164cf7ce17..c368073100a 100644 --- a/M2/Macaulay2/m2/enginering.m2 +++ b/M2/Macaulay2/m2/enginering.m2 @@ -225,7 +225,40 @@ commonEngineRingInitializations = (F) -> ( *- ) ------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- TODO improve this, or deprecate promote/lift(List,R,S) +defaultDegMap := (R,S) -> ( + n:=degreeLength S-degreeLength R; + if n==0 then identity + else if n<0 then d -> take(d,degreeLength S) + else d -> d|toList(n:0) + ) + +-- automate promote +setupPromote = method() +setupPromote (Function,Ring,Ring,Function) := (f,R,S,degmap) -> ( + promote(R,S) := (a,S) -> f a; + promote(List,R,S) := (m,R,S) -> apply(m,degmap); + -- promote(Matrix,R,S) := + -- promote(MutableMatrix,R,S) := -- doesn't work, cf https://github.com/Macaulay2/M2/issues/2192 + promote(Module,R,S) := (M,R1,S1) -> S ** M; + promote(Matrix,R,S) := (m,R,S) -> map(promote(target m,S),promote(source m,S),applyTable(entries m,x->promote(x,S))); + promote(MutableMatrix,R,S) := (m,R,S) -> mutableMatrix applyTable(entries m,x->promote(x,S)); + ) +setupPromote (Function,Ring,Ring) := (f,R,S) -> setupPromote(f,R,S,defaultDegMap(R,S)); + +-- automate (to some extent) lift +setupLift = method() +setupLift (Function,Ring,Ring,Function) := (f,R,S,degmap) -> ( + lift(R,S) := opts -> (a,S) -> if opts.Verify then f a else try f a; + lift(List,R,S) := opts -> (m,R,S) -> apply(m,degmap); + lift(Module,R,S) := opts -> (M,R,S) -> S ** M; + lift(Matrix,R,S) := opts -> (m,R,S) -> map(lift(target m,S),lift(source m,S),applyTable(entries m,x->lift(x,S))); + lift(MutableMatrix,R,S) := opts -> (m,R,S) -> mutableMatrix applyTable(entries m,x->lift(x,S)); + ) +setupLift (Function,Ring,Ring) := (f,R,S) -> setupLift(f,R,S,defaultDegMap(R,S)); + + ----------------------------------------------------------------------------- reduce := (r,s) -> ( z := syz( matrix{{r,s}}, SyzygyLimit => 1 ); a := z_(1,0); @@ -329,9 +362,10 @@ frac EngineRing := R -> if isField R then R else if R.?frac then R.frac else ( if R.?indexSymbols then F.indexSymbols = applyValues(R.indexSymbols, r -> promote(r,F)); if R.?indexStrings then F.indexStrings = applyValues(R.indexStrings, r -> promote(r,F)); if R.?numallvars then F.numallvars=R.numallvars; - scan(R.baseRings, S -> if S.?frac and not isPromotable(S.frac,F) then - promote(S.frac,F) := (a,F) -> fraction(promote(numerator a,R),promote(denominator a,R)) - ); + scan(R.baseRings, S -> if S.?frac and not isPromotable(S.frac,F) then ( + setupPromote(a->fraction(promote(numerator a,R),promote(denominator a,R)),S.frac,F); + setupLift(a->fraction(lift(numerator a,S),lift(denominator a,S)),F,S.frac); + )); F) -- methods for all ring elements diff --git a/M2/Macaulay2/m2/exports.m2 b/M2/Macaulay2/m2/exports.m2 index 2d9febd66ec..c77d7ee82e6 100644 --- a/M2/Macaulay2/m2/exports.m2 +++ b/M2/Macaulay2/m2/exports.m2 @@ -1127,6 +1127,8 @@ export { "setRandomSeed", "setup", "setupEmacs", + "setupLift", + "setupPromote", "shield", "show", "showClassStructure", diff --git a/M2/Macaulay2/m2/matrix.m2 b/M2/Macaulay2/m2/matrix.m2 index 66ec39c5a35..27be32811e4 100644 --- a/M2/Macaulay2/m2/matrix.m2 +++ b/M2/Macaulay2/m2/matrix.m2 @@ -166,9 +166,9 @@ Matrix * Matrix := Matrix => (m,n) -> ( else ( R := ring m; S := ring target n; - if R =!= S then ( - try m = m ** S else - try n = n ** R else + if R =!= S then ( -- use toSameRing? + try m = promote(m,S) else + try n = promote(n,R) else error "maps over incompatible rings"; ); M = target m; diff --git a/M2/Macaulay2/m2/newring.m2 b/M2/Macaulay2/m2/newring.m2 index af59bf8b464..c8efc8a7af9 100644 --- a/M2/Macaulay2/m2/newring.m2 +++ b/M2/Macaulay2/m2/newring.m2 @@ -77,7 +77,15 @@ tensor(QuotientRing, QuotientRing) := monoidTensorDefaults >> optns -> (R, S) fg := substitute(f,(vars AB)_{0 .. m-1}) | substitute(g,(vars AB)_{m .. m+n-1}); -- forceGB fg; -- if the monomial order chosen doesn't restrict, then this -- is an error!! MES - AB/image fg) + RS := AB/image fg; + setupPromote map(RS,R,(vars AB)_{0 .. m-1}); + setupLift map(R,RS,generators A | toList(n:0)); + if S =!= R then ( + setupPromote map(RS,S,(vars AB)_{m .. m+n-1}); + setupLift map(S,RS,toList(m:0) | generators B); + ); + RS + ) ------------------------- -- Graph of a ring map -- diff --git a/M2/Macaulay2/m2/polyrings.m2 b/M2/Macaulay2/m2/polyrings.m2 index 7b882739871..59a1b5df1cc 100644 --- a/M2/Macaulay2/m2/polyrings.m2 +++ b/M2/Macaulay2/m2/polyrings.m2 @@ -274,7 +274,12 @@ selectVariables(List,PolynomialRing) := (v,R) -> ( o.Variables = o.Variables_v; o.Degrees = o.Degrees_v; o = new OptionTable from o; - (S := (coefficientRing R)(monoid [o]),map(R,S,(generators R)_v))) + S := (coefficientRing R)(monoid [o]); + f := map(R,S,(generators R)_v); + g := map(S,R,apply(generators R, v->substitute(v,S))); + setupPromote f; + setupLift g; + (S,f)) ----------------------------------------------------------------------------- diff --git a/M2/Macaulay2/m2/ringmap.m2 b/M2/Macaulay2/m2/ringmap.m2 index e1f5a200bf1..c17ab4bd4f1 100644 --- a/M2/Macaulay2/m2/ringmap.m2 +++ b/M2/Macaulay2/m2/ringmap.m2 @@ -14,8 +14,6 @@ needs "mutablemat.m2" -- should do something about the degree map here degmap0 := n -> ( d := toList ( n : 0 ); e -> d ) -workable = f -> try (f(); true) else false - ----------------------------------------------------------------------------- -- RingMap type declarations and basic methods ----------------------------------------------------------------------------- @@ -85,7 +83,7 @@ map(Ring, Ring, Matrix) := RingMap => opts -> (R, S, m) -> ( " into a degree of length ", toString degreeLength R); opts.DegreeMap ) - else if workable (() -> promote({},S,R)) then (d -> first promote({d},S,R)) + else if (pr:=lookup(promote,List,S,R)) =!= null then (d -> first pr({d},S,R)) else if degreeLength R === degreeLength S then identity else if degreeLength S === 0 or degreeLength R === 0 then degmap0 degreeLength R else ( @@ -569,6 +567,18 @@ map(Module,Module,RingMap,List) := Matrix => o -> (M,N,p,f) -> map(M,N,p,map(M,r map(Module,Nothing,RingMap,List) := Matrix => o -> (M,N,p,f) -> map(M,N,p,map(M,,f),o) map(Module,RingMap) := Matrix => o -> (M,p) -> map(M,,p,map(M,cover M,1),o) +-- +setupPromote (RingMap,Ring,Ring,Function) := lookup(setupPromote,Function,Ring,Ring,Function) +setupPromote (RingMap,Ring,Ring) := (f,R,S) -> setupPromote(f,R,S,f.cache.DegreeMap) +-- note that promote(Module,R,S) := (M,R,S) -> f ** M would make more sense, but promote only works with free modules anyway +setupPromote RingMap := f -> setupPromote(f,source f,target f) +setupPromote (Ring,Ring) := (R,S) -> setupPromote map(S,R) + +setupLift (RingMap,Ring,Ring) := (f,R,S) -> -- f is a partial inverse to the promote map + setupLift( a -> ( b := f a; if promote(b,R) == a then b else error "cannot lift" ), R,S,f.cache.DegreeMap); + +setupLift RingMap := f -> setupLift(f,source f,target f) + -- Local Variables: -- compile-command: "make -C $M2BUILDDIR/Macaulay2/m2 " -- End: diff --git a/M2/Macaulay2/packages/CotangentSchubert/cotangent.m2 b/M2/Macaulay2/packages/CotangentSchubert/cotangent.m2 index 7de27ab1719..8efe5ed1c4e 100644 --- a/M2/Macaulay2/packages/CotangentSchubert/cotangent.m2 +++ b/M2/Macaulay2/packages/CotangentSchubert/cotangent.m2 @@ -61,18 +61,6 @@ expandElem := (P,vrs,els) -> ( sub(C,ring first els) * product(#vrs, i -> (els#i)^(ee#i)) + expandElem(Q,vrs,els) ) --- automate promotion -promoteFromMap = method() -promoteFromMap (Ring,Ring,RingMap) := (R,S,f) -> ( - promote(R,S) := (a,S1) -> f a; - promote(Matrix,R,S) := - promote(MutableMatrix,R,S) := -- doesn't work, cf https://github.com/Macaulay2/M2/issues/2192 - promote(Module,R,S) := (M,R1,S1) -> f M; --- promote(List,R,S) := (L,R1,S1) -> f\L; -- TODO put back!!!!!!!!!! - S.baseRings = prepend(R,S.baseRings); -- temporary -- until promotability test improved in enginering.m2 - ) -promoteFromMap (Ring,Ring) := (R,S) -> promoteFromMap(R,S,map(S,R)) - tautoClass = method(Dispatch=>{Thing,Thing,Type},Options=>true); -- "Chern classes" -- renamed tautoClass to avoid confusion with motivic classes zeroSection = method(Dispatch=>{Type},Options=>true) -- note the {} dualZeroSection = method(Dispatch=>{Type},Options=>true) -- note the {} @@ -114,18 +102,18 @@ pushforwardToPointFromCotangent=method(); -- pushforward to a point from K(T^*(G q := getSymbol "q"; zbar := getSymbol "zbar"; FK_-1 = frac(factor(ZZ (monoid[q,zbar,DegreeRank=>0]))); -- same as FK_1, really but diff variable name FK_0 = frac(factor(ZZ (monoid[q,DegreeRank=>0]))); -promoteFromMap(FK_0,FK_-1); +setupPromote(FK_0,FK_-1); h := getSymbol "h"; ybar := getSymbol "ybar"; FH_-1 = frac(factor(ZZ (monoid[h,ybar]))); -- same as FH_1, really but diff variable name FH_0 = frac(factor(ZZ (monoid[h]))); -promoteFromMap(FH_0,FH_-1); +setupPromote(FH_0,FH_-1); defineFK = n -> ( if not FK#?n then ( z := getSymbol "z"; -- q := getSymbol "q"; FK_n = frac(factor(ZZ (monoid[q,z_1..z_n,DegreeRank=>0,MonomialOrder=>{Weights=>{n+1:1},RevLex}]))); - promoteFromMap(FK_0,FK_n); + setupPromote(FK_0,FK_n); ); FK#n ) @@ -134,7 +122,7 @@ defineFH = n -> ( if not FH#?n then ( y := getSymbol "y"; -- h := getSymbol "h"; FH_n = frac(factor(ZZ (monoid[h,y_1..y_n,MonomialOrder=>{Weights=>{n+1:1},Weights=>{1,n:0},RevLex}]))); - promoteFromMap(FH_0,FH_n); + setupPromote(FH_0,FH_n); ); FH#n ) @@ -149,6 +137,7 @@ defineB = (FF,n,Kth,Equiv) -> ( -- TODO remove FF -if Equiv then elem(k,drop(gens FF,1)) else if Kth then binomial(n,k) else 0); BB := BB0/J; BBs#(n,Kth,Equiv) = BB; + if Equiv then setupPromote(map(BB,if Kth then FK_0 else FH_0,{FF_0})); ); BBs#(n,Kth,Equiv) ) @@ -258,7 +247,6 @@ setupCotangent = cotOpts >> curCotOpts -> dims0 -> ( ); if curCotOpts.Presentation === Borel then ( BB := defineB(FF,n,curCotOpts.Ktheory,curCotOpts.Equivariant); - if curCotOpts.Equivariant then promoteFromMap(FF0,BB,map(BB,FF0,{FF_0})); -- TODO move elsewhere x := getSymbol "x"; -- Chern classes inds := splice apply(d+1, i -> apply(1..dimdiffs#i,j->(j,i))); @@ -278,13 +266,10 @@ setupCotangent = cotOpts >> curCotOpts -> dims0 -> ( R1 := FF monoid new Array from args; f := map(BB,R1,e\inds); AA := R1 / kernel f; - if curCotOpts.Equivariant then promoteFromMap(FF0,AA,map(AA,FF0,{FF_0})); - promoteFromMap(AA,BB,f*map(R1,AA)); + if curCotOpts.Equivariant then setupPromote(map(AA,FF0,{FF_0})); + setupPromote(f*map(R1,AA)); -- reverse transformation - lift(Module,BB,AA) := opts -> (v,b,AA) -> vector apply(entries v,x->lift(x,AA)); - lift(Matrix,BB,AA) := opts -> (m,b,AA) -> matrix applyTable(entries m,x->lift(x,AA)); - lift (BB,AA) := opts -> (b,AA) -> ( - if d == n-1 then return (map(AA,BB,gens AA)) b; -- special case of full flag + setupLift( if #(unique dims) == n+1 then map(AA,BB,gens AA) else b -> ( -- special case of full flag AB := FF monoid (BB.generatorSymbols | AA.generatorSymbols); -- no using it b = sub(b,AB); -- scan(d+1,i->b=expandElem(b,toList(AB_(dims#i)..AB_(dims#(i+1)-1)),toList(AB_(n+dims#i)..AB_(n+dims#(i+1)-1)))); @@ -292,7 +277,7 @@ setupCotangent = cotOpts >> curCotOpts -> dims0 -> ( v := seq -> apply(toList seq, j -> AB_j); scan(d+1,i->b=expandElem(b,v(dims#i..dims#(i+1)-1),v(n+dims#i..n+dims#(i+1)-1))); sub(b,AA) - ); + ),BB,AA); -- tautoClass (ZZ,ZZ,AA) := { Partial => true} >> o -> (j,i,AA) -> if o.Partial then AA_(dims#i+j-1) else e (j,i); zeroSection AA := { Partial => true} >> o -> (cacheValue (zeroSection,o.Partial)) (if o.Partial then AA -> lift(zeroSection(AA,Partial=>false),AA) From 309161ab407ec2f8da58b3f359d163c4599e747a Mon Sep 17 00:00:00 2001 From: pzinn Date: Mon, 7 Oct 2024 16:52:30 +1100 Subject: [PATCH 3/4] minor liftabale changes --- M2/Macaulay2/m2/quotring.m2 | 2 +- M2/Macaulay2/m2/rationals.m2 | 1 - M2/Macaulay2/m2/rings.m2 | 3 ++- M2/Macaulay2/packages/Macaulay2Doc/functions/liftable-doc.m2 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/M2/Macaulay2/m2/quotring.m2 b/M2/Macaulay2/m2/quotring.m2 index ec946cd15e6..793b78b18db 100644 --- a/M2/Macaulay2/m2/quotring.m2 +++ b/M2/Macaulay2/m2/quotring.m2 @@ -281,7 +281,7 @@ char QuotientRing := (stashValue symbol char) ((S) -> ( g := generators gb relns; if g == 0 then return char ring g; m := g_(0,0); - if liftable(m,ZZ) then lift(m,ZZ) else 0)) + lift(m,ZZ,Verify=>false) ?? 0)) singularLocus = method() singularLocus(Ring) := QuotientRing => (R) -> ( diff --git a/M2/Macaulay2/m2/rationals.m2 b/M2/Macaulay2/m2/rationals.m2 index 50b35d00b27..849b048e8ae 100644 --- a/M2/Macaulay2/m2/rationals.m2 +++ b/M2/Macaulay2/m2/rationals.m2 @@ -50,7 +50,6 @@ assert (hash ZZ < hash QQ) lift(QQ,ZZ) := opts -> (r,o) -> if denominator r === 1 then numerator r else if opts.Verify then error "rational number is not an integer" liftable(QQ,ZZ) := (r,o) -> denominator r === 1 lift(QQ,QQ) := opts -> (r,QQ) -> r -liftable(QQ,QQ) := (QQ,QQ) -> true QQ.degreeLength = 0 isUnit Number := x -> x != 0 diff --git a/M2/Macaulay2/m2/rings.m2 b/M2/Macaulay2/m2/rings.m2 index 5c79e2d6812..48f77242c27 100644 --- a/M2/Macaulay2/m2/rings.m2 +++ b/M2/Macaulay2/m2/rings.m2 @@ -90,12 +90,13 @@ toExternalString Ring := toString @@ describe -- promote, lift, liftable, and isConstant ----------------------------------------------------------------------------- +-- TODO rename isLiftable; currently impossible due to conflict with Varieties::isLiftable -- some remnants from lift and promote, version 2 liftable = method(TypicalValue => Boolean, Dispatch => {Thing, Type, Type}) liftable(Number, Number) := liftable(Number, RingElement) := liftable(RingElement, Number) := -liftable(RingElement, RingElement) := (f, R) -> null =!= lift(f, R, Verify => false) +liftable(RingElement, RingElement) := (f, R) -> lookup(lift,class f,R) =!= null and null =!= lift(f, R, Verify => false) isConstant = method(TypicalValue => Boolean) isConstant RingElement := r -> liftable(r, coefficientRing ring r) diff --git a/M2/Macaulay2/packages/Macaulay2Doc/functions/liftable-doc.m2 b/M2/Macaulay2/packages/Macaulay2Doc/functions/liftable-doc.m2 index 377db380fd3..1e8130d6896 100644 --- a/M2/Macaulay2/packages/Macaulay2Doc/functions/liftable-doc.m2 +++ b/M2/Macaulay2/packages/Macaulay2Doc/functions/liftable-doc.m2 @@ -6,7 +6,7 @@ undocumented {(liftable, Number, Number), (liftable, Number, RingElement), (liftable, RingElement, Number), (liftable, RingElement, RingElement), - (liftable, QQ, QQ), (liftable, QQ, ZZ), + (liftable, QQ, ZZ), (lift, Matrix, InexactNumber), (lift,Matrix,InexactNumber'),(lift, Number, InexactNumber), (liftable, Number, InexactNumber), From d1023ef11a20fa5f80c1b97c6790f8b12201419b Mon Sep 17 00:00:00 2001 From: pzinn Date: Mon, 7 Oct 2024 16:53:22 +1100 Subject: [PATCH 4/4] doc and tests for promote, lift update --- M2/Macaulay2/editors/emacs | 2 +- M2/Macaulay2/packages/Macaulay2Doc/doc5.m2 | 8 ++-- .../Macaulay2Doc/functions/setupLift-doc.m2 | 43 +++++++++++++++++++ .../functions/setupPromote-doc.m2 | 29 +++++++++++++ M2/Macaulay2/tests/normal/testpromote.m2 | 23 ++++++++++ 5 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 M2/Macaulay2/packages/Macaulay2Doc/functions/setupLift-doc.m2 create mode 100644 M2/Macaulay2/packages/Macaulay2Doc/functions/setupPromote-doc.m2 diff --git a/M2/Macaulay2/editors/emacs b/M2/Macaulay2/editors/emacs index b71ec9f2798..837cf3d52a7 160000 --- a/M2/Macaulay2/editors/emacs +++ b/M2/Macaulay2/editors/emacs @@ -1 +1 @@ -Subproject commit b71ec9f2798e29f89e539aee41fa0637e190e286 +Subproject commit 837cf3d52a7598e8f680c97aab48ef5f9c07c1fe diff --git a/M2/Macaulay2/packages/Macaulay2Doc/doc5.m2 b/M2/Macaulay2/packages/Macaulay2Doc/doc5.m2 index 740f0ed96eb..163de20ea29 100644 --- a/M2/Macaulay2/packages/Macaulay2Doc/doc5.m2 +++ b/M2/Macaulay2/packages/Macaulay2Doc/doc5.m2 @@ -360,7 +360,7 @@ document { Key => {(eagonNorthcott,Matrix),eagonNorthcott}, document { Key => {(selectVariables,List,PolynomialRing),selectVariables}, Headline => "make a subring of a polynomial ring generated by selected variables", - Usage => "(S,f) = selectVariables(v,R)", + Usage => "(S,F) = selectVariables(v,R)", Inputs => { "v" => {"a sorted list of numbers specifying which variables to select"}, "R" @@ -369,13 +369,13 @@ document { Key => {(selectVariables,List,PolynomialRing),selectVariables}, "S" => PolynomialRing => {"a polynomial ring generated as a subring of R by the variables whose indices occur in the list v, together with the induced monomial ordering" }, - "f" => RingMap => {"the inclusion map from S to R"} + "F" => RingMap => {"the inclusion map from S to R"} }, EXAMPLE lines /// - (S,f) = selectVariables({2,4}, QQ[a..h,Weights=>1..8]); + (S,F) = selectVariables({2,4}, QQ[a..h,Weights=>1..8]); describe S options S - f + F /// } diff --git a/M2/Macaulay2/packages/Macaulay2Doc/functions/setupLift-doc.m2 b/M2/Macaulay2/packages/Macaulay2Doc/functions/setupLift-doc.m2 new file mode 100644 index 00000000000..9d7f4032c41 --- /dev/null +++ b/M2/Macaulay2/packages/Macaulay2Doc/functions/setupLift-doc.m2 @@ -0,0 +1,43 @@ +--- status: DRAFT +--- author(s): PZJ +--- notes: + +undocumented methods setupLift + +doc /// + Key + setupLift + Headline + set up lift from one ring to another + Usage + setupLift (f,R,S) + setupLift g + Inputs + f: Function + R: Ring + S: Ring + g: RingMap + Description + Text + There are two possible ways of implementing @TO "lift"@. In the first one, we use a function: + Example + R=QQ[x] + S=QQ[y] + setupPromote map(R,S,{x^2}) + setupLift(a->sum(listForm a, (e,c)->if odd first e then error "not liftable" else c*y^(first e//2)),R,S) + promote(y^2+2,R) + lift(oo,S) + lift(x,S,Verify=>false) + Text + In the second one, we define a ring map which is a partial inverse to the promotion map: + Example + R=QQ[x,y] + S=R[s] + setupPromote map(R,S,{x+y}) + setupLift map(S,R,{s,0}) + promote(s^3+2*s-1,R) + lift(oo,S) + lift(x,S,Verify=>false) + SeeAlso + setupPromote +/// diff --git a/M2/Macaulay2/packages/Macaulay2Doc/functions/setupPromote-doc.m2 b/M2/Macaulay2/packages/Macaulay2Doc/functions/setupPromote-doc.m2 new file mode 100644 index 00000000000..a4b2a1139b7 --- /dev/null +++ b/M2/Macaulay2/packages/Macaulay2Doc/functions/setupPromote-doc.m2 @@ -0,0 +1,29 @@ +--- status: DRAFT +--- author(s): PZJ +--- notes: + +undocumented methods setupPromote + +doc /// + Key + setupPromote + Headline + automatic promotion from one ring to another + Usage + setupPromote f + Inputs + f: RingMap + Description + Text + After calling @TT "setupPromote"@, any operation that is given an element of the source of @TT "f"@ but + expects an element of the target of @TT "f"@ will automatically @TO "promote"@ it by applying @TT "f"@. + Example + R=QQ[x_1,x_2] + R'=QQ[e_1,e_2,Degrees=>{1,2}] + setupPromote map(R,R',{x_1+x_2,x_1*x_2}) + promote(e_1^2,R) + e_1*x_1 + e_2==x_1*x_2 + SeeAlso + setupLift +/// diff --git a/M2/Macaulay2/tests/normal/testpromote.m2 b/M2/Macaulay2/tests/normal/testpromote.m2 index fcd727de9ba..8d8b5fd821c 100644 --- a/M2/Macaulay2/tests/normal/testpromote.m2 +++ b/M2/Macaulay2/tests/normal/testpromote.m2 @@ -63,6 +63,29 @@ assert( rawLift(raw C, f) == raw C_0 ) --E = frac D --F = GF(2,5) +-- more sophisticated, m2 level, promotes +R=QQ[x]; S=R[y]; +a=promote(1/x,frac S) +assert(lift(a,frac R) == 1/x) +assert(1/x + 1/y == a + 1/y) +assert(y/x == a * y) +assert(promote((frac R)^{1,2},frac S)==(frac S)^{{1,0},{2,0}}) +T=R**QQ[z]; +assert(promote(x_R,T) == x_T) +assert(lift(x_T,R) == x_R) +assert(lift(z,R,Verify=>false) === null) + +R=QQ[x_1,x_2] +R'=QQ[e_1,e_2,Degrees=>{1,2}] +f=map(R,R',{x_1+x_2,x_1*x_2}) +setupPromote f +assert(e_2==x_1*x_2) +assert(map(R,R') === f) + +R=QQ[u]; S=QQ[v]; +setupPromote map(R,S,{u^2},DegreeMap=>i->2*i) +assert(isHomogeneous map(R,S)) +assert(promote(S^{1,2},R)==R^{2,4}) end -- Local Variables: