From b49270aa5820fba3fd8fba8eda3b39dc2eb94f5b Mon Sep 17 00:00:00 2001 From: kellerlv <54511397+kellerlv@users.noreply.github.com> Date: Wed, 13 Aug 2025 22:02:59 -0400 Subject: [PATCH 1/4] New package simplicial modules --- M2/Macaulay2/packages/=distributed-packages | 1 + M2/Macaulay2/packages/SimplicialModules.m2 | 208 + .../SimplicialModules/Normalization.m2 | 311 ++ .../SimplicialMapUtilities_Modified.m2 | 253 ++ .../SimplicialModules/SimplicialModule.m2 | 1436 ++++++ .../SimplicialModules/SimplicialModuleDOC.m2 | 4001 +++++++++++++++++ .../SimplicialModuleTESTS1.m2 | 1198 +++++ .../SimplicialModule_Modified.m2 | 823 ++++ 8 files changed, 8231 insertions(+) create mode 100644 M2/Macaulay2/packages/SimplicialModules.m2 create mode 100644 M2/Macaulay2/packages/SimplicialModules/Normalization.m2 create mode 100644 M2/Macaulay2/packages/SimplicialModules/SimplicialMapUtilities_Modified.m2 create mode 100644 M2/Macaulay2/packages/SimplicialModules/SimplicialModule.m2 create mode 100644 M2/Macaulay2/packages/SimplicialModules/SimplicialModuleDOC.m2 create mode 100644 M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 create mode 100644 M2/Macaulay2/packages/SimplicialModules/SimplicialModule_Modified.m2 diff --git a/M2/Macaulay2/packages/=distributed-packages b/M2/Macaulay2/packages/=distributed-packages index 0afda8756c..1a809e7523 100644 --- a/M2/Macaulay2/packages/=distributed-packages +++ b/M2/Macaulay2/packages/=distributed-packages @@ -288,3 +288,4 @@ AllMarkovBases Tableaux CpMackeyFunctors JSONRPC +SimplicialModules diff --git a/M2/Macaulay2/packages/SimplicialModules.m2 b/M2/Macaulay2/packages/SimplicialModules.m2 new file mode 100644 index 0000000000..5bec277a98 --- /dev/null +++ b/M2/Macaulay2/packages/SimplicialModules.m2 @@ -0,0 +1,208 @@ +newPackage( + "SimplicialModules", + AuxiliaryFiles => true, + Version => "0.1", + Date => "September 27, 2023", + Authors => { + {Name => "Keller VandeBogert", Email => "kvandebo@nd.edu", HomePage => "https://sites.google.com/view/kellervandebogert/home"}, + {Name => "Michael DeBellevue", Email => "", HomePage => ""}}, + Headline => "methods for working in the category of simplicial modules", + Keywords => {"Homological Algebra", "Commutative Algebra"}, + PackageExports => {"Complexes", "SchurFunctors"}, + PackageImports => {"Complexes"} + ) + +export {"SimplicialModule", + "SimplicialModuleMap", + "simplicialModule", + --"combineSFactors", + "forgetComplex", + "forgetDegeneracy", + "isSimplicialModule", + "isSimplicialMorphism", + "randomSimplicialMap", + "tensorwithComponents", + "topDegree", + "exteriorInclusion", + "extPower", + "naiveNorm", + "normalize", + "schurMap", + "simplicialTensor", + "symmetricQuotient", + "tensorLES", + --"CheckMap", + "CheckComplex", + "RememberSummands", + "Degeneracy", + "TopDegree", + "ss", + "complexLength", + "CheckSum", + "complexMap", + "summandSurjection" + } + + + + +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- **CODE** -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +load "./SimplicialModules/SimplicialMapUtilities_Modified.m2" +load "./SimplicialModules/SimplicialModule.m2" +load "./SimplicialModules/Normalization.m2" + + + +----------------------------------------------------------------------------- +-- Documentation +----------------------------------------------------------------------------- + +beginDocumentation() + +load "./SimplicialModules/SimplicialModuleDOC.m2" + + + +----------------------------------------------------------------------------- +-- Tests +----------------------------------------------------------------------------- + +load "./SimplicialModules/SimplicialModuleTESTS1.m2" + + + +----------------------------------------------------------------------------- +-- Development +----------------------------------------------------------------------------- + +end-- + +uninstallPackage "SimplicialModules" +restart +debug installPackage "SimplicialModules" +debug loadPackage("SimplicialModules", LoadDocumentation => true, Reload => true) +debug needsPackage "SimplicialModules" +check SimplicialModules +viewHelp SimplicialModules + + Q = QQ[x_1..x_3]; + K = koszulComplex vars Q; + isWellDefined simplicialModule(K, 4) --no degeneracy here + S = simplicialModule(K,4, Degeneracy => true) + S.dd**Q^1 + isWellDefined S + Sdegen = simplicialModule(K,4,Degeneracy => true) + S.dd + --S.ss --should return error, no such key + Sdegen.ss --this is the version that actually has degeneracy maps cached + simplicialModule(K, 5) + C = complex(Q^1, Base => 1) + simplicialModule(C, 3) + isWellDefined oo + simplicialModule(complex(Q^2, Base => 2), 6, Degeneracy => true) + isWellDefined oo --nice, now we can be confident the objects we are messing with actually make any sense + oo.ss + id_S + phi = exteriorInclusion(S); + prune phi + prune coker phi + K = koszulComplex {x_1,x_2} + Sn = simplicialModule(K, 4, Degeneracy => true) + phi = exteriorInclusion(K) + isCommutative phi + isWellDefined phi + isCommutative prune phi + isWellDefined prune phi + sphi = exteriorInclusion(Sn); + psphi = prune sphi; + isWellDefined (source psphi).cache.pruningMap + isCommutative (source psphi).cache.pruningMap + isSimplicialMorphism (source psphi).cache.pruningMap --pruningMaps are well-defined morphisms + + S = simplicialModule(K,6) + + + p = randomComplexMap(K, K, Degree => 1, InternalDegree => 1) + sp = simplicialModule p + isWellDefined sp + isCommutative sp + normalize(sp, CheckComplex => false) + prune oo ---reobtain p + p' = randomComplexMap(K, K, Degree => -1) + sp' = simplicialModule p' + isWellDefined sp' + isCommutative sp' + normalize(sp', CheckComplex => false) + prune oo --reobtain p' + p = randomComplexMap(K, K, Degree => 1, Cycle => true, InternalDegree => 2) + sp = simplicialModule p + isWellDefined sp + isCommutative sp + normalize(sp, CheckComplex => false) + prune oo ---reobtain p + diffs = simplicialModule K.dd + isWellDefined diffs + isCommutative diffs + + image(id_S) == S + simplicialModule(id_K, 6) == id_S + isSimplicialMorphism id_S + simplicialModule(complex(Q^0), 6, Degeneracy => true) -- should be able to input 0 and get a well-defined output + isWellDefined oo + phi = randomSimplicialMap(S, S, Cycle => true, InternalDegree => 1) + isWellDefined phi + isCommutative phi + + bS = basis(0, forgetComplex S) + prune bS.dd + isWellDefined bS + isWellDefined prune bS + bid = basis(0, id_(forgetComplex S)) + isWellDefined bid + isCommutative bid + isWellDefined prune bid + isCommutative prune bid + + fS = forgetComplex S + fS.?ss + + bS = basis(1, forgetComplex S) + isWellDefined bS + prune bS.dd + isWellDefined oo + prune bS.ss + isWellDefined oo + normalize bS + prune oo + prune basis(1, K) + + bS = basis(3, forgetComplex S) + isWellDefined bS + prune bS.dd; + isWellDefined oo + prune bS.ss; + isWellDefined oo + normalize bS + prune oo + prune basis(3, koszulComplex vars Q) + + tS = truncate(1, S) + isWellDefined tS + prune tS + isWellDefined prune tS + tS = truncate(1, fS) + isWellDefined tS + prune tS + isWellDefined prune tS + isCommutative truncate(2, id_S) + isCommutative truncate(2, id_fS) + + K = koszulComplex {x_1,x_2} + isWellDefined (Sc = schurMap({1,1}, K)) + prune ext(2, K) + prune schurMap({2,1}, K, TopDegree => 4) diff --git a/M2/Macaulay2/packages/SimplicialModules/Normalization.m2 b/M2/Macaulay2/packages/SimplicialModules/Normalization.m2 new file mode 100644 index 0000000000..8d09248a7b --- /dev/null +++ b/M2/Macaulay2/packages/SimplicialModules/Normalization.m2 @@ -0,0 +1,311 @@ + needsPackage "SchurFunctors" + needsPackage "Complexes" + + altSumFace = method(); +altSumFace(SimplicialModule,ZZ) := (S,n) -> (sum(0..n,i->(-1)^i*(S.dd)_(n,i))) + +altSumFace(Complex,ZZ) := (C,n) -> (altSumFace(simplicialModule(C,n),n)) + +--this function computes the naive normalization +--of a simplicial object, with is just the complex built from the +--modules of the simplicial object equipped with differential which is just the alternating sum of the face maps. +naiveNorm = method(); +naiveNorm(SimplicialModule,ZZ) := (S,n) -> (complex for i from 1 to n list altSumFace(S,i)) + +naiveNorm(SimplicialModule) := S -> naiveNorm(S, S.topDegree) + +naiveNorm(Complex,ZZ) := (C,n) -> (naiveNorm(simplicialModule(C,n),n)) + + + +--we assume that S is Gamma(C) for some complex C here +--sym = method(); +--sym(ZZ,Matrix) := (d,M) -> ( +-*symMult = method(); +symMult(List,ZZ,Ring) := (L,d,Q) -> (Qn := Q[z_1..z_d]; + M1 := tensor(for i in L list basis(i,Qn)); + M2 := basis(sum L,Qn); + sub(M1//M2,Q) + )*- + +--this function constructs the Dold-Puppe extension of the Schur functor to the category +--of chain complexes. The list L should be a partition +schurMap = method(Options => {Degeneracy => false,TopDegree => null}); +schurMap(List,SimplicialModule) := SimplicialModule => opts -> (lambda,S) -> (tdeg := topDegree S; + --C := S.complex; + L := hashTable for i to tdeg list i => schurModule(lambda,combineSFactors(S,i)); + H1 := hashTable for i in keys (S.dd.map) list i => schur(lambda,((S.dd)_i)); + if opts.Degeneracy==true then H2 := hashTable for i in keys (S.ss.map) list i => schur(lambda,((S.ss)_i)); + --print("we made it"); + if opts.Degeneracy==true then return simplicialModule(L,H1,H2,tdeg); + simplicialModule(L,H1,tdeg) + ) + +schurMap(List,SimplicialModuleMap) := SimplicialModuleMap => opts -> (lambda,phi) -> ( + S1 := source phi; + S2 := target phi; + if instance((keys phi.map)#0,Sequence) then error "Expected SimplicialModuleMap to have singly graded indices"; + map(schurMap(lambda,S2),schurMap(lambda,S1),new HashTable from for i to max(topDegree S1,topDegree S2) list i => schur(lambda,phi_i),Degree => degree phi) + ) + +schurMap(List,Complex) := Complex => opts -> (lambda,C) -> (S := if not(opts.TopDegree === null) then simplicialModule(C,opts.TopDegree) + else simplicialModule(C,(sum lambda)*length(C)); + Sn := schurMap(lambda,S); + normalize(Sn) + ) + +schurMap(List,ComplexMap) := ComplexMap => opts -> (lambda,phi) -> (phin := if not(opts.TopDegree === null) then simplicialModule(phi,opts.TopDegree) + else simplicialModule(phi,(sum lambda)*(max(length(source phi),length target phi))); + phik := schurMap(lambda,phin); + normalize(phik) + ) + +-*sym = method(Options => {Degeneracy => false,TopDegree => null}); +sym(ZZ,Matrix) := Matrix => opts -> (d,phi) -> (Q := ring phi; + n := rank source phi; + m := rank target phi; + phitens := tensor((d:phi)); + M1 := symMult(toList(d:1),n,Q); + M2 := symMult(toList(d:1),m,Q); + matrix entries transpose ((matrix entries transpose(M2*phitens))//transpose(M1)) + ) + + +sym(ZZ,SimplicialModule) := SimplicialModule => opts -> (d,S) -> (tdeg := topDegree S; + --C := S.complex; + L = hashTable for i to tdeg list i => symmetricPower(d,combineSFactors(S,i)); + H1 = hashTable for i in keys (S.dd.map) list i => map(symmetricPower(d,target (S.dd)_i),symmetricPower(d,source (S.dd)_i),sym(d,((S.dd)_i))); + if opts.Degeneracy==true then H2 = hashTable for i in keys (S.ss.map) list i => sym(d,((S.ss)_i)); + --print("we made it"); + if opts.Degeneracy==true then return simplicialModule(L,H1,H2,tdeg); + simplicialModule(L,H1,tdeg) + ) + +sym(ZZ,SimplicialModuleMap) := SimplicialModuleMap => opts -> (d,phi) -> ( + S1 := source phi; + S2 := target phi; + if instance((keys phi.map)#0,Sequence) then error "Expected SimplicialModuleMap to have singly graded indices"; + map(sym(d,S2),sym(d,S1),new HashTable from for i to max(topDegree S1,topDegree S2) list i => sym(d,phi_i),Degree => degree phi) + ) + +sym(ZZ,Complex) := Complex => opts -> (d,C) -> (if not(opts.TopDegree === null) then S = simplicialModule(C,opts.TopDegree) + else S = simplicialModule(C,d*length(C)); + Sn := sym(d,S); + normalize(Sn) + ) + +sym(ZZ,ComplexMap) := ComplexMap => opts -> (d,phi) -> (if not(opts.TopDegree === null) then phin = simplicialModuleMap(phi,opts.TopDegree) + else phin = simplicialModuleMap(phi,d*(max(length(source phi),length target phi))); + phik := sym(d,phin); + normalize(phik) + )*- + + +--this function computes the Dold-Puppe extension of the exterior power functor +--to the category of chain complexes. The integer d is the degree of the exterior power +extPower = method(Options => {Degeneracy=>false,TopDegree => null}) +extPower(ZZ,SimplicialModule) := SimplicialModule => opts -> (d,S) -> (tdeg := topDegree S; + --C := S.complex; + L := hashTable for i to tdeg list i => exteriorPower(d,combineSFactors(S,i)); + H1 := hashTable for i in keys (S.dd.map) list i =>exteriorPower(d,((S.dd)_i)); + H2 := if opts.Degeneracy==true then hashTable for i in keys (S.ss.map) list i => exteriorPower(d,((S.ss)_i)); + --print("we made it"); + if opts.Degeneracy==true then return simplicialModule(L,H1,H2,tdeg); + simplicialModule(L,H1,tdeg) + ) + +extPower(ZZ,SimplicialModuleMap) := SimplicialModuleMap => opts -> (d,phi) -> ( + S1 := source phi; + S2 := target phi; + if instance((keys phi.map)#0,Sequence) then error "Expected SimplicialModuleMap to have singly graded indices"; + map(extPower(d,S2),extPower(d,S1),new HashTable from for i to max(topDegree S1,topDegree S2) list i => exteriorPower(d,phi_i),Degree => degree phi) + ) + +extPower(ZZ,Complex) := Complex => opts -> (d,C) -> (S := if not(opts.TopDegree === null) then simplicialModule(C,opts.TopDegree) + else simplicialModule(C,d*length(C)); + Sn := extPower(d,S); + normalize(Sn) + ) + +extPower(ZZ,ComplexMap) := ComplexMap => opts -> (d,phi) -> (phin := if not(opts.TopDegree === null) then simplicialModule(phi,opts.TopDegree) + else simplicialModule(phi,d*(max(length(source phi),length target phi))); + phik := extPower(d,phin); + normalize(phik) + ) + +--need to make this smarter: it should cache components so you can recover them easily + +--This function computes the simplicial tensor product and caches the direct sum +--indices so that the user can easily access components of the resulting face maps +--on particular direct summands of the tensor product +simplicialTensor = method(Options => {Degeneracy=>false,TopDegree => null}) +simplicialTensor(List) := SimplicialModule => opts -> T -> (if instance(T_0,SimplicialModule) then ( + degens := all(T, i->i.?ss); + tdeg := max apply(T,i->topDegree i); + L := hashTable for i to tdeg list i => tensorwithComponents(apply(T,s->s_i)); + H1 := hashTable for i in keys ((T_0).dd.map) list i => map(L#(i_0-1),L#(i_0),tensor(apply(T,s->s.dd_i))); + H2 := if opts.Degeneracy==true or degens then hashTable for i in keys ((T_0).ss.map) list i => tensorwithComponents(apply(T,s->s.ss_i)); + if opts.Degeneracy==true or degens then return simplicialModule(L,H1,H2,tdeg); + return simplicialModule(L,H1,tdeg); + ); + tLength := max apply(T,j->try length j else length source j); + if instance(T_0,Complex) then return normalize simplicialTensor(apply(T,j->simplicialModule(j,length(T)*tLength))); + if instance(T_0, ComplexMap) then return normalize tensor(apply(T, j -> simplicialModule(j, length(T)*tLength))); + ) + +simplicialTensor(SimplicialModule,SimplicialModule) := SimplicialModule => opts -> (S,T) -> (simplicialTensor({S,T})) + +simplicialTensor(ComplexMap, ComplexMap) := ComplexMap => opts -> (f,g) -> simplicialTensor({f,g}) + +simplicialTensor(ZZ,SimplicialModule) := SimplicialModule => opts -> (d,S) -> (simplicialTensor(toList(d:S),opts)) + +simplicialTensor(ZZ,Complex) := Complex => opts -> (d,C) -> (simplicialTensor(toList(d:C))) + +simplicialTensor(Complex,Complex) := Complex => opts -> (C,D) -> (simplicialTensor({C,D})) + + +SimplicialModule ** SimplicialModule := SimplicialModule => (S,T) -> (simplicialTensor(S,T)) + +hhh = method(); +hhh(Complex) := C -> (sum toList apply(0..length C,i->length HH_i(C))) + +degenMorphisms = method() +degenMorphisms(SimplicialModule,ZZ,ZZ) := (S,n,k) -> (Cn := naiveNorm(S,n); + map(Cn,Cn,i->(S.ss)_(i,k),Degree => 1) + ) + +degenMorphisms(Complex,ZZ,ZZ) := (C,n,k) -> (degenMorphisms(simplicialModule(C,n),n,k)) + +faceMorphisms = method() +faceMorphisms(SimplicialModule,ZZ,ZZ) := (S,n,k) -> (Cn := naiveNorm(S,n); + map(Cn,Cn,i->(S.dd)_(i,k),Degree => -1) + ) + +faceMorphisms(Complex,ZZ,ZZ) := (C,n,k) -> (faceMorphisms(simplicialModule(C,n),n,k)) + +makeNormMap = method(); +makeNormMap(SimplicialModule,ZZ) := (S,d) -> ( + K2 := intersect(for i from 1 to d list ker S.dd_(d,i)); + K1 := if d>1 then intersect(for i from 1 to d-1 list ker S.dd_(d-1,i)) else + if d ==1 then S_0; + I1 := if K1==0 then map(S_(d-1),(ring S)^0,0) + else inducedMap(S_(d-1),K1); + I2 := if K2==0 then map(S_d,(ring S)^0,0) + else inducedMap(S_(d),K2); + if I1 == 0 or I2 == 0 then return map(source I1,source I2,0); + ((S.dd_(d,0)*I2)//I1) + ) + +makeNormMap(SimplicialModuleMap,ZZ) := (phi,d) -> ( + S1 := source phi; + S2 := target phi; + if d==0 then return phi_0; + K1 := intersect( for i from 1 to d list ker S1.dd_(d,i)); + K2 := intersect( for i from 1 to d list ker S2.dd_(d,i)); + inducedMap(K2,K1,phi_d) + ) + +--this is the normalization functor from the category of simplicial modules +--back to the category of nonnegatively-graded chain complexes. +normalize = method(Options => {CheckSum => true,CheckComplex => true}); +normalize(SimplicialModule,ZZ) := Complex => opts -> (S,d) -> ( + if opts.CheckComplex and any(keys S,i->i==symbol complex) then return naiveTruncation(S.complex,0,d); + n := length components S; + if opts.CheckSum and n>1 then return directSum for i to n-1 list normalize((components S)_i,d); + complex for i from 1 to d list makeNormMap(S,i)) + +normalize(SimplicialModule) := Complex => opts -> S -> (if any(keys S,i->i==symbol complex) then return normalize(S,S.complexLength,opts); + normalize(S,S.topDegree,opts) + ) + +normalize(SimplicialModuleMap,ZZ) := ComplexMap => opts -> (phi,d) -> ( + if opts.CheckComplex and phi.cache.?complexMap then return naiveTruncation(phi.cache.complexMap,0,d); + n := length components phi; + if opts.CheckSum and n>1 then return directSum for i to n-1 list normalize((components phi)_i,d); + src := source phi; + trg := target phi; + C1 := normalize(src,d,opts); + C2 := normalize(trg,d,opts); + map(C2,C1,new HashTable from for i to max(max C1,max C2) list i => (if (f:=makeNormMap(phi,i)) == 0 then continue else map(C2_i, C1_i, f))) + ) + +normalize(SimplicialModuleMap) := ComplexMap => opts -> phi -> (d := max(topDegree source phi,topDegree target phi); + normalize(phi,d,opts) + ) + + +--this function computes the image of the 2nd exterior power into the tensor product +exteriorInclusion = method(); +exteriorInclusion(Module) := M -> ( + inducedMap(M**M,image(id_M**id_M-tensorCommutativity(M,M))) + ) + + +exteriorInclusion(SimplicialModule) := S -> (cS := forgetComplex S; + w2S := extPower(2,S); + T := S**S; + map(T,w2S,hashTable for i in keys cS.module list i => (dual wedgeProduct(1,1,dual cS.module#i))) + ) + +exteriorInclusion(Complex,ZZ) := (C,d) -> (normalize exteriorInclusion(simplicialModule(C,d))) + +exteriorInclusion(Complex) := C -> (exteriorInclusion(C,length C)) + +--computes the image of the surjection from the simplicial tensor product +--onto the second symmetric power of a complex +symmetricQuotient = method(); +symmetricQuotient(Module) := M -> ( + phi := exteriorInclusion(M); + inducedMap(coker phi,ambient coker phi) + ) + +symmetricQuotient(SimplicialModule) := S -> ( + phi := exteriorInclusion(S); + inducedMap(coker phi,target phi) + ) + +symmetricQuotient(Complex,ZZ) := (C,d) -> (normalize symmetricQuotient(simplicialModule(C,d))) + +symmetricQuotient(Complex) := C -> (symmetricQuotient(C,length C)) + + +--this computes the long exact sequence of homology induced by the canonical short +--exact sequence of complexes $0 --> \wedge^2 --> T^2 --> Sym^2 --> 0$ +tensorLES = method(); +tensorLES(Complex,ZZ) := (C,d) -> (phi1 := exteriorInclusion(C,d); + phi2 := inducedMap(coker phi1,target phi1); + longExactSequence(prune phi2,prune phi1, Concentration => LengthLimit => d-1) + ) + + + +posComps = (n,d) -> (compositions(d, n-d))/(i -> i + toList(d : 1)) + +surjectionBijection = L -> ( + n := length L - 1; + d := sum L - 1; + lo := 0; + H := new MutableHashTable from {}; + for i from 0 to n do ( + for j from lo to lo + L_i-1 do ( + H#(j) = i; + ); + lo = lo + L_i; + ); + new HashTable from H + ) + +summandSurjection = method() +summandSurjection(ZZ,ZZ) := (n,d) -> ( + L := sort posComps(n+1,d+1); + L/surjectionBijection + ) + + + + + + + + + diff --git a/M2/Macaulay2/packages/SimplicialModules/SimplicialMapUtilities_Modified.m2 b/M2/Macaulay2/packages/SimplicialModules/SimplicialMapUtilities_Modified.m2 new file mode 100644 index 0000000000..51d4e29b72 --- /dev/null +++ b/M2/Macaulay2/packages/SimplicialModules/SimplicialMapUtilities_Modified.m2 @@ -0,0 +1,253 @@ +entryCalculatorModified = (mu,j) -> ( + -- Calculates the (mu,j)'th entry of the A matrix + -- mu is a composition and j ranges from 0 to n + -- Note the we get compositions with strictly positive parts + -- by taking compositions with non-negative parts and adding one + u := 0; + for mui in (reverse mu) do ( + u=u+mui+1; + if u == j+1 then ( + if mui == 0 then + return 2 + else + return 1 + ); + ); + 0 +) + +entryCalculatorTrans = (j,mu) -> ( + -- Calculates the (mu,j)'th entry of the A matrix + -- mu is a composition and j ranges from 0 to n + -- Note the we get compositions with strictly positive parts + -- by taking compositions with non-negative parts and adding one + u := 0; + for i from 0 to #mu-1 do ( + u=u+mu_i+1; + if u == j+1 then ( + if mu_i == 0 then + return 2 + else + return 1 + ); + ); + 0 +) + + + +promoteMaptoComplex = (d,k,C) -> (matrix d)**id_(C_k) + +promoteFaceMapZerotoComplex = (d,C) -> matrix ( + -- This runs over the whole matrix again and so is probably not an efficient way of doing things + -- Having the output of FaceMapZero be a hash table would be faster + d / (i -> apply(i,j -> ( + if j<0 then ( + id_(C_(abs(j+1))) + -- abs because identities were stored as negatives + -- +1 first because we stored identity of C_k as -k-1 + ) + else if j>0 then ( + dd^C_(j-1) + -- -1 because we stored the differential of C_k as k+1 + -- I don't actually think we need to do that though? probably could just store it as k + ) + else 0 + ) + ) + ) + ) + +zeroMatrix = (numRow,numCol) -> toList (numRow:(toList(numCol:0))); +zeroMemoized = memoize zeroMatrix + -- Faster than using table + +-*ACol = ( + (n,k,j) -> apply(sort compositions(k+1,n-k), mu -> entryCalculator(mu,j)) + ) + -- Returns the jth column of the AMatrix + *- + +ACol = (n,k,j) -> ( + apply(compositions(k+1,n-k), mu -> entryCalculatorModified(mu,j)) + ) + +Amattrans = (n,k) -> ( + -- Computes the transpose of amatrix + -- since we always access it by columns later it's more convenient + table(sort compositions(k+1,n-k,0..n,entryCalculatorTrans) + ) +) + +--registerFinalizer(ACol,"Garbage Collected") + +rowOfId = (n,l) -> splice {l:0,1,(n-1-l):0} +-- n-1 so that the result has n-many columns + + +faceMapZero = (n,len) -> ( + -- Output is topDeg-many rows and sum(len,i->binomial(n,i))-many columns + -* This probably can be optimized + The output is extremely sparse, so should probably be reimplemented + as a hash table or function of some kind that specifies rules for + the i,j'th entry of the table + *- + -- If bounded => true then do this + -- TODO implement option toggle for bounded complexes + -- (otherwise why sum these binomial coefficients) + maxRows := sum(len+1,i->binomial(n-1,i)); + -- The number of rows, taking into account complex length bound + -- When len is larger than n, we'll have 2^n many rows + offset := 0; -- keeps track of what the top zero pad should be + verticalStrips := for k to len list ( + -- First loop over the vertical strips of columns + bink := binomial(n,k); -- Each strip is width binomial(n,k) + topZeros := zeroMatrix(offset,bink); + -- Create appropriately sized top pad of zeros + modifiedMat := for row to bink-1 list ( + -- This modified identity matrix uses Pascal's identity + -- First binomial(n-1,k-1) entries will be differential + if row<=binomial(n-1,k-1)-1 then splice{row:0,k+1,(bink-1-row):0} + --k+1 to keep track of which differential we'll need (k'th diff of complex) + else splice{row:0, -k-1,(bink-1-row):0} + -- -k-1 to keep track of which identity map we'll need (identity map of C_k) + ); + botZeros := zeroMatrix(maxRows-offset-binomial(n,k),binomial(n,k)); + -- Create appropriately sized bottom pad of zeros + offset = offset + binomial(n-1,k-1); + -- Update the offset + verticalStrip := flatten{topZeros,modifiedMat,botZeros} + -- Concat the modified matrix with the pads + ); + for row to maxRows-1 list ( + -- This concats the rows of the vertical strips together + flatten apply(verticalStrips, strip->strip#row) + ) + ) + + +faceMapnk = (n,k) -> ( + -- output is binomial(n-1,k)-many rows and binomial(n,k)-many columns + if k==n then + -- I don't remember if we actually need this check + -- I think we need to zero pad extra rows at when faceMapi is called below + {{0}} + else ( + Abigvector := ACol(n,k,n); + -- Selects the nth column of AMat(n,k) + Asmallvector := ACol(n-1,k,n-1); + -- Selects the (n-1)th column of AMat(n-1,k) + onePos := positions(Abigvector, i -> i==1); + -- The positions of ones in Asmallvector describe horizontal locations where we'll want a row of the identity matrix + outputMat := onePos / (l -> rowOfId(binomial(n,k),l)) + ) + ) + + -*faceMapnk = (n,k) -> ( + -- output is binomial(n-1,k)-many rows and binomial(n,k)-many columns + if k==n then + -- I don't remember if we actually need this check + -- I think we need to zero pad extra rows at when faceMapi is called below + {{0}} + else ( + Abigvector := ACol(n,k,n); + -- Selects the nth column of AMat(n,k) + Asmallvector := ACol(n-1,k,n-1); + -- Selects the (n-1)th column of AMat(n-1,k) + onePos := positions(Abigvector, i -> i==1); + -- The positions of ones in Asmallvector describe horizontal locations where we'll want a row of the identity matrix + outputMat := onePos / (l -> rowOfId(binomial(n,k),l)) + ) + )*- + +faceMapik = (n,k,i) -> ( + -- I think there are supposed to be binomial(n-1,k)-many rows + -- There are binomial(n,k)-many columns + -- I think my timing code was wack and this is actually slower than the earlier implementation + -- Need to go back and check that + -- From what I recall, they were both pretty close though so it's not a high priority + Abigvector := ACol(n,k,i); + Asmallvector := ACol(n-1,k,i-1); + zeroPos := positions(Abigvector, i -> i==0); + onePos := positions(Abigvector, i -> i==1); + outputMat := new MutableList from zeroPos / (l -> rowOfId(binomial(n,k),l)); + sumPositions := positions(Asmallvector, i->i>=1); + for l to #sumPositions-1 do ( + myIndex := sumPositions_l; + outputMat#myIndex = outputMat#myIndex + (rowOfId(binomial(n,k),onePos#l)); + ); + toList outputMat +) + +faceMapi = (n,i,C) -> ( + -- Need to check if this can be sped up by direct summing as lists + -- Instead of first passing to matrices + -- and then saving the creation of the matrix option till the very end + (lo, hi) := concentration C; + maxK := min(hi,n-1); + -- Are we running till maxK? or until maxK+1? + if i==0 then ( + maxK = min(hi,n); + promoteFaceMapZerotoComplex(faceMapZero(n,maxK),C) + ) + else if i==n then ( + preMat := fold(directSum,for k from 0 to maxK list ( + promoteMaptoComplex(faceMapnk(n,k),k,C) + -- Notice that we only pass in k at most n-1, so the check for k==n in faceMapi isn't needed + )); + preMat | map(target preMat,C_n,0) + ) + else ( + preMat = fold(directSum,for k from 0 to maxK list ( + promoteMaptoComplex(faceMapik(n,k,i),k,C) + )); + preMat | map(target preMat,C_n,0) + ) + ) + +degenMapik = (n, k, i) -> ( + -- We'll have binomial(n,k) many columns #A(n+1,k)=binomial(n+1,k)-many rows + + numCols := binomial(n,k); + zeroes := new List from (numCols) : 0; + col := ACol(n+1,k,i); + sig := new MutableList from 0..(#col-1); + l := 0; + for j to (#col-1) do( + if (col#j == 0) then ( + sig#j = rowOfId(numCols,l); + l = l+1; + continue; + ); + sig#j = zeroes; + ); + new List from sig + ) + +-*degenMapi = (n,i,C) -> ( + maxK := min(length C,n); + preMat := fold(directSum,for k from 0 to maxK list ( + promoteMaptoComplex(degenMapik(n,k,i),k,C) + ) + ); + preMat || map(C_(n+1),source preMat,0) + )*- + + +degenMapi = (n,i,C) -> ( + maxK := min(max C,n); + preMat := fold(directSum,for k from 0 to maxK list ( + promoteMaptoComplex(degenMapik(n,k,i),k,C) + ) + ); + preMat || map(C_(n+1),source preMat,0) + ) + + + + + + + + + diff --git a/M2/Macaulay2/packages/SimplicialModules/SimplicialModule.m2 b/M2/Macaulay2/packages/SimplicialModules/SimplicialModule.m2 new file mode 100644 index 0000000000..fa9d60d6fc --- /dev/null +++ b/M2/Macaulay2/packages/SimplicialModules/SimplicialModule.m2 @@ -0,0 +1,1436 @@ + needsPackage "Complexes" + + SimplicialModule = new Type of MutableHashTable -- + -- note: we make this mutable in order to construct the + -- differential as a morphism of Simplicial modules (in the style of Complexes) + -- BUT: after construction, it is should be IMMUTABLE!! + -- at some point, we might want to allow lazy determination of the modules and maps + -- but for now, we insist that all modules and maps are explicit. + -- key: + -- ring + -- modules: hash table: ZZ => Module + -- differential: SimplicialModuleMap from C --> C, degree -1 + + + SimplicialModuleMap = new Type of HashTable + -- keys: + -- degree: ZZ + -- source: Simplicial module over a ring R + -- target: simplicial module over the same ring R + -- maps themselves (HashTable of Matrices), keys lying in the concentration period of the source. + -- not all of the keys maps#i, need be present. + -- missing ones are presumed to be zero maps. + -- cache: a CacheTable + -- cache.isCommutative: whether this map commutes with the face/degeneracy maps + -- not set until needed. unset means we have not checked yet, + -- and the user hasn't declared it to be true/false yet. + +SimplicialModule.synonym = "Simplicial Module" +SimplicialModuleMap.synonym = "Map of Simplicial Modules" + +topDegree = method(); +topDegree SimplicialModule := ZZ => S -> S.topDegree +topDegree SimplicialModuleMap := ZZ => f -> max(topDegree source f, topDegree target f) + +ring SimplicialModule := Ring => S -> S.ring + +moduleMaker = (C,d) -> ( + moduleList := new MutableHashTable; + maxK := min (d, length C); + for k to maxK do ( + moduleList#(d,k) = directSum toList( + binomial(d,k):(C_k)); + ); + for i in (sort keys moduleList) list (i,moduleList#i) + ) + +mapMaker = (phi,d) -> ( + mapList := new MutableHashTable; + maxK := min (d, max(length source phi,length target phi)); + for k to maxK do ( + mapList#(d,k) = directSum toList( + binomial(d,k):(phi_k)); + ); + for i in (sort keys mapList) list (i,mapList#i) + ) + + + + +--H1 is the face maps, H2 is the degeneracy maps +simplicialModule = method(Options => {Base=>0,Degeneracy => false}) +simplicialModule(Complex,HashTable,HashTable,ZZ) := SimplicialModule => opts -> (C,H1,H2,d) -> ( + spots := sort keys H1; + if #spots === 0 then + error "expected at least one map"; + R := ring C; + moduleList := new MutableHashTable; + for b to d do ( + maxK := min (b, max C); + for k to maxK do ( + modwComps := directSum toList(binomial(b,k):(C_k)); + modwComps.cache.components = flatten toList(binomial(b,k):(components (C_k))); + moduleList#(b,k) = modwComps + ); + ); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => new HashTable from moduleList, + symbol cache => new CacheTable, + symbol complexLength => max C, + symbol complex => C + }; + S.dd = map(S,S,H1,Degree=>-1); + S.ss = map(S,S,H2,Degree=>1); + S + ) + +--H1 is the face maps +simplicialModule(Complex,HashTable,ZZ) := SimplicialModule => opts -> (C,H1,d) -> (--print("made it here!"); + spots := sort keys H1; + if #spots === 0 then + error "expected at least one map"; + (lo, hi) := concentration C; + R := ring C; + moduleList := new MutableHashTable; + for b to d do ( + maxK := min (b, hi); + for k to maxK do ( + modwComps := directSum toList(binomial(b,k):(C_k)); + modwComps.cache.components = flatten toList(binomial(b,k):(components (C_k))); + moduleList#(b,k) = modwComps + ); + ); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => new HashTable from moduleList, + symbol cache => new CacheTable, + symbol complexLength => hi, + symbol complex => C + }; + S.dd = map(S,S,H1,Degree=>-1); + S + ) + +simplicialModule(HashTable,HashTable,HashTable,ZZ) := SimplicialModule => opts -> (L,H1,H2,d) -> (--print("we got started"); + R := ring (L#((keys L)#0)); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => L, + symbol cache => new CacheTable, + }; + S.dd = map(S,S,H1,Degree=>-1); + S.ss = map(S,S,H2,Degree=>1); + S + ) + +simplicialModule(HashTable,HashTable,ZZ) := SimplicialModule => opts -> (L,H1,d) -> (--print("we got started"); + R := ring (L#((keys L)#0)); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => L, + symbol cache => new CacheTable, + }; + S.dd = map(S,S,H1,Degree=>-1); + S + ) + + +simplicialModule(Complex,ZZ) := SimplicialModule => opts -> (C,d) -> ( + --C is a chain complex, output is the Dold-Kan image of C in the category of simplicial modules + if not instance(opts.Base, ZZ) then + error "expected Base to be an integer"; + (lo, hi) := concentration C; + --if lo == hi then + if instance(C,Complex) then ( + if opts.Degeneracy == true then (degenmapHash := hashTable flatten for n from 0 to d-1 list ( + for i from 0 to n list ( + (n,i) => degenMapi(n,i,C) + ) + );); + facemapHash := hashTable flatten for n from 1 to d list ( + for i from 0 to n list ( + (n,i) => faceMapi(n,i,C) + ) + ); + --print("mde it here first"); + if opts.Degeneracy == true then break return simplicialModule(C,facemapHash,degenmapHash,d); + --print("made it here"); + return simplicialModule(C,facemapHash,d) + ); + ) + + simplicialModule(Complex) := SimplicialModule => opts -> C -> (simplicialModule(C,max C,Degeneracy => opts.Degeneracy)) + + + simplicialModule(Module,ZZ) := SimplicialModule => opts -> (M,d) -> (simplicialModule(complex M,d,Degeneracy => opts.Degeneracy)) + + simplicialModule(Ring,ZZ) := SimplicialModule => opts -> (R,d) -> (simplicialModule(R^1,d,Degeneracy => opts.Degeneracy)) + +simplicialModule(Ideal, ZZ) := SimplicialModule => opts -> (I,d) -> simplicialModule(module I, d, opts) + +simplicialModule(ComplexMap,ZZ) := SimplicialModuleMap => opts -> (phi,d) -> ( + deg := degree phi; + src := simplicialModule(source phi,d, opts); + trg := simplicialModule(target phi, d, opts); + if deg > 0 then return simplicialModule map((target phi)[deg], source phi, phi, Degree => 0); + if deg < 0 then return simplicialModule map(target phi, (source phi)[-deg], phi[-deg], Degree => 0); + result := map(trg,src,new HashTable from for i to d list i => directSum apply(mapMaker(phi,i),j->j_1),Degree => degree phi); + result.cache.complexMap = phi; + result + ) + +simplicialModule(ComplexMap) := SimplicialModuleMap => opts -> phi -> (tDeg := max((source phi).concentration_1,(target phi).concentration_1); + simplicialModule(phi,tDeg, opts) + ) + + + +isWellDefined SimplicialModule := Boolean => C -> ( + k := keys C; + -- check keys, check their types + if not instance(C.ring, Ring) then ( + if debugLevel > 0 then ( + << "-- expected 'ring C' to be a ring" << endl; + ); + return false; + ); + (lo,hi) := (0, C.topDegree); + if not instance(hi,ZZ) or lo > hi then ( + if debugLevel > 0 then ( + << "-- expected topDegree to be a nonnegative integer" << endl; + ); + return false; + ); + if not instance(C.module, HashTable) then ( + if debugLevel > 0 then ( + << "-- expected C.module to be a HashTable" << endl; + ); + return false; + ); + if not instance(C.dd, SimplicialModuleMap) then ( + if debugLevel > 0 then ( + << "-- expected dd^C to be a SimplicialModuleMap" << endl; + ); + return false; + ); + if not instance(C.cache, CacheTable) then ( + if debugLevel > 0 then ( + << "-- expected 'C.cache' to be a CacheTable" << endl; + ); + return false; + ); + -- check ring matches modules + if not all(keys C.module, i -> instance(i,Sequence) and i_0 >= lo and i_0 <= hi) + and not all(keys C.module, i -> instance(i,ZZ) and i >= lo and i <= hi) then ( + if debugLevel > 0 then ( + << "-- expected all keys of C.module to be sequences or integers with nonnegative first entry, bounded by the top degree" << [lo,hi] << endl; + ); + return false; + ); + if not all(values C.module, m -> ring m === ring C) then ( + if debugLevel > 0 then ( + << "-- expected all modules in C.module to be over 'ring C'" << endl; + ); + return false; + ); + -- check face maps + if ring C.dd =!= ring C then ( + if debugLevel > 0 then ( + << "-- expected ring of the face maps to be the ring of the simplicial module" << endl; + ); + return false; + ); + if degree C.dd =!= -1 then ( + if debugLevel > 0 then ( + << "-- expected degree of the face maps to be -1" << endl; + ); + return false; + ); + if not all(keys (dd^C).map, i -> instance(i,Sequence) and i_0 >= lo+1 and i_0 <= hi) then ( + if debugLevel > 0 then ( + << "-- expected all maps of the face maps to be indexed by integers in the concentration [lo+1,hi]" << endl; + ); + return false; + ); + for i from lo+1 to hi do ( + f := dd^C_i; + if source f =!= C_i or target f =!= C_(i-1) + then ( + if debugLevel > 0 then ( + << "-- expected source and target of the face maps to be modules in the simplicial module " << endl; + << "-- face map at index " << i << " fails this condition" << endl; + ); + return false; + ); + ); + if not(C.?ss) then ( + D := naiveNorm C; + if not isWellDefined D then ( + if debugLevel > 0 then ( + << "-- expected naive normalization to be a well-defined complex " << endl; + ); + return false; + ); + ); + if C.?ss then ( + if not isSimplicialModule C then ( + if debugLevel >0 then ( + << "--object fails to satisfy simplicial identities; run isSimplicialModule to see where it fails" << endl; + ); + return false; + ); + ); + true + ) + + +--this method checks if the simplicial identities hold for simplicial objects with degeneracy map keys +isSimplicialModule = method() +isSimplicialModule(SimplicialModule) := Boolean => S -> ( + if not S.?ss then error "Expected S to have both face and degeneracy maps"; + faceMaps := S.dd; + degenMaps := S.ss; + t := S.topDegree; + for i from 1 to t do ( + for j from 2 to i do ( + for k from 1 to j-1 do ( + if not(dd^S_(i-1,k)*dd^S_(i,j) == dd^S_(i-1,j-1)*dd^S_(i,k)) + then ( + if debugLevel > 0 then ( + << "--simplicial map identities fail for face/face compositions" << endl; + << "--face/face composition for indices " << (i,j,k) << " fail" << endl; + ); + return false; + ); + ); + ); + ); + for i from 0 to t-1 do ( + for j from 0 to i do ( + for k from 0 to j-1 do ( + if not(dd^S_(i+1,k)*ss^S_(i,j) == ss^S_(i-1,j-1)*dd^S_(i,k)) + then ( + if debugLevel > 0 then ( + << "--simplicial map identities fail for face/degeneracy compositions" << endl; + << "--face/degeneracy composition for indices " << (i,j,k) << " fail" << endl; + ); + return false; + ); + ); + ); + ); + for i from 0 to t-1 do ( + for j from 0 to i do ( + if not(dd^S_(i+1,j)*ss^S_(i,j) == 1) or not(dd^S_(i+1,j+1)*ss^S_(i,j) == 1) + then ( + if debugLevel > 0 then ( + << "--simplicial map identities fail for face/degeneracy compositions" << endl; + << "--face/degeneracy composition for indices " << (i,j,j) << " fail" << endl; + ); + return false; + ); + ); + ); + for i from 0 to t-1 do ( + for j from 0 to i do ( + for k from j+2 to i do ( + if not(dd^S_(i+1,k)*ss^S_(i,j) == ss^S_(i-1,j)*dd^S_(i,k-1)) + then ( + if debugLevel > 0 then ( + << "--simplicial map identities fail for face/degeneracy compositions" << endl; + << "--face/degeneracy composition for indices " << (i,j,k) << " fail" << endl; + ); + return false; + ); + ); + ); + ); + for i from 0 to t-1 do ( + for j from 0 to i do ( + for k from 0 to j do ( + if not(ss^S_(i+1,k)*ss^S_(i,j) == ss^S_(i+1,j+1)*ss^S_(i,k)) + then ( + if debugLevel > 0 then ( + << "--simplicial map identities fail for degeneracy/degeneracy compositions" << endl; + << "--degeneracy/degeneracy composition for indices " << (i,j,k) << " fail" << endl; + ); + return false; + ); + ); + ); + ); + true + ) + + + +isWellDefined SimplicialModuleMap := f -> ( + k := keys f; + -- source and target + if ring f.source =!= ring f.target then ( + if debugLevel > 0 then ( + << "-- expected source and target to have the same ring" << endl; + ); + return false; + ); + if not isWellDefined f.source or not isWellDefined f.target then ( + if debugLevel > 0 then ( + << "-- expected source and target to be well-defined simplicial modules" << endl; + ); + return false; + ); + if not instance(f.degree, ZZ) then ( + if debugLevel > 0 then ( + << "-- expected degree of homomorphism to be an integer" << endl; + ); + return false; + ); + (lo,hi) := (0,f.source.topDegree); + if not all(keys f.map, i -> instance(i,ZZ) or instance(i, Sequence)) then ( + if debugLevel > 0 then ( + << "-- expected all maps to be indexed by integers or sequences of two integers" << endl; + ); + return false; + ); + if all(keys f.map, i -> instance(i,ZZ)) then for i from lo to hi do ( + g := f_i; + if source g =!= f.source_i or target g =!= f.target_(i+f.degree) + then ( + if debugLevel > 0 then ( + << "-- expected source and target of maps to agree with those of simplicial module " << endl; + << "-- the map at index " << i << " fails this condition" << endl; + ); + return false; + ); + ); + --print "here we are"; + if all(keys f.map, i -> instance(i,ZZ)) and f.cache.?isCommutative then ( + deg := degree f; + C := f.source; + D := f.target; + (loC,hiC) := (0, C.topDegree); + (loD,hiD) := (0, D.topDegree); + iscommutative := true; + for i from loC to hiC do ( + if i+deg-1 >= loD and i+deg-1 <= hiD then ( + for l from 0 to i do ( + if not (dd^D_(i+deg,l) * f_i == (-1)^deg * (f_(i-1) * dd^C_(i,l))) + then ( + iscommutative = false; + if f.cache.isCommutative then ( + if debugLevel > 0 then ( + << "-- the cache table incorrectly asserts that the maps commute with the differentials " << endl; + << "-- differential at index " << i << " fails this condition" << endl; + ); + return false; + ); + ) + );)); + if iscommutative and not f.cache.isCommutative then ( + if debugLevel > 0 then ( + << "-- the cache table incorrectly asserts that the maps do not commute with the differentials " << endl; + ); + return false; + ); + ); + true + ) + + +isCommutative SimplicialModuleMap := Boolean => f -> ( + if debugLevel == 0 and f.cache.?isCommutative then + return f.cache.isCommutative; + C := source f; + D := target f; + deg := degree f; + hasDegens := C.?ss and D.?ss; + (loC,hiC) := (0, C.topDegree); + (loD,hiD) := (0, D.topDegree); + for i from loC to hiC do ( + if i+deg-1 >= loD and i+deg-1 <= hiD then ( + for l from 0 to i do ( + if not (dd^D_(i+deg,l) * f_i == (-1)^deg * (f_(i-1) * dd^C_(i,l))) + or not (if hasDegens then ss^D_(i+deg,l) * f_i == (-1)^deg * (f_(i+1) * ss^C_(i,l)) else true) + then ( + if debugLevel > 0 then ( + << "-- block " << (i,i-1) << " fails to commute" << endl; + ); + f.cache.isCommutative = false; + return false; + ) + ); + ) + ); + f.cache.isCommutative = true; + true + ) + +isSimplicialMorphism = method(TypicalValue => Boolean) +isSimplicialMorphism SimplicialModuleMap := (f) -> ( + if debugLevel > 0 and degree f =!= 0 then ( + << "-- the complex map has non-zero degree" << endl; + return false; + ); + degree f === 0 and isCommutative f + ) + + +--this function forgets the data of the underlying complex of a simplicial module, if the simplicial module S +--is obtained as a Dold-Kan image + forgetComplex = method(Options => {RememberSummands => true}); + forgetComplex(SimplicialModule) := SimplicialModule => opts -> S -> ( + if not any(keys S,i->i==symbol complex) then return S; + L := new HashTable from for i to S.topDegree list i => combineSFactors(S,i,RememberSummands => opts.RememberSummands); + faces := new HashTable from for i in keys S.dd.map list i => S.dd.map#i; + if any(keys S,i->i==symbol ss) then ( + degens := new HashTable from for i in keys S.ss.map list i => S.ss.map#i; + return simplicialModule(L,faces,degens,S.topDegree); + ); + D := simplicialModule(L,faces,S.topDegree); + D.cache.components = components S; + D + ) + +--totalizing operation +combineSFactors = method(Options => {RememberSummands => true}); +combineSFactors(SimplicialModule,ZZ) := Module => opts -> (S,d) -> ( + if d<0 or d > S.topDegree then return (ring S)^0; + modwComps := directSum for j in components S list directSum for i to min(d,j.complexLength) list (j.module)#(d,i); + if opts.RememberSummands then modwComps.cache.components = flatten flatten for j in components S list for i to min(d,S.complexLength) list components (S.module#(d,i)); + modwComps + ) + + +--forgets the data of degeneracy maps of a simplicial object + --useful for when the user wants to ignore degeneracy maps + --for the purposes of speeding up computations + forgetDegeneracy = method(); + forgetDegeneracy(SimplicialModule) := S -> ( + if not any(keys S,i->i==symbol ss) then return S; + if any(keys S,i->i==symbol complex) then return simplicialModule(S.complex,S.dd.map,S.topDegree); + simplicialModule(S.module,S.dd.map,S.topDegree) + ) + + +SimplicialModule _ Sequence := Module => (S,p) -> ( + if #p =!= 2 then + error ("Expected a pair of integer indices"); + if S.module#?(p#0,p#1) then S.module#(p#0,p#1) else (ring S)^0 + ) + + +SimplicialModule _ ZZ := Module => (S,n) -> (if S.module#?n then S.module#n else combineSFactors(S,n)) + + + +net SimplicialModule := S -> ( + (lo,hi) := (0,topDegree S); + if lo > hi then + error "In a simplical module, top degree should be nonnegative" + --"0" + else if lo == hi and S_lo === 0 then + "0" + else if any(keys S,i->i==symbol complex) then + (horizontalJoin (between(" <-- ", + for i from lo to hi list + stack (net directSum(for k from 0 to min(i,S.complexLength) list (S.module)#(i,k)), " ", net i)) | {"<-- ..."}) ) + else + horizontalJoin (between(" <-- ", + for i from lo to hi list + stack (net ((S.module)#i), " ", net i)) | {"<-- ..."}) + ) + + + Symbol ^ SimplicialModule := SimplicialModuleMap => (sym, C) -> ( + if sym === dd then return C.dd; + if sym === ss then C.ss + else error "expected symbol to be 'dd' or 'ss'" + ) + +lineOnTop := (s) -> concatenate(width s : "-") || s + +source SimplicialModuleMap := SimplicialModule => f -> f.source +target SimplicialModuleMap := SimplicialModule => f -> f.target +ring SimplicialModuleMap := SimplicialModule => f -> ring source f +degree SimplicialModuleMap := ZZ => f -> f.degree + +isHomogeneous SimplicialModuleMap := (f) -> all(values f.map, isHomogeneous) + +--simplicialModuleMap = method(Options => {Degeneracy => false}); + + + + +map(SimplicialModule, SimplicialModule, HashTable) := SimplicialModuleMap => opts -> (tar, src, maps) -> ( + if not(topDegree tar == topDegree src) then error "expected source and target to have the same top degree"; + R := ring tar; + if ring src =!= R or any(values maps, f -> ring f =!= R) then + error "expected source, target and maps to be over the same ring"; + deg := if opts.Degree === null + then 0 + else if instance(opts.Degree, ZZ) then + opts.Degree + else + error "expected integer degree"; + (lo,hi) := (0,topDegree tar); + maps' := hashTable for k in keys maps list ( + if instance(k, Sequence) then ( + f := maps#k; + -- note: we use != instead of =!= in the next 2 tests, + -- since we want to ignore any term order differences + --print(k); + --print(source f); + --print(src_(first k)); + -*if rank source f != rank src_( first k) then ( + error ("map with index "|toString(k)|" has inconsistent source"); + ); + if rank target f != rank tar_(first(k)+deg) then + error ("map with index "|toString(k)|" has inconsistent target"); + if first k < lo or first k > hi then continue else*- (k,f) + ) + else ( + f = maps#k; + -- note: we use != instead of =!= in the next 2 tests, + -- since we want to ignore any term order differences + --print(k); + --print(source f); + --print(src_(first k)); + -*if source f != src_(k) then ( + error ("map with index "|toString(k)|" has inconsistent source"); + ); + if target f != tar_(k+deg) then + error ("map with index "|toString(k)|" has inconsistent target"); + if k < lo or k > hi then continue else*- (k,f) + )); + new SimplicialModuleMap from { + symbol source => src, + symbol target => tar, + symbol degree => deg, + symbol map => maps', + symbol cache => new CacheTable + } + ) + +map(SimplicialModule, SimplicialModule, ZZ) := SimplicialModuleMap => opts -> (D, C, j) -> ( + if j === 0 then ( + result := map(D,C,hashTable{},opts); + result.cache.isCommutative = true; + return result + ); + if j === 1 then ( + if C == D and (opts.Degree === null or opts.Degree === 0) then + return id_C; + error "expected source and target to be the same"; + ); + error "expected integer to be zero or one"; + ) + +---this method is good for inducing maps on subcomplexes +map(SimplicialModule, SimplicialModule, SimplicialModuleMap) := SimplicialModuleMap => opts -> (tar, src, f) -> ( + deg := if opts.Degree === null then degree f else opts.Degree; + H := hashTable for k in keys f.map list k => map(tar_(deg+k), src_k, f.map#k); + map(tar,src,H, Degree=>deg) + ) + + + + +SimplicialModuleMap _ ZZ := Matrix => (f,i) -> ( + if f.map#?i then f.map#i else map((target f)_(i + degree f), (source f)_i, 0)) + +SimplicialModuleMap _ Sequence := Matrix => (f,s) -> ( + if f.map#?s then f.map#s else map((target f)_(s#0 + degree f), (source f)_(s#0), 0)) + + + + +expression SimplicialModuleMap := Expression => f -> ( + d := degree f; + s := sort keys f.map; + if #s === 0 then + new ZeroExpression from {0} + else if instance(s_0,Sequence) then new VerticalList from for i in s list + RowExpression {(i#0+d,i#1), ":", MapExpression { target f_i, source f_i, f_i }, ":", i} + else if instance(s_0,ZZ) then return new VerticalList from for i in s list + RowExpression {i+d, ":", MapExpression { target f_i, source f_i, f_i }, ":", i} + ) + + + + net SimplicialModuleMap := Net => f -> ( + v := between("", + for i in sort keys f.map list ( + if instance(i,Sequence) then (horizontalJoin( + net ((i#0+f.degree,i#1)), " : ", net target f_i, " <--", + lineOnTop net f_i, + "-- ", net source f_i, " : ", net i + )) + else (horizontalJoin( + net (i+f.degree), " : ", net target f_i, " <--", + lineOnTop net f_i, + "-- ", net source f_i, " : ", net i + )) + )); + if # v === 0 then net "0" + else stack v + ) + + + + +SimplicialModule == ZZ := (C,n) -> ( + if n =!= 0 then error "cannot compare Simplicial module to non-zero integer"; + (lo,hi) := (0,C.topDegree); + for i from lo to hi do if C_i != 0 then return false; + true + ) +ZZ == SimplicialModule := (n,C) -> C == n + +--as written, the code assumes one only takes direct sums of simplicial modules with same top degree +SimplicialModule.directSum = args -> ( + local D; + assert(#args > 0); + R := ring args#0; + if not all(args, C -> ring C === R) then error "expected all simplicial modules to be over the same ring"; + concentrations := for C in args list (0,C.topDegree); + --checking if they all are Dold-Kan images + allComplexes := all(args,i->any(keys i,j->j==symbol complex)); + allDegens := all(args,i->any(keys i, j->j== symbol ss)); + if not allComplexes then args = apply(args,i->forgetComplex(i)); + lo := concentrations/first//min; + hi := concentrations/last//max; + if not(all(args,i->i.topDegree==hi)) then error "all objects should have the same top degree"; + S := first args; + LM := new HashTable from for i in keys S.module list i => directSum for j in args list if j.module#?i then j_i else continue; + faceHashM := new HashTable from for i in keys S.dd.map list i => directSum for j in args list if j.dd.map#?i then j.dd_i; + if allDegens then ( + degenMapHashM := new HashTable from for i in keys S.ss.map list i => directSum for j in args list if j.ss.map#?i then j.ss_i; + D = if allComplexes then simplicialModule(directSum for i in args list i.complex,faceHashM,degenMapHashM,hi) + else simplicialModule(LM,faceHashM,degenMapHashM,hi); + D.cache.components = toList args; + return D; + ); + D = if allComplexes then simplicialModule(directSum for i in args list i.complex,faceHashM,S.topDegree) + else simplicialModule(LM,faceHashM,S.topDegree); + D.cache.components = toList args; + D + ) +SimplicialModule ++ SimplicialModule := SimplicialModule => (C,D) -> directSum(C,D) +directSum SimplicialModule := C -> directSum(1 : C) + +components SimplicialModule := C -> if C.cache.?components then C.cache.components else {C} + +SimplicialModule#id = (C) -> ( + (lo,hi) := (0,C.topDegree); + maps := hashTable for i from lo to hi list i => id_(C_i); + result := map(C,C,maps); + result.cache.isCommutative = true; + result + ) + + +SimplicialModuleMap ^ ZZ := SimplicialModuleMap => (f,n) -> ( + tDeg := (source f).topDegree; + df := degree f; + if n === -1 then ( + maps := hashTable for i from 0 to tDeg list (i+df) => ( + f_i^(-1) + ); + result := map(source f, target f, maps, Degree=>-df); + if f.cache.?isCommutative then result.cache.isCommutative = f.cache.isCommutative; + result + ) + else if n < 0 then (f^-1)^(-n) + else if n === 0 then id_(source f) + else if n === 1 then f + else ( + if source f != target f then error "expected source and target to be the same"; + maps = hashTable for i from 0 to tDeg list i => ( + s := f_i; + j := 1; + while j < n do ( + s = f_(i+j*df) * s; + j = j+1; + ); + if s == 0 then continue else s + ); + result = map(source f, source f, maps, Degree=> n * df); + if f.cache.?isCommutative then result.cache.isCommutative = f.cache.isCommutative; + result + ) + ) + + +SimplicialModule ** SimplicialModule := SimplicialModule => (C,D) -> simplicialTensor(C,D) + +--it seemed more efficient to directly define the tensor product with a module +--as opposed to converting the module into a simplicial object then using simplicialTensor +Module ** SimplicialModule := SimplicialModule => (M,S) -> ( + if any(keys S,i->i==symbol complex) then return simplicialModule(M**(S.complex), S.topDegree, Degeneracy => S.?ss); + LM := new HashTable from for i in keys S.module list i => M**(S.module)#i; + faceHashM := new HashTable from for i in keys S.dd.map list i => map(M ** S_(i_0-1), M ** S_(i_0), M**(S.dd.map)#i); + if any(keys S,i->i==symbol ss) then ( + degenMapHashM := new HashTable from for i in keys S.ss.map list i => map(M ** S_(i_0+1), S_(i_0), M**(S.ss.map)#i); + if any(keys S,i->i==symbol complex) then return simplicialModule(M**(S.complex),faceHashM,degenMapHashM,S.topDegree) + else return simplicialModule(LM,faceHashM,degenMapHashM,S.topDegree); + ); + simplicialModule(LM,faceHashM,S.topDegree) + ) + +SimplicialModule ** Module := SimplicialModule => (S,M) -> ( + if any(keys S,i->i==symbol complex) then return simplicialModule((S.complex)**M, S.topDegree, Degeneracy => S.?ss); + LM := new HashTable from for i in keys S.module list i => (S.module)#i**M; + faceHashM := new HashTable from for i in keys S.dd.map list i => map(S_(i_0-1) ** M, S_(i_0) ** M, (S.dd.map)#i**M); + if any(keys S,i->i==symbol ss) then ( + degenMapHashM := new HashTable from for i in keys S.ss.map list i => map(S_(i_0+1), S_(i_0), (S.ss.map)#i**M); + if any(keys S,i->i==symbol complex) then return simplicialModule((S.complex)**M,faceHashM,degenMapHashM,S.topDegree) + else return simplicialModule(LM,faceHashM,degenMapHashM,S.topDegree); + ); + simplicialModule(LM,faceHashM,S.topDegree) + ) + +SimplicialModule ** Matrix := SimplicialModuleMap => (S, f) -> ( + if S.?complex then return simplicialModule((S.complex)**f, topDegree S, Degeneracy => S.?ss); + if ring S =!= ring f then error "expected Simplicial module and Matrix over the same ring"; + src := S ** source f; + tar := S ** target f; + map(tar, src, new HashTable from for i to S.topDegree list i => map(tar_i, src_i, S_i ** f, Degeneracy => S.?ss)) + ) + +Matrix ** SimplicialModule := SimplicialModuleMap => (f, S) -> ( + if S.?complex then return simplicialModule(f**(S.complex), topDegree S, Degeneracy => S.?ss); + if ring S =!= ring f then error "expected Simplicial module and Matrix over the same ring"; + src := (source f) ** S; + tar := (target f) ** S; + map(tar, src, new HashTable from for i to S.topDegree list i => map(tar_i, src_i, f ** S_i, Degeneracy => S.?ss)) + ) + +SimplicialModule ** Ring := SimplicialModule => (S,R) -> ( + LM := new HashTable from for i in keys S.module list i => R**(S.module)#i; + faceHashM := new HashTable from for i in keys S.dd.map list i => R**(S.dd.map)#i; + if any(keys S,i->i==symbol complex) and not(S.?ss) then return simplicialModule(R**(S.complex),faceHashM,S.topDegree); + if any(keys S,i->i==symbol ss) then ( + degenMapHashM := new HashTable from for i in keys S.ss.map list i => R**(S.ss.map)#i; + if any(keys S,i->i==symbol complex) then return simplicialModule(R**(S.complex),faceHashM,degenMapHashM,S.topDegree) + else return simplicialModule(LM,faceHashM,degenMapHashM,S.topDegree); + ); + simplicialModule(LM,faceHashM,S.topDegree) + ) + +Ring ** SimplicialModule := SimplicialModule => (R,S) -> S ** R + +RingMap SimplicialModule := SimplicialModule => (phi,S) -> ( + if any(keys S,i->i==symbol complex) then return simplicialModule(phi(S.complex), S.topDegree, Degeneracy => S.?ss); + LM := new HashTable from for i in keys S.module list i => phi((S.module)#i); + faceHashM := new HashTable from for i in keys S.dd.map list i => phi((S.dd.map)#i); + if any(keys S,i->i==symbol ss) then ( + degenMapHashM := new HashTable from for i in keys S.ss.map list i => phi((S.ss.map)#i); + if any(keys S,i->i==symbol complex) then return simplicialModule(phi(S.complex),faceHashM,degenMapHashM,S.topDegree) + else return simplicialModule(LM,faceHashM, degenMapHashM, S.topDegree); + ); + simplicialModule(LM,faceHashM,S.topDegree) + ) + +tensor(RingMap, SimplicialModule) := SimplicialModule => {} >> opts -> (phi, S) -> ( + if source phi =!= ring S then error "expected the source of the ring map to be the ring of the simplicial module"; + LM := new HashTable from for i in keys S.module list i => tensor(phi,(S.module)#i); + faceHashM := new HashTable from for i in keys S.dd.map list i => tensor(phi,(S.dd.map)#i); + if any(keys S,i->i==symbol complex) and not(S.?ss) then return simplicialModule(tensor(phi,(S.complex)),faceHashM,S.topDegree); + if S.?ss then ( + degenMapHashM := new HashTable from for i in keys S.ss.map list i => tensor(phi,(S.ss.map)#i); + if any(keys S,i->i==symbol complex) then return simplicialModule(tensor(phi,(S.complex)),faceHashM,degenMapHashM,S.topDegree) + else return simplicialModule(LM,faceHashM,degenMapHashM,S.topDegree); + ); + simplicialModule(LM,faceHashM,S.topDegree) + ) +tensor(SimplicialModule, RingMap) := SimplicialModule => {} >> opts -> (S, phi) -> tensor(phi, S) + +RingMap ** SimplicialModule := SimplicialModule => (phi, S) -> tensor(phi, S) +SimplicialModule ** RingMap := SimplicialModule => (S, phi) -> tensor(phi, S) + + +SimplicialModuleMap | SimplicialModuleMap := SimplicialModuleMap => (f,g) -> ( + if target f != target g then error "expected targets to be the same"; + if (source f).topDegree =!= (source g).topDegree then error "expected sources to have same top degree"; + deg := degree f; + if deg =!= degree g then error "expected maps with the same degree"; + map(target f, source f ++ source g, new HashTable from for i to (source f).topDegree list i => (f_i|g_i), Degree=>deg) + ) + +SimplicialModuleMap || SimplicialModuleMap := SimplicialModuleMap => (f,g) -> ( + if source f != source g then error "expected sources to be the same"; + if (target f).topDegree =!= (target g).topDegree then error "expected targets to have same top degree"; + deg := degree f; + if deg =!= degree g then error "expected maps with the same degree"; + map(target f ++ target g, source f, new HashTable from for i to (source f).topDegree list i => (f_i||g_i), Degree=>deg) + ) + +SimplicialModule == SimplicialModule := (C,D) -> ( + --note: we don't check for equality of keys since some operations + --on simplicial modules may add a key + if C === D then return true; + if topDegree C =!= topDegree D then return false; + if ring C =!= ring D then return false; + for i from 0 to C.topDegree do ( + if C_i != D_i then return false; + ); + for i in keys C.dd.map do ( + if C.dd.map#i != D.dd.map#i then return false; + ); + if any(keys C,i->i==symbol ss) then for i in keys C.ss.map do ( + if C.ss.map#i != D.ss.map#i then return false; + ); + true + ) + +SimplicialModule == ZZ := (C,n) -> ( + if n =!= 0 then error "cannot compare simplicial module to non-zero integer"; + for i from 0 to C.topDegree do if C_i != 0 then return false; + true + ) +ZZ == SimplicialModule := (n,C) -> C == n + +transs := (C,v) -> ( + if C.cache.?indexComponents then ( + Ci := C.cache.indexComponents; + apply(v, i -> if Ci#?i then Ci#i else error "expected an index of a component of the direct sum")) + else ( + if not C.cache.?components then error "expected a direct sum of simplicialmodules"; + Cc := C.cache.components; + apply(v, i -> if not Cc#?i then error "expected an index of a component of the direct sum"); + v) + ) + + +SimplicialModule _ Array := SimplicialModuleMap => (C,v) -> ( + v = transs(C,v); + D := directSum apply(toList v, j -> C.cache.components#j); + Cc := if any(keys C,i->i==symbol complex) then forgetComplex(C,RememberSummands => false) else C; + maps := hashTable for i from 0 to Cc.topDegree list i => map(C_i,D_i,Cc_i_v); + result := map(C,D,maps); + result.cache.isCommutative = true; + result + ) + +SimplicialModule ^ Array := SimplicialModuleMap => (C,v) -> ( + v = transs(C,v); + D := directSum apply(toList v, j -> C.cache.components#j); + Cc := if any(keys C,i->i==symbol complex) then forgetComplex(C,RememberSummands => false) else C; + maps := hashTable for i from 0 to Cc.topDegree list i => map(D_i,C_i,Cc_i^v); + result := map(D,C,maps); + result.cache.isCommutative = true; + result + ) + + +SimplicialModuleMap == SimplicialModuleMap := (f,g) -> ( + if f === g then return true; + if source f != source g or target f != target g + then return false; + for i from 0 to (source f).topDegree do ( + if f_i != g_i then return false; + ); + true + ) +SimplicialModuleMap == ZZ := Boolean => (f,n) -> ( + if n === 0 then + all(keys f.map, k -> f.map#k == 0) + else if n === 1 then ( + if source f != target f then return false; + if degree f =!= 0 then return false; + (lo,hi) := (0,(source f).topDegree); + for i from lo to hi do + if f_i != 1 then return false; + f.cache.isCommutative = true; -- this is the identity, after all! + true + ) + else + error "cannot compare ComplexMap to integer other than 0 or 1" + ) +ZZ == SimplicialModuleMap := Boolean => (n,f) -> f == n + +RingElement * SimplicialModuleMap := (r,f) -> ( + df := degree f; + maps := hashTable for i to (source f).topDegree list i => ( + h := r * f_i; + if h == 0 then continue else h + ); + result := map(target f, source f, maps, Degree=>df); + result + ) + +SimplicialModuleMap * RingElement := (f,r) -> (r*f) + +Number * SimplicialModuleMap := (r,f) -> ( + try r = promote(r,ring f) else error "can't promote scalar to ring of complex homomorphism"; + r * f + ) + +SimplicialModuleMap * Number := (f,r) -> ( + try r = promote(r,ring f) else error "can't promote scalar to ring of complex homomorphism"; + f * r + ) + +- SimplicialModuleMap := (f) -> ( + result := (-1)*f; + if isCommutativeCached f then + result.cache.isCommutative = true; + result + ) + +SimplicialModuleMap + SimplicialModuleMap := (f,g) -> ( + df := degree f; + dg := degree g; + if source f != source g then error "expected simplicial module homomorphisms with the same source"; + if target f != target g then error "expected simplicial homomorphisms with the same target"; + if df =!= dg then error "expected complex homomorphisms with the same degree"; + maps := hashTable for i from 0 to (source f).topDegree list i => ( + h := f_i + g_i; + if h == 0 then continue else h + ); + result := map(target f, source f, maps, Degree=>df); + result + ) +SimplicialModuleMap + Number := +SimplicialModuleMap + RingElement := SimplicialModuleMap => (f,r) -> ( + if r == 0 then f + else ( + if source f != target f + then error "expected same source and target" + else f + r*id_(target f)) + ) +Number + SimplicialModuleMap := +RingElement + SimplicialModuleMap := SimplicialModuleMap => (r,f) -> f + r + +SimplicialModuleMap - Number := +SimplicialModuleMap - RingElement := +SimplicialModuleMap - SimplicialModuleMap := SimplicialModuleMap => (f,g) -> f + (-1)*g + +Number - SimplicialModuleMap := +RingElement - SimplicialModuleMap := SimplicialModuleMap => (r,f) -> -f + r + +SimplicialModuleMap * SimplicialModuleMap := (f,g) -> ( + --this is the case where just composing normal maps + if all(keys f.map, i-> instance(i, ZZ)) then ( + df := degree f; + dg := degree g; + maps := hashTable for i from 0 to (source g).topDegree list i => ( + h := f_(dg + i) * g_i; + if h == 0 then continue else h + ); + result := map(target f, source g, maps, Degree=>df+dg); + return result; + ); + --this is the case where face/degeneracy maps are being composed + --note: this case is not really used, since composition of face maps + --should be treated as a sort of totalized operation + if all(keys f.map, i-> instance(i, Sequence)) then ( + df = degree f; + dg = degree g; + maps = hashTable for i in keys g.map list i => ( + h := f_((dg + i_0, i_1)) * g_i; + if h == 0 then continue else h + ); + result = map(target f, source g, maps, Degree=>df+dg); + return result; + ); + ) + +--need to complete this +SimplicialModuleMap.directSum = args -> ( + -- args: sequence of SimplicialModuleMap's + -- args: f_i : C_i --> D_i, having same degree deg + -- result : sum(C_i) --> sum(D_i) + R := ring args#0; + deg := degree args#0; + if not all(args, f -> ring f === R) then + error "expected maps all over the same ring"; + if not all(args, f -> degree f === deg) then + error "expected maps to all have the same degree"; + -- WARNING: we call simplicialModule.directSum directly rather than using + -- just directSum to avoid getting a cached copy of the direct + -- sum. Otherwise the labels of the cached copies might get + -- changed (in Options.directSum). + src := SimplicialModule.directSum (args/source); + tar := SimplicialModule.directSum (args/target); + -- only keep matrices in the homomorphism that are non-zero + spots := unique flatten(args/(f -> keys f.map)); + maps := hashTable for i in spots list i => directSum(args/(f -> f_i)); + result := map(tar,src,maps,Degree=>deg); + result.cache.components = toList args; + result + ) + +SimplicialModuleMap ++ SimplicialModuleMap := SimplicialModuleMap => (f,g) -> directSum(f,g) +directSum SimplicialModuleMap := f -> directSum(1 : f) +components SimplicialModuleMap := f -> if f.cache.?components then f.cache.components else {f} +SimplicialModuleMap ^ Array := SimplicialModuleMap => (f,v) -> (target f)^v * f +SimplicialModuleMap _ Array := SimplicialModuleMap => (f,v) -> f * (source f)_v + + + + +-- the following method is not exported: +isCommutativeCached = method() +isCommutativeCached SimplicialModuleMap := Boolean => f -> f.cache.?isCommutative and f.cache.isCommutative + + +-------------------------------------------------------------------- +-- tensor products of simplicial maps ------------------------------ +-------------------------------------------------------------------- +tensor(SimplicialModuleMap, SimplicialModuleMap) := SimplicialModuleMap => {} >> opts -> (f,g) -> ( + -- f : C1 --> C2, g : D1 --> D2 + -- f**g : C1**D1 --> C2**D2 + -- (f**g)_i : sum_j(C1_j ** D1_(i-j) --> C2_(j+df) ** D2_(i-j+dg)) + df := degree f; + dg := degree g; + src := (source f) ** (source g); + tar := (target f) ** (target g); + -- for the i-th matrix src_i --> tar_(i+df+dg) + -- we make a table of matrices, and create a block matrix from that using "matrix" and "map" + (lo,hi) := (0,src.topDegree); + maps := hashTable for i from lo to hi list i => f_i**g_i; + result := map(tar, src, maps, Degree=>df+dg); + result + ) +SimplicialModuleMap ** SimplicialModuleMap := SimplicialModuleMap => (f,g) -> tensor(f,g) +SimplicialModule ** SimplicialModuleMap := SimplicialModuleMap => (C,g) -> id_C ** g +SimplicialModuleMap ** SimplicialModule := SimplicialModuleMap => (f,D) -> f ** id_D +Module ** SimplicialModuleMap := SimplicialModuleMap => (M,g) -> ( + map(M**(target g),M**(source g),new HashTable from for i in keys (g.map) list i => M**(g.map#i), Degree => degree g) + ) +SimplicialModuleMap ** Module := SimplicialModuleMap => (g,N) -> ( + map((target g) ** N,(source g) ** N,new HashTable from for i in keys (g.map) list i => (g.map#i)**N, Degree => degree g) + ) + + +SimplicialModuleMap ** Ring := SimplicialModuleMap => (g,R) -> ( + map((target g)**R,(source g)**R,new HashTable from for i in keys (g.map) list i => (g.map#i)**R, Degree => degree g) + ) +Ring ** SimplicialModuleMap := SimplicialModuleMap => (R,f) -> f ** R + +RingMap SimplicialModuleMap := SimplicialModuleMap => (phi,f) -> ( + if f.?complexMap then return simplicialModule(phi(f.complexMap), topDegree f, Degeneracy => (source f).?ss); + map(phi target f, phi source f, new HashTable from for i in keys (f.map) list i=> phi((f.map)#i), Degree => degree f) + ) + +tensor(RingMap, SimplicialModuleMap) := SimplicialModuleMap => {} >> opts -> (phi, f) -> ( + if source phi =!= ring f then error "expected the source of the ring map to be the ring of the complex map"; + map(tensor(phi, target f), tensor(phi, source f), new HashTable from for i in keys (f.map) list i=> tensor(phi,(f.map)#i), Degree => degree f) + ) +tensor(SimplicialModuleMap, RingMap) := SimplicialModuleMap => {} >> opts -> (f, phi) -> tensor(phi, f) + +RingMap ** SimplicialModuleMap := SimplicialModuleMap => (phi, f) -> tensor(phi, f) +SimplicialModuleMap ** RingMap := SimplicialModuleMap => (f, phi) -> tensor(phi, f) + +---------------------------------------------------------------------------------------- +------------- some functionality for complexes acting on simplicial modules ------------ + +Complex ** SimplicialModule := SimplicialModule => (C,S) -> (simplicialModule(C,S.topDegree)**S) + +SimplicialModule ** Complex := SimplicialModule => (S,C) -> (S**simplicialModule(C,S.topDegree)) + +ComplexMap ** SimplicialModuleMap := SimplicialModuleMap => (f,g) -> (tDeg := max((source g).topDegree,(target g).topDegree); + simplicialModule(f,tDeg)**g + ) + +SimplicialModuleMap ** ComplexMap := SimplicialModuleMap => (g,f) -> (tDeg := max((source g).topDegree,(target g).topDegree); + g**simplicialModule(f,tDeg) + ) + +Complex ** SimplicialModuleMap := SimplicialModuleMap => (C,f) -> (id_C**f) +SimplicialModuleMap ** Complex := SimplicialModuleMap => (f,C) -> (f**id_C) + + + +kernel SimplicialModuleMap := SimplicialModule => opts -> f -> ( + -- f : B --> C + local result; + B := source f; + modules := hashTable for i from 0 to B.topDegree list i => kernel f_i; + inducedMaps := hashTable for i from 0 to B.topDegree list i => inducedMap(B_i, modules#i); + facemaps := hashTable for i in keys (B.dd.map) list i => ( + b1 :=B.dd_i * inducedMaps#(i_0); + b2 := map(target b1,source inducedMaps#(i_0-1),inducedMaps#(i_0-1)); + (b1) // b2 + ); + if any(keys B,i->i==symbol ss) then ( + degenmaps := hashTable for i in keys (B.ss.map) list i => ( + b1 := B.ss_i * inducedMaps#(i_0); + b2 := map(target b1,source inducedMaps#(i_0+1),inducedMaps#(i_0+1)); + (b1) // b2 + ); + result = simplicialModule(modules,facemaps,degenmaps,B.topDegree); + result.cache.kernel = f; + return result; + ); + result = simplicialModule(modules,facemaps,B.topDegree); + result.cache.kernel = f; + result + ) +cokernel SimplicialModuleMap := SimplicialModule => f -> ( + -- f : B --> C + local result; + C := target f; + deg := degree f; + modules := hashTable for i from 0 to C.topDegree list i => cokernel f_(i-deg); + facemaps := hashTable for i in keys (C.dd.map) list i => ( + map(modules#(i_0-1), modules#(i_0), matrix C.dd_i) + ); + if any(keys C,i->i==symbol ss) then ( + degenmaps := hashTable for i in keys (C.ss.map) list i => ( + map(modules#(i_0+1), modules#(i_0), matrix C.ss_i) + ); + result = simplicialModule(modules,facemaps,degenmaps,C.topDegree); + result.cache.cokernel = f; + return result; + ); + result = simplicialModule(modules,facemaps,C.topDegree); + result.cache.cokernel = f; + result + ) + +image SimplicialModuleMap := SimplicialModule => f -> ( + -- f : B --> C + local result; + B := source f; + C := target f; + deg := degree f; + modules := hashTable for i from 0 to C.topDegree list i => image f_(i-deg); + inducedMaps := hashTable for i from 0 to B.topDegree list i => inducedMap(C_i, modules#i); + facemaps := hashTable for i in keys (C.dd.map) list i => ( + b1 :=C.dd_i * inducedMaps#(i_0); + b2 := map(target b1,source inducedMaps#(i_0-1),inducedMaps#(i_0-1)); + (b1) // b2 + ); + if any(keys C,i->i==symbol ss) then ( + degenmaps := hashTable for i in keys (C.ss.map) list i => ( + b1 := C.ss_i * inducedMaps#(i_0); + b2 := map(target b1,source inducedMaps#(i_0+1),inducedMaps#(i_0+1)); + (b1) // b2 + ); + result = simplicialModule(modules,facemaps,degenmaps,C.topDegree); + result.cache.image = f; + return result; + ); + result = simplicialModule(modules,facemaps,C.topDegree); + result.cache.image = f; + result + ) + +coimage SimplicialModuleMap := SimplicialModule => f -> ( + -- f : B --> C + local result; + B := source f; + modules := hashTable for i from 0 to B.topDegree list i => coimage f_(i); + facemaps := hashTable for i in keys (B.dd.map) list i => ( + map(modules#(i_0-1), modules#(i_0), matrix B.dd_i) + ); + if any(keys B,i->i==symbol ss) then ( + degenmaps := hashTable for i in keys (B.ss.map) list i => ( + map(modules#(i_0+1), modules#(i_0), matrix B.ss_i) + ); + result = simplicialModule(modules,facemaps,degenmaps,B.topDegree); + result.cache.coimage = f; + return result; + ); + result = simplicialModule(modules,facemaps,B.topDegree); + result.cache.coimage = f; + result + ) + +--this function takes the tensor product of a direct sum, but caches the components +--of the resulting tensor product based on the component indices of the original modules. +--useful for accessing induced maps on components of tensor products of direct sums +tensorwithComponents = method(); +tensorwithComponents(Module,Module) := (M,N) -> ( + T := if M.cache.?indexComponents then flatten table(keys (M.cache.indexComponents),toList(0..length components N-1),(u,v) -> {u,v}) + else flatten table(toList(0..length components M-1),toList(0..length components N-1),(u,v) -> {u,v}); + result := M**N; + if M.cache.?indexComponents then result.cache.components = apply(T,i->(M.cache.components#(M.cache.indexComponents#(i_0)))**(N.cache.components#(i_1))) + else result.cache.components = apply(T,i->((components M)#(i_0))**((components N)#(i_1))); + result.cache.indexComponents = hashTable for i to length(T)-1 list flatten (T_i) => i; + result.cache.indices = for i to length(T)-1 list flatten (T_i); + result + ) + +tensorwithComponents(Matrix,Matrix) := (A,B) -> ( + srcA := source A; + srcB := source B; + trgA := target A; + trgB := target B; + map(tensorwithComponents(trgA,trgB),tensorwithComponents(srcA,srcB),A**B) + ) + +tensorwithComponents List := L -> ( + if length L == 2 then return tensorwithComponents(L_0,L_1); + Ln := for i from 2 to length L-1 list L_i; + tensorwithComponents({tensorwithComponents(L_0,L_1)}|Ln) + ) + + +homology(SimplicialModule) := SimplicialModule => opts -> C -> ( + t := topDegree C; + simplicialModule( HH normalize C, t, Degeneracy => C.?ss) + ) + +homology(SimplicialModuleMap) := SimplicialModuleMap => opts -> f -> ( + t := topDegree f; + degens := (source f).?ss and (target f).?ss; + simplicialModule( HH normalize f, t, Degeneracy => degens) + ) + + +SimplicialModule Array := (C, L) -> (t := topDegree C; + simplicialModule( (normalize C) L, t, Degeneracy => C.?ss ) + ) + +SimplicialModuleMap Array := (f, L) -> (t := topDegree f; + simplicialModule( (normalize f) L, t, Degeneracy => (source f).?ss) + ) + +minimalPresentation SimplicialModule := +prune SimplicialModule := SimplicialModule => opts -> (cacheValue symbol minimalPresentation)(C -> ( + R := ring C; + -- opts is ignored here + -- to be cached: in the input C: cache the result D + -- in the result: cache pruningMap: D --> C + faceKeys := keys C.dd.map; + if any(keys C,i->i==symbol ss) then degenKeys := keys C.ss.map; + prunedMods := new MutableHashTable from for i to C.topDegree list i => prune C_i; + prunedFaceMaps := new MutableHashTable from for i in faceKeys list i => map(prune C_(i_0-1),prune C_(i_0),0); + if any(keys C,i->i==symbol ss) then prunedDegenMaps := new MutableHashTable from for i in degenKeys list i=>map(prune C_(i_0+1),prune C_(i_0),0); + nonzeros := select(0..C.topDegree, i -> minimalPresentation C_i != 0); + D := if #nonzeros === 0 + then ( + simplicialModule((ring C)^0,C.topDegree) + ) + else ( + lo := min nonzeros; + hi := max nonzeros; + for i from lo to hi do prunedMods#i = minimalPresentation(C_i); + for i in select(faceKeys,i->(i_0>=lo and i_0<=hi)) do prunedFaceMaps#i = minimalPresentation C.dd_i; + if any(keys C,i->i==symbol ss) then ( + for i in select(degenKeys,i->(i_0>=lo and i_0 prunedMods#i; + nmFaces := new HashTable from for i in keys prunedFaceMaps list i=> prunedFaceMaps#i; + if any(keys C,i->i==symbol ss) then ( + nmDegens := new HashTable from for i in keys prunedDegenMaps list i=> prunedDegenMaps#i; + ); + if any(keys C,i->i==symbol ss) then simplicialModule(nmMods,nmFaces,nmDegens,C.topDegree) else simplicialModule(nmMods,nmFaces,C.topDegree) + ); + -- create the isomorphism D --> C + pruning := hashTable for i from 0 to C.topDegree list i => (minimalPresentation C_i).cache.pruningMap; + D.cache.pruningMap = map(C,D,pruning); + D.cache.pruningMap.cache.isCommutative = true; + D + )) + + +minimalPresentation SimplicialModuleMap := +prune SimplicialModuleMap := SimplicialModuleMap => opts -> f -> ( + if all(keys f.map, i -> instance(i, Sequence)) then return (if degree f == -1 then (prune source f).dd else (prune source f).ss); + C := source f; + if not C.cache.?pruningMap then f = f * (minimalPresentation C).cache.pruningMap; + D := target f; + if not D.cache.?pruningMap then f = (minimalPresentation D).cache.pruningMap^-1 * f; + f + ) + +inducedMap(SimplicialModule, SimplicialModule) := SimplicialModuleMap => opts -> (D,C) -> ( + -- compute f : C --> D the map induced by the identity matrix. + deg := if opts.Degree === null then 0 else opts.Degree; + (loC,hiC) := (0,C.topDegree); + (loD,hiD) := (0,D.topDegree); + maps := hashTable for i from max(loC,loD-deg) to min(hiC,hiD-deg) list i => inducedMap(D_(i+deg),C_i, Verify => opts.Verify); + map(D,C,maps,Degree=>deg) + ) + + +randomSimplicialMap = method(Options=>{ + Degree => 0, + InternalDegree => null, + Cycle => false, + Boundary => false + }) +randomSimplicialMap(SimplicialModule, SimplicialModule) := SimplicialModuleMap => opts -> (C,D) -> ( + simplicialModule(randomComplexMap(normalize C, normalize D, opts), min(C.topDegree, D.topDegree), Degeneracy => C.?ss) + ) + +basis(List, Complex) := Complex => opts -> (deg, C) -> ( + (a,b) := concentration C; + L := for i from a+1 to b list basis(deg, C.dd_i, opts); + complex(L, Base => a)) + +basis(ZZ, Complex) := Complex => opts -> (deg, C) -> ( + (a,b) := concentration C; + L := for i from a+1 to b list basis(deg, C.dd_i, opts); + complex(L, Base => a)) + +basis(List, SimplicialModule) := SimplicialModule => opts -> (L, S) -> ( + if S.?complex then return simplicialModule(basis(L,S.complex), S.topDegree, Degeneracy => S.?ss); + mods := hashTable for i in keys S.module list i => image basis(L, S_i, opts); + H1 := hashTable for i in keys S.dd.map list i => basis(L, S.dd_i, opts); + if S.?ss then H2 := hashTable for i in keys S.ss.map list i => basis(L, S.ss_i, opts); + if S.?ss then return simplicialModule(mods, H1, H2, S.topDegree); + simplicialModule(mods, H1, S.topDegree) + ) + +basis(ZZ, SimplicialModule) := SimplicialModule => opts -> (L, S) -> ( + if S.?complex then return simplicialModule(basis(L,S.complex), S.topDegree, Degeneracy => S.?ss); + mods := hashTable for i in keys S.module list i => image basis(L, S_i, opts); + H1 := hashTable for i in keys S.dd.map list i => basis(L, S.dd_i, opts); + if S.?ss then H2 := hashTable for i in keys S.ss.map list i => basis(L, S.ss_i, opts); + if S.?ss then return simplicialModule(mods, H1, H2, S.topDegree); + simplicialModule(mods, H1, S.topDegree) + ) + +basis(List, SimplicialModuleMap) := SimplicialModuleMap => opts -> (L, phi) -> ( + map(basis(L, target phi, opts), basis(L, source phi, opts), hashTable for i in keys phi.map list i => ( + if (f := basis(L, phi_i, opts)) == 0 then continue else f) ) + ) + +basis(ZZ, SimplicialModuleMap) := SimplicialModuleMap => opts -> (L, phi) -> ( + map(basis(L, target phi, opts), basis(L, source phi, opts), hashTable for i in keys phi.map list i => ( + if (f := basis(L, phi_i, opts)) == 0 then continue else f) ) + ) + + +truncate(List, SimplicialModule) := SimplicialModule => {} >> opts -> (L, S) -> ( + if S.?complex then return simplicialModule(truncate(L,S.complex), S.topDegree, Degeneracy => S.?ss); + mods := hashTable for i in keys S.module list i => truncate(L, S_i, opts); + H1 := hashTable for i in keys S.dd.map list i => truncate(L, S.dd_i, opts); + if S.?ss then H2 := hashTable for i in keys S.ss.map list i => truncate(L, S.ss_i, opts); + if S.?ss then return simplicialModule(mods, H1, H2, S.topDegree); + simplicialModule(mods, H1, S.topDegree) + ) +truncate(ZZ, SimplicialModule) := SimplicialModule => {} >> opts -> (e, S) -> truncate({e}, S) + +truncate(List, SimplicialModuleMap) := SimplicialModuleMap => {} >> opts -> (L, phi) -> ( + map(truncate(L, target phi, opts), truncate(L, source phi, opts), hashTable for i in keys phi.map list i => ( + if (f := truncate(L, phi_i, opts)) == 0 then continue else f) ) + ) + +truncate(ZZ, SimplicialModuleMap) := SimplicialModuleMap => {} >> opts -> (L, phi) -> truncate({L}, phi, opts) + + + + +isShortExactSequence(SimplicialModuleMap, SimplicialModuleMap) := Boolean => (g, f) -> ( + -- f : A --> B, g : B --> C + -- the SES is 0 --> A --> B --> C --> 0. + isWellDefined g and + isWellDefined f and + isSimplicialMorphism g and + isSimplicialMorphism f and + g*f == 0 and + image f == kernel g and + kernel f == 0 and + coker g == 0 + ) diff --git a/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleDOC.m2 b/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleDOC.m2 new file mode 100644 index 0000000000..19ac21cb77 --- /dev/null +++ b/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleDOC.m2 @@ -0,0 +1,4001 @@ +doc /// + Key + SimplicialModules + Headline + A package for creating and computing objects in the category of Simplicial R-Modules + Description + Text + A simplicial R-module is a presheaf on the so-called Simplex Category, with values in the category of R-modules. Concretely, such objects can be viewed as nonnegatively graded R-modules + equipped with certain face and degeneracy operators satisfying the simplicial identites. As an example, every R-module M can be converted into a simplicial R-module whose degree + n piece is equal to M for all n, and with face/degeneracy operators simply given by the identity. + Example + S = simplicialModule(ZZ^2,3,Degeneracy => true) --the integer 3 specifies a top degree, the option Degeneracy specifies whether or not to compute degeneracy maps + Text + The output string for a simplicial module is meant to indicate that this object is infinite in general, + and the user can only compute a finite snapshot of the object. + The face/degeneracy maps can be accessed using the keys {\tt dd} and {\tt ss}, respectively. In order to verify that the resulting face/degeneracy maps satisfy the simplicial + identities, one can use the @TO isSimplicialModule@ command. + Example + S.dd + S.ss + assert isSimplicialModule S + Text + In general, simplicial objects are infinite objects. Because of this, the user can specify a top degree for the resulting simplicial object. If no top degree is specified, then + the default top degree is determined by the input object. + Text + @SUBSECTION "The Dold-Kan Correspondence"@ + Text + The category of simplicial R-modules is equivalent to the category of nonegatively graded + chain complexes via an equivalence known as the Dold-Kan correspondence. + + This means that there is a functor that converts a chain complex into a simplicial object, known as the Dold-Kan functor. In practice, the image of the Dold-Kan functor is + highly nontrivial to compute by hand. However, this package uses an algorithm of Kock-Sakuranath to compute Dold-Kan images quite efficiently by using the @TO simplicialModule@ + command: + Example + R = ZZ/101[x_1..x_3]; + K = koszulComplex vars R + simplicialModule(K) --defaults to top degree 3 + elapsedTime simplicialModule(K,6) --specify top degree 6 + elapsedTime S' = simplicialModule(K,6, Degeneracy => true) + isWellDefined S' --this method checks the simplicial identities as well as many other basic checks + Text + The other piece of the Dold-Kan correspondence is the functor that converts a simplicial module into a chain complex. This functor is often referred to as the normalization functor, + and is also implemented as the command @TO normalize@. If a simplicial R-module is computed as the Dold-Kan image of some complex, then this complex is cached and the @TO normalize@ command + returns this cached complex. If the user wants the normalization to be computed without accessing this cached value, one can use the {\tt CheckComplex => false} option. + By default, the normalization function does not prune the output, so the user should use @TO prune@ to get a nicer looking output. + Example + R = ZZ/101[x_1..x_3]; + K = koszulComplex vars R + Kn = normalize(simplicialModule(K,4), CheckComplex => false) + Kn.dd + K == prune Kn + Text + As the above example shows, applying the normalization to the Dold-Kan image recovers the original complex. + Text + @SUBSECTION "Canonical Extensions of Functors to the Category of Chain Complexes"@ + Text + One of the main utilities of the Dold-Kan correspondence from the perspective of a commutative algebraist is as a method of canonically extending any + endofunctor of R-modules to an endofunctor of nonnegatively chain complexes. This is because endofunctors of R-modules naturally extend to endofunctors + of simplicial R-modules by just applying the functor degree-wise. Since any nonnegatively graded chain complex can be converted into a simplicial R-module + (and vice versa) this yields a canonical way to extend endofunctors of R-modules to chain complexes in a way that preserves homotopy equivalence. + + This extension is often called the Dold-Puppe extension, and was introduced in pioneering work on the theory of derived nonlinear functors. + In general, the Dold-Puppe extension of a functor looks quite different from the classically defined functor, and in most cases may not be quasi-isomorphic over arbitrary base rings! + Example + Q = ZZ/101[x_1,x_2]; + K1 = complex {matrix{{x_1}}}; + K2 = complex {matrix{{x_2}}}; + T1 = K1**K2 + T1.dd + T2 = prune simplicialTensor({K1,K2}) + T2.dd + phi1 = extend(T1,T2,id_(T1_0)) + phi2 = extend(T2,T1,id_(T1_0)) + phi1*phi2 == id_T1 + isNullHomotopic(phi2*phi1 - id_T2) + Text + The above example allows us to directly verify that the classically defined tensor product is homotopy equivalent to the Dold-Kan version. This is true over arbitrary base rings, + but there are other functors such as the symmetric/exterior power functors that have classical definitions for chain complexes that are not necessarily + homotopy equivalent to the Dold-Puppe extensions: + Example + needsPackage "ChainComplexOperations" + Q = ZZ/2[x_1..x_3]; + K = koszulComplex vars Q; + W1 = complex wedge2(chainComplex K) --the classical "naively" defined exterior power functor + W2 = prune extPower(2,K) --the simplicial version of the exterior power functor + prune HH W1 + prune HH W2 + Text + Notice that the two definitions of exterior power yield complexes that are not even quasi-isomorphic, and hence certainly not homotopy equivalent. Moreover, the "naive" + definition yields a complex that does not even have finite length homology, while the Dold-Puppe extension applied to a complex with finite length homology is guaranteed + to have finite length homology. This preservation of "good behavior" for Dold-Puppe extensions of functors was the main motivation of the authors of CITE for using + simplicial techniques to prove the Total Rank Conjecture in characteristic 2. The @TO extPower@ command along with Schur functors in general have also been implemented in a + functorial way and can take morphisms of chain complexes as inputs: + Example + Q=ZZ/101[x_1,x_2]; + K = koszulComplex vars Q; + F = complex res ((ideal vars Q)^2); + phi = extend(K,F,id_(K_0)) + e2phi = prune extPower(2,phi) --induced map on the exterior powers of these complexes + assert isCommutative e2phi + --ephi = prune extPower(3,phi,TopDegree => 4); --the TopDegree option specifies how many homological degrees to compute + --assert isCommutative ephi; + --ephi_1 + --ephi_2; + --prune schurMap({2},phi) --the second symmetric power + --sphi = schurMap({2,1},phi,TopDegree => 3); --schur functor corresponding to partition {2,1} applied to phi + --sphi_1 + Text + This package thus lays the groundwork for computing with Dold-Puppe extensions of nonlinear functors, deriving nonlinear functors, and also allows any endofunctor of R-modules + implemented in Macaulay2 to immediately be canonically extended to an endofunctor at the level of chain complexes. Moreover, almost all methods + are implemented with an eye toward user accessibility and comprehension of the outputs. This is illustrated + in many of the documentation nodes below. + Text + @SUBSECTION "Getting started:"@ + Text + @UL { + TO "The Dold-Kan Correspondence in Macaulay2", + TO "Making simplicial modules", + TO "Making maps between simplicial modules", + TO "Basic invariants and properties", + TO "face/degeneracy maps of a simplicial module" + }@ + Text + @SUBSECTION "Contributors"@ + Text + The following people have generously contributed code or improved existing code: + Text + @SUBSECTION "Acknowledgments"@ + Text + This package began its life during the 2023 Macaulay2 workshop in Minneapolis. Many documentation + nodes for the basic constructors not specific to the {\tt SimplicialModule} type have been + repurposed from existing documentation coming from the @TO Complexes@ package. +/// + + +doc /// + Key + SimplicialModule + complexLength + Degeneracy + Headline + the class of all simplicial modules + Description + Text + A simplicial R-module is a presheaf on the so-called Simplex Category, with values in the category of R-modules. Concretely, such objects can be viewed as nonnegatively graded R-modules + equipped with certain face and degeneracy operators satisfying the simplicial identites. As an example, every R-module M can be converted into a simplicial R-module whose degree + n piece is equal to M for all n, and with face/degeneracy operators simply given by the identity. + Example + S = simplicialModule(ZZ^2,3,Degeneracy => true) --the integer 3 specifies a top degree, the option Degeneracy specifies whether or not to compute degeneracy maps + Text + The output string for a simplicial module is meant to indicate that this object is infinite in general, + and the user can only compute a finite snapshot of the object. + The face/degeneracy maps can be accessed using the keys {\tt dd} and {\tt ss}, respectively. In order to verify that the resulting face/degeneracy maps satisfy the simplicial + identities, one can use the @TO isSimplicialModule@ command. + Example + keys S + SeeAlso + "The Dold-Kan Correspondence in Macaulay2" + "Making simplicial modules" +/// + + +doc /// + Key + "The Dold-Kan Correspondence in Macaulay2" + (simplicialModule, Complex, ZZ) + (simplicialModule, Complex) + summandSurjection + Headline + compute the image of a non-negatively graded complex under the Dold-Kan correspondence + Usage + simplicialModule(C,d) + simplicialModule(C) + Inputs + C : Complex + d : ZZ + an integer specifying the top degree of the output SimplicialModule (if d is not specified, the top degree is the length of the complex C) + Description + Text + Given any non-negatively graded chain complex, the Dold-Kan correspondence is an equivalence of + categories: + $$\text{Ch}_{\geq 0} (R) \leftrightarrow \text{Simplicial R-modules}.$$ + If the simplicial module is obtained as a Dold-Kan image of some complex $C$, + then for each $i$ there is a decomposition + $$S_i = C_0 \oplus C_1^{\binom{i}{1}} \oplus \cdots \oplus C_j^{\binom{i}{j}} \oplus \cdots.$$ + To be technically correct, each of the direct summands $C_j$ of $S_i$ should be thought of as being + parametrized by an order preserving surjection $f : [i] \to [j]$ (where $[n] := \{ 0 ,\dots , n \}$. To deduce which surjection + corresponds to a given summand, first notice that order preserving surjections $f : [i] \to [j]$ + are in bijection with compositions of $i+1$ into $j+1$ parts by just listing the sizes of the + fibers of the map $f$. For instance, the composition $(2,2,1)$ corresponds to the surjection + $f : [4] \to [2]$ defined via + $$f(0) = f(1) = 0, \quad f(2) = f(3) = 1, \quad f(4) = 2.$$ + With this in mind, one can deduce the surjection corresponding to a summand as follows: + Example + R = ZZ/101[a..c] + C = koszulComplex vars R + S = simplicialModule(C, 4, Degeneracy => true) + S_2 + components S_2 --these are all the modules showing up + S_(2,1) + components S_(2,1) --these are only the components of C_1^2 + sort(select(compositions(2,3), i -> all(i, j -> j>0))) + Text + The ordering of the surjections corresponding to a summand agrees with the lexicographic + ordering of compositions via the bijection mentioned above. Thus the first summand of $C_1$ appearing + in $S_2$ corresponds to the surjection $f : [2] \to [1]$ given by $f(0) = 0$ and $f(1) = f(2) = 1$, + and the second summand corresponds to the surjection $f: [2] \to [1]$ with $f(0) = f(1) = 0$ and $f(2) = 1$. + These surjections may be accessed more directly using the {\tt summandSurjection} command: + Example + summandSurjection(2,0) --the surjection parametrizing C_0 + summandSurjection(2,1) --the surjections parametrizing C_1 + summandSurjection(2,2) --the surjection parametrizing C_2 + Text + Notice that the individual terms $C_j^{\binom{i}{j}}$ may be accessed as the $(i,j)$-component + of the simplicial module. There are moreover explicit formulas for the face and degeneracy + maps in terms of the differentials of $C$. These can also be accessed: + Example + S.dd --face maps + S.ss --degeneracy maps + S.dd_(2,0) + Text + If you want to restrict/project a face/degeneracy map to a particular summand, this can be done as follows: + Example + (S.dd_(2,0))_[1]^[0] --restrict to 1th summand of S_2, project onto 0th summand of S_1 + (S.dd_(2,0))_[2]^[1] --restrict to 2th summand of S_2, project onto 1th summand of S_1 + (S.dd_(2,0))_[3]^[1] --restrict to 3th summand of S_2, project onto 1th summand of S_1 + Text + The above computations tell us that the component of the face map $d_{2,0}$ mapping + $$C_{(1,2)} \to C_{(2)} $$ + is given by the differential of the original complex $C$ (we are using the compositions + correponding to the surjection to label the free modules now). The component + $$C_{(2,1)} \to C_{(1,1)}$$ + is simply the identity map, and the component + $$C_{(1,1,1)} \to C_{(1,1)}$$ + is also given by the differential of $C$. + SeeAlso + "Making simplicial modules" + "Making maps between simplicial modules" +/// + + +doc /// + Key + "Making simplicial modules" + Headline + information about the basic constructors + Description + Text + @SUBSECTION "Basic constructors"@ + Text + @UL { + TO (simplicialModule, HashTable, HashTable, HashTable, ZZ), + TO (simplicialModule, Module, ZZ), + TO (symbol SPACE, SimplicialModule, Array), + TO (isWellDefined, SimplicialModule) + }@ + Text + @SUBSECTION "Important computations creating new simplicial modules"@ + Text + @UL { + TO (simplicialModule, Complex), + TO (simplicialTensor, Complex, Complex) + }@ + Text + @SUBSECTION "More advanced constructors"@ + Text + @UL { + TO (symbol++, SimplicialModule, SimplicialModule), + TO (symbol**, SimplicialModule, SimplicialModule), + TO (symbol SPACE, RingMap, SimplicialModule), + TO (symbol **, RingMap, SimplicialModule), + TO (minimalPresentation, SimplicialModule), + TO (truncate, List, SimplicialModule) + }@ + Text + @SUBSECTION "Extracting simplicial modules from simplicial maps"@ + Text + @UL { + TO (source, SimplicialModuleMap), + TO (target, SimplicialModuleMap), + TO (kernel, SimplicialModuleMap), + TO (cokernel, SimplicialModuleMap), + TO (image, SimplicialModuleMap), + TO (coimage, SimplicialModuleMap) + }@ + SeeAlso + "Making maps between simplicial modules" + "Basic invariants and properties" +/// + +doc /// + Key + "Basic invariants and properties" + Headline + information about accessing basic features + Description + Text + @SUBSECTION "Predicates for simplicial modules and simplicial module maps"@ + Text + @UL { + TO (isWellDefined, SimplicialModule), + TO (isWellDefined, SimplicialModuleMap), + TO (isCommutative, SimplicialModuleMap), + TO (isSimplicialMorphism, SimplicialModuleMap), + TO (isShortExactSequence, SimplicialModuleMap, SimplicialModuleMap) + }@ + Text + @SUBSECTION "Other invariants for simplicial modules"@ + Text + @UL { + TO (ring, SimplicialModule), + TO (topDegree, SimplicialModule), + TO (components, SimplicialModule) + }@ + Text + @SUBSECTION "Other invariants for simplicial module maps"@ + Text + @UL { + TO (source, SimplicialModuleMap), + TO (target, SimplicialModuleMap), + TO (degree, SimplicialModuleMap), + TO (ring, SimplicialModuleMap), + TO (isHomogeneous, SimplicialModuleMap), + TO (components, SimplicialModuleMap) + }@ + SeeAlso + "Making simplicial modules" + "Making maps between simplicial modules" +/// + + + +doc /// + Key + (ring, SimplicialModule) + (ring, SimplicialModuleMap) + Headline + access the ring of a simplicial module or a simplicial module map + Usage + ring C + Inputs + C:SimplicialModule + or a @TO "SimplicialModuleMap"@ + Outputs + :Ring + Description + Text + Every simplicial module or simplicial module map has a base ring. This + function access that information. + Example + S = ZZ/101[a,b,c,d]; + C = simplicialModule freeResolution coker vars S + ring C + assert(ring C === S) + ring id_C + assert(ring id_C === S) + SeeAlso + "Basic invariants and properties" + ring +/// + + +doc /// + Key + topDegree + (topDegree, SimplicialModule) + (topDegree, SimplicialModuleMap) + Headline + top degree of a simplicial module + Usage + topDegree C + Inputs + C:SimplicialModule + Outputs + d:ZZ + an integer specifying the top degree to which the + face/degeneracy maps of a simplicial module have been computed + Description + Text + In this package, each simplicial module necessarily has a top degree which is a + finite bound up to which Macaulay2 will compute the face and/or degeneracy maps. + This function is mainly used in programming, to loop over all + non-zero modules or maps in the simplicial module. + Example + S = ZZ/101[a..c]; + C = simplicialModule(freeResolution coker vars S, 8) + topDegree C + C' = simplicialModule(freeResolution coker vars S, 6) + assert(topDegree C' == 6) + Text + Indices that are outside of the top degree automatically + return the zero object. + Example + C_-1 + C_9 + C'_7 + Text + The function {\tt topDegree} does no computation, and just accesses + a cached value. + SeeAlso + "Basic invariants and properties" + (symbol _, SimplicialModule, ZZ) +/// + + +doc /// + Key + simplicialModule + (simplicialModule, HashTable, HashTable, HashTable, ZZ) + (simplicialModule, HashTable, HashTable, ZZ) + (simplicialModule, Complex, HashTable, HashTable, ZZ) + (simplicialModule, Complex, HashTable, ZZ) + Headline + make a simplicial module + Usage + simplicialModule(H1, H2, H3, d) + Inputs + H1:HashTable + or @TO Complex@, used to determine the modules in each degree + H2:HashTable + used to specify the face maps + H3:HashTable + optional, used to specify degeneracy maps if needed + d:ZZ + an integer, specifying the top degree to compute the simplicial module up to + Degeneracy => Boolean + option specifying whether or not to also compute the degeneracy maps + Outputs + :SimplicialModule + Description + Text + A simplicial module is a sequence of objects (e.g. modules), + connected by maps called face/degeneracy maps denoted by $d$ and $s$, respectively. + These maps satisfy the simplicial identities: + 1. For face maps: + \[ d_j d_i = d_i d_{j-1} \text{ for } 0 \leq i < j \leq n \] + 2. For face and degeneracy maps: + \[ d_i s_j = s_{j-1} d_i \text{ for } i < j \] + \[ d_j s_j = \text{id} \] + \[ d_{j+1} s_j = \text{id} \] + \[ d_k s_j = s_j d_{k-1} \text{ for } k > j+1 \] + 3. For degeneracy maps: + \[ s_j s_i = s_i s_{j+1} \text{ for } i \leq j \] + + This constructor is the most basic constructor for building a simplicial module, + and is called by all of the more user friendly constructors. It is highly recommend + that the user sees @TO (simplicialModule, Complex)@ to quickly build simplicial modules. + Example + S = ZZ/101[a..d] + moduleHash = hashTable { 0 => S^1, + 1 => S^1++S^2, + 2 => S^1++S^2++S^2++S^1} + faceHash = hashTable {(1,0) => matrix {{1, a, b}}, + (1,1) => matrix {{1_S, 0, 0}}, + (2,0) => matrix {{1, a, b, 0, 0, 0}, + {0, 0, 0, 1, 0, -b}, + {0, 0, 0, 0, 1, a}}, + (2,1) => matrix {{1_S, 0, 0, 0, 0, 0}, + {0, 1, 0, 1, 0,0}, + {0, 0, 1, 0, 1, 0}}, + (2,2) => matrix {{1_S, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0}, + {0, 0, 1, 0, 0, 0}}} + degenHash = hashTable {(0,0) => matrix {{1_S}, {0}, {0}}, + (1,0) => matrix {{1_S, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + {0, 0, 0}}, + (1,1) => matrix {{1_S, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}}} + T = simplicialModule(moduleHash, faceHash, degenHash, 2) + T.module + T.dd + T.ss + T' = simplicialModule(moduleHash, faceHash, 2) + T'.?ss + Text + In the above, notice that if the user does not provide a hash table + specifying the degeneracy maps, then the simplicial module is still constructed + using only the data of the face maps. This feature is intentional since for the + purposes of efficiency, storing the data of the degeneracy maps may slow down + computations (and one can compute normalizations using only the face maps). In general, + the method @TO forgetDegeneracy@ allows the user to ignore the data of the degeneracy maps + if needed. + Text + In the following example, we see that one can construct simplicial modules + that are not well-defined. The user should use @TO (isWellDefined, SimplicialModule)@ + in order to check that a simplicial module is indeed well-defined. + Example + H1 = hashTable {0 => S^1, 1 => S^1, 2 => S^1} + H2 = hashTable {(1,0) => map(S^1, S^1, 0), + (1,1) => map(S^1, S^1, 0), + (2,0) => map(S^1, S^1, 0), + (2,1) => map(S^1, S^1, 0), + (2,2) => map(S^1, S^1, 0)} + H3 = hashTable {(0,0) => map(S^1, S^1, 0), + (1,0) => map(S^1, S^1, 0), + (1,1) => map(S^1, S^1, 0)} + U = simplicialModule(H1,H2,H3,2) + U.dd + U.ss + isWellDefined U + Caveat + This constructor minimizes computation + and does very little error checking. To verify that a complex + is well constructed, use @TO (isWellDefined, SimplicialModule)@. + SeeAlso + "Making simplicial modules" + (isWellDefined, SimplicialModule) + (simplicialModule, HashTable, HashTable, HashTable, ZZ) + (simplicialModule, Module, ZZ) + (symbol SPACE, SimplicialModule, Array) +/// + + +doc /// + Key + (simplicialModule, Module, ZZ) + (simplicialModule, Ideal, ZZ) + (simplicialModule, Ring, ZZ) + Headline + make a simplicial module associated to a complex concentrated in degree 0 + Usage + simplicialModule(M, d) + Inputs + M:Module + or @TO "Ideal"@, or @TO "Ring"@. + d:ZZ + top degree to compute the simplicial module up to + Outputs + :SimplicialModule + returns the complex whose 0-th component is {\tt M}. + Description + Text + In contrast to @TO (simplicialModule,HashTable,HashTable,HashTable,ZZ)@ or @TO + (simplicialModule,Complex,ZZ)@, this constructor provides a convenient + method to construct a simplicial module from a single module/ring/ideal. + + We illustrate this with a free module. + Example + S = ZZ/101[a..d] + C0 = simplicialModule( S^2, 6, Degeneracy => true) + f = dd^C0 + source f, target f + f == 0 + isWellDefined C0 + C0 == 0 + topDegree C0 + Example + C1 = simplicialModule(complex(S^2, Base=>3), 6, Degeneracy => true) + C1_3 + C1_0 + Text + A ring or an ideal will be converted to a module first. + Example + C2 = simplicialModule( S, 5, Degeneracy => true) + I = ideal(a^2-b, c^3) + C3 = simplicialModule( I, 7, Degeneracy => true) + C4 = simplicialModule( (S/I), 8, Degeneracy => true) + (ring C3, ring C4) + Text + The zero simplicial module over a ring {\tt S} is most conveniently + created by giving the zero module. + Example + C5 = simplicialModule(S^0, 8, Degeneracy => true) + C5 == 0 + dd^C5 == 0 + ss^C5 == 0 + C5_0 + SeeAlso + "Making simplicial modules" + (isWellDefined, SimplicialModule) + (simplicialModule, HashTable, HashTable, HashTable, ZZ) +/// + +doc /// + Key + (isWellDefined, SimplicialModule) + Headline + whether a simplicial module is well-defined + Usage + isWellDefined C + Inputs + C:SimplicialModule + Outputs + :Boolean + that is true when {\tt C} determines a well defined simplicial module + Description + Text + This routine checks that the face/degeneracy maps of {\tt C} satisfy the simplicial identities + (see @TO isSimplicialModule@ for a list of these identities). + If there are no degeneracy maps stored, it instead checks that the naive normalization of C + is a well-defined complex. + Additionally, it checks that the underlying data in {\tt C} is a properly formed + @TO SimplicialModule@ object in Macaulay2. If the variable {\tt debugLevel} is set to a value greater than zero, + then information about the nature of any failure is displayed. + Text + As a first example, we construct the Dold-Kan image of a free resolution and verify that it is + well-defined. + Example + R = QQ[a..d]; + f0 = matrix {{-b^2+a*c, b*c-a*d, -c^2+b*d}} + f1 = map(source f0,, {{d, c}, {c, b}, {b, a}}) + C = simplicialModule(complex {f0, f1}, 3, Degeneracy => true) + isWellDefined C + dd^C + ss^C + dd^C*ss^C --if C is well-defined, this should be all identity maps + Text + The zero simplicial module is well-defined. + Example + C = simplicialModule(R^0, 6, Degeneracy => true) + isWellDefined C + SeeAlso + (isWellDefined, SimplicialModuleMap) + map +/// + + +doc /// + Key + (symbol _, SimplicialModule, ZZ) + (symbol _, SimplicialModule, Sequence) + Headline + access individual objects of a simplicial module + Usage + C_i + Inputs + C:SimplicialModule + i:ZZ + or @TO Sequence@, indicating a term in some degree + Outputs + :Module + the {\tt i}-th object + Description + Text + The data of the modules of a simplicial module is stored in two different ways, + depending on whether the simplicial module $S$ is obtained as the Dold-Kan image + of some complex. If the simplicial module is obtained as a Dold-Kan image of some complex $C$, + then for each $i$ there is a decomposition + $$S_i = C_0 \oplus C_1^{\binom{i}{1}} \oplus \cdots \oplus C_j^{\binom{i}{j}} \oplus \cdots.$$ + Thus the individual terms $C_j^{\binom{i}{j}}$ may be accessed as the $(i,j)$-component + of the simplicial module. + If $S$ is not obtained as a Dold-Kan image, then each term is considered singly indexed with no additional components. + Example + S = ZZ/101[a..c] + C = simplicialModule(freeResolution coker vars S, 4, Degeneracy => true) + C.?complex + C.complex + C_(1,0) == C.complex_0 + C_(1,1) == C.complex_1 + C_(2,1) == C.complex_1 ++ C.complex_1 + tC = C ** C + tC.?complex + tC_2 + Text + If the simplicial object is obtained as a Dold-Kan image, then using an integer subscript + will automatically take the direct sum over all the terms of the complex appearing in that degree + (and cache the components of that direct sum accordingly). + Example + C_3 + components C_3 + (C_3)_[1,2,3] --extract the inclusion of (C.complex_1)^3 + Text + Indices that are outside of the top degree automatically + return the zero object. + Example + C_(-1,3) + C_-7 + SeeAlso + (symbol _, SimplicialModuleMap, ZZ) +/// + + +doc /// + Key + (symbol ==, SimplicialModule, SimplicialModule) + (symbol ==, SimplicialModule, ZZ) + (symbol ==, ZZ, SimplicialModule) + Headline + whether two simplicial modules are equal + Usage + C == D + C == 0 + Inputs + C:SimplicialModule + D:SimplicialModule + Outputs + :Boolean + that is true when {\tt C} and {\tt D} are equal + Description + Text + Two simplicial modules are equal if the corresponding + objects and corresponding maps at each index are equal. + Example + S = ZZ/101[a..c] + C = simplicialModule(K = freeResolution coker vars S, 4) + D = image id_C; + C === D + C == D + Text + Both the maps and the objects must be equal. + Example + E = simplicialModule(complex for i from 1 to 3 list 0*dd^K_i, 4) + dd^E + C == E + E == 0 + Text + A simplicial module is equal to zero if all the objects and maps are zero. + This could require computation to determine if something that + is superficially not zero is in fact zero. + Example + f = id_C + D = coker f + D == 0 + Example + C0 = simplicialModule( S^0, 5, Degeneracy => true) + C1 = simplicialModule(complex(S^0, Base => 2), 5, Degeneracy => true) + topDegree C0 == topDegree C1 + C0 == C1 + C0 == 0 + C1 == 0 + Caveat + Testing for equality is not the same as testing for isomorphism. + SeeAlso +/// + + +doc /// + Key + "face/degeneracy maps of a simplicial module" + (symbol^, Symbol, SimplicialModule) + ss + Headline + access the face and degeneracy maps of a simplicial module + Usage + dd^C + ss^C + Inputs + C:SimplicialModule + Outputs + :SimplicialModuleMap + a map of degree -1 or 1, respectively + Description + Text + A simplicial module is a sequence of modules connected + by homomorphisms, called face/degeneracy maps, such that + these maps satisfy a set of identities known as the simplicial identities. + More precisely we should have the following equalities: + 1. For face maps: + \[ d_j d_i = d_i d_{j-1} \text{ for } 0 \leq i < j \leq n \] + 2. For face and degeneracy maps: + \[ d_i s_j = s_{j-1} d_i \text{ for } i < j \] + \[ d_j s_j = \text{id} \] + \[ d_{j+1} s_j = \text{id} \] + \[ d_k s_j = s_j d_{k-1} \text{ for } k > j+1 \] + 3. For degeneracy maps: + \[ s_j s_i = s_i s_{j+1} \text{ for } i \leq j \] + Text + The face/degeneracy maps are considered as double indexed in this package. This is because + for a fixed integer $n$, the module $S_n$ comes equipped with $n$ face and degeneracy maps: + $$d_{n,i} : S_n \to S_{n-1}, \quad \text{and} \quad s_{n,i} : S_n \to S_{n+1}.$$ + The above maps can be accessed as follows: + Example + R = QQ[a..d]; + I = ideal(a*d-b*c, b^2-a*c, c^2-b*d); + C = simplicialModule(freeResolution(R^1/I), 4, Degeneracy => true) + isWellDefined C + dd^C + C.dd + ss^C + C.ss + assert(dd^C === C.dd) + assert(source dd^C === C) + assert(target dd^C === C) + assert(degree dd^C === -1) + assert(source ss^C === C) + assert(target ss^C === C) + assert(degree ss^C === 1) + Text + The individual maps between terms are indexed by their + source. + Example + dd^C_(2,0) + assert(source dd^C_2 === C_2) + assert(target dd^C_2 === C_1) + SeeAlso + "Making maps between simplicial modules" + (symbol_, SimplicialModuleMap, ZZ) + (symbol_, SimplicialModule, ZZ) + (source, SimplicialModuleMap) + (target, SimplicialModuleMap) + (degree, SimplicialModuleMap) +/// + + + +doc /// + Key + (symbol_, SimplicialModule, Array) + (symbol^, SimplicialModule, Array) + Headline + the canonical inclusion or projection map of a direct sum + Usage + i = C_[name] + p = C^[name] + Inputs + C:SimplicialModule + name: + Outputs + :SimplicialModuleMap + {\tt i} is the canonical inclusion and {\tt p} is + the canonical projection + Description + Text + The direct sum is an n-ary operator with projection and + inclusion maps from each component satisfying appropriate + identities. + + One can access these maps as follows. + Example + S = ZZ/101[a,b,c]; + C1 = simplicialModule(freeResolution coker vars S, 5, Degeneracy => true) + C2 = simplicialModule(complex (ideal(a,b,c)) , 5, Degeneracy => true) + D = C1 ++ C2 + D_[0] + isCommutative D_[0] + D_[1] + D^[0] * D_[0] == 1 + D^[1] * D_[1] == 1 + D^[0] * D_[1] == 0 + D^[1] * D_[0] == 0 + D_[0] * D^[0] + D_[1] * D^[1] == 1 + Text + The default names for the components are the non-negative + integers. However, one can choose any name. + Example + E = (chicken => C1) ++ (nuggets => C2) + E_[chicken] + E_[nuggets] + E^[chicken] * E_[chicken] == 1 + E^[nuggets] * E_[nuggets] == 1 + E^[chicken] * E_[nuggets] == 0 + E^[nuggets] * E_[chicken] == 0 + E_[chicken] * E^[chicken] + E_[nuggets] * E^[nuggets] == 1 + Text + One can also access inclusion and projection maps of sub-direct sums. + Example + F = directSum(C1, C2, simplicialModule(complex(S^2, Base => 1), 5, Degeneracy => true)) + prune (F^[0,1]) + isSimplicialMorphism oo + prune (F_[0,2]) + isSimplicialMorphism oo + SeeAlso + (directSum, SimplicialModule) + (components, SimplicialModule) + indices +/// + +doc /// + Key + (components, SimplicialModule) + Headline + list the components of a direct sum + Usage + components C + Inputs + C:SimplicialModule + Outputs + :List + the component simplicial modules of a direct sum (of simplicial modules) + Description + Text + A simplicial module which has been constructed as a direct sum + stores its component simplicial modules. + Example + S = ZZ/101[a,b,c]; + C1 = simplicialModule freeResolution coker vars S + C2 = simplicialModule(complex (ideal(a,b,c)), 3) + D = C1 ++ C2 + L = components D + L_0 === C1 + L_1 === C2 + E = (peanut => C1) ++ (butter => C2) + components E + Text + The names of the component simplicial modules are called indices, + and are used to access the relevant inclusion and projection maps. + Example + indices D + D^[0] + indices E + E_[butter] + SeeAlso + (directSum, SimplicialModule) + indices + (symbol_, SimplicialModule, Array) + (symbol^, SimplicialModule, Array) +/// + + +doc /// + Key + (symbol**, SimplicialModule, SimplicialModule) + (symbol**, Complex, SimplicialModule) + (symbol**, SimplicialModule, Complex) + (symbol**, SimplicialModule, Module) + (symbol**, Module, SimplicialModule) + Headline + tensor product of simplicial modules + Usage + D = C1 ** C2 + Inputs + C1:SimplicialModule + or @ofClass Module@ + C2:SimplicialModule + or @ofClass Module@ + Outputs + D:SimplicialModule + tensor product of {\tt C1} and {\tt C2} + Description + Text + The tensor product is a simplicial module $D$ whose $i$th component is + the tensor product of the degree i components of $C1$ and $C2$. The face/degeneracy maps + are given by the tensor products of the face an degeneracy maps of the original objects. + + As the next example illustrates, the simplicial tensor product in general does not + normalize to give an object that is isomorphic to the classically defined tensor product + of complexes. + Example + S = ZZ/101[a..c] + Ca = simplicialModule(complex {matrix{{a}}}, 3) + Cb = simplicialModule(complex {matrix{{b}}}, 3) + Cc = simplicialModule(complex {matrix{{c}}}, 3) + Cab = Cb ** Ca + dd^Cab + (prune normalize Cab).dd + assert isWellDefined Cab + Cabc = Cc ** Cab + Cc ** Cb ** Ca + dd^(nC = prune normalize Cabc) + assert isWellDefined nC + Text + If one of the arguments is a module, it is considered as a complex concentrated in homological degree 0. + Example + Cabc ** (S^1/(a,b,c)); + S^2 ** Cabc + Text + Because the tensor product can be regarded as the total complex of a double complex, + each term of the tensor product comes with pairs of indices, labelling the summands. + Example + indices Cabc_1 + components Cabc_1 + Cabc_1_[{1,0}] + indices Cabc_2 + components Cabc_2 + Cabc_2_[{0,2}] + SeeAlso + indices + components + directSum +/// + + + +doc /// + Key + (truncate, List, SimplicialModule) + (truncate, ZZ, SimplicialModule) + Headline + truncation of a simplicial module at a specified degree or set of degrees + Usage + truncate(d, C) + Inputs + d:List + or @TO "ZZ"@, if the underlying ring $R$ is singly graded. + C:SimplicialModule + that is homogeneous over $R$ + Outputs + :SimplicialModule + a simplicial module whose terms consist of all elements of component-wise degree at least {\tt d}. + Description + Text + Truncation of homogeneous (graded) modules induces a natural + operation on simplicial modules. + Text + In the singly graded case, the truncation of a homogeneous + module $M$ at degree $d$ is generated by all homogeneous + elements of degree at least $d$ in $M$. This method applies + this operation to each term in a simplicial module. + Example + R = QQ[a,b,c]; + I = ideal(a*b, a*c, b*c) + C = simplicialModule(freeResolution I, 3, Degeneracy => true) + D = truncate(3,C) + assert isWellDefined D + Text + Truncating at a degree less than the minimal generators + is the identity operation. + Example + assert(C == truncate(0, C)) + Text + In the multi-graded case, the truncation of a homogeneous module at + a list of degrees is generated by all homogeneous elements of degree + that are component-wise greater than or equal to at least one + of the degrees. + Example + A = ZZ/101[x_0, x_1, y_0, y_1, y_2, Degrees => {2:{1,0}, 3:{0,1}}]; + I = intersect(ideal(x_0, x_1), ideal(y_0, y_1, y_2)) + C = simplicialModule(freeResolution I, 3, Degeneracy => true) + D1 = prune truncate({{1,1}}, C) + D2 = truncate({{1,0}}, C) + D3 = truncate({{0,1}}, C) + D4 = truncate({{1,0},{0,1}}, C); + D5 = truncate({{2,2}}, C); + assert all({D1,D2,D3,D4,D5}, isWellDefined) + SeeAlso + "Making simplicial modules" + (truncate, List, Module) + (truncate, List, SimplicialModuleMap) +/// + + +doc /// + Key + (symbol SPACE, RingMap, SimplicialModule) + Headline + apply a ring map to a simplicial module + Usage + phi C + Inputs + phi:RingMap + whose source is a ring $R$, and whose target is a ring $S$ + C:SimplicialModule + over the ring $R$ + Outputs + :SimplicialModule + over the ring $S$ + Description + Text + We illustrate the image of a simplicial module under a ring map. + Example + R = QQ[x,y,z] + S = QQ[s,t] + phi = map(S, R, {s, s+t, t}) + I = ideal(x^3, x^2*y, x*y^4, y*z^5) + C = simplicialModule(freeResolution I, 3, Degeneracy => true) + D = phi C + isWellDefined D + dd^D + Text + When the ring map doesn't preserve homogeneity, + the @TO "DegreeMap"@ option is needed to determine + the degrees of the image free modules in the simplicial module. + Example + R = ZZ/101[a..d] + S = ZZ/101[s,t] + phi = map(S, R, {s^4, s^3*t, s*t^3, t^4}, DegreeMap => i -> 4*i) + C = simplicialModule(freeResolution coker vars R, 4, Degeneracy => true) + D = phi C + assert isWellDefined D + Caveat + Every term in the simplicial module must be free or a submodule of a free module. + Otherwise, use @TO (tensor, RingMap, SimplicialModule)@. + SeeAlso + (symbol SPACE, RingMap, SimplicialModuleMap) + (symbol **, RingMap, SimplicialModule) +/// + + +doc /// + Key + (symbol**, RingMap, SimplicialModule) + (symbol**, SimplicialModule, RingMap) + (tensor, RingMap, SimplicialModule) + (tensor, SimplicialModule, RingMap) + (symbol**, SimplicialModule, Ring) + (symbol**, Ring, SimplicialModule) + Headline + tensor a simplicial module along a ring map + Usage + phi ** C + tensor(phi, C) + S ** C + C ** S + Inputs + phi:RingMap + whose source is a ring $R$ and whose target is a ring $S$ + C:SimplicialModule + over the ring $R$ + Outputs + :SimplicialModule + over the ring $S$ + Description + Text + These methods implement the base change of rings. As input, one can either + give a ring map $\phi$, or the ring $S$ (when there is a canonical map + from $R$ to $S$). + Text + We illustrate the tensor product of a simplicial module along a ring map. + Example + R = QQ[x,y,z]; + S = QQ[s,t]; + phi = map(S, R, {s, s+t, t}) + I = ideal(x^3, x^2*y, x*y^4, y*z^5) + C = simplicialModule(freeResolution I, 3, Degeneracy => true) + D = phi ** C + assert isWellDefined D + dd^D + ss^D + Text + If a ring is used rather than a ring map, then the implicit + map from the underlying ring of the complex to the given ring + is used. + Example + A = R/(x^2+y^2+z^2); + C ** A + assert(map(A,R) ** C == C ** A) + Text + The commutativity of tensor product is witnessed as follows. + Example + assert(D == C ** phi) + assert(C ** A == A ** C) + Text + When the modules in the complex are not free modules, + this is different than the image of a complex + under a ring map. + Example + use R + I = ideal(x*y, x*z, y*z); + J = I + ideal(x^2, y^2); + g = inducedMap(module J, module I) + assert isWellDefined g + C = simplicialModule(complex {g}, 3, Degeneracy => true) + D1 = phi C + assert isWellDefined D1 + D2 = phi ** C + assert isWellDefined D2 + prune D1 + prune D2 + Text + When the ring map doesn't preserve homogeneity, + the @TO "DegreeMap"@ option is needed to determine + the degrees of the image free modules in the complex. + Example + R = ZZ/101[a..d]; + S = ZZ/101[s,t]; + f = map(S, R, {s^4, s^3*t, s*t^3, t^4}, DegreeMap => i -> 4*i) + C = simplicialModule(freeResolution coker vars R, 3, Degeneracy => true) + D = f ** C + D == f C + assert isWellDefined D + SeeAlso + (symbol **, RingMap, SimplicialModuleMap) + (symbol SPACE, RingMap, SimplicialModule) +/// + + + +doc /// + Key + (minimalPresentation, SimplicialModule) + (prune, SimplicialModule) + (prune, SimplicialModuleMap) + (minimalPresentation, SimplicialModuleMap) + Headline + minimal presentation of all terms in a simplicial module + Usage + D = minimalPresentation C + D = prune C + h = minimalPresentation f + h = prune f + Inputs + C:SimplicialModule + or $f$ @ofClass SimplicialModuleMap@ + Exclude => + unused + Outputs + D:SimplicialModule + isomorphic to the input, where each term is replaced + by a minimally presented model, or $h$ @ofClass SimplicialModuleMap@ + where the source and target are minimally presented + Consequences + Item + The isomorphism $g : D \to C$ is available as + @TT "g = D.cache.pruningMap"@. The inverse isomorphism + can be obtained as @TT "g^-1"@ + Description + Text + This is frequently useful to make the output of certain + operations readable or understandable. This operation + is functorial, applying both to simplicial modules and simplicial module maps. + Text + In particular, images/kernels/cokernels of maps need to be pruned to + be understood. For instance, this is useful + for recognizing when terms given by subquotient modules + are actually zero. + Example + S = ZZ/101[a,b,c,d,e]; + I = ideal(a,b) * ideal(c,d,e) + F = simplicialModule((dual freeResolution I)[-4], 2, Degeneracy => true) + C = HH F + D = prune C + g = D.cache.pruningMap + assert isWellDefined g + assert isSimplicialMorphism g + assert (target g == C) + assert (source g == D) + g^-1 + assert(g*g^-1 == 1 and g^-1*g == 1) + Text + The image of a map of simplicial modules also becomes more + understandable via pruning. + Example + S = ZZ/101[a,b,c]; + I = ideal(a^2,b^2,c^2); + J = I + ideal(a*b*c); + FI = simplicialModule(freeResolution I, Degeneracy => true) + FJ = simplicialModule(freeResolution J, Degeneracy => true) + f = randomSimplicialMap(FJ, FI ** S^{-1}, Cycle => true) + C = image f + D = prune C + g = D.cache.pruningMap + assert isWellDefined g + assert isSimplicialMorphism g + assert (target g == C) + assert (source g == D) + g^-1 + assert(g*g^-1 == 1 and g^-1*g == 1) + Text + One can directly prune the map of simplicial modules $f$. + Example + h = prune f + assert(source h === prune source f) + assert(target h === prune target f) + SeeAlso + "Making simplicial modules" + (minimalPresentation, Module) + randomSimplicialMap + isSimplicialMorphism +/// + + +doc /// + Key + "Making maps between simplicial modules" + Headline + information about the basic constructors + Description + Text + @SUBSECTION "Basic constructors"@ + Text + @UL { + TO (map, SimplicialModule, SimplicialModule, HashTable), + TO (map, SimplicialModule, SimplicialModule, ZZ), + TO (map, SimplicialModule, SimplicialModule, SimplicialModuleMap), + TO (id, SimplicialModule), + TO "face/degeneracy maps of a simplicial module", + TO (symbol SPACE, SimplicialModuleMap, Array), + TO (isWellDefined, SimplicialModuleMap) + }@ + Text + @SUBSECTION "Important computations creating new simplicial module maps"@ + Text + @UL { + TO (symbol**, SimplicialModule, Matrix) + }@ + Text + @SUBSECTION "Canonical maps between simplicial modules"@ + Text + Some simplicial modules come with canonical maps. + These are best accessed using @TO inducedMap@. + Text + @UL { + TO (kernel, SimplicialModuleMap), + TO (cokernel, SimplicialModuleMap), + TO (image, SimplicialModuleMap), + TO (coimage, SimplicialModuleMap), + TO (inducedMap, SimplicialModule, SimplicialModule) + }@ + Text + @SUBSECTION "Random maps of simplicial modules"@ + Text + The method @TO (randomSimplicialMap, SimplicialModule, SimplicialModule)@ + allows one to construct random simplicial module maps, + random morphisms between simplicial modules, and random + null homotopies between simplicial modules. + Text + @UL { + TO (isCommutative, SimplicialModuleMap), + TO (isSimplicialMorphism, SimplicialModuleMap) + }@ + Text + @SUBSECTION "Elementary operations on simplicial module maps"@ + Text + @UL { + TO "arithmetic with simplicial module maps", + TO (symbol +, SimplicialModuleMap, SimplicialModuleMap), + TO (symbol |, SimplicialModuleMap, SimplicialModuleMap), + TO (symbol ||, SimplicialModuleMap, SimplicialModuleMap), + TO (symbol ++, SimplicialModuleMap, SimplicialModuleMap), + TO (symbol **, SimplicialModuleMap, SimplicialModuleMap), + TO (symbol _, SimplicialModuleMap, Array), + TO (symbol ^, SimplicialModuleMap, Array), + TO (truncate, List, SimplicialModuleMap), + TO (symbol SPACE, RingMap, SimplicialModuleMap), + TO (symbol **, RingMap, SimplicialModuleMap) + }@ + SeeAlso + "Making simplicial modules" + "Basic invariants and properties" +/// + + +doc /// + Key + SimplicialModuleMap + complexMap + Headline + the class of all maps between simplicial modules + Description + Text + @LITERAL ////////@ + + A map of simplicial modules $f \colon C \rightarrow D$ of degree $d$ is a + sequence of maps $f_i \colon C_i \rightarrow D_{d+i}$. + No relationship between the maps $f_i$ and + and the face/degeneracy maps of either $C$ or $D$ is assumed. If a simplicial module map + is obtained as the image of a morphism of complexes under the Dold-Kan functor, + the key {\tt complexMap} will be stored for more efficient normalization computations. + + The usual algebraic operations are available: addition, + subtraction, scalar multiplication, and composition. The + identity map from a simplicial module to itself can be produced with + @TO "id"@. An attempt to add (subtract, or compare) a ring + element to a simplicial module will result in the ring element being + multiplied by the appropriate identity map. + SeeAlso + SimplicialModule + "Making maps between simplicial modules" + "arithmetic with simplicial module maps" +/// + + +doc /// + Key + (map, SimplicialModule, SimplicialModule, HashTable) + Headline + make a map of simplicial modules + Usage + f = map(D, C, H) + Inputs + C:SimplicialModule + D:SimplicialModule + H:HashTable + whose keys are integers, and whose values are the maps between + the corresponding terms + Degree => ZZ + the degree of the resulting map + DegreeLift => + unused + DegreeMap => + unused + Outputs + f:SimplicialModuleMap + Description + Text + A map of simplicial modules $f : C \rightarrow D$ of degree $d$ is a + sequence of maps $f_i : C_i \rightarrow D_{d+i}$. + No relationship between the maps $f_i$ and + and the face/degeneracy maps of either $C$ or $D$ is assumed. + + We construct a map of simplicial modules by specifying the + individual maps between the terms. Note that this constructor is typically + used more behind the scenes, and using the @TO simplicialModule@ or basic map constructors + is typically much more efficient than typing the maps by hand. + Example + R = ZZ/101[a,b,c]; + C = simplicialModule(F = freeResolution coker matrix{{a^2-b^2,b^3-c^3,c^4}}, Degeneracy => true) + D = simplicialModule(G = freeResolution coker vars R, Degeneracy => true) + H = hashTable { 0 => map(D_0, C_0, 1), + 1 => map(D_1, C_1, {{1, 0, 0, 0}, {0, a, 0, 0}, {0, -b, b^2, 0}, {0, 0, -c^2, c^3}}), + 2 => map(D_2, C_2, {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, a, 0, 0, 0, 0,0, 0, 0, 0}, + {0, -b, b^2, 0, 0, 0, 0, 0, 0, 0}, + {0, 0,-c^2, c^3, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, a, 0, 0, 0, 0,0}, + {0, 0, 0, 0, -b, b^2, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,-c^2, c^3, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, -a*c^2, a*c^3, 0}, + {0, 0, 0, 0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3}}), + 3 => map(D_3, C_3, {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0}, + {0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0}, + {0, -b, b^2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0}, + {0, 0, -c^2, c^3, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, a, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, -b, b^2, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,-c^2, c^3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0,0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0,0, 0, 0, 0, 0, 0, -b, b^2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0}, + {0, 0, 0, 0, 0, 0, 0, 0, -c^2, c^3, 0, 0, 0, 0, 0, 0,0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0,0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-a*c^2, a*c^3, 0, 0, 0, 0, 0, 0, 0,0}, + {0, 0, 0, 0, 0, 0,0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0, 0, 0,0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -a*c^2,a*c^3, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, b*c^2, -b*c^3, b^2*c^3, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0, 0}, + {0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -a*c^2, a*c^3,0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2*c^3}}) + } + f = map(D, C, H) + assert isWellDefined f + assert isHomogeneous f + assert(degree f == 0) + assert isSimplicialMorphism f + Text + The keys in the hash table index the terms in the source of the + map. If a key is missing, that map is taken to be the zero map. + We illustrate this by constructing the 0 map as follows: + Example + h = map(C, C, hashTable {}) + h == 0 + Text + This is the primary constructor used by all of the more user friendly + methods for constructing a chain complex. + Caveat + This constructor minimizes computation + and does very little error checking. To verify that a simplicial module map + is well constructed, use @TO (isWellDefined, SimplicialModuleMap)@. + SeeAlso + SimplicialModuleMap + (isWellDefined, SimplicialModuleMap) + (isHomogeneous, SimplicialModuleMap) + (degree, SimplicialModuleMap) + (isSimplicialMorphism, SimplicialModuleMap) + (isCommutative, SimplicialModuleMap) + (source, SimplicialModuleMap) + (target, SimplicialModuleMap) +/// + + +doc /// + Key + (map, SimplicialModule, SimplicialModule, ZZ) + Headline + make the zero map or identity between simplicial modules + Usage + f = map(D, C, 0) + f = map(C, C, 1) + Inputs + C:SimplicialModule + D:SimplicialModule + 0:ZZ + or 1 + Degree => ZZ + the degree of the resulting map + DegreeLift => + unused + DegreeMap => + unused + Outputs + f:SimplicialModuleMap + the zero map from $C$ to $D$ or the identity map from $C$ to $C$ + Description + Text + A map of simplicial modules $f : C \rightarrow D$ of degree $d$ is a + sequence of maps $f_i : C_i \rightarrow D_{d+i}$. + + We construct the zero map between two + simplicial modules. + Example + R = QQ[a,b,c] + C = simplicialModule(freeResolution coker vars R, Degeneracy => true) + D = simplicialModule(freeResolution coker matrix{{a^2, b^2, c^2}}, Degeneracy => true) + f = map(D, C, 0) + assert isWellDefined f + assert isSimplicialMorphism f + g = map(C, C, 0, Degree => 13) + assert isWellDefined g + assert(degree g == 13) + assert not isSimplicialMorphism g + assert isCommutative g + assert isHomogeneous g + assert(source g == C) + assert(target g == C) + Text + Using this function to create the identity map + is the same as using @TO (id, SimplicialModule)@. + Example + assert(map(C, C, 1) === id_C) + SeeAlso + SimplicialModuleMap + (isWellDefined, SimplicialModuleMap) + (isHomogeneous, SimplicialModuleMap) + (degree, SimplicialModuleMap) + (isSimplicialMorphism, SimplicialModuleMap) + (isCommutative, SimplicialModuleMap) + (source, SimplicialModuleMap) + (target, SimplicialModuleMap) + (id, SimplicialModule) +/// + +doc /// + Key + (map, SimplicialModule, SimplicialModule, SimplicialModuleMap) + Headline + make a new map of simplicial modules, induced from an existing one + Usage + g = map(D, C, f) + Inputs + C:SimplicialModule + D:SimplicialModule + f:SimplicialModuleMap + regarded as providing matrices which induce maps between the terms of $C$ and $D$ + Degree => ZZ + the degree $d$ of the resulting map + DegreeLift => + unused + DegreeMap => + unused + Outputs + g:SimplicialModuleMap + Description + Text + A map of simplicial modules $f : C' \rightarrow D'$ is a + sequence of maps $f_i : C'_i \rightarrow D'_{d'+i}$. + The new map $g : C \rightarrow D$ is the sequence of maps $g_i : C_i \rightarrow D_{d+i}$ + induced by the matrix of $f_i$. + + One use for this function is to get the new map of simplicial modules induced by + forgetting the underlying complexes of the course and target, assuming that the + source and target is obtained as a Dold-Kan image. + Example + R = ZZ/101[a,b,c]; + C = simplicialModule(freeResolution coker vars R, Degeneracy => true) + f = map(forgetComplex C, forgetComplex C, id_C) + assert isWellDefined f + assert(degree f == 0) + assert isCommutative f + assert isSimplicialMorphism f + normalize f --notice how the normalization is not already pruned + normalize id_C + prune normalize f == normalize id_C + SeeAlso + SimplicialModuleMap + (isWellDefined, SimplicialModuleMap) + (degree, SimplicialModuleMap) + (isSimplicialMorphism, SimplicialModuleMap) + (isCommutative, SimplicialModuleMap) + (symbol SPACE, SimplicialModule, Array) +/// + + + +doc /// + Key + (id, SimplicialModule) + Headline + the identity map of a simplicial module + Usage + f = id_C + Inputs + C:SimplicialModule + Outputs + f:SimplicialModuleMap + the identity map from $C$ to itself + Description + Text + The simplicial modules together with simplicial morphisms + forms a category. In particular, every simplicial module has an identity map. + Example + R = ZZ/101[x,y]/(x^3, y^3) + C = simplicialModule(freeResolution(coker vars R, LengthLimit=>6), 6, Degeneracy => true) + f = id_C; + assert isWellDefined f + assert isSimplicialMorphism f + SeeAlso + (map, SimplicialModule, SimplicialModule, ZZ) + (isWellDefined, SimplicialModuleMap) + (isSimplicialMorphism, SimplicialModuleMap) +/// + +doc /// + Key + (isWellDefined, SimplicialModuleMap) + Headline + whether a map of simplicial modules is well-defined + Usage + isWellDefined f + Inputs + f:SimplicialModuleMap + Outputs + :Boolean + that is true when {\tt f} determines a well defined simplicial module map + Description + Text + A map of simplicial modules $f : C \to D$ of degree $d$ is a sequence of + maps $f_i : C_i \to D_{d+i}$. No relationship is required between + these maps and the face/degeneracy maps in the source and target. + + This routine checks that $C$ and $D$ are well-defined + simplicial modules, and that, for each $f_i$, the source and + target equal $C_i$ and $D_{d+i}$, respectively. If the + variable {\tt debugLevel} is set to a value greater than + zero, then information about the nature of any failure is + displayed. + Text + Unlike the @TO2((isWellDefined, SimplicialModule), + "corresponding function for SimplicialModulees")@, + the basic constructors for simplicial module maps are all but + assured to be well defined. The only case that could cause + a problem is if one constructs the source or target + complex, and those are not well defined. + Example + R = ZZ/101[a,b,c]; + C = simplicialModule(F = freeResolution coker matrix{{a^2-b^2,b^3-c^3,c^4}}, Degeneracy => true) + D = simplicialModule(G = freeResolution coker vars R, Degeneracy => true) + H = hashTable { 0 => map(D_0, C_0, 1), + 1 => map(D_1, C_1, {{1, 0, 0, 0}, {0, a, 0, 0}, {0, -b, b^2, 0}, {0, 0, -c^2, c^3}}), + 2 => map(D_2, C_2, {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, a, 0, 0, 0, 0,0, 0, 0, 0}, + {0, -b, b^2, 0, 0, 0, 0, 0, 0, 0}, + {0, 0,-c^2, c^3, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, a, 0, 0, 0, 0,0}, + {0, 0, 0, 0, -b, b^2, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,-c^2, c^3, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, -a*c^2, a*c^3, 0}, + {0, 0, 0, 0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3}}), + 3 => map(D_3, C_3, {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0}, + {0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0}, + {0, -b, b^2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0}, + {0, 0, -c^2, c^3, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, a, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, -b, b^2, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,-c^2, c^3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0,0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0,0, 0, 0, 0, 0, 0, -b, b^2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0}, + {0, 0, 0, 0, 0, 0, 0, 0, -c^2, c^3, 0, 0, 0, 0, 0, 0,0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0,0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-a*c^2, a*c^3, 0, 0, 0, 0, 0, 0, 0,0}, + {0, 0, 0, 0, 0, 0,0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0, 0, 0,0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -a*c^2,a*c^3, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, b*c^2, -b*c^3, b^2*c^3, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0, 0}, + {0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -a*c^2, a*c^3,0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2*c^3}}) + } + f = map(D, C, H) + assert isWellDefined f + assert isHomogeneous f + assert(degree f == 0) + assert isSimplicialMorphism f + Text + We construct two random maps of simplicial modules, + and check to see that, as should be the case, + both are well defined. + Example + g = randomSimplicialMap(D,C); --outputs are large + normalize g + assert isWellDefined g + assert not isCommutative g + Example + h = randomSimplicialMap(D,C, Cycle => true); + normalize h + assert isWellDefined h + assert isSimplicialMorphism h + Text + This method also checks the following aspects of + the data structure: + Text + @UL { + TEX "The underlying hash table has exactly the expected keys, + namely, {\\tt source, target, degree, map, cache}", + "The ring of the source and target are the same", + "The source and target are well defined simplicial modules", + "The degree is an integer", + TEX "All keys in the {\\tt map} field are integers or sequences, + in the range of the top degree of the source", + TEX "The source and target of each $f_i$ is as expected", + TEX "If the {\\tt isCommutative} key is present in the cache + table, then commutativity of the map with the face/degeneracy maps + is checked" + }@ + SeeAlso + (isWellDefined, SimplicialModule) + (isCommutative, SimplicialModuleMap) + (isSimplicialMorphism, SimplicialModuleMap) + (map, SimplicialModule, SimplicialModule, HashTable) +/// + +doc /// + Key + (source, SimplicialModuleMap) + Headline + get the source of a map of simplicial modules + Usage + C = source f + Inputs + f:SimplicialModuleMap + Outputs + C:SimplicialModule + Description + Text + Given a simplicial module map $f : C \to D$ + this method returns the simplicial module $C$. + Example + R = ZZ/101[a..d] + I = ideal(a^2, b^2, c^2) + J = I + ideal(a*b*c) + FI = simplicialModule(freeResolution I, Degeneracy => true) + FJ = simplicialModule(freeResolution J, Degeneracy => true) + f = randomSimplicialMap(FJ, FI, Cycle=>true) + source f + assert isWellDefined f + assert isSimplicialMorphism f + assert(source f == FI) + assert(target f == FJ) + Text + The face/degeneracy map in a simplicial module is considered to have type SimplicialModuleMap. + Example + kk = coker vars R + F = simplicialModule(freeResolution kk, Degeneracy => true) + source dd^F == F + target dd^F == F + degree dd^F == -1 + SeeAlso + "Making simplicial modules" + (target, SimplicialModuleMap) + (randomSimplicialMap, SimplicialModule, SimplicialModule) +/// + +doc /// + Key + (target, SimplicialModuleMap) + Headline + get the target of a map of simplicial modules + Usage + C = target f + Inputs + f:SimplicialModuleMap + Outputs + C:SimplicialModule + Description + Text + Given a simplicial module map $f : C \to D$ + this method returns the simplicial module $D$. + Example + R = ZZ/101[a..d] + I = ideal(a^2, b^2, c^2) + J = I + ideal(a*b*c) + FI = simplicialModule(freeResolution I, Degeneracy => true) + FJ = simplicialModule(freeResolution J, Degeneracy => true) + f = randomSimplicialMap(FJ, FI, Cycle=>true) + source f + assert isWellDefined f + assert isSimplicialMorphism f + assert(source f == FI) + assert(target f == FJ) + Text + The face/degeneracy map in a simplicial module is considered to have type SimplicialModuleMap. + Example + kk = coker vars R + F = simplicialModule(freeResolution kk, Degeneracy => true) + source dd^F == F + target dd^F == F + degree dd^F == -1 + SeeAlso + "Making simplicial modules" + (source, SimplicialModuleMap) + (freeResolution, Ideal) + (randomSimplicialMap, SimplicialModule, SimplicialModule) +/// + +doc /// + Key + (degree, SimplicialModuleMap) + Headline + get the degree of a map of simplicial modules + Usage + degree f + Inputs + f:SimplicialModuleMap + Outputs + :ZZ + Description + Text + A simplicial module map $f : C \to D$ of degree $d$ is a sequence of + of maps $f_i : C_i \to D_{i+d}$. + This method returns $d$. + Text + The degree of the face/degeneracy map of a simplicial module is -1 or 1, respectively. + Example + R = ZZ/101[a..d]; + I = ideal(a^2, b^2, c^2) + FI = simplicialModule(freeResolution I, Degeneracy => true) + assert(degree dd^FI == -1) + assert(degree ss^FI == 1) + Example + FJ = simplicialModule(freeResolution (I + ideal(a*b*c)), Degeneracy => true) + f = randomSimplicialMap(FJ, FI, Cycle=>true, Degree => -2); + normalize f + SeeAlso + "Basic invariants and properties" + (source, SimplicialModuleMap) + (target, SimplicialModuleMap) + (randomSimplicialMap, SimplicialModule, SimplicialModule) +/// + + +doc /// + Key + (symbol _, SimplicialModuleMap, ZZ) + (symbol _, SimplicialModuleMap, Sequence) + Headline + access individual matrices in a simplicial module map + Usage + f_i + Inputs + f:SimplicialModuleMap + i:ZZ + the degree index or a sequence + Outputs + :Matrix + the {\tt i}-th map + Description + Text + A simplicial module map $f : C \to D$ of degree $d$ is a sequence of maps $f_i : C_i \to D_{i+d}$. + This method allows one to access the individual $f_i$. + Example + S = ZZ/101[a..c]; + C = simplicialModule(freeResolution coker matrix{{a^2, b^2, c^2}}, Degeneracy => true) + D = simplicialModule(freeResolution coker vars S, Degeneracy => true) + f = randomSimplicialMap(D, C) + f_2 + f_0 + Text + The face/degeneracy maps of a simplicial module are instead instead by sequences $(a,b)$ of integers, + where $b \leq a$. + Example + dd^C_(2,0) + dd^C_(2,1) + dd^C_(2,2) + ss^C_(0,0) + ss^C_(1,0) + ss^C_(1,1) + Text + Indices that are outside of the top degree or range of sequences return 0 by default. + Example + topDegree f + f_-1 + f_3 + f_4 + ss^D_(2,3) + ss^D_(4,0) + SeeAlso + (symbol_, SimplicialModule, ZZ) +/// + +doc /// + Key + (isHomogeneous, SimplicialModuleMap) + Headline + whether a map of simplicial modules is homogeneous + Usage + isHomogeneous f + Inputs + f:SimplicialModuleMap + Outputs + :Boolean + that is true when $f_i$ is homogeneous, for all $i$ + Description + Text + A map of simplicial modules $f \colon C \to D$ is homogeneous + (graded) if its underlying ring is graded, and all the + component maps $f_i \colon C_i \to D_{d+i}$ are graded of + degree zero, where $f$ has degree $d$. + Example + S = ZZ/101[a,b,c,d]; + I = minors(2, matrix{{a,b,c},{b,c,d}}) + C = simplicialModule(freeResolution (S^1/I), Degeneracy => true) + assert isHomogeneous dd^C + f = randomSimplicialMap(C, C, Degree => -1) + assert isHomogeneous f + f = randomSimplicialMap(C, C, InternalDegree => 2) + Text + A map of simplicial modules may be homogeneous even if the + source or the target is not homogeneous. + Example + phi = map(S, S, {1,b,c,d}) + D = phi C + dd^D + assert not isHomogeneous dd^D + SeeAlso + "Basic invariants and properties" + isHomogeneous + (isHomogeneous, SimplicialModuleMap) + (randomSimplicialMap, SimplicialModule, SimplicialModule) +/// + + + +doc /// + Key + (components, SimplicialModuleMap) + Headline + list the components of a direct sum + Usage + components f + Inputs + f:SimplicialModuleMap + Outputs + :List + the component maps of a direct sum of maps of simplicial modules + Description + Text + A map of simplicial modules stores its component maps. + Example + S = ZZ/101[a,b,c]; + C = simplicialModule(freeResolution coker vars S, Degeneracy => true) + g1 = id_C + g2 = randomSimplicialMap(C[1], C[2], Boundary => true) + f = g1 ++ g2 + assert isWellDefined f + L = components f + L_0 === g1 + L_1 === g2 + indices f + Text + The names of the components are called indices, and are + used to access the relevant inclusion and projection maps. + Example + f^[0] + f_[0] + SeeAlso + (directSum, SimplicialModuleMap) + (components, SimplicialModule) + indices + (symbol_, SimplicialModuleMap, Array) + (symbol^, SimplicialModuleMap, Array) +/// + +doc /// + Key + (symbol*, SimplicialModuleMap, SimplicialModuleMap) + Headline + composition of homomorphisms of simplicial modules + Usage + f = h * g + Inputs + h:SimplicialModuleMap + if a ring element or integer, then we multiply the ring element + by the appropriate identity map + g:SimplicialModuleMap + Outputs + f:SimplicialModuleMap + the composition of $g$ followed by $h$ + Description + Text + If $g_i : C_i \rightarrow D_{d+i}$, and $h_j : D_j \rightarrow E_{e+j}$, + then the composition corresponds to + $f_i := h_{d+i} * g_i : C_i \rightarrow E_{i+d+e}$. In particular, + the degree of the composition $f$ is the sum of the degrees of + $g$ and $h$. + Example + R = ZZ/101[a..d] + C = simplicialModule(freeResolution coker vars R, Degeneracy => true) + 3 * dd^C + 0 * dd^C + dd^C * ss^C --if C is a well-defined simplicial object, these should all be identity maps + SeeAlso + "Making maps between simplicial modules" + "arithmetic with simplicial module maps" +/// + +doc /// + Key + (symbol ^, SimplicialModuleMap, ZZ) + Headline + the n-fold composition + Usage + f^n + Inputs + f:SimplicialModuleMap + whose source and target are the same simplicial module + n:ZZ + Outputs + :SimplicialModuleMap + the composition of $f$ with itself $n$ times. + Description + Text + A simplicial module map $f : C \to C$ can be composed with itself. + This method produces these new maps of simplicial modules. + Text + The face/degeneracy maps -- always composes with itself to give the + zero map. + Example + S = ZZ/101[a..c]; + C = simplicialModule(freeResolution coker matrix{{a^2, b^2, c^2}}, Degeneracy => true) + f = dd^C + f^2 + assert(source f == target f) + assert(degree f == -1) + assert(degree f^2 == -2) + Example + g = randomSimplicialMap(C, C) + g^2 + g^3 + Text + The zero-th power returns the identity map + Example + f^0 == id_(C[1]) + g^0 == id_C + Text + When $n$ is negative, the result is the $n$-fold power + of the inverse simplicial module map, if it exists. + Example + h = randomSimplicialMap(C, C) + h^-1 + assert(h * h^-1 == id_C) + h^-4 + assert(h^-4 * h^4 == id_C) + SeeAlso + (symbol^, Matrix, ZZ) +/// + +doc /// + Key + (symbol ==, SimplicialModuleMap, SimplicialModuleMap) + (symbol ==, SimplicialModuleMap, ZZ) + (symbol ==, ZZ, SimplicialModuleMap) + Headline + whether two simplicial module maps are equal + Usage + f == g + f == 0 + f == 1 + Inputs + f:SimplicialModuleMap + or 0, or 1. + g:SimplicialModuleMap + or 0, or 1. + Outputs + :Boolean + that is true when {\tt f} and {\tt g} are equal + Description + Text + Two simplicial module maps are equal if they have the same source, + the same target, and $f_i = g_i$ for all $i$. + Example + S = ZZ/101[a..c] + C = simplicialModule(freeResolution coker vars S, Degeneracy => true) + f = id_C + assert(f == 1) + Text + A simplicial module map is equal to zero if all the maps are zero. + This could require computation to determine if something that + is superficially not zero is in fact zero. + Example + assert(0 * id_C == 0) + Example + g = randomSimplicialMap(C, C) + h = inducedMap(coker g, target g) + assert(h == 0) + Text + Testing whether a map is equal to 1 is a shorthand for determining + if the simplicial module map is the identity. + Although the matrices may appear to be the identity, the map is not the + identity when the source and target are not equal. + Example + g = randomSimplicialMap(C, C, InternalDegree=>1, Cycle=>true) + h = inducedMap(coker g, target g) + assert(h != 1) + Text + Testing for equality is not the same testing for isomorphism. + In particular, different presentations of a simplicial module need not be equal. + Example + D = prune image g + p = D.cache.pruningMap + p == 1 + assert(coker p == 0 and ker p == 0) + assert(prune p == 1) + SeeAlso + (symbol ==, SimplicialModule, SimplicialModule) + (symbol SPACE, SimplicialModuleMap, Array) + randomSimplicialMap + (prune, SimplicialModule) +/// + +doc /// + Key + (isCommutative, SimplicialModuleMap) + Headline + whether a simplicial module map commutes with the face/degeneracy maps + Usage + isCommutative f + Inputs + f:SimplicialModuleMap + Outputs + :Boolean + that is true when $f$ commutes with the face/degeneracy maps + Description + Text + For a simplicial module map $f : C \to D$, this method + checks whether, for all $i$, we have + $dd^D_{i} * f_i = f_{i-1} * dd^C_i$ and, if the source at target are equipped with + degeneracy maps, it also checks the equality $ss^D_{i} * f_i = f_{i+1} * ss^C_i$. + Text + We first construct a random simplicial module map which commutes with the face/degeneracy map. + Example + S = ZZ/101[a,b,c]; + C = simplicialModule(freeResolution coker vars S, Degeneracy => true) + D = C ** C + isWellDefined D + f1 = prune randomSimplicialMap(D, C, Cycle => true, InternalDegree => 1); + prune normalize f1 + isCommutative oo + isCommutative f1 + assert(degree f1 == 0) + Text + We next generate a simplicial module map that is commutative and (likely) + induces a nontrivial map on homology. + Example + f2 = randomSimplicialMap(D, C, Cycle => true); + isCommutative f2 + assert(degree f2 == 0) + assert isSimplicialMorphism f2 + Text + If the @TO "debugLevel"@ is greater than zero, then + the location of the first failure of commutativity is displayed. + SeeAlso + isSimplicialMorphism + randomSimplicialMap +/// + +doc /// + Key + (isSimplicialMorphism, SimplicialModuleMap) + isSimplicialMorphism + Headline + whether a simplicial module map is a morphism of simplicial modules + Usage + isSimplicialMorphism f + Inputs + f:SimplicialModuleMap + Outputs + :Boolean + that is true when $f$ commutes with the face/degeneracy maps and has degree $0$ + Description + Text + For a simplicial module map $f : C \to D$ of degree $d$, this method + checks whether $d = 0$ and, for all $i$, we have + $dd^D_{i+d} * f_i = f_{i-1} * dd^C_i$ and if the simplicial module + also has degeneracy maps, it checks that $ss^D_{i} * f_i = f_{i+1} * ss^C_i$. + Text + We first construct a random simplicial module morphism. + Example + S = ZZ/101[a,b,c]; + C = simplicialModule(freeResolution coker vars S, Degeneracy => true) + D = C ** C + f1 = randomSimplicialMap(D, C, Cycle => true, InternalDegree => 1); + isSimplicialMorphism f1 + assert(degree f1 == 0) + Text + We next generate a complex morphism that (likely) + induces a nontrivial map on homology. + Example + f2 = randomSimplicialMap(D, C, Cycle => true); + isSimplicialMorphism f2 + assert(degree f2 == 0) + assert isSimplicialMorphism f2 + prune HH f2 + Text + If the @TO "debugLevel"@ is greater than zero, then + information about the failure is displayed. + SeeAlso + (isCommutative, SimplicialModuleMap) + randomSimplicialMap +/// + + +doc /// + Key + (symbol**, SimplicialModule, Matrix) + (symbol**, Matrix, SimplicialModule) + Headline + create the tensor product of a simplicial module and a map of modules + Usage + h = C ** f + h = f ** C + Inputs + C:SimplicialModule + over a ring $R$ + f:Matrix + defining a homomorphism from the $R$-module $M$ to the $R$-module $N$ + Outputs + h:SimplicialModuleMap + from $C \otimes M$ to $C \otimes N$ + Description + Text + For any simplicial module $C$, a map $f \colon M \to N$ of $R$-modules induces a + morphism $C \otimes f$ of simplicial modules + from $C \otimes M$ to $C \otimes N$. This method returns this map of simplicial modules. + Example + R = ZZ/101[a..d]; + I = ideal(c^2-b*d, b*c-a*d, b^2-a*c) + J = ideal(I_0, I_1) + C = simplicialModule(koszulComplex vars R, Degeneracy => true) + f = map(R^1/I, R^1/J, 1) + C ** f; + isSimplicialMorphism oo + f ** C; + isSimplicialMorphism oo + f' = random(R^2, R^{-1, -1, -1}) + C ** f'; + f' ** C; + assert isWellDefined(C ** f') + assert isWellDefined(f' ** C) + Text + Tensoring with a simplicial module defines a functor from the category + of $R$-modules to the category of simplicial modules over $R$. + Example + f'' = random(source f', R^{-2,-2}) + assert((C ** f') * (C ** f'') == C ** (f' * f'')) + assert(C ** id_(R^{-1,-2,-3}) == id_(C ** R^{-1,-2,-3})) + SeeAlso + "Making maps between simplicial modules" + (symbol**, SimplicialModule, SimplicialModule) +/// + +doc /// + Key + (symbol**, SimplicialModuleMap, SimplicialModuleMap) + (tensor, SimplicialModuleMap, SimplicialModuleMap) + (symbol**, SimplicialModule, SimplicialModuleMap) + (symbol**, SimplicialModuleMap, SimplicialModule) + (symbol**, ComplexMap, SimplicialModuleMap) + (symbol**, SimplicialModuleMap, ComplexMap) + (symbol**, Complex, SimplicialModuleMap) + (symbol**, SimplicialModuleMap, Complex) + (symbol**, SimplicialModuleMap, Module) + (symbol**, Module, SimplicialModuleMap) + Headline + the map of simplicial modules between tensor simplicial modules + Usage + h = f ** g + h = tensor(f, g) + Inputs + f:SimplicialModuleMap + g:SimplicialModuleMap + Outputs + h:SimplicialModuleMap + Description + Text + The maps $f : C \to D$ and $g : E \to F$ of simplicial modules induces the map + $h = f \otimes g : C \otimes E \to D \otimes F$ defined by $c \otimes e \mapsto f(c) \otimes g(e)$. + Example + S = ZZ/101[a..c] + C = simplicialModule(freeResolution coker vars S, Degeneracy => true) + D = simplicialModule((freeResolution coker matrix{{a^2,a*b,b^3}})[-1], Degeneracy => true) + f = randomSimplicialMap(D,C) + E = simplicialModule((dual C.complex)[-3], Degeneracy => true) + F = simplicialModule((dual D.complex)[-3], 3, Degeneracy => true) + g = randomSimplicialMap(F,E) + h = f ** g; + assert isWellDefined h + assert(prune source h == C ** E) + assert(prune target h == D ** F) + Text + If one argument is a SimplicialModule or Module, + then the identity map of the corresponding complex is used. + Example + fE = f ** E; + assert(fE == f ** id_E) + k = coker vars S + gk = g ** k; + Text + This routine is functorial. + Example + D' = simplicialModule((freeResolution coker matrix{{a^2,a*b,c^3}})[-1], 3, Degeneracy => true) + f' = randomSimplicialMap(D', D) + (f' * f) ** g == (f' ** g) * (f ** id_E) + (f' * f) ** g == (f' ** id_F) * (f ** g) + F' = simplicialModule(dual (freeResolution coker matrix{{a^2,a*b,a*c,b^3}})[-3], Degeneracy => true) + g' = randomSimplicialMap(F', F) + f ** (g' * g) == (f ** g') * (id_C ** g) + f ** (g' * g) == (id_D ** g') * (f ** g) + SeeAlso + (symbol**, SimplicialModule, SimplicialModule) + (randomSimplicialMap, SimplicialModule, SimplicialModule) +/// + +doc /// + Key + (truncate, List, SimplicialModuleMap) + (truncate, ZZ, SimplicialModuleMap) + Headline + truncation of a simplicial module map at a specified degree or set of degrees + Usage + truncate(d, f) + Inputs + d:List + or @TO "ZZ"@, if the underlying ring $R$ is singly graded. + f:SimplicialModuleMap + that is homogeneous over $R$ + Outputs + :SimplicialModuleMap + a simplicial module map over $R$ whose terms in the source and target + consist of all elements of component-wise degree at least {\tt d}. + Description + Text + Truncation of homogeneous (graded) maps induces a natural + operation on maps of simplicial modules. + Text + In the singly graded case, the truncation of a homogeneous + module $M$ at degree $d$ is generated by all homogeneous + elements of degree at least $d$ in $M$. The truncation of + a map between homogeneous modules is the induced map + between the truncation of the source and the truncation of + the target. This method applies this operation to each + term in a map of simplicial modules. + Example + R = QQ[a,b,c]; + C = simplicialModule(freeResolution ideal(a*b, a*c, b*c), 3, Degeneracy => true) + D = simplicialModule((freeResolution ideal(a*b, a*c, b*c, a^2-b^2))[-1], 3, Degeneracy => true) + f = randomSimplicialMap(D,C, Cycle => true) + g = truncate(3,f); + assert isWellDefined g + assert (source g == truncate(3, source f)) + assert (target g == truncate(3, target f)) + Text + Truncating at a degree less than the minimal generators + is the identity operation. + Example + assert(f == truncate(0, f)) + Text + In the multi-graded case, the truncation of a homogeneous module at + a list of degrees is generated by all homogeneous elements of degree + that are component-wise greater than or equal to at least one + of the degrees. As in the singly graded case, this induces a map between + the truncations the source and target. + Example + A = ZZ/101[x_0, x_1, y_0, y_1, y_2, Degrees => {2:{1,0}, 3:{0,1}}]; + I = intersect(ideal(x_0, x_1), ideal(y_0, y_1, y_2)) + C = simplicialModule(freeResolution I, 4, Degeneracy => true) + J = intersect(ideal(x_0^2, x_1^2), ideal(y_0^2, y_1^2, y_2^2)) + D = simplicialModule(freeResolution J, 4, Degeneracy => true) + f = simplicialModule(extend(C.complex, D.complex, id_(A^1)), 2) + g1 = prune truncate({{1,1}}, f); + g1_0 + g1_1 + g2 = truncate({{1,0}}, f); + g2_1 + g3 = truncate({{0,1}}, f); + g4 = truncate({{1,0},{0,1}}, f); + g4_1 + g5 = truncate({{2,2}}, f); + assert all({g1,g2,g3,g4,g5}, isWellDefined) + SeeAlso + "Making maps between simplicial modules" + (truncate, List, Matrix) + (truncate, List, SimplicialModule) +/// + + +doc /// + Key + (symbol SPACE, RingMap, SimplicialModuleMap) + Headline + apply a ring map to a map of simplicial modules + Usage + phi f + Inputs + phi:RingMap + whose source is a ring $R$, and whose target is a ring $S$ + f:SimplicialModuleMap + over the ring $R$ + Outputs + :SimplicialModuleMap + over the ring $S$ + Description + Text + We illustrate the image of a simplicial module map along a ring map. + Example + R = QQ[a,b,c,d]; + S = QQ[s,t]; + phi = map(S, R, {s, s+t, t, s-t}) + I = ideal(a*b, b*c, c*d) + J = I + ideal(a^2, b^2, c^2, d^2) + CI = simplicialModule(freeResolution I, 4, Degeneracy => true) + CJ = simplicialModule(freeResolution J, Degeneracy => true) + f = simplicialModule(extend(CJ.complex, CI.complex, map(CJ_0, CI_0, 1)), Degeneracy => true) + assert isWellDefined f + g = phi f + assert isWellDefined g + dd^(source g) + ss^(source g) + dd^(target g); + prune HH normalize g + SeeAlso + (symbol SPACE, RingMap, SimplicialModule) + (symbol **, RingMap, SimplicialModuleMap) +/// + +doc /// + Key + (symbol**, RingMap, SimplicialModuleMap) + (symbol**, Ring, SimplicialModuleMap) + (symbol**, SimplicialModuleMap, RingMap) + (symbol**, SimplicialModuleMap, Ring) + (tensor, RingMap, SimplicialModuleMap) + (tensor, SimplicialModuleMap, RingMap) + Headline + tensor a map of simplicial modules along a ring map + Usage + phi ** f + tensor(phi, f) + S ** f + f ** S + Inputs + phi:RingMap + whose source is a ring $R$, and whose target is a ring $S$ + f:SimplicialModuleMap + over the ring $R$ + Outputs + :SimplicialModuleMap + over the ring $S$ + Description + Text + These methods implement the base change of rings. As input, one can either + give a ring map $\phi$, or the ring $S$ (when there is a canonical map + from $R$ to $S$). + Text + We illustrate the tensor product of a map of simplicial modules along a ring map. + Example + R = QQ[a,b,c,d]; + S = QQ[s,t]; + phi = map(S, R, {s, s+t, t, s-t}) + I = ideal(a*b, b*c, c*d) + J = I + ideal(a^2, b^2, c^2, d^2) + CI = simplicialModule(freeResolution I, 4, Degeneracy => true) + CJ = simplicialModule(freeResolution J, Degeneracy => true) + f = simplicialModule(extend(CJ.complex, CI.complex, map(CJ_0, CI_0, 1)), Degeneracy => true) + assert isWellDefined f + g = phi ** f + assert isWellDefined g + dd^(source g) + ss^(source g) + dd^(target g); + simplicialModule prune HH normalize g + isSimplicialMorphism oo + SeeAlso + (symbol **, RingMap, SimplicialModule) + (symbol SPACE, RingMap, SimplicialModuleMap) +/// + +doc /// + Key + (inducedMap, SimplicialModule, SimplicialModule) + Headline + make the map of simplicial modules induced at each term by the identity map + Usage + f = inducedMap(D, C) + Inputs + C:SimplicialModule + D:SimplicialModule + Degree => ZZ + specify the degree of the map of simplicial modules, if not 0 + Verify => Boolean + if true, check that the resulting maps are well-defined + Outputs + f:SimplicialModuleMap + Description + Text + Let $d$ be the value of the optional argument {\tt + Degree}, or zero, if not given. For each $i$, the terms + $D_{i+d}$ and $C_i$ must be subquotients of the same + ambient free module. This method returns the simplicial module map + induced by the identity on each of these free modules. + + If {\tt Verify => true} is given, then this method + also checks that these identity maps induced well-defined + maps. This can be a relatively expensive computation. + Text + We illustrate this method by truncating a free resolution + at two distinct internal degrees. We check that + the various induced maps compose to give another + induced map. + Example + needsPackage "Truncations" + kk = ZZ/32003 + R = kk[a,b,c] + F = simplicialModule(freeResolution (ideal gens R)^2, 2, Degeneracy => true) + C1 = truncate(3, F); + prune normalize C1 + C2 = truncate(4, F); + prune normalize C2 + assert isWellDefined C1 + assert isWellDefined C2 + f = inducedMap(C1, C2); + prune normalize f + assert isWellDefined f + f1 = inducedMap(F, C1) + f2 = inducedMap(F, C2) + assert isWellDefined f1 + assert isWellDefined f2 + assert(f2 == f1 * f) + SeeAlso + (inducedMap, Module, Module) + "Truncations :: truncate(ZZ,SimplicialModule)" +/// + + +doc /// + Key + "arithmetic with simplicial module maps" + (symbol+, SimplicialModuleMap, SimplicialModuleMap) + (symbol+, RingElement, SimplicialModuleMap) + (symbol+, Number, SimplicialModuleMap) + (symbol+, SimplicialModuleMap, RingElement) + (symbol+, SimplicialModuleMap, Number) + (symbol-, SimplicialModuleMap) + (symbol-, SimplicialModuleMap, SimplicialModuleMap) + (symbol-, RingElement, SimplicialModuleMap) + (symbol-, Number, SimplicialModuleMap) + (symbol-, SimplicialModuleMap, RingElement) + (symbol-, SimplicialModuleMap, Number) + (symbol*, RingElement, SimplicialModuleMap) + (symbol*, Number, SimplicialModuleMap) + (symbol*, SimplicialModuleMap, RingElement) + (symbol*, SimplicialModuleMap, Number) + Headline + perform arithmetic operations on simplicial module maps + Usage + f + g + a + f + f + a + -f + f - g + a - f + f - a + a * f + Inputs + f:SimplicialModuleMap + g:SimplicialModuleMap + a:RingElement + that is, an element in the underlying ring or a number + Outputs + :SimplicialModuleMap + Description + Text + The set of simplicial module maps forms a module over the underlying @TO2((ring, SimplicialModuleMap), "ring")@. + These methods implement the basic operations of addition, subtraction, and scalar multiplication. + Example + R = ZZ/101[a..d]; + C = simplicialModule(freeResolution coker matrix{{a*b, a*c^2, b*c*d^3, a^3}}, Degeneracy => true) + D = simplicialModule(freeResolution coker matrix{{a*b, a*c^2, b*c*d^3, a^3, a*c*d}}, 3, Degeneracy => true) + f = randomSimplicialMap(D, C, Cycle => true); + prune normalize f + g = randomSimplicialMap(D, C, Boundary => true); + prune normalize g + Example + f+g; + isSimplicialMorphism oo + f-g; + isSimplicialMorphism oo + -f; + 3*f; + 0*f + a*f; + assert(0*f == 0) + assert(1*f == f) + assert((-1)*f == -f) + assert(-(f-g) == g-f) + assert((a+b)*f == a*f + b*f) + assert(a*(f+g) == a*f + a*g) + assert isSimplicialMorphism (f+g) + Text + Adding or subtracting a scalar is the same as adding or subtracting the + scalar multiple of the identity. In particular, the source and target must be equal. + Example + h = randomSimplicialMap(C, C); + prune normalize h + prune normalize(h+1) + assert(h+1 == h + id_C) + assert(h+a == h + a*id_C) + assert(1-h == id_C - h) + assert(b-c*h == -c*h + b*id_C) + assert(b-h*c == -h*c + id_C*b) + SeeAlso + "Making maps between simplicial modules" + randomSimplicialMap + (map, SimplicialModule, SimplicialModule, SimplicialModuleMap) +/// + +doc /// + Key + (symbol|, SimplicialModuleMap, SimplicialModuleMap) + Headline + join or concatenate maps horizontally + Usage + f | g + Inputs + f:SimplicialModuleMap + g:SimplicialModuleMap + Outputs + :SimplicialModuleMap + Description + Text + Given simplicial module maps with the same target, + this method constructs the associated map + from the direct sum of the sources to the target. + + First, we define some non-trivial maps of simplicial modules. + Example + R = ZZ/101[a..d]; + C1 = simplicialModule((freeResolution coker matrix{{a,b,c}})[1], Degeneracy => true) + C2 = simplicialModule(freeResolution coker matrix{{a*b,a*c,b*c}}, Degeneracy => true) + D = simplicialModule(freeResolution coker matrix{{a^2,b^2,c*d}}, Degeneracy => true) + f = randomSimplicialMap(D, C1) + g = randomSimplicialMap(D, C2) + Example + h = f|g + assert isWellDefined h + assert(source h === source f ++ source g) + assert(target h === target f) + SeeAlso + (symbol++, SimplicialModule, SimplicialModule) + (symbol++, SimplicialModuleMap, SimplicialModuleMap) + (symbol||, SimplicialModuleMap, SimplicialModuleMap) + (symbol|, Matrix, Matrix) +/// + +doc /// + Key + (symbol||, SimplicialModuleMap, SimplicialModuleMap) + Headline + join or concatenate maps vertically + Usage + f || g + Inputs + f:SimplicialModuleMap + g:SimplicialModuleMap + Outputs + :SimplicialModuleMap + Description + Text + Given simplicial module maps with the same source, + this method constructs the associated map + from the source to the direct sum of the targets. + + First, we define some non-trivial maps of simplicial modules. + Example + R = ZZ/101[a..d]; + D1 = simplicialModule((freeResolution coker matrix{{a,b,c}})[1], Degeneracy => true) + D2 = simplicialModule(freeResolution coker matrix{{a*b,a*c,b*c}}, Degeneracy => true) + C = simplicialModule(freeResolution coker matrix{{a^2,b^2,c*d}}, Degeneracy => true) + f = randomSimplicialMap(D1, C) + g = randomSimplicialMap(D2, C) + Example + h = f||g + assert isWellDefined h + assert(target h === target f ++ target g) + assert(source h === source f) + SeeAlso + (symbol++, SimplicialModule, SimplicialModule) + (symbol++, SimplicialModuleMap, SimplicialModuleMap) + (symbol|, SimplicialModuleMap, SimplicialModuleMap) + (symbol||, Matrix, Matrix) +/// + +doc /// + Key + (symbol++, SimplicialModuleMap, SimplicialModuleMap) + (directSum, SimplicialModuleMap) + Headline + direct sum of simplicial module maps + Usage + h = f ++ g + h = directSum(f,g,...) + h = directSum(name1 => f, name2 => g, ...) + Inputs + f:SimplicialModuleMap + g:SimplicialModuleMap + Outputs + h:SimplicialModuleMap + that is the direct sum of the input chain simplicial module maps + Description + Text + The direct sum of two simplicial module maps is a a simplicial module map + from the direct sum of the sources to the direct sum of + the targets. + + First, we define some non-trivial maps of simplicial modules. + Example + R = ZZ/101[a..d]; + C1 = simplicialModule((freeResolution coker matrix{{a,b,c}})[1], Degeneracy => true) + C2 = simplicialModule(freeResolution coker matrix{{a*b,a*c,b*c}}, Degeneracy => true) + D1 = simplicialModule((freeResolution coker matrix{{a,b,c}}),2, Degeneracy => true) + D2 = simplicialModule(freeResolution coker matrix{{a^2, b^2, c^2}}[-1], 2, Degeneracy => true) + f = randomSimplicialMap(D1, C1, Cycle => true) + g = randomSimplicialMap(D2, C2, Cycle => true) + Example + h = f ++ g + assert isWellDefined h + assert isSimplicialMorphism h + Text + The direct sum of any sequence of simplicial module maps can be + computed as follows. + Example + directSum(f, g, f[2]) + h2 = directSum(peanut => f, butter => g, jelly => f[2]) + indices h2 + h2_[butter,jelly] + assert(source oo == C2 ++ C1[2]) + Text + One can easily obtain the compositions with canonical + injections and surjections. + Example + h_[0]^[0] == f + h_[1]^[1] == g + h_[0]^[1] == 0 + h_[1]^[0] == 0 + Example + h_[0] == h * (C1 ++ C2)_[0] + h_[1] == h * (C1 ++ C2)_[1] + h^[0] == (D1 ++ D2)^[0] * h + h^[1] == (D1 ++ D2)^[1] * h + SeeAlso + (symbol++, SimplicialModule, SimplicialModule) + (symbol**, SimplicialModuleMap, SimplicialModuleMap) + (symbol_, SimplicialModuleMap, Array) +/// + + +doc /// + Key + (image, SimplicialModuleMap) + Headline + make the image of a map of simplicial modules + Usage + E = image f + Inputs + f : SimplicialModuleMap + Outputs + E : SimplicialModule + Description + Text + If $f : C \to D$ is a map of simplicial modules of degree $d$, + then the image is the simplicial module $E$ whose $i-th$ is $image(f_{i-d})$, + and whose face/degeneracy map is induced from the face/degeneracy map + on the target. + Text + In the following example, we first construct a random + simplicial morphism $f : C \to D$. + Example + S = ZZ/101[a,b,c,d]; + C = simplicialModule(freeResolution ideal(b^2-a*c, b*c-a*d, c^2-b*d),3, Degeneracy => true) + D = simplicialModule(freeResolution ideal(a,b,c), Degeneracy => true) + f = randomSimplicialMap(D, C, Cycle => true, InternalDegree => 0) + prune image f + prune normalize oo + i = inducedMap(forgetComplex target f, image f) + isSimplicialMorphism i + normalize i + Text + There is a canonical map of simplicial modules from the image to the target. + Example + g1 = inducedMap(target f, image f) + ker g1 == 0 + image g1 == image f + SeeAlso + "Making simplicial modules" + "Making maps between simplicial modules" + image + (coimage, SimplicialModuleMap) + (kernel, SimplicialModuleMap) + (cokernel, SimplicialModuleMap) +/// + +doc /// + Key + (coimage, SimplicialModuleMap) + Headline + make the coimage of a map of simplicial modules + Usage + coimage f + Inputs + f : SimplicialModuleMap + Outputs + : SimplicialModule + Description + Text + The coimage of a simplicial module map $f : C \to D$ + is the simplicial module $E$ whose $i-th$ term is $coimage(f_i)$, + and whose face/degeneracy map is induced from the face/degeneracy map + on the source. + Text + In the following example, we first construct a random + simplicial morphism $f : C \to D$. + Example + S = ZZ/101[a,b,c,d]; + C = simplicialModule(freeResolution ideal(b^2-a*c, b*c-a*d, c^2-b*d), 3, Degeneracy => true) + D = simplicialModule(freeResolution ideal(a,b,c), Degeneracy => true) + f = randomSimplicialMap(D, C, Cycle => true, InternalDegree => 0) + g1 = inducedMap(coimage f, source f) + coimage g1 == coimage f + coker g1 == 0 + Caveat + The coimage is more computationally intensive than @TO (image, SimplicialModuleMap)@ + because, unlike {\tt image}, it computes kernels of maps of modules. + SeeAlso + "Making simplicial modules" + "Making maps between simplicial modules" + coimage + (image, SimplicialModuleMap) + (kernel, SimplicialModuleMap) + (cokernel, SimplicialModuleMap) +/// + +doc /// + Key + (kernel, SimplicialModuleMap) + Headline + make the kernel of a map of simplicial modules + Usage + kernel f + ker f + Inputs + f : SimplicialModuleMap + Outputs + : SimplicialModule + Description + Text + The kernel of a simplicial module map $f : C \to D$ + is the simplicial module $E$ whose $i-th$ term is $kernel(f_i)$, + and whose face/degeneracy map is induced from the face/degeneracy map + on the source. + Text + In the following example, we first construct a random + simplicial morphism $f : C \to D$. + Example + S = ZZ/101[a,b,c,d]; + C = simplicialModule(freeResolution ideal(b^2-a*c, b*c-a*d, c^2-b*d), 3, Degeneracy => true) + D = simplicialModule(freeResolution ideal(a,b,c), Degeneracy => true) + f = randomSimplicialMap(D, C, Boundary => true, InternalDegree => 0) + prune ker f + h1 = inducedMap(source f, ker f) + ker f == image h1 + ker h1 == 0 + SeeAlso + "Making simplicial modules" + "Making maps between simplicial modules" + ker + (image, SimplicialModuleMap) + (coimage, SimplicialModuleMap) + (cokernel, SimplicialModuleMap) +/// + +doc /// + Key + (cokernel, SimplicialModuleMap) + Headline + make the cokernel of a map of simplicial modules + Usage + cokernel f + coker f + Inputs + f : SimplicialModuleMap + Outputs + : SimplicialModule + Description + Text + If $f : C \to D$ is a map of simplicial modules of degree $d$, + then the cokernel is the simplicial module $E$ whose $i-th$ is $cokernel(f_{i-d})$, + and whose face/degeneracy map is induced from the face/degeneracy map + on the target. + Text + In the following example, we first construct a random + simplicial morphism $f : C \to D$. + Example + S = ZZ/101[a,b,c,d]; + C = simplicialModule(freeResolution ideal(b^2-a*c, b*c-a*d, c^2-b*d), 3, Degeneracy => true) + D = simplicialModule(freeResolution ideal(a,b,c), Degeneracy => true) + f = randomSimplicialMap(D, C, Cycle => true, InternalDegree => 0) + prune coker f + prune normalize oo + prune HH coker f + g1 = inducedMap(coker f, target f) + coker f == image g1 + coker g1 == 0 + SeeAlso + "Making simplicial modules" + "Making maps between simplicial modules" + cokernel + (image, SimplicialModuleMap) + (coimage, SimplicialModuleMap) + (kernel, SimplicialModuleMap) +/// + + +doc /// + Key + (symbol^, SimplicialModuleMap, Array) + (symbol_, SimplicialModuleMap, Array) + Headline + the composition with the canonical inclusion or projection map + Usage + i = f_[name] + p = f^[name] + Inputs + f:SimplicialModuleMap + name: + Outputs + :SimplicialModuleMap + {\tt i} is the composition of {\tt f} with the canonical inclusion and {\tt p} is + the composition of the canonical projection with {\tt f} + Description + Text + The direct sum is an n-ary operator with projection and + inclusion maps from each component satisfying appropriate + identities. + + One can access these maps as follows. First, we define + some non-trivial maps of simplicial modules. + Example + R = ZZ/101[a..d]; + C1 = simplicialModule((freeResolution coker matrix{{a,b,c}})[1], 3, Degeneracy => true) + C2 = simplicialModule(freeResolution coker matrix{{a*b,a*c,b*c}}, 3, Degeneracy => true) + D1 = simplicialModule((freeResolution coker matrix{{a,b,c}}), Degeneracy => true) + D2 = simplicialModule(freeResolution coker matrix{{a^2, b^2, c^2}}[-1], 3, Degeneracy => true) + f = randomSimplicialMap(D1, C1, Cycle => true) + g = randomSimplicialMap(D2, C2, Cycle => true) + Example + h = f ++ g; + Text + The four basic maps are the inclusion from each summand of the source + and the projection to each summand of the target. + Example + h_[0] == h * (C1 ++ C2)_[0] + h_[1] == h * (C1 ++ C2)_[1] + h^[0] == (D1 ++ D2)^[0] * h + h^[1] == (D1 ++ D2)^[1] * h + Text + These can be combined to obtain the blocks of the map of simplicial modules. + Example + h_[0]^[0] == f + h_[1]^[1] == g + h_[0]^[1] == 0 + h_[1]^[0] == 0 + Text + The default names for the components are the non-negative + integers. However, one can choose any name. + Example + h = (chicken => f) ++ (nuggets => g); + indices h + h_[chicken]^[chicken] == f + h_[nuggets]^[nuggets] == g + SeeAlso + (symbol++, SimplicialModule, SimplicialModule) + (symbol^, SimplicialModule, Array) + (symbol_, SimplicialModule, Array) + (directSum, SimplicialModule) + (components, SimplicialModule) + indices +/// + +doc /// + Key + (randomSimplicialMap, SimplicialModule, SimplicialModule) + randomSimplicialMap + [randomSimplicialMap, Boundary] + [randomSimplicialMap, Cycle] + [randomSimplicialMap, Degree] + [randomSimplicialMap, InternalDegree] + Cycle + Boundary + InternalDegree + Headline + a random map of simplicial modules + Usage + f = randomSimplicialMap(C,D) + Inputs + C:SimplicialModule + D:SimplicialModule + Boundary => Boolean + whether the constructed {\tt f} is a simplicial null homotopy + Cycle => Boolean + whether the constructed {\tt f} commutes with the face/degeneracy maps + Degree => ZZ + the degree of the constructed map of simplicial modules + InternalDegree => List + or @ofClass ZZ@ + Outputs + f:SimplicialModuleMap + Description + Text + A random simplicial module map $f : C \to D$ is obtained from choosing a random + map of the underlying normalizations, which uses the @TO randomComplexMap@ command. + Example + S = ZZ/101[a..c] + C = simplicialModule(freeResolution coker matrix{{a*b, a*c, b*c}}, 3, Degeneracy => true) + D = simplicialModule(freeResolution coker vars S, Degeneracy => true) + f = randomSimplicialMap(D,C) + assert isWellDefined f + assert not isCommutative f + Text + When the random element is chosen with option {\tt Cycle => true}, the associated map of simplicial modules commutes + with the face/degeneracy map. + Example + g = randomSimplicialMap(D,C, Cycle => true) + assert isWellDefined g + assert isCommutative g + assert isSimplicialMorphism g + Text + When the random element is chosen with option {\tt Boundary => true}, the associated map of simplicial modules is a + simplicial null homotopy. + Example + h = randomSimplicialMap(D,C, Boundary => true) + assert isWellDefined h + assert isCommutative h + assert isSimplicialMorphism h + assert isNullHomotopic normalize h + nullHomotopy normalize h + Text + When the degree of the random element is chosen with specific degree, + the associated map of simplicial modules will be a well-defined degree 0 simplicial + morphism mapping to the Dold-Kan image of the shift of the normalization. Thus, + even when specifying nonzero degree this constructor will still yield a simplicial + morphism. + Example + p = randomSimplicialMap(D, C, Cycle => true, Degree => -1) + assert isWellDefined p + assert isCommutative p + assert isSimplicialMorphism p + Text + Given an internal degree, the random element is constructed as maps of modules with this degree. + Example + q = randomSimplicialMap(D, C, Boundary => true, InternalDegree => 2); + assert isCommutative q + assert isSimplicialMorphism q + source q === C + target q === D + assert isNullHomotopic normalize q +/// + + +doc /// + Key + (isShortExactSequence, SimplicialModuleMap, SimplicialModuleMap) + Headline + whether a pair of simplicial module maps forms a short exact sequence + Usage + isShortExactSequence(g, f) + Inputs + f:SimplicialModuleMap + g:SimplicialModuleMap + Outputs + :Boolean + that is @TO true@ if these form a short exact sequence + Description + Text + A short exact sequence of simplicial modules + \[ 0 \to B \xrightarrow{f} C \xrightarrow{g} D \to 0\] + consists of two morphisms of simplicial modules + $f \colon B \to C$ and $g \colon C \to D$ such that + $g f = 0$, $\operatorname{image} f = \operatorname{ker} g$, + $\operatorname{ker} f = 0$, and $\operatorname{coker} g = 0$. + Text + From a simplicial morphism $h \colon B \to C$, one obtains a + short exact sequence + \[ 0 \to \operatorname{image} h \to C \to \operatorname{coker} h \to 0. \] + Example + R = ZZ/101[a,b,c]; + B = simplicialModule(freeResolution coker matrix{{a^2*b, a*b*c, c^3}}, Degeneracy => true) + C = simplicialModule(freeResolution coker vars R, 2, Degeneracy => true) + h = randomSimplicialMap(C, B, Cycle => true) + f = inducedMap(C, image h) + g = inducedMap(coker h, C) + assert isShortExactSequence(g,f) + Text + A short exact sequence of modules gives rise to a short + exact sequence of simplicial modules. These simplicial modules arise + as free resolutions of the modules. + Example + I = ideal(a^3, b^3, c^3) + J = I + ideal(a*b*c) + K = I : ideal(a*b*c) + SES = complex{ + map(comodule J, comodule I, 1), + map(comodule I, (comodule K) ** R^{-3}, {{a*b*c}}) + } + assert isWellDefined SES + assert isShortExactSequence(dd^SES_1, dd^SES_2) + (g,f) = (horseshoeResolution SES)/simplicialModule; + assert isShortExactSequence(g,f) + SeeAlso + "Basic invariants and properties" +/// + +doc /// + Key + (symbol SPACE, SimplicialModule, Array) + (symbol SPACE, SimplicialModuleMap, Array) + Headline + shift a simplicial module or simplicial module map + Usage + D = C[i] + g = f[i] + Inputs + C:SimplicialModule + or {\tt f}, a @TO SimplicialModuleMap@ + :Array + {\tt [i]}, where {\tt i} is an integer + Outputs + D:SimplicialModule + or {\tt g}, a @TO SimplicialModuleMap@. + Description + Text + The shifted simplicial module $D$ is not as simple to define as the + shift in the category of chain complexes. This method naively normalizes the + given simplicial module/map, applies the shift in the category of chain complexes, + then applied the Dold-Kan functor to the result. + + As the following example shows, this is not the same thing as simply shifting + all terms of the simplicial module. + Example + S = ZZ/101[a..d] + D = simplicialModule(S^1, 5) + D[-1] + oo.dd + D[-2] + C = simplicialModule(freeResolution coker vars S, Degeneracy => true) + dd^C_(3,0) + ss^C_(2,0) + D = C[1] + assert isWellDefined D + dd^D_(2,0) + ss^D_(1,0) + Text + Notice that the face maps of the shifted simplicial module are not simply the negation + of the face maps of the original. The shift operator is functorial, as illustrated below. + Example + C2 = simplicialModule(freeResolution (S^1/(a^2, b^2, c^2, d^2)), Degeneracy => true) + C3 = simplicialModule(freeResolution (S^1/(a^2, b^3, c^4, d^5)), Degeneracy => true) + f2 = simplicialModule(extend(C.complex, C2.complex, map(C_0, C2_0, 1))); + f3 = simplicialModule(extend(C2.complex, C3.complex, map(C2_0, C3_0, 1))); + isWellDefined (f2[-1]) + isSimplicialMorphism (f2[-1]) + isSimplicialMorphism (f3[-2]) + SeeAlso + "Making simplicial modules" +/// + +doc /// + Key + (directSum, SimplicialModule) + (symbol++, SimplicialModule, SimplicialModule) + Headline + direct sum of simplicial modules + Usage + D = C1 ++ C2 + D = directSum(C1,C2,...) + D = directSum(name1 => C1, name2 => C2, ...) + Inputs + Ci:SimplicialModule + Outputs + D:SimplicialModule + the direct sum of the input simplicial modules + Description + Text + The direct sum of two simplicial modules is another simplicial module. + Example + S = ZZ/101[a,b,c]; + C1 = simplicialModule(freeResolution coker vars S, Degeneracy => true) + D1 = C1 ++ simplicialModule(complex(S^13)[-2], 3, Degeneracy => true) + isWellDefined D1 + D1.?ss --knows to cache degeneracy maps if inputs have degeneracy maps + C2 = simplicialModule(ideal(a,b,c), 3, Degeneracy => true) + C1 ++ C2 + assert isWellDefined(C1 ++ C2) + Text + The direct sum of a sequence of simplicialModule can be computed as follows. + Example + C3 = directSum(C1,C2,C2[-2]) + assert isWellDefined C3 + Text + The direct sum is an n-ary operator with projection and + inclusion maps from each component satisfying appropriate + identities. + Example + C4 = directSum(first => C1, second => C2) + C4_[first] -- inclusion map C1 --> C4 + C4^[first] -- projection map C4 --> C1 + C4^[first] * C4_[first] == 1 + C4^[second] * C4_[second] == 1 + C4^[first] * C4_[second] == 0 + C4^[second] * C4_[first] == 0 + C4_[first] * C4^[first] + C4_[second] * C4^[second] == 1 + Text + There are two short exact sequences associated to a direct sum. + Example + isShortExactSequence(C4^[first], C4_[second]) + isShortExactSequence(C4^[second], C4_[first]) + Text + Given a simplicial module which is a direct sum, we obtain the component + simplicial complexes and their names (indices) as follows. + Example + components C3 + indices C3 + components C4 + indices C4 + SeeAlso + (components,SimplicialModule) + indices + (symbol^, SimplicialModule, Array) + (symbol_, SimplicialModule, Array) + (isShortExactSequence, SimplicialModuleMap, SimplicialModuleMap) +/// + + + +doc /// + Key + (isSimplicialModule, SimplicialModule) + isSimplicialModule + Headline + check if the simplicial identities hold for a simplicial object with degeneracy map keys + Usage + isSimplicialModule(S) + Inputs + S:SimplicialModule + A simplicial module with face maps `dd` and degeneracy maps `ss`. + Outputs + :Boolean + true if the simplicial identities hold, false otherwise + Description + Text + This function checks if the simplicial identities hold for a given simplicial object `S` with face maps `dd` and degeneracy maps `ss`. The simplicial identities are a set of equations that need to be satisfied by the face and degeneracy maps of the simplicial object. + Text + Specifically, the function verifies the following identities: + 1. For face maps: + \[ d_j d_i = d_i d_{j-1} \text{ for } 0 \leq i < j \leq n \] + 2. For face and degeneracy maps: + \[ d_i s_j = s_{j-1} d_i \text{ for } i < j \] + \[ d_j s_j = \text{id} \] + \[ d_{j+1} s_j = \text{id} \] + \[ d_k s_j = s_j d_{k-1} \text{ for } k > j+1 \] + 3. For degeneracy maps: + \[ s_j s_i = s_i s_{j+1} \text{ for } i \leq j \] + Text + If any of these identities fail, the function returns `false`. If all identities are satisfied, the function returns `true`. + Example + R = QQ[a..d]; + f0 = matrix {{-b^2+a*c, b*c-a*d, -c^2+b*d}} + f1 = map(source f0,, {{d, c}, {c, b}, {b, a}}) + C = simplicialModule(complex {f0, f1}, 3, Degeneracy => true) + isSimplicialModule C + dd^C + ss^C + dd^C*ss^C --if C is simplicial, this should be all identity maps + Text + The zero simplicial module is well-defined. + Example + C = simplicialModule(R^0, 6, Degeneracy => true) + isSimplicialModule C + SeeAlso + isWellDefined +/// + + +doc /// + Key + (forgetComplex, SimplicialModule) + forgetComplex + RememberSummands + Headline + forget the underlying complex data of a simplicial module obtained as a Dold-Kan image + Usage + forgetComplex(S) + Inputs + S:SimplicialModule + A simplicial module, which is assumed to be obtained as a Dold-Kan image. + RememberSummands => Boolean + Default value is true. Indicates whether to remember the component summands of the simplicial module when creating the new simplicial module. + Outputs + :SimplicialModule + A new simplicial module that has no longer is no longer viewed as a Dold-Kan image of some complex + Description + Text + This function removes the data of the underlying complex from a simplicial module $S$ that is obtained as a Dold-Kan image. + The function checks if the simplicial module has an associated complex and, if so, it reconstructs the simplicial module without the complex data + while preserving the face and degeneracy maps. + Text + If the option `RememberSummands` is set to true (the default), the function will remember the summands + of the simplicial module when reconstructing it. The face and degeneracy maps of the original simplicial module + are preserved in the new simplicial module. + This function is good for testing that the normalization of the Dold-Kan functor recovers the original complex, + since the @TO normalize@ command by default first checks if a simplicial module is obtained as a Dold-Kan image + before attempting a more costly computation. + Example + R = ZZ/101[x_1..x_3]; + K = koszulComplex vars R + S = simplicialModule(K,4, Degeneracy => true) + S.?complex + fS = forgetComplex S + components fS_3 + ffS = forgetComplex(S, RememberSummands => false) + components ffS_3 + Kn = normalize fS + Knn = normalize ffS + Kn.dd + K == prune Kn + SeeAlso + normalize + forgetDegeneracy +/// + + + +doc /// + Key + (forgetDegeneracy, SimplicialModule) + forgetDegeneracy + Headline + forget the data of degeneracy maps of a simplicial object + Usage + forgetDegeneracy(S) + Inputs + S:SimplicialModule + A simplicial module whose degeneracy maps are to be forgotten. + Outputs + :SimplicialModule + The simplicial module S, but with no degeneracy maps stored. + Description + Text + This function removes the data of degeneracy maps from a simplicial module `S`. + It is useful when the user wants to ignore degeneracy maps for the purpose of speeding up computations or simplifying the simplicial object. + Example + Q = ZZ/101[a..d] + K = koszulComplex vars Q + S = simplicialModule(K, 6, Degeneracy => true) + elapsedTime S**S + fS = forgetDegeneracy S + elapsedTime fS**fS --faster when degeneracy is ignored + Text + The change in speed becomes much more noticeable as ranks get larger. + SeeAlso + forgetComplex +/// + + + + +doc /// + Key + tensorwithComponents + (tensorwithComponents, Module, Module) + (tensorwithComponents, Matrix, Matrix) + (tensorwithComponents, List) + Headline + compute the tensor product of direct summands, caching the components for easy access + Usage + tensorwithComponents(M, N) + Inputs + M:Module + N:Module + Two modules whose tensor product of direct summands is to be computed. + Outputs + :Module + The tensor product of M and N, with cached components for easier access + Description + Text + This function computes the tensor product of two modules M and N, but additionally caches the components based on the component indices of the original modules. + This caching is particularly useful for easily accessing induced maps on components of tensor products of direct sums. + Text + If M and N have cached index components, then this function will use those indices. This function + is mostly used to extracting components of the simplicial tensor product, since the full + face/degeneracy maps are typically much too large to be displayed on their own. + Example + Q = ZZ/101[a..b] + M = Q^2++Q^3 + N = Q^3++Q^4 + components(M**N) --all components of M and N have been forgotten + T = tensorwithComponents(M,N) + components T + indices T + Text + This method also works for lists of modules, for purposes of iterating: + Example + tensorwithComponents {M,M,M} + indices oo + Text + This method is also functorial, which makes it easy to restrict maps + to tensor summands: + Example + L = directSum {Q^2, Q^3, Q^4} + f = L_[0,2] + phi = tensorwithComponents(f, f) + phi^[{0,2}]_[{0,1}] +/// + + + +doc /// + Key + (naiveNorm, SimplicialModule, ZZ) + (naiveNorm, SimplicialModule) + (naiveNorm, Complex, ZZ) + naiveNorm + Headline + compute the naive normalization of a simplicial object + Usage + naiveNorm(S, n) + Inputs + S:SimplicialModule + A simplicial module or @TO Complex@ + n:ZZ + and an integer n specifying the top degree for normalization. + Outputs + :Complex + The naive normalization complex of S, where the differential is the alternating sum of face maps. + Description + Text + This function computes the naive normalization of a simplicial object S. The naive normalization is a complex built from the modules of the simplicial object, + with a differential that is the alternating sum of the face maps. In general the naive normalization + is homotopy equivalent to the normalization (see @TO normalize@), but is much bigger in general. + Example + Q = ZZ/101[a..d] + K = koszulComplex vars Q + S = simplicialModule(K, Degeneracy => true) + nK = naiveNorm(S) + isWellDefined nK + prune HH nK + Text + Note that in the above, the naive normalization will always be an infinite complex, + so there will always be extraneous homology at the tail end. Note in this case that + the homology of the naive normalization is precisely the homology of {\tt K}, as it should + be (in fact, it is homotopy equivalent to {\tt K}). + SeeAlso + normalize +/// + + + +doc /// + Key + schurMap + (schurMap, List, SimplicialModule) + (schurMap, List, SimplicialModuleMap) + (schurMap, List, Complex) + (schurMap, List, ComplexMap) + TopDegree + Headline + construct the Dold-Puppe extension of the Schur functor + Usage + schurMap(lambda, S, Options => {Degeneracy => false, TopDegree => null}) + Inputs + lambda: List + A list representing a partition. + S: SimplicialModule + or @TO SimplicialModuleMap@, or @TO Complex@, or @TO ComplexMap@ to apply the Schur functor extension. + Degeneracy => Boolean + Default value is false. Indicates whether to include degeneracy maps in the construction. + TopDegree => ZZ + Default is null. If provided, specifies the top degree for the construction of the simplicial module. + Outputs + : SimplicialModule + The Dold-Puppe extension of the Schur functor applied to the simplicial module S. + Description + Text + This function constructs the Dold-Puppe extension of the Schur functor to the category of simplicial modules, + applied to a simplicial module S or a complex (or maps thereof). The construction involves + creating a simplicial module where each component is a Schur functor applied to the corresponding component of S. + Text + By default, degeneracy maps are not computed in this method since it adds additional computation time + that is not necessary for computing the normalization or many of invariants of interest. However, + if the user is interested in having degeneracy maps, use the option {\tt Degeneracy => true}. + Example + Q = ZZ/101[a..b] + K = koszulComplex vars Q; + S = simplicialModule(K, 4, Degeneracy => true) + S2S = elapsedTime schurMap({2}, S) + elapsedTime schurMap({2}, S, Degeneracy => true) + Text + In general, if a polynomial functor has degree $d$, the Dold-Puppe extension of a functor + applied to a chain complex of length $t$ will have length at most $d \cdot t$. We can see this + explicitly in the following example: + Example + S = simplicialModule(K, 5) + S2 = schurMap({2}, S) + prune normalize S2 --notice the output has length 4 + minimize oo + Text + If the input is a complex, then the default top degree is taken to be the degree of the + Schur functor multiplied by the length of the complex. Computationally, this upper bound + is often too big to be computed at the moment, so the user may need to specify a top degree + by using the {\tt TopDegree => d} option. + Example + Q = ZZ/101[a..c] + K = koszulComplex vars Q; + S2K = elapsedTime prune schurMap({2}, K, TopDegree => 4) + (minimize S2K).dd --ignore the last differential + --S21K = elapsedTime prune schurMap({2,1}, K, TopDegree => 3) --top degree 4 takes ~1 minute + Text + These functors are particularly interesting in the modular setting, ie, when the characteristic + of the underlying field is small relative to the degree of the Schur functor. In this case, + the induced complexes will have different homotopy classes as the characteristic varies. + Example + needsPackage "ChainComplexOperations" + Q = ZZ/2[a,b] + K = koszulComplex vars Q; + S2K = minimize prune schurMap({2}, K) + S2K' = sym2(chainComplex K) --the "naive" sym2 functor + S2K.dd + S2K'.dd + prune HH S2K + prune HH S2K' --not quasi-isomorphic! + Q = ZZ/3[a,b]; + K = koszulComplex vars Q; + prune HH schurMap({2}, K) + prune HH complex sym2(chainComplex K) --quasi-isomorphic in all other characterisics + --S3K = elapsedTime minimize prune schurMap({3}, K) --takes 23 seconds + --S21K = elapsedTime minimize prune schurMap({2,1}, K) --takes 17 seconds + --S21K.dd + --prune HH S21K + Text + This method is also implemented in a functorial way. + Example + Q = ZZ/2[a,b] + K = koszulComplex vars Q; + F = freeResolution( (ideal vars Q)^2) + phi = extend(K, F, id_(K_0)) + f = elapsedTime prune schurMap({2}, phi) + isCommutative f + isWellDefined f + prune HH source f + prune HH target f + prune HH f + Caveat + As many of the above examples show, this method can quickly become + computationally infeasible when the modules in the complex have too big of rank. + This seems to stem more from the efficiency of the @TO schur@ method, since methods such + as the tensor product still run very quickly even with huge matrices. + SeeAlso + extPower + simplicialTensor + symmetricQuotient +/// + + + +doc /// + Key + extPower + (extPower, ZZ, SimplicialModule) + (extPower, ZZ, SimplicialModuleMap) + (extPower, ZZ, Complex) + (extPower, ZZ, ComplexMap) + Headline + compute the Dold-Puppe extension of the exterior power functor to simplicial modules + Usage + extPower(d, S, Options => {Degeneracy => false, TopDegree => null}) + Inputs + d: ZZ + An integer representing the degree of the exterior power. + S: SimplicialModule + A simplicial module to which the exterior power functor extension is applied. + Degeneracy => Boolean + Default value is false. Indicates whether to include degeneracy maps in the construction. + TopDegree => ZZ + Default is null. If provided, specifies the top degree for the construction of the simplicial module. + Outputs + : SimplicialModule + The Dold-Puppe extension of the exterior power functor applied to the simplicial module S. + Description + Text + This function computes the Dold-Puppe extension of the exterior power functor to the category of chain complexes. + It can be applied to a simplicial module, a complex, or maps thereof. This method is equivalent + to using @TO schurMap@ for the partition $(1, 1, \dots , 1)$, but is generally much faster. + Example + Q = ZZ/2[a,b] + K = koszulComplex vars Q + w3K = elapsedTime prune extPower(3, K) + --elapsedTime prune schurMap({1,1,1}, K) --takes much longer + (minimize w3K).dd + prune HH w3K + Text + This method is also implemented in a functorial way: + Example + F = freeResolution( (ideal vars Q)^2) + phi = extend(K, F, id_(K_0)) + f = elapsedTime prune extPower(2, phi) + prune HH f + Text + Since this method runs significantly faster than using {\tt schurMap}, we can compute the + full exterior power complex of a longer complex: + Example + Q = ZZ/2[a..c]; + K = koszulComplex vars Q + --w2K = elapsedTime prune extPower(2, K) + --(minimize w2K).dd + --prune HH w2K --has more interesting homology than in the nonmodular case + needsPackage "ChainComplexOperations" + Q = ZZ/3[a..c] + K = koszulComplex vars Q + prune HH wedge2(chainComplex K) --notice: homology concentrated in odd degrees + Caveat + This method may take a very long time to run if the user inputs a large/long complex. + Use the option {\tt TopDegree => d} to only run the computation up to a certain degree. + SeeAlso + schurMap + exteriorInclusion + symmetricQuotient + simplicialTensor +/// + + + +doc /// + Key + simplicialTensor + (simplicialTensor, List) + (simplicialTensor, Complex, Complex) + (simplicialTensor, ComplexMap, ComplexMap) + (simplicialTensor, ZZ, Complex) + (simplicialTensor, ZZ, SimplicialModule) + Headline + compute the simplicial tensor product and cache direct sum indices for easy access + Usage + simplicialTensor(T, Options => {Degeneracy => false, TopDegree => null}) + Inputs + T: List + A list of simplicial modules or complexes to compute the tensor product. + Degeneracy => Boolean + Default value is false. Indicates whether to include degeneracy maps in the construction. + TopDegree => ZZ + Default is null. If provided, specifies the top degree for the construction of the simplicial module. + Outputs + : SimplicialModule + The simplicial tensor product of the components in T, with cached direct sum indices. + Description + Text + This function computes the simplicial tensor product of a list T, which can consist of simplicial modules or complexes. + It caches direct sum indices using @TO tensorwithComponents@ so that the user can easily access + components of the resulting face/degeneracy maps on particular direct summands of the tensor product. + + The simplicial tensor product of complexes is built as the Dold-Kan extension of the tensor product + functor on the category of R-modules. In general, this complex looks quite different from the + standard tensor product of complexes. In fact, the simplicial tensor product is always homotopy + equivalent to the classically defined tensor product. + Example + Q = ZZ/101[x_1,x_2]; + K1 = complex {matrix{{x_1}}}; + K2 = complex {matrix{{x_2}}}; + T1 = K1**K2 + T1.dd + T2 = prune simplicialTensor({K1,K2}) + T2.dd + phi1 = extend(T1,T2,id_(T1_0)) + phi2 = extend(T2,T1,id_(T1_0)) + phi1*phi2 == id_T1 + isNullHomotopic(phi2*phi1 - id_T2) + Text + Here is how to access specific components of the face maps for a tensor product of simplicial + modules: + Example + S1 = simplicialModule(K1, 4) + S2 = simplicialModule(K2, 4) + S12 = S1**S2 + indices S12_4 --lists the indices of the summands + netList flatten for i in indices S12_4 list ( + for j in indices S12_3 list ( if (dd^S12_(4,0))_[i]^[j]==0 then continue else + horizontalJoin {net (dd^S12_(4,0))_[i]^[j], " : ", net i, " --> " , net j} )) + Text + One reason for using the simplicial tensor product + is that its components as a simplicial module are more canonically built, and thus naturally + extend functorial maps on the category of R-modules to the category of chain complexes. + + We can see actually see this in an example. The exterior power functor admits a canonical + comultiplication map + $$\bigwedge^{i+j} \to \bigwedge^i \otimes \bigwedge^j.$$ + This means that for any chain complex $C$ there is a canonical inclusion of complexes + $$\bigwedge^{i+j} C \hookrightarrow \bigwedge^i C \otimes \bigwedge^j C.$$ + Constructing this inclusion directly using the naive definition of the exterior power functor + on complexes would be extremely unnatural, but filtering through the simplicial category + makes this a very easy task: + Example + Q = ZZ/101[a,b]; + K = koszulComplex vars Q + SK = simplicialModule(K,6) --want top degree 6 since the resulting complexes should have length 6 + w21K = extPower(2, SK) ** SK + w3K = extPower(3, SK) + H = hashTable for i from 0 to 6 list i => dual wedgeProduct(2,1, dual SK_i); + inclusion = map(w21K, w3K, H); + isWellDefined inclusion + isCommutative inclusion + prune ker inclusion --should be 0 since it is an inclusion + S21' = chainComplex { matrix {{a, b, 0, 0, -b}, {0, 0, a, b, a}}, matrix {{-b, b, 0, 0, + b, 0}, {a, -a, 0, 0, 0, b}, {0, 0, -b, b, -a, 0}, {0, 0, a, -a, 0, -a}, {0, 0, 0, 0, a, b}}, + matrix {{a, b, 0, -b, -b}, {a, b, 0, 0, -2*b}, {0, a, b, a, 0}, {0, a, b, 0, a}, {0, 0, 0, + -b, b}, {0, 0, 0, a, -a}}, matrix {{3*b, 0}, {-a, 2*b}, {0, -3*a}, {a, b}, {a, b}}} + S21 = complex(S21')[-1] --this is the S^(2,1) schur functor; note the ranks + prune HH S21 --note the homology + Text + Just for sake of illustration, let us see how the above example changes in the modular + setting; note that the only characteristic for which the inclusion + $$\bigwedge^3 \hookrightarrow \bigwedge^2 \otimes \bigwedge^1$$ + is not canonically split is for characteristic 3, so we should expect the Dold-Kan + extension of the Schur functor $\mathbb{S}^{(2,1)} (K)$ to look different in characteristic 3. + (the resulting minimization of $\mathbb{S}^{(2,1)} (K)$ should not have coefficients, for instance). + Example + Q = ZZ/3[a,b]; + K = koszulComplex vars Q + SK = simplicialModule(K,6) --want top degree 6 since the resulting complexes should have length 6 + w21K = extPower(2, SK) ** SK + w3K = extPower(3, SK) + H = hashTable for i from 0 to 6 list i => dual wedgeProduct(2,1, dual SK_i); + inclusion = map(w21K, w3K, H); + --inc = prune normalize inclusion; + --next commands are commented out since they are longer computations + --S21K = prune coker inc --the char 3 simplicial schur functor + --(minimize S21K).dd --complex is longer! All other cases have ranks (2,5,6,5,2) + --prune HH S21K --more homology as well! + Text + Note that the above method of computing the Schur functor $\mathbb{S}^{(2,1)} (K)$ is + significantly faster than the {\tt schurMap} command. + + This method is also implemented functorially, so it can be applied to simplicial maps + and complex maps. + Example + F = freeResolution( (ideal vars Q)^2) + phi = extend(K, F, id_(K_0)) + prune simplicialTensor(phi, phi) + Caveat + The user should remember to prune the output upon normalizing a simplicial + tensor product. + SeeAlso + extPower + symmetricQuotient +/// + + + +doc /// + Key + normalize + (normalize, SimplicialModule, ZZ) + (normalize, SimplicialModule) + (normalize, SimplicialModuleMap, ZZ) + (normalize, SimplicialModuleMap) + CheckSum + CheckComplex + Headline + normalization functor from simplicial modules to nonnegatively-graded chain complexes + Usage + normalize(S, d, Options => {CheckSum => true, CheckComplex => true}) + Inputs + S: SimplicialModule + or @TO SimplicialModuleMap@, the object to be normalized. + d: ZZ + An integer specifying the degree up to which the normalization should be computed. + CheckSum => Boolean + Default value is true. If true and S has more than one component, computes the direct sum of normalized components. + CheckComplex => Boolean + Default value is true. If true and S contains a cached simplicial module or map, it outputs this cached value. + Outputs + : Complex + or @TO ComplexMap@, the normalized nonnegatively-graded chain complex resulting from the normalization process. + Description + Text + This function computes the normalization functor from the category of simplicial modules + to the category of nonnegatively-graded chain complexes. It is implemented in a functorial way, + applying both to simplicial modules and simplicial module maps. + + The normalization of a simplicial module $S$ is by definition equal to the complex $N (S)$ with: + $$N(S)_n := \bigcap_{i=1}^n \ker d^S_{(n,i)},$$ + with differential induced by the face map $d_{(n,0)}^S$. As currently implemented, the normalization + does not prune the output; the user should use {\tt prune} to obtain the best looking output. + + The {\tt normalize} command is implemented so that it first checks whether a simplicial module + has been obtained as the Dold-Kan image of some complex. If it has, then it returns that complex + without doing any additional computation. If the user prefers that the normalization is computed + by definition instead of accessing this cached value, use the option {\tt CheckComplex => false}. + Example + R = ZZ/101[x_1..x_3]; + K = koszulComplex vars R + S = simplicialModule(K,10, Degeneracy => true) + keys S + K == normalize S + Kn = normalize(S, CheckComplex => false) + Kn.dd + K == Kn + K == prune Kn + Text + For computational efficiency, this method also checks if the simplicial module has been constructed as a direct sum of simplicial + modules. If it has, then it returns the direct sum of the normalizations of each component. If the + user prefers that this shortcut is not taken, use {\tt CheckSum => false}. + Example + S10 = directSum toList(10: forgetComplex S) + elapsedTime prune normalize S10 + elapsedTime prune normalize(S10, CheckSum => false) --about 3-4 times slower; becomes significant for larger ranks + Text + The user may also specify the top homological degree to compute the normalization up to. Note that + this can help speed up computational time; if the user knows the normalization should have + a shorter length, then they should specify this upper bound in the syntax: + Example + elapsedTime prune normalize(S10, 3, CheckSum => false) --MUCH FASTER! + Text + Again, this method is functorial, and when combined with other methods in this package + can be a particularly power way of obtaining nontrivial morphisms of complexes. We use this + method to obtain the image of the inclusion + $$\bigwedge^3 K \to bigwedge^2 K \otimes K$$ + for a Koszul complex K. Constructing this map directly using the naive definitions of + tensor products/exterior powers of complexes is not possible in full generality. Taking + advantage of the Dold-Kan correspondence and simplicial methods allows us to obtain + this inclusion explicitly. + Example + Q = ZZ/3[a,b]; + K = koszulComplex vars Q + SK = simplicialModule(K,6) --want top degree 6 since the resulting complexes should have length 6 + w21K = extPower(2, SK) ** SK + w3K = extPower(3, SK) + H = hashTable for i from 0 to 6 list i => dual wedgeProduct(2,1, dual SK_i); + inclusion = map(w21K, w3K, H); + inc = prune normalize(inclusion,3); + isWellDefined inc + isCommutative inc + Text + Taking the cokernel of the above morphism yields a canonically + defined Schur functor $\mathbb{S}^{(2,1)} (K)$; constructing this complex + using the classical Schur complex definition will yield a complex that does not + have finite length homology (and hence isn't even homotopically equivalent). + Example + S21K = prune coker inc --this is only a snapshot; should go up to degree 6 + (minimize S21K).dd + prune HH S21K --free part is because we truncated + SeeAlso + (directSum, SimplicialModule) + naiveNorm + extPower + simplicialTensor +/// + + +doc /// + Key + exteriorInclusion + (exteriorInclusion, SimplicialModule) + (exteriorInclusion, Complex, ZZ) + (exteriorInclusion, Complex) + (exteriorInclusion, Module) + Headline + computes the image of the 2nd exterior power into the tensor product + Usage + exteriorInclusion(S) + Inputs + M:SimplicialModule + or @TO Complex@ or @TO Module@, optional integer argument specifies top degree + Outputs + :SimplicialModuleMap + or @TO Matrix@, the map representing the image of the 2nd exterior power of $S$ into the tensor product $S \otimes S$. + Description + Text + Given a simplicial module $S$ (or a complex), this function computes the map + $$\bigwedge^2 S \to S \otimes S,$$ + The cokernel of + this map is by definition the second symmetric power of $S$. This method + is main used in conjunction with the @TO tensorLES@ command to compute induced + maps on homology for canonical short exact sequences. + Example + Q = ZZ/101[a,b,c] + K = koszulComplex vars Q + --elapsedTime schurMap({2}, K) --takes some time + phi = elapsedTime exteriorInclusion(K,3); --specify top degree 3 + isWellDefined phi + isCommutative phi + prune coker phi + Text + All of the homology of the second symmetric/exterior powers are guaranteed to be concentrated + in degrees $0$ to $3$ in the above example, so it suffices to compute only $4$ terms to + understand all of the homology. + Example + for i to 3 list prune HH_i source phi + for i to 3 list prune HH_i (coker phi) + Text + Notice that since the tensor square splits outside of characteristic 2, the symmetric power + picks up the even degree homology and the exterior square picks up the odd homology. In + characteristic 2 this changes: + Example + Q = ZZ/2[a,b,c] + K = koszulComplex vars Q + phi = elapsedTime exteriorInclusion(K,3); --specify top degree 3 + isWellDefined phi + isCommutative phi + for i to 2 list prune HH_i source phi + for i to 2 list prune HH_i (coker phi) + SeeAlso + symmetricQuotient + extPower + simplicialTensor +/// + + + + +doc /// + Key + symmetricQuotient + (symmetricQuotient, SimplicialModule) + (symmetricQuotient, Complex, ZZ) + (symmetricQuotient, Complex) + (symmetricQuotient, Module) + Headline + computes the image of the surjection from the simplicial tensor product onto the second symmetric power of a simplicial module + Usage + symmetricQuotient(S) + Inputs + S: SimplicialModule + or @TO Complex@ or @TO Module@, optional integer argument specifies top degree + Outputs + : SimplicialModuleMap + The induced map representing the image of the surjection from the simplicial tensor product onto the second symmetric power of S. + Description + Text + This function computes the induced map on the cokernel of the map constructed by + the @TO exteriorInclusion@ method, which is explicitly giving the map + $$S \otimes S \to \operatorname{Sym}^2 (S).$$ + Let us see some examples: + Example + Q = ZZ/2[a,b]; + K = koszulComplex vars Q; + phi = prune symmetricQuotient(K,4) + isWellDefined phi + isCommutative phi + prune coker phi == 0 + prune HH phi + prune coker oo --the induced map on homology is NOT surjective, in contrast to the case when 2 is a unit + SeeAlso + tensorLES + exteriorInclusion + simplicialTensor +/// + + + + +doc /// + Key + tensorLES + (tensorLES, Complex, ZZ) + Headline + computes the long exact sequence of homology induced by the canonical short exact sequence of complexes + Usage + tensorLES(C, d) + Inputs + C: Complex + A complex. + d: ZZ + An integer specifying the top degree for constructing the simplicial module. + Outputs + : Complex + The long exact sequence of homology induced by the canonical short exact sequence \( 0 \to \wedge^2 C \to T^2 C \to Sym^2 C \to 0 \). + Description + Text + This function computes the long exact sequence of homology associated with the canonical short exact sequence of complexes: + \( 0 \to \bigwedge^2 C \to C \otimes C \to operatorname{Sym}^2 C \to 0 \). + Text + This function first computes the exterior inclusion map on the complex C up to degree d using the @TO exteriorInclusion@ function. + Then it constructs the induced map on the cokernel of this exterior inclusion map, which is the surjection to the second symmetric power of C. + Finally, it computes the long exact sequence of homology using the @TO longExactSequence@ function on the pruned maps of the induced maps. + + This long exact sequence is only interesting in characteristic 2, since the above sequence is split whenever 2 is a unit, + so there are no interesting connecting homomorphisms. Let's see some examples in characteristic 2 of the + connecting homomorphisms: + Example + Q = ZZ/2[a,b] + K = koszulComplex vars Q + prune tensorLES(K,4) + oo.dd_6 --nontrivial connecting homomorphism + F = freeResolution( (ideal vars Q)^3) + --prune tensorLES(F,4) --takes time to run, commented out + L = complex {K.dd_1, map(source K.dd_1,target K.dd_2 ,K.dd_2*K.dd_1), K.dd_2} + hL = elapsedTime prune tensorLES(L,4) + netList {hL.dd_3, hL.dd_6, hL.dd_9, hL.dd_12, hL.dd_15} --two nontrivial connecting homs + SeeAlso + exteriorInclusion + simplicialTensor + /// + diff --git a/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 b/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 new file mode 100644 index 0000000000..a8405c35b1 --- /dev/null +++ b/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 @@ -0,0 +1,1198 @@ +TEST /// +---basic test arising from ring documentation +S = ZZ/101[a,b,c,d]; + C = simplicialModule freeResolution coker vars S + ring C + assert(ring C === S) + ring id_C + assert(ring id_C === S) +/// + + +TEST /// +--test for topdeg from doc +S = ZZ/101[a..c]; + C = simplicialModule(freeResolution coker vars S, 8) + assert(topDegree C == 8) + C' = simplicialModule(freeResolution coker vars S, 6) + assert(topDegree C' == 6) + + S = ZZ/101[a..d] + C0 = simplicialModule( S^2, 6, Degeneracy => true) + f = dd^C0 + assert(source f == target f) + f == 0 + isWellDefined C0 + C0 == 0 + assert(topDegree C0 == 6) + C5 = simplicialModule(S^0, 8, Degeneracy => true) + assert(C5 == 0) + assert(dd^C5 == 0) + assert(ss^C5 == 0) + C5_0 +/// + + +TEST /// +R = QQ[a..d]; + I = ideal(a*d-b*c, b^2-a*c, c^2-b*d); + C = simplicialModule(freeResolution(R^1/I), 4, Degeneracy => true) + dd^C + C.dd + ss^C + C.ss + assert(dd^C === C.dd) + assert(source dd^C === C) + assert(target dd^C === C) + assert(degree dd^C === -1) + assert(source ss^C === C) + assert(target ss^C === C) + assert(degree ss^C === 1) + dd^C_(2,0) + assert(source dd^C_2 === C_2) + assert(target dd^C_2 === C_1) +/// + + +TEST /// +--direct sum testing +S = ZZ/101[a,b,c]; + C1 = simplicialModule(freeResolution coker vars S, 5, Degeneracy => true) + C2 = simplicialModule(complex (ideal(a,b,c)) , 5, Degeneracy => true) + D = C1 ++ C2 + assert isWellDefined D_[0] + assert isCommutative D_[0] + assert isWellDefined D_[1] + assert isCommutative D_[1] + assert(D^[0] * D_[0] == 1) + assert(D^[1] * D_[1] == 1) + assert(D^[0] * D_[1] == 0) + assert(D^[1] * D_[0] == 0) + assert(D_[0] * D^[0] + D_[1] * D^[1] == 1) +/// + +TEST /// +S = ZZ/101[a..d] + moduleHash = hashTable { 0 => S^1, + 1 => S^1++S^2, + 2 => S^1++S^2++S^2++S^1} + faceHash = hashTable {(1,0) => matrix {{1, a, b}}, + (1,1) => matrix {{1_S, 0, 0}}, + (2,0) => matrix {{1, a, b, 0, 0, 0}, + {0, 0, 0, 1, 0, -b}, + {0, 0, 0, 0, 1, a}}, + (2,1) => matrix {{1_S, 0, 0, 0, 0, 0}, + {0, 1, 0, 1, 0,0}, + {0, 0, 1, 0, 1, 0}}, + (2,2) => matrix {{1_S, 0, 0, 0, 0, 0}, + {0, 1, 0, 0, 0, 0}, + {0, 0, 1, 0, 0, 0}}} + degenHash = hashTable {(0,0) => matrix {{1_S}, {0}, {0}}, + (1,0) => matrix {{1_S, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + {0, 0, 0}}, + (1,1) => matrix {{1_S, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}}} + T = simplicialModule(moduleHash, faceHash, degenHash, 2) + assert(T.?module) + assert T.?dd + assert T.?ss + T' = simplicialModule(moduleHash, faceHash, 2) + H1 = hashTable {0 => S^1, 1 => S^1, 2 => S^1} + H2 = hashTable {(1,0) => map(S^1, S^1, 0), + (1,1) => map(S^1, S^1, 0), + (2,0) => map(S^1, S^1, 0), + (2,1) => map(S^1, S^1, 0), + (2,2) => map(S^1, S^1, 0)} + H3 = hashTable {(0,0) => map(S^1, S^1, 0), + (1,0) => map(S^1, S^1, 0), + (1,1) => map(S^1, S^1, 0)} + U = simplicialModule(H1,H2,H3,2) + assert U.?dd + assert U.?ss + assert not isWellDefined U +/// + +TEST /// +S = ZZ/101[a..d] + C0 = simplicialModule( S^2, 6, Degeneracy => true) + f = dd^C0 + source f, target f + f == 0 + assert isWellDefined C0 + C0 == 0 + assert(topDegree C0 ==6) + C2 = simplicialModule( S, 5, Degeneracy => true) + I = ideal(a^2-b, c^3) + C3 = simplicialModule( I, 7, Degeneracy => true) + C4 = simplicialModule( (S/I), 8, Degeneracy => true) + assert isSimplicial C2 + assert isSimplicial C3 + assert isSimplicial C4 + C5 = simplicialModule(S^0, 8, Degeneracy => true) + assert(C5 == 0) + assert (dd^C5 == 0) + assert(ss^C5 == 0) + C5_0 +/// + +TEST /// +S = ZZ/101[a..c] + C = simplicialModule(freeResolution coker vars S, 4, Degeneracy => true) + assert C.?complex + assert isWellDefined C.complex + assert(C_(1,0) == C.complex_0) + assert(C_(1,1) == C.complex_1) + assert(C_(2,1) == C.complex_1 ++ C.complex_1) + tC = C ** C + assert not tC.?complex + tC_2 +/// + + +TEST /// +S = ZZ/101[a..c] + C = simplicialModule(K = freeResolution coker vars S, 4) + D = image id_C; + assert(not(C === D)) + assert(C == D) + E = simplicialModule(complex for i from 1 to 3 list 0*dd^K_i, 4) + assert isWellDefined dd^E + assert not(C == E) + assert not(E == 0) + f = id_C + D = coker f + assert(D == 0) + C0 = simplicialModule( S^0, 5, Degeneracy => true) + C1 = simplicialModule(complex(S^0, Base => 2), 5, Degeneracy => true) + topDegree C0 == topDegree C1 + assert(C0 == C1) + assert(C0 == 0) + assert(C1 == 0) +/// + + +TEST /// +R = QQ[a..d]; + I = ideal(a*d-b*c, b^2-a*c, c^2-b*d); + C = simplicialModule(freeResolution(R^1/I), 4, Degeneracy => true) + isWellDefined C + dd^C + C.dd + ss^C + C.ss + assert(dd^C === C.dd) + assert(source dd^C === C) + assert(target dd^C === C) + assert(degree dd^C === -1) + assert(source ss^C === C) + assert(target ss^C === C) + assert(degree ss^C === 1) + dd^C_(2,0) + assert(source dd^C_2 === C_2) + assert(target dd^C_2 === C_1) +/// + + +TEST /// +S = ZZ/101[a,b,c]; + C1 = simplicialModule(freeResolution coker vars S, 5, Degeneracy => true) + C2 = simplicialModule(complex (ideal(a,b,c)) , 5, Degeneracy => true) + D = C1 ++ C2 + D_[0] + assert isCommutative D_[0] + D_[1] + assert(D^[0] * D_[0] == 1) + assert(D^[1] * D_[1] == 1) + assert(D^[0] * D_[1] == 0) + assert(D^[1] * D_[0] == 0) + assert(D_[0] * D^[0] + D_[1] * D^[1] == 1) + E = (chicken => C1) ++ (nuggets => C2) + E_[chicken] + E_[nuggets] + assert(E^[chicken] * E_[chicken] == 1) + assert(E^[nuggets] * E_[nuggets] == 1) + assert(E^[chicken] * E_[nuggets] == 0) + assert(E^[nuggets] * E_[chicken] == 0) + assert(E_[chicken] * E^[chicken] + E_[nuggets] * E^[nuggets] == 1) + F = directSum(C1, C2, simplicialModule(complex(S^2, Base => 1), 5, Degeneracy => true)) + prune (F^[0,1]) + assert isSimplicialMorphism oo + prune (F_[0,2]) + assert isSimplicialMorphism oo +/// + + +TEST /// +S = ZZ/101[a,b,c]; + C1 = simplicialModule freeResolution coker vars S + C2 = simplicialModule(complex (ideal(a,b,c)), 3) + D = C1 ++ C2 + L = components D + assert(L_0 === C1) + assert(L_1 === C2) + E = (peanut => C1) ++ (butter => C2) + components E +/// + + +TEST /// +S = ZZ/101[a..c] + Ca = simplicialModule(complex {matrix{{a}}}, 3) + Cb = simplicialModule(complex {matrix{{b}}}, 3) + Cc = simplicialModule(complex {matrix{{c}}}, 3) + Cab = Cb ** Ca + dd^Cab + (prune normalize Cab).dd + assert isWellDefined Cab + Cabc = Cc ** Cab + Cc ** Cb ** Ca + dd^(nC = prune normalize Cabc) + assert isWellDefined nC + Cabc ** (S^1/(a,b,c)); + assert isWellDefined oo + S^2 ** Cabc + assert isWellDefined oo +/// + +TEST /// +R = QQ[a,b,c]; + I = ideal(a*b, a*c, b*c) + C = simplicialModule(freeResolution I, 3, Degeneracy => true) + D = truncate(3,C) + assert isWellDefined D + assert(C == truncate(0, C)) + A = ZZ/101[x_0, x_1, y_0, y_1, y_2, Degrees => {2:{1,0}, 3:{0,1}}]; + I = intersect(ideal(x_0, x_1), ideal(y_0, y_1, y_2)) + C = simplicialModule(freeResolution I, 3, Degeneracy => true) + D1 = prune truncate({{1,1}}, C) + D2 = truncate({{1,0}}, C) + D3 = truncate({{0,1}}, C) + D4 = truncate({{1,0},{0,1}}, C); + D5 = truncate({{2,2}}, C); + assert all({D1,D2,D3,D4,D5}, isWellDefined) +/// + + +TEST /// +R = QQ[x,y,z] + S = QQ[s,t] + phi = map(S, R, {s, s+t, t}) + I = ideal(x^3, x^2*y, x*y^4, y*z^5) + C = simplicialModule(freeResolution I, 3, Degeneracy => true) + D = phi C + assert isWellDefined D + dd^D + R = ZZ/101[a..d] + S = ZZ/101[s,t] + phi = map(S, R, {s^4, s^3*t, s*t^3, t^4}, DegreeMap => i -> 4*i) + C = simplicialModule(freeResolution coker vars R, 4, Degeneracy => true) + D = phi C + assert isWellDefined D +/// + +TEST /// +R = QQ[x,y,z]; + S = QQ[s,t]; + phi = map(S, R, {s, s+t, t}) + I = ideal(x^3, x^2*y, x*y^4, y*z^5) + C = simplicialModule(freeResolution I, 3, Degeneracy => true) + D = phi ** C + assert isWellDefined D + assert isWellDefined dd^D + assert isWellDefined ss^D + A = R/(x^2+y^2+z^2); + C ** A + assert(map(A,R) ** C == C ** A) + use R + I = ideal(x*y, x*z, y*z); + J = I + ideal(x^2, y^2); + g = inducedMap(module J, module I) + assert isWellDefined g + C = simplicialModule(complex {g}, 3, Degeneracy => true) + D1 = phi C + assert isWellDefined D1 + D2 = phi ** C + assert isWellDefined D2 + prune D1 + prune D2 + R = ZZ/101[a..d]; + S = ZZ/101[s,t]; + f = map(S, R, {s^4, s^3*t, s*t^3, t^4}, DegreeMap => i -> 4*i) + C = simplicialModule(freeResolution coker vars R, 3, Degeneracy => true) + D = f ** C + D == f C + assert isWellDefined D +/// + + +TEST /// +S = ZZ/101[a,b,c,d,e]; + I = ideal(a,b) * ideal(c,d,e) + F = simplicialModule((dual freeResolution I)[-4], 2, Degeneracy => true) + C = HH F + D = prune C + g = D.cache.pruningMap + assert isWellDefined g + assert isSimplicialMorphism g + assert (target g == C) + assert (source g == D) + g^-1 + assert(g*g^-1 == 1 and g^-1*g == 1) + S = ZZ/101[a,b,c]; + I = ideal(a^2,b^2,c^2); + J = I + ideal(a*b*c); + FI = simplicialModule(freeResolution I, Degeneracy => true) + FJ = simplicialModule(freeResolution J, Degeneracy => true) + f = randomSimplicialMap(FJ, FI ** S^{-1}, Cycle => true) + C = image f + D = prune C + g = D.cache.pruningMap + assert isWellDefined g + assert isSimplicialMorphism g + assert (target g == C) + assert (source g == D) + g^-1 + assert(g*g^-1 == 1 and g^-1*g == 1) + h = prune f + assert(source h === prune source f) + assert(target h === prune target f) +/// + + +TEST /// +R = ZZ/101[a,b,c]; + C = simplicialModule(F = freeResolution coker matrix{{a^2-b^2,b^3-c^3,c^4}}, Degeneracy => true) + D = simplicialModule(G = freeResolution coker vars R, Degeneracy => true) + H = hashTable { 0 => map(D_0, C_0, 1), + 1 => map(D_1, C_1, {{1, 0, 0, 0}, {0, a, 0, 0}, {0, -b, b^2, 0}, {0, 0, -c^2, c^3}}), + 2 => map(D_2, C_2, {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, a, 0, 0, 0, 0,0, 0, 0, 0}, + {0, -b, b^2, 0, 0, 0, 0, 0, 0, 0}, + {0, 0,-c^2, c^3, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, a, 0, 0, 0, 0,0}, + {0, 0, 0, 0, -b, b^2, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,-c^2, c^3, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, -a*c^2, a*c^3, 0}, + {0, 0, 0, 0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3}}), + 3 => map(D_3, C_3, {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0}, + {0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0}, + {0, -b, b^2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0}, + {0, 0, -c^2, c^3, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, a, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, -b, b^2, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,-c^2, c^3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0,0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0,0, 0, 0, 0, 0, 0, -b, b^2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0}, + {0, 0, 0, 0, 0, 0, 0, 0, -c^2, c^3, 0, 0, 0, 0, 0, 0,0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0,0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-a*c^2, a*c^3, 0, 0, 0, 0, 0, 0, 0,0}, + {0, 0, 0, 0, 0, 0,0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0, 0, 0,0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -a*c^2,a*c^3, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, b*c^2, -b*c^3, b^2*c^3, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0, 0}, + {0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -a*c^2, a*c^3,0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2*c^3}}) + } + f = map(D, C, H) + assert isWellDefined f + assert isHomogeneous f + assert(degree f == 0) + assert isSimplicialMorphism f + h = map(C, C, hashTable {}) + assert(h == 0) +/// + + +TEST /// +R = QQ[a,b,c] + C = simplicialModule(freeResolution coker vars R, Degeneracy => true) + D = simplicialModule(freeResolution coker matrix{{a^2, b^2, c^2}}, Degeneracy => true) + f = map(D, C, 0) + assert isWellDefined f + assert isSimplicialMorphism f + g = map(C, C, 0, Degree => 13) + assert isWellDefined g + assert(degree g == 13) + assert not isSimplicialMorphism g + assert isCommutative g + assert isHomogeneous g + assert(source g == C) + assert(target g == C) + assert(map(C, C, 1) === id_C) +/// + + +TEST /// +R = ZZ/101[a,b,c]; + C = simplicialModule(freeResolution coker vars R, Degeneracy => true) + f = map(forgetComplex C, forgetComplex C, id_C) + assert isWellDefined f + assert(degree f == 0) + assert isCommutative f + assert isSimplicialMorphism f + normalize f --notice how the normalization is not already pruned + normalize id_C + prune normalize f == normalize id_C +/// + + +TEST /// +R = ZZ/101[x,y]/(x^3, y^3) + C = simplicialModule(freeResolution(coker vars R, LengthLimit=>6), 6, Degeneracy => true) + f = id_C; + assert isWellDefined f + assert isSimplicialMorphism f +/// + +TEST /// +R = ZZ/101[a,b,c]; + C = simplicialModule(F = freeResolution coker matrix{{a^2-b^2,b^3-c^3,c^4}}, Degeneracy => true) + D = simplicialModule(G = freeResolution coker vars R, Degeneracy => true) + H = hashTable { 0 => map(D_0, C_0, 1), + 1 => map(D_1, C_1, {{1, 0, 0, 0}, {0, a, 0, 0}, {0, -b, b^2, 0}, {0, 0, -c^2, c^3}}), + 2 => map(D_2, C_2, {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, a, 0, 0, 0, 0,0, 0, 0, 0}, + {0, -b, b^2, 0, 0, 0, 0, 0, 0, 0}, + {0, 0,-c^2, c^3, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, a, 0, 0, 0, 0,0}, + {0, 0, 0, 0, -b, b^2, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,-c^2, c^3, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, -a*c^2, a*c^3, 0}, + {0, 0, 0, 0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3}}), + 3 => map(D_3, C_3, {{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0}, + {0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0}, + {0, -b, b^2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0}, + {0, 0, -c^2, c^3, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, a, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, -b, b^2, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,-c^2, c^3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0,0, 0, 0, 0, 0, a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0,0, 0, 0, 0, 0, 0, -b, b^2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0}, + {0, 0, 0, 0, 0, 0, 0, 0, -c^2, c^3, 0, 0, 0, 0, 0, 0,0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0,0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-a*c^2, a*c^3, 0, 0, 0, 0, 0, 0, 0,0}, + {0, 0, 0, 0, 0, 0,0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0, 0, 0,0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -a*c^2,a*c^3, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, b*c^2, -b*c^3, b^2*c^3, 0, 0, 0, 0}, + {0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2, 0, 0, 0}, + {0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -a*c^2, a*c^3,0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b*c^2, -b*c^3, b^2*c^3, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, a*b^2*c^3}}) + } + f = map(D, C, H) + assert isWellDefined f + assert isHomogeneous f + assert(degree f == 0) + assert isSimplicialMorphism f + g = randomSimplicialMap(D,C); --outputs are large + normalize g + assert isWellDefined g + assert not isCommutative g + h = randomSimplicialMap(D,C, Cycle => true); + normalize h + assert isWellDefined h + assert isSimplicialMorphism h +/// + + +TEST /// +R = ZZ/101[a..d] + I = ideal(a^2, b^2, c^2) + J = I + ideal(a*b*c) + FI = simplicialModule(freeResolution I, Degeneracy => true) + FJ = simplicialModule(freeResolution J, Degeneracy => true) + f = randomSimplicialMap(FJ, FI, Cycle=>true) + source f + assert isWellDefined f + assert isSimplicialMorphism f + assert(source f == FI) + assert(target f == FJ) + kk = coker vars R + F = simplicialModule(freeResolution kk, Degeneracy => true) + assert(source dd^F == F) + assert(target dd^F == F) + assert(degree dd^F == -1) +/// + +TEST /// +R = ZZ/101[a..d]; + I = ideal(a^2, b^2, c^2) + FI = simplicialModule(freeResolution I, Degeneracy => true) + assert(degree dd^FI == -1) + assert(degree ss^FI == 1) +/// + + +TEST /// +S = ZZ/101[a,b,c,d]; + I = minors(2, matrix{{a,b,c},{b,c,d}}) + C = simplicialModule(freeResolution (S^1/I), Degeneracy => true) + assert isHomogeneous dd^C + f = randomSimplicialMap(C, C, Degree => -1) + assert isHomogeneous f + f = randomSimplicialMap(C, C, InternalDegree => 2) + phi = map(S, S, {1,b,c,d}) + D = phi C + dd^D + assert not isHomogeneous dd^D +/// + + +TEST /// +S = ZZ/101[a..c]; + C = simplicialModule(freeResolution coker matrix{{a^2, b^2, c^2}}, Degeneracy => true) + f = dd^C + f^2 + assert(source f == target f) + assert(degree f == -1) + assert(degree f^2 == -2) + g = randomSimplicialMap(C, C) + assert isWellDefined g^2 + assert isWellDefined g^3 + assert not(f^0 == id_(C[1])) + assert(g^0 == id_C) + h = randomSimplicialMap(C, C) + assert isWellDefined h^-1 + assert(h * h^-1 == id_C) + assert isWellDefined h^-4 + assert(h^-4 * h^4 == id_C) +/// + + +TEST /// +S = ZZ/101[a..c] + C = simplicialModule(freeResolution coker vars S, Degeneracy => true) + f = id_C + assert(f == 1) + assert(0 * id_C == 0) + g = randomSimplicialMap(C, C) + h = inducedMap(coker g, target g) + assert(h == 0) + g = randomSimplicialMap(C, C, InternalDegree=>1, Cycle=>true) + h = inducedMap(coker g, target g) + assert(h != 1) + D = prune image g + p = D.cache.pruningMap + p == 1 + assert(coker p == 0 and ker p == 0) + assert(prune p == 1) +/// + + +TEST /// +S = ZZ/101[a,b,c]; + C = simplicialModule(freeResolution coker vars S, Degeneracy => true) + D = C ** C + isWellDefined D + f1 = prune randomSimplicialMap(D, C, Cycle => true, InternalDegree => 1); + prune normalize f1 + isCommutative oo + isCommutative f1 + assert(degree f1 == 0) + f2 = randomSimplicialMap(D, C, Cycle => true); + isCommutative f2 + assert(degree f2 == 0) + assert isSimplicialMorphism f2 +/// + +TEST /// +S = ZZ/101[a,b,c]; + C = simplicialModule(freeResolution coker vars S, Degeneracy => true) + D = C ** C + f1 = randomSimplicialMap(D, C, Cycle => true, InternalDegree => 1); + assert isSimplicialMorphism f1 + assert(degree f1 == 0) +/// + +TEST /// +R = ZZ/101[a..d]; + I = ideal(c^2-b*d, b*c-a*d, b^2-a*c) + J = ideal(I_0, I_1) + C = simplicialModule(koszulComplex vars R, Degeneracy => true) + f = map(R^1/I, R^1/J, 1) + C ** f; + assert isSimplicialMorphism oo + f ** C; + assert isSimplicialMorphism oo + f' = random(R^2, R^{-1, -1, -1}) + C ** f'; + f' ** C; + assert isWellDefined(C ** f') + assert isWellDefined(f' ** C) + f'' = random(source f', R^{-2,-2}) + assert((C ** f') * (C ** f'') == C ** (f' * f'')) + assert(C ** id_(R^{-1,-2,-3}) == id_(C ** R^{-1,-2,-3})) +/// + +TEST /// +S = ZZ/101[a..c] + C = simplicialModule(freeResolution coker vars S, Degeneracy => true) + D = simplicialModule((freeResolution coker matrix{{a^2,a*b,b^3}})[-1], Degeneracy => true) + f = randomSimplicialMap(D,C) + E = simplicialModule((dual C.complex)[-3], Degeneracy => true) + F = simplicialModule((dual D.complex)[-3], 3, Degeneracy => true) + g = randomSimplicialMap(F,E) + h = f ** g; + assert isWellDefined h + assert(prune source h == C ** E) + assert(prune target h == D ** F) + fE = f ** E; + assert(fE == f ** id_E) + k = coker vars S + gk = g ** k; + D' = simplicialModule((freeResolution coker matrix{{a^2,a*b,c^3}})[-1], 3, Degeneracy => true) + f' = randomSimplicialMap(D', D) + assert((f' * f) ** g == (f' ** g) * (f ** id_E)) + assert((f' * f) ** g == (f' ** id_F) * (f ** g)) + F' = simplicialModule(dual (freeResolution coker matrix{{a^2,a*b,a*c,b^3}})[-3], Degeneracy => true) + g' = randomSimplicialMap(F', F) + assert(f ** (g' * g) == (f ** g') * (id_C ** g)) + assert(f ** (g' * g) == (id_D ** g') * (f ** g)) +/// + + +TEST /// +R = QQ[a,b,c]; + C = simplicialModule(freeResolution ideal(a*b, a*c, b*c), 3, Degeneracy => true) + D = simplicialModule((freeResolution ideal(a*b, a*c, b*c, a^2-b^2))[-1], 3, Degeneracy => true) + f = randomSimplicialMap(D,C, Cycle => true) + g = truncate(3,f); + assert isWellDefined g + assert (source g == truncate(3, source f)) + assert (target g == truncate(3, target f)) + assert(f == truncate(0, f)) + A = ZZ/101[x_0, x_1, y_0, y_1, y_2, Degrees => {2:{1,0}, 3:{0,1}}]; + I = intersect(ideal(x_0, x_1), ideal(y_0, y_1, y_2)) + C = simplicialModule(freeResolution I, 4, Degeneracy => true) + J = intersect(ideal(x_0^2, x_1^2), ideal(y_0^2, y_1^2, y_2^2)) + D = simplicialModule(freeResolution J, 4, Degeneracy => true) + f = simplicialModule(extend(C.complex, D.complex, id_(A^1)), 2) + g1 = prune truncate({{1,1}}, f); + g1_0 + g1_1 + g2 = truncate({{1,0}}, f); + g2_1 + g3 = truncate({{0,1}}, f); + g4 = truncate({{1,0},{0,1}}, f); + g4_1 + g5 = truncate({{2,2}}, f); + assert all({g1,g2,g3,g4,g5}, isWellDefined) +/// + +TEST /// +R = QQ[a,b,c,d]; + S = QQ[s,t]; + phi = map(S, R, {s, s+t, t, s-t}) + I = ideal(a*b, b*c, c*d) + J = I + ideal(a^2, b^2, c^2, d^2) + CI = simplicialModule(freeResolution I, 4, Degeneracy => true) + CJ = simplicialModule(freeResolution J, Degeneracy => true) + f = simplicialModule(extend(CJ.complex, CI.complex, map(CJ_0, CI_0, 1)), Degeneracy => true) + assert isWellDefined f + g = phi ** f + assert isWellDefined g + assert isWellDefined dd^(source g) + assert isWellDefined ss^(source g) + dd^(target g); + simplicialModule prune HH normalize g + assert isSimplicialMorphism oo +/// + +TEST /// +needsPackage "Truncations" + kk = ZZ/32003 + R = kk[a,b,c] + F = simplicialModule(freeResolution (ideal gens R)^2, 2, Degeneracy => true) + C1 = truncate(3, F); + prune normalize C1 + C2 = truncate(4, F); + prune normalize C2 + assert isWellDefined C1 + assert isWellDefined C2 + f = inducedMap(C1, C2); + prune normalize f + assert isWellDefined f + f1 = inducedMap(F, C1) + f2 = inducedMap(F, C2) + assert isWellDefined f1 + assert isWellDefined f2 + assert(f2 == f1 * f) +/// + + +TEST /// +R = ZZ/101[a..d]; + C = simplicialModule(freeResolution coker matrix{{a*b, a*c^2, b*c*d^3, a^3}}, Degeneracy => true) + D = simplicialModule(freeResolution coker matrix{{a*b, a*c^2, b*c*d^3, a^3, a*c*d}}, 3, Degeneracy => true) + f = randomSimplicialMap(D, C, Cycle => true); + prune normalize f + g = randomSimplicialMap(D, C, Boundary => true); + prune normalize g + f+g; + assert isSimplicialMorphism oo + f-g; + assert isSimplicialMorphism oo + -f; + 3*f; + 0*f + a*f; + assert(0*f == 0) + assert(1*f == f) + assert((-1)*f == -f) + assert(-(f-g) == g-f) + assert((a+b)*f == a*f + b*f) + assert(a*(f+g) == a*f + a*g) + assert isSimplicialMorphism (f+g) + h = randomSimplicialMap(C, C); + prune normalize h + prune normalize(h+1) + assert(h+1 == h + id_C) + assert(h+a == h + a*id_C) + assert(1-h == id_C - h) + assert(b-c*h == -c*h + b*id_C) + assert(b-h*c == -h*c + id_C*b) +/// + + +TEST /// +R = ZZ/101[a..d]; + C1 = simplicialModule((freeResolution coker matrix{{a,b,c}})[1], Degeneracy => true) + C2 = simplicialModule(freeResolution coker matrix{{a*b,a*c,b*c}}, Degeneracy => true) + D = simplicialModule(freeResolution coker matrix{{a^2,b^2,c*d}}, Degeneracy => true) + f = randomSimplicialMap(D, C1) + g = randomSimplicialMap(D, C2) + h = f|g + assert isWellDefined h + assert(source h === source f ++ source g) + assert(target h === target f) +/// + +TEST /// +R = ZZ/101[a..d]; + D1 = simplicialModule((freeResolution coker matrix{{a,b,c}})[1], Degeneracy => true) + D2 = simplicialModule(freeResolution coker matrix{{a*b,a*c,b*c}}, Degeneracy => true) + C = simplicialModule(freeResolution coker matrix{{a^2,b^2,c*d}}, Degeneracy => true) + f = randomSimplicialMap(D1, C) + g = randomSimplicialMap(D2, C) + h = f||g + assert isWellDefined h + assert(target h === target f ++ target g) + assert(source h === source f) +/// + +TEST /// +R = ZZ/101[a..d]; + C1 = simplicialModule((freeResolution coker matrix{{a,b,c}})[1], Degeneracy => true) + C2 = simplicialModule(freeResolution coker matrix{{a*b,a*c,b*c}}, Degeneracy => true) + D1 = simplicialModule((freeResolution coker matrix{{a,b,c}}),2, Degeneracy => true) + D2 = simplicialModule(freeResolution coker matrix{{a^2, b^2, c^2}}[-1], 2, Degeneracy => true) + f = randomSimplicialMap(D1, C1, Cycle => true) + g = randomSimplicialMap(D2, C2, Cycle => true) + h = f ++ g + assert isWellDefined h + assert isSimplicialMorphism h + directSum(f, g, f[2]) + h2 = directSum(peanut => f, butter => g, jelly => f[2]) + indices h2 + h2_[butter,jelly] + assert(source oo == C2 ++ C1[2]) + assert(h_[0]^[0] == f) + assert(h_[1]^[1] == g) + assert(h_[0]^[1] == 0) + assert(h_[1]^[0] == 0) + assert(h_[0] == h * (C1 ++ C2)_[0]) + assert(h_[1] == h * (C1 ++ C2)_[1]) + assert(h^[0] == (D1 ++ D2)^[0] * h) + assert(h^[1] == (D1 ++ D2)^[1] * h) +/// + +TEST /// +S = ZZ/101[a,b,c,d]; + C = simplicialModule(freeResolution ideal(b^2-a*c, b*c-a*d, c^2-b*d),3, Degeneracy => true) + D = simplicialModule(freeResolution ideal(a,b,c), Degeneracy => true) + f = randomSimplicialMap(D, C, Cycle => true, InternalDegree => 0) + assert isCommutative f + assert isWellDefined prune image f + prune normalize oo + i = inducedMap(forgetComplex target f, image f) + isSimplicialMorphism i + normalize i + g1 = inducedMap(target f, image f) + assert(ker g1 == 0) + assert(image g1 == image f) +/// + + +TEST /// +S = ZZ/101[a,b,c,d]; + C = simplicialModule(freeResolution ideal(b^2-a*c, b*c-a*d, c^2-b*d), 3, Degeneracy => true) + D = simplicialModule(freeResolution ideal(a,b,c), Degeneracy => true) + f = randomSimplicialMap(D, C, Cycle => true, InternalDegree => 0) + assert isCommutative f + g1 = inducedMap(coimage f, source f) + assert(coimage g1 == coimage f) + assert(coker g1 == 0) +/// + +TEST /// +S = ZZ/101[a,b,c,d]; + C = simplicialModule(freeResolution ideal(b^2-a*c, b*c-a*d, c^2-b*d), 3, Degeneracy => true) + D = simplicialModule(freeResolution ideal(a,b,c), Degeneracy => true) + f = randomSimplicialMap(D, C, Boundary => true, InternalDegree => 0) + assert isCommutative f + assert isWellDefined prune ker f + h1 = inducedMap(source f, ker f) + assert(ker f == image h1) + assert(ker h1 == 0) +/// + + +TEST /// +S = ZZ/101[a,b,c,d]; + C = simplicialModule(freeResolution ideal(b^2-a*c, b*c-a*d, c^2-b*d), 3, Degeneracy => true) + D = simplicialModule(freeResolution ideal(a,b,c), Degeneracy => true) + f = randomSimplicialMap(D, C, Cycle => true, InternalDegree => 0) + assert isCommutative f + assert isWellDefined prune coker f + prune normalize oo + prune HH coker f + g1 = inducedMap(coker f, target f) + assert(coker f == image g1) + assert(coker g1 == 0) +/// + + +TEST /// +R = ZZ/101[a..d]; + C1 = simplicialModule((freeResolution coker matrix{{a,b,c}})[1], 3, Degeneracy => true) + C2 = simplicialModule(freeResolution coker matrix{{a*b,a*c,b*c}}, 3, Degeneracy => true) + D1 = simplicialModule((freeResolution coker matrix{{a,b,c}}), Degeneracy => true) + D2 = simplicialModule(freeResolution coker matrix{{a^2, b^2, c^2}}[-1], 3, Degeneracy => true) + f = randomSimplicialMap(D1, C1, Cycle => true) + assert isCommutative f + g = randomSimplicialMap(D2, C2, Cycle => true) + assert isCommutative g + h = f ++ g; + assert(h_[0] == h * (C1 ++ C2)_[0]) + assert(h_[1] == h * (C1 ++ C2)_[1]) + assert(h^[0] == (D1 ++ D2)^[0] * h) + assert(h^[1] == (D1 ++ D2)^[1] * h) + assert(h_[0]^[0] == f) + assert(h_[1]^[1] == g) + assert(h_[0]^[1] == 0) + assert(h_[1]^[0] == 0) + h = (chicken => f) ++ (nuggets => g); + indices h + assert(h_[chicken]^[chicken] == f) + assert(h_[nuggets]^[nuggets] == g) +/// + + +TEST /// +S = ZZ/101[a..c] + C = simplicialModule(freeResolution coker matrix{{a*b, a*c, b*c}}, 3, Degeneracy => true) + D = simplicialModule(freeResolution coker vars S, Degeneracy => true) + f = randomSimplicialMap(D,C) + assert isWellDefined f + assert not isCommutative f + g = randomSimplicialMap(D,C, Cycle => true) + assert isWellDefined g + assert isCommutative g + assert isSimplicialMorphism g + h = randomSimplicialMap(D,C, Boundary => true) + assert isWellDefined h + assert isCommutative h + assert isSimplicialMorphism h + assert isNullHomotopic normalize h + nullHomotopy normalize h + p = randomSimplicialMap(D, C, Cycle => true, Degree => -1) + assert isWellDefined p + assert isCommutative p + assert isSimplicialMorphism p + q = randomSimplicialMap(D, C, Boundary => true, InternalDegree => 2); + assert isCommutative q + assert isSimplicialMorphism q + assert(source q == C) + assert(target q == D) + assert isNullHomotopic normalize q +/// + +TEST /// +R = ZZ/101[a,b,c]; + B = simplicialModule(freeResolution coker matrix{{a^2*b, a*b*c, c^3}}, Degeneracy => true) + C = simplicialModule(freeResolution coker vars R, 2, Degeneracy => true) + h = randomSimplicialMap(C, B, Cycle => true) + f = inducedMap(C, image h) + assert isCommutative f + g = inducedMap(coker h, C) + assert isCommutative g + assert isShortExactSequence(g,f) + I = ideal(a^3, b^3, c^3) + J = I + ideal(a*b*c) + K = I : ideal(a*b*c) + SES = complex{ + map(comodule J, comodule I, 1), + map(comodule I, (comodule K) ** R^{-3}, {{a*b*c}}) + } + assert isWellDefined SES + assert isShortExactSequence(dd^SES_1, dd^SES_2) + (g,f) = (horseshoeResolution SES)/simplicialModule; + assert isShortExactSequence(g,f) +/// + + +TEST /// +S = ZZ/101[a..d] + D = simplicialModule(S^1, 5) + D[-1] + oo.dd + D[-2] + C = simplicialModule(freeResolution coker vars S, Degeneracy => true) + dd^C_(3,0) + ss^C_(2,0) + D = C[1] + assert isWellDefined D + assert isWellDefined dd^D_(2,0) + ss^D_(1,0) + C2 = simplicialModule(freeResolution (S^1/(a^2, b^2, c^2, d^2)), Degeneracy => true) + C3 = simplicialModule(freeResolution (S^1/(a^2, b^3, c^4, d^5)), Degeneracy => true) + f2 = simplicialModule(extend(C.complex, C2.complex, map(C_0, C2_0, 1))); + f3 = simplicialModule(extend(C2.complex, C3.complex, map(C2_0, C3_0, 1))); + assert isWellDefined (f2[-1]) + assert isSimplicialMorphism (f2[-1]) + assert isSimplicialMorphism (f3[-2]) +/// + + +TEST /// +S = ZZ/101[a,b,c]; + C1 = simplicialModule(freeResolution coker vars S, Degeneracy => true) + D1 = C1 ++ simplicialModule(complex(S^13)[-2], 3, Degeneracy => true) + assert isWellDefined D1 + assert(D1.?ss) --knows to cache degeneracy maps if inputs have degeneracy maps + C2 = simplicialModule(ideal(a,b,c), 3, Degeneracy => true) + C1 ++ C2 + assert isWellDefined(C1 ++ C2) + C3 = directSum(C1,C2,C2[-2]) + assert isWellDefined C3 + C4 = directSum(first => C1, second => C2) + assert isCommutative C4_[first] -- inclusion map C1 --> C4 + assert isCommutative C4^[first] -- projection map C4 --> C1 + assert(C4^[first] * C4_[first] == 1) + assert(C4^[second] * C4_[second] == 1) + assert(C4^[first] * C4_[second] == 0) + assert(C4^[second] * C4_[first] == 0) + assert(C4_[first] * C4^[first] + C4_[second] * C4^[second] == 1) + assert isShortExactSequence(C4^[first], C4_[second]) + assert isShortExactSequence(C4^[second], C4_[first]) +/// + + +TEST /// +Q = ZZ/101[a..d] + K = koszulComplex vars Q + S = simplicialModule(K, Degeneracy => true) + nK = naiveNorm(S) + assert isWellDefined nK + prune HH nK +/// + +TEST /// +Q = QQ[x_1..x_3]; + K = koszulComplex vars Q; + assert isWellDefined simplicialModule(K, 4) --no degeneracy here + S = simplicialModule(K,4, Degeneracy => true) + S.dd**Q^1 + assert isWellDefined oo + assert isWellDefined S + Sdegen = simplicialModule(K,4,Degeneracy => true) + S.dd + assert Sdegen.?ss --this is the version that actually has degeneracy maps cached + simplicialModule(K, 5) + C = complex(Q^1, Base => 1) + simplicialModule(C, 3) + assert isWellDefined oo + simplicialModule(complex(Q^2, Base => 2), 6, Degeneracy => true) + assert isWellDefined oo --nice, now we can be confident the objects we are messing with actually make any sense + assert oo.?ss + assert isSimplicialMorphism id_S + phi = exteriorInclusion(S); + assert isWellDefined phi + assert isCommutative phi + assert isWellDefined prune phi + assert isCommutative prune phi + assert isWellDefined prune coker phi + K = koszulComplex {x_1,x_2} + Sn = simplicialModule(K, 4, Degeneracy => true) + phi = exteriorInclusion(K) + assert isCommutative phi + assert isWellDefined phi + assert isCommutative prune phi + assert isWellDefined prune phi + sphi = exteriorInclusion(Sn); + psphi = prune sphi; + assert isWellDefined (source psphi).cache.pruningMap + assert isCommutative (source psphi).cache.pruningMap + assert isSimplicialMorphism (source psphi).cache.pruningMap --pruningMaps are well-defined morphisms + S = simplicialModule(K,6) + + + p = randomComplexMap(K, K, Degree => 1, InternalDegree => 1) + sp = simplicialModule p + assert isWellDefined sp + assert not isCommutative sp + normalize(sp, CheckComplex => false) + prune oo ---reobtain p + p' = randomComplexMap(K, K, Degree => -1) + sp' = simplicialModule p' + assert isWellDefined sp' + assert not isCommutative sp' + normalize(sp', CheckComplex => false) + prune oo --reobtain p' + p = randomComplexMap(K, K, Degree => 1, Cycle => true, InternalDegree => 2) + sp = simplicialModule p + assert isWellDefined sp + assert isCommutative sp + normalize(sp, CheckComplex => false) + prune oo ---reobtain p + diffs = simplicialModule K.dd + isWellDefined diffs + assert isCommutative diffs + + assert(image(id_S) == S) + assert(simplicialModule(id_K, 6) == id_S) + assert isSimplicialMorphism id_S + simplicialModule(complex(Q^0), 6, Degeneracy => true) -- should be able to input 0 and get a well-defined output + assert isWellDefined oo + phi = randomSimplicialMap(S, S, Cycle => true, InternalDegree => 1) + assert isWellDefined phi + assert isCommutative phi + + bS = basis(0, forgetComplex S) + prune bS.dd + assert isWellDefined bS + assert isWellDefined prune bS + bid = basis(0, id_(forgetComplex S)) + assert isWellDefined bid + assert isCommutative bid + assert isWellDefined prune bid + assert isCommutative prune bid + + fS = forgetComplex S + assert not fS.?ss + + bS = basis(1, forgetComplex S) + assert isWellDefined bS + prune bS.dd + assert isWellDefined oo + --prune bS.ss + --assert isWellDefined oo + normalize bS + prune oo + prune basis(1, K) + + bS = basis(3, forgetComplex S) + assert isWellDefined bS + prune bS.dd; + assert isWellDefined oo + --prune bS.ss; + --assert isWellDefined oo + normalize bS + prune oo + prune basis(3, koszulComplex vars Q) + + tS = truncate(1, S) + assert isWellDefined tS + prune tS + assert isWellDefined prune tS + tS = truncate(1, fS) + assert isWellDefined tS + prune tS + assert isWellDefined prune tS + assert isCommutative truncate(2, id_S) + assert isCommutative truncate(2, id_fS) + + K = koszulComplex {x_1,x_2} + assert isWellDefined (Sc = schurMap({1,1}, K)) + prune extPower(2, K) + assert isWellDefined prune schurMap({2,1}, K, TopDegree => 4) +/// + + +TEST /// +Q = ZZ/2[a,b] + K = koszulComplex vars Q; + F = freeResolution( (ideal vars Q)^2) + phi = extend(K, F, id_(K_0)) + f = elapsedTime prune schurMap({2}, phi) + assert isCommutative f + assert isWellDefined f + prune HH source f + prune HH target f + prune HH f +/// + + +TEST /// +Q = ZZ/101[x_1,x_2]; + K1 = complex {matrix{{x_1}}}; + K2 = complex {matrix{{x_2}}}; + T1 = K1**K2 + T1.dd + T2 = prune simplicialTensor({K1,K2}) + T2.dd + phi1 = extend(T1,T2,id_(T1_0)) + phi2 = extend(T2,T1,id_(T1_0)) + assert(phi1*phi2 == id_T1) + assert isNullHomotopic(phi2*phi1 - id_T2) + Q = ZZ/101[a,b]; + K = koszulComplex vars Q + SK = simplicialModule(K,6) --want top degree 6 since the resulting complexes should have length 6 + w21K = extPower(2, SK) ** SK + w3K = extPower(3, SK) + assert isWellDefined w3K + H = hashTable for i from 0 to 6 list i => dual wedgeProduct(2,1, dual SK_i); + inclusion = map(w21K, w3K, H); + assert isWellDefined inclusion + assert isCommutative inclusion +/// + +TEST /// +R = ZZ/101[x_1..x_3]; + K = koszulComplex vars R + S = simplicialModule(K,10, Degeneracy => true) + keys S + assert(K == normalize S) + Kn = normalize(S, CheckComplex => false) + Kn.dd + assert not(K == Kn) + assert(K == prune Kn) + Q = ZZ/3[a,b]; + K = koszulComplex vars Q + SK = simplicialModule(K,6) --want top degree 6 since the resulting complexes should have length 6 + w21K = extPower(2, SK) ** SK + w3K = extPower(3, SK) + H = hashTable for i from 0 to 6 list i => dual wedgeProduct(2,1, dual SK_i); + inclusion = map(w21K, w3K, H); + assert isWellDefined inclusion + assert isCommutative inclusion + Q = ZZ/2[a,b,c] + K = koszulComplex vars Q + phi = elapsedTime exteriorInclusion(K,4); --specify top degree 4 + assert isWellDefined phi + assert isCommutative phi +/// + diff --git a/M2/Macaulay2/packages/SimplicialModules/SimplicialModule_Modified.m2 b/M2/Macaulay2/packages/SimplicialModules/SimplicialModule_Modified.m2 new file mode 100644 index 0000000000..b9882e5a75 --- /dev/null +++ b/M2/Macaulay2/packages/SimplicialModules/SimplicialModule_Modified.m2 @@ -0,0 +1,823 @@ + + needsPackage "Complexes" + load "SimplicialMapUtilities_Modified.m2" + + + SimplicialModule = new Type of MutableHashTable -- + -- note: we make this mutable in order to construct the + -- differential as a morphism of ZZdFactorizations (in the style of Complexes) + -- BUT: after construction, it is should be IMMUTABLE!! + -- at some point, we might want to allow lazy determination of the modules and maps + -- but for now, we insist that all modules and maps are explicit. + -- key: + -- ring + -- modules: hash table: ZZ => Module + -- differential: ComplexMap from C --> C, degree -1 (mod d) + -- period: an integer d, tells us for which d the factorization C is ZZ/d-graded + -- cache: a CacheTable + + SimplicialModuleMap = new Type of HashTable + -- keys: + -- degree: ZZ + -- source: Simplicial module over a ring R + -- target: simplicial module over the same ring R + -- maps themselves (HashTable of Matrices), keys lying in the concentration period of the source. + -- not all of the keys maps#i, need be present. + -- missing ones are presumed to be zero maps. + -- cache: a CacheTable + -- cache.isCommutative: whether this map commutes with the differentials + -- not set until needed. unset means we have not checked yet, + -- and the user hasn't declared it to be true/false yet. + +SimplicialModule.synonym = "Simplicial Module" +SimplicialModuleMap.synonym = "Map of Simplicial Modules" + +topDegree = method(); +topDegree SimplicialModule := ZZ => S -> S.topDegree + +ring SimplicialModule := Ring => S -> S.ring + +moduleMaker = (C,d) -> ( + moduleList := new MutableHashTable; + maxK := min (d, length C); + for k to maxK do ( + moduleList#(d,k) = directSum toList( + binomial(d,k):(C_k)); + ); + for i in (sort keys moduleList) list (i,moduleList#i) + ) + +mapMaker = (phi,d) -> ( + mapList := new MutableHashTable; + maxK = min (d, max(length source phi,length target phi)); + for k to maxK do ( + mapList#(d,k) = directSum toList( + binomial(d,k):(phi_k)); + ); + for i in (sort keys mapList) list (i,mapList#i) + ) + +combineSFactors = method(); +combineSFactors(SimplicialModule,ZZ) := (S,d) -> (directSum for i to min(d,S.complexLength) list (S.module)#(d,i)) + +--H1 is the face maps, H2 is the degeneracy maps +simplicialModuleModified = method(Options => {Base=>0,Degeneracy => false}) +simplicialModuleModified(Complex,HashTable,HashTable,ZZ) := SimplicialModule => opts -> (C,H1,H2,d) -> ( + spots := sort keys H1; + if #spots === 0 then + error "expected at least one map"; + R := ring C; + moduleList := new MutableHashTable; + for b to d do ( + maxK = min (b, length C); + for k to maxK do ( + moduleList#(b,k) = directSum toList(binomial(b,k):(C_k)); + ); + ); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => new HashTable from moduleList, + symbol cache => new CacheTable, + symbol complexLength => length C, + symbol complex => C + }; + S.dd = map(S,S,H1,Degree=>-1); + S.ss = map(S,S,H2,Degree=>1); + S + ) + +--H1 is the face maps +simplicialModuleModified(Complex,HashTable,ZZ) := SimplicialModule => opts -> (C,H1,d) -> (--print("made it here!"); + spots := sort keys H1; + if #spots === 0 then + error "expected at least one map"; + R := ring C; + moduleList := new MutableHashTable; + for b to d do ( + maxK = min (b, length C); + for k to maxK do ( + moduleList#(b,k) = directSum toList(binomial(b,k):(C_k)); + ); + ); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => new HashTable from moduleList, + symbol cache => new CacheTable, + symbol complexLength => length C, + symbol complex => C + }; + S.dd = map(S,S,H1,Degree=>-1); + S + ) + +simplicialModuleModified(HashTable,HashTable,HashTable,ZZ) := SimplicialModule => opts -> (L,H1,H2,d) -> (--print("we got started"); + R := ring (L#((keys L)#0)); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => L, + symbol cache => new CacheTable, + }; + --print("made it to face"); + S.dd = map(S,S,H1,Degree=>-1); + --print("we are almost done"); + S.ss = map(S,S,H2,Degree=>1); + S + ) + +simplicialModuleModified(HashTable,HashTable,ZZ) := SimplicialModule => opts -> (L,H1,d) -> (--print("we got started"); + R := ring (L#((keys L)#0)); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => L, + symbol cache => new CacheTable, + }; + --print("made it to face"); + S.dd = map(S,S,H1,Degree=>-1); + --print("we are almost done"); + S + ) + + +simplicialModuleModified(Complex,ZZ) := SimplicialModule => opts -> (C,d) -> ( + --C is a chain complex, output is the Dold-Kan image of C in the category of simplicial modules + if not instance(opts.Base, ZZ) then + error "expected Base to be an integer"; + if instance(C,Complex) then ( + if opts.Degeneracy == true then (degenmapHash := hashTable flatten for n from 1 to d-1 list ( + for i from 0 to n list ( + (n,i) => degenMapiModified(n,i,C) + ) + );); + facemapHash := hashTable flatten for n from 1 to d list ( + for i from 0 to n list ( + (n,i) => faceMapiModified(n,i,C) + ) + ); + --print("mde it here first"); + if opts.Degeneracy == true then break return simplicialModule(C,facemapHash,degenmapHash,d); + --print("made it here"); + return simplicialModule(C,facemapHash,d) + ); + ) + + simplicialModuleModified(Complex) := SimplicialModule => opts -> C -> (simplicialModule(C,length C,Degeneracy => opts.Degeneracy)) + + simplicialModuleModified(Module,ZZ) := SimplicialModule => opts -> (M,d) -> (simplicialModule(complex M,d,Degeneracy => opts.Degeneracy)) + + +SimplicialModule _ Sequence := Module => (S,p) -> ( + if #p =!= 2 then + error ("Expected a pair of integer indices"); + if S.module#?(p#0,p#1) then S.module#(p#0,p#1) else (ring S)^0 + ) +SimplicialModule _ ZZ := Module => (S,n) -> directSum for i in keys (S.module) list (if first(splice(toSequence{i}))==n then S.module#(i) else continue) + +net SimplicialModule := S -> ( + (lo,hi) := (0,topDegree S); + if lo > hi then + error "In a complex, lo <= hi should always hold in the concentration" + --"0" + else if lo == hi and C_lo === 0 then + "0" + else if any(keys S,i->i==symbol complex) then + (horizontalJoin between(" <-- ", + for i from lo to hi list + stack (net directSum(for k from 0 to min(i,S.complexLength) list (S.module)#(i,k)), " ", net i))) + else + horizontalJoin between(" <-- ", + for i from lo to hi list + stack (net ((S.module)#i), " ", net i)) + ) + + + Symbol ^ SimplicialModule := SimplicialModuleMap => (sym, C) -> ( + if sym === dd then C.dd; + if sym === ss then C.ss + else error "expected symbol to be 'dd' or 'ss'" + ) + + lineOnTop := (s) -> concatenate(width s : "-") || s + +source SimplicialModuleMap := SimplicialModule => f -> f.source +target SimplicialModuleMap := SimplicialModule => f -> f.target +ring SimplicialModuleMap := SimplicialModule => f -> ring source f +degree SimplicialModuleMap := ZZ => f -> f.degree + +isHomogeneous SimplicialModuleMap := (f) -> all(values f.map, isHomogeneous) + +simplicialModuleMap = method(Options => {Degeneracy => false}); +simplicialModuleMap(ComplexMap,ZZ) := SimplicialModuleMap => opts -> (phi,d) -> ( + src := simplicialModule(source phi,d); + trg := simplicialModule(target phi,d); + map(trg,src,new HashTable from for i to d list i => directSum apply(mapMaker(phi,i),j->j_1),Degree => degree phi) + ) + + +-*map(SimplicialModule, SimplicialModule, HashTable) := SimplicialModuleMap => opts -> (tar, src, maps) -> ( + if not(topDegree tar == topDegree src) then error "expected source and target to have the same top degree"; + R := ring tar; + if ring src =!= R or any(values maps, f -> ring f =!= R) then + error "expected source, target and maps to be over the same ring"; + deg := if opts.Degree === null + then 0 + else if instance(opts.Degree, ZZ) then + opts.Degree + else + error "expected integer degree"; + (lo,hi) := (0,topDegree tar); + maps' := hashTable for k in keys maps list ( + if not instance(k_0, ZZ) then error "expected integer keys"; + f := maps#k; + -- note: we use != instead of =!= in the next 2 tests, + -- since we want to ignore any term order differences + --print(k); + --print(source f); + --print(src_(first k)); + if rank source f != rank src_(first k) then ( + error ("map with index "|toString(k)|" has inconsistent source"); + ); + if rank target f != rank tar_(first(k)+deg) then + error ("map with index "|toString(k)|" has inconsistent target"); + if first k < lo or first k > hi then continue else (k,f) + ); + new SimplicialModuleMap from { + symbol source => src, + symbol target => tar, + symbol degree => deg, + symbol map => maps', + symbol cache => new CacheTable + } + )*- + +map(SimplicialModule, SimplicialModule, HashTable) := SimplicialModuleMap => opts -> (tar, src, maps) -> ( + if not(topDegree tar == topDegree src) then error "expected source and target to have the same top degree"; + R := ring tar; + if ring src =!= R or any(values maps, f -> ring f =!= R) then + error "expected source, target and maps to be over the same ring"; + deg := if opts.Degree === null + then 0 + else if instance(opts.Degree, ZZ) then + opts.Degree + else + error "expected integer degree"; + (lo,hi) := (0,topDegree tar); + maps' := hashTable for k in keys maps list ( + if instance(k, Sequence) then ( + f := maps#k; + -- note: we use != instead of =!= in the next 2 tests, + -- since we want to ignore any term order differences + --print(k); + --print(source f); + --print(src_(first k)); + if rank source f != rank src_(first k) then ( + error ("map with index "|toString(k)|" has inconsistent source"); + ); + if rank target f != rank tar_(first(k)+deg) then + error ("map with index "|toString(k)|" has inconsistent target"); + if first k < lo or first k > hi then continue else (k,f) + ) + else ( + f := maps#k; + -- note: we use != instead of =!= in the next 2 tests, + -- since we want to ignore any term order differences + --print(k); + --print(source f); + --print(src_(first k)); + if rank source f != rank src_(k) then ( + error ("map with index "|toString(k)|" has inconsistent source"); + ); + if rank target f != rank tar_(k+deg) then + error ("map with index "|toString(k)|" has inconsistent target"); + if k < lo or k > hi then continue else (k,f) + )); + new SimplicialModuleMap from { + symbol source => src, + symbol target => tar, + symbol degree => deg, + symbol map => maps', + symbol cache => new CacheTable + } + ) + +map(SimplicialModule, SimplicialModule, List) := SimplicialModuleMap => opts -> (tar, src, maps) -> ( + -- case 1: maps is a (single) list of matrices (maps between components of the complex) + -- case 2: maps is a double list of ComplexMap's + -- in this case, if the maps all commute with differentials, and are diagonal, then + -- we could declare the result to be commutative as well. Should we do this? + -- Can tell, depending on the class of maps#0. + (lo,hi) := (0,topDegree tar); + if instance(maps#0, List) then ( + mapHash := hashTable for i from lo to hi list i => ( + h := maps#(i-lo); + if h_0 == 0 then continue else h + ); + --print("makde it here"); + return map(tar,src,mapHash,opts) + ); + -- At this point, the first entry of 'maps' is a List. + -- Check: it is a table of ComplexMap + -*R := ring tar; + if R =!= ring src then error "expected complexes over the same ring"; + if not isTable maps then error "expected a table of SimplicialModuleMaps"; + -- check: all entries which are SimplicialModuleMaps have the same homological degree + deg := if opts.Degree === null + then null + else if instance(opts.Degree, ZZ) then + opts.Degree + else + error "expected integer degree"; + degs := unique for f in flatten maps list + if instance(f,ZZdFactorizationMap) + then degree f + else continue; + if #degs > 1 then error "expected all ZZdFactorizationMaps to have the same degree"; + if deg =!= null and #degs == 1 and degs#0 =!= deg then error "Supplied degree is incompatible with the ComplexMaps"; + if deg === null then deg = (if #degs == 1 then degs#0 else 0); + -- At this point, we need to create (block) matrices for each component of the complex. + mapHash = hashTable for i from lo to hi list i => ( + newmaps := applyTable(maps, f -> if instance(f,SimplicialModuleMap) then f_i else f); + h := map(tar_(i+deg), src_i, matrix newmaps); + if h == 0 then continue else h + ); + map(tar,src,mapHash,opts, Degree=>deg)*- + ) + +-*flatten(SimplicialModuleMap) := SimplicialModuleMap => phi -> (if instance((keys phi.map)#0,ZZ) then return phi + else (*- + + +SimplicialModuleMap _ ZZ := Matrix => (f,i) -> ( + if f.map#?i then f.map#i else map((target f)_(i + degree f), (source f)_i, 0)) + +SimplicialModuleMap _ Sequence := Matrix => (f,s) -> ( + if f.map#?s then f.map#s else map((target f)_(s#0 + degree f), (source f)_(s#0), 0)) + + + + +-*expression SimplicialModuleMap := Expression => f -> ( + d := degree f; + s := sort keys f.map; + if #s === 0 then + new ZeroExpression from {0} + else new VerticalList from for i in s list + RowExpression {(i#0+d,i#1), ":", MapExpression { target f_i, source f_i, f_i }, ":", i} + )*- + +expression SimplicialModuleMap := Expression => f -> ( + d := degree f; + s := sort keys f.map; + if #s === 0 then + new ZeroExpression from {0} + else if instance(s_0,Sequence) then new VerticalList from for i in s list + RowExpression {(i#0+d,i#1), ":", MapExpression { target f_i, source f_i, f_i }, ":", i} + else if instance(s_0,ZZ) then return new VerticalList from for i in s list + RowExpression {i+d, ":", MapExpression { target f_i, source f_i, f_i }, ":", i} + ) + +-*net SimplicialModuleMap := Net => f -> ( + v := between("", + for i in sort keys f.map list ( + horizontalJoin( + net ((i#0+f.degree,i#1)), " : ", net target f_i, " <--", + lineOnTop net f_i, + "-- ", net source f_i, " : ", net i + ) + )); + if # v === 0 then net "0" + else stack v + )*- + + net SimplicialModuleMap := Net => f -> ( + v := between("", + for i in sort keys f.map list ( + if instance(i,Sequence) then (horizontalJoin( + net ((i#0+f.degree,i#1)), " : ", net target f_i, " <--", + lineOnTop net f_i, + "-- ", net source f_i, " : ", net i + )) + else (horizontalJoin( + net (i+f.degree), " : ", net target f_i, " <--", + lineOnTop net f_i, + "-- ", net source f_i, " : ", net i + )) + )); + if # v === 0 then net "0" + else stack v + ) + + + + SimplicialModule = new Type of MutableHashTable -- + -- note: we make this mutable in order to construct the + -- differential as a morphism of ZZdFactorizations (in the style of Complexes) + -- BUT: after construction, it is should be IMMUTABLE!! + -- at some point, we might want to allow lazy determination of the modules and maps + -- but for now, we insist that all modules and maps are explicit. + -- key: + -- ring + -- modules: hash table: ZZ => Module + -- differential: ComplexMap from C --> C, degree -1 (mod d) + -- period: an integer d, tells us for which d the factorization C is ZZ/d-graded + -- cache: a CacheTable + + SimplicialModuleMap = new Type of HashTable + -- keys: + -- degree: ZZ + -- source: Simplicial module over a ring R + -- target: simplicial module over the same ring R + -- maps themselves (HashTable of Matrices), keys lying in the concentration period of the source. + -- not all of the keys maps#i, need be present. + -- missing ones are presumed to be zero maps. + -- cache: a CacheTable + -- cache.isCommutative: whether this map commutes with the differentials + -- not set until needed. unset means we have not checked yet, + -- and the user hasn't declared it to be true/false yet. + +SimplicialModule.synonym = "Simplicial Module" +SimplicialModuleMap.synonym = "Map of Simplicial Modules" + +topDegree = method(); +topDegree SimplicialModule := ZZ => S -> S.topDegree + +ring SimplicialModule := Ring => S -> S.ring + +moduleMaker = (C,d) -> ( + moduleList := new MutableHashTable; + maxK := min (d, length C); + for k to maxK do ( + moduleList#(d,k) = directSum toList( + binomial(d,k):(C_k)); + ); + for i in (sort keys moduleList) list (i,moduleList#i) + ) + +mapMaker = (phi,d) -> ( + mapList := new MutableHashTable; + maxK = min (d, max(length source phi,length target phi)); + for k to maxK do ( + mapList#(d,k) = directSum toList( + binomial(d,k):(phi_k)); + ); + for i in (sort keys mapList) list (i,mapList#i) + ) + +combineSFactors = method(); +combineSFactors(SimplicialModule,ZZ) := (S,d) -> (directSum for i to min(d,S.complexLength) list (S.module)#(d,i)) + +--H1 is the face maps, H2 is the degeneracy maps +simplicialModule = method(Options => {Base=>0,Degeneracy => false}) +simplicialModule(Complex,HashTable,HashTable,ZZ) := SimplicialModule => opts -> (C,H1,H2,d) -> ( + spots := sort keys H1; + if #spots === 0 then + error "expected at least one map"; + R := ring C; + moduleList := new MutableHashTable; + for b to d do ( + maxK = min (b, length C); + for k to maxK do ( + moduleList#(b,k) = directSum toList(binomial(b,k):(C_k)); + ); + ); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => new HashTable from moduleList, + symbol cache => new CacheTable, + symbol complexLength => length C, + symbol complex => C + }; + S.dd = map(S,S,H1,Degree=>-1); + S.ss = map(S,S,H2,Degree=>1); + S + ) + +--H1 is the face maps +simplicialModule(Complex,HashTable,ZZ) := SimplicialModule => opts -> (C,H1,d) -> (--print("made it here!"); + spots := sort keys H1; + if #spots === 0 then + error "expected at least one map"; + R := ring C; + moduleList := new MutableHashTable; + for b to d do ( + maxK = min (b, length C); + for k to maxK do ( + moduleList#(b,k) = directSum toList(binomial(b,k):(C_k)); + ); + ); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => new HashTable from moduleList, + symbol cache => new CacheTable, + symbol complexLength => length C, + symbol complex => C + }; + S.dd = map(S,S,H1,Degree=>-1); + S + ) + +simplicialModule(HashTable,HashTable,HashTable,ZZ) := SimplicialModule => opts -> (L,H1,H2,d) -> (--print("we got started"); + R := ring (L#((keys L)#0)); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => L, + symbol cache => new CacheTable, + }; + --print("made it to face"); + S.dd = map(S,S,H1,Degree=>-1); + --print("we are almost done"); + S.ss = map(S,S,H2,Degree=>1); + S + ) + +simplicialModule(HashTable,HashTable,ZZ) := SimplicialModule => opts -> (L,H1,d) -> (--print("we got started"); + R := ring (L#((keys L)#0)); + S := new SimplicialModule from { + symbol ring => R, + symbol topDegree => d, + symbol module => L, + symbol cache => new CacheTable, + }; + --print("made it to face"); + S.dd = map(S,S,H1,Degree=>-1); + --print("we are almost done"); + S + ) + + +simplicialModule(Complex,ZZ) := SimplicialModule => opts -> (C,d) -> ( + --C is a chain complex, output is the Dold-Kan image of C in the category of simplicial modules + if not instance(opts.Base, ZZ) then + error "expected Base to be an integer"; + if instance(C,Complex) then ( + if opts.Degeneracy == true then (degenmapHash := hashTable flatten for n from 1 to d-1 list ( + for i from 0 to n list ( + (n,i) => degenMapiModified(n,i,C) + ) + );); + facemapHash := hashTable flatten for n from 1 to d list ( + for i from 0 to n list ( + (n,i) => faceMapiModified(n,i,C) + ) + ); + --print("mde it here first"); + if opts.Degeneracy == true then break return simplicialModule(C,facemapHash,degenmapHash,d); + --print("made it here"); + return simplicialModule(C,facemapHash,d) + ); + ) + + simplicialModule(Complex) := SimplicialModule => opts -> C -> (simplicialModule(C,length C,Degeneracy => opts.Degeneracy)) + + simplicialModule(Module,ZZ) := SimplicialModule => opts -> (M,d) -> (simplicialModule(complex M,d,Degeneracy => opts.Degeneracy)) + + +SimplicialModule _ Sequence := Module => (S,p) -> ( + if #p =!= 2 then + error ("Expected a pair of integer indices"); + if S.module#?(p#0,p#1) then S.module#(p#0,p#1) else (ring S)^0 + ) +SimplicialModule _ ZZ := Module => (S,n) -> directSum for i in keys (S.module) list (if first(splice(toSequence{i}))==n then S.module#(i) else continue) + +net SimplicialModule := S -> ( + (lo,hi) := (0,topDegree S); + if lo > hi then + error "In a complex, lo <= hi should always hold in the concentration" + --"0" + else if lo == hi and C_lo === 0 then + "0" + else if any(keys S,i->i==symbol complex) then + (horizontalJoin between(" <-- ", + for i from lo to hi list + stack (net directSum(for k from 0 to min(i,S.complexLength) list (S.module)#(i,k)), " ", net i))) + else + horizontalJoin between(" <-- ", + for i from lo to hi list + stack (net ((S.module)#i), " ", net i)) + ) + + + Symbol ^ SimplicialModule := SimplicialModuleMap => (sym, C) -> ( + if sym === dd then C.dd; + if sym === ss then C.ss + else error "expected symbol to be 'dd' or 'ss'" + ) + + lineOnTop := (s) -> concatenate(width s : "-") || s + +source SimplicialModuleMap := SimplicialModule => f -> f.source +target SimplicialModuleMap := SimplicialModule => f -> f.target +ring SimplicialModuleMap := SimplicialModule => f -> ring source f +degree SimplicialModuleMap := ZZ => f -> f.degree + +isHomogeneous SimplicialModuleMap := (f) -> all(values f.map, isHomogeneous) + +simplicialModuleMap = method(Options => {Degeneracy => false}); +simplicialModuleMap(ComplexMap,ZZ) := SimplicialModuleMap => opts -> (phi,d) -> ( + src := simplicialModule(source phi,d); + trg := simplicialModule(target phi,d); + map(trg,src,new HashTable from for i to d list i => directSum apply(mapMaker(phi,i),j->j_1),Degree => degree phi) + ) + + +-*map(SimplicialModule, SimplicialModule, HashTable) := SimplicialModuleMap => opts -> (tar, src, maps) -> ( + if not(topDegree tar == topDegree src) then error "expected source and target to have the same top degree"; + R := ring tar; + if ring src =!= R or any(values maps, f -> ring f =!= R) then + error "expected source, target and maps to be over the same ring"; + deg := if opts.Degree === null + then 0 + else if instance(opts.Degree, ZZ) then + opts.Degree + else + error "expected integer degree"; + (lo,hi) := (0,topDegree tar); + maps' := hashTable for k in keys maps list ( + if not instance(k_0, ZZ) then error "expected integer keys"; + f := maps#k; + -- note: we use != instead of =!= in the next 2 tests, + -- since we want to ignore any term order differences + --print(k); + --print(source f); + --print(src_(first k)); + if rank source f != rank src_(first k) then ( + error ("map with index "|toString(k)|" has inconsistent source"); + ); + if rank target f != rank tar_(first(k)+deg) then + error ("map with index "|toString(k)|" has inconsistent target"); + if first k < lo or first k > hi then continue else (k,f) + ); + new SimplicialModuleMap from { + symbol source => src, + symbol target => tar, + symbol degree => deg, + symbol map => maps', + symbol cache => new CacheTable + } + )*- + +map(SimplicialModule, SimplicialModule, HashTable) := SimplicialModuleMap => opts -> (tar, src, maps) -> ( + if not(topDegree tar == topDegree src) then error "expected source and target to have the same top degree"; + R := ring tar; + if ring src =!= R or any(values maps, f -> ring f =!= R) then + error "expected source, target and maps to be over the same ring"; + deg := if opts.Degree === null + then 0 + else if instance(opts.Degree, ZZ) then + opts.Degree + else + error "expected integer degree"; + (lo,hi) := (0,topDegree tar); + maps' := hashTable for k in keys maps list ( + if instance(k, Sequence) then ( + f := maps#k; + -- note: we use != instead of =!= in the next 2 tests, + -- since we want to ignore any term order differences + --print(k); + --print(source f); + --print(src_(first k)); + if rank source f != rank src_(first k) then ( + error ("map with index "|toString(k)|" has inconsistent source"); + ); + if rank target f != rank tar_(first(k)+deg) then + error ("map with index "|toString(k)|" has inconsistent target"); + if first k < lo or first k > hi then continue else (k,f) + ) + else ( + f := maps#k; + -- note: we use != instead of =!= in the next 2 tests, + -- since we want to ignore any term order differences + --print(k); + --print(source f); + --print(src_(first k)); + if rank source f != rank src_(k) then ( + error ("map with index "|toString(k)|" has inconsistent source"); + ); + if rank target f != rank tar_(k+deg) then + error ("map with index "|toString(k)|" has inconsistent target"); + if k < lo or k > hi then continue else (k,f) + )); + new SimplicialModuleMap from { + symbol source => src, + symbol target => tar, + symbol degree => deg, + symbol map => maps', + symbol cache => new CacheTable + } + ) + +map(SimplicialModule, SimplicialModule, List) := SimplicialModuleMap => opts -> (tar, src, maps) -> ( + -- case 1: maps is a (single) list of matrices (maps between components of the complex) + -- case 2: maps is a double list of ComplexMap's + -- in this case, if the maps all commute with differentials, and are diagonal, then + -- we could declare the result to be commutative as well. Should we do this? + -- Can tell, depending on the class of maps#0. + (lo,hi) := (0,topDegree tar); + if instance(maps#0, List) then ( + mapHash := hashTable for i from lo to hi list i => ( + h := maps#(i-lo); + if h_0 == 0 then continue else h + ); + --print("makde it here"); + return map(tar,src,mapHash,opts) + ); + -- At this point, the first entry of 'maps' is a List. + -- Check: it is a table of ComplexMap + -*R := ring tar; + if R =!= ring src then error "expected complexes over the same ring"; + if not isTable maps then error "expected a table of SimplicialModuleMaps"; + -- check: all entries which are SimplicialModuleMaps have the same homological degree + deg := if opts.Degree === null + then null + else if instance(opts.Degree, ZZ) then + opts.Degree + else + error "expected integer degree"; + degs := unique for f in flatten maps list + if instance(f,ZZdFactorizationMap) + then degree f + else continue; + if #degs > 1 then error "expected all ZZdFactorizationMaps to have the same degree"; + if deg =!= null and #degs == 1 and degs#0 =!= deg then error "Supplied degree is incompatible with the ComplexMaps"; + if deg === null then deg = (if #degs == 1 then degs#0 else 0); + -- At this point, we need to create (block) matrices for each component of the complex. + mapHash = hashTable for i from lo to hi list i => ( + newmaps := applyTable(maps, f -> if instance(f,SimplicialModuleMap) then f_i else f); + h := map(tar_(i+deg), src_i, matrix newmaps); + if h == 0 then continue else h + ); + map(tar,src,mapHash,opts, Degree=>deg)*- + ) + +-*flatten(SimplicialModuleMap) := SimplicialModuleMap => phi -> (if instance((keys phi.map)#0,ZZ) then return phi + else (*- + + +SimplicialModuleMap _ ZZ := Matrix => (f,i) -> ( + if f.map#?i then f.map#i else map((target f)_(i + degree f), (source f)_i, 0)) + +SimplicialModuleMap _ Sequence := Matrix => (f,s) -> ( + if f.map#?s then f.map#s else map((target f)_(s#0 + degree f), (source f)_(s#0), 0)) + + + + +-*expression SimplicialModuleMap := Expression => f -> ( + d := degree f; + s := sort keys f.map; + if #s === 0 then + new ZeroExpression from {0} + else new VerticalList from for i in s list + RowExpression {(i#0+d,i#1), ":", MapExpression { target f_i, source f_i, f_i }, ":", i} + )*- + +expression SimplicialModuleMap := Expression => f -> ( + d := degree f; + s := sort keys f.map; + if #s === 0 then + new ZeroExpression from {0} + else if instance(s_0,Sequence) then new VerticalList from for i in s list + RowExpression {(i#0+d,i#1), ":", MapExpression { target f_i, source f_i, f_i }, ":", i} + else if instance(s_0,ZZ) then return new VerticalList from for i in s list + RowExpression {i+d, ":", MapExpression { target f_i, source f_i, f_i }, ":", i} + ) + +-*net SimplicialModuleMap := Net => f -> ( + v := between("", + for i in sort keys f.map list ( + horizontalJoin( + net ((i#0+f.degree,i#1)), " : ", net target f_i, " <--", + lineOnTop net f_i, + "-- ", net source f_i, " : ", net i + ) + )); + if # v === 0 then net "0" + else stack v + )*- + + net SimplicialModuleMap := Net => f -> ( + v := between("", + for i in sort keys f.map list ( + if instance(i,Sequence) then (horizontalJoin( + net ((i#0+f.degree,i#1)), " : ", net target f_i, " <--", + lineOnTop net f_i, + "-- ", net source f_i, " : ", net i + )) + else (horizontalJoin( + net (i+f.degree), " : ", net target f_i, " <--", + lineOnTop net f_i, + "-- ", net source f_i, " : ", net i + )) + )); + if # v === 0 then net "0" + else stack v + ) + + + From 8b24e46c2a850404eb02fb716b6e49b6224a6c32 Mon Sep 17 00:00:00 2001 From: kellerlv <54511397+kellerlv@users.noreply.github.com> Date: Wed, 13 Aug 2025 22:07:21 -0400 Subject: [PATCH 2/4] Fixed typos --- .../packages/SimplicialModules/SimplicialModuleDOC.m2 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleDOC.m2 b/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleDOC.m2 index 19ac21cb77..d12d98c46b 100644 --- a/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleDOC.m2 +++ b/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleDOC.m2 @@ -6,7 +6,7 @@ doc /// Description Text A simplicial R-module is a presheaf on the so-called Simplex Category, with values in the category of R-modules. Concretely, such objects can be viewed as nonnegatively graded R-modules - equipped with certain face and degeneracy operators satisfying the simplicial identites. As an example, every R-module M can be converted into a simplicial R-module whose degree + equipped with certain face and degeneracy operators satisfying the simplicial identities. As an example, every R-module M can be converted into a simplicial R-module whose degree n piece is equal to M for all n, and with face/degeneracy operators simply given by the identity. Example S = simplicialModule(ZZ^2,3,Degeneracy => true) --the integer 3 specifies a top degree, the option Degeneracy specifies whether or not to compute degeneracy maps @@ -143,7 +143,7 @@ doc /// Description Text A simplicial R-module is a presheaf on the so-called Simplex Category, with values in the category of R-modules. Concretely, such objects can be viewed as nonnegatively graded R-modules - equipped with certain face and degeneracy operators satisfying the simplicial identites. As an example, every R-module M can be converted into a simplicial R-module whose degree + equipped with certain face and degeneracy operators satisfying the simplicial identities. As an example, every R-module M can be converted into a simplicial R-module whose degree n piece is equal to M for all n, and with face/degeneracy operators simply given by the identity. Example S = simplicialModule(ZZ^2,3,Degeneracy => true) --the integer 3 specifies a top degree, the option Degeneracy specifies whether or not to compute degeneracy maps @@ -228,7 +228,7 @@ doc /// The above computations tell us that the component of the face map $d_{2,0}$ mapping $$C_{(1,2)} \to C_{(2)} $$ is given by the differential of the original complex $C$ (we are using the compositions - correponding to the surjection to label the free modules now). The component + corresponding to the surjection to label the free modules now). The component $$C_{(2,1)} \to C_{(1,1)}$$ is simply the identity map, and the component $$C_{(1,1,1)} \to C_{(1,1)}$$ @@ -3530,7 +3530,7 @@ doc /// Q = ZZ/3[a,b]; K = koszulComplex vars Q; prune HH schurMap({2}, K) - prune HH complex sym2(chainComplex K) --quasi-isomorphic in all other characterisics + prune HH complex sym2(chainComplex K) --quasi-isomorphic in all other characteristics --S3K = elapsedTime minimize prune schurMap({3}, K) --takes 23 seconds --S21K = elapsedTime minimize prune schurMap({2,1}, K) --takes 17 seconds --S21K.dd From 30402be3dd02e69f5aaad8dbd54b5426a2b28a80 Mon Sep 17 00:00:00 2001 From: kellerlv <54511397+kellerlv@users.noreply.github.com> Date: Thu, 14 Aug 2025 08:15:07 -0400 Subject: [PATCH 3/4] Bug fix in test 5 (forgot to update old function name) --- .../packages/SimplicialModules/SimplicialModuleTESTS1.m2 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 b/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 index a8405c35b1..5ee2e76fad 100644 --- a/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 +++ b/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 @@ -133,9 +133,9 @@ S = ZZ/101[a..d] I = ideal(a^2-b, c^3) C3 = simplicialModule( I, 7, Degeneracy => true) C4 = simplicialModule( (S/I), 8, Degeneracy => true) - assert isSimplicial C2 - assert isSimplicial C3 - assert isSimplicial C4 + assert isSimplicialModule C2 + assert isSimplicialModule C3 + assert isSimplicialModule C4 C5 = simplicialModule(S^0, 8, Degeneracy => true) assert(C5 == 0) assert (dd^C5 == 0) From c136b1721c382263f4cfc336952c167ef598e4dd Mon Sep 17 00:00:00 2001 From: kellerlv <54511397+kellerlv@users.noreply.github.com> Date: Thu, 14 Aug 2025 18:03:36 -0400 Subject: [PATCH 4/4] Pruned down tests Should now run without taking too much memory --- .../SimplicialModuleTESTS1.m2 | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 b/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 index 5ee2e76fad..a614fc3036 100644 --- a/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 +++ b/M2/Macaulay2/packages/SimplicialModules/SimplicialModuleTESTS1.m2 @@ -598,14 +598,14 @@ S = ZZ/101[a,b,c]; D = C ** C isWellDefined D f1 = prune randomSimplicialMap(D, C, Cycle => true, InternalDegree => 1); - prune normalize f1 - isCommutative oo - isCommutative f1 + g1 = prune normalize f1 + assert(isCommutative g1) + assert(isCommutative f1) assert(degree f1 == 0) - f2 = randomSimplicialMap(D, C, Cycle => true); - isCommutative f2 - assert(degree f2 == 0) - assert isSimplicialMorphism f2 + --f2 = randomSimplicialMap(D, C, Cycle => true); + --isCommutative f2 + --assert(degree f2 == 0) + --assert isSimplicialMorphism f2 /// TEST /// @@ -1128,7 +1128,7 @@ Q = QQ[x_1..x_3]; K = koszulComplex {x_1,x_2} assert isWellDefined (Sc = schurMap({1,1}, K)) prune extPower(2, K) - assert isWellDefined prune schurMap({2,1}, K, TopDegree => 4) + --assert isWellDefined prune schurMap({2,1}, K, TopDegree => 4) /// @@ -1182,7 +1182,7 @@ R = ZZ/101[x_1..x_3]; assert(K == prune Kn) Q = ZZ/3[a,b]; K = koszulComplex vars Q - SK = simplicialModule(K,6) --want top degree 6 since the resulting complexes should have length 6 + SK = simplicialModule(K,4) --want top degree 6 since the resulting complexes should have length 6 w21K = extPower(2, SK) ** SK w3K = extPower(3, SK) H = hashTable for i from 0 to 6 list i => dual wedgeProduct(2,1, dual SK_i); @@ -1191,7 +1191,7 @@ R = ZZ/101[x_1..x_3]; assert isCommutative inclusion Q = ZZ/2[a,b,c] K = koszulComplex vars Q - phi = elapsedTime exteriorInclusion(K,4); --specify top degree 4 + phi = elapsedTime exteriorInclusion(K,3); --specify top degree 3 assert isWellDefined phi assert isCommutative phi ///