newPackage(
	"BGG",
    	Version => "1.4.2", 
    	Date => "Jan 11, 2016",
    	Authors => {
	     {Name => "Hirotachi Abo", Email => "abo@uidaho.edu", HomePage => "http://www.webpages.uidaho.edu/~abo/"},
	     {Name => "Wolfram Decker", Email => "decker@math.uni-sb.de", HomePage => "http://www.math.uni-sb.de/ag/decker/"},
	     {Name => "David Eisenbud", Email => "de@msri.org", HomePage => "http://www.msri.org/~de/"},	     
	     {Name => "Frank-Olaf Schreyer", Email => "schreyer@math.uni-sb.de", HomePage => "http://www.math.uni-sb.de/ag/schreyer/"},
	     {Name => "Gregory G. Smith", Email => "ggsmith@mast.queensu.ca", HomePage => "http://www.mast.queensu.ca/~ggsmith/"},
	     {Name => "Mike Stillman", Email => "mike@math.cornell.edu", HomePage => "http://www.math.cornell.edu/~mike/"}
	     },
    	Headline => "Bernstein-Gelfand-Gelfand correspondence",
	Keywords => {"Commutative Algebra"},
	PackageExports => {"BoijSoederberg"},
	PackageImports => {"Truncations"},
    	DebuggingMode => false
    	)

export {
     "symExt", "bgg", "tateResolution", 
     "beilinson", "cohomologyTable", 
     "directImageComplex", 
     "pureResolution",
     "Regularity", 
     "Exterior",
     "universalExtension",
     "projectiveProduct"
     }

symExt = method()
symExt(Matrix, PolynomialRing) := Matrix => (m,E) ->(
     ev := map(E,ring m,vars E);
     mt := transpose jacobian m;
     jn := gens kernel mt;
     q  := vars(ring m)**id_(target m);
     ans:= transpose ev(q*jn);
     --now correct the degrees:
     map(E^{(rank target ans):1}, E^{(rank source ans):0}, 
         ans));

bgg = method()
bgg(ZZ,Module,PolynomialRing) := Matrix => (i,M,E) ->(
     S :=ring(M);
     numvarsE := rank source vars E;
     ev := map(E,S,vars E);
     f0 := basis(i,M);
     f1 := basis(i+1,M);
     g := ((vars S)**f0)//f1;
     b := (ev g)*((transpose vars E)**(ev source f0));
     --correct the degrees (which are otherwise wrong in the transpose)
     map(E^{(rank target b):i+1},E^{(rank source b):i}, b));

tateResolution = method(TypicalValue => ChainComplex)
tateResolution(Matrix, PolynomialRing, ZZ, ZZ) := ChainComplex => (m,E,loDeg,hiDeg)->(
     M := coker m;
     reg := regularity M;
     bnd := max(reg+1,hiDeg-1);
     mt  := presentation truncate(bnd,M);
     o   := symExt(mt,E);
     --adjust degrees, since symExt forgets them
     ofixed   :=  map(E^{(rank target o):bnd+1},
                E^{(rank source o):bnd},
                o);
     res(coker ofixed, LengthLimit=>max(1,bnd-loDeg+1)));

sortedBasis = (i,E) -> (
     m := basis(i,E);
     p := sortColumns(m,MonomialOrder=>Descending);
     m_p);

beilinson1=(e,dege,i,S)->(
     E := ring e;
     mi := if i < 0 or i >= numgens E then map(E^1, E^0, 0)
           else if i === 0 then id_(E^1)
           else sortedBasis(i+1,E);
     r := i - dege;
     mr := if r < 0 or r >= numgens E then map(E^1, E^0, 0)
           else sortedBasis(r+1,E);
     s := numgens source mr;
     if i === 0 and r === 0 then
          substitute(map(E^1,E^1,{{e}}),S)
     else if i>0 and r === i then substitute(e*id_(E^s),S)
     else if i > 0 and r === 0 then
          (vars S) * substitute(contract(diff(e,mi),transpose mr),S)
     else substitute(contract(diff(e,mi), transpose mr),S));

UU = (i,S) -> (
     if i < 0 or i >= numgens S then S^0
     else if i === 0 then S^1
     else cokernel koszul(i+2,vars S) ** S^{i});

beilinson = method()
beilinson(Matrix,PolynomialRing) := Matrix => (o,S) -> (
     coldegs := degrees source o;
     rowdegs := degrees target o;
     mats := table(numgens target o, numgens source o,
              (r,c) -> (
                   rdeg := first rowdegs#r;
                   cdeg := first coldegs#c;
                   overS := beilinson1(o_(r,c),cdeg-rdeg,cdeg,S);
                   -- overS = substitute(overE,S);
                   map(UU(rdeg,S),UU(cdeg,S),overS)));
     if #mats === 0 then matrix(S,{{}})
     else matrix(mats));


tateToCohomTable = (T) -> (
     C := betti T;
     n := max apply(keys C, (i,d,d1) -> i-d1);
     new CohomologyTally from apply(keys C, (i,d,d1) -> (
	       ((n-(i-d1), -d1), C#(i,d,d1))
	       ))
     )

cohomologyTable = method()
cohomologyTable(CoherentSheaf, ZZ, ZZ) := CohomologyTally => (F,lo,hi) -> (
     M := module F;
     S := ring M;
     e := local e;
     E := (coefficientRing S)[e_0..e_(numgens S-1), SkewCommutative=>true];
     T := tateResolution(presentation M, E, lo, hi);
     tateToCohomTable T
     )
cohomologyTable(Matrix, PolynomialRing, ZZ, ZZ) := CohomologyTally => (m,E,lo,hi) -> (
     T := tateResolution(m, E, lo, hi);
     tateToCohomTable T
     )


-------new 8/11/10 -- DE+MES
--degreeD takes the part of a free module, matrix or chain complex where
--all first components of the degrees of the generators of the
--modules involved are d.

degreeD = method()
degreeD(ZZ,Module) := (d,F) -> (
     -- assume, for now, that F is a free module
     if not isFreeModule F then error "required a free module";
     R := ring F;
     R^(-select(degrees F, e -> e#0 == d))
     )

degreeD(ZZ,Matrix) := (d,m) -> (
     tar := positions(degrees target m, e -> e#0 == d);
     src := positions(degrees source m, e -> e#0 == d);
     submatrix(m, tar, src)
     )

degreeD(ZZ,ChainComplex) := (d, F) -> (
     -- takes the first degree d part of F
     a := min F;
     b := max F;
     G := new ChainComplex;
     G.ring = ring F;
     for i from a to b do
	  G#i = degreeD(d, F#i);
     for i from a+1 to b do (
	  G.dd#i = map(G#(i-1), G#i, degreeD(d, F.dd_i));
	  );
     G
     )
degreeD(ZZ,ChainComplexMap) := (d, f) -> (
     -- takes the first degree d part of f : S --> T
     -- assumption: that min C === min D
     -- returning a new ChainComplexMap
     S := source f;
     T := target f;
     Sd := degreeD(d, S);
     Td := degreeD(d, T);
     a := min(min Sd, min Td);
     b := max(max Sd, max Td);
     map(Td, Sd, i -> (
	       -- need the degree d part of the map from Sd_i --> Td_i
	       degreeD(d, f_i)
	       ))
     )


symmetricToExteriorOverA=method()
symmetricToExteriorOverA(Matrix,Matrix,Matrix):= (m,e,x) -> (
--this function converts between a  presentation matrix m with 
--entries m^i_j of degree deg_x m^i_j = 0 or 1 only 
--of a module over a symmetric algebra A[x] and the linear part of the
--presentation map for the module 
--    P=ker (Hom_A(E,(coker m)_0) -> Hom_A(E,(coker m)_1))
--over the  exterior algebra A<e>.
--                                 Berkeley, 19/12/2004, Frank Schreyer.
     S:= ring x; 
     E:=ring e;
     a:=rank source m;
     La:=degrees source m;
     co:=toList select(0..a-1,i->  (La_i)_0==0);
     M0:=coker substitute(m_co,vars E);
     M:=coker m;
     m1:=presentation (ideal x * M);
-- script uses the fact that the generators of ideal x* M are ordered
---as follows
-- x_0 generators of M,x_1*generators of M, ...
     b:=rank source m1;
     Lb:=degrees source m1;     
     cob:=toList select(0..b-1,i->  (Lb_i)_0==1);
     M1:=coker substitute(m1_cob,vars E);
     F:=substitute(id_(target m),vars E);
     G:=e_{0}**F;
     n:=rank source e -1;
     apply(n,j->G=G|(e_{j+1}**F)); -- (vars E)**F
     phi:=map(M1,M0,transpose G)
     )


symmetricToExteriorOverA(Module) := M -> (
     --M is a module over S = A[x0...].  must be gen in x-degree 0,
     --related in x-degree 1
     S := ring M;
     xvars := vars S;
     A := coefficientRing S;
     if not S.?Exterior then(
	  e := local e;
	  --S.Exterior = exterior alg over A on dual vars to the vars of S (new vars have deg = {-1,0})
	  S.Exterior = A[e_0 .. e_(numgens S - 1), SkewCommutative => true, Degrees=>{numgens S:-1}]
	  );
     E := S.Exterior;
     symmetricToExteriorOverA(presentation M, vars E, vars S)
     )


directImageComplex = method(Options => {Regularity=>null})
directImageComplex Module := opts -> (M) -> (
     S := ring M;
     regM := if opts.Regularity === null then regularityMultiGraded M
          else opts.Regularity;
     if regM < 0 then (M = truncate(0, M); regM = 0);
     degsM := degrees M/first;
     if max degsM > regM then error("regularity is higher than you think!");
     N := if min degsM === regM then M else image basis(regM,M);
     xm := regM * degree(S_0);
     phi := symmetricToExteriorOverA(N ** S^{xm});
     E := ring phi;
     F := complete res( image phi, LengthLimit => max(1,1+regM));
     F = E^{-xm} ** F[regM];
     F0 := degreeD(0, F);
     toA := map(coefficientRing E,E,DegreeMap=> i -> drop(i,1));
     --we should truncate away the terms that are 0, and (possibly) the terms above the (n+1)-st
     F0A := toA F0;
     G := new ChainComplex;
     G.ring = ring F0A;
     n := numgens ring M;
     for i from -n+1 to 1 do(
	  G.dd_i = F0A.dd_i);
     G
     )

RingMap ChainComplexMap := ChainComplexMap => (f,phi) -> map(f target phi, f source phi, i -> f phi_i)

directImageComplex Matrix := opts -> (f) -> (
     -- plan: compute both regularities
     --   if a value is given, then it should be the max of the 2 regularities
     -- 
     S := ring f;
     A := coefficientRing S;
     regMN := if opts.Regularity === null 
              then (
		   regM := regularityMultiGraded source f;
		   regN := regularityMultiGraded target f;
		   max(regM, regN))
	      else opts.Regularity;
     if regMN < 0 then (f = basis(0, f); regMN = 0);
     degsM := degrees (source f)/first;
     if max degsM > regMN then error("regularity is higher than you think!");
     degsN := degrees (target f)/first;
     if max degsN > regMN then error("regularity is higher than you think!");
     truncf := if min degsM === regMN and min degsN === regMN then f else (
        basis(regMN,f));
     M := source truncf;
     N := target truncf;
     StoA := map(A,S,DegreeMap => i -> drop(i,1));
     truncfA := StoA matrix truncf;
     xm := regMN * degree(S_0);
     phiM := symmetricToExteriorOverA(M ** S^{xm});
     phiN := symmetricToExteriorOverA(N ** S^{xm});
     E := ring phiM;
     FM := complete res( image phiM, LengthLimit => max(1,1+regMN));
     FN := complete res( image phiN, LengthLimit => max(1,1+regMN));
     fMN := extend(FN, FM, truncfA ** E);
     fMN = E^{-xm} ** fMN[regMN];
     FM = E^{-xm} ** FM[regMN];
     FN = E^{-xm} ** FN[regMN];
     fMN0 := degreeD(0, fMN);
     EtoA := map(A,E,DegreeMap=> i -> drop(i,1));
--     error("debug");
     EtoA fMN0
     )

--New 10/2010 -- David Eisenbud

directImageComplex ChainComplex := opts -> F -> (
     --The idea is to take the Tate resolutions of th modules
     --in F at a point where they're all linear (beyond all the
     --regularities) and form one map of the double complex
     --there. Then resolve backward and take the degree zero part
     --as usual.

     --at the moment we don't handle the user-supplied regularity
     --option.

     S := ring F;
     A := coefficientRing S;
     StoA := map(A,S,DegreeMap => i -> drop(i,1));

     minF := min F; --lowest index i such that F_i is defined
     maxF := max F; --highest index i such that F_i is defined     
     --could save some work by testing for a complex of zero sheaves here; but it probably doesn't matter.
     
     len := max F-min F; -- number of maps given in F

     modules := apply(toList(minF..maxF), i-> F_i);
     --note: modules_i = F_(minF+i)
     maps := apply(toList(minF+1..maxF), i->F.dd_i);
     --note: maps_i = is the map with TARGET F_(minF+i)

     regF := if opts.Regularity === null 
              then (max apply(modules, 
			M -> regularityMultiGraded M))
	      else opts.Regularity;
     if regF < 0 then regF = 0;

     --at the moment we don't handle the user-supplied regularity
     --option.
     
     --truncate len+1 steps beyond regF. This can be refined a bit.
     truncMaps := apply(len, i -> basis(regF+len+1,maps_i)); -- the maps are now numbered by the module they go TO.
     truncModules := prepend(target truncMaps_0, apply(truncMaps, d->source d));
     mapsA := apply(truncMaps, d->StoA matrix d);
     
     xm := (1+len+regF) * degree(S_0);
     Ediffs := apply(truncModules, M -> 
	  symmetricToExteriorOverA(M ** S^{xm}));
     --note: the sources of Ediffs seem to  be free modules over E
     --generated in degree zero.

     E := ring Ediffs_0;
     EtoA := map(A,E,DegreeMap=> i -> drop(i,1));     

     Ereslen := apply(len+1, i -> complete res( image Ediffs_i, LengthLimit => len+1));
     mapsE := apply(len, i -> map((Ereslen_i)_0, Ereslen_(i+1)_0, mapsA_i ** E));
     FE := apply(len, i -> extend(Ereslen_i, Ereslen_(i+1), mapsE_i));

     Ereslen = apply(Ereslen, EE -> E^{-xm} ** EE[regF+len+1]);     	 
     FE = apply(FE, FEi -> E^{-xm} ** FEi[regF+len+1]);     	 

     E1 := directSum apply(len+1, i-> (Ereslen_i)_(-regF-i));
     CE1 := components E1;

     E0 := directSum apply(len+1, i-> (Ereslen_i)_(-regF-i-1));     
     CE0 := components E0;
          
     D :=  apply(len+1, i-> apply(len+1, j->
	       if j == i   then -((Ereslen_i).dd_(-regF-i)) else 
	       if j == i+1 then ((FE_i)_(-regF-j)) else 
	       map(CE0_i, CE1_j, 0)));
     Dmat := matrix D;
     Eres := complete res(coker Dmat, LengthLimit => max(1,1+regF+len));
     dirIm := (EtoA degreeD(0,Eres))[regF+1-minF];
     --now truncate away the parts below zero and above 
     nonzero := positions(apply(min dirIm..max dirIm, i -> rank dirIm_i != 0), t -> t);
     minDirIm := min nonzero + min dirIm;
     maxDirIm := max nonzero + min dirIm;
--     error(); -- there was an error when the output would be 0. Fixed Jan 29, 2012.
     if minDirIm>maxDirIm then chainComplex{map(A^0, A^0, 0)} else
     chainComplex(apply(minDirIm..maxDirIm, i-> dirIm.dd_i))[-minDirIm+1]
     
     )


regularityMultiGraded = method()
regularityMultiGraded (Module) := (M) -> (
     S := ring M;
     (R,f) := flattenRing S;
     deglen := #degree R_0;
     w := flatten {1,toList(deglen-1:0)};
     regularity (coker f presentation M, Weights=>w)
     )

--FIX -- put in whatever you need on the command line.
     --assumes the existence of
--     kk := ZZ/101;
--     A := kk[x_0..x_(2*d-2)];
--     S := A[y_0,y_1];
universalExtension = method()
universalExtension(List,List) := (La,Lb) -> (
     --Let Fi be the direct sum of line bundles on P1
     --F1 = O(a), F2 = O(b)
     --The script makes a module E representing the bundle that is
     --the universal extension of F2 by F1 on P^1; so the extension is
     --  0 --> F1 --> E --> F2 --> 0.
     --The answer is defined over A[y_0,y_1] representing 
     -- P^1 x Ext(Sheaf F2,Sheaf F1).
     -- The matrix obtained has relations in total degree {c,-1}
     kk := ZZ/101;
     la :=#La;
     lb :=#Lb;
     c := min La;
     N := sum(la, p-> sum(lb, q-> Lb#q-c-1));
     x := local x;
     y := local y;
     A := kk[x_0..x_(N-1)];
     S := A[y_0,y_1];

     m := bblock(Lb,c,S);
     n := ablock(La, Lb, S);
     coker (n||m)
   )

bblock = method()
bblock(ZZ,ZZ, Ring) := (b,c,S) -> map(S^{(b-c):{c+1,-1}}, S^{(b-c-1):{c,-1}}, 
	             (i,j)->
	       if i == j then S_0 else
	       if i == j+1 then S_1 else 0_S
	       )
	  
bblock(List, ZZ,Ring) := (Lb, c, S) ->directSum apply(#Lb, i->bblock(Lb#i, c, S))

ablock = method()
ablock(List, List, Ring) := (La,Lb,S) ->(
     --works over a tower ring S = A[S_0,S_1], where a
     --has at least #La*#Lb variables
     A:=coefficientRing S;
     c := min La;
     offset := 0;
     matrix apply(#La, p->apply(#Lb, q-> (
     	  	    mpq := map(S^{{La#p, 0}}, S^{(Lb#q-c-1):{c, -1}}, (i,j)->(
	       		      sub(A_(offset+j),S)*S_1^(La#p-c))); --was La#q-c
		    offset = offset+Lb#q-c-1;
		    mpq)
     		 ))
     )

--files to produce pure resolutions as direct images of 
--twisted Koszul complexes. Both the sparse sop and arbitrary
--multilinear sop's are implemented.


partitions(ZZ, List) := (k, mm) -> (
     --list of ways of writing k as a sum of #mm
     --non-negative numbers of which the i-th is <=mm_i
     ell := #mm;
     if k<0 or ell <1 then error("needs arguments k,ell with k>=0, ell >0");
     if k == 0 then return {toList(ell:0)};
     if ell == 1 and  k<= mm_(ell-1) then return {{k}};
     if ell == 1 and k>mm_(ell-1) then return{{}}; 
     P := {};
     for i from 0 to min(k,mm_0) do
         P = P | apply(
	      partitions(k-i,drop(mm,1)), 
	               s->prepend(i,s)
		       );
    select(P,p->#p == #mm))

projectiveProduct = method()
projectiveProduct(Ring, List) := (A,D) -> (
     --Takes a list of dimensions D = d_1..d_r
     --and makes the  product 
     --P_A^{d_1}x..xP_A^{d_r} 
     --of projective spaces over the base A, as a tower ring.
     --Returns the tower ring
     --together with a system of multilinear parameters
     --(degree = {1,..,1})
     --for the whole product.
     --The length of the sop is 
     --numgens A + sum D, 1 more than 
     --the projective dimension of the whole product.
     --The sop is formed from the symmetric functions
     --using the functions "partitions" above. (It could
     --also be done putting an appropriate matrix
     --in the next routine.)
     S := A;
     x := local x;
     SList := apply (#D, i->S = S[x_(i,0)..x_(i,D_i)]);
     SList = prepend(A,SList);
     SS := last SList;
     dimList := prepend(numgens A-1, D);
        --now make the parameters
     params := matrix{
	  for k from 0 to sum dimList list(
     P := partitions(k,dimList);
     sum(P, p -> product(#dimList, i->sub(SList_i_(p_i), SS))
	  )
                                           ) 
                     };
     (SS,params)
     )
///
restart
path = prepend( "/Users/david/src/Colorado-2010/PushForward",path)
notify=true
loadPackage("BGG", Reload =>true)
--load "examples2.m2"
dL = {1,1}
dLPlus = dL +splice {#dL:1}
A = kk[vars (0..product(dLPlus)-1)]
L = projectiveProduct (A,dL,Sparse =>false)
betti L_1
transpose L_1

dimList = {1,1}
dimList = {2}
dimList = {0,1}
A = kk[a,b]
L = projectiveProduct (A,dimList)
betti L_1
///

projectiveProduct(Matrix, List) := (M,D) -> (
     --Takes a list D of dimensions
     --and makes the appropriate product of 
     --projective spaces over a base ring A = ring M, as a tower ring.
     --Returns the tower ring
     --together with a system of q linear combinations of
     --the 1...1 forms specified by M, which must
     --have product(D_0+1, .. ,D_r+1) rows (and q columns),
     A := ring M;
     S := A;
     x := local x;
     SList := apply (#D, i->S = S[x_(i,0)..x_(i,D_i)]);
     SList = prepend(A,SList);
     SS := last SList;
   --now make the parameters
     if numrows M != product(D, d->1+d) then
	       error("M has the wrong number of rows");
     N := gens trim product apply(#D, i->
	  promote(ideal vars SList_(i+1), SS));
     params := map(SS^1, 
	  SS^(splice{numcols M:splice{1+#D:-1}}), N*M);
     (SS,params)
     )
///
restart
path = prepend( "/Users/david/src/Colorado-2010/PushForward",path)
notify=true
loadPackage("BGG", Reload =>true)
load "examples2.m2"
dL = {1,1}
q = 3

t = product(dL, i->1+i)
A = kk[vars(0..q*t-1)]

M = genericMatrix(A,A_0,t,q)
L = projectiveProduct (M,dL)
betti L_1
numcols M
///

--Now given a degree list degList, form the corresponding
--product of projective spaces and the Koszul complex over
--it, and take the direct image to get a pure resolution.

pureResolution = method()
pureResolution(Ring, List) := (A, degListOrig) -> (
     n := #degListOrig - 1;
     --normalize the degList to make the first entry zero:
     degList := apply(n+1, i-> degListOrig_i - degListOrig_0);
          
     --check the conditions for a pure resolution:
     if numgens A < n then 
        error("number of vars should be >= (length of list)-1");
     for i from 1 to n do (
	  if degList_i <= degList_(i-1) then 
	      error("list must be strictly increasing")
	      );

     --get ready to form the product of projective spaces
     dimList1 := apply(#degList-1, i->degList_(i+1)-degList_i-1);
     --dimList1 = {m_1..m_n} in the notation of our paper.
     degList1 := degList_{0..n-1};
     --degList1 = {0,d_1,..,d_(n-1)} in the notation of our paper.
     
     --Now drop the terms where m_i = 0
     jumpList := positions(dimList1, i-> i>0);
     dimList := dimList1_jumpList;
     
     twists := {0}|degList1_jumpList;
     --the leading zero corresponds to the base ring A.
     --Note that degList1 already begins with a zero corresponding
     --to the normalized degreeList_0.

     (S,params) := projectiveProduct(A, dimList);
     K := S^{reverse twists}**koszul(params);
     while ring K =!= A do (
	  K = directImageComplex K;
	  S = ring K);
     
     --now restore the zero-th twist of degListOrig
     A^{-degListOrig_0} ** K
     )

pureResolution(Matrix, List) := (M, degListOrig) -> (
     A := ring M;
     n := #degListOrig - 1;
     --normalize the degList to make the first entry zero:
     degList := apply(n+1, i-> degListOrig_i - degListOrig_0);
          
     for i from 1 to n do (
	  if degList_i <= degList_(i-1) then 
	      error("list must be strictly increasing")
	      );

     --get ready to form the product of projective spaces
     dimList1 := apply(#degList-1, i->degList_(i+1)-degList_i-1);
     --dimList1 = {m_1..m_n} in the notation of our paper.
     degList1 := degList_{0..n-1};
     --degList1 = {0,d_1,..,d_(n-1)} in the notation of our paper.
     
     --Now drop the terms where m_i = 0
     jumpList := positions(dimList1, i-> i>0);
     dimList := dimList1_jumpList;
     --check for input errors
     if numrows M != product(dimList, d->d+1) then
     	  error("M has the wrong number of rows");
     
     twists := {0}|degList1_jumpList;
     --the leading zero corresponds to the base ring A.
     --Note that degList1 already begins with a zero corresponding
     --to the normalized degreeList_0.

     --now set up the direct image computation
     (S,params) := projectiveProduct(M, dimList);
     K := S^{reverse twists}**koszul(params);
     while ring K =!= A do (
	  K = directImageComplex K;
	  S = ring K);
     
     --now restore the zero-th twist of degListOrig
     A^{-degListOrig_0} ** K
     )

pureResolution(ZZ, List) := (p, degList) -> (
--a version with the sparse system of parameters, giving
--just the characteristic and letting the program supply the
--ground ring.(Produces module of finite length with the given
--pure resolution type.)
     a := local a;
     kk := if p == 0 then QQ else ZZ/p;
     A := kk[a_0..a_(#degList-2)];
     pureResolution(A, degList)
     )


pureResolution(ZZ,ZZ,List):= (p, q, degList) -> (
     --A version with a generic system of q parameters.     
     --p will be the characteristic, q the number of parameters
     --(the codimension of support, 
     --at least when q is large enough.)
     
     --first compute the number of variables needed:
     dimList1 := apply(#degList-1, i->degList_(i+1)-degList_i-1);
     --dimList1 = {m_1..m_n} in the notation of our paper.
     --Now drop the terms where m_i = 0
     jumpList := positions(dimList1, i-> i>0);
     dL := dimList1_jumpList;
     t := product(dL, i->1+i);
     a := local a;
     kk := if p == 0 then QQ else ZZ/p;
     A := kk[a_0..a_(q*t-1)];
     M := genericMatrix(A,A_0,t,q);
     pureResolution(M, degList)
     )


beginDocumentation()


document {
     Key => BGG, 
     Headline => "Bernstein-Gel'fand-Gel'fand correspondence", 
     "The Bernstein-Gel'fand-Gel'fand correspondence is an isomorphism between the derived category of 
     bounded complexes of finitely generated modules over a polynomial ring and the derived category of 
     bounded complexes of finitely generated module over an exterior algebra (or of certain Tate resolutions). 
     This package implements routines for investigating the BGG correspondence.", 
     PARA {}, 
     "More details can be found in ",  
     HREF("http://www.math.uiuc.edu/Macaulay2/Book/", "Sheaf Algorithms Using Exterior Algebra"), ".", 
     } 
     
document { 
     Key => {symExt,(symExt,Matrix,PolynomialRing)}, 
     Headline => "the first differential of the complex R(M)",
     Usage => "symExt(m,E)",
     Inputs => {
	  "m" => Matrix => "a presentation matrix for a positively graded module M over a polynomial ring",
	  "E" => PolynomialRing => "exterior algebra"
	  },
     Outputs => {
	  Matrix => {"a matrix representing the map ",  TT "M_1 ** omega_E <-- M_0 ** omega_E"}  
	  },
     "This function takes as input a matrix ", TT "m", " with linear entries, which we think of as 
     a presentation matrix for a positively graded ", TT "S", "-module ", TT "M", " matrix representing 
     the map " , TT "M_1 ** omega_E <-- M_0 ** omega_E", " which is the first differential of 
     the complex ", TT "R(M)",    ".", 
     EXAMPLE lines ///
	  S = ZZ/32003[x_0..x_2]; 
	  E = ZZ/32003[e_0..e_2, SkewCommutative=>true];
	  M = coker matrix {{x_0^2, x_1^2}};
	  m = presentation truncate(regularity M,M);
	  symExt(m,E)
     	  ///,
     Caveat => "This function is a quick-and-dirty tool which requires little computation. However 
     if it is called on two successive truncations of a module, then the maps it produces may NOT 
     compose to zero because the choice of bases is not consistent.",   
     SeeAlso => {bgg}
     }

document { 
     Key => {bgg,(bgg,ZZ,Module,PolynomialRing)}, 
     Headline => "the ith differential of the complex R(M)",
     Usage => "bgg(i,M,E)",
     Inputs => {
	  "i" => ZZ => "the cohomological index",
	  "M" => Module => {"graded ", TT "S", "-module"},  
	  "E" => PolynomialRing => "exterior algebra"
	  },
     Outputs => {
	  Matrix => {"a matrix representing the ith differential"}  
	  },
     "This function takes as input an integer ", TT "i", " and a finitely generated graded ", TT "S", 
     "-module ", TT "M", ", and returns the ith map in ", TT "R(M)", ", which is an adjoint 
     of the multiplication map between ", TT "M_i", " and ", TT "M_{i+1}", ".",    
     EXAMPLE lines ///
	  S = ZZ/32003[x_0..x_2]; 
	  E = ZZ/32003[e_0..e_2, SkewCommutative=>true];
	  M = coker matrix {{x_0^2, x_1^2, x_2^2}};
	  bgg(1,M,E)
	  bgg(2,M,E)
     	  ///,
     SeeAlso => {symExt}
     }

document { 
     Key => {tateResolution,(tateResolution, Matrix,PolynomialRing,ZZ,ZZ)}, 
     Headline => "finite piece of the Tate resolution",
     Usage => "tateResolution(m,E,l,h)",
     Inputs => {
	  "m" => Matrix => "a presentation matrix for a module",
	  "E" => PolynomialRing => "exterior algebra",
	  "l" => ZZ => "lower cohomological degree", 
	  "h" => ZZ => "upper bound on the cohomological degree"
	  },
     Outputs => {
	  ChainComplex => {"a finite piece of the Tate resolution"}  
	  },
     "This function takes as input a presentation matrix ", TT "m", " of a finitely generated graded "
     , TT "S", "-module ", TT "M", " an exterior algebra ", TT "E", " and two integers ", TT "l", 
     " and ", TT "h", ". If ", TT "r", " is the regularity of ", TT "M", ", then this function 
     computes the piece of the Tate resolution from cohomological degree ", TT "l", 
     " to cohomological degree ", TT "max(r+2,h)", ". For instance, for the homogeneous 
     coordinate ring of a point in the projective plane:",  
     EXAMPLE lines ///
	  S = ZZ/32003[x_0..x_2]; 
	  E = ZZ/32003[e_0..e_2, SkewCommutative=>true];
	  m = matrix{{x_0,x_1}};
	  regularity coker m
	  T = tateResolution(m,E,-2,4)
	  betti T
	  T.dd_1
     	  ///,
     SeeAlso => {symExt}
     }

document { 
     Key => {cohomologyTable,(cohomologyTable,CoherentSheaf,ZZ,ZZ), (cohomologyTable,Matrix,PolynomialRing,ZZ,ZZ)}, 
     Headline => "dimensions of cohomology groups",
     Usage => "cohomologyTable(F,l,h) or cohomologyTable(m,E,l,h)",
     Inputs => {
	  "F" => CoherentSheaf => "a coherent sheaf on a projective scheme", 
  	  "l" => ZZ => "lower cohomological degree", 
	  "h" => ZZ => "upper bound on the cohomological degree",
	  "m" => Matrix => "a presentation matrix for a module",
	  "E" => PolynomialRing => "exterior algebra"
	   },
     Outputs => {
	  {TO "BoijSoederberg::CohomologyTally", " dimensions of cohomology groups"}  
	  },
     "
     This function takes as input a coherent sheaf ", TT "F", ", two integers ", TT "l", 
     " and ", TT "h", ", and prints the dimension ", 
     TT "dim HH^j F(i-j)", " for ", TT "h>=i>=l", ". As a simple example, we compute the dimensions of cohomology groups 
     of the projective plane.",   
     EXAMPLE lines ///
	  S = ZZ/32003[x_0..x_2]; 
	  PP2 = Proj S; 
	  F =sheaf S^1
          cohomologyTable(F,-10,5)
     	  ///,
     "There is also a built-in sheaf cohomology function ", TO2((cohomology, ZZ, CoherentSheaf), "HH"), " in Macaulay2. 
     However, these algorithms are much slower than ", TT "cohomologyTable", ".",   
     PARA {}, 
     "Alternatively, this function takes as input      
     a presentation matrix ", TT "m", " of a finitely generated graded "
     , TT "S", "-module ", TT "M", "and an exterior algebra ", TT "E", "with the same number of variables. 
     In this form, the function is equivalent to the function ", TT "sheafCohomology", 
     " in ", HREF("http://www.math.uiuc.edu/Macaulay2/Book/", "Sheaf Algorithms Using Exterior Algebra"),  ".",
     EXAMPLE lines ///
	  S = ZZ/32003[x_0..x_2]; 
	  E = ZZ/32003[e_0..e_2, SkewCommutative=>true];
	  m  = koszul (3, vars S); 
	  regularity coker m 
	  betti tateResolution(m,E,-6,2)
          cohomologyTable(m,E,-6,2)
     	  ///,
     PARA {}, 
     "As the third example, we compute the dimensions of cohomology groups of the structure sheaf of an 
     irregular elliptic surface.", 
     EXAMPLE lines /// 
          S = ZZ/32003[x_0..x_4]; 
	  X = Proj S; 
          ff = res coker map(S^{1:0},S^{3:-1,2:-2},{{x_0..x_2,x_3^2,x_4^2}}); 
	  alpha = map(S^{1:-2},target ff.dd_3,{{1,4:0,x_0,2:0,x_1,0}})*ff.dd_3; 
	  beta = ff.dd_4//syz alpha; 
	  K = syz syz alpha|beta;
	  fK = res prune coker K;
	  s = random(target fK.dd_1,S^{1:-4,3:-5});
	  ftphi = res prune coker transpose (fK.dd_1|s);
	  I = ideal ftphi.dd_2;
	  F = sheaf S^1/I; 
	  cohomologyTable(F,-2,6)
     ///, 	  
     SeeAlso => {symExt, tateResolution}
     }

document { 
     Key => {beilinson,(beilinson, Matrix,PolynomialRing)}, 
     Headline => "Vector bundle map associated to the Beilinson monad",
     Usage => "beilinson(m,S)",
     Inputs => {
	  "m" => Matrix => {"a presentation matrix for a module over an exterior algebra ", TT "E"},
	  "S" => PolynomialRing => {"polynomial ring with the same number of variables as ", TT "E"},
	  },
     Outputs => {
	  Matrix => {"vector bundle map"}  
	  },
     "The BGG correspondence is an equivalence between complexes of modules over exterior algebras and complexes 
     of coherent sheaves over projective spaces. This function takes as input a map between two free ", TT "E", "-modules, 
     and returns the associate map between direct sums of exterior powers of cotangent bundles. In particular, it is useful 
     to construct the Belinson monad for a coherent sheaf.",  
     EXAMPLE lines ///
	  S = ZZ/32003[x_0..x_2]; 
	  E = ZZ/32003[e_0..e_2, SkewCommutative=>true];
	  alphad = map(E^1,E^{2:-1},{{e_1,e_2}});
	  alpha = map(E^{2:-1},E^{1:-2},{{e_1},{e_2}});
	  alphad' = beilinson(alphad,S)
	  alpha' = beilinson(alpha,S)
	  F = prune homology(alphad',alpha')
	  betti F
	  cohomologyTable(presentation F,E,-2,3)
     	  ///,
     "As the next example, we construct the monad of the Horrock-Mumford bundle:", 
      	  EXAMPLE lines ///
	  S = ZZ/32003[x_0..x_4]; 
	  E = ZZ/32003[e_0..e_4, SkewCommutative=>true];
	  alphad = map(E^5,E^{2:-2},{{e_4*e_1,e_2*e_3},{e_0*e_2,e_3*e_4},{e_1*e_3,e_4*e_0},{e_2*e_4,e_0*e_1},{e_3*e_0,e_1*e_2}})
	  alpha = syz alphad
	  alphad' = beilinson(alphad,S)
	  alpha' = beilinson(alpha,S)
	  F = prune homology(alphad',alpha');
	  betti res F
	  regularity F
	  cohomologyTable(presentation F,E,-6,6)
     	  ///,
     SeeAlso => {symExt}
     }

doc ///
   Key
     directImageComplex
     [directImageComplex, Regularity]
   Headline
     direct image complex
   Usage
     directImageComplex F
   Description
    Text
      Forms a minimal free complex representing the direct image complex of $F$ in the
      derived category, where $F$ is a module, chain complex or map of modules.
   Caveat
    The option "Regularity" is currently not supported.
///

doc ///
   Key
    Regularity
   Headline
    Option for directImageComplex
   Caveat
    Currently not supported
///
doc ///
   Key
    Exterior
   Headline
    dual exterior algebra cached in a polynomial ring
   Description
    Text
     checked for, and possibly installed, by "symmetricToExterior"
///

doc ///
   Key 
     (directImageComplex, Module)
   Headline
     Complex representing the direct image 
   Usage
     F = directImageComplex M
   Inputs 
     M: Module
       graded over a ring of the form S = A[y_0..y_n], representing a sheaf on $\PP^n_A$,
       where A is a polynomial ring.
     Regularity=>ZZ
       the Castelnuovo-Mumford regularity of {\tt M}.  If not provided, this value will be computed
   Outputs
     F: ChainComplex
       complex of free modules over A. Homology in homological degree -i is 
       $R^i \pi_* {\mathcal M}$, where ${\mathcal M}$ is the sheaf on $\PP^n_A$ represented by M.
   Description
    Text
      The computation is done using the exterior algebra method described by Eisenbud and Schreyer,
      in Eisenbud, David; Schreyer, Frank-Olaf 
      ``Relative Beilinson monad and direct image for families of coherent sheaves.'' 
      Trans. Amer. Math. Soc. 360 (2008), no. 10, 5367--5396.
      
      The computation requires knowing the Castelnuovo-Mumford regularity of M 
      in the variables y_i. If not provided by the user,
      it is computed by the function. The default is Regularity => null, 
      which means it must be computed.
      
      The ring A must be a polynomial ring. For the moment, the module M must be homogeneous
      for the variables of A as well as for the variables of S (bihomogeneous).
      
      It is proven in loc. cit. that every complex of free modules can be realized
      as the direct image of a vector bundle on $\PP^n_A$.
      
      The following example can be used to study the loci in the family of extensions
      of a pair of vector bundles on $\PP^1$ where the extension bundle has a given
      splitting type: this type is calculated by the Fitting ideals of the
      matrices defining the direct image complexes of various twists of the bundle.
      See Section 5 in loc. cite. It is conjectured there that all the sums of
      these Fitting ideals for the universal extension of 
      $\mathcal O_{\PP^1}^{r-1}$ by $\mathcal O_{\PP^1}(d)$ are radical,
      as in the example below.
      
      First we examine the extensions of ${\mathcal O}_{\PP^1}(1)$ by ${\mathcal O}_{\PP^1}(-3)$.
      There is a 3-dimensional vector space 
      $$
      Ext^1({\mathcal O}_{\PP^1}(1),{\mathcal O}_{\PP^1}(-3))
      $$
      of extensions. The ``universal extension'' is thus a bundle on
      $\PP^1\times Ext$. The locus where the extension
      bundle splits as ${\mathcal O}_{\PP^1}(-2) \oplus {\mathcal O}_{\PP^1}$ is the
      locus where the map in the direct image complex drops rank, and this is
      the (cone over a) conic, defined by the determinant of this matrix.
    Example
      M=universalExtension({-3}, {1})
      S = ring M;
      A = coefficientRing S;
      F = directImageComplex M
      F.dd_0
      det (F.dd_0)
    Text
      Here is a larger example, the extension of 
      ${\mathcal O}_{\PP^1}^2$ by ${\mathcal O}_{\PP^1}(6)$
    Example
      r=3;
      d=6;
      M=universalExtension(splice {(r-1):0}, {d})
      S = ring M;
      A = coefficientRing S;
      L = for i from -d to 0 list directImageComplex(S^{{i,0}}**M);
      netList L
      maps = apply(L, F-> F.dd_0)
   SeeAlso 
     universalExtension
     (directImageComplex, Matrix)
///

doc ///
   Key
     (directImageComplex, Matrix)
   Headline
     map of direct image complexes
   Usage
     piF = directImageComplex F
   Inputs
     F:Matrix
       a homomorphism $F : M \rightarrow N$ of graded $S = A[y_0..y_n]$ modules, graded of degree 0,
       where we think of $M$ and $N$ as representing sheaves on $\PP^n_A$
   Outputs
     piF:ChainComplexMap
       the induced map on chain complexes {\tt piF : directImageComplex M --> directImageComplex N}
   Description
    Text
     We give an application of this function to create 
     pure free resolutions. A much more general tool for doing
     this is in the script pureResolution.
     
     A "pure free resolution of type (d_0,d_1,..,d_n)" is a resolution of a graded Cohen-Macaulay
     module M over a polynomial ring such that for each 
     i = 1,..,n, the module of i-th syzygies of M is generated by
     syzygies of degree d_i. Eisenbud and Schreyer constructed
     such free resolutions in all characteristics and for all
     degree sequences $d_0 < d_1 < \cdots < d_n$ by pushing forward
     appropriate twists of a Koszul complex. (The construction
     was known for the Eagon-Northcott complex since work of Kempf). 
     
     If one of the 
     differences $d_{i+1} - d_i$ is equal to 1, then it turns out that one of
     the maps in the pure resolution is part of the map of complexes
     directImageComplex k_j, where k_j is a map in this 
     Koszul complex. Here is a simple example, where we produce
     one of the complexes in the family that included the
     Eagon-Northcott complex (see for example "Commutative Algebra
     with a View toward Algebraic Geometry", by D. Eisenbud.)
    Example
     kk = ZZ/101
     A = kk[u,v,w]
     T = A[x,y]
     params = matrix"ux,uy+vx,vy+wx,wy"
     kn = koszul(4,params)
     D = directImageComplex kn
    Text
     The direct image complexes each have only one nonzero
     term,and so D has only one nonzero component. According
     to Eisenbud and Schreyer, this is the last map in a pure
     resolution. Since the dual of a pure resolution is again
     a resolution, we can simply take the dual of this map
     and resolve to see the dual of the resolution (or dualize
     again to see the resolution itself, which is the Eagon-Northcott
     complex itself in this case.
    Example
     m = transpose D_(-1)
     betti res coker m
     (dual oo)[-3]
   SeeAlso
     directImageComplex
     pureResolution
     universalExtension
///

doc ///
   Key
     (directImageComplex, ChainComplex)
   Headline
     direct image of a chain complex
   Usage
     piC = directImageComplex C
   Inputs
     C:ChainComplex
       over a bigraded ring $S = A[y_0..y_n]$, where $A$ is singly graded
   Outputs
     piC:ChainComplex
       a minimal free complex representing the direct image complex in the derived category
   Description
    Text
     The method is an elaboration of the exterior algebra method for computing cohomology
     discovered by Eisenbud, Floeystad, Schreyer: Sheaf cohomology and free resolutions over
     exterior algebras. Trans. Amer. Math. Soc. (2003).

     We give an application of this function to create generalized Eagon-Northcott complexes,
     discovered by Buchsbaum, Eisenbud, and Kirby, and described in 
     Eisenbud, Commutative Algebra, 1995, section A2.6.  This method can be generalized 
     to produce pure resolutions of any degree sequence.

     These are the complexes associated to a generic 2 by 5 matrix.
    Example
      (p,q) = (2,5) -- number of rows and columns
      A=ZZ/101[a_(0,0)..a_(p-1,q-1)];
      S = A [x_0..x_(p-1)];
      M = sub(map(A^p, A^{q:-1},transpose genericMatrix(A,a_(0,0),q,p)), S)
      Y = map(S^1, S^{q:{-1,-1}}, (vars S)*M)
      F = koszul Y
      L = for i from -1 to q-p+1 list directImageComplex(F**S^{{i,0}});
      L/betti
   Caveat
     This function is not yet functorial, i.e., there is no method to take a map of
     chain complexes and produce the induced map on direct image complexes.
     Additionally, the input ring must be a tower ring with exactly two gradings, and the
     variables must have degree $\{0,1\}$ and $\{1,0\}$
     A later version will remove these restrictions
   SeeAlso
     directImageComplex
///

doc ///
   Key 
     universalExtension
     (universalExtension, List, List)
   Headline
     Universal extension of vector bundles on P^1
   Usage
     E = universalExtension(La, Lb)
   Inputs
     La: List 
       of integers
     Lb: List 
       of integers
   Outputs 
     E: Module 
       representing the extension
   Description
    Text
     Every vector bundle E on $\PP^1$ splits as a sum of line bundles
     OO(a_i). If La is a list of integers, we write E(La) for the direct sum of the
     line bundle OO(La_i).  Given two such bundles specified by the lists
     La and Lb this script constructs a module representing the universal
     extension of E(Lb) by E(La). It is defined on the product variety
     Ext^1(E(La), E(Lb)) x $\PP^1$, and represented here by
     a graded module over the coordinate ring S = A[y_0,y_1] of this variety;
     here A is the coordinate ring of Ext^1(E(La), E(Lb)), which is a polynomial
     ring.
    Example
     M = universalExtension({-2}, {2})
     M = universalExtension({-2,-3}, {2,3})
    Text
     It is interesting to consider the loci in Ext where the extension has
     a particular splitting type. See the documentation for directImageComplex
     for a conjecture about the equations of these varieties.
   SeeAlso
    directImageComplex
///

doc ///
   Key
     pureResolution
     (pureResolution, Ring, List)
     (pureResolution, Matrix, List)     
     (pureResolution, ZZ, List)
     (pureResolution, ZZ, ZZ, List)     
   Headline
     creates a pure resolution as an iterated direct image
   Usage
     F = pureResolution(A, D)
     F = pureResolution(M, D)
     F = pureResolution(p, D)
     F = pureResolution(p,q,D)
   Inputs
     A:Ring
     D:List
     M:Matrix 
       D is a strictly increasing list of integers, the degree sequence
       A is a ring with at least #D-1 variables, the base ring.
       The pure resolution created is the sparse one defined in the
       paper of Eisenbud-Schreyer.
       If M, a matrix over A, is given, then M is used instead
       to construct the resolution (see below).
       If one integer p is given, the program constructs a base ring with the right number of
       variables for the sparse example. If two integers p,q are given, the program
       constructs a base ring of characteristic p and makes a generic system of parameters
       with q elements by taking a generic matrix for M.
   Outputs
     F:ChainComplex
       F will be a pure resolution over A of a module of finite length
       over A, with the desired degree sequence.
       If there are more than #D-1 variables, then a longer resolution
       will be produced, padding the degree sequence at the end
       with consecutive integers.
   Description
    Text
     A "pure free resolution of type (d_0,d_1,..,d_n)" 
     is a resolution of a graded Cohen-Macaulay
     module M over a polynomial ring such that for each 
     i = 1,..,n, the module of i-th syzygies of M is generated by
     syzygies of degree d_i. Eisenbud and Schreyer constructed
     such free resolutions in all characteristics and for all
     degree sequences $d_0 < d_1 < \cdots < d_n$ by pushing forward
     appropriate twists of a Koszul complex. (The construction
     was known for the Eagon-Northcott complex since work of Kempf).

     The script allows several variations including a sparse version 
     and a generic version.
     
     Here is a simple example, where we produce
     one of the complexes in the family that included the
     Eagon-Northcott complex (see for example the appendix in
     "Commutative Algebra with a View toward Algebraic Geometry"
     by D. Eisenbud.) This way of producing the Eagon-Northcott 
     complex was certainly known to George Kempf, who may have invented it.
    Example
     kk = ZZ/101
     A = kk[u,v,w]
     T = A[x,y]
     params = matrix"ux,uy+vx,vy+wx,wy"
     kn = koszul(params)
     directImageComplex kn
    Text
     If we twist the map kn a little before taking the direct image
     we get other complexes in a family that also includes
     the Buchsbaum-Rim complex (see Eisenbud, loc. cit.)
    Example
     for d from -1 to 3 do 
       (print betti directImageComplex (T^{{d,0}}**kn);print())
    Text
     For more complex examples, we use the function 
     {\tt pureResolution}, which creates a Koszul complex over a product of
     projective spaces over a ground ring A and (iteratively) forms the direct image over A.
     In the following
     we specify a ground ring A and a degree sequence.
    Example
     A = kk[a,b,c]
     betti (pureResolution(A,{1,3,4,6}))
    Text
     If one doesn't want to bother creating the ring, it suffices to give the characteristic.
    Example
     betti (F = pureResolution(11,{0,2,4}))
     describe ring F
    Text
     With the form {\tt pureResolution(M,D)}
     It is possible to specify a matrix M of linear forms in the ground ring A that
     defines the parameters used in the Koszul complex whose direct image is taken.
     The matrix M in pureResolution(M,D) 
     should have size product(m_i+1) x q, where
     the m_i+1 are the successive differences of the entries of D that happen to be >1, and
     q >= #D-1+sum(m_i).(The m_i are the dimensions of the projective spaces from whose product
     we are projecting.)
    Example
     A = kk[a,b]
     M = random(A^4, A^{4:-1})
     time betti (F = pureResolution(M,{0,2,4}))
    Text
     With the form {\tt pureResolution(p,q,D)}
     we can directly create the situation of {\tt pureResolution(M,D)} where M is
     generic 
     product(m_i+1) x #D-1+sum(m_i) 
     matrix of linear forms defined over a ring with product(m_i+1) * #D-1+sum(m_i) 
     variables of characteristic p, created by the script. For a given number of
     variables in A this runs much faster than taking a random matrix M.
    Example
     time betti (F = pureResolution(11,4,{0,2,4}))
     ring F
   SeeAlso
     directImageComplex
     universalExtension
///



doc ///
   Key 
     projectiveProduct
     (projectiveProduct, Ring, List)
     (projectiveProduct, Matrix, List)
   Headline
     Makes a product of projective spaces and a system of parameters
   Usage
     (S, params) = projectiveProduct(A,dimList)
   Inputs 
     A: Ring
     dimList: List
       A the desired base ring. dimList a list of dimensions {d1..dn}
   Outputs
     S: Ring
     params: Matrix
       S is the iterated tower ring A[x_(0,0)..x_(0,d1)]..[..x_(n,dn)] representing the product
       P_A^{d1} x ..x P_A^{dn}, where the products are relative to A, and params is a system
       of multilinear forms in S. They are sparse if M is not present, or determined by M
       if it is.
   SeeAlso 
     pureResolution
///


TEST///
          S = ZZ/32003[x_0..x_2]; 
	  E = ZZ/32003[e_0..e_2, SkewCommutative=>true];
	  M = coker matrix {{x_0^2, x_1^2}};
	  m = presentation truncate(regularity M,M);
	  assert(symExt(m,E)==map(E^{{1}, {1}, {1}, {1}},E^4,{{e_2, 0, 0, 0}, {e_1, e_2, 0, 0}, {e_0, 0, e_2, 0}, {0, e_0, e_1, e_2}}))
///

TEST///
          S = ZZ/32003[x_0..x_2]; 
	  E = ZZ/32003[e_0..e_2, SkewCommutative=>true];
	  M = coker matrix {{x_0^2, x_1^2, x_2^2}};
	  assert(bgg(1,M,E)==map(E^{3:2},,{{e_1, e_0, 0}, {e_2, 0, e_0}, {0, e_2, e_1}}))
///
TEST///	  
	  S = ZZ/32003[x_0..x_2]; 
	  E = ZZ/32003[e_0..e_2, SkewCommutative=>true];
	  m = matrix{{x_0,x_1}};
	  regularity coker m
	  T = tateResolution(m,E,-2,4)
          assert(toList(7:1) == apply(length T+1, i-> rank T#i))
	  assert(all(toList(1..length T), i-> (matrix entries T.dd_i)==matrix {{e_2}}))
///
TEST /// 
	  S = ZZ/32003[x_0..x_2]; 
	  PP2 = Proj S; 
	  F =sheaf S^1
          C = cohomologyTable(F,-10,5)
	  assert(values C == apply(keys C, p -> rank HH^(p#0)(F(p#1))))
///
TEST /// 	  
	  S = ZZ/32003[x_0..x_2]; 
	  E = ZZ/32003[e_0..e_2, SkewCommutative=>true];
	  alphad = map(E^1,E^{2:-1},{{e_1,e_2}})
          assert(matrix entries beilinson(alphad,S) == matrix {{x_0, 0, -x_2, 0, x_0, x_1}})
          alpha = map(E^{2:-1},E^{1:-2},{{e_1},{e_2}});
	  assert(matrix entries beilinson(alpha,S) ==  map(S^6,S^1,{{0}, {1}, {0}, {-1}, {0}, {0}}))
///


TEST ///
  R = ZZ/101[x,y]
  M = R^{4}
  C = directImageComplex M
  assert(C^1 == 0)
  assert(rank C^0 == 5)
  assert(C^-1 == 0)
///

TEST ///
  R = ZZ/101[x,y]
  M = R^{-4}
  C = directImageComplex M
  assert(rank C^1 == 3)
  assert(C^0 == 0)
  assert(C^-1 == 0)
///

TEST ///
  R = ZZ/101[x,y]
  M = R^{0}
  C = directImageComplex M
  assert(C^1 == 0)
  assert(rank C^0 == 1)
  assert(C^-1 == 0)
///

TEST ///
  needsPackage "ChainComplexExtras"
  kk = ZZ/101
  A = kk[a]
  S = A[x,y]
  M1 = S^{{-1,0},{0,0}}
  C1 = directImageComplex(id_M1)
  assert(C1_0 == 1)
  assert isChainComplexMap C1

  M2 = S^{{-1,0}}
  C2 = directImageComplex(id_M2)
  assert isChainComplexMap C2
  assert(C2_0 == 0)

  M3 = S^{{-2,0}}
  C3 = directImageComplex(id_M3)
  assert isChainComplexMap C3
  assert(C3_0 == 0)
///

TEST///
  (p,q) = (2,5)
  kk = ZZ/101
  A=kk[a_(0,0)..a_(p-1,q-1)]
  S = A [x_0..x_(p-1)]
  M = sub(map(A^p, A^{q:-1},transpose genericMatrix(A,a_(0,0),q,p)), S)

  Y = map(S^1, S^{q:{-1,-1}}, (vars S)*M)
  F = koszul Y
  L = directImageComplex(F**S^{{2,0}})
  ans = new BettiTally from {(0,{0},0) => 3, (3,{4},4) => 5, 
       (1,{1},1) => 10, (4,{5},5) => 2,
       (2,{2},2) => 10};
  assert(betti L == ans)
///

-*
--I don't see why the following doesn't work. The output of the left side sure LOOKS like that on the right
TEST///
A = ZZ/11[a,b]
(projectiveProduct(A,{1,1}))_0 === A[x_(0,0), x_(0,1)][x_(1,0), x_(1,1)]
///
*-

TEST///
A = QQ[a,b]
betti pureResolution(A,{0,2,4}) == new BettiTally from {(0,{0},0) => 3, (1,{2},2) => 6, (2,{4},4) => 3}
betti pureResolution(11,{0,2,4})== new BettiTally from {(0,{0},0) => 3, (1,{2},2) => 6, (2,{4},4) => 3}
betti pureResolution(2,{1,2,4})==new BettiTally from {(0,{1},1) => 2, (1,{2},2) => 3, (2,{4},4) => 1}
betti pureResolution(2,3,{1,2,4})
///
end

restart
uninstallPackage "BGG"
installPackage "BGG"
check "BGG"
viewHelp BGG
