diff --git a/M2/Macaulay2/m2/exports.m2 b/M2/Macaulay2/m2/exports.m2 index 642d28fb599..95b80ee3557 100644 --- a/M2/Macaulay2/m2/exports.m2 +++ b/M2/Macaulay2/m2/exports.m2 @@ -829,6 +829,7 @@ export { "isModule", "isMonomialIdeal", "isMutable", + "isNormal", "isOpen", "isOutputFile", "isPolynomialRing", @@ -954,6 +955,7 @@ export { "nextPrime", "nextkey", "norm", + "normalCone", "not", "notImplemented", "null", diff --git a/M2/Macaulay2/m2/shared.m2 b/M2/Macaulay2/m2/shared.m2 index 01b01cfa1ba..67e829d8cd3 100644 --- a/M2/Macaulay2/m2/shared.m2 +++ b/M2/Macaulay2/m2/shared.m2 @@ -24,6 +24,10 @@ isEmpty = method(TypicalValue => Boolean) isSmooth = method(TypicalValue => Boolean, Options => true) isVeryAmple = method(TypicalValue => Boolean, Options => true) +isNormal = method() + +normalCone = method(Options => true) + -- symbols protect Base diff --git a/M2/Macaulay2/packages/AInfinity.m2 b/M2/Macaulay2/packages/AInfinity.m2 index 0fe2366f487..9cc12c749f6 100644 --- a/M2/Macaulay2/packages/AInfinity.m2 +++ b/M2/Macaulay2/packages/AInfinity.m2 @@ -126,7 +126,7 @@ d1d1 := hashTable for i from min B to max B2 -2 list D := map(labeledTensorComplex{A0,B},B2,d1d1, Degree => -2); assert (isComplexMap D); -m0 := nullHomotopy D; +m0 := nullHomotopy(D, FreeToExact => true); for i from 4 to limit do( (C,K) := componentsAndIndices B2_i; for k in K do ( @@ -212,7 +212,7 @@ for i from lo+1 to hi list (A0**G).dd_(i-2)*D_i - D_(i-1)*BG.dd_i ); -m0 := nullHomotopy D; +m0 := nullHomotopy(D, FreeToExact => true); for i from 2 to min(limit, 1+(concentration G)_1) do( --was just 1+(concentration G)_1 (C,K) := componentsAndIndices BG_i; for k in K do ( @@ -386,7 +386,7 @@ p = new MutableHashTable from for i from 2 to length G list i=>(presentation R ** G_(i-2))*(BG_i)^[{2,i-2}] p#2 p#3 -nullHomotopy map(G[-2],BG,p) +nullHomotopy(map(G[-2],BG,p), FreeToExact => true) G[-2] BG @@ -646,7 +646,7 @@ if n >= 2 then ( d1d1 := hashTable for i from min B to max B list i+2 => (d1**id_(B_i))*(B2_(i+2))^[{2,i}] - (id_(B_i)**d1)*(B2_(i+2))^[{i,2}]; D := map(A0**B,B2,d1d1, Degree => -2); - m0 := nullHomotopy D; + m0 := nullHomotopy(D, FreeToExact => true); tlist := flatten for i from 4 to 1+(concentration B)_1 list( (C,K) := componentsAndIndices B2_i; diff --git a/M2/Macaulay2/packages/Complexes.m2 b/M2/Macaulay2/packages/Complexes.m2 index 8d25be14a0c..f8f6e8bc95b 100644 --- a/M2/Macaulay2/packages/Complexes.m2 +++ b/M2/Macaulay2/packages/Complexes.m2 @@ -32,6 +32,7 @@ export { "connectingExtMap", "connectingTorMap", "cylinder", + "epicResolutionMap", "freeResolution", "homotopyMap", "horseshoeResolution", @@ -45,10 +46,14 @@ export { "isNullHomotopyOf", "isShortExactSequence", "liftMapAlongQuasiIsomorphism", +-- "minimalBetti", "minimizingMap", "nullHomotopy", + --"nullhomotopy" => "nullHomotopy", "naiveTruncation", "randomComplexMap", +-- "res" => "resolution", +-- "resolution", "resolutionMap", "tensorCommutativity", "torSymmetry", @@ -58,6 +63,7 @@ export { "yonedaMap'", "yonedaProduct", -- Option names + "FreeToExact", -- used in nullHomotopy "OverField", "OverZZ", "Homogenization", @@ -112,6 +118,7 @@ load "Complexes/ChainComplex.m2" load "Complexes/FreeResolutions.m2" load "Complexes/ChainComplexMap.m2" load "Complexes/Tor.m2" +load "Complexes/Ext.m2" -------------------------------------------------------------------- -- interface code to legacy types ---------------------------------- @@ -125,7 +132,7 @@ chainComplex Complex := ChainComplex => (cacheValue symbol ChainComplex) (C -> ( D )) -complex ChainComplex := Complex => opts -> (cacheValue symbol Complex)(D -> ( +complex ChainComplex := Complex => {} >> opts -> (cacheValue symbol Complex)(D -> ( (lo,hi) := (min D, max D); while lo < hi and (D_lo).numgens == 0 do lo = lo+1; while lo < hi and (D_hi).numgens == 0 do hi = hi-1; @@ -146,7 +153,7 @@ chainComplex ComplexMap := ChainComplexMap => f -> ( g ) -complex ChainComplexMap := ComplexMap => opts -> g -> ( +complex ChainComplexMap := ComplexMap => {} >> opts -> g -> ( map(complex target g, complex source g, i -> g_i, Degree => degree g) ) -------------------------------------------------------------------- @@ -395,6 +402,9 @@ doc /// S = ZZ/101[a..d] -K = res coker vars S +K = freeResolution coker vars S L = K ** K +-- would be nice if these were fast(er): elapsedTime L**L; +elapsedTime (oo ** K) +elapsedTime (K ** ooo) diff --git a/M2/Macaulay2/packages/Complexes/ChainComplex.m2 b/M2/Macaulay2/packages/Complexes/ChainComplex.m2 index c55f60c4bcb..c3a0ce551c4 100644 --- a/M2/Macaulay2/packages/Complexes/ChainComplex.m2 +++ b/M2/Macaulay2/packages/Complexes/ChainComplex.m2 @@ -53,8 +53,10 @@ concentration ComplexMap := Sequence => f -> ( max Complex := ZZ => C -> max concentration C min Complex := ZZ => C -> min concentration C -complex = method(Options => {Base=>0}) -complex HashTable := Complex => opts -> maps -> ( +complexOptions = {Base => 0} +--complex = method(Options => {Base=>0}) +complex = method(Options => true) +complex HashTable := Complex => complexOptions >> opts -> maps -> ( spots := sort keys maps; if #spots === 0 then error "expected at least one matrix"; @@ -80,7 +82,7 @@ complex HashTable := Complex => opts -> maps -> ( C.dd = map(C,C,maps,Degree=>-1); C ) -complex List := Complex => opts -> L -> ( +complex List := Complex => complexOptions >> opts -> L -> ( -- L is a list of matrices or a list of modules if not instance(opts.Base, ZZ) then error "expected Base to be an integer"; @@ -104,7 +106,10 @@ complex List := Complex => opts -> L -> ( ); error "expected a list of matrices or a list of modules"; ) -complex Module := Complex => opts -> (M) -> ( +complex Matrix := Complex => complexOptions >> opts -> M -> ( + complex({M}, opts) + ) +complex Module := Complex => complexOptions >> opts -> (M) -> ( if not instance(opts.Base, ZZ) then error "complex: expected base to be an integer"; if M.cache.?Complex and opts.Base === 0 then return M.cache.Complex; @@ -118,9 +123,9 @@ complex Module := Complex => opts -> (M) -> ( C.dd = map(C,C,0,Degree=>-1); C ) -complex Ring := Complex => opts -> R -> complex(R^1, opts) -complex Ideal := Complex => opts -> I -> complex(module I, opts) -complex Complex := Complex => opts -> C -> ( +complex Ring := Complex => complexOptions >> opts -> R -> complex(R^1, opts) +complex Ideal := Complex => complexOptions >> opts -> I -> complex(module I, opts) +complex Complex := Complex => complexOptions >> opts -> C -> ( -- all this does is change the homological degrees -- so the concentration begins at opts.Base (lo,hi) := concentration C; @@ -133,7 +138,7 @@ complex Complex := Complex => opts -> C -> ( complex(L, Base=>opts.Base) ) ) -complex ComplexMap := Complex => opts -> f -> ( +complex ComplexMap := Complex => complexOptions >> opts -> f -> ( if degree f === -1 then ( if source f =!= target f then error "expected a differential"; (lo,hi) := concentration source f; @@ -483,6 +488,8 @@ defaultLengthLimit = (R, baselen, len) -> ( len ) +-- MES: note, this list of options is all of the ones from resolution, in the Core, +-- except FastNonminimal is not present (use instead: Strategy => Nonminimal). freeResolution = method(Options => { StopBeforeComputation => false, LengthLimit => infinity, -- (infinity means numgens R) @@ -533,6 +540,29 @@ freeResolution Matrix := ComplexMap => opts -> f -> extend( matrix f ) +-- TODO: reinstate these once we remove all uses of ChainComplex... +-- resolution Module := Complex => opts -> M -> ( +-- o := pairs opts; +-- o2 := new OptionTable from select(pairs opts, x -> x#0 =!= FastNonminimal); +-- if opts.FastNonminimal then ( +-- o2 = o2 ++ {Strategy => Nonminimal}; +-- << "warning: `FastNonminimal => true` is deprecated. Use: res(..., Strategy => Nonminimal) instead" << endl; +-- ); +-- freeResolution(M, o2) +-- ) +-- resolution Ideal := Complex => opts -> I -> resolution(comodule I, opts) +-- resolution MonomialIdeal := Complex => opts -> I -> resolution(comodule ideal I, opts) +-- resolution Matrix := ComplexMap => opts -> f -> extend( +-- resolution(target f, opts), +-- resolution(source f, opts), +-- matrix f +-- ) + +complete Complex := C -> C +complete ComplexMap := F -> F +nullhomotopy ComplexMap := F -> nullHomotopy F +status Complex := C -> << "resolution status of a Complex needs to be implemented" << endl; + isHomogeneous Complex := (C) -> isHomogeneous dd^C -- These next two local functions are lifted from previous code in m2/chaincomplexes.m2 @@ -592,6 +622,11 @@ poincareN Complex := C -> ( f ) +rank Complex := ZZ => C -> ( + (lo, hi) := concentration C; + sum for i from lo to hi list (-1)^i * rank C_i + ) + minimalPresentation Complex := prune Complex := Complex => opts -> (cacheValue symbol minimalPresentation)(C -> ( -- opts is ignored here @@ -783,15 +818,15 @@ homomorphism(ZZ, Matrix, Complex) := ComplexMap => (i, f, E) -> ( if not E.cache.?homomorphism then error "expected target of map to be of the form 'Hom(C,D)'"; if not isFreeModule source f or not rank source f == 1 then error "expected source of map to be free of rank 1"; - if E_i =!= target f then ( - -- if f arises from a kernel computation, then the target is not E_i - -- it is instead a submodule of E_i. The next line provides the 'f' - -- that maps directly to E_i. - -- BUT: if you just use 'ambient f', which seems like it should - -- work, the problem is that the target of the map 'ambient f' - -- doesn't retain the information about the components of E_i - f = map(E_i, source f, super f); - ); + -- we redefine f for two reasons: + -- (1) there might be a bug in 'super Matrix' where it gives a module which is === to E_i + -- but is missing the direct sum component information. + -- (2) If f is a map to the kernel of the differential then we use 'super' + -- to make the target exactly (this) E_i (with component info). + f = if E_i == target f then + map(E_i, source f, f) + else + map(E_i, source f, super f); (C,D) := E.cache.homomorphism; (lo,hi) := concentration C; H := hashTable for j from lo to hi list j => @@ -899,26 +934,65 @@ Complex ** RingMap := Complex => (C, phi) -> tensor(phi, C) -------------------------------------------------------------------- -- resolutions ----------------------------------------------------- -------------------------------------------------------------------- +-- private function nextLambda = method() -nextLambda ComplexMap := ComplexMap => (lambda) -> ( +-- nextLambda ComplexMap := ComplexMap => (lambda) -> ( +-- C := target lambda; +-- L0 := source lambda; +-- (lo,hi) := concentration L0; +-- D := cone naiveTruncation(lambda, (hi,hi+2), (hi-1, hi)); +-- HC1 := HH_(hi+1) D; +-- pHC1 := prune HC1; +-- if pHC1 == 0 then return null; +-- a1 := inducedMap(pHC1, cover pHC1); +-- a2 := pHC1.cache.pruningMap; +-- g1 := map(D_(hi+1), source gens HC1, (gens HC1) // (gens D_(hi+1))); +-- g2 := map(HC1, source gens HC1, 1); +-- h := g1 * ((a2 * a1)//g2); +-- L1 := complex(append(for i from lo+1 to hi list dd^L0_i, h^[0]), Base=>lo); +-- map(C,L1,i -> if i === hi+1 then -h^[1] else lambda_i) +-- ) +-- -- private function +-- nextLambdaEpi = method() +-- nextLambdaEpi(ComplexMap) := ComplexMap => (lambda) -> ( +-- -- This version is for creating an epimorphism +-- C := target lambda; +-- L0 := source lambda; +-- (lo,hi) := concentration L0; +-- D := cone naiveTruncation(lambda, (hi,hi+2), (hi-1, hi)); +-- ZC1 := ker dd^D_(hi+1); +-- --HC1 := HH_(hi+1) D; +-- pZC1 := prune ZC1; +-- if pZC1 == 0 then return null; +-- a1 := inducedMap(pZC1, cover pZC1); +-- a2 := pZC1.cache.pruningMap; +-- g1 := map(D_(hi+1), source gens ZC1, (gens ZC1) // (gens D_(hi+1))); +-- g2 := map(ZC1, source gens ZC1, 1); +-- h := g1 * ((a2 * a1)//g2); +-- L1 := complex(append(for i from lo+1 to hi list dd^L0_i, h^[0]), Base=>lo); +-- map(C,L1,i -> if i === hi+1 then -h^[1] else lambda_i) +-- ) +-- private function +nextLambda(ComplexMap, Boolean) := ComplexMap => (lambda, isEpi) -> ( + -- This version is for creating an epimorphism C := target lambda; L0 := source lambda; (lo,hi) := concentration L0; D := cone naiveTruncation(lambda, (hi,hi+2), (hi-1, hi)); - HC1 := HH_(hi+1) D; - pHC1 := prune HC1; - if pHC1 == 0 then return null; - a1 := inducedMap(pHC1, cover pHC1); - a2 := pHC1.cache.pruningMap; - g1 := map(D_(hi+1), source gens HC1, (gens HC1) // (gens D_(hi+1))); - g2 := map(HC1, source gens HC1, 1); + keyModule := if isEpi then ker dd^D_(hi+1) else HH_(hi+1) D; + pkeyModule := prune keyModule; + if pkeyModule == 0 then return null; + a1 := inducedMap(pkeyModule, cover pkeyModule); + a2 := pkeyModule.cache.pruningMap; + g1 := map(D_(hi+1), source gens keyModule, (gens keyModule) // (gens D_(hi+1))); + g2 := map(keyModule, source gens keyModule, 1); h := g1 * ((a2 * a1)//g2); L1 := complex(append(for i from lo+1 to hi list dd^L0_i, h^[0]), Base=>lo); map(C,L1,i -> if i === hi+1 then -h^[1] else lambda_i) ) -resolutionMap = method(Options => options freeResolution) -resolutionMap Complex := ComplexMap => opts -> C -> ( +resolutionMapPrivate = method(Options => options freeResolution) +resolutionMapPrivate(Complex, Boolean) := ComplexMap => opts -> (C, isEpi) -> ( if opts.LengthLimit < 0 then error "expected a non-negative value for LengthLimit"; if not C.cache.?resolutionMap or C.cache.resolutionMap.cache.LengthLimit < opts.LengthLimit then ( @@ -937,7 +1011,7 @@ resolutionMap Complex := ComplexMap => opts -> C -> ( local g; -- how to implement length limit here. What does length limit mean? while ( - g = nextLambda f; + g = nextLambda(f, isEpi); (len <= hi - lo or g =!= null) and len <= lengthlimit ) do ( if g === null then ( @@ -964,6 +1038,12 @@ resolutionMap Complex := ComplexMap => opts -> C -> ( else fC ) +resolutionMap = method(Options => options freeResolution) +resolutionMap Complex := ComplexMap => opts -> C -> resolutionMapPrivate(C, false, opts) + +epicResolutionMap = method(Options => options freeResolution) +epicResolutionMap Complex := ComplexMap => opts -> C -> resolutionMapPrivate(C, true, opts) + resolution Complex := opts -> C -> ( -- TODO: remove this hack once resolution doesn't have FastNonminimal anymore and is defined in Complexes). opts1 := new OptionTable from for k in keys opts list if k === FastNonminimal then continue else k => opts#k; diff --git a/M2/Macaulay2/packages/Complexes/ChainComplexDoc.m2 b/M2/Macaulay2/packages/Complexes/ChainComplexDoc.m2 index 6d303e275d1..492498a3169 100644 --- a/M2/Macaulay2/packages/Complexes/ChainComplexDoc.m2 +++ b/M2/Macaulay2/packages/Complexes/ChainComplexDoc.m2 @@ -173,6 +173,7 @@ doc /// TO (Ext, ZZ, Module, Module), TO (Ext, ZZ, Matrix, Module), TO (Ext, ZZ, Module, Matrix), + TO (Ext, Module, Module), TO (Hom, Complex, Complex), TO (Hom, ComplexMap, ComplexMap), TO (homomorphism, ComplexMap), @@ -408,9 +409,10 @@ doc /// doc /// Key - complex (complex, List) - [complex, Base] + complex + (complex, Matrix) + [(complex, List), Base] Base Headline make a chain complex @@ -418,7 +420,7 @@ doc /// complex L Inputs L:List - of maps + of maps, or a single matrix. Base => ZZ the index of the target of the first map in the differential. @@ -483,6 +485,14 @@ doc /// HH C prune HH C prune HH_1 C + Text + Having the input be a matrix is equivalent to having it be + a singleton list containing this matrix. + Example + C' = complex F1 + assert isWellDefined C' + C'' = complex(F1, Base => 3) + assert isWellDefined C'' Caveat This constructor minimizes computation and does very little error checking. To verify that a complex @@ -2341,10 +2351,8 @@ doc /// Usage D = C1 ** C2 Inputs - C1:Complex - or @ofClass Module@ - C2:Complex - or @ofClass Module@ + C1:{Complex, Module} + C2:{Complex, Module} Outputs D:Complex tensor product of {\tt C1} and {\tt C2} @@ -2401,19 +2409,17 @@ doc /// Usage D = Hom(C1,C2) Inputs - C1:Complex - or @ofClass Module@, or @ofClass Ring@ - C2:Complex - or @ofClass Module@, or @ofClass Ring@ + C1:{Complex, Module, Ring} + C2:{Complex, Module, Ring} Outputs D:Complex the complex of homomorphisms between {\tt C1} and {\tt C2} Description Text The complex of homomorphisms is a complex $D$ whose $i$th component is - the direct sum of $Hom(C1_j, C2_{j+i})$ over all $j$. - The differential on $Hom(C1_j, C2_{j+i})$ is the differential - $Hom(id_{C1}, dd^{C2}) + (-1)^j Hom(dd^{C1}, id_{C2})$. + the direct sum of $\operatorname{Hom}(C1_j, C2_{j+i})$ over all $j$. + The differential on $\operatorname{Hom}(C1_j, C2_{j+i})$ is the differential + $\operatorname{Hom}(id_{C1}, dd^{C2}) + (-1)^j \operatorname{Hom}(dd^{C1}, id_{C2})$. $dd^{C1} \otimes id_{C2} + (-1)^j id_{C1} \otimes dd^{C2}$. In particular, for this operation to be well-defined, both @@ -2425,7 +2431,7 @@ doc /// dd^D assert isWellDefined D Text - The homology of this complex is $Hom(C, ZZ/101)$ + The homology of this complex is $\operatorname{Hom}(C, ZZ/101)$ Example prune HH D == Hom(C, coker vars S) Text @@ -2472,9 +2478,9 @@ doc /// g = homomorphism f Inputs f:ComplexMap - a map of the form $f : R^1 \to Hom(C, D)$, where + a map of the form $f : R^1 \to \operatorname{Hom}(C, D)$, where $C$ and $D$ are complexes, - $Hom(C,D)$ has been previously computed, and $R$ is + $\operatorname{Hom}(C,D)$ has been previously computed, and $R$ is the underlying ring of these complexes Outputs g:ComplexMap @@ -2482,7 +2488,7 @@ doc /// Description Text As a first example, consider two Koszul complexes $C$ and $D$. - From a random map $f : R^1 \to Hom(C, D)$, we construct + From a random map $f : R^1 \to \operatorname{Hom}(C, D)$, we construct the corresponding map of chain complexes $g : C \to D$. Example R = ZZ/101[a,b,c] @@ -2495,9 +2501,9 @@ doc /// isWellDefined g assert not isCommutative g Text - The map $g : C \to D$ corresponding to a random map into $Hom(C,D)$ + The map $g : C \to D$ corresponding to a random map into $\operatorname{Hom}(C,D)$ does not generally commute with the differentials. However, if the - element of $Hom(C,D)$ is a cycle, then the corresponding map does commute. + element of $\operatorname{Hom}(C,D)$ is a cycle, then the corresponding map does commute. Example f = randomComplexMap(H, complex R^{-2}, Cycle => true) isWellDefined f @@ -2543,12 +2549,12 @@ doc /// from $C$ to $D$ Outputs f:ComplexMap - a map of the form $f : R^1 \to Hom(C, D)$, where + a map of the form $f : R^1 \to \operatorname{Hom}(C, D)$, where $R$ is the underlying ring of these complexes Description Text As a first example, consider two Koszul complexes $C$ and $D$. - From a random map $f : R^1 \to Hom(C, D)$, we construct + From a random map $f : R^1 \to \operatorname{Hom}(C, D)$, we construct the corresponding map of chain complexes $g : C \to D$. Example R = ZZ/101[a,b,c] @@ -2559,9 +2565,9 @@ doc /// f = homomorphism' g isWellDefined f Text - The map $g : C \to D$ corresponding to a random map into $Hom(C,D)$ + The map $g : C \to D$ corresponding to a random map into $\operatorname{Hom}(C,D)$ does not generally commute with the differentials. However, if the - element of $Hom(C,D)$ is a cycle, then the corresponding map does commute. + element of $\operatorname{Hom}(C,D)$ is a cycle, then the corresponding map does commute. Example g = randomComplexMap(D, C, Cycle => true, InternalDegree => 3) isWellDefined g @@ -2604,7 +2610,7 @@ doc /// method returns the corresponding map of complexes of degree $i$. Text As a first example, consider two Koszul complexes $C$ and $D$. - From a random map $f \colon R^1 \to Hom(C, D)$, we construct + From a random map $f \colon R^1 \to \operatorname{Hom}(C, D)$, we construct the corresponding map of chain complexes $g \colon C \to D$. Example R = ZZ/101[a,b,c]; @@ -2616,9 +2622,9 @@ doc /// assert isWellDefined g assert not isCommutative g Text - The map $g \colon C \to D$ corresponding to a random map into $Hom(C,D)$ + The map $g \colon C \to D$ corresponding to a random map into $\operatorname{Hom}(C,D)$ does not generally commute with the differentials. However, if the - element of $Hom(C,D)$ is a cycle, then the corresponding map does commute. + element of $\operatorname{Hom}(C,D)$ is a cycle, then the corresponding map does commute. Example h = randomComplexMap(E, complex R^{-2}, Cycle => true, Degree => -1) f = h_0 @@ -2742,7 +2748,7 @@ doc /// :Complex Description Text - The dual of a complex $C$ is by definition $Hom(C, R)$, where $R$ is the ring of $C$. + The dual of a complex $C$ is by definition $\operatorname{Hom}(C, R)$, where $R$ is the ring of $C$. Example S = ZZ/101[a..d]; B = intersect(ideal(a,c),ideal(b,d)) @@ -4363,6 +4369,66 @@ doc /// freeResolution /// +doc /// + Key + (Ext,Module,Module) + (Ext,Ideal,Ideal) + (Ext,Ideal,Module) + (Ext,Ideal,Ring) + (Ext,Module,Ideal) + (Ext,Module,Ring) + Headline + total Ext module + Usage + Ext(M, N) + Inputs + M:{Module, Ideal, Ring} + that is homogeneous + N:{Module, Ideal, Ring} + over the same ring as $M$, that is also homogeneous + Outputs + :Module + the $\operatorname{Ext}$ module of $M$ and $N$, as a + multigraded module, with the modules + $\operatorname{Ext}^i(M,N)$ for all values of $i$ + appearing simultaneously. + Description + Text + The computation of the total Ext module is possible for modules over the + ring $R$ of a complete intersection, according to the algorithm + of Shamash-Eisenbud-Avramov-Buchweitz. The result is provided as a finitely + presented module over a new ring with one additional variable of degree + $\{-2,-d\}$ for each equation of degree $d$ defining $R$. The + variables in this new ring have degree length $1$ more than the degree length of + the original ring. In other words, it is multigraded with the + degree $d$ part of $\operatorname{Ext}^n(M,N)$ appearing as the degree + $\{-n,d\}$ part of $\operatorname{Ext}(M,N)$. + Text + We illustrate this in the following example. + Example + R = QQ[x,y]/(x^3,y^2); + N = cokernel matrix {{x^2, x*y}} + H = Ext(N,N); + ring H + S = ring H; + H + isHomogeneous H + rank source basis( { -2,-3 }, H) + rank source basis( { -3 }, Ext^2(N,N) ) + rank source basis( { -4,-5 }, H) + rank source basis( { -5 }, Ext^4(N,N) ) + hilbertSeries H + hilbertSeries(H,Order=>11) + Text + For more information, see the chapter {\it Resolutions and cohomology over complete intersections} + by Luchezar L. Avramov and Daniel R. Grayson, in the book + @HREF("https://macaulay2.com/Book/ComputationsBook/book/book.pdf", "Computatations in Algebraic Geometry with Macaulay2")@. + Text + The result of the computation is cached for future reference. + SeeAlso + "computing with Ext" +/// + /// Key Headline @@ -4375,3 +4441,5 @@ doc /// Caveat SeeAlso /// + + diff --git a/M2/Macaulay2/packages/Complexes/ChainComplexMap.m2 b/M2/Macaulay2/packages/Complexes/ChainComplexMap.m2 index 99482cfdf0f..478f2457e4e 100644 --- a/M2/Macaulay2/packages/Complexes/ChainComplexMap.m2 +++ b/M2/Macaulay2/packages/Complexes/ChainComplexMap.m2 @@ -308,7 +308,11 @@ ComplexMap == ZZ := Boolean => (f,n) -> ( ) ZZ == ComplexMap := Boolean => (n,f) -> f == n -RingElement * ComplexMap := (r,f) -> ( +Number * ComplexMap := +RingElement * ComplexMap := ComplexMap => (r,f) -> ( + if ring r =!= ring f then + try r = promote(r,ring f) + else error "can't promote scalar to ring of complex homomorphism"; df := degree f; (lo,hi) := (source f).concentration; maps := hashTable for i from lo to hi list i => ( @@ -321,7 +325,11 @@ RingElement * ComplexMap := (r,f) -> ( result ) +ComplexMap * Number := ComplexMap * RingElement := (f,r) -> ( + if ring r =!= ring f then + try r = promote(r,ring f) + else error "can't promote scalar to ring of complex homomorphism"; df := degree f; (lo,hi) := (source f).concentration; maps := hashTable for i from lo to hi list i => ( @@ -334,16 +342,6 @@ ComplexMap * RingElement := (f,r) -> ( result ) -Number * ComplexMap := (r,f) -> ( - try r = promote(r,ring f) else error "can't promote scalar to ring of complex homomorphism"; - r * f - ) - -ComplexMap * Number := (f,r) -> ( - try r = promote(r,ring f) else error "can't promote scalar to ring of complex homomorphism"; - f * r - ) - - ComplexMap := (f) -> ( result := (-1)*f; if isCommutativeCached f then @@ -636,6 +634,7 @@ Hom(Matrix, ComplexMap) := ComplexMap => opts -> (f,g) -> Hom(map(complex target f, complex source f, i -> if i === 0 then f), g, opts) dual ComplexMap := ComplexMap => {} >> o -> f -> Hom(f, (ring f)^1) +transpose ComplexMap := ComplexMap => f -> dual f homomorphism ComplexMap := ComplexMap => (h) -> ( -- h should be a homomorphism of complexes from R^1[-i] --> E = Hom(C,D) @@ -1069,9 +1068,6 @@ coimage ComplexMap := Complex => f -> ( -- homotopy -------------------------------------------------------- -------------------------------------------------------------------- isNullHomotopyOf = method() -isNullHomotopic = method() -nullHomotopy = method() -- this function attempts to construct one, might fail - isNullHomotopyOf(ComplexMap, ComplexMap) := (h, f) -> ( -- returns true if h is a null homotopy for f : C --> D. -- if debugLevel > 0, then more info as to where it is not, is given @@ -1105,12 +1101,20 @@ isNullHomotopyOf(ComplexMap, ComplexMap) := (h, f) -> ( ) ) --- TODO: we are keeping this version so that we may compare the --- more general version with this version, at a later date. -nullHomotopyFreeSource = f -> ( - -- f:ComplexMap - -- key assumption: 'source f' is a complex of free modules +isNullHomotopic = method() +isNullHomotopic ComplexMap := Boolean => f -> ( + g := homomorphism' f; + H := target g; + d := degree f; + g1 := g_0 // dd^H_(d+1); + g_0 == dd^H_(d+1) * g1 + ) + +nullHomotopyFreeToExact = f -> ( + -- key assumption: 'source f' is a complex of free modules AND the target is exact -- result is a ComplexMap h : C --> D, of degree degree(f)+1 + if not isFree source f then error "expected source of complex map to be free"; + -- Note: we do not check that the target is exact! C := source f; D := target f; deg := degree f + 1; @@ -1118,32 +1122,22 @@ nullHomotopyFreeSource = f -> ( (lo,hi) := concentration f; for i from lo to hi do ( if hs#?(i-1) then ( - rem := (f_i - hs#(i-1) * dd^C_i) % (dd^D_(i+deg)); - if rem != 0 then return null; -- error "can't construct homotopy"; + --rem := (f_i - hs#(i-1) * dd^C_i) % (dd^D_(i+deg)); + --if rem != 0 then return null; -- error "can't construct homotopy"; hs#i = (f_i - hs#(i-1) * dd^C_i) // (dd^D_(i+deg)) ) else ( - rem = f_i % dd^D_(i+deg); - if rem != 0 then return null; -- error "can't construct homotopy"; + --rem = f_i % dd^D_(i+deg); + --if rem != 0 then return null; -- error "can't construct homotopy"; hs#i = f_i // dd^D_(i+deg) ) ); map(D, C, new HashTable from hs, Degree => deg) ) -isNullHomotopic ComplexMap := Boolean => f -> ( - g := homomorphism' f; - H := target g; - d := degree f; - g1 := g_0 // dd^H_(d+1); - g_0 == dd^H_(d+1) * g1 - ) - -nullHomotopy ComplexMap := ComplexMap => f -> ( - -- we check that the source is free, as that can be much faster - -- TODO: nullHomotopy should perhaps be hook-ified. - result := if isFree source f then nullHomotopyFreeSource f; - if result =!= null then return result; +nullHomotopy = method(Options => true) -- this function attempts to construct one, might fail +nullHomotopy ComplexMap := ComplexMap => {FreeToExact => false} >> opts -> f -> ( + if opts.FreeToExact then return nullHomotopyFreeToExact f; g := homomorphism' f; H := target g; d := degree f; @@ -1333,7 +1327,7 @@ connectingMap(ComplexMap, ComplexMap) := ComplexMap => opts -> (g, f) -> ( assert isWellDefined p; assert isWellDefined q; ); - HH(q) * (HH(p))^-1 + - HH(q) * (HH(p))^-1 -- sign is negative because of the def of cylinder. ) longExactSequence = method(Options => true) @@ -1379,14 +1373,15 @@ horseshoeResolution(Matrix, Matrix) := Sequence => opts -> (g,f) -> ( horseshoeResolution(complex{g,f}, opts) ) -connectingExtMap = method(Options => {Concentration => null}) +connectingExtMap = method(Options => {Concentration => null, + LengthLimit => infinity}) connectingExtMap(Module, Matrix, Matrix) := ComplexMap => opts -> (M, g, f) -> ( - F := freeResolution M; - connectingMap(Hom(F, g), Hom(F, f), opts) + F := freeResolution(M, LengthLimit => opts.LengthLimit); + connectingMap(Hom(F, g), Hom(F, f), Concentration => opts.Concentration) ) connectingExtMap(Matrix, Matrix, Module) := ComplexMap => opts -> (g, f, N) -> ( - (g', f') := horseshoeResolution(g, f); - G := freeResolution N; + (g', f') := horseshoeResolution(g, f, LengthLimit => opts.LengthLimit); + G := freeResolution(N, LengthLimit => opts.LengthLimit); -- TODO: the indexing on opts.Concentration needs to be negated - connectingMap(Hom(f', G), Hom(g', G), opts) + connectingMap(Hom(f', G), Hom(g', G), Concentration => opts.Concentration) ) diff --git a/M2/Macaulay2/packages/Complexes/ChainComplexMapDoc.m2 b/M2/Macaulay2/packages/Complexes/ChainComplexMapDoc.m2 index 71c34731949..342288a29db 100644 --- a/M2/Macaulay2/packages/Complexes/ChainComplexMapDoc.m2 +++ b/M2/Macaulay2/packages/Complexes/ChainComplexMapDoc.m2 @@ -1271,6 +1271,7 @@ doc /// doc /// Key (dual, ComplexMap) + (transpose, ComplexMap) Headline the dual of a map of complexes Usage @@ -1299,10 +1300,16 @@ doc /// D' = (freeResolution coker matrix{{a^2,a*b,c^3}})[-1] f' = randomComplexMap(D', D) dual(f' * f) == dual f * dual f' + Text + For backwards compatibility, one can also use {\tt transpose}. + Example + h' = transpose f + assert(h == h') SeeAlso (Hom, ComplexMap, ComplexMap) (randomComplexMap, Complex, Complex) (dual, Matrix) + (transpose, Matrix) /// doc /// @@ -3401,10 +3408,6 @@ doc /// assert isWellDefined h' assert(degree h' === degree g + 1) assert not isNullHomotopyOf(h', g) - Text - For developers: when the source of $f$ is a free complex, - a procedure, that is often faster, is attempted. In the - general case this method uses the Hom complex. Caveat The output is only a null homotopy when one exists. SeeAlso @@ -4348,6 +4351,201 @@ doc /// "Working with Ext" /// +/// + Key + Headline + Usage + Inputs + Outputs + Description + Text + I don't know how to create morphisms of complexes which are quasi-isomorphisms but not epic... + One way (doesn't seem to exactly work): start with a map of two complexes, create their liftings, and construct the map between their free resolutions. + Example + restart + needsPackage "Complexes" + kk = ZZ/101; + S = kk[x_0..x_3] + K1 = koszulComplex{x_0*x_1, x_1*x_2} ** + K2 = koszulComplex{x_0*x_1, x_1*x_2, x_1^2-x_0*x_2, x_2^2-x_1*x_3} + phi = randomComplexMap(K2, K1, Cycle => true) + resolution K2 + + + + Example + S = kk[x_0..x_3, Degrees => {2:{1,0}, 2:{0,1}}] + K1 = koszulComplex{x_0, x_1} + K2 = koszulComplex{x_2, x_3} + K = K1 ** K2 + K0 = K ** coker vars S + phi = resolutionMap K0 + prune coker phi -- surjective + prune ker phi -- not injective... + B = ideal(x_0, x_1) * ideal(x_2, x_3) + K = koszulComplex gens B + F = freeResolution B + K0 = K ** coker vars S + F0 = F ** coker vars S + + prune HH F0 + prune HH K0 + prune HH F + prune HH K + phi = randomComplexMap(F, K, Cycle => true) + isHomogeneous F + isHomogeneous K + prune coker phi + prune ker phi -- phi is neither injective nor surjective + phi0 = randomComplexMap(F0, K0, Cycle => true) + prune coker phi0 + prune ker phi0 -- phi is neither injective nor surjective + + Caveat + SeeAlso +/// + +/// + Key + "Standard maps for complexes" + Headline + Standard maps for complexes + Description + Text + TODO: naturality of these constructions. + Text + @SUBSECTION "Unitor"@ + Text + Let $C$ be an $R$-complex. There is an isomorphism from $R \otimes_R C \to C$ given by $r \otimes m \mapsto rm$. + In \emph{Macaulay2}, this isomorphism is simply the identity map on $C$. + Example + R = ZZ/11[a..c] + C = koszulComplex{a,b,c} + R ** C == C + unitor = map(C, R**C, 1) + assert(unitor == id_C) + assert isWellDefined unitor + Text + @SUBSECTION "Counitor"@ + Text + Let $C$ be an $R$-complex. There is an isomorphism from $C \to Hom(R, C)$ given by + $m \mapsto (r \mapsto rm)$. + In \emph{Macaulay2}, this isomorphism is simply the identity map on $C$. + Example + R = ZZ/11[a..c] + C = koszulComplex{a,b,c} + dd^(Hom(R, C)), dd^C + Text + Note that the signs of the odd degree differentials are not the same. + Example + counitor = map(Hom(R, C), C, i -> if member(i % 4, {0,1}) then id_(C_i) else -id_(C_i)) + isWellDefined counitor + isComplexMorphism counitor + unitor = map(C, R**C, 1) + assert(unitor == id_C) + assert isWellDefined unitor + Example + R = ZZ/11[vars(0..17)] + m1 = genericMatrix(R,a,3,3) + m2 = genericMatrix(R,j,3,3) + I = ideal(m1*m2-m2*m1) + C = freeResolution I + counitor = map(Hom(R, C), C, i -> if member(i % 4, {0,1}) then id_(C_i) else -id_(C_i)); + isWellDefined counitor + isComplexMorphism counitor + Text + Counitor is compatible with shifts in homological degree. + Example + counitor = map(Hom(R, C[1]), C[1], i -> if member(i % 4, {0,1}) then id_((C[1])_i) else -id_((C[1])_i)); + assert isWellDefined counitor + assert isComplexMorphism counitor + counitor = map(Hom(R, C[-1]), C[-1], i -> if member(i % 4, {0,1}) then id_((C[-1])_i) else -id_((C[-1])_i)); + assert isWellDefined counitor + assert isComplexMorphism counitor + Text + @SUBSECTION "Tensor commutativity"@ + Text + Example + R = ZZ/11[a..d] + C = koszulComplex{a,b,c,d} + D = koszulComplex{a^2, b^2, c^2-d^2} + phi = tensorCommutativity(C, D); + assert isWellDefined phi + assert isComplexMorphism phi + assert(ker phi == 0 and coker phi == 0) + assert(source phi === C ** D) + assert(target phi === D ** C) + assert(C ** D != D ** C) + Example + (C, D) = (C[-1], D[3]); + phi = tensorCommutativity(C, D); + assert isWellDefined phi + assert isComplexMorphism phi + assert(ker phi == 0 and coker phi == 0) + assert(source phi === C ** D) + assert(target phi === D ** C) + assert(C ** D != D ** C) + Text + @SUBSECTION "Tensor Associativity"@ + Text + R = ZZ/11[a..d]; + A = koszulComplex{a,b,c,d} + B = koszulComplex{a^2, b^2, c^2-d^2} + C = koszulComplex{b-1,c-1} + phi = tensorAssociativity(A, B, C); + assert isWellDefined phi + assert isComplexMorphism phi + assert(ker phi == 0 and coker phi == 0) + assert(source phi === A ** (B ** C)) + assert(target phi === (A ** B) ** C) + Example + (A, B, C) = (A[3], B[-1], C[2]); + phi = tensorAssociativity(A, B, C); + assert isWellDefined phi + assert isComplexMorphism phi + assert(ker phi == 0 and coker phi == 0) + assert(source phi === A ** (B ** C)) + assert(target phi === (A ** B) ** C) + Text + @SUBSECTION "Hom swap"@ + Text + First, we start with the version: $R$ is commutative, and + all the complexes are $R$-complexes. + + For $A, B, C$ complexes over $R$, the {\bf Hom swap} + map is the $R$-complex morphism from + $\Hom_R(A, \Hom_R(B, C)) \to \Hom_R(B, \Hom_R(A, C)),$ + defined as follows. TODO: finish. + Text + First, we consider Hom-swap and adjunction for modules. + Example + R = ZZ/11[a..d]; + C = cokernel matrix{{a,b,c}} + B = (cokernel matrix{{a,b,c},{b,c,d}}) ** R^{3} + A = image matrix{{a,b,c},{b,c,0}} + A = R^{0,1} + C = R^{100, 101, 102} + B = R^{10, 11, 12, 13} + Hom(A,C) + Hom(B,C) + HABC = Hom(A, Hom(B,C)) + HBAC = Hom(B, Hom(A,C)) + f = tensorCommutativity(dual A, dual B) ** id_C + source f === HABC + target f === HBAC + Example + R = ZZ/11[a..d]; + A = koszulComplex{a,b,c,d} + B = koszulComplex{a^2, b^2, c^2-d^2} + C = koszulComplex{b-1,c-1} + E1 = Hom(A, Hom(B, C)) + E2 = Hom(B, Hom(A, C)) + E1.dd_2, E2.dd_2 + Text + @SUBSECTION "Adjunction"@ + SeeAlso +/// + /// Key Headline @@ -4374,3 +4572,4 @@ doc /// TODO: email from Janina Letz on March 23, 2021, has some bugs in Complexes... /// +end-- diff --git a/M2/Macaulay2/packages/Complexes/ChainComplexTests.m2 b/M2/Macaulay2/packages/Complexes/ChainComplexTests.m2 index 6c9a2e2b1f0..179d6c5d388 100644 --- a/M2/Macaulay2/packages/Complexes/ChainComplexTests.m2 +++ b/M2/Macaulay2/packages/Complexes/ChainComplexTests.m2 @@ -1344,31 +1344,34 @@ TEST /// g1 = randomComplexMap(CJ, CI, Cycle=>true) g2 = randomComplexMap(CK, CJ, Cycle=>true) assert isWellDefined g1 - assert isCommutative g1 + assert isComplexMorphism g1 assert isWellDefined g2 - assert isCommutative g2 + assert isComplexMorphism g2 fCI = resolutionMap CI fCJ = resolutionMap CJ fCK = resolutionMap CK g = g2 * g1; assert isWellDefined g - assert isCommutative g + assert isComplexMorphism g g1' = liftMapAlongQuasiIsomorphism(g1 * fCI, fCJ); g2' = liftMapAlongQuasiIsomorphism(g2 * fCJ, fCK); assert isWellDefined g1' - assert isCommutative g1' + assert isComplexMorphism g1' assert isWellDefined g2' - assert isCommutative g2' + assert isComplexMorphism g2' g' = liftMapAlongQuasiIsomorphism(g * fCI, fCK); + assert isWellDefined g' + assert isComplexMorphism g' diffg' = g2' * g1' - g'; assert isNullHomotopic diffg' - h = nullHomotopy diffg'; + h = nullHomotopy diffg' assert isWellDefined h - assert isNullHomotopyOf(h, diffg') + assert(degree h == 1) + debugLevel = 1 + assert isNullHomotopyOf(h, diffg') -- MES FAILURE #38 diffg'_-1 -- just to see the nontrivial-ness of the differentials /// - TEST /// -* restart @@ -2214,3 +2217,150 @@ needsPackage "Complexes" resolution X resolution(minimize X) /// + +TEST /// +-* + restart + needsPackage "Complexes" +*- + S = ZZ/101[x,y] + K2 = koszulComplex{x,y} + + H = Hom(K2, K2) + ZH0 = ker H.dd_0 + numgens ZH0 + + f = ZH0_{0} + assert(target super f == H_0) + assert(target super f === H_0) -- warning: this target is missing direct sum information. + g = homomorphism(0, f, H) -- the corresponding complex morphism K2 --> K2 FAILS + assert isWellDefined g + assert(source g == K2) + assert(target g == K2) + assert(g == id_K2) + -- original reason for this test: + -- target f is H_0, except it doesn't have the stashed direct sum components... +/// + +TEST /// +-* + restart + needsPackage "Complexes"; +*- + C = koszulComplex{1,3,5} + assert isWellDefined(3*id_C) + + C = koszulComplex{1_QQ,3,5} + assert isWellDefined(3*id_C) + assert isWellDefined((3/2)*id_C) + + S = ZZ[] + C = koszulComplex{1_S,3,5} + assert isWellDefined(3*id_C) + + C = koszulComplex{1_RR,3,5} + assert isWellDefined C + --assert isWellDefined(3*id_C) -- FAILS: TODO: get isCommutative RR_53, etc to work + + C = koszulComplex{1_(RR_100),3,5} + assert isWellDefined C + -- assert isWellDefined(3*id_C) -- FAILS + + S = ZZ/11 + C = koszulComplex{1_S,3,5} + assert isWellDefined(3*id_C) + + -- here is where we first noticed this bug. + needsPackage "SimplicialComplexes"; + S = ZZ[a,b,c] + T = ZZ[a,b,c,d,e,f] + use S + D = simplicialComplex {a*b, b*c, a*c} -- triangle + use T + E = simplicialComplex {a*b*d*e, a*b*d*f, a*b*e*f, + a*c*d*e, a*c*d*f, a*c*e*f, + b*c*d*e, b*c*d*f, b*c*e*f} + use T + alpha = map(E, D, {a,b,c}) + beta = map(E, D, {d,e,f}) + assert isWellDefined alpha + assert isWellDefined beta + phi = complex chainComplex alpha + psi = complex chainComplex beta + prune HH phi + prune HH psi + isNullHomotopic phi + assert isNullHomotopic (phi-psi) + nullHomotopy phi + assert isNullHomotopyOf(oo, phi) +/// + +TEST /// +-* + restart + needsPackage "Complexes"; +*- + S = ZZ/32003[a,b,c,x,y,z, Degrees => {3:{1,0}, 3:{0,1}}] + Kt = (t) -> koszulComplex{a^t, b^t, c^t} + Ls = (s) -> koszulComplex{x^s, y^s, z^s} + F = Kt 1 ** Ls 1 + B = ideal(a,b,c) * ideal(x,y,z) + G = res B + betti G + prune HH F + prune HH G + -- want to construct the subcomplex of F that doesn't have any terms in degree 0. +/// + +TEST /// +-* + restart + needsPackage "Complexes"; +*- + S = ZZ/101[a..e, Degrees=>{2:{1,0},3:{0,1}}]/(e^3) + h = a*c^2 + a*c*d + b*d^2; + I = (ideal(a,b) * ideal(c,d))^[2] + g = map(S^1/h, S^1, 1) + f = map(S^1, S^{-degree h}, {{h}}) + assert isShortExactSequence(g,f) + delta = connectingExtMap(S^1/I, g, f, LengthLimit => 5) + assert isWellDefined delta + assert(degree delta == 0) + assert(source delta_(-1) == Ext^1(comodule I, S^1/h)) + assert(target delta_(-1) == Ext^2(comodule I, S^{{-1,-2}})) + delta_-2 + delta_-1 + g1 = Hom(S^1/I, g) + + F = freeResolution(S^1/I, LengthLimit => 5) + g' = Hom(F, g) + f' = Hom(F, f) + LES = longExactSequence(g', f') + assert all(3, i -> dd^LES_(3*(i+1)) == delta_(i+1)) + assert(HH LES == 0) + + -- another test + S = ZZ/101[a..e]/(e^3); + I = ideal(c^3-b*d^2, b*c-a*d) + J = ideal(a*c^2-b^2*d, b^3-a^2*c) + g = map(S^1/(I+J), S^1/I ++ S^1/J, {{1,1}}) + f = map(S^1/I ++ S^1/J, S^1/intersect(I,J), {{1},{-1}}) + assert isShortExactSequence(g,f) + delta = connectingExtMap(g, f, S^1, LengthLimit => 5) + assert isWellDefined delta + assert(source delta_-2 == Ext^2(comodule intersect(I,J), S)) + assert(target delta_-2 == Ext^3(comodule (I+J), S)) + + (g',f') = horseshoeResolution(g,f, LengthLimit => 5); + assert isShortExactSequence(g',f') + LES' = longExactSequence(Hom(f', S^1), Hom(g', S^1)); + assert(HH LES' == 0) + assert all(-6..6, i -> dd^LES'_(3*(i+1)) == delta_i) + + F = freeResolution(S^1/I, LengthLimit => 5) + g' = Hom(F, g) + f' = Hom(F, f) + LES = longExactSequence(g', f') + assert all(3, i -> dd^LES'_(-3*(i+1)) == delta_(-i-2)) -- note that contravariance shifts the indexing... + assert(HH LES == 0) +/// diff --git a/M2/Macaulay2/packages/Complexes/Ext.m2 b/M2/Macaulay2/packages/Complexes/Ext.m2 new file mode 100644 index 00000000000..7080a4731c1 --- /dev/null +++ b/M2/Macaulay2/packages/Complexes/Ext.m2 @@ -0,0 +1,108 @@ +-- total ext over complete intersections + +-- Code originally written by Dan Grayson +-- change 2009/1/12: +-- some modifications contributed 23 Mar 2007 by "Paul S. Aspinwall" , +-- but we also get rid of the fudge factor entirely, depending instead on automatic +-- computation of the heft vector + +-- TODO: Ext(R, S) should work as well +Ext(Ring, Ring) := +Ext(Ring, Ideal) := +Ext(Ring, Module) := +Ext(Ideal, Ring) := +Ext(Ideal, Ideal) := +Ext(Ideal, Module) := +Ext(Module, Ring) := +Ext(Module, Ideal) := Module => opts -> (M, N) -> Ext(module M, module N, opts) +Ext(Module, Module) := Module => opts -> (M, N) -> ( + -- c.f. caching in Hom(Module,Module) + cacheModule := youngest(M.cache.cache, N.cache.cache); + cacheKey := (Ext,M,N); + if cacheModule#?cacheKey then return cacheModule#cacheKey; + B := ring M; + if B =!= ring N + then error "expected modules over the same ring"; + if not isCommutative B + then error "'Ext' not implemented yet for noncommutative rings."; + if not isHomogeneous B + then error "'Ext' received modules over an inhomogeneous ring"; + if not isHomogeneous N or not isHomogeneous M + then error "'Ext' received an inhomogeneous module"; + if N == 0 or M == 0 then return cacheModule#cacheKey = B^0; + p := presentation B; + A := ring p; + I := ideal mingens ideal p; + n := numgens A; + c := numgens I; + if c =!= codim B + then error "total Ext available only for complete intersections"; + f := I_*; -- apply(c, i -> I_i); + pM := lift(presentation M,A); + pN := lift(presentation N,A); + M' := cokernel ( pM | p ** id_(target pM) ); + N' := cokernel ( pN | p ** id_(target pN) ); + assert isHomogeneous M'; + assert isHomogeneous N'; + C := freeResolution M'; + X := getSymbol "X"; + K := coefficientRing A; + S := K(monoid [X_1 .. X_c, toSequence A.generatorSymbols, + Degrees => { + apply(0 .. c-1, i -> prepend(-2, - degree f_i)), + apply(0 .. n-1, j -> prepend( 0, degree A_j)) + }]); + -- make a monoid whose monomials can be used as indices + Rmon := monoid [X_1 .. X_c,Degrees=>{c:{2}}]; + -- make group ring, so 'basis' can enumerate the monomials + R := K Rmon; + -- make a hash table to store the blocks of the matrix + blks := new MutableHashTable; + blks#(exponents 1_Rmon) = C.dd; + scan(0 .. c-1, i -> + blks#(exponents Rmon_i) = nullHomotopy(- f_i*id_C, FreeToExact => true)); + -- a helper function to list the factorizations of a monomial + factorizations := (gamma) -> ( + -- Input: gamma is the list of exponents for a monomial + -- Return a list of pairs of lists of exponents showing the + -- possible factorizations of gamma. + if gamma === {} then { ({}, {}) } + else ( + i := gamma#-1; + splice apply(factorizations drop(gamma,-1), + (alpha,beta) -> apply (0..i, + j -> (append(alpha,j), append(beta,i-j)))))); + scan(4 .. length C + 1, d -> if even d then ( + scan( flatten \ exponents \ leadMonomial \ first entries basis(d,R), + gamma -> ( + s := - sum(factorizations gamma, + (alpha,beta) -> ( + if blks#?alpha and blks#?beta + then blks#alpha * blks#beta + else 0)); + -- compute and save the nonzero nullhomotopies + if s != 0 then blks#gamma = nullHomotopy(s, FreeToExact => true))))); + -- make a free module whose basis elements have the right degrees + (loC, hiC) := concentration C; + Cstar := S^(apply(toList(loC..hiC), + i -> toSequence apply(degrees C_i, d -> prepend(i,d)))); + -- assemble the matrix from its blocks. + -- We omit the sign (-1)^(n+1) which would ordinarily be used, + -- which does not affect the homology. + toS := map(S,A,apply(toList(c .. c+n-1), i -> S_i), + DegreeMap => prepend_0); + Delta := map(Cstar, Cstar, + transpose sum(keys blks, m -> S_m * toS sum blks#m), + Degree => { -1, degreeLength A:0 }); + DeltaBar := Delta ** (toS ** N'); + if debugLevel > 10 then ( + assert isHomogeneous DeltaBar; + assert(DeltaBar * DeltaBar == 0); + stderr << describe ring DeltaBar < 2) /// + +TEST /// + R = QQ[x, Degrees => {{}}] + M = image x + F = freeResolution M + assert(isWellDefined F) + epsilon = augmentationMap F + assert isWellDefined epsilon + assert(M === (target epsilon)_0) +/// + +TEST /// + -- errorDepth = 0 + A = ZZ/103[x,y,z]; + J = ideal(x^3,y^4,z^5); + B = A/J; + f = matrix {{27*x^2-19*z^2, 38*x^2*y+47*z^3}, + { -5*x^2+z^2, -37*x^2*y+51*x*y^2-36*y^3+11*y*z^2+8*z^3}, + {x^2-x*y, z^3}}; + M = cokernel f; + N = B^1/(x^2 + z^2,y^3 - 2*z^3); + time E = Ext(M,N); -- used 3.32 seconds in version 0.9.92 + t = tally degrees target presentation E + u = new Tally from {{-3, -7} => 7, {-3, -6} => 7, {0, 1} => 3, {0, 2} => 4, {-4, -9} => 4, {-4, -8} => 1, {-4, -7} => 1, {-1, -2} => 4, {-2, -5} => 3, + {-2, -4} => 8} + assert ( t === u ) +/// diff --git a/M2/Macaulay2/packages/Complexes/FreeResolutions.m2 b/M2/Macaulay2/packages/Complexes/FreeResolutions.m2 index 6ffef2fcb0d..27f0bd9aa89 100644 --- a/M2/Macaulay2/packages/Complexes/FreeResolutions.m2 +++ b/M2/Macaulay2/packages/Complexes/FreeResolutions.m2 @@ -454,12 +454,12 @@ resolutionBySyzygies = (opts, M) -> ( RO.complex = (lengthlimit) -> ( syzmats := toList RO.SyzygyList; - C := if numcols first syzmats === 0 then complex M + C := if numcols first syzmats === 0 then complex target first syzmats else ( if numcols last syzmats === 0 then syzmats = drop(syzmats, -1); complex syzmats ); - C.cache.augmentationMap = map(complex M, C, i -> map(M, target presentation M, 1)); + C.cache.augmentationMap = map(complex M, C, i -> map(M, C_0, 1)); C); RO.compute(opts.LengthLimit, opts.DegreeLimit); @@ -601,7 +601,67 @@ truncate(BettiTally, InfiniteNumber, InfiniteNumber) := BettiTally => {} >> opts else continue ) +----------------------------------------------------------------------------- +-- minimalBetti +----------------------------------------------------------------------------- + +-- TODO: place this here, not in Core +-- minimalBetti = method( +-- TypicalValue => BettiTally, +-- Options => { +-- DegreeLimit => null, +-- LengthLimit => infinity, +-- Weights => null, +-- ParallelizeByDegree => false -- currently: only used over primes fields of positive characteristic +-- }) + +--- version 1.24.05 version of minimalBetti. -* +minimalBetti Module := BettiTally => opts -> M -> ( + R := ring M; + degreelimit := resolutionDegreeLimit(R, opts.DegreeLimit); + lengthlimit := resolutionLengthLimit(R, opts.LengthLimit); + -- check to see if a cached resolution is sufficient + cacheKey := ResolutionContext{}; + if M.cache#?cacheKey and isComputationDone(C := M.cache#cacheKey, + DegreeLimit => degreelimit, LengthLimit => lengthlimit) + then return betti(C.Result.Resolution, Weights => opts.Weights); + -- if not, compute a fast non-minimal resolution + -- the following line is because we need to make sure we have the resolution + -- either complete, or one more than the desired minimal betti numbers. + + -- We see if we can now compute a non-minimal resolution. + -- If not, we compute a usual resolution. + -- TODO: this isn't quite correct. + useFastNonminimal := not isQuotientRing R and + char R > 0 and char R < (1<<15); + + if not useFastNonminimal then + return betti resolution(M, DegreeLimit => degreelimit, LengthLimit => lengthlimit); + -- At this point, we think we are good to use the faster algorithm. + -- First, we need to comppute the non-minimal resolution to one further step. + if instance(opts.LengthLimit, ZZ) then lengthlimit = lengthlimit + 1; + C = resolution(M, + StopBeforeComputation => true, FastNonminimal => true, ParallelizeByDegree => opts.ParallelizeByDegree, + DegreeLimit => degreelimit, LengthLimit => lengthlimit); + rC := if C.?Resolution and C.Resolution.?RawComputation then C.Resolution.RawComputation + -- TODO: when can this error happen? + else error "cannot use 'minimalBetti' with this input. Input must be an ideal or module in a + polynomial ring or skew commutative polynomial ring over a finite field, which is singly graded. + These restrictions might be removed in the future."; + -- + B := unpackEngineBetti rawMinimalBetti(rC, + if opts.DegreeLimit =!= null then {opts.DegreeLimit} else {}, + if opts.LengthLimit =!= infinity then {opts.LengthLimit} else {} + ); + betti(B, Weights => heftvec(opts.Weights, heft R)) + ) +minimalBetti Ideal := BettiTally => opts -> I -> minimalBetti( + if I.cache.?quotient then I.cache.quotient + else I.cache.quotient = cokernel generators I, opts + ) +*- + minimalBetti Module := BettiTally => opts -> M -> ( R := ring M; degreelimit := opts.DegreeLimit; @@ -640,6 +700,10 @@ minimalBetti Module := BettiTally => opts -> M -> ( betti(B, Weights => heftvec(opts.Weights, heft R)) ) +minimalBetti Ideal := BettiTally => opts -> I -> minimalBetti(comodule I, opts) + +-* +-- older version of Core version of minimalBetti. Can't use here? minimalBetti(Module, Thing) := BettiTally => opts -> (M, junk) -> ( R := ring M; degreelimit := resolutionDegreeLimit(R, opts.DegreeLimit); diff --git a/M2/Macaulay2/packages/Complexes/Tor.m2 b/M2/Macaulay2/packages/Complexes/Tor.m2 index 9233b3900a2..382f5b957c8 100644 --- a/M2/Macaulay2/packages/Complexes/Tor.m2 +++ b/M2/Macaulay2/packages/Complexes/Tor.m2 @@ -28,10 +28,10 @@ Tor(ZZ, Module, Matrix) := Matrix => opts -> (i,M,f) -> ( ) ) -torSymmetry = method() -torSymmetry(ZZ, Module, Module) := Matrix => (i, M, N) -> ( - FM := freeResolution M; - FN := freeResolution N; +torSymmetry = method(Options => {LengthLimit => infinity}) +torSymmetry(ZZ, Module, Module) := Matrix => opts -> (i, M, N) -> ( + FM := freeResolution(M, LengthLimit => opts.LengthLimit); + FN := freeResolution(N, LengthLimit => opts.LengthLimit); TorMN := Tor_i(M,N); TorNM := Tor_i(N,M); alpha := gens TorMN; @@ -46,15 +46,15 @@ torSymmetry(ZZ, Module, Module) := Matrix => (i, M, N) -> ( map(TorNM, TorMN, delta) ) -connectingTorMap = method(Options => {Concentration => null}) +connectingTorMap = method(Options => {Concentration => null, LengthLimit => infinity}) connectingTorMap(Module, Matrix, Matrix) := ComplexMap => opts -> (M, g, f) -> ( - F := freeResolution M; - connectingMap(F ** g, F ** f, opts) + F := freeResolution(M, LengthLimit => opts.LengthLimit); + connectingMap(F ** g, F ** f, Concentration => opts.Concentration) ) connectingTorMap(Matrix, Matrix, Module) := ComplexMap => opts -> (g, f, M) -> ( - (g', f') := horseshoeResolution(g, f); - connectingMap(g' ** M, f' ** M, opts) + (g', f') := horseshoeResolution(g, f, LengthLimit => opts.LengthLimit); + connectingMap(g' ** M, f' ** M, Concentration => opts.Concentration) ) TEST /// @@ -179,3 +179,45 @@ TEST /// h3' = delta'_3 * ts3' assert(h3 == h3') /// + +TEST /// +-* + restart + needsPackage "Complexes" +*- + -- for quotient rings, some methods reuqire LengthLimit. + S = ZZ/101[a..e]/(e^2); + I = ideal(c^3-b*d^2, b*c-a*d) + J = ideal(a*c^2-b^2*d, b^3-a^2*c) + g = map(S^1/(I+J), S^1/I ++ S^1/J, {{1,1}}) + f = map(S^1/I ++ S^1/J, S^1/intersect(I,J), {{1},{-1}}) + assert isShortExactSequence(g,f) + kk = coker vars S + delta = connectingTorMap(kk, g, f, LengthLimit => 5); + delta' = connectingTorMap(g, f, kk, LengthLimit => 5); + assert isWellDefined delta + assert isWellDefined delta' + F = freeResolution(kk, LengthLimit => 5) + LES = longExactSequence(F ** g, F ** f); + assert all(3, i -> dd^LES_(3*(i+1)) == delta_(i+1)) + assert(HH LES == 0) + -- another way + (g',f') = horseshoeResolution(g,f, LengthLimit => 5); + assert isShortExactSequence(g',f') + LES' = longExactSequence(g' ** kk, f' ** kk); + assert(HH LES' == 0) + assert all(3, i -> dd^LES'_(3*(i+1)) == delta'_(i+1)) + -- now we show commutativity of some squares + -- which show that delta, delta' are isomorphic. + h2 = torSymmetry(1, kk, source f, LengthLimit => 5) * delta_2 + ts = torSymmetry(2, kk, target g, LengthLimit => 5) + ts' = map(source delta'_2, source ts, ts) + h2' = delta'_2 * ts' + assert(h2 == h2') + -- now for delta_3 + h3 = torSymmetry(2, kk, source f, LengthLimit => 5) * delta_3 + ts3 = torSymmetry(3, kk, target g, LengthLimit => 5) + ts3' = map(source delta'_3, source ts3, ts3) + h3' = delta'_3 * ts3' + assert(h3 == h3') +/// diff --git a/M2/Macaulay2/packages/Depth.m2 b/M2/Macaulay2/packages/Depth.m2 index a9a0ef251c0..6beb0255d5f 100644 --- a/M2/Macaulay2/packages/Depth.m2 +++ b/M2/Macaulay2/packages/Depth.m2 @@ -648,7 +648,7 @@ doc/// (depth, Ideal, Module) (depth, Module) (depth, Ideal, Ideal) - Headline + Headline computes the depth of a ring Usage d = depth(I,M) diff --git a/M2/Macaulay2/packages/IntegralClosure.m2 b/M2/Macaulay2/packages/IntegralClosure.m2 index e2c47e3cc2b..cea270fee52 100644 --- a/M2/Macaulay2/packages/IntegralClosure.m2 +++ b/M2/Macaulay2/packages/IntegralClosure.m2 @@ -32,7 +32,6 @@ export{ "integralClosure", "icFractions", "icMap", - "isNormal", "conductor", "makeS2", "idealizer", @@ -662,7 +661,8 @@ fInIdeal = (f,I) -> ( -- COMMENT: This computes the jacobian of the ring which can be expensive. -- However, it first checks the less expensive S2 condition and then -- checks R1. -isNormal = method() + +--isNormal = method() isNormal(Ring) := Boolean => (R) -> ( -- 1 argument: A ring - usually a quotient ring. -- Return: A boolean value, true if the ring is normal and false diff --git a/M2/Macaulay2/packages/Macaulay2Doc/shared.m2 b/M2/Macaulay2/packages/Macaulay2Doc/shared.m2 index a31095f933b..3d777937eac 100644 --- a/M2/Macaulay2/packages/Macaulay2Doc/shared.m2 +++ b/M2/Macaulay2/packages/Macaulay2Doc/shared.m2 @@ -15,6 +15,9 @@ document { Key => isVeryAmple, methodstr, SeeAlso => { "Divisor::isVeryAmple(WeilDivisor)", "Polyhedra::isVeryAmple(Polyhedron)", "PositivityToricBundles::isVeryAmple(ToricVectorBundleKlyachko)", "NormalToricVarieties::isVeryAmple(ToricDivisor)" } } +document { Key => isNormal, methodstr, SeeAlso => { "Polyhedra::isNormal(Polyhedron)","IntegralClosure::isNormal(Ring)"} } +document { Key => normalCone, methodstr, SeeAlso => { "Polyhedra::normalCone(Polyhedron,Polyhedron)","ReesAlgebra::normalCone(Ideal)"} } + document { Key => cone, Headline => "mapping cone or polyhedral cone", diff --git a/M2/Macaulay2/packages/OldPolyhedra.m2 b/M2/Macaulay2/packages/OldPolyhedra.m2 index 3eb8a03b612..14d071d5ffb 100644 --- a/M2/Macaulay2/packages/OldPolyhedra.m2 +++ b/M2/Macaulay2/packages/OldPolyhedra.m2 @@ -3053,7 +3053,7 @@ ZZ * Polyhedron := (k,P) -> promote(k,QQ) * P -- INPUT : '(P,Q)', two polyhedra -- OUTPUT : 'C', a Cone, the inner normal cone of P in the face Q -- COMMENT : 'Q' must be a face of P -normalCone (Polyhedron,Polyhedron) := Cone => opts -> (P,Q) -> ( +normalCone (Polyhedron,Polyhedron) := Cone => {} >> opts -> (P,Q) -> ( if not P.cache.?normalCone then P.cache.normalCone = new MutableHashTable; if not P.cache.normalCone#?Q then ( -- Checking for input errors diff --git a/M2/Macaulay2/packages/Polyhedra.m2 b/M2/Macaulay2/packages/Polyhedra.m2 index 94f1febd348..fb193f5bb8c 100644 --- a/M2/Macaulay2/packages/Polyhedra.m2 +++ b/M2/Macaulay2/packages/Polyhedra.m2 @@ -38,7 +38,7 @@ newPackage("Polyhedra", Email => "k.l@fu-berlin.de" } }, - PackageImports=>{"IntegralClosure", "ReesAlgebra", "LLLBases"} + PackageImports=>{"LLLBases"} ) --------------------------------------------------------------------------- diff --git a/M2/Macaulay2/packages/Polyhedra/extended/legacy.m2 b/M2/Macaulay2/packages/Polyhedra/extended/legacy.m2 index 321ac95af2a..8cc9a2345b1 100644 --- a/M2/Macaulay2/packages/Polyhedra/extended/legacy.m2 +++ b/M2/Macaulay2/packages/Polyhedra/extended/legacy.m2 @@ -111,7 +111,7 @@ imageFan (Matrix,Cone) := (M,C) -> ( -- INPUT : '(P,Q)', two polyhedra -- OUTPUT : 'C', a Cone, the inner normal cone of P in the face Q -- COMMENT : 'Q' must be a face of P -normalCone (Polyhedron,Polyhedron) := Cone => opts -> (P,Q) -> ( +normalCone (Polyhedron,Polyhedron) := Cone => {} >> opts -> (P,Q) -> ( if not P.cache.?normalCone then P.cache.normalCone = new MutableHashTable; if not P.cache.normalCone#?Q then ( -- Checking for input errors diff --git a/M2/Macaulay2/packages/ReesAlgebra.m2 b/M2/Macaulay2/packages/ReesAlgebra.m2 index 33bef1822a8..79f1cbc2543 100644 --- a/M2/Macaulay2/packages/ReesAlgebra.m2 +++ b/M2/Macaulay2/packages/ReesAlgebra.m2 @@ -57,14 +57,14 @@ check "ReesAlgebra" *- export{ - "analyticSpread", + "analyticSpread", + "associatedGradedRing", "distinguished", "intersectInP", "isLinearType", "minimalReduction", "isReduction", "multiplicity", - "normalCone", "reductionNumber", "reesIdeal", "reesAlgebra", @@ -79,12 +79,10 @@ export{ "expectedReesIdeal", "PlaneCurveSingularities", --synonyms - "associatedGradedRing" => "normalCone", "reesAlgebraIdeal" => "reesIdeal", "Trim" -- option in reesIdeal } - symmetricAlgebraIdeal = method(Options => { VariableBaseName => "w" }) @@ -209,8 +207,7 @@ isLinearType(Module, RingElement):= o-> (N,a)->( J := ideal((vars S) * P); ((gens I) % J) == 0) -normalCone = method(TypicalValue => Ring, - Options => { +normalConeOptions = { DegreeLimit => {}, BasisElementLimit => infinity, PairLimit => infinity, @@ -218,17 +215,21 @@ normalCone = method(TypicalValue => Ring, Strategy => null, Variable => "w" } -) -normalCone(Ideal) := o -> I -> ( + +normalCone Ideal := Ring => normalConeOptions >> o -> I -> ( RI := reesAlgebra(I,o); RI/promote(I,RI) ) -normalCone(Ideal, RingElement) := o -> (I,a) -> ( +normalCone(Ideal, RingElement) := Ring => normalConeOptions >> o -> (I,a) -> ( RI := reesAlgebra(I,a,o); RI/promote(I,RI) ) +associatedGradedRing = method(Options => normalConeOptions) +associatedGradedRing Ideal := Ring => o -> I -> normalCone(I, o) +associatedGradedRing(Ideal, RingElement) := Ring => o -> (I,a) -> normalCone(I, a, o) + multiplicity = method( Options => { DegreeLimit => {}, @@ -1256,15 +1257,18 @@ doc /// doc /// Key - normalCone - (normalCone, Ideal) (normalCone, Ideal, RingElement) - + (normalCone, Ideal) + associatedGradedRing + (associatedGradedRing, Ideal) + (associatedGradedRing, Ideal, RingElement) Headline The normal cone of a subscheme Usage normalCone I normalCone(I,f) + associatedGradedRing I + associatedGradedRing(I,f) Inputs I:Ideal f:RingElement @@ -1980,8 +1984,8 @@ doc /// [reesAlgebra,Strategy] [isLinearType,Strategy] [isReduction, Strategy] - [normalCone, Strategy] - [multiplicity, Strategy] + [multiplicity, Strategy] + [associatedGradedRing, Strategy] [specialFiberIdeal, Strategy] [specialFiber, Strategy] [analyticSpread, Strategy] @@ -2025,7 +2029,7 @@ doc /// [specialFiber, PairLimit] [specialFiberIdeal, PairLimit] [multiplicity, PairLimit] - [normalCone, PairLimit] + [associatedGradedRing, PairLimit] [isReduction, PairLimit] [isLinearType,PairLimit] [reesAlgebra,PairLimit] @@ -2062,7 +2066,7 @@ doc /// [specialFiber, MinimalGenerators] [specialFiberIdeal, MinimalGenerators] [multiplicity, MinimalGenerators] - [normalCone, MinimalGenerators] + [associatedGradedRing, MinimalGenerators] [isReduction, MinimalGenerators] [isLinearType,MinimalGenerators] [reesAlgebra,MinimalGenerators] @@ -2099,7 +2103,7 @@ doc /// [analyticSpread, BasisElementLimit] [specialFiber, BasisElementLimit] [multiplicity, BasisElementLimit] - [normalCone, BasisElementLimit] + [associatedGradedRing, BasisElementLimit] [isReduction, BasisElementLimit] [isLinearType,BasisElementLimit] [reesAlgebra,BasisElementLimit] @@ -2135,8 +2139,8 @@ doc /// [distinguished,DegreeLimit] [analyticSpread, DegreeLimit] [specialFiber, DegreeLimit] - [normalCone, DegreeLimit] [multiplicity, DegreeLimit] + [associatedGradedRing, DegreeLimit] [isReduction, DegreeLimit] [isLinearType,DegreeLimit] [reesAlgebra,DegreeLimit] diff --git a/M2/Macaulay2/tests/normal/ext-total.m2 b/M2/Macaulay2/tests/normal/ext-total.m2 index 748044432eb..1199ca76b99 100644 --- a/M2/Macaulay2/tests/normal/ext-total.m2 +++ b/M2/Macaulay2/tests/normal/ext-total.m2 @@ -16,7 +16,32 @@ assert ( degs == apply( newdegs, repair )) heft0 = {-3, 1} degs1 = {{0, 0}, {0, 0}, {0, 0}, {1, 2}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 4}, {1, 4}, {1, 4}, {1, 5}, {1, 5}, {1, 5}, {2, 5}, {2, 6}, {2, 6}, {2, 7}, {2, 7}, {2, 7}, {2, 7}, {2, 7}, {2, 7}, {2, 7}, {2, 7}, {2, 7}, {2, 8}, {2, 8}, {2, 8}, {3, 9}, {3, 9}, {3, 9}, {3, 9}, {3, 9}, {3, 9}, {3, 9}}; -degs2 = {{0, -2}, {0, -3}, {0, -3}, {0, -4}, {0, -5}, {0, -2}, {0, -3}, {0, -3}, {0, -4}, {0, -5}, {0, -2}, {0, -3}, {0, -3}, {0, -4}, {0, -5}, {1, 0}, {1, -1}, {1, -1}, {1, -2}, {1, -3}, {1, 1}, {1, 0}, {1, 0}, {1, -1}, {1, -2}, {1, 1}, {1, 0}, {1, 0}, {1, -1}, {1, -2}, {1, 1}, {1, 0}, {1, 0}, {1, -1}, {1, -2}, {1, 1}, {1, 0}, {1, 0}, {1, -1}, {1, -2}, {1, 2}, {1, 1}, {1, 1}, {1, 0}, {1, -1}, {1, 2}, {1, 1}, {1, 1}, {1, 0}, {1, -1}, {1, 2}, {1, 1}, {1, 1}, {1, 0}, {1, -1}, {1, 3}, {1, 2}, {1, 2}, {1, 1}, {1, 0}, {1, 3}, {1, 2}, {1, 2}, {1, 1}, {1, 0}, {1, 3}, {1, 2}, {1, 2}, {1, 1}, {1, 0}, {2, 3}, {2, 2}, {2, 2}, {2, 1}, {2, 0}, {2, 4}, {2, 3}, {2, 3}, {2, 2}, {2, 1}, {2, 4}, {2, 3}, {2, 3}, {2, 2}, {2, 1}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 6}, {2, 5}, {2, 5}, {2, 4}, {2, 3}, {2, 6}, {2, 5}, {2, 5}, {2, 4}, {2, 3}, {2, 6}, {2, 5}, {2, 5}, {2, 4}, {2, 3}, {3, 7}, {3, 6}, {3, 6}, {3, 5}, {3, 4}, {3, 7}, {3, 6}, {3, 6}, {3, 5}, {3, 4}, {3, 7}, {3, 6}, {3, 6}, {3, 5}, {3, 4}, {3, 7}, {3, 6}, {3, 6}, {3, 5}, {3, 4}, {3, 7}, {3, 6}, {3, 6}, {3, 5}, {3, 4}, {3, 7}, {3, 6}, {3, 6}, {3, 5}, {3, 4}, {3, 7}, {3, 6}, {3, 6}, {3, 5}, {3, 4}}; +degs2 = {{0, -2}, {0, -3}, {0, -3}, {0, -4}, {0, -5}, {0, -2}, + {0, -3}, {0, -3}, {0, -4}, {0, -5}, {0, -2}, {0, -3}, + {0, -3}, {0, -4}, {0, -5}, {1, 0}, {1, -1}, {1, -1}, + {1, -2}, {1, -3}, {1, 1}, {1, 0}, {1, 0}, {1, -1}, + {1, -2}, {1, 1}, {1, 0}, {1, 0}, {1, -1}, {1, -2}, + {1, 1}, {1, 0}, {1, 0}, {1, -1}, {1, -2}, {1, 1}, + {1, 0}, {1, 0}, {1, -1}, {1, -2}, {1, 2}, {1, 1}, + {1, 1}, {1, 0}, {1, -1}, {1, 2}, {1, 1}, {1, 1}, + {1, 0}, {1, -1}, {1, 2}, {1, 1}, {1, 1}, {1, 0}, {1, -1}, + {1, 3}, {1, 2}, {1, 2}, {1, 1}, {1, 0}, {1, 3}, {1, 2}, + {1, 2}, {1, 1}, {1, 0}, {1, 3}, {1, 2}, {1, 2}, {1, 1}, + {1, 0}, {2, 3}, {2, 2}, {2, 2}, {2, 1}, {2, 0}, {2, 4}, + {2, 3}, {2, 3}, {2, 2}, {2, 1}, {2, 4}, {2, 3}, {2, 3}, + {2, 2}, {2, 1}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, + {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 5}, {2, 4}, + {2, 4}, {2, 3}, {2, 2}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, + {2, 2}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 5}, + {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 5}, {2, 4}, {2, 4}, + {2, 3}, {2, 2}, {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, + {2, 5}, {2, 4}, {2, 4}, {2, 3}, {2, 2}, {2, 6}, {2, 5}, + {2, 5}, {2, 4}, {2, 3}, {2, 6}, {2, 5}, {2, 5}, {2, 4}, + {2, 3}, {2, 6}, {2, 5}, {2, 5}, {2, 4}, {2, 3}, {3, 7}, + {3, 6}, {3, 6}, {3, 5}, {3, 4}, {3, 7}, {3, 6}, {3, 6}, + {3, 5}, {3, 4}, {3, 7}, {3, 6}, {3, 6}, {3, 5}, {3, 4}, + {3, 7}, {3, 6}, {3, 6}, {3, 5}, {3, 4}, {3, 7}, {3, 6}, + {3, 6}, {3, 5}, {3, 4}, {3, 7}, {3, 6}, {3, 6}, {3, 5}, {3, 4}, {3, 7}, {3, 6}, {3, 6}, {3, 5}, {3, 4}}; degDB = {-1, 0} degs' = apply(degs, adjust) @@ -57,39 +82,8 @@ assert ( t' === u ) << "then we do the computation with unadjusted degrees" << endl comp (degs,heft0,degs1,degs2,degDB) t = tally degrees target presentation E - assert ( t === u ) --* - -the answer changed between these two versions: - -u123$ ls -l ~/local.Linux/encap/Macaulay2-0.9.95/bin/M2 --rwxr-xr-x 1 dan academic 5036156 2006-11-06 11:50 /home/25/dan/local.Linux/encap/Macaulay2-0.9.95/bin/M2 - -u123$ ls -l ~/local.Linux/encap/Macaulay2-0.9.94/bin/M2 --rwxr-xr-x 1 dan academic 5028988 2006-10-24 10:33 /home/25/dan/local.Linux/encap/Macaulay2-0.9.94/bin/M2 - -*- - - --- errorDepth = 0 -A = ZZ/103[x,y,z]; -J = ideal(x^3,y^4,z^5); -B = A/J; -f = matrix {{27*x^2-19*z^2, 38*x^2*y+47*z^3}, - { -5*x^2+z^2, -37*x^2*y+51*x*y^2-36*y^3+11*y*z^2+8*z^3}, - {x^2-x*y, z^3}}; -M = cokernel f; -N = B^1/(x^2 + z^2,y^3 - 2*z^3); --- gbTrace = 3 -debugLevel = 99 -time E = Ext(M,N); - -- used 3.32 seconds in version 0.9.92 -t = tally degrees target presentation E -u = new Tally from {{-3, -7} => 7, {-3, -6} => 7, {0, 1} => 3, {0, 2} => 4, {-4, -9} => 4, {-4, -8} => 1, {-4, -7} => 1, {-1, -2} => 4, {-2, -5} => 3, - {-2, -4} => 8} -assert ( t === u ) -- Local Variables: -- compile-command: "make -C $M2BUILDDIR/Macaulay2/packages/Macaulay2Doc/test ext-total.out" -- End: