From dde3a1d416598b5e09ee1bef01bfbc96aaef3bf8 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Mon, 10 Jun 2024 19:05:28 -0400 Subject: [PATCH 01/24] added Semidirect for action with defaults --- BettiCharacters.m2 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index ccd8b18..02a32a2 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -44,6 +44,7 @@ export { "Labels", "numActors", "ringActors", + "Semidirect", "Sub", "symmetricGroupActors", "symmetricGroupTable" @@ -565,7 +566,7 @@ CharacterDecomposition * CharacterTable := Character => character -- optional argument Sub=>true means ring actors are passed -- as one-row matrices of substitutions, Sub=>false means -- ring actors are passed as matrices -action = method(TypicalValue=>Action,Options=>{Sub=>true}) +action = method(TypicalValue=>Action,Options=>{Sub=>true,Semidirect=>(d -> {d},identity)}) -- constructor for action on resolutions -- INPUT: From e9399859fc46e9c1c73d0b6163808f1fa3107c8b Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Mon, 10 Jun 2024 19:16:14 -0400 Subject: [PATCH 02/24] storing orbit and rep functions for actions on modules --- BettiCharacters.m2 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 02a32a2..f136cbc 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -40,6 +40,8 @@ export { "CharacterDecomposition", "CharacterTable", "decomposeCharacter", + "degreeOrbit", + "degreeRepresentative", "inverseRingActors", "Labels", "numActors", @@ -566,6 +568,7 @@ CharacterDecomposition * CharacterTable := Character => character -- optional argument Sub=>true means ring actors are passed -- as one-row matrices of substitutions, Sub=>false means -- ring actors are passed as matrices +-- Semidirect option (added after v2.2) action = method(TypicalValue=>Action,Options=>{Sub=>true,Semidirect=>(d -> {d},identity)}) -- constructor for action on resolutions @@ -834,6 +837,8 @@ action(Module,List,List):=ActionOnGradedModule=>op->(M,l,l0) -> ( (symbol actors) => apply(l0,g->map(F,F,g)), (symbol module) => M', (symbol relations) => image relations M', + (symbol degreeOrbit) => first op.Semidirect, + (symbol degreeRepresentative) => last op.Semidirect, } ) From e246a5d3f13541c7f34aca1efe7217fa0b49069d Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Mon, 10 Jun 2024 19:17:46 -0400 Subject: [PATCH 03/24] passing semidirect option through short constructor --- BettiCharacters.m2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index f136cbc..7fab2aa 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -854,7 +854,7 @@ action(Module,List) := ActionOnGradedModule => op -> (M,l) -> ( ) else ( l0 = toList(#l:(id_(module ambient M))); ); - action(M,l,l0,Sub=>op.Sub) + action(M,l,l0,Sub=>op.Sub,Semidirect=>op.Semidirect) ) -- equality check for actions on graded modules From aed7b91decb2b234c2317b0cb80c9a66a881dee3 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Mon, 10 Jun 2024 19:23:06 -0400 Subject: [PATCH 04/24] semidirect actors for modules --- BettiCharacters.m2 | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 7fab2aa..45f5318 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -868,7 +868,14 @@ actors(ActionOnGradedModule,List) := List => (A,d) -> ( M := A.module; -- get basis in degree d as map of free modules -- how to get this depends on the class of M - b := ambient basis(d,M); + -- (after adding semidirect option single degree d + -- is replaced by orbit of degrees) + orb := A.degreeOrbit; + degList := orb d; + --b := ambient basis(d,M); + -- collect basis for each degree in orbit + -- then join them horizontally + b := fold( (x,y) -> x|y, apply(degList, d -> ambient basis(d,M))) if zero b then return toList(numActors(A):map(source b)); -- function for actors of A in degree d f := A -> apply(ringActors A, A.actors, (g,g0) -> ( @@ -880,7 +887,9 @@ actors(ActionOnGradedModule,List) := List => (A,d) -> ( ) ); -- make cache function from f and run it on A - ((cacheValue (symbol actors,d)) f) A + -- (save actors to representative of degree orbit) + rep := A.degreeRepresentative; + ((cacheValue (symbol actors,rep d)) f) A ) -- returns actors on component of given degree From 4aa6bd03b0e379e7ae072cc40a205b750e60db1e Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Mon, 10 Jun 2024 19:44:19 -0400 Subject: [PATCH 05/24] better caching for semidirect on modules --- BettiCharacters.m2 | 56 +++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 45f5318..1f3b67b 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -865,31 +865,37 @@ ActionOnGradedModule == ActionOnGradedModule := (A,B) -> A === B -- returns actors on component of given multidegree -- the actors are computed and stored actors(ActionOnGradedModule,List) := List => (A,d) -> ( - M := A.module; - -- get basis in degree d as map of free modules - -- how to get this depends on the class of M - -- (after adding semidirect option single degree d - -- is replaced by orbit of degrees) - orb := A.degreeOrbit; - degList := orb d; - --b := ambient basis(d,M); - -- collect basis for each degree in orbit - -- then join them horizontally - b := fold( (x,y) -> x|y, apply(degList, d -> ambient basis(d,M))) - if zero b then return toList(numActors(A):map(source b)); - -- function for actors of A in degree d - f := A -> apply(ringActors A, A.actors, (g,g0) -> ( - --g0*b acts on the basis of the ambient module - --sub(-,g) acts on the polynomial coefficients - --result must be reduced against module relations - --then factored by original basis to get action matrix - (sub(g0*b,g) % A.relations) // b - ) - ); - -- make cache function from f and run it on A - -- (save actors to representative of degree orbit) - rep := A.degreeRepresentative; - ((cacheValue (symbol actors,rep d)) f) A + -- ensure function is computed with rep of degree orbit + -- so that cached results can be pulled up faster + degRep := A.degreeRepresentative d; + if (d != degRep) then ( + actors(A,degRep) + ) + else ( + M := A.module; + -- get basis in degree d as map of free modules + -- how to get this depends on the class of M + -- (after adding semidirect option single degree d + -- is replaced by orbit of degrees) + orb := A.degreeOrbit; + degList := orb d; + --b := ambient basis(d,M); + -- collect basis for each degree in orbit + -- then join them horizontally + b := fold( (x,y) -> x|y, apply(degList, d -> ambient basis(d,M))); + if zero b then return toList(numActors(A):map(source b)); + -- function for actors of A in degree d + f := A -> apply(ringActors A, A.actors, (g,g0) -> ( + --g0*b acts on the basis of the ambient module + --sub(-,g) acts on the polynomial coefficients + --result must be reduced against module relations + --then factored by original basis to get action matrix + (sub(g0*b,g) % A.relations) // b + ) + ); + -- make cache function from f and run it on A + ((cacheValue (symbol actors,d)) f) A + ) ) -- returns actors on component of given degree From 58ec69f620ede72dd95257c30146a7fab9dd4e50 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Tue, 11 Jun 2024 13:06:57 -0400 Subject: [PATCH 06/24] char on modules uses deg rep --- BettiCharacters.m2 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 1f3b67b..32e334c 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -866,7 +866,7 @@ ActionOnGradedModule == ActionOnGradedModule := (A,B) -> A === B -- the actors are computed and stored actors(ActionOnGradedModule,List) := List => (A,d) -> ( -- ensure function is computed with rep of degree orbit - -- so that cached results can be pulled up faster + -- so that cached results can be pulled up directly degRep := A.degreeRepresentative d; if (d != degRep) then ( actors(A,degRep) @@ -903,8 +903,11 @@ actors(ActionOnGradedModule,ZZ) := List => (A,d) -> actors(A,{d}) -- return character of component of given multidegree character(ActionOnGradedModule,List) := Character => (A,d) -> ( + -- ensure function is computed with rep of degree orbit + degRep := A.degreeRepresentative d; F := coefficientRing ring A; - acts := actors(A,d); + -- zero action, return empty character and don't store + acts := actors(A,degRep); if all(acts,zero) then ( return new Character from { cache => new CacheTable, @@ -914,14 +917,14 @@ character(ActionOnGradedModule,List) := Character => (A,d) -> ( (symbol characters) => hashTable {}, }; ); - -- function for character of A in degree d + -- otherwise make function for character of A in degree d f := A -> ( new Character from { cache => new CacheTable, (symbol ring) => F, (symbol degreeLength) => degreeLength ring A, (symbol numActors) => numActors A, - (symbol characters) => hashTable {(0,d) => lift(matrix{apply(acts, trace)},F)}, + (symbol characters) => hashTable {(0,degRep) => lift(matrix{apply(acts, trace)},F)}, } ); -- make cache function from f and run it on A @@ -3545,4 +3548,3 @@ assert( (c1 - c2)^{{5},{6}} == c) /// end - From d150b37f5729ce1688a7542ad0fef83275426d0b Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Tue, 11 Jun 2024 13:10:30 -0400 Subject: [PATCH 07/24] fixed double caching for degree in same orbit --- BettiCharacters.m2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 32e334c..3518031 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -928,7 +928,7 @@ character(ActionOnGradedModule,List) := Character => (A,d) -> ( } ); -- make cache function from f and run it on A - ((cacheValue (symbol character,d)) f) A + ((cacheValue (symbol character,degRep)) f) A ) -- return character of component of given degree From 4a48003ac41a474abbd66af7e54a3d44520e6911 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Tue, 11 Jun 2024 13:25:04 -0400 Subject: [PATCH 08/24] self solution for caching characters of modules --- BettiCharacters.m2 | 80 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 24 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 3518031..01b4e27 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -905,30 +905,32 @@ actors(ActionOnGradedModule,ZZ) := List => (A,d) -> actors(A,{d}) character(ActionOnGradedModule,List) := Character => (A,d) -> ( -- ensure function is computed with rep of degree orbit degRep := A.degreeRepresentative d; - F := coefficientRing ring A; - -- zero action, return empty character and don't store - acts := actors(A,degRep); - if all(acts,zero) then ( - return new Character from { - cache => new CacheTable, - (symbol ring) => F, - (symbol degreeLength) => degreeLength ring A, - (symbol numActors) => numActors A, - (symbol characters) => hashTable {}, - }; - ); - -- otherwise make function for character of A in degree d - f := A -> ( - new Character from { - cache => new CacheTable, - (symbol ring) => F, - (symbol degreeLength) => degreeLength ring A, - (symbol numActors) => numActors A, - (symbol characters) => hashTable {(0,degRep) => lift(matrix{apply(acts, trace)},F)}, - } - ); - -- make cache function from f and run it on A - ((cacheValue (symbol character,degRep)) f) A + -- if not cached, compute + if not A.cache#?(symbol character,degRep) then ( + F := coefficientRing ring A; + -- zero action, return empty character and don't cache + acts := actors(A,degRep); + if all(acts,zero) then ( + return new Character from { + cache => new CacheTable, + (symbol ring) => F, + (symbol degreeLength) => degreeLength ring A, + (symbol numActors) => numActors A, + (symbol characters) => hashTable {}, + }; + ); + -- otherwise make character of A in degree d + print("\n Nonzero character is computed\n"); + A.cache#(symbol character,degRep) = new Character from { + cache => new CacheTable, + (symbol ring) => F, + (symbol degreeLength) => degreeLength ring A, + (symbol numActors) => numActors A, + (symbol characters) => hashTable {(0,degRep) => lift(matrix{apply(acts, trace)},F)}, + }; + ); + -- return cached value + A.cache#(symbol character,degRep) ) -- return character of component of given degree @@ -3548,3 +3550,33 @@ assert( (c1 - c2)^{{5},{6}} == c) /// end + +-- return character of component of given multidegree +character(ActionOnGradedModule,List) := Character => (A,d) -> ( + -- ensure function is computed with rep of degree orbit + degRep := A.degreeRepresentative d; + F := coefficientRing ring A; + -- zero action, return empty character and don't store + acts := actors(A,degRep); + if all(acts,zero) then ( + return new Character from { + cache => new CacheTable, + (symbol ring) => F, + (symbol degreeLength) => degreeLength ring A, + (symbol numActors) => numActors A, + (symbol characters) => hashTable {}, + }; + ); + -- otherwise make function for character of A in degree d + f := A -> ( + new Character from { + cache => new CacheTable, + (symbol ring) => F, + (symbol degreeLength) => degreeLength ring A, + (symbol numActors) => numActors A, + (symbol characters) => hashTable {(0,degRep) => lift(matrix{apply(acts, trace)},F)}, + } + ); + -- make cache function from f and run it on A + ((cacheValue (symbol character,degRep)) f) A + ) From 0b5b4da4964a1d950aae7d17cf263c0add05b7c2 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Tue, 11 Jun 2024 13:25:45 -0400 Subject: [PATCH 09/24] removed test print warning --- BettiCharacters.m2 | 1 - 1 file changed, 1 deletion(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 01b4e27..10f9b44 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -920,7 +920,6 @@ character(ActionOnGradedModule,List) := Character => (A,d) -> ( }; ); -- otherwise make character of A in degree d - print("\n Nonzero character is computed\n"); A.cache#(symbol character,degRep) = new Character from { cache => new CacheTable, (symbol ring) => F, From aa66770dce3388cee208dd280eeb858fd1526e6b Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Tue, 11 Jun 2024 13:27:08 -0400 Subject: [PATCH 10/24] cleared after end area --- BettiCharacters.m2 | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 10f9b44..4b9ffdc 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -3549,33 +3549,3 @@ assert( (c1 - c2)^{{5},{6}} == c) /// end - --- return character of component of given multidegree -character(ActionOnGradedModule,List) := Character => (A,d) -> ( - -- ensure function is computed with rep of degree orbit - degRep := A.degreeRepresentative d; - F := coefficientRing ring A; - -- zero action, return empty character and don't store - acts := actors(A,degRep); - if all(acts,zero) then ( - return new Character from { - cache => new CacheTable, - (symbol ring) => F, - (symbol degreeLength) => degreeLength ring A, - (symbol numActors) => numActors A, - (symbol characters) => hashTable {}, - }; - ); - -- otherwise make function for character of A in degree d - f := A -> ( - new Character from { - cache => new CacheTable, - (symbol ring) => F, - (symbol degreeLength) => degreeLength ring A, - (symbol numActors) => numActors A, - (symbol characters) => hashTable {(0,degRep) => lift(matrix{apply(acts, trace)},F)}, - } - ); - -- make cache function from f and run it on A - ((cacheValue (symbol character,degRep)) f) A - ) From 53d07bf6f6346a669372895963c995766ebeed22 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Tue, 11 Jun 2024 13:38:30 -0400 Subject: [PATCH 11/24] self solution for caching of actors on modules --- BettiCharacters.m2 | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 4b9ffdc..e64e314 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -866,26 +866,21 @@ ActionOnGradedModule == ActionOnGradedModule := (A,B) -> A === B -- the actors are computed and stored actors(ActionOnGradedModule,List) := List => (A,d) -> ( -- ensure function is computed with rep of degree orbit - -- so that cached results can be pulled up directly degRep := A.degreeRepresentative d; - if (d != degRep) then ( - actors(A,degRep) - ) - else ( + -- if not cached, compute + if not A.cache#?(symbol actors,degRep) then ( M := A.module; -- get basis in degree d as map of free modules - -- how to get this depends on the class of M - -- (after adding semidirect option single degree d - -- is replaced by orbit of degrees) - orb := A.degreeOrbit; - degList := orb d; - --b := ambient basis(d,M); - -- collect basis for each degree in orbit - -- then join them horizontally + -- (after semidirect: single degree d replaced by degree orbit) + degList := A.degreeOrbit d; + -- collect bases for degrees in orbit and join horizontally b := fold( (x,y) -> x|y, apply(degList, d -> ambient basis(d,M))); - if zero b then return toList(numActors(A):map(source b)); - -- function for actors of A in degree d - f := A -> apply(ringActors A, A.actors, (g,g0) -> ( + if zero b then ( + A.cache#(symbol actors,degRep) = toList(numActors(A):map(source b)); + ) + else ( + A.cache#(symbol actors,degRep) = + apply(ringActors A, A.actors, (g,g0) -> ( --g0*b acts on the basis of the ambient module --sub(-,g) acts on the polynomial coefficients --result must be reduced against module relations @@ -893,9 +888,10 @@ actors(ActionOnGradedModule,List) := List => (A,d) -> ( (sub(g0*b,g) % A.relations) // b ) ); - -- make cache function from f and run it on A - ((cacheValue (symbol actors,d)) f) A - ) + ); + ); + -- return cached value + A.cache#(symbol actors,degRep) ) -- returns actors on component of given degree From e4bd0b51ccf1a7df25ec0e40f3e5cccce44052d8 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Fri, 14 Jun 2024 10:15:57 -0400 Subject: [PATCH 12/24] added semidirect options to action on complex constructor --- BettiCharacters.m2 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index e64e314..1aac05c 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -631,6 +631,8 @@ action(ChainComplex,List,List,ZZ):=ActionOnComplex=>op->(C,l,l0,i) -> ( (symbol numActors) => #l, (symbol ringActors) => l, (symbol inverseRingActors) => apply(l,inverse), + (symbol degreeOrbit) => first op.Semidirect, + (symbol degreeRepresentative) => last op.Semidirect, } ) From adae0488fcb59713be869a6b40005e1791774a78 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Fri, 14 Jun 2024 10:17:00 -0400 Subject: [PATCH 13/24] passthrough semidirect option for shortcut complex constructor --- BettiCharacters.m2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 1aac05c..d68ada0 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -641,7 +641,7 @@ action(ChainComplex,List,List,ZZ):=ActionOnComplex=>op->(C,l,l0,i) -> ( action(ChainComplex,List) := ActionOnComplex => op -> (C,l) -> ( R := ring C; l0 := toList(#l:(id_(R^1))); - action(C,l,l0,min C,Sub=>op.Sub) + action(C,l,l0,min C,Sub=>op.Sub,Semidirect=>op.Semidirect) ) -- equality check for actions on complexes From a3d558743c464cbaa7473bc83f42f16a6eb05d4d Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Fri, 14 Jun 2024 10:35:21 -0400 Subject: [PATCH 14/24] improved caching for actors on complex --- BettiCharacters.m2 | 47 +++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index d68ada0..88bb81c 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -685,20 +685,41 @@ actors = method(TypicalValue=>List) -- if homological degree is not the one passed by user, -- the actors are computed and stored actors(ActionOnComplex,ZZ) := List => (A,i) -> ( - -- homological degrees where action is already cached - places := apply(keys A.cache, k -> k#1); - C := target A; - if zero(C_i) then return toList(numActors(A):map(C_i)); - if i > max places then ( - -- function for actors of A in hom degree i - f := A -> apply(inverseRingActors A,actors(A,i-1), - -- given a map of free modules C.dd_i : F <-- F', - -- the inverse group action on the ring (as substitution) - -- and the group action on F, computes the group action on F' - (gInv,g0) -> sub(C.dd_i,gInv)\\(g0*C.dd_i) + -- if not cached, compute + if not A.cache#?(symbol actors,i) then ( + -- homological degrees where action is already cached + places := apply(keys A.cache, k -> k#1); + -- get the complex + C := target A; + -- if zero in that hom degree, return zeros + if zero(C_i) then return toList(numActors(A):map(C_i)); + -- if hom degree is to the right of previously computed + if i > max places then ( + A.cache#(symbol actors,i) = + apply(inverseRingActors A,actors(A,i-1), + -- given a map of free modules C.dd_i : F <-- F', + -- the inverse group action on the ring (as substitution) + -- and the group action on F, computes the group action on F' + (gInv,g0) -> sub(C.dd_i,gInv)\\(g0*C.dd_i) + ); + ) + -- if hom degree is to the left of previously computed + else ( + A.cache#(symbol actors,i) = + apply(inverseRingActors A,actors(A,i+1), (gInv,g0) -> + -- given a map of free modules C.dd_i : F <-- F', + -- the inverse group action on the ring (as substitution) + -- and the group action on F', computes the group action on F + -- it is necessary to transpose because we need a left factorization + -- but M2's command // always produces a right factorization + transpose(transpose(C.dd_(i+1))\\transpose(sub(C.dd_(i+1),gInv)*g0)) + ); ); - -- make cache function from f and run it on A - ((cacheValue (symbol actors,i)) f) A + ); + -- return cached value + A.cache#(symbol actors,i) + ) + ) else ( -- function for actors of A in hom degree i f = A -> apply(inverseRingActors A,actors(A,i+1), (gInv,g0) -> From c1fcdbf2ddfa9c8c625eccd70a97f013e63ceada Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Fri, 14 Jun 2024 10:36:02 -0400 Subject: [PATCH 15/24] removed code left behind --- BettiCharacters.m2 | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 88bb81c..8781083 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -720,21 +720,6 @@ actors(ActionOnComplex,ZZ) := List => (A,i) -> ( A.cache#(symbol actors,i) ) - ) else ( - -- function for actors of A in hom degree i - f = A -> apply(inverseRingActors A,actors(A,i+1), (gInv,g0) -> - -- given a map of free modules C.dd_i : F <-- F', - -- the inverse group action on the ring (as substitution) - -- and the group action on F', computes the group action on F - -- it is necessary to transpose because we need a left factorization - -- but M2's command // always produces a right factorization - transpose(transpose(C.dd_(i+1))\\transpose(sub(C.dd_(i+1),gInv)*g0)) - ); - -- make cache function from f and run it on A - ((cacheValue (symbol actors,i)) f) A - ) - ) - -- return the character of one free module of a resolution -- in a given homological degree character(ActionOnComplex,ZZ) := Character => (A,i) -> ( From 4c319e97e5ca919b22201d418dde215f35d8b032 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Fri, 14 Jun 2024 10:55:26 -0400 Subject: [PATCH 16/24] fixed potential issue with reading from cache of action on complex --- BettiCharacters.m2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 8781083..c6c6304 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -688,7 +688,7 @@ actors(ActionOnComplex,ZZ) := List => (A,i) -> ( -- if not cached, compute if not A.cache#?(symbol actors,i) then ( -- homological degrees where action is already cached - places := apply(keys A.cache, k -> k#1); + places := apply(select(keys A.cache, k -> k#0 == symbol actors), k -> k#1); -- get the complex C := target A; -- if zero in that hom degree, return zeros From 52686c495efd646c79ce8a07cb67de66f8f0b008 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Fri, 14 Jun 2024 11:22:02 -0400 Subject: [PATCH 17/24] improved caching for characters of actions on complexes --- BettiCharacters.m2 | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index c6c6304..42cb97f 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -723,19 +723,19 @@ actors(ActionOnComplex,ZZ) := List => (A,i) -> ( -- return the character of one free module of a resolution -- in a given homological degree character(ActionOnComplex,ZZ) := Character => (A,i) -> ( - F := coefficientRing ring A; - -- if complex is zero in hom degree i, return empty character - if zero (target A)_i then ( - return new Character from { - cache => new CacheTable, - (symbol ring) => F, - (symbol degreeLength) => degreeLength ring A, - (symbol numActors) => numActors A, - (symbol characters) => hashTable {}, - }; - ); - -- function for character of A in hom degree i - f := A -> ( + -- if not cached, compute + if not A.cache#?(symbol character,i) then ( + F := coefficientRing ring A; + -- if complex is zero in hom degree i, return empty character, don't cache + if zero (target A)_i then ( + return new Character from { + cache => new CacheTable, + (symbol ring) => F, + (symbol degreeLength) => degreeLength ring A, + (symbol numActors) => numActors A, + (symbol characters) => hashTable {}, + }; + ); -- separate degrees of i-th free module degs := hashTable apply(unique degrees (target A)_i, d -> (d,positions(degrees (target A)_i,i->i==d)) @@ -746,16 +746,17 @@ character(ActionOnComplex,ZZ) := Character => (A,i) -> ( lift(matrix{apply(actors(A,i), g -> trace g_indx^indx)},F) ) ); - new Character from { + -- cache character + A.cache#(symbol character,i) = new Character from { cache => new CacheTable, (symbol ring) => F, (symbol degreeLength) => degreeLength ring A, (symbol numActors) => numActors A, (symbol characters) => H, - } + }; ); - -- make cache function from f and run it on A - ((cacheValue (symbol character,i)) f) A + -- return cached value + A.cache#(symbol character,i) ) -- return characters of all free modules in a resolution From 0c3c8ec5dd0edb073de0edfa788e5ef2d4e50508 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Fri, 14 Jun 2024 12:12:18 -0400 Subject: [PATCH 18/24] nicer degree separation for trace of action on complexes --- BettiCharacters.m2 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 42cb97f..010c0c4 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -736,10 +736,10 @@ character(ActionOnComplex,ZZ) := Character => (A,i) -> ( (symbol characters) => hashTable {}, }; ); - -- separate degrees of i-th free module - degs := hashTable apply(unique degrees (target A)_i, d -> - (d,positions(degrees (target A)_i,i->i==d)) - ); + -- record position of degrees of i-th free module + -- based on their unique degree orbit rep + degs := partition(j -> A.degreeRepresentative degree ((target A)_i)_j, + toList(0..rank((target A)_i)-1)); -- create raw character from actors H := applyPairs(degs, (d,indx) -> ((i,d), From ecdab37f2826b786720109d2cc0c0e677a7ca3cb Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Fri, 14 Jun 2024 14:41:52 -0400 Subject: [PATCH 19/24] basis over degree orbit is now sorted --- BettiCharacters.m2 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 010c0c4..4cb2a23 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -883,7 +883,12 @@ actors(ActionOnGradedModule,List) := List => (A,d) -> ( -- (after semidirect: single degree d replaced by degree orbit) degList := A.degreeOrbit d; -- collect bases for degrees in orbit and join horizontally - b := fold( (x,y) -> x|y, apply(degList, d -> ambient basis(d,M))); + b := rsort fold( (x,y) -> x|y, apply(degList, d -> ambient basis(d,M))); + -- the basis command returns a matrix with columns in decreasing order + -- joining basis from different degrees may break this order + -- the rsort at the beginning recovers M2's default order + -- this sorting was made necessary after introducing semidirect options + -- actors matrix would be useless without out as it may not match basis if zero b then ( A.cache#(symbol actors,degRep) = toList(numActors(A):map(source b)); ) From 9d5e1d4689fd1fb69d9e8e6da657512075e93c5a Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Fri, 14 Jun 2024 15:38:27 -0400 Subject: [PATCH 20/24] changed \\ to // --- BettiCharacters.m2 | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 4cb2a23..d63e652 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -602,7 +602,8 @@ action(ChainComplex,List,List,ZZ):=ActionOnComplex=>op->(C,l,l0,i) -> ( error "action: expected ring actor matrix to be a one-row substitution matrix"; ); --convert variable substitutions to matrices - l=apply(l,g->(vars R)\\lift(g,R)); + --l=apply(l,g->(vars R)\\lift(g,R)); --deprecated + l=apply(l,g->lift(g,R)//(vars R)); ) else ( --if ring actors are matrices they must be square if not all(l,g->numRows(g)==n) then ( @@ -700,7 +701,8 @@ actors(ActionOnComplex,ZZ) := List => (A,i) -> ( -- given a map of free modules C.dd_i : F <-- F', -- the inverse group action on the ring (as substitution) -- and the group action on F, computes the group action on F' - (gInv,g0) -> sub(C.dd_i,gInv)\\(g0*C.dd_i) + --(gInv,g0) -> sub(C.dd_i,gInv)\\(g0*C.dd_i) --deprecated + (gInv,g0) -> (g0*C.dd_i)//sub(C.dd_i,gInv) ); ) -- if hom degree is to the left of previously computed @@ -712,7 +714,8 @@ actors(ActionOnComplex,ZZ) := List => (A,i) -> ( -- and the group action on F', computes the group action on F -- it is necessary to transpose because we need a left factorization -- but M2's command // always produces a right factorization - transpose(transpose(C.dd_(i+1))\\transpose(sub(C.dd_(i+1),gInv)*g0)) + --transpose(transpose(C.dd_(i+1))\\transpose(sub(C.dd_(i+1),gInv)*g0)) --deprecated + transpose(transpose(sub(C.dd_(i+1),gInv)*g0)//transpose(C.dd_(i+1))) ); ); ); @@ -805,7 +808,8 @@ action(Module,List,List):=ActionOnGradedModule=>op->(M,l,l0) -> ( error "action: expected ring actor matrix to be a one-row substitution matrix"; ); --convert variable substitutions to matrices - l=apply(l,g->(vars R)\\lift(g,R)); + --l=apply(l,g->(vars R)\\lift(g,R)); --deprecated + l=apply(l,g->lift(g,R)//(vars R)); ) else ( --if ring actors are matrices they must be square if not all(l,g->numRows(g)==n) then ( From c7594ba591b295bdccfff940ebf62d1a3ebeb9ea Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Fri, 14 Jun 2024 15:48:56 -0400 Subject: [PATCH 21/24] version bump to 2.3 --- BettiCharacters.m2 | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index d63e652..e19f324 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -1,5 +1,5 @@ -------------------------------------------------------------------------------- --- Copyright 2021-2023 Federico Galetto +-- Copyright 2021-2024 Federico Galetto -- -- This program is free software: you can redistribute it and/or modify it under -- the terms of the GNU General Public License as published by the Free Software @@ -18,8 +18,8 @@ newPackage( "BettiCharacters", - Version => "2.2", - Date => "July 22, 2023", + Version => "2.3", + Date => "June 14, 2024", AuxiliaryFiles => false, Authors => {{Name => "Federico Galetto", Email => "galetto.federico@gmail.com", @@ -1254,7 +1254,10 @@ Node (BOLD "2.2: ", "Characters and character tables are now defined over fields (instead of polynomial rings). This version also introduces new character operations - and $\\TeX$ printing for characters and character tables.") + and $\\TeX$ printing for characters and character tables."), + (BOLD "2.3: ", "New option for the action of a semidirect + product of a finite group acting on a torus. + Improved caching and removed calls to deprecated functions.") }@ Subnodes :Defining and computing actions From 129a5ca52c34d527d482e3b9b80b2c490b262ce4 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Sat, 15 Jun 2024 11:35:37 -0400 Subject: [PATCH 22/24] docs and test for Semidirect --- BettiCharacters.m2 | 110 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index e19f324..bae9d67 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -1871,6 +1871,7 @@ Node Action (action,ChainComplex,List,List,ZZ) (action,Module,List,List) + Semidirect Sub Node @@ -3144,6 +3145,90 @@ Node action +Node + Key + Semidirect + [action, Semidirect] + degreeOrbit + degreeRepresentative + Headline + action of semidirect product with torus + Description + Text + Consider a polynomial ring $R$ and an $R$-module $M$ + with a $\mathbb{Z}^r$-grading corresponding to the action of a + torus $T$. Let $G$ be a finite group acting on $R$ + and $M$ in a way that is compatible with multiplication. + Then the semidirect product $T\rtimes G$ acts on $R$ and $M$. + For a given degree $d \in \mathbb{Z}^r$, the graded + components $R_d$ and $M_d$ need not be representations of $G$. + However, if $\mathcal{O}$ is the orbit of $d$ under the action + of $G$ on the character group $\mathbb{Z}^r$ of $T$, then + $\bigoplus_{d\in\mathcal{O}} R_d$ and + $\bigoplus_{d\in\mathcal{O}} M_d$ are representations of + $T\rtimes G$. Starting with version 2.3, the + @TO "BettiCharacters"@ package allows one to compute the + characters of $G$ on these representations using the + @TO "Semidirect"@ option of the @TO "action"@ method, + and specifying a single degree $d$ in the orbit $\mathcal{O}$. + + The value of the @TO "Semidirect"@ option is a list of two + functions. The first function takes as input a degree $d$ + and returns its orbit $\mathcal{O}$ as output. This function is + stored in the action under the key @TO "degreeOrbit"@. The second + function takes as input a degree $d$ and returns a user-chosen + representative $d'$ from the orbit $\mathcal{O}$ of $d$. This + function is stored in the action under the key @TO "degreeRepresentative"@. + When computing the actors or the characters of $G$ on + $\bigoplus_{d\in\mathcal{O}} R_d$ and $\bigoplus_{d\in\mathcal{O}} M_d$, + the values are stored only for the chosen representative $d'$, + and computing the actors or characters of $G$ for another degree + in the same orbit produces the same result as for $d'$. + By default, both functions are set to the identity, which + corresponds to the action of the direct product $T\times G$. + + A typical use case is that of the symmetric group $\mathfrak{S}_n$ + acting on a fine graded polynomial ring $\Bbbk [x_1,\dots,x_n]$ by + permuting the variables. The symmetric group also acts by + permuting the entries of the degrees $d \in \mathbb{Z}^n$. + In this case, the orbit of $d$ consists of all its permutations, + which can be obtained with the function @TO "uniquePermutations"@. + As a representative of this orbit we choose the unique degree $d$ + whose entries are sorted in nonincreasing order from left to right; + this can be obtained with the function @TO "rsort"@. + Example + R = QQ[x_1..x_4,Degrees=>{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}] + S4 = symmetricGroupActors R + A = action(R,S4,Semidirect=>{uniquePermutations,rsort}) + actors(A,{2,0,0,0}) + character(A,{2,0,0,0}) + actors(A,{1,1,0,0}) + character(A,{1,1,0,0}) + oo == character(A,{1,0,1,0}) + I = ideal apply(subsets(gens R,3),product) + ideal apply(gens R, y -> y^5) + M = R/I + B = action(M,S4,Semidirect=>{uniquePermutations,rsort}) + actors(B,{2,1,0,0}) + character(B,{2,1,0,0}) + Text + Similarly, the @TO "Semidirect"@ option can be used + for actions on complexes and for computing Betti characters + of a module. + Example + RI = res I + C = action(RI,S4,Semidirect=>{uniquePermutations,rsort}) + character C + Caveat + Characters of actions with the semidirect option are indexed + by user-chosen representatives of degree orbits as explained + above. However, the duals of these characters and characters + constructed directly by the user may not follow this choice + of representatives. Applying further operations to such + characters may result in a mix of different orbit + representatives for the same degree orbits. + SeeAlso + action + Node Key Sub @@ -3565,4 +3650,29 @@ c = character(R,3, hashTable { assert( (c1 - c2)^{{5},{6}} == c) /// +-- Test 6 (fine grading, semidirect product with symmetric group) +TEST /// +clearAll +R = QQ[x,y,z,Degrees=>{{1,0,0},{0,1,0},{0,0,1}}] +I = ideal(x*y,x*z,y*z) +RI = res I +S3 = symmetricGroupActors R +A1 = action(RI,S3,Semidirect=>{uniquePermutations,rsort}) +c1 = character(A1) +d1 = character(R,3, hashTable { + (0,{0,0,0}) => matrix{{1,1,1}}, + (1,{1,1,0}) => matrix{{0,1,3}}, + (2,{1,1,1}) => matrix{{-1,0,2}} + }) +assert( c1 == d1) +A2 = action(R,S3,Semidirect=>{uniquePermutations,rsort}) +c2 = character(A2,{0,3,0}) ++ character(A2,{1,0,2}) ++ character(A2,{1,1,1}) +d2 = character(R,3, hashTable { + (0,{3,0,0}) => matrix{{0,1,3}}, + (0,{2,1,0}) => matrix{{0,0,6}}, + (0,{1,1,1}) => matrix{{1,1,1}} + }) +assert( c2 == d2) +/// + end From 77b3b4604d9fee146bfaa09591649371df95998c Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Sat, 15 Jun 2024 14:02:34 -0400 Subject: [PATCH 23/24] example 5 from Murai-Raicu --- BettiCharacters.m2 | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index bae9d67..510c67d 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -1278,6 +1278,7 @@ Node "BettiCharacters Example 2" "BettiCharacters Example 3" "BettiCharacters Example 4" + "BettiCharacters Example 5" Node Key @@ -1608,6 +1609,63 @@ Node character(B,{1,2}) +Node + Key + "BettiCharacters Example 5" + Headline + semidirect product of torus and symmetric group + Description + Text + We present the example in the introduction of + @HREF("https://doi.org/10.1112/jlms.12551", + "S. Murai, C. Raicu - An equivariant Hochster’s formula for $\\mathfrak{S}_n$-invariant monomial ideals")@. + + Consider the ideal $I$ in three variables generated by + monomials whose exponent vectors are permutations of + $(4,1,1)$ or $(5,2,0)$. This ideal is clearly stable + under the permutation action of $\mathfrak{S}_3$. + Moreover, $I$ is compatible with the fine grading + on $R = \Bbbk [x_1,x_2,x_3]$ given by $\deg (x_i) = e_i + \in \mathbb{Z}^3$. We compute a minimal free resolution of + $R/I$ and show its Betti diagram. + Example + R = QQ[x_1..x_3,Degrees=>{{1,0,0},{0,1,0},{0,0,1}}] + I = ideal(x_1^4*x_2*x_3,x_1*x_2^4*x_3,x_1*x_2*x_3^4, + x_1^5*x_2^2,x_1^5*x_3^2,x_1^2*x_2^5,x_1^2*x_3^5,x_2^5*x_3^2,x_2^2*x_3^5) + RI = res I + betti RI + Text + Next, we set up the action of the semidirect product + $(\Bbbk^\times)^3 \rtimes \mathfrak{S}_3$ where + $\mathfrak{S}_3$ acts on $(\Bbbk^\times)^3$ by + permuting entries. This results in $\mathfrak{S}_3$ + acting on the grading group $\mathbb{Z}^3$ (the character + group of $(\Bbbk^\times)^3$) by permuting the + entries of the degree vectors. Thus, the orbit of a + degree $d\in \mathbb{Z}^3$ consists of all permutations + of $d$; we fix the nonincreasing permutation of $d$ as + the distinguished representative of this orbit. + See @TO "Semidirect"@ for details. + Example + S3 = symmetricGroupActors(R) + A = action(RI,S3,Semidirect=>{uniquePermutations,rsort}) + c = character A + Text + To match the description of the paper, which resolves the + ideal $I$ instead of the quotient $R/I$, we remove + the component in homological degree 0, then shift the + complex to the left. Finally, the resulting character is + decomposed against the character table of $\mathfrak{S}_3$. + Example + c = (c - character(R,3,hashTable{(0,{0,0,0})=>matrix{{1,1,1}}}))[1] + T = symmetricGroupTable(3,QQ) + decomposeCharacter(c,T) + Text + The irreducible representations found above match + our expectations as can be verified by + applying Pieri's rule to the description + in Example 1.4 of Murai and Raicu's paper. + Node Key Action From 8fb7a195356ea7ee6dc828ee8fbc941d021b0b53 Mon Sep 17 00:00:00 2001 From: Federico Galetto Date: Sat, 15 Jun 2024 14:13:09 -0400 Subject: [PATCH 24/24] simplified example for Semidirect option --- BettiCharacters.m2 | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/BettiCharacters.m2 b/BettiCharacters.m2 index 510c67d..b77e24c 100644 --- a/BettiCharacters.m2 +++ b/BettiCharacters.m2 @@ -3254,19 +3254,26 @@ Node As a representative of this orbit we choose the unique degree $d$ whose entries are sorted in nonincreasing order from left to right; this can be obtained with the function @TO "rsort"@. + + We illustrate this use case. First, consider the action + on the polynomial ring. Example R = QQ[x_1..x_4,Degrees=>{{1,0,0,0},{0,1,0,0},{0,0,1,0},{0,0,0,1}}] S4 = symmetricGroupActors R A = action(R,S4,Semidirect=>{uniquePermutations,rsort}) - actors(A,{2,0,0,0}) - character(A,{2,0,0,0}) - actors(A,{1,1,0,0}) - character(A,{1,1,0,0}) - oo == character(A,{1,0,1,0}) - I = ideal apply(subsets(gens R,3),product) + ideal apply(gens R, y -> y^5) + actors(A,{1,1,1,0}) + character(A,{1,1,1,0}) + Text + As expected, the character is the same if we compute it + for a different degree in the same orbit. + Example + oo == character(A,{1,0,1,1}) + Text + Next, consider the quotient by an ideal stable under the group action. + Example + I = ideal apply(subsets(gens R,3),product) M = R/I B = action(M,S4,Semidirect=>{uniquePermutations,rsort}) - actors(B,{2,1,0,0}) character(B,{2,1,0,0}) Text Similarly, the @TO "Semidirect"@ option can be used