diff --git a/M2/Macaulay2/m2/matrix2.m2 b/M2/Macaulay2/m2/matrix2.m2 index 01bcad74f35..a51ccbcbf79 100644 --- a/M2/Macaulay2/m2/matrix2.m2 +++ b/M2/Macaulay2/m2/matrix2.m2 @@ -396,6 +396,7 @@ Matrix \\ Matrix := Matrix => (g, f) -> quotient'(f, g) quotient(Matrix, Matrix) := Matrix => opts -> (f, g) -> ( -- given f: A-->C and g: B-->C, then find (f//g): A-->B such that g o (f//g) + r = f if target f != target g then error "quotient: expected maps with the same target"; + if f == 0 then return map(source g, source f, 0); c := runHooks((quotient, Matrix, Matrix), (opts, f, g), Strategy => opts.Strategy); if c =!= null then c else error "quotient: no method implemented for this type of input") @@ -408,11 +409,19 @@ addHook((quotient, Matrix, Matrix), Strategy => Default, MinimalGenerators => opts.MinimalGenerators }; map(source g, source f, homomorphism(homomorphism'(f, opts) // Hom(source f, g, opts))))) --- FIXME: this is still causing unreasonable slow downs, e.g. for (large m) // (scalar) -addHook((quotient, Matrix, Matrix), Strategy => "Reflexive", (opts, f, g) -> if f == 0 or isFreeModule source f then ( - L := source f; -- result may not be well-defined if L is not free +addHook((quotient, Matrix, Matrix), Strategy => "Reflexive", (opts, f, g) -> ( + L := source f; M := target f; N := source g; + -- TODO: should this be a separate strategy? + if not isFreeModule L then return ( + -- result may not be well-defined if L is not free, + -- unless the composition h * syz p is zero + p := coverMap L; + h := quotient(f * p, g, Strategy => "Reflexive"); + -- TODO: does h * gens ker p != 0 suffice? + if h * inducedMap(source p, kernel p) == 0 then map(N, L, h)); + -- if M.?generators then ( M = cokernel presentation M; -- this doesn't change the cover ); diff --git a/M2/Macaulay2/packages/Macaulay2Doc/functions/quotient-remainder-doc.m2 b/M2/Macaulay2/packages/Macaulay2Doc/functions/quotient-remainder-doc.m2 index 1f44bec5d5c..1126dd757e9 100644 --- a/M2/Macaulay2/packages/Macaulay2Doc/functions/quotient-remainder-doc.m2 +++ b/M2/Macaulay2/packages/Macaulay2Doc/functions/quotient-remainder-doc.m2 @@ -152,8 +152,8 @@ Node reduction of @TT "f"@ modulo a Gröbner basis for the image of @TT "dual g"@. See @TO quotient@ for the dual notion. - If the remainder @TT "f - h*g"@ is zero, then the quotient @TT "g\\f"@ - satisfies the equation @TT "f === (g\\f) * g"@. Otherwise, the equation + If the remainder @TT "f - h*g"@ is zero, then the quotient @TT "g\\\\f"@ + satisfies the equation @TT "f === (g\\\\f) * g"@. Otherwise, the equation @TT "h * g + r === f"@ will hold, where @TT "r"@ is the map provided by @TO remainder'@. Example diff --git a/M2/Macaulay2/packages/Macaulay2Doc/ov_system.m2 b/M2/Macaulay2/packages/Macaulay2Doc/ov_system.m2 index 34bd142e82d..d737a7fa59c 100644 --- a/M2/Macaulay2/packages/Macaulay2Doc/ov_system.m2 +++ b/M2/Macaulay2/packages/Macaulay2Doc/ov_system.m2 @@ -1870,7 +1870,12 @@ document { Key => "loadedFiles", PARA { "After each source file is successfully loaded, the full path to the file is stored in the hash table ", TO "loadedFiles", ". It is stored as the value, with the corresponding key being a small integer, consecutively assigned, starting at 0." }, - EXAMPLE "peek loadedFiles"} + EXAMPLE lines /// + loadedFiles#0 + #loadedFiles + ///, + --SeeAlso => { "filesLoaded" }, + } document { Key => "homeDirectory", Headline => "the home directory of the user", diff --git a/M2/Macaulay2/packages/SpectralSequences.m2 b/M2/Macaulay2/packages/SpectralSequences.m2 index 5da4de6ece1..06bb5436a45 100644 --- a/M2/Macaulay2/packages/SpectralSequences.m2 +++ b/M2/Macaulay2/packages/SpectralSequences.m2 @@ -18,8 +18,8 @@ newPackage( "SpectralSequences", -- AuxiliaryFiles => true, - Version => "1.0", - Date => "20 September 2016", + Version => "1.1", + Date => "8 July 2025", Authors => { { Name => "David Berlekamp", @@ -47,8 +47,7 @@ newPackage( HomePage => "http://math.berkeley.edu/~thanh"}}, Headline => "spectral sequences", Keywords => {"Homological Algebra"}, - PackageImports => {"Truncations"}, - PackageExports => {"SimplicialComplexes", "ChainComplexExtras", "PushForward"} + PackageExports => {"SimplicialComplexes", "Complexes", "PushForward"} ) export { @@ -91,148 +90,25 @@ ReverseDictionary = value Core#"private dictionary"#"ReverseDictionary" -------------------------------------------------------------------------------- -- CODE -------------------------------------------------------------------------------- ------------------------------------------------------------------------------------- --- ChainComplexExtraExtras -- Several people have worked on this portion of the code --------------------------------------------------------------------------------------- +-- TODO: move these to Complexes --- since things are mutable we don't want to cache spots spots = method() +spots Complex := List => C -> sort keys C.module -spots ChainComplex := List => ( - C -> sort select(keys complete C,i -> class i === ZZ)) - -max ChainComplex := K -> max spots K -min ChainComplex := K -> min spots K - -support ChainComplex := List => ( - C -> sort select (spots C, i -> C_i != 0)) - - --- Computes the graded pieces of the total complex of a Hom double complex --- (just as a graded module, so no maps!) -Hom (GradedModule, GradedModule) := GradedModule => opts -> (C, D) -> ( - R := C.ring; if R =!= D.ring then error "expected graded modules over the same ring"; - (c,d) := (spots C, spots D); - pairs := new MutableHashTable; - scan(c, i -> scan(d, j -> ( - k := j-i; - p := if not pairs#?k then pairs#k = new MutableHashTable else pairs#k; - p#(i,j) = 1;))); - scan(keys pairs, k -> pairs#k = sort keys pairs#k); - E := new GradedModule; - E.ring = R; - scan(keys pairs, k-> ( - p := pairs#k; - E#k = directSum(apply(p, v -> v => Hom(C_(v#0), D_(v#1), opts)));)); - E) - - - -isWellDefined ChainComplexMap := Boolean => f -> ( - (F,G):= (source f, target f); - all(drop(spots F,1), i -> G.dd_i * f#i == f#(i-1) * F.dd_i)) - --- Computes the total complex of the Hom double complex of two chain complexes --- This code is different from that in ChainComplexExtras. We need this version --- so that the indices are cached. -Hom (ChainComplex, ChainComplex) := ChainComplex => opts -> (C, D) -> ( - if C.ring =!= D.ring then error "expected chain complexes over the same ring"; - hom := lookup(Hom, GradedModule, GradedModule); - E := chainComplex (hom opts)(C, D); - scan(spots E, i -> if E#?i and E#?(i-1) then E.dd#i = - map(E#(i-1), E#i, - matrix table( - E#(i-1).cache.indices, E#i.cache.indices, - (j,k) -> map(E#(i-1).cache.components#(E#(i-1).cache.indexComponents#j), - (E#i).cache.components#((E#i).cache.indexComponents#k), - if j#0 === k#0 and j#1 === k#1-1 then (-1)^(k#0)*Hom(C_(k#0), D.dd_(k#1), opts) - else if j#0 === k#0 + 1 and j#1 === k#1 then Hom(C.dd_(j#0), D_(k#1), opts) - else 0)))); - E -) - -Hom (ChainComplex, ChainComplexMap) := ChainComplexMap => opts -> (C, f) -> ( - (F, G) := (Hom(C, source f, opts), Hom(C, target f, opts)); - map(G,F, i -> map(G_i,F_i, matrix table( G_i.cache.indices,F_i.cache.indices, - (j,k) -> map(G#i.cache.components#(G#i.cache.indexComponents#j), - F#i.cache.components#(F#i.cache.indexComponents#k), - if j === k then Hom(C_(j#0), f_(j#1), opts) - else 0))))) - -Hom (ChainComplexMap, ChainComplex) := ChainComplexMap => opts -> (f, C) -> ( - (F, G) := (Hom(target f, C, opts), Hom(source f, C, opts)); - map(G,F, i -> map (G_i,F_i, matrix table(G_i.cache.indices,F_i.cache.indices, - (j,k) -> map(G#i.cache.components#(G#i.cache.indexComponents#j), - F#i.cache.components#(F#i.cache.indexComponents#k), - if j === k then Hom(f_(j#0), C_(j#1), opts) - else 0))))) - -ChainComplexMap ** ChainComplex := ChainComplexMap => (f,C) -> ( - (F,G) := ((source f) ** C, (target f) ** C); - map(G,F, i -> map (G_i,F_i, matrix table(G_i.cache.indices,F_i.cache.indices, - (j,k) -> map(G#i.cache.components#(G#i.cache.indexComponents#j), - F#i.cache.components#(F#i.cache.indexComponents#k), - if j === k then f_(j#0) ** C_(j#1) - else 0))))) - -ChainComplex ** ChainComplexMap := ChainComplexMap => (C,f) -> ( - (F,G) := (C ** source f, C ** target f); - map(G,F, i -> map (G_i,F_i, matrix table(G_i.cache.indices,F_i.cache.indices, - (j,k) -> map(G#i.cache.components#(G#i.cache.indexComponents#j), - F#i.cache.components#(F#i.cache.indexComponents#k), - if j === k then C_(j#0) ** f_(j#1) - else 0))))) - --- truncate a chain complex at a given homological degree -truncate(ChainComplex,ZZ):= {} >> o -> (C,q) ->( - if q == 0 then return C - else ( - m := min support C; - n := max support C; - l := length C; - if q < -l or q > l then return image(0*id_C) - else K:=new ChainComplex; - K.ring=C.ring; - if q < 0 then for i from min C + 1 to max C do ( - if i <= n + q then K.dd_i = C.dd_i - else if i-1 > n + q then K.dd_i = inducedMap(0*C_(i-1),0*C_i,C.dd_i) - else K.dd_i = inducedMap(C_(i-1), 0*C_i, C.dd_i) ) - else for i from min C+1 to max C do ( - if i-1 >= q + m then K.dd_i = C.dd_i - else if i < q + m then K.dd_i = inducedMap(0*C_(i-1),0*C_i,C.dd_i) - else K.dd_i = map(0*C_(i-1), C_i, 0*C.dd_i) )); - K) - +support Complex := List => C -> select(spots C, i -> C_i != 0) -- the following relies on the pushFwd method from the package "PushForward.m2" - -pushFwd(RingMap,ChainComplex):=o->(f,C) -> -( pushFwdC := chainComplex(source f); - maps := apply(spots C, i-> (i,pushFwd(f,C.dd_i))); - for i from min C to max C do ( - pushFwdC.dd_(maps#i_0) = maps#i_1 - ); - pushFwdC - ) - - --- New method for tensor that returns the tensor product of a complex via a ring map -tensor(RingMap, ChainComplex) := ChainComplex => {} >> opts -> (f,C) -> ( - k := min C; - D := chainComplex( - if even(k) then apply( - drop(select(keys complete C, - i -> instance(i,ZZ)),1), - j -> f ** C.dd_j) - else apply( - drop(select(keys complete C, - i -> instance(i,ZZ)),1), - j -> (-1) * (f ** C.dd_j))); - D[-k] - ) - - ----------------------------------------------------------------------------------- +pushFwd(RingMap, Complex) := o -> (f, C) -> ( + (lo, hi) := concentration C; + if lo == hi + then complex(pushFwd(f, C_lo, o), Base => lo) + else complex applyValues(C.dd.map, + m -> pushFwd(f, m, o))) + +naiveTruncation(Complex, ZZ) := Complex => (C, n) -> ( + (lo, hi) := concentration C; + if n > 0 then naiveTruncation(C, (lo + n, infinity)) else + if n < 0 then naiveTruncation(C, (-infinity, hi + n)) else C) ------------------------------------------------------------------------------------- -- filtered complexes @@ -251,19 +127,19 @@ support FilteredComplex := List => ( FilteredComplex _ InfiniteNumber := -FilteredComplex _ ZZ := ChainComplex => (K,p) -> ( +FilteredComplex _ ZZ := Complex => (K,p) -> ( if K#?p then K#p else if p < min K then K#(min K) else if p > max K then K#(max K) ) FilteredComplex ^ InfiniteNumber := -FilteredComplex ^ ZZ := ChainComplex => (K,p) -> K_(-p) +FilteredComplex ^ ZZ := Complex => (K,p) -> K_(-p) -chainComplex FilteredComplex := ChainComplex => K -> K_infinity +complex FilteredComplex := Complex => {} >> o -> K -> K_infinity -- Returns the inclusion map from the pth subcomplex to the top -inducedMap (FilteredComplex, ZZ) := ChainComplexMap => opts -> (K,p) -> ( +inducedMap (FilteredComplex, ZZ) := ComplexMap => opts -> (K,p) -> ( if not K.cache#?inducedMaps then K.cache.inducedMaps = new MutableHashTable; if not K.cache.inducedMaps#?p then K.cache.inducedMaps#p = inducedMap(K_infinity, K_p); K.cache.inducedMaps#p) @@ -289,38 +165,41 @@ filteredComplex = method(Options => { ReducedHomology => true}) filteredComplex(List) := FilteredComplex => opts -> L -> ( - local maps; - local C; - if #L === 0 - then error "expected at least one chain complex map or simplicial complex"; - if all(#L, p -> class L#p === SimplicialComplex) then ( - kk := coefficientRing L#0; - if opts.ReducedHomology == true then ( - C = chainComplex complex L#0; -- By default the ambient simplicial complex is the first element of the list - maps = apply(#L-1, p -> map(C, chainComplex complex L#(p+1), - i -> sub(contract(transpose matrix{faces(i,L#0)}, matrix{faces(i,L#(p+1))}), kk)))) - else (C = truncate(chainComplex complex L#0,1); -- By default the ambient simplicial complex is the first element of the list - maps = apply(#L-1, p -> map(C, truncate(chainComplex complex L#(p+1),1), - i -> sub(contract(transpose matrix{faces(i,L#0)}, matrix{faces(i,L#(p+1))}), kk)))) - ) - else ( - maps = L; - if any(#maps, p -> class maps#p =!= ChainComplexMap) then ( - error "expected sequence of chain complexes"); - C = target maps#0;-- By default the ambient chain complex is target of first map. - if any(#maps, p -> target maps#p != C) then ( - error "expected all map to have the same target")); - Z := image map(C, C, i -> 0*id_(C#i)); -- make zero subcomplex as a subcomplex of ambient complex - P := {}; - myList := {}; - for p from 0 to #maps - 1 do ( - myList = myList | - {#maps - (p+1) -opts.Shift => image maps#p}; - ); - if myList != {} then (P = {(#maps-opts.Shift) => C} | myList) - else P = { - opts.Shift => C} ; - if (last P)#1 != Z then (P = P | {(-1-opts.Shift) => Z}); - return new FilteredComplex from P | {symbol zero => (ring C)^0, symbol cache => new CacheTable}) + if #L == 0 then error "expected at least one complex map or simplicial complex"; + if not uniform L then error "expected a list of complex maps or simplicial complexes"; + -- + maps := if instance(L#0, SimplicialComplex) then ( + kk := coefficientRing L#0; + if opts.ReducedHomology == true then ( + -- By default the ambient simplicial complex is the first element of the list + C := complex L#0; + apply(#L-1, p -> map(C, complex L#(p+1), + i -> sub(contract(transpose matrix{faces(i,L#0)}, matrix{faces(i,L#(p+1))}), kk)))) + else ( + -- By default the ambient simplicial complex is the first element of the list + C = complex L#0; + C = naiveTruncation(C, 1); + apply(#L-1, p -> map(C, naiveTruncation(complex L#(p+1), 1), + i -> sub(contract(transpose matrix{faces(i,L#0)}, matrix{faces(i,L#(p+1))}), kk)))) + ) + else if instance(L#0, ComplexMap) then ( + -- By default the ambient chain complex is target of first map. + C = target L#0; + if same apply(L, target) then L + else error "expected all maps to have the same target") + else error "expected a list of complex maps or simplicial complexes"; + -- + Z := image map(C, C, i -> 0*id_(C_i)); -- make zero subcomplex as a subcomplex of ambient complex + P := {}; + myList := {}; + for p from 0 to #maps - 1 do ( + myList = myList | + {#maps - (p+1) -opts.Shift => image maps#p}; + ); + if myList != {} then (P = {(#maps-opts.Shift) => C} | myList) + else P = { - opts.Shift => C} ; + if (last P)#1 != Z then (P = P | {(-1-opts.Shift) => Z}); + return new FilteredComplex from P | {symbol zero => (ring C)^0, symbol cache => new CacheTable}) -------------------------------------------------------------------------------- @@ -329,33 +208,28 @@ filteredComplex(List) := FilteredComplex => opts -> L -> ( -- make the filtered complex associated to the "naive truncation of a chain complex" -filteredComplex ChainComplex := FilteredComplex => opts-> C->( complete C; - n := max support C; - m := min support C; - p := length C; - if p > 0 then ( - H := for i from 1 to p list inducedMap(C,truncate(C,-i)); - filteredComplex( H, Shift => - m) ) - else filteredComplex {map(C, image(0 * id_C), id_C)}--{map(C, id_C} -- now the constructor supports the zero chain complex - ) - +filteredComplex Complex := FilteredComplex => opts -> C -> ( + (lo, hi) := concentration C; + if lo == hi + then filteredComplex{ map(C, image(0 * id_C), id_C) } + else filteredComplex(Shift => -lo, + apply(hi-lo, i -> inducedMap(C, naiveTruncation(C, lo, hi-i-1))))) --produce the "x-filtration" of the tensor product complex. -FilteredComplex ** ChainComplex := FilteredComplex => (K,C) -> ( - xTensormodules := (p,q,T)->(apply( (T#q).cache.indices, - i-> if (i#0) <=p then - image (id_(((T#q).cache.components)#(((T#q).cache.indexComponents)#i))) - else image(0* id_(((T#q).cache.components)#(((T#q).cache.indexComponents)#i)))) ); - xTensorComplex := (T,p) ->(K := new ChainComplex; - K.ring = T.ring; - for i from min T to max T do ( - if T#?(i-1) then - K.dd_i = inducedMap( - directSum(xTensormodules(p,i-1,T) - ), - directSum(xTensormodules(p,i,T)),T.dd_i)); - K - ); +xTensormodules := (p,q,T) -> ( + apply(indices T_q, components T_q, + (ind, M) -> if ind#0 <= p + then image id_M + else image(0 * id_M))) + +xTensorComplex := (T,p) ->( + (lo, hi) := concentration T; + if lo == hi + then complex(directSum xTensormodules(p, lo, T), Base => lo) + else complex applyPairs(T.dd.map, + (i,f) -> i => inducedMap(directSum(xTensormodules(p, i-1, T)), directSum(xTensormodules(p, i, T)), f))) + +FilteredComplex ** Complex := FilteredComplex => (K,C) -> ( supp := support K_infinity; -- try to handle the boundary cases -- if supp != {} and #supp > 1 then ( @@ -378,18 +252,20 @@ filteredComplex(reverse for i from P to (N-1) list ) --produce the "y-filtration" of the tensor product complex. -ChainComplex ** FilteredComplex := FilteredComplex => (C,K) -> ( - yTensorModules := (p,q,T)->(apply( (T#q).cache.indices, - i-> if (i#1) <=p then image (id_(((T#q).cache.components)#(((T#q).cache.indexComponents)#i))) - else image(0* id_(((T#q).cache.components)#(((T#q).cache.indexComponents)#i)))) ); - yTensorComplex := (T,p) -> (K := new ChainComplex; - K.ring = T.ring; - for i from min T to max T do ( - if T#?(i-1) then - K.dd_i = inducedMap(directSum(yTensorModules(p,i-1,T)), - directSum(yTensorModules(p,i,T)),T.dd_i)); - K - ); +yTensorModules := (p,q,T)->( + apply(indices T_q, components T_q, + (ind, M) -> if ind#1 <= p + then image id_M + else image(0 * id_M))) + +yTensorComplex := (T,p) -> ( + (lo, hi) := concentration T; + if lo == hi + then complex(directSum(yTensorModules(p, lo, T), Base => lo)) + else complex applyPairs(T.dd.map, + (i,f) -> i => inducedMap(directSum(yTensorModules(p, i-1, T)), directSum(yTensorModules(p, i, T)), f))) + +Complex ** FilteredComplex := FilteredComplex => (C,K) -> ( supp := support K_infinity; -- try to handle the boundary cases -- if supp != {} and #supp > 1 then ( @@ -412,40 +288,36 @@ filteredComplex(reverse for i from P to (N-1) list ) -- produce the "x-filtration" of the Hom complex. -xmodules := (n, d, H)->( +xHomModules := (n, d, H)->( -- want components {p,q} = Hom(-p, q) with p + q = d and p <= n - apply( (H#d).cache.indices, - i -> if - (i#0) <= n then - image (id_(((H#d).cache.components)#(((H#d).cache.indexComponents)#i))) - else image(0* id_(((H#d).cache.components)#(((H#d).cache.indexComponents)#i)))) ); - - -xComplex := (T,n) -> - (K := new ChainComplex; - K.ring = T.ring; - for i from min T to max T do ( - if T#?(i-1) then - K.dd_i = inducedMap(directSum(xmodules(n,i-1,T)),directSum(xmodules(n,i,T)),T.dd_i)); - K - ) + apply(indices H_d, components H_d, + (ind, M) -> if -ind#0 <= n + then image id_M + else image(0 * id_M))) + +xHomComplex := (T,n) -> ( + (lo, hi) := concentration T; + if lo == hi + then complex(directSum(xHomModules(n, lo, T), Base => lo)) + else complex applyPairs(T.dd.map, + (i,f) -> i => inducedMap(directSum(xHomModules(n, i-1, T)), directSum(xHomModules(n, i, T)), f))) -- produce the "x-filtration" of the Hom complex. -Hom (FilteredComplex, ChainComplex):= FilteredComplex => opts -> (K, D) -> ( - C := complete D; +Hom (FilteredComplex, Complex):= FilteredComplex => opts -> (K, C) -> ( supp := support K_infinity; -- try to handle the boundary cases -- if supp != {} and #supp > 1 then ( N := - max support K_infinity; P := - min support K_infinity; H := Hom(K_infinity, C, opts); - filteredComplex(reverse for i from N to P - 1 list inducedMap(H, xComplex(H,i)), + filteredComplex(reverse for i from N to P - 1 list inducedMap(H, xHomComplex(H,i)), Shift => - N) ) else ( if #supp == 1 then ( p := min supp; h := Hom(K_infinity, C, opts); - filteredComplex( {inducedMap(h, xComplex(h, p))}, Shift => p + 1 ) + filteredComplex( {inducedMap(h, xHomComplex(h, p))}, Shift => p + 1 ) ) else( hhh := Hom(K_infinity, C, opts); @@ -456,40 +328,35 @@ Hom (FilteredComplex, ChainComplex):= FilteredComplex => opts -> (K, D) -> ( -- next are some functions used in the "y-filtration" of the Hom complex. -ymodules := (n, d, H) -> ( +yHomModules := (n, d, H) -> ( -- want components {p,q} = Hom(-p, q) with p + q = d and q <= n - apply( (H#d).cache.indices, - i -> if (i#1) <= n then - image (id_(((H#d).cache.components)#(((H#d).cache.indexComponents)#i))) - else image(0* id_(((H#d).cache.components)#(((H#d).cache.indexComponents)#i)))) - ) - - -yComplex := (T,n) -> - (K := new ChainComplex; - K.ring = T.ring; - for i from min T to max T do ( - if T#?(i-1) then - K.dd_i = inducedMap(directSum(ymodules(n,i-1,T)),directSum(ymodules(n,i,T)),T.dd_i)); - K - ) - -Hom (ChainComplex, FilteredComplex) := FilteredComplex => opts -> (D, K) -> ( - C := complete D; + apply(indices H_d, components H_d, + (ind, M) -> if ind#1 <= n + then image id_M + else image(0 * id_M))) + +yHomComplex := (T,n) -> ( + (lo, hi) := concentration T; + if lo == hi + then complex(directSum(yHomModules(n, lo, T), Base => lo)) + else complex applyPairs(T.dd.map, + (i,f) -> i => inducedMap(directSum(yHomModules(n, i-1, T)), directSum(yHomModules(n, i, T)), f))) + +Hom (Complex, FilteredComplex) := FilteredComplex => opts -> (C, K) -> ( supp := support K_infinity; -- try to handle the boundary cases -- if supp != {} and #supp > 1 then ( N := max support K_infinity; P := min support K_infinity; H := Hom(C, K_infinity, opts); - filteredComplex(reverse for i from P to N - 1 list inducedMap(H, yComplex(H,i)), + filteredComplex(reverse for i from P to N - 1 list inducedMap(H, yHomComplex(H,i)), Shift => - P) ) else ( if #supp == 1 then ( p := min supp; h := Hom(C, K_infinity, opts); - filteredComplex( {inducedMap(h, yComplex(h, p))}, Shift => - p + 1 ) + filteredComplex( {inducedMap(h, yHomComplex(h, p))}, Shift => - p + 1 ) ) else( hhh := Hom(C, K_infinity, opts); @@ -501,14 +368,14 @@ Hom (ChainComplex, FilteredComplex) := FilteredComplex => opts -> (D, K) -> ( -- I-adic filtration code -- -- the following script allows us to multiply a chain complex by an ideal -Ideal * ChainComplex := ChainComplex => (I,C) -> ( - D := new ChainComplex; - D.ring = C.ring; - apply(drop(spots C, 1), i -> D.dd_i = inducedMap(I * C_(i-1), I * C_i, C.dd_i)); - D - ) - -filteredComplex(Ideal,ChainComplex,ZZ) := FilteredComplex => opts -> (I,C,n) ->( +Ideal * Complex := Complex => (I,C) -> ( + (lo, hi) := concentration C; + if lo == hi + then complex(I * C_lo, Base => lo) + else complex applyValues(C.dd.map, + f -> inducedMap(I * target f, I * source f, f))) + +filteredComplex(Ideal,Complex,ZZ) := FilteredComplex => opts -> (I,C,n) ->( if n < 0 then error "expected a non-negative integer" else filteredComplex(apply(n, i -> inducedMap(C, I^(i+1) * C)), Shift => n) @@ -700,7 +567,7 @@ SpectralSequence ^ InfiniteNumber:= -- again trying to handle the case of the zero complex -- if min K_(infinity) < infinity and max K_infinity > - infinity then ( for p from min K to max K do ( - for q from - p + min K_(infinity) to max K_(infinity) do ( + for q from -p + min K_(infinity) to max K_(infinity) + 1 do ( if E.Prune == false then H#{p,q} = epq(K,p,q,s) else H#{p,q} = prune epq(K,p,q,s) ); @@ -770,7 +637,7 @@ page SpectralSequencePage := Page => opts -> E -> ( -- again trying to handle the case of the zero complex -- if min K_(infinity) < infinity and max K_infinity > - infinity then ( for p from min K to max K do ( - for q from -p + min K_(infinity) to max K_(infinity) do ( + for q from -p + min K_(infinity) to max K_(infinity) + 1 do ( -- H#{p,q} = E^s_{p,q} if E.Prune == false then H#{p,q} = epq(K,p,q,s) else H#{p,q} = prune epq(K,p,q,s) @@ -915,18 +782,20 @@ SpectralSequencePageMap ^ List := Matrix => (d,i)-> (d_(-i)) -- auxiliary spectral sequence stuff. filteredComplex SpectralSequence := FilteredComplex => opts -> E -> E.filteredComplex -chainComplex SpectralSequence := ChainComplex => E -> chainComplex filteredComplex E +complex SpectralSequence := Complex => {} >> opts -> E -> complex E.filteredComplex + -- given a morphism f: A --> B -- compute the connecting map -- HH_{n+1}( coker f) --> HH_n (im f) connectingMorphism = method() -connectingMorphism(ChainComplexMap,ZZ) := (a,n) -> ( +connectingMorphism(ComplexMap,ZZ) := (a,n) -> ( K := filteredComplex ({a}) ; e := spectralSequence K ; e^1 .dd_{1, n} ) + -- here are some needed functions related to Hilbert polynomials -- hilbertPolynomial ZZ := ProjectiveHilbertPolynomial => o -> (M) -> ( if M == 0 then new ProjectiveHilbertPolynomial from {} else @@ -970,24 +839,19 @@ basis (List,SpectralSequencePage) := opts -> (deg,E) -> ( -- edgeComplex = method() - edgeComplex(SpectralSequence) := (E) -> ( if E.Prune == true then error "not currently implemented for pruned spectral sequences"; - if E.Prune == true then error "not currently implemented for pruned spectral sequences"; M := select(spots E^2 .dd, i -> E^2_i != 0); l := min apply(M, i -> i#0); m := min apply(M, i -> i#1); - C := chainComplex E; + C := complex E; if M != {} then ( - chainComplex {inducedMap(E^2_{l + 1, m}, HH_(l + m + 1) C, id_(C_(l + m + 1))), + complex {inducedMap(E^2_{l + 1, m}, HH_(l + m + 1) C, id_(C_(l + m + 1))), inducedMap(HH_(l + m + 1) C, E^2_{l,m + 1}, id_(C_(l + m + 1))), E^2 .dd_{l + 2,m}, inducedMap(E^2_{l + 2, m}, HH_(l + m + 2) C, id_(C_(l + m + 2)))}) - else - (c := new ChainComplex; c.ring = E.filteredComplex _infinity .ring; - c) - ) + else complex C.ring) + - filteredHomologyObject = method() filteredHomologyObject(ZZ, ZZ,FilteredComplex) := (p,n,K) -> ( @@ -1215,7 +1079,7 @@ doc /// Example B = QQ[a..d] J = ideal vars B - C = complete res monomialCurveIdeal(B,{1,3,4}) + C = res monomialCurveIdeal(B,{1,3,4}) K = filteredComplex(J,C,4) Text Here are some higher pages of the associated spectral sequence: @@ -1409,25 +1273,25 @@ doc /// R = QQ[x,y,z,w] ; c2 = matrix(R,{{1},{0}}) ; c1 = matrix(R,{{0,1}}) ; - C = chainComplex({c1,c2}) + C = complex({c1,c2}) D_2 = image matrix(R,{{1}}); D_1 = image matrix(R,{{1,0},{0,0}}); D_0 = image matrix(R,{{1}}); - D = chainComplex({inducedMap(D_0,D_1,C.dd_1),inducedMap(D_1,D_2,C.dd_2)}) + D = complex({inducedMap(D_0,D_1,C.dd_1),inducedMap(D_1,D_2,C.dd_2)}) E_2 = image matrix(R,{{0}}); E_1 = image matrix(R,{{1,0},{0,0}}); E_0 = image matrix(R,{{1}}); - E = chainComplex({inducedMap(E_0,E_1,C.dd_1),inducedMap(E_1,E_2,C.dd_2)}) + E = complex({inducedMap(E_0,E_1,C.dd_1),inducedMap(E_1,E_2,C.dd_2)}) Text We now make our chain complex maps. Example - d = chainComplexMap(C,D,apply(spots C, i-> inducedMap(C_i,D_i,id_C _i))) - e = chainComplexMap(C,E,apply(spots C, i->inducedMap(C_i,E_i, id_C _i))) + d = map(C,D,apply(spots C, i-> inducedMap(C_i,D_i,id_C _i))) + e = map(C,E,apply(spots C, i->inducedMap(C_i,E_i, id_C _i))) Text We can check that these are indeed chain complex maps: Example - isChainComplexMap d - isChainComplexMap e + isWellDefined d + isWellDefined e Text Now, given the list of chain complex maps $\{d, e\}$, we obtain a filtration of $C$ by: @@ -1566,7 +1430,7 @@ doc /// Text We can check that the homology of the simplicial complex twoSphere agrees with that of $\mathbb{S}^2$. Example - C = truncate(chainComplex complex twoSphere,1) + C = naiveTruncation(complex twoSphere, 1) prune HH C Text We now write down our simplicial complex whose topological realization @@ -1578,7 +1442,7 @@ doc /// Again we can check that we've entered a simplicial complex whose homology agrees with that of the real projective plane. Example - B = truncate(chainComplex complex realProjectivePlane,1) + B = naiveTruncation(complex realProjectivePlane, 1) prune HH B Text We now compute the fibers of the anti-podal quotient map @@ -1633,7 +1497,7 @@ doc/// We can check that the homology of this simplicial complex agrees with that of the Klein Bottle: Example - C = truncate(chainComplex complex Delta,1) + C = naiveTruncation(complex Delta, 1) prune HH C Text Let $S$ be the simplicial complex with facets $\{A_0 A_1, A_0 A_2, A_1 A_2\}$. Then $S$ is a triangulation of $S^1$. The simplicial map @@ -1684,7 +1548,7 @@ doc /// $\Delta$ agrees with that of the torus $\mathbb{S}^1 \times \mathbb{S}^1 $ Example - C = truncate(chainComplex complex Delta,1) + C = naiveTruncation(complex Delta, 1) prune HH C Text Let $S$ be the simplicial complex with facets $\{A_0 A_1, A_0 A_2, A_1 A_2\}$. Then $S$ is a triangulation of $S^1$. The simplicial map @@ -1734,8 +1598,8 @@ doc /// B = B_*/(x -> x^2)//ideal; -- need to take a large enough power. -- it turns out that 2 is large enough for this example - G = complete res image gens B; - F = koszul gens I; + G = res image gens B; + F = koszulComplex gens I; K = Hom(G, filteredComplex(F)); E = prune spectralSequence K; E^1 @@ -1791,11 +1655,10 @@ doc /// M = intersect(ideal(a_0,a_1),ideal(b_0,b_1)) ; -- irrelevant ideal M = M_*/(x -> x^5)//ideal ; -- Suitably high Frobenius power of M G = res image gens M ; - I = ideal random(R^1, R^{{-3,-3}}) -- ideal of C - b = chainComplex gradedModule R^{{1,0}} -- make line bundle a chain complex - a = chainComplex gradedModule R^{{-2,-3}} + b = complex R^{{1,0}} -- make line bundle a chain complex + a = complex R^{{-2,-3}} -- make the map OO(-2, -3) --> OO(1,0) - f = chainComplexMap(b, a,{random(R^1, R^{{-3,-3}})}) ; + f = randomComplexMap(b, a, Degree => 0) K = filteredComplex ({Hom(G,f)}) ; -- the two step filtered complex we want E = prune spectralSequence K ; Text @@ -2081,9 +1944,9 @@ doc /// f = map(S,R,{s^2,s*t,t^2}); N = coker vars S; M = coker vars R --; - F := complete res N; + F := res N; pushFwdF := pushFwd(f,F); - G := complete res M; + G := res M; E := spectralSequence(filteredComplex(G) ** pushFwdF); EE := spectralSequence(G ** (filteredComplex pushFwdF)); e = prune E; @@ -2452,7 +2315,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text The infinity page of the resulting spectral sequence is computed below. @@ -2542,7 +2405,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text We compute an example of a pruning map below. @@ -2572,13 +2435,13 @@ doc /// doc /// Key - (spots, ChainComplex) + (spots, Complex) Headline which spots does the given chain complex has a module. Usage s = spots L Inputs - L:ChainComplex + L:Complex Outputs s:List Description @@ -2599,7 +2462,7 @@ doc /// Inputs L:List or - L:ChainComplex + L:Complex or L:SpectralSequence ReducedHomology => Boolean @@ -2695,7 +2558,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); E = spectralSequence K Text @@ -2731,7 +2594,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); E = spectralSequence K Text @@ -2746,24 +2609,36 @@ doc /// "Examples of filtered complexes and spectral sequences" /// - - doc /// - Key - (truncate, ChainComplex, ZZ) - Headline - compute the hard truncation of a chain complex - Description - Text - Computes the hard truncation of a chain complex as a specified homological degree. - Example - B = QQ[a..d]; - C = koszul vars B - truncate(C,1) - truncate(C,-1) - truncate(C,-10) - truncate(C,10) -/// + Key + (naiveTruncation, Complex, ZZ) + Headline + compute the hard truncation of a chain complex + Usage + naiveTruncation(C, n) + Inputs + C:Complex + n:ZZ + Outputs + :Complex + Description + Text + This method returns the naive truncation of $C$ by truncating + the low homological degrees if $n$ is positive (i.e. from left) + and high homological degrees if $n$ is negative (i.e. from right). + Example + B = QQ[a..d]; + C = (koszulComplex vars B)[2] + naiveTruncation(C, 10) + naiveTruncation(C, 2) + naiveTruncation(C, 1) + naiveTruncation(C, 0) + naiveTruncation(C,-1) + naiveTruncation(C,-2) + naiveTruncation(C,-10) + SeeAlso + (naiveTruncation, Complex, ZZ, ZZ) +/// doc /// Key @@ -2785,7 +2660,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text We compute an example of a pruning map below. @@ -2801,7 +2676,7 @@ doc /// doc /// Key - (support,ChainComplex) + (support,Complex) Headline nonzero parts of a chain complex Description @@ -2810,13 +2685,13 @@ doc /// Example A = QQ[x,y]; - C = koszul vars A + C = koszulComplex vars A support C - D = truncate(C,1) + D = naiveTruncation(C, 1) spots D support D SeeAlso - (spots, ChainComplex) + (spots, Complex) /// @@ -2834,7 +2709,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text We compute an example of a pruning map below. @@ -2873,38 +2748,38 @@ doc /// R = QQ[x,y,z,w] d2 = matrix(R,{{1},{0}}) d1 = matrix(R,{{0,1}}) - C = chainComplex({d1,d2}) + C = complex({d1,d2}) Text We now make the modules of the another chain complex which we will label D. Example D_2 = image matrix(R,{{1}}) D_1 = image matrix(R,{{1,0},{0,0}}) D_0 = image matrix(R,{{1}}) - D = chainComplex({inducedMap(D_0,D_1,C.dd_1),inducedMap(D_1,D_2,C.dd_2)}) + D = complex({inducedMap(D_0,D_1,C.dd_1),inducedMap(D_1,D_2,C.dd_2)}) Text Now make a chain complex map. Example - d = chainComplexMap(C,D,apply(spots C, i-> inducedMap(C_i,D_i,id_C _i))) - isChainComplexMap d - d == chainComplexMap(C,D,{inducedMap(C_0,D_0,id_(C_0)),inducedMap(C_1,D_1,id_(C_1)),inducedMap(C_2,D_2,id_(C_2))}) + d = map(C,D,{inducedMap(C_0,D_0,id_(C_0)),inducedMap(C_1,D_1,id_(C_1)),inducedMap(C_2,D_2,id_(C_2))}) + isWellDefined d Text We now make the modules of another chain complex which we will label E. Example E_2 = image matrix(R,{{0}}) E_1 = image matrix(R,{{1,0},{0,0}}) E_0 = image matrix(R,{{1}}) - E = chainComplex({inducedMap(E_0,E_1,C.dd_1),inducedMap(E_1,E_2,C.dd_2)}) + E = complex({inducedMap(E_0,E_1,C.dd_1),inducedMap(E_1,E_2,C.dd_2)}) Text Now make a chain complex map. Example - e = chainComplexMap(C,E,apply(spots C, i->inducedMap(C_i,D_i, id_C _i))) + e = map(C,E,{inducedMap(C_0,E_0,id_(C_0)),inducedMap(C_1,E_1,id_(C_1)),inducedMap(C_2,E_2,id_(C_2))}) + isWellDefined e Text Now make a filtered complex from a list of chain complex maps. Example K = filteredComplex({d,e}) Text We can make a filtered complex, with a specified minimum filtration degree - from a list of ChainComplexMaps by using the Shift option. + from a list of ComplexMaps by using the Shift option. Example L = filteredComplex({d,e},Shift => 1) M = filteredComplex({d,e},Shift => -1) @@ -2927,13 +2802,13 @@ doc /// doc /// Key - (filteredComplex, ChainComplex) + (filteredComplex, Complex) Headline obtain a filtered complex from a chain complex Usage K = filteredComplex C Inputs - C: ChainComplex + C: Complex -- these options don't do anything for this constructor. ReducedHomology => Boolean Shift => ZZ @@ -2943,12 +2818,11 @@ doc /// Text Produces the filtered complex obtained by successively truncating the complex. Example - needsPackage "SpectralSequences" A = QQ[x,y] - C = koszul vars A + C = koszulComplex vars A K = filteredComplex C SeeAlso - (truncate, ChainComplex,ZZ) + (naiveTruncation, Complex, ZZ, ZZ) /// doc /// @@ -2985,10 +2859,9 @@ doc /// Example C = filteredComplex E SeeAlso - --(_, FilteredComplex,InfiniteNumber) - --(^,FilteredComplex,InfiniteNumber) -/// - + (symbol _, FilteredComplex, InfiniteNumber) + (symbol ^, FilteredComplex, InfiniteNumber) +/// doc /// Key @@ -3013,7 +2886,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text We compute the degree $0$ piece of the $E^3$ page below. @@ -3045,7 +2918,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text We compute the degree $0$ piece of the $E^3$ page below. @@ -3056,23 +2929,23 @@ doc /// doc /// Key - (chainComplex, FilteredComplex) + (complex, FilteredComplex) Headline the ambient chain complex of a filtered complex Usage - C = chainComplex K + C = complex K Inputs K:FilteredComplex Outputs - C:ChainComplex + C:Complex Description Text Returns the ambient chain complex of the filtered complex. Example A = QQ[x,y]; - C = koszul vars A + C = koszulComplex vars A K = filteredComplex C; - chainComplex K + complex K K_infinity SeeAlso (symbol _, FilteredComplex, ZZ) @@ -3105,7 +2978,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text Compare some pages of the non-pruned version of the spectral sequence @@ -3147,7 +3020,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text Compare some pruned and non-prunded pages the spectral sequence $E$ below. @@ -3182,22 +3055,22 @@ doc /// Returns the spectral sequence associated to the filtered complex. Example A = QQ[x,y]; - C = koszul vars A + C = koszulComplex vars A K = filteredComplex C; E = spectralSequence K /// doc /// Key - (Hom, FilteredComplex, ChainComplex) - (Hom, ChainComplex, FilteredComplex) + (Hom, FilteredComplex, Complex) + (Hom, Complex, FilteredComplex) Headline the filtered Hom complex Usage f = Hom(K,C) Inputs K:FilteredComplex - C:ChainComplex + C:Complex Outputs f:FilteredComplex Description @@ -3216,24 +3089,24 @@ doc /// doc /// Key - (chainComplex, SpectralSequence) + (complex, SpectralSequence) Headline the underlying chain complex of a Spectral Sequence Usage - K = chainComplex E + K = complex E Inputs E:SpectralSequence Outputs - K:ChainComplex + K:Complex Description Text Returns the underlying chain complex of a spectral sequence. Example A = QQ[x,y]; - C = koszul vars A + C = koszulComplex vars A K = filteredComplex C; E = spectralSequence K - chainComplex E + complex E /// doc /// @@ -3259,7 +3132,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text @@ -3351,7 +3224,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text @@ -3392,7 +3265,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text We compute a map on the third page of the spectral sequence associated to $K$. @@ -3426,7 +3299,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text We compute a map on the third page of the spectral sequence associated to $K$. @@ -3460,7 +3333,7 @@ doc /// Example B = QQ[a..d]; J = ideal vars B; - C = complete res monomialCurveIdeal(B,{1,3,4}); + C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); Text @@ -3515,7 +3388,7 @@ doc /// (Using cohomological or upper indexing conventions.) The relationship $E^{-i,-j} = E_{i,j}$ holds. Example A = QQ[x,y] - C = koszul vars A; + C = koszulComplex vars A; K = filteredComplex C; E = spectralSequence K E_0 @@ -3545,7 +3418,7 @@ doc /// (Using homological or lower indexing conventions.) The relationship $E_{i,j} = E^{-i,-j}$ holds. Example A = QQ[x,y] - C = koszul vars A; + C = koszulComplex vars A; K = filteredComplex C; E = spectralSequence K E^0 @@ -3558,15 +3431,15 @@ doc /// doc /// Key - (symbol **, ChainComplex, FilteredComplex) - (symbol **, FilteredComplex, ChainComplex) + (symbol **, Complex, FilteredComplex) + (symbol **, FilteredComplex, Complex) Headline filtered tensor product of complexes Usage KK = C ** K KK = K ** C Inputs - C:ChainComplex + C:Complex K:FilteredComplex Outputs KK:FilteredComplex @@ -3577,26 +3450,26 @@ doc /// The following example illustrates the syntax. Example A = QQ[x,y]; - B = koszul vars A; - C = koszul vars A; + B = koszulComplex vars A; + C = koszulComplex vars A; F' = (filteredComplex B) ** C F'' = B ** (filteredComplex C) SeeAlso "Filtrations and tensor product complexes" /// - + doc /// Key - (tensor, RingMap, ChainComplex) + (tensor, RingMap, Complex) Headline tensor product of a chain complex by a ring map Usage D = tensor(f,C) Inputs f:RingMap - C:ChainComplex + C:Complex Outputs - D:ChainComplex + D:Complex Description Text Given a ring map R -> S and a chain complex over R, @@ -3625,7 +3498,7 @@ doc /// K:FilteredComplex i:ZZ Outputs - f:ChainComplexMap + f:ComplexMap Description Text Returns the chain complex map specifying the inclusion of the i piece @@ -3633,7 +3506,7 @@ doc /// complex to the ambient chain complex. Example A = QQ[x,y]; - C = koszul vars A; + C = koszulComplex vars A; K = filteredComplex C inducedMap(K,1) /// @@ -3651,14 +3524,14 @@ doc /// j:ZZ an integer, infinity, or -infinity Outputs - C:ChainComplex + C:Complex Description Text Returns the chain complex in (homological) filtration degree j. The relationship $K _ j = K ^{(-j)}$ holds. Example A = QQ[x,y]; - C = koszul vars A; + C = koszulComplex vars A; K = filteredComplex C K_0 K_1 @@ -3687,14 +3560,14 @@ doc /// j:ZZ an integer, infinity, or -infinity Outputs - C:ChainComplex + C:Complex Description Text Returns the chain complex in (cohomological) filtration degree j. The relationship $K ^ j = K _{(-j)}$ holds. Example A = QQ[x,y]; - C = koszul vars A; + C = koszulComplex vars A; K = filteredComplex C K_0 K_1 @@ -3719,7 +3592,7 @@ doc /// Usage g = connectingMorphism(f, n) Inputs - f:ChainComplexMap + f:ComplexMap n:ZZ Outputs g:Matrix @@ -3731,13 +3604,13 @@ doc /// doc /// Key - (connectingMorphism, ChainComplexMap,ZZ) + (connectingMorphism, ComplexMap,ZZ) Headline use spectral sequences to compute connecting morphisms Usage g = connectingMorphism(f, n) Inputs - f:ChainComplexMap + f:ComplexMap n:ZZ Outputs g:Matrix @@ -3880,10 +3753,6 @@ doc /// /// ---doc /// --- Key --- associatedGradedHomologyObject ---/// doc /// Key @@ -3971,7 +3840,7 @@ doc /// Inputs E: SpectralSequence Outputs - C: ChainComplex + C: Complex Description Text Suppose that $E$ is a spectral sequence with the properties that: @@ -4023,14 +3892,14 @@ doc /// doc /// Key - (filteredComplex, Ideal, ChainComplex, ZZ) + (filteredComplex, Ideal, Complex, ZZ) Headline I-adic filtrations of chain complexes Usage K = filteredComplex(I,C,n) Inputs I: Ideal - C: ChainComplex + C: Complex n: ZZ Outputs K: FilteredComplex @@ -4040,7 +3909,7 @@ doc /// Example B = QQ[a..d] J = ideal vars B - C = complete res monomialCurveIdeal(B,{1,3,4}) + C = res monomialCurveIdeal(B,{1,3,4}) K = filteredComplex(J,C,4) Text Here are higher some pages of the associated spectral sequence: @@ -4160,19 +4029,14 @@ doc /// TEST /// -restart; -needsPackage "SpectralSequences"; A = QQ[a,b,c]; -C = new ChainComplex; -C.ring = A; +C = complex A^0 K = filteredComplex C; assert(K_0 == C); assert(K_1 == C); /// TEST /// -restart; -needsPackage "SpectralSequences"; A = QQ[a,b,c]; D = simplicialComplex {a*b*c}; F2D = D; @@ -4196,8 +4060,6 @@ assert(all(keys support e^5, j -> isIsomorphism homologyIsomorphism(e,j#0,j#1,5) /// TEST /// -restart -needsPackage "SpectralSequences"; -- The following example is taken from p. 127, Fig 7.2 of -- Zomorodian's "Topology for computing" A = ZZ [s,t,u,v,w] ; @@ -4252,8 +4114,6 @@ assert(all(keys support e^12, j -> isIsomorphism homologyIsomorphism(e,j#0,j#1,1 /// TEST /// -restart -needsPackage "SpectralSequences"; A = QQ[a,b,c,d]; D = simplicialComplex {a*d*c, a*b, a*c, b*c}; F2D = D; @@ -4291,11 +4151,9 @@ assert(all(keys support e^12, j -> isIsomorphism homologyIsomorphism(e,j#0,j#1,1 /// TEST /// -restart -needsPackage "SpectralSequences"; B = QQ[a..d]; J = ideal vars B; -C = complete res monomialCurveIdeal(B,{1,3,4}); +C = res monomialCurveIdeal(B,{1,3,4}); K = filteredComplex(J,C,4); e = prune spectralSequence K; assert(all(keys support e^0, j -> isIsomorphism homologyIsomorphism(e,j#0,j#1,0))) @@ -4307,8 +4165,6 @@ assert(all(keys support e^4, j -> isIsomorphism homologyIsomorphism(e,j#0,j#1,4) TEST /// -restart -needsPackage "SpectralSequences"; S = ZZ/101[x,y]; I = ideal(x^2,x*y,y^2); R = S/I; @@ -4338,7 +4194,3 @@ installPackage("SpectralSequences", RemakeAllDocumentation => true) check "SpectralSequences"; viewHelp SpectralSequences ------------------------------------------ - -Status API Training Shop Blog About -© 2016 GitHub, Inc. Terms Privacy Security Contact Help - diff --git a/M2/Macaulay2/tests/normal/quotient.m2 b/M2/Macaulay2/tests/normal/quotient.m2 index 44276ba8483..93dac5ce5cf 100644 --- a/M2/Macaulay2/tests/normal/quotient.m2 +++ b/M2/Macaulay2/tests/normal/quotient.m2 @@ -40,3 +40,117 @@ assert(f \\ h == g) assert((f\\h) * f == h) assert(g // h == 0) -- does it always happen that this is zero if lift can't occur? Probably not assert(h \\ f == 0) + + +-- tests which show that the "Reflexive" strategy doesn't always work +S = QQ[x_0,x_1,x_2] --/ sum(3, i -> x_i^3) +a = x_0 + x_1 +b = x_0^2-x_0*x_1+x_1^2 +A = matrix {{x_2, a}, {b, -x_2^2}} +B = matrix {{x_2^2, a}, {b, -x_2}} + +f = map(S^2 / a, S^2 / a, A * B) +f' = map(S^2 / a, S^2, A * B) +g = map(S^2 / a, S^2, A) +h = map(S^2 / a, S^2 / a, B) +assert all({f', f, g, h}, isWellDefined) + +-- f does not factor through g without a remainder +assert not isSubset(image homomorphism' f, image Hom(source f, g)) + +-- here is the example +q = f // g +assert(isWellDefined q and q == 0) + +q = quotient(f, g, Strategy => Default) +assert(isWellDefined q and q == 0) + +-- the Reflexive strategy is not applicable here +assert try ( quotient(f, g, Strategy => "Reflexive"); false ) else true + +-- but f' does (left) factor through g +assert isSubset(image homomorphism' f, image Hom(g, target f)) + +q = g \\ f' +assert isWellDefined q +assert(f' == q * g) +assert(h == q) + +q = quotient'(f', g, Strategy => Default) +assert isWellDefined q +assert(f' == q * g) +assert(h == q) + +assert try ( quotient'(f', g, Strategy => "Reflexive"); false ) else true + + +-- this is an example where the improved "Reflexive" strategy works +f = homomorphism random Hom(image(A | B), S^2) +g = homomorphism random Hom(image(B | A), S^2) +h = homomorphism random Hom(image(A | B), image(B | A)) +f = g * h +assert all({f, g}, isWellDefined) + +-- f factors through g without a remainder +assert isSubset(image homomorphism' f, image Hom(source f, g)) + +-- here is the example +q = f // g +assert(isWellDefined q and f == g * q) + +q = quotient(f, g, Strategy => Default) +assert(isWellDefined q and f == g * q) + + +-- this is an example where the improved "Reflexive" strategy works +R = ZZ/2[x,y,z,w] +g = matrix {{x, x+y+z}, {x+y+z, z}} +f = g * matrix {{y^2}, {z^2}} +f = inducedMap(target f / (x+y+z), source f / (x+y+z), f) +g = inducedMap(target g / (x+y+z), source g, g) +isWellDefined f +isWellDefined g + +-- f does not factor through g without a remainder +assert not isSubset(image homomorphism' f, image Hom(source f, g)) + +q = quotient(f, g, Strategy => Default) +assert(isWellDefined q and q == 0) + +assert try ( quotient(f, g, Strategy => "Reflexive"); false ) else true + +---- +clearAll +B = QQ[a..d] +f = prune map(B^1, image(map(B^{{-2}, 3:{-3}}, B^{{-3}, 3:{-4}, {-3}, 3:{-4}, {-3}, 3:{-4}, {-3}, 3:{-4}}, {{a, 0, 0, 0, b, 0, 0, 0, c, 0, 0, 0, d, 0, 0, 0}, {0, a, 0, 0, 0, b, 0, 0, 0, c, 0, 0, 0, d, 0, 0}, {0, 0, a, 0, 0, 0, b, 0, 0, 0, c, 0, 0, 0, d, 0}, {0, 0, 0, a, 0, 0, 0, b, 0, 0, 0, c, 0, 0, 0, d}})),{{a*b*c-a^2*d, a*b^3-a^3*c, a^2*c^2-a*b^2*d, a*c^3-a*b*d^2, b^2*c-a*b*d, b^4-a^2*b*c, a*b*c^2-b^3*d, b*c^3-b^2*d^2, b*c^2-a*c*d, b^3*c-a^2*c^2, a*c^3-b^2*c*d, c^4-b*c*d^2, b*c*d-a*d^2, b^3*d-a^2*c*d, a*c^2*d-b^2*d^2, c^3*d-b*d^3}}) +g = prune map(B^1, image(map(B^1, B^{4:{-1}}, {{a, b, c, d}})), {{a, b, c, d}}) +assert isSubset(image homomorphism' f, image Hom(source f, g)) +elapsedTime assert(f == g * quotient(f, g, Strategy => Default)) +elapsedTime assert(f == g * quotient(f, g, Strategy => "Reflexive")) + +---- +S = QQ[x] +f = random(S^1/x, S^1/x^3) +g = random(S^1/x, S^1/x^2) +elapsedTime assert(f == g * quotient(f, g, Strategy => Default)) +elapsedTime assert(f == g * quotient(f, g, Strategy => "Reflexive")) + +---- +S = QQ[x,y]; +M = coker matrix {{x,y},{-y,x}}; +g = random(M, M) +f = g * random(M, M) +q = quotient(f, g, Strategy => "Reflexive") +assert(isWellDefined q and f == g * q) + +---- +S = QQ[x,y,z] +M = S^{-2} +N = S^{-3} +P = truncate(3, S^1) +h = homomorphism random(3, Hom(P, N)) +g = homomorphism random(0, Hom(N, M)) +f = g * h +assert all({f, g, h}, isWellDefined) +q = quotient(f, g, Strategy => "Reflexive") +assert(isWellDefined q and f == g * q) diff --git a/M2/cmake/build-libraries.cmake b/M2/cmake/build-libraries.cmake index 2c1e1608aa5..10471a9d900 100644 --- a/M2/cmake/build-libraries.cmake +++ b/M2/cmake/build-libraries.cmake @@ -511,7 +511,7 @@ ExternalProject_Add(build-msolve TEST_EXCLUDE_FROM_MAIN ON STEP_TARGETS install test ) -_ADD_COMPONENT_DEPENDENCY(programs msolve "gmp;mpfr;flint" MSOLVE_FOUND) +_ADD_COMPONENT_DEPENDENCY(programs msolve "gmp;mpfr;flint" MSOLVE) # https://numpi.dm.unipi.it/software/mpsolve