--------------------------------------------------------------------
-- documentation for chain complexes -------------------------------
--------------------------------------------------------------------

-*
        Text
            The major change is replacing the @TO ChainComplex@ data type with @TO Complex@.
            The internal structure of this new data type is somewhat different, but more
            importantly, it has a richer set of constructors.  Use the functions
            @TO (complex, ChainComplex)@, @TO (complex, ChainComplexMap)@, @TO (chainComplex, Complex)@, @TO (chainComplex, ComplexMap)@, 
            to translate between these representations.
*-

doc ///
    Key
        Complexes
    Headline
        development package for beta testing new version of chain complexes    
    Description
        Text
            This package develops new data types and routines for homological algebra.
            Eventually, it will replace the current facilities for homological algebra.
            We are making this available in order to get feedback from users before
            making this change.  Please email the authors with any and all comments or
            suggestions.
        Text
            The overarching goal is to make all of the homological algebra routines functorial.
            For instance, we have @TO2(canonicalMap, "canonical maps")@ associated to kernels,
            cokernels, images, coimages, cones, and cylinders.
    SeeAlso
        "Making chain complexes"
        "Making maps between chain complexes"
        "Basic invariants and properties"
        "Working with Ext"
        "Working with Tor"
        "Towards computing in the derived category"
///

doc ///
    Key
        "Making chain complexes"
    Headline
        information about the basic constructors
    Description
    	Text
    	    @SUBSECTION "Basic constructors"@
	Text
    	    @UL {
                TO (complex, HashTable),
                TO (complex, List),
                TO (complex, Module), 
                TO (complex, Complex),
                TO (symbol SPACE, Complex, Array),
                TO (isWellDefined, Complex)
            }@
    	Text
    	    @SUBSECTION "Important computations creating new complexes"@
	Text
    	    @UL {
                TO (freeResolution, Module),
                TO (resolution, Complex),
                TO (homology, Complex)
            }@
    	Text
    	    @SUBSECTION "More advanced constructors"@
	Text
    	    @UL {
                TO (symbol++, Complex, Complex),
                TO (symbol**, Complex, Complex),
                TO (Hom, Complex, Complex),
                TO (dual, Complex),
                TO (symbol SPACE, RingMap, Complex),
                TO (symbol **, RingMap, Complex),
                TO (koszulComplex, Matrix),
                TO (naiveTruncation, Complex, ZZ, ZZ),
                TO (canonicalTruncation, Complex, ZZ, ZZ),
                TO (minimalPresentation, Complex),
                TO (minimize, Complex),
                TO (gradedModule, Complex),
                TO (part, List, Complex),
                TO (truncate, List, Complex),
                TO (yonedaExtension, Matrix)
            }@
    	Text
    	    @SUBSECTION "Extracting complexes from complex maps"@
        Text
    	    @UL {
                TO (source, ComplexMap),
                TO (target, ComplexMap),
                TO (kernel, ComplexMap),
                TO (cokernel, ComplexMap),
                TO (image, ComplexMap),
                TO (coimage, ComplexMap),
                TO (cone, ComplexMap),
                TO (cylinder, ComplexMap)
            }@
    SeeAlso
        "Making maps between chain complexes"
        "Basic invariants and properties"
        "Working with Ext"
        "Working with Tor"
        "Towards computing in the derived category"
///

doc ///
    Key
        "Basic invariants and properties"
    Headline
        information about accessing basic features
    Description
    	Text
    	    @SUBSECTION "Predicates for complexes and complex maps"@
        Text
    	    @UL {
                TO (isWellDefined, Complex),
                TO (isExact, Complex),
                TO (isHomogeneous, Complex),
                TO (isFree, Complex),
                TO (isShortExactSequence, Complex),
                TO (isWellDefined, ComplexMap),
                TO (isCommutative, ComplexMap),
                TO (isComplexMorphism, ComplexMap),
                TO (isQuasiIsomorphism, ComplexMap),
                TO (isShortExactSequence, ComplexMap, ComplexMap),
                TO (isNullHomotopic, ComplexMap),
                TO (isNullHomotopyOf, ComplexMap, ComplexMap)
            }@
    	Text
    	    @SUBSECTION "Other invariants for complexes"@
        Text
    	    @UL {
                TO (ring, Complex),
                TO (concentration, Complex),
                TO (max, Complex),
                TO (min, Complex),
                TO (length, Complex),
                TO (regularity, Complex),
                TO (betti, Complex),
                TO (poincare, Complex),
                TO (poincareN, Complex),
                TO (components, Complex)
            }@
    	Text
    	    @SUBSECTION "Other invariants for complex maps"@
        Text
    	    @UL {
                TO (source, ComplexMap),
                TO (target, ComplexMap),
                TO (degree, ComplexMap),
                TO (ring, ComplexMap),
                TO (concentration, ComplexMap),
                TO (isHomogeneous, ComplexMap),
                TO (components, ComplexMap),
            }@
    SeeAlso
        "Making chain complexes"
        "Making maps between chain complexes"
        "Working with Ext"
        "Working with Tor"
        "Towards computing in the derived category"
///

doc ///
    Key
        "Working with Ext"
    Headline
        information about functorial properties
    Description
    	Text
    	    @SUBSECTION "Hom and Ext"@
        Text
    	    @UL {
                TO (Ext, ZZ, Module, Module),
                TO (Ext, ZZ, Matrix, Module),
                TO (Ext, ZZ, Module, Matrix),
                TO (Hom, Complex, Complex),
                TO (Hom, ComplexMap, ComplexMap),
                TO (homomorphism, ComplexMap),
                TO (homomorphism', ComplexMap),
                TO (connectingExtMap, Module, Matrix, Matrix)
            }@
        Text
    	    @SUBSECTION "Yoneda extensions and elements of Ext"@
        Text
    	    @UL {
                TO (yonedaMap, Matrix),
                TO (yonedaMap', ComplexMap),
                TO (yonedaExtension, Matrix),
                TO (yonedaExtension', Complex),
                TO (yonedaProduct, Matrix, Matrix),
                TO (yonedaProduct, Module, Module)
            }@
    SeeAlso
        "Making chain complexes"
        "Making maps between chain complexes"
        "Basic invariants and properties"
        "Working with Tor"
        "Towards computing in the derived category"
///

doc ///
    Key
        "Working with Tor"
    Headline
        information about functorial properties
    Description
        Text
    	    @UL {
                TO (Tor, ZZ, Module, Module),
                TO (Tor, ZZ, Module, Matrix),
                TO (Tor, ZZ, Matrix, Module),
                TO (tensor, Complex, Complex),
                TO (tensor, ComplexMap, ComplexMap),
                TO (tensorCommutativity, Complex, Complex),
                TO (tensorAssociativity, Complex, Complex, Complex),
                TO (torSymmetry, ZZ, Module, Module),
                TO connectingTorMap
            }@
    SeeAlso
        "Making chain complexes"
        "Making maps between chain complexes"
        "Basic invariants and properties"
        "Working with Ext"
        "Towards computing in the derived category"
///

--------------------------------------------------------------------
-- chain complexes -------------------------------------------------
--------------------------------------------------------------------
doc ///
    Key
        Complex
    Headline
        the class of all chain complexes
    Description
        Text
            A complex is a sequence of objects $C_i$, connected by
            maps $dd^C_i : C_i \rightarrow C_{i-1}$ such that the
            composition of any two consecutive maps is zero.

            TODO: more needs to be added here explaining how to used complexes.
            and links to "landing pages".
///

doc ///
    Key
        (ring, Complex)
        (ring, ComplexMap)
    Headline
        access the ring of a complex or a complex map
    Usage
        ring C
    Inputs
        C:Complex
            or a @TO "ComplexMap"@
    Outputs
        :Ring
    Description
        Text
            Every complex or complex map has a base ring.  This
            function access that information.
        Example
            S = ZZ/101[a,b,c,d];
            C = 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
        concentration
        (concentration, Complex)
        (max, Complex)
        (min, Complex)
    Headline
        indices on which a complex may be non-zero
    Usage
        (lo,hi) = concentration C
    Inputs
        C:Complex
    Outputs
        lo:ZZ
        hi:ZZ
            a pair of integers {\tt lo}, {\tt hi} such that {\tt C_i = 0}
            for {\tt i < lo} or {\tt i > hi}.
    Description
        Text
            In this package, each complex has a concentration {\tt (lo, hi)} 
            such that {\tt lo <= hi}.  When {\tt lo <= i <= hi}, the module
            {\tt C_i} might be zero.  The methods {\tt max} and {\tt min} 
            applied to the complex {\tt C} return {\tt lo} and {\tt hi}, respectively.
      
            This function is mainly used in programming, to loop over all
            non-zero modules or maps in the complex.  This should not be confused
            with the support of a complex.
        Example
            S = ZZ/101[a..c];
            C = freeResolution coker vars S
            concentration C
            D = C ++ C[5]
            concentration D
            min D
            max D
            assert((min D, max D) === concentration D)
        Text
            Indices that are outside of the concentration automatically
            return the zero object.
        Example
            C_-1
            D_4
        Text
            The function {\tt concentration} does no computation.
            To eliminate extraneous zeros, use @TO (prune, Complex)@.
        Example
            f1 = a*id_C  
            E = ker f1
            concentration E
            concentration prune E
        Text
            The concentration of a zero complex can be arbitrary, however,
            after pruning, its concentration will be {\tt (0,0)}.
        Example      
            C0 = (complex S^0)[4]
            concentration C0
            prune C0
            concentration oo
    SeeAlso
        "Basic invariants and properties"
        (symbol _, Complex, ZZ)
        (concentration, ComplexMap)
///

doc ///
    Key
        Concentration
    Headline
        optional argument used to specify the concentration
    Description
        Text
            In this package, each complex $C$ has a concentration
            $(\ell, h)$ such that $\ell \leq h$.  For all $i < \ell$
            and all $i > h$, the term $C_i$ is zero.  When $\ell \leq
            i \leq h$, the module $C_i$ may or may not be zero.
        Text
            Several methods use this optional argument to specify the 
            concentration of their outputs.
    SeeAlso
        (concentration, Complex)
///

doc ///
    Key
        (complex, HashTable)
    Headline
        make a chain complex
    Usage
        complex H
    Inputs
        H:HashTable
            each key is an integer indexing a differential, and the 
            value at that key is the map
        Base => ZZ
            ignored when the input is a hash table
    Outputs
        :Complex
    Description
        Text
            A complex is a sequence of objects (e.g. modules),
            connected by maps called differentials.  The composition
            of any two consecutive maps is zero.
      
            The same data type is used for both chain and cochain
            complexes.  If {\tt C} is a complex, then we have 
            {\tt C^i = C_{-i}}.

            We construct the Koszul complex on the generators for the
            ideal of the twisted cubic curve.
        Example
            S = ZZ/101[a..d]
            I = ideal(b^2-a*c, b*c-a*d, c^2-b*d)
            F1 = map(S^1,,matrix{{I_0, I_1, I_2}})
            F2 = map(source F1,,matrix{
                    {0, I_2, -I_1},
                    {-I_2, 0, I_0},
                    {I_1, -I_0, 0}
                    })
            F3 = map(source F2,,matrix{{I_0}, {I_1}, {I_2}})
            C = complex hashTable{1 => F1, 2 => F2, 3 => F3}
            isWellDefined C
        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 complex
        is well constructed, use @TO (isWellDefined, Complex)@.
    SeeAlso
        "Making chain complexes"
        (isWellDefined, Complex)
        (complex, List)
        (complex, Module)
///

doc ///
    Key
        complex
        (complex, List)
        [complex, Base]
        Base
    Headline
        make a chain complex
    Usage
        complex L
    Inputs
        L:List
            of maps
        Base => ZZ
            the index of the target of the first map 
            in the differential.
    Outputs
        :Complex
    Description
        Text
            A complex is a sequence of objects (e.g. modules),
            connected by maps called differentials.  The composition
            of any two consecutive maps is zero.
      
            The same data type is used for both chain and cochain
            complexes.  If {\tt C} is a complex, then we have
            {\tt C^i = C_{-i}}.

            Often, a complex is most easily described by giving a list
            of consecutive maps which form the differential.

            We construct the Koszul complex on the generators for the
            ideal of the twisted cubic curve.
        Example
            S = ZZ/101[a..d]
            I = ideal(b^2-a*c, b*c-a*d, c^2-b*d)
            F1 = map(S^1,,matrix{{I_0, I_1, I_2}})
            F2 = map(source F1,,matrix{
                    {0, I_2, -I_1},
                    {-I_2, 0, I_0},
                    {I_1, -I_0, 0}
                    })
            F3 = map(source F2,,matrix{{I_0}, {I_1}, {I_2}})
            C = complex {F1, F2, F3}
            isWellDefined C
        Text
            To start a complex at a base different from zero, use the
            optional argument {\tt Base}.
        Example
            C1 = complex({F1, F2, F3}, Base => 1)
            isWellDefined C1
        Text
            Notice that this changes the homological degrees of the
            maps, but is not the same as the shift of the complex
            (which for odd shifts negates the maps).
        Example
            dd^C1
            dd^(C[-1])
        Text
            Having constructed this complex, we can access individual
            terms and maps.
        Example
            C_2
            C^(-1)
            C^(-1) == C_1
            C_7
            dd^C
            dd^C_2
            length C
        Text
            By computing the homology of this complex, we see that
            these generators do not form a regular sequence, because
            $H_1(C)$ is non-zero.
        Example
            HH C
            prune HH C
            prune HH_1 C
    Caveat
        This constructor minimizes computation
        and does very little error checking. To verify that a complex
        is well constructed, use @TO (isWellDefined, Complex)@.
    SeeAlso
        "Making chain complexes"
        (isWellDefined, Complex)
        (complex, HashTable)
        (complex, Module)
        (symbol SPACE, Complex, Array)
///

doc ///
    Key
        (complex, Module)
        (complex, Ideal)
        (complex, Ring)
    Headline
        make a chain complex of length zero
    Usage
        complex M
    Inputs
        M:Module
            or @TO "Ideal"@, or @TO "Ring"@.
        Base => ZZ
            index for {\tt M}
    Outputs
        :Complex
            returns the complex whose 0-th component is {\tt M}.
    Description
        Text
            In contrast to @TO (complex,HashTable)@ and @TO
            (complex,List)@, this constructor provides a convenient
            method to construct a complex with only one non-zero
            component.
      
            We illustrate this with a free module.
        Example
            S = ZZ/101[a..d]
            C0 = complex S^2
            f = dd^C0
            source f, target f
            f == 0
            isWellDefined C0
            C0 == 0
            length C0
        Example
            C1 = complex(S^2, Base=>3)
            C1 == C0[-3]
            C1_3
            C1_0
        Text
            A ring or an ideal will be converted to a module first.
        Example
            C2 = complex S
            I = ideal(a^2-b, c^3)
            C3 = complex I
            C4 = complex (S/I)
            (ring C3, ring C4)
        Text
            The zero complex over a ring {\tt S} is most conveniently
            created by giving the zero module.
        Example
            C5 = complex S^0
            C5 == 0
            dd^C5 == 0
            C5_0
    SeeAlso
        "Making chain complexes"
        (isWellDefined, Complex)
        (complex, HashTable)
///

doc ///
    Key
        (complex, Complex)
    Headline
        make a complex by reindexing the terms of the complex
    Usage
        D = complex(C, Base => i)
    Inputs
        C:Complex
        Base => ZZ
            the target of the lowest differential
    Outputs
        D:Complex
            where if $d$ is the smallest index of the target of the
            differentials of C, then for all integers $j$ we have
            $D_{i+j} = C_{d+j}$
    Description
        Text
            This returns an alteration of the input complex,
            reindexing the terms of the complex.
        Example
            S = ZZ/101[a..d]
            C = freeResolution coker vars S
            D = complex(C, Base => 1)
            E = complex(D, Base => -11)
            dd^D_2 == dd^C_1
            dd^E_-9 == dd^C_2
        Text
            Rather than specifying the homological degree of the
            lowest target, one can also shift the homological degree,
            which may simultaneously negate the maps.
        Example
            F = C[-1]
            for i from min F to max F list
                dd^F_i == - dd^D_i
    SeeAlso
        "Making chain complexes"
        (isWellDefined, Complex)
        (complex, HashTable)
        (complex, List)
        (symbol SPACE, Complex, Array)
///

doc ///
    Key
        (complex, ComplexMap)
    Headline
        make a complex by specifying the differential
    Usage
        C = complex d
    Inputs
        d:ComplexMap
        Base => ZZ
            unused
    Outputs
        C:Complex
            whose differential is $d$
    Description
        Text
            Given a map $d$ of complexes having degree -1 and whose source 
            and targets are equal, this method constructs the chain complex
            whose differential is $d$.  This constructor does not verify that
            $d^2 = 0$.
        Example
            S = ZZ/101[x_1..x_4];
            F = freeResolution coker vars S
            d = randomComplexMap(F, F, Cycle => true, InternalDegree => -1, Degree => -1)
            d^2
            C = complex d
            assert isWellDefined C
            assert all(0..4, i -> dd^C_i == d_i)
        Example
            e = randomComplexMap(F, F, InternalDegree => -1, Degree => -1)
            D = complex e
            debugLevel = 1
            assert not isWellDefined D
    SeeAlso
        "Making chain complexes"
        (isWellDefined, Complex)
        (complex, HashTable)
        (complex, List)
///

-- TODO: Add programming details
doc ///
   Key
     (isWellDefined, Complex)
   Headline
     whether a complex is well-defined
   Usage
     isWellDefined C
   Inputs
     C:Complex
   Outputs
     :Boolean
       that is true when {\tt C} determines a well defined complex
   Description
    Text
      This routine checks that the differential of {\tt C} composes to zero.
      Additionally, it checks that the underlying data in {\tt C} is a properly formed
      Complex 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 by hand the free resolution of the twisted
      cubic.  One must work with maps rather than matrices, because the source and the target
      of adjacent maps must be the same (including degree information).
    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 = complex {f0, f1}
      isWellDefined C
      dd^C
      (dd^C)^2
    Text
      The zero complex is well-defined.
    Example
      C = complex R^0
      isWellDefined C
    Text
    
      The next example demonstrates the case when the sequence maps do not compose to 0.
    Example
      g1 = map(source f0,, {{-d, c}, {c, b}, {b, a}})
      C = complex {f0, g1}
      isWellDefined C
      debugLevel = 1
      isWellDefined C
      (dd^C)^2
   SeeAlso
     (isWellDefined, ComplexMap)
     map
///

doc ///
   Key
     (symbol _, Complex, ZZ)
     (symbol ^, Complex, ZZ)
   Headline
     access individual object in a complex
   Usage
     C_i
     C^i
   Inputs
     C:Complex
     i:ZZ
       either the homological or cohomological index
   Outputs
     :Module
       the {\tt i}-th object
   Description
    Text
       Complexes can be either chain complexes or cochain complexes.  Subscripts
       refer to homological indices, and superscripts refer to
       cohomological indices.
     
       In this package homological indices are used by default.  For
       example, the @TO "concentration"@ references homological indices.
       Nevertheless, we always have the equation $C^i = C_{-i}$.
    Example
      S = ZZ/101[a..c]
      C = freeResolution coker vars S
      C_2
      C^(-2)
      C_2 == C^(-2)
    Text
      Indices that are outside of the concentration automatically
      return the zero object.
    Example
      C_-7
   SeeAlso
///

doc ///
   Key
     (symbol ==, Complex, Complex)
     (symbol ==, Complex, ZZ)
     (symbol ==, ZZ, Complex)
   Headline
     whether two complexes are equal
   Usage
     C == D
     C == 0
   Inputs
     C:Complex
     D:Complex
   Outputs
     :Boolean
       that is true when {\tt C} and {\tt D} are equal
   Description
    Text
      Two complexes are equal if the corresponding 
      objects and corresponding maps at each index are equal.
    Example
      S = ZZ/101[a..c]
      C = freeResolution coker vars S
      D = C[3][-3]
      C === D
      C == D
    Text
      Both the maps and the objects must be equal.
    Example
      (lo,hi) = concentration C
      E = complex for i from lo+1 to hi list 0*dd^C_i
      dd^E
      C == E
      E == 0
    Text
      A complex 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 = complex S^0
      C1 = C0[4]
      concentration C0 == concentration C1
      C0 == C1
      C0 == 0
      C1 == 0
    Text
      Testing for equality is not the same testing for isomorphism.
      In particular, different presentations of a complex need not be equal.
    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 = complex {f0, f1}
      HH C != complex coker f0
      prune HH C == complex coker f0
   Caveat
   SeeAlso
///

doc ///
    Key
        "differential of a chain complex"
        (symbol^, Symbol, Complex)
    Headline
        get the maps between the terms in a complex
    Usage
        dd^C
        dd_C
    Inputs
        C:Complex
    Outputs
        :ComplexMap
            a map of degree -1
    Description
        Text
            A chain complex is a sequence of modules connected
            by homomorphisms, called differentials, such that
            the composition of any two consecutive maps is zero.
        Text
            One can access the differential of a complex as follows.
        Example
            R = QQ[a..d];
            I = ideal(a*d-b*c, b^2-a*c, c^2-b*d);
            C = freeResolution(R^1/I)
            dd^C
            C.dd
            assert(dd^C === C.dd)
            assert(source dd^C === C)
            assert(target dd^C === C)
            assert(degree dd^C === -1)
        Text
            The composition of the differential with itself is zero.
        Example
            (dd^C)^2 == 0
        Text
            The individual maps between terms are indexed by their
            source.
        Example
            dd^C_2
            assert(source dd^C_2 === C_2)
            assert(target dd^C_2 === C_1)
    SeeAlso
        "Making maps between chain complexes"
        (symbol_, ComplexMap, ZZ)
        (symbol_, Complex, ZZ)
        (source, ComplexMap)
        (target, ComplexMap)
        (degree, ComplexMap)
///

doc ///
   Key
     (symbol SPACE, Complex, Array)
     (symbol SPACE, ComplexMap, Array)
   Headline
     shift a complex or complex map
   Usage
     D = C[i]
     g = f[i]
   Inputs
     C:Complex
       or {\tt f}, a @TO ComplexMap@
     :Array
       {\tt [i]}, where {\tt i} is an integer
   Outputs
     D:Complex
       or {\tt g}, a @TO ComplexMap@.
   Description
    Text
      The shifted complex $D$ is defined by $D_j = C_{i+j}$ for all $j$
      and the sign of the differential is changed if $i$ is odd.
       
      The shifted complex map $g$ is defined by $g_j = f_{i+j}$ for all $j$.
    
      The shift defines a natural automorphism on the category of complexes. 
      Topologists often call the shifted complex $C[1]$ the {\it suspension} of $C$.
    Example
      S = ZZ/101[a..d]
      C = freeResolution coker vars S
      dd^C_3
      D = C[1]
      assert isWellDefined D
      assert(dd^D_2 == -dd^C_3)
    Text
      In order to shift the complex one step, and not change the differential, one
      can do the following.
    Example
      E = complex(C, Base => -1)
      assert isWellDefined E
      assert(dd^E_2 == dd^C_3)
    Text
      The shift operator is functorial, as illustrated below.
    Example
      C2 = freeResolution (S^1/(a^2, b^2, c^2, d^2))
      C3 = freeResolution (S^1/(a^2, b^3, c^4, d^5))
      f2 = extend(C, C2, map(C_0, C2_0, 1))
      f3 = extend(C2, C3, map(C2_0, C3_0, 1))
      assert((f2*f3)[1] == (f2[1]) * (f3[1]))
      assert(source(f2[1]) == C2[1])
      assert(target(f2[1]) == C[1])
   SeeAlso
     concentration
     (complex, Complex)
     (extend, Complex, Complex, Matrix)
///

doc ///
    Key
        (gradedModule, Complex)
    Headline
        a new complex in which the differential is zero
    Usage
        gradedModule C
    Inputs
        C:Complex
    Outputs
        :Complex
            whose differential is the zero map
    Description
        Text
            This routine isolates the terms in the complex
            and forgets the differentials
        Example
            R = ZZ/101[a,b,c,d,e];
            I = intersect(ideal(a,b),ideal(c,d,e))
            C = (dual freeResolution I)[-4]
            dd^C
            G = gradedModule C
            dd^G
            assert(isWellDefined G)
            assert(G != C)
        Text
            The homology of a complex already has zero differential.
        Example
            H = HH C
            prune H
            dd^H == 0
            assert(H == gradedModule H)
    SeeAlso
        (homology, Complex)
///

doc ///
    Key
        [freeResolution, LengthLimit]
        [freeResolution, DegreeLimit]
        [freeResolution, HardDegreeLimit]
        [freeResolution, PairLimit]
        [freeResolution, SortStrategy]
        [freeResolution, StopBeforeComputation]
        [freeResolution, SyzygyLimit]
        [freeResolution, ParallelizeByDegree]
    Headline
        optional arguments for freeResolution
    Description
        Text
            We would dearly love to not have this in the main node!
///

doc ///
    Key
        freeResolution
        (freeResolution, Module)
        (freeResolution, Ideal)
        (freeResolution, MonomialIdeal)
    Headline
        compute a free resolution of a module or ideal
    Usage
        freeResolution M
        freeResolution I
    Inputs
        M:Module
        I:Ideal
            in the ring $R$, treated as the quotient module $R^1/I$
        LengthLimit => ZZ
            this is used to limit somehow the computation where resolutions might be too long or infinite
        DegreeLimit => List
            or @ofClass ZZ@, an option that specifies that the computation stops at the given
            (slanted) degree
        HardDegreeLimit => List
            unused
        PairLimit => ZZ
            or @TO infinity@, an internal option which specifies that the computation should stop after a 
            certain number of s-pairs have computed
        SortStrategy => ZZ
            an internal option that specifies the strategy to be used for sorting S-pairs
        StopBeforeComputation => Boolean
            whether to start the computation. This can be useful when you want to obtain the 
            partially computed resolution contained in an interrupted computation.
        Strategy => ZZ
            one of the integers 0,1,2,3, one of the symbols Engine,
            Homogenization, Syzygies, Nonminimal, OverField, OverZZ, or null
        SyzygyLimit => ZZ
            or @TO infinity@, 
            an internal option which specifies that the computation should stop after a 
            certain number of syzygies have computed
        ParallelizeByDegree => Boolean
            Use additional parallelism to compute different (homological degree, internal degree) pairs in
            parallel when possible. To control parallelism, see "parallelism in engine computations"
    Outputs
        :Complex
            a free resolution of the module $M$ or of the
            quotient module $R^1/I$
    Description
        Text
            A free resolution of a module $M$ is a complex

            $\phantom{WWWW}
            F_0 \leftarrow F_1 \leftarrow F_2 \leftarrow \dotsb
            $

            of free modules, whose homology is concentrated in
            homological degree zero and is isomorphic to the module
            $M$.  Equivalently, the augmented complex

            $\phantom{WWWW}
            0 \leftarrow M \leftarrow F_0 \leftarrow F_1 \leftarrow F_2 \leftarrow \dotsb
            $

            is exact.
            
            This function lies at the heart of many computations in commutative algebra
            and algebraic geometry.  As a consequence, this is one of the most used
            functions in {\em Macaulay2}.
        Text
            As a first example, we construct the free resolution of the twisted cubic curve,
            and extract its basic numerical invariants via @TO (length, Complex)@ and
            @TO (betti,Complex)@.
        Example
            R = QQ[a..d];
            I = ideal(c^2-b*d, b*c-a*d, b^2-a*c)
            M = R^1/I
            C = freeResolution M
            length C
            betti C
            dd^C
            assert isWellDefined C
        Text
            We verify in two ways that $C$ is a free resolution of $M$.
        Example
            assert(prune HH C == complex M)
            assert(length HH C == 0)
            f = augmentationMap C
            assert isWellDefined f
            assert(source f === C)
            assert(target f == complex M)
            aC = cone f
            assert(HH aC == 0)
        Text
            Giving an ideal as the input produces a free resolution
            not of the module $I$, but of the comodule $R^1/I$.
        Example
            assert(freeResolution I == C)
            assert(resolution complex M == freeResolution M)
        Text
            We obtain the resolution of the module $I$, rather than the comodule $R^1/I$,
            as follows.
        Example
            C' = freeResolution module I
            assert isWellDefined C'
            assert(C' != C)
            assert(betti naiveTruncation(C, 1, infinity) == betti C'[-1])
        Text
            Over a quotient ring, free resolutions are typically infinite.
            To specify a finite part of the resolution, one needs to use
            the optional argument {\tt LengthLimit}.
        Example
            S = ZZ/101[a,b];
            R = S/(a^3+b^3);
            C = freeResolution (coker vars R, LengthLimit => 7)
            length C
            betti C
            dd^C
        Text
            Over an exterior algebra, free resolutions are again typically
            infinite, so one needs to specify the {\tt LengthLimit}.
        Example
            E = ZZ/101[e_1..e_6, SkewCommutative => true];
            I = ideal(e_4*e_5-e_4*e_6+e_5*e_6,
                e_2*e_3-e_2*e_6+e_3*e_6,
                e_1*e_3-e_1*e_5+e_3*e_5,
                e_1*e_2-e_1*e_4+e_2*e_4)
            F = freeResolution(I, LengthLimit => 5)
            assert isWellDefined F
            assert isHomogeneous F
            betti F
        Text
            Over a Weyl algebra, free resolutions have finite length,
            so one does not need to specific the {\tt LengthLimit}.
        Example
            S = QQ[x,y,Dx,Dy, WeylAlgebra => {{x,Dx}, {y,Dy}}];
            I = ideal(x*Dy, y*Dx)
            F = freeResolution comodule I
            assert isWellDefined F
            dd^F
        Text
            Todo: we will add pointers to more advanced nodes and usage information
            (e.g. Strategies, Optional arguments, and seeing partial results).
    SeeAlso
        "Making chain complexes"
        (augmentationMap, Complex)
        (cone, ComplexMap)
        (resolution, Complex)
        (resolutionMap, Complex)
        (betti, Complex)
///

doc ///
    Key
        "Strategies for free resolutions"
        [freeResolution, Strategy]
    Headline
        overview of the different algorithms for computing free resolutions
    Description
        Text
            There are several distinct algorithms for computing free
            resolutions in {\it Macaulay2}.  They make different
            assumptions about the module or underlying ring.
        Text
    	    @UL {
                TO "freeResolution(..., Strategy => OverField)",
                TO "freeResolution(..., Strategy => OverZZ)",
                TO "freeResolution(..., Strategy => Engine)",
                TO "freeResolution(..., Strategy => 1)",
                TO "freeResolution(..., Strategy => 3)",
                TO "freeResolution(..., Strategy => 2)",
                TO "freeResolution(..., Strategy => 0)",
                TO "freeResolution(..., Strategy => Homogenization)",
                TO "freeResolution(..., Strategy => Syzygies)",
                TO "freeResolution(..., Strategy => Nonminimal)"
            }@
        Text
            One can always access the full list of possible strategies
            in {\it Macaulay2} as follows.
        Example
            hooks freeResolution
    SeeAlso
        (freeResolution, Module)
        hooks
///

-- To use in the doc of the Engine strategy, perhaps...
///
        Text
            Since this strategy 
        Example
            m = map(S^1 ++ S^{1},, {{1, b, b-c}, {b, d*e, e^2}})
            assert isHomogeneous m
            C = freeResolution(coker m, Strategy => 2)
            dd^C
            M = prune coker m
            C' = freeResolution M
            dd^C'
///

doc ///
    Key
        "Strategy for free resolutions over a field"
        "freeResolution(..., Strategy => OverField)"
        OverField
    Headline
        algorithm for computing free resolutions over a field
    Usage
        freeResolution M
        freeResolution(M, Strategy => OverField)
    Inputs
        M:Module
            over a field
    Outputs
        :Complex
            a free resolution of the module $M$
    Description
        Text
            @SUBSECTION "Description"@
        Text
            Every module over a field is free.  Therefore a
            minimal free resolution is determined by choosing a basis.
            This is the default strategy when the
            underlying ring is a field, so in practice it never
            needs to be specified.
        Text
            Our first examples are over finite fields.  Notice that
            the most interesting feature is the augmentation map.
        Example
            kk = ZZ/32003;
            M = coker random(kk^3, kk^2)
            F = freeResolution M -- uses Strategy => OverField
            assert isWellDefined F
            g = augmentationMap F
            assert isWellDefined g
            assert(source g == F)
            assert(target g == complex M)
            assert(coker g == 0 and ker g == 0)
        Text
            Finding a minimal free resolution for a module
            over a field is equivalent to finding a @TO2((minimalPresentation, Module), "minimal Presentation")@.
        Example
            N = ker random(kk^3, kk^2) ++ M
            F = freeResolution N
            g = augmentationMap F
            PN = minimalPresentation N
            assert(g_0 == PN.cache.pruningMap)
        Example
            kk = GF(3^10);
            M = coker random(kk^3, kk^2)
            F = freeResolution M
            g = augmentationMap F
        Text
            This also works over the rationals, number fields, and
            fraction fields.
        Example
            kk = QQ;
            M = coker random(kk^3, kk^2, Height => 10000)
            F = freeResolution M
            g = augmentationMap F
        Example
            S = QQ[a]/(a^3-a-1);
            kk = toField S;
            M = coker sub(random(S^3, S^{-2,-2}) + random(S^3, S^{-1,-1}) + random(S^3, S^2), kk)
            F = freeResolution M
            g = augmentationMap F
        Example
            S = ZZ/101[a,b,c,d];
            kk = frac S;
            M = coker sub(random(S^3, S^{-1,-1}), kk)
            F = freeResolution M
            g = augmentationMap F
    SeeAlso
        "Strategies for free resolutions"
        (freeResolution, Module)
        (augmentationMap, Complex)
///

doc ///
    Key
        "Strategy for free resolutions over the integers"
        "freeResolution(..., Strategy => OverZZ)"
        OverZZ
    Headline
        algorithm for computing free resolutions of ZZ-modules
    Usage
        freeResolution M
        freeResolution(M, Strategy => OverZZ)
    Inputs
        M:Module
            over the ring of integers
    Outputs
        :Complex
            a free resolution of the module $M$
    Description
        Text
            @SUBSECTION "Description"@
        Text
            Every module over the integers has projective dimension at
            most one.  This is the default strategy when the
            underlying ring is the integers, so in practice it never
            needs to be specified.
        Text
            Our first example is the cokernel of a $3 \times 3$
            matrix with positive small integer entries.
        Example
            M = coker matrix{{8,4,9},{7,3,7},{6,9,5}}
            F = freeResolution M -- uses Strategy => OverZZ
            assert isWellDefined F
            dd^F
            g = augmentationMap F
            assert isWellDefined g
            assert(source g == F)
            assert(target g == complex M)
            assert isQuasiIsomorphism g
        Text
            The next example shows that the projective dimension
            can be less than one.  In other words, a free module
            can have a non-trivial presentation.
        Example
            G = freeResolution coker matrix {{20, 15, 19}, {7, 3, 7}, {6, 9, 5}}
            length G
            G_0
            g = augmentationMap G
            assert isWellDefined g
            assert isQuasiIsomorphism g
        Text
            The final example involves a slightly larger matrix.  
            The first matrix of the free resolution is the minimal
            presentation of the module.
        Example
            n = random(ZZ^5, ZZ^3) * matrix{{21,3,0},{0,3,1},{0,0,7}} * random(ZZ^3, ZZ^10)
            F = freeResolution coker n
            dd^F_1
            minimalPresentation coker n
            smithNormalForm(n, ChangeMatrix => {false,false})
    SeeAlso
        "Strategies for free resolutions"
        (freeResolution, Module)
        (augmentationMap, Complex)
        (minimalPresentation, Module)
        (smithNormalForm, Matrix)
///

doc ///
    Key
        "Strategy for free resolutions via Schreyer-Lascala"
        "freeResolution(..., Strategy => 0)"
    Headline
        algorithm for computing free resolutions exploiting the Schreyer frame
    Usage
        freeResolution(M, Strategy => 0)
        freeResolution(I, Strategy => 0)
    Inputs
        M:Module
            a homogeneous module over $S$, a (quotient of a) polynomial ring
        I:Ideal
            a homogeneous ideal in $S$
    Outputs
        :Complex
            a minimal free resolution of $M$ or $S^1/I$
    Description
        Text
            @SUBSECTION "Description"@
        Text
            This is one of the algorithms in the engine of {\it Macaulay2}
            for computing minimal free resolutions.  This particular
            variant requires that the ring $S$ be commutative,
            and homogeneous over a base field.
        Text
            This first example computes a minimal free resolution
            of the twisted cubic curve in projective $3$-space.
        Example
            kk = ZZ/32003;
            S = kk[a..d];
            I = ideal(b^2-a*c, b*c - a*d, c^2-b*d)
            M = S^1/I
            F = freeResolution(M, Strategy => 0)
            dd^F
            betti F
            assert isWellDefined F
            assert(isQuasiIsomorphism augmentationMap F)
        Text
            When the input is an ideal $I$, the free resolution of
            $S^1/I$ is returned.
        Example
            F1 = freeResolution(I, Strategy => 0)
            assert(F1 == F)
            F2 = freeResolution(module I, Strategy => 0)
            dd^F1
            dd^F2
        Text
            This strategy also works when the underlying ring is
            a homogeneous quotient.
        Example
            R = S/(a^3, b^3, c^3, d^3);
            J = ideal(b^2-a*c, b*c - a*d, c^2-b*d + (b^2-a*c))
            M = R^1/J
            C = freeResolution(M, Strategy => 0, LengthLimit => 8)
            assert isWellDefined C
            betti C
        Text
            The first map in the resulting complex is
            not necessarily given by the generators of the
            ideal or the relations of the module.
        Example
            dd^C_1
            gens J
            relations M
        Text
            This strategy is an implementation of the algorithm
            in Roberto La Scala and Mike Stillman,
            {\it Strategies for computing minimal free resolutions}
            J. Symbolic Comput. {\bf 26} (1998), no.4, 409-431.
            
            It uses the Schreyer algorithm for free resolutions,
            including using induced (Schreyer) monomial orders
            on the free modules in the resolution, together with
            a method to minimize the resolution appearing in the above paper.
            
            Both strategies 0 and 1 are implementations of this algorithm,
            however they use slightly different internal data structures.
            Moreover, strategy 0 precomputes a Groebner basis for the presentation
            of the module.  In contrast, strategy 1 obtains the Groebner basis
            as part of the algorithm.
    SeeAlso
        "Strategies for free resolutions"
        (freeResolution, Module)
        (augmentationMap, Complex)
///

doc ///
    Key
        "Default strategy for free resolutions of homogeneous modules"
        "freeResolution(..., Strategy => 1)"
    Headline
        algorithm for computing free resolutions exploiting the Schreyer frame
    Usage
        freeResolution M
        freeResolution I
        freeResolution(M, Strategy => 1)
        freeResolution(I, Strategy => 1)
    Inputs
        M:Module
            a homogeneous module over $S$, a (quotient of a) polynomial ring
        I:Ideal
            a homogeneous ideal in $S$
    Outputs
        :Complex
            a minimal free resolution of $M$ or $S^1/I$
    Description
        Text
            @SUBSECTION "Description"@
        Text
            This is a primary algorithm in the engine of {\it
            Macaulay2} for computing minimal free resolutions. This is
            the default variant when the ring $S$ is a homogeneous commutative
            polynomial ring over a base field.
        Text
            This first example computes a minimal free resolution
            of the twisted cubic curve in projective $3$-space.
        Example
            kk = ZZ/32003;
            S = kk[a..d];
            I = ideal(b^2-a*c, b*c - a*d, c^2-b*d)
            M = S^1/I
            F = freeResolution M
            dd^F
            betti F
            assert isWellDefined F
            assert(isQuasiIsomorphism augmentationMap F)
        Text
            When the input is an ideal $I$, the free resolution of
            $S^1/I$ is returned.
        Example
            F1 = freeResolution I
            assert(F1 == F)
            F2 = freeResolution module I
            dd^F1
            dd^F2
        Text
            This strategy also works when the underlying ring is
            a homogeneous quotient.
        Example
            R = S/(a^3, b^3, c^3, d^3);
            J = ideal(b^2-a*c, b*c - a*d, c^2-b*d + (b^2-a*c))
            M = R^1/J
            C = freeResolution(M, LengthLimit => 8)
            assert isWellDefined C
            betti C
        Text
            This strategy is an implementation of the algorithm
            in Roberto La Scala and Mike Stillman,
            {\it Strategies for computing minimal free resolutions}
            J. Symbolic Comput. {\bf 26} (1998), no.4, 409-431.

            It uses the Schreyer algorithm for free resolutions,
            including using induced (Schreyer) monomial orders
            on the free modules in the resolution, together with
            a method to minimize the resolution appearing in the above paper.
            
            Both strategies 0 and 1 are implementations of this algorithm,
            however they use slightly different internal data structures.
            Moreover, strategy 0 precomputes a Groebner basis for the presentation
            of the module.  In contrast, strategy 1 obtains the Groebner basis
            as part of the algorithm.
    SeeAlso
        "Strategies for free resolutions"
        (freeResolution, Module)
        (augmentationMap, Complex)
///

doc ///
    Key
        "Strategy for free resolutions of homogeneous modules via successive syzygies"
        "freeResolution(..., Strategy => 2)"
    Headline
        algorithm for computing free resolutions step by step
    Usage
        freeResolution(M, Strategy => 2)
        freeResolution(I, Strategy => 2)
    Inputs
        M:Module
            a homogeneous module over $S$, a (quotient of a) polynomial ring
        I:Ideal
            a homogeneous ideal in $S$
    Outputs
        :Complex
            a minimal free resolution of $M$ or $S^1/I$
    Description
        Text
            @SUBSECTION "Description"@
        Text
            This is one of the algorithms in the engine of {\it Macaulay2} for
            computing minimal free resolutions. This is the default
            variant when the ring $S$ is a homogeneous quotient of
            an almost commutative polynomial ring over a base field.
            In particular, this variant applies to homogeneous modules
            over a homogenized Weyl algebra or an exterior algebra.            
        Text
            This first example computes part of the minimal free
            resolution of the ground field over a hypersurface ring.
        Example
            kk = ZZ/32003;
            R = kk[a..d]/(a^2+b^2+c^2+d^2);
            I = ideal(a,b,c,d)
            M = R^1/I
            F = freeResolution(M, LengthLimit => 5)
            dd^F
            assert isWellDefined F
            assert isQuasiIsomorphism(augmentationMap F, Concentration => (0,4))
        Text
            When the input is an ideal $I$, the free resolution of
            $R^1/I$ is returned.
        Example
            F1 = freeResolution(I, LengthLimit => 5)
            assert(F1 == F)
            F2 = freeResolution(module I, LengthLimit => 5)
            dd^F1
            dd^F2
        Text
            This strategy also works when the underlying ring is
            simply a polynomial ring, but is often slower than
            Strategy 1. However, unlike Strategy 1, 
            this strategy preserves the given presentation of the module,
            which can be desirable.
        Example
            S = kk[a..e]
            J = ideal(a^3-e^3, a*b^2-c*e^2, a*b*c, a*b*c + a^3 - e^3)
            assert isHomogeneous J
            C2 = freeResolution(J, Strategy => 2)
            C1 = freeResolution ideal J_*
            assert isWellDefined C2
            betti C2
            betti C1
            assert(dd^C2_1 == gens J)
            assert(dd^C1_1 != gens J)
        Text
            For completeness, we present an example over a homogenized
            Weyl algebra.
        Example
            W = kk[x,y,z,dx,dy,dz,h, WeylAlgebra => {x => dx, y => dy, z => dz, h}]
            I = ideal(x*dy-y*dz, x*y*dy*dz)
            M = W^1/I
            F = freeResolution(M, Strategy => 2)
            dd^F
            assert isWellDefined F
            assert isQuasiIsomorphism augmentationMap F
        Text
            This strategy works degree by degree.  Within each degree,
            it first computes the syzygies of the presentation matrix,
            and then computes the second syzygies, and so on.  This
            strategy uses Schreyer orders on the free modules in the
            resolution which often improves efficiency.

            Although similar to Strategy 3, this strategy does not use
            Hilbert functions to aid the computation.
    SeeAlso
        "Strategies for free resolutions"
        (freeResolution, Module)
        (augmentationMap, Complex)
///

doc ///
    Key
        "Strategy for free resolutions of homogeneous modules aided by Hilbert functions"
        "freeResolution(..., Strategy => 3)"
    Headline
        algorithm for computing free resolutions step by step aided by Hilbert functions
    Usage
        freeResolution(M, Strategy => 3)
        freeResolution(I, Strategy => 3)
    Inputs
        M:Module
            a homogeneous module over $S$, a (quotient of a) polynomial ring
        I:Ideal
            a homogeneous ideal in $S$
    Outputs
        :Complex
            a minimal free resolution of $M$ or $S^1/I$
    Description
        Text
            @SUBSECTION "Description"@
        Text
            This is one of the algorithms in the engine of {\it
            Macaulay2} for computing minimal free resolutions. This is
            a variant when the ring $S$ is a homogeneous quotient of
            an almost commutative polynomial ring over a base field.
            In particular, this variant applies to homogeneous modules
            over a homogenized Weyl algebra or an exterior algebra.
        Text
            This first example computes part of the minimal free
            resolution of the ground field over a hypersurface ring.
        Example
            kk = ZZ/32003;
            R = kk[a..d]/(a^2+b^2+c^2+d^2);
            I = ideal(a,b,c,d)
            M = R^1/I
            F = freeResolution(M, Strategy => 3, LengthLimit => 5)
            dd^F
            assert isWellDefined F
            assert isQuasiIsomorphism(augmentationMap F, Concentration => (0,4))
        Text
            When the input is an ideal $I$, the free resolution of
            $R^1/I$ is returned.
        Example
            F1 = freeResolution(I, Strategy => 3, LengthLimit => 3)
            assert(F1 == naiveTruncation(F,0,3))
            F2 = freeResolution(module I, Strategy => 3, LengthLimit => 3)
            dd^F1
            dd^F2
        Text
            This strategy also works when the underlying ring is
            simply a polynomial ring, but is often slower than
            Strategy 1. However, unlike Strategy 1, 
            this strategy preserves the given presentation of the module,
            which can be desirable.
        Example
            S = kk[a..e]
            J = ideal(a^3-e^3, a*b^2-c*e^2, a*b*c, a*b*c + a^3 - e^3)
            assert isHomogeneous J
            C2 = freeResolution(J, Strategy => 3)
            C1 = freeResolution ideal J_*
            assert isWellDefined C2
            betti C2
            betti C1
            assert(dd^C2_1 == gens J)
            assert(dd^C1_1 != gens J)
        Text
            For completeness, we present an example over an
            exterior algebra.
        Example
            E = kk[a..d, SkewCommutative => true]
            I = ideal(a*b-c*d, a*b*c*d)
            M = E^1/I
            F = freeResolution(M, Strategy => 3, LengthLimit => 4)
            dd^F
            assert isWellDefined F
            assert isQuasiIsomorphism(augmentationMap F, Concentration => (0,3))
        Text
            This strategy works degree by degree.  Within each degree,
            it first computes the syzygies of the presentation matrix,
            and then computes the second syzygies, and so on.  This
            strategy uses Schreyer orders on the free modules in the
            resolution which often improves efficiency.

            Although similar to Strategy 2, this strategy does use
            Hilbert functions to aid the computation.
    SeeAlso
        "Strategies for free resolutions"
        (freeResolution, Module)
        (augmentationMap, Complex)
///

-- TODO: add Syzygies key here, when it is no longer in the Core.
-- TODO: add in a WeylAlgebra example once the code is functioning better.
--            W = ZZ/11[x,y,z,dx,dy,dz,WeylAlgebra => {x => dx, y => dy, z => dz}, Degrees => {1,1,1,-1,-1,-1}]
--            J = ideal(x*dz-y*dx, x*dy^2+dz)  -- res J takes quite a while, then quits with a divide by zero error!
--
--            Wh = QQ[x,y,z,dx,dy,dz,h,WeylAlgebra => {x => dx, y => dy, z => dz, h}]
--            J = ideal(x*dz-y*dx, x*dy^2+dz*h^2)
--            use W
--            dehom = map(W, Wh, {x,y,z,dx,dy,dz,1})
--            C = freeResolution(J) -- strategy 
--            C0 = dehom C
--            isWellDefined C0
--            prune HH C0
doc ///
    Key
        "Strategy for free resolutions via syzygies"
        "freeResolution(..., Strategy => Syzygies)"
    Headline
        algorithm for computing free resolutions step by step using syzygies
    Usage
        freeResolution(M, Strategy => Syzygies)
        freeResolution(I, Strategy => Syzygies)
    Inputs
        M:Module
            a module over a ring $R$
        I:Ideal
            an ideal in $R$
    Outputs
        :Complex
            a free resolution of $M$ or $R^1/I$
    Description
        Text
            @SUBSECTION "Description"@
        Text
            This is one of the algorithms written at top level of {\it
            Macaulay2} for computing free resolutions, although
            it uses engine code to compute syzygies. This
            variant works over most rings in {\it Macaulay2},
            including Weyl algebras and exterior algebras.
        Text
            This first example computes part of the free
            resolution of the ground field over a inhomogeneous $E_8$ singularity.
        Example
            kk = ZZ/32003;
            R = kk[a,b,c]/(a^2+b^3+c^5);
            I = ideal(a,b,c)
            M = R^1/I
            F = freeResolution(M, Strategy => Syzygies, LengthLimit => 5)
            dd^F
            assert isWellDefined F
            assert isQuasiIsomorphism(augmentationMap F, Concentration => (0,4))
        Text
            When the input is an ideal $I$, the free resolution of
            $R^1/I$ is returned.
        Example
            F1 = freeResolution(I, Strategy => Syzygies, LengthLimit => 3)
            assert(F1 == naiveTruncation(F,0,3))
            F2 = freeResolution(module I, Strategy => Syzygies, LengthLimit => 3)
            dd^F1
            dd^F2
        Text
            For completeness, we present an example over an
            exterior algebra.
        Example
            E = kk[a..d, SkewCommutative => true]
            I = ideal(a*b-c*d, a*b*c*d)
            M = E^1/I
            F = freeResolution(M, Strategy => Syzygies, LengthLimit => 4)
            dd^F
            assert isWellDefined F
            assert isQuasiIsomorphism(augmentationMap F, Concentration => (0,3))
        Text
            This strategy works one homological degree
            at a time.
            It first computes the syzygies of the presentation matrix,
            and then computes the second syzygies, and so on.  This
            strategy uses Schreyer orders on the free modules in the
            resolution which often improves efficiency.
    SeeAlso
        "Strategies for free resolutions"
        (freeResolution, Module)
        (augmentationMap, Complex)
///

doc ///
    Key
        "Strategy for free resolutions via homogenization"
        "freeResolution(..., Strategy => Homogenization)"
        Homogenization
    Headline
        algorithm for computing free resolutions by first homogenizing
    Usage
        freeResolution(M, Strategy => Homogenization)
        freeResolution(I, Strategy => Homogenization)
    Inputs
        M:Module
            a module over a ring $R$
        I:Ideal
            an ideal in $R$
    Outputs
        :Complex
            a free resolution of $M$ or $R^1/I$
    Description
        Text
            @SUBSECTION "Description"@
        Text
            This is one of the algorithms written at top level of {\it
            Macaulay2} for computing free resolutions, although
            it uses engine code to compute free resolutions of the
            homogenized module or ideal.  This is the default
            strategy for inhomogeneous ideals or modules over
            a {\it commutative} ring.
            The result is rarely a minimal resolution; minimal
            resolutions are not generally defined in the inhomogeneous
            case.
        Text
            This first example computes a free resolution
            of an inhomogeneous ideal.
        Example
            kk = ZZ/53;
            S = kk[a,b,c,d];
            I = ideal(a^3-b^2-a*c, a*b*c-d^2, a^3-d^2)
            M = S^1/I
            F = freeResolution M
            dd^F
            assert isWellDefined F
            assert isQuasiIsomorphism(augmentationMap F, Concentration => (0,4))
        Text
            Even though minimal resolutions are not generally defined,
            the @TO minimize@ method will often produce a smaller
            resolution.
        Example        
            mF = minimize F
            dd^mF
            assert isWellDefined mF
            prune HH mF
        Text
            When the input is an ideal $I$, the free resolution of
            $S^1/I$ is returned.
        Example
            F1 = freeResolution I
            assert(F1 == F)
            F2 = freeResolution module I
            dd^F1
            dd^F2
        Text
            This strategy also works over quotient rings.
        Example
            R = S/(a^4-a*d, b^3-a*d)
            I = ideal(a^3-b^2-a*c, a*b*c-d*a, a^3+d^2)
            M = R^1/I
            F = freeResolution(M, Strategy => Homogenization, LengthLimit => 4)
            assert isWellDefined F
            dd^F_2
        Text
            This strategy homogenizes the ideal or module as well
            as the underlying ring, calls an engine routine
            to compute the resolution, and finally dehomogenizes the
            result.
    SeeAlso
        "Strategies for free resolutions"
        (freeResolution, Module)
        (augmentationMap, Complex)
        (minimize, Complex)
///

doc ///
    Key
        "freeResolution(..., Strategy => Engine)"
    Headline
        algorithm for computing a free resolution
    Usage
        freeResolution(M, Strategy => Engine)
        freeResolution(I, Strategy => Engine)
    Inputs
        M:Module
            a homogeneous module over $S$, a (quotient of a) polynomial ring
        I:Ideal
            a homogeneous ideal in $S$
    Outputs
        :Complex
            a minimal free resolution of $M$ or $S^1/I$
    Description
        Text
            @SUBSECTION "Description"@
        Text
            This strategy chooses, depending on the ring type, an appropriate
            algorithm in the engine for computing free resolutions of homogeneous
            modules and ideals.
            This particular strategy is not intended for users, rather it is
            used internally to select an appropriate algorithm when no strategy
            is specified by the user.
        Text
            This first example computes part of the minimal free
            resolution of the ground field over a hypersurface ring.
        Example
            kk = ZZ/32003;
            R = kk[a..f];
            I = ideal(a^3-b^2*c, a^3*d - c*b^3, a*e^2-c*f^2)
            M = R^1/I
            F = freeResolution(M, Strategy => Engine)
            dd^F
            assert isWellDefined F
            assert isQuasiIsomorphism(augmentationMap F, Concentration => (0,4))
        Text
            When the input is an ideal $I$, the free resolution of
            $R^1/I$ is returned.
        Example
            F1 = freeResolution(I, Strategy => Engine)
            assert(F1 == naiveTruncation(F,0,3))
            F2 = freeResolution(module I, Strategy => Engine)
            dd^F1
            dd^F2
        Text
            The following code shows how this method chooses
            between strategies 1 and 2.
        Example
            code (freeResolution, Module, Strategy => Engine)
    SeeAlso
        "Strategies for free resolutions"
        "freeResolution(..., Strategy => 1)"
        "freeResolution(..., Strategy => 2)"
        (freeResolution, Module)
        (augmentationMap, Complex)
///

doc ///
    Key
        "Strategy for nonminimal free resolutions"
        "freeResolution(..., Strategy => Nonminimal)"
        Nonminimal
    Headline
        algorithm for computing nonminimal free resolutions
    Usage
        freeResolution(M, Strategy => Nonminimal)
        freeResolution(I, Strategy => Nonminimal)
    Inputs
        M:Module
            a module over a ring $R$
        I:Ideal
            an ideal in $R$
    Outputs
        :Complex
            a free resolution of $M$ or $R^1/I$
    Description
        Text
            @SUBSECTION "Description"@
        Text
            This is the main the algorithm in the engine of {\it
            Macaulay2} for computing {\it nonminimal} free resolutions
            of possibly inhomogeneous modules and ideals over a
            polynomial ring or exterior algebra defined over a finite
            field.  For homogeneous ideals and modules over such
            rings, this variant generally computes a non-minimal
            resolution much faster than engine routines that return a
            minimal free resolution. In particular, this algorithm is
            used by @TO "minimalBetti"@ for faster computation of
            Betti tables.
        Text
            This first example computes part of the free
            resolution of the ground field over a inhomogeneous $E_8$ singularity.
        Example
            kk = ZZ/32003;
            R = kk[a..f];
            I = ideal(a*b*c-d*e*f, a*b*f-c*d*e, a*b*d-c^3)
            F = freeResolution(I, Strategy => Nonminimal)
            dd^F
            betti F
            minimalBetti I
            assert isWellDefined F
            assert isQuasiIsomorphism(augmentationMap F)
        Text
            We also present an inhomogeneous example over a polynomial ring.
        Example
            I = ideal(a*b*c-d*e*f, a^2*b*f-c*d*e, a*b*d-c^2)
            F = freeResolution(I, Strategy => Nonminimal)
            dd^F
            assert isWellDefined F
            assert isQuasiIsomorphism augmentationMap F
            minimize F
            freeResolution I
        Text
            We also present an example over an
            exterior algebra.
        Example
            E = kk[a..d, SkewCommutative => true]
            I = ideal(a*b-c*d, a*b*c*d)
            F = freeResolution(I, Strategy => Nonminimal, LengthLimit => 4)
            dd^F
            betti F
            minimalBetti I
            assert isWellDefined F
            assert isQuasiIsomorphism(augmentationMap F, Concentration => (0,3))
        Text
            This strategy implements an algorithm of Frank Schreyer.
            It first computes lead terms of all of the syzygy modules
            of the ideal or module, and then determines each syzygy
            using a linear algebra approach together with a
            number of optimizations.
    SeeAlso
        "Strategies for free resolutions"
        (freeResolution, Module)
        (augmentationMap, Complex)
///

doc ///
   Key
     (homology, Complex)
   Headline
     homology of a complex
   Usage
     H = HH C
   Inputs
     C:Complex
   Outputs
     H:Complex
   Description
    Text
      The homology complex $H$ is defined by {\tt ker dd^C}/{\tt image dd^C}.
      The differential of the homology complex is the zero map.
      
      The first example is the complex associated to
      a triangulation of the real projective plane, having
      6 vertices, 15 edges, and 10 triangles.
    Example
      d1 = matrix {
          {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 
          {-1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, 
          {0, -1, 0, 0, 0, -1, 0, 0, 0, 1, 1, 1, 0, 0, 0}, 
          {0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, 0, 1, 1, 0}, 
          {0, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, -1, 0, 1}, 
          {0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, -1, -1}}
      d2 = matrix {
          {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0}, 
          {0, 0, -1, -1, 0, 0, 0, 0, 0, 0}, 
          {1, 0, 1, 0, 0, 0, 0, 0, 0, 0}, 
          {0, 1, 0, 0, -1, 0, 0, 0, 0, 0}, 
          {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, 
          {0, 0, 0, 0, 0, -1, -1, 0, 0, 0}, 
          {-1, 0, 0, 0, 0, 0, 0, -1, 0, 0}, 
          {0, -1, 0, 0, 0, 1, 0, 0, 0, 0}, 
          {0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, 
          {0, 0, -1, 0, 0, 0, 0, 0, -1, 0}, 
          {0, 0, 0, 0, 0, -1, 0, 0, 1, 0}, 
          {0, 0, 0, -1, 0, 0, -1, 0, 0, 0}, 
          {0, 0, 0, 0, 0, 0, 0, 0, -1, -1}, 
          {0, 0, 0, 0, 0, 0, 0, -1, 0, 1}, 
          {0, 0, 0, 0, -1, 0, 0, 0, 0, -1}}
      C = complex {d1,d2}
      dd^C
      H = HH C
      dd^H == 0
    Text
      To see that the first homology group has torsion,
      we compute a minimal presentation of the homology.
    Example
      Hpruned = prune HH C
      dd^Hpruned == 0
    Text
      By dualizing the minimal free resolution of a monomial ideal,
      we get a free complex with non-trivial homology.  This particular
      complex is related to the local cohomology supported at the
      monomial ideal.
    Example
      S = ZZ/101[a..d, DegreeRank=>4];
      I = intersect(ideal(a,b),ideal(c,d))
      C = freeResolution (S^1/I)
      prune HH C
      Cdual = dual C
      prune HH Cdual
      prune HH_(-2) Cdual
   SeeAlso
     (dual, Complex)
     (prune, Complex)
///



doc ///
   Key
     (homology,ZZ,Complex)
     (cohomology,ZZ,Complex)
   Headline
     homology or cohomology module of a complex
   Usage
     HH_i C
     HH^i C
   Inputs
     i:ZZ
     C:Complex
   Outputs
     :Module
       the $i$-th homology or cohomology of the complex
   Description
    Text
      The $i$-th homology of a complex $C$ is the quotient
      ({\tt ker dd^C_i/image dd^C_(i+1)}).

      The first example is the complex associated to
      a triangulation of the real projective plane, having
      6 vertices, 15 edges, and 10 triangles.
    Example
      d1 = matrix {
          {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 
          {-1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, 
          {0, -1, 0, 0, 0, -1, 0, 0, 0, 1, 1, 1, 0, 0, 0}, 
          {0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, 0, 1, 1, 0}, 
          {0, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, -1, 0, 1}, 
          {0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, -1, -1}};
      d2 = matrix {
          {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0}, 
          {0, 0, -1, -1, 0, 0, 0, 0, 0, 0}, 
          {1, 0, 1, 0, 0, 0, 0, 0, 0, 0}, 
          {0, 1, 0, 0, -1, 0, 0, 0, 0, 0}, 
          {0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, 
          {0, 0, 0, 0, 0, -1, -1, 0, 0, 0}, 
          {-1, 0, 0, 0, 0, 0, 0, -1, 0, 0}, 
          {0, -1, 0, 0, 0, 1, 0, 0, 0, 0}, 
          {0, 0, 0, 0, 0, 0, 1, 1, 0, 0}, 
          {0, 0, -1, 0, 0, 0, 0, 0, -1, 0}, 
          {0, 0, 0, 0, 0, -1, 0, 0, 1, 0}, 
          {0, 0, 0, -1, 0, 0, -1, 0, 0, 0}, 
          {0, 0, 0, 0, 0, 0, 0, 0, -1, -1}, 
          {0, 0, 0, 0, 0, 0, 0, -1, 0, 1}, 
          {0, 0, 0, 0, -1, 0, 0, 0, 0, -1}};
      C = complex {d1,d2}
      dd^C
      HH C
      prune HH_0 C
      prune HH_1 C
      prune HH_2 C
    Text
      The $i$-th cohomology of a complex $C$ is the $(-i)$-th
      homology of $C$.
    Example
      S = ZZ/101[a..d, DegreeRank=>4];
      I = intersect(ideal(a,b),ideal(c,d))
      C = dual freeResolution (S^1/I)
      prune HH^1 C
      prune HH^2 C
      prune HH^3 C
   SeeAlso
     prune
     (dual, Complex)
///

doc ///
   Key
     (directSum, Complex)
     (symbol++, Complex, Complex)
   Headline
     direct sum of complexes
   Usage
     D = C1 ++ C2
     D = directSum(C1,C2,...)
     D = directSum(name1 => C1, name2 => C2, ...)
   Inputs
     Ci:Complex
   Outputs
     D:Complex
       the direct sum of the input complexes
   Description
    Text
      The direct sum of two complexes is another complex.
    Example
      S = ZZ/101[a,b,c];
      C1 = freeResolution coker vars S
      C1 ++ complex(S^13)[-2]
      C2 = complex (ideal(a,b,c))
      C1 ++ C2
      assert isWellDefined(C1 ++ C2)
    Text
      The direct sum of a sequence of complexes 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 complex which is a direct sum, we obtain the component
      complexes and their names (indices) as follows.
    Example
      components C3
      indices C3
      components C4
      indices C4
   SeeAlso
     (components,Complex)
     indices
     (symbol^, Complex, Array)
     (symbol_, Complex, Array)
     (isShortExactSequence, ComplexMap, ComplexMap)
     (sum, Complex)
///

doc ///
   Key
     (symbol_, Complex, Array)
     (symbol^, Complex, Array)
   Headline
     the canonical inclusion or projection map of a direct sum
   Usage
     i = C_[name]
     p = C^[name]
   Inputs
     C:Complex
     name:
   Outputs
     :ComplexMap
       {\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 = freeResolution coker vars S
      C2 = complex (ideal(a,b,c))
      D = C1 ++ C2
      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 = (mike => C1) ++ (greg => C2)
      E_[mike]
      E_[greg]
      E^[mike] * E_[mike] == 1
      E^[greg] * E_[greg] == 1
      E^[mike] * E_[greg] == 0
      E^[greg] * E_[mike] == 0
      E_[mike] * E^[mike] + E_[greg] * E^[greg] == 1
    Text
      One can also access inclusion and projection maps of sub-direct sums.
    Example
      F = directSum(C1, C2, (complex S^13)[-4])
      F^[0,1]
      F_[0,2]
   SeeAlso
     (directSum, Complex)
     (components, Complex)
     indices
///

doc ///
   Key
     (components, Complex)
   Headline
     list the components of a direct sum
   Usage
     components C
   Inputs
     C:Complex
   Outputs
     :List
       the component complexes of a direct sum (of complexes)
   Description
    Text
      A complex which has been constructed as a direct sum
      stores its component complexes.
    Example
      S = ZZ/101[a,b,c];
      C1 = freeResolution coker vars S
      C2 = complex (ideal(a,b,c))
      D = C1 ++ C2
      L = components D
      L_0 === C1
      L_1 === C2
      E = (mike => C1) ++ (greg => C2)
      components E
    Text
      The names of the component complexes are called indices, 
      and are used to access the relevant inclusion and projection maps.
    Example
      indices D
      D^[0]
      indices E
      E_[greg]
   SeeAlso
     (directSum, Complex)
     indices
     (symbol_, Complex, Array)
     (symbol^, Complex, Array)
///

doc ///
   Key
     (length, Complex)
   Headline
     length of a complex
   Usage
     length C
   Inputs
     C:Complex
   Outputs
     :ZZ
   Description
    Text
      The length of a complex is the difference between the highest index
      of a non-zero object and the lowest index of a non-zero object.
      
      Typically, it counts the number of non-zero differentials, e.g. in
      a free resolution.
    Example
      S = ZZ/101[a,b,c,d];
      C1 = freeResolution coker vars S
      length C1
      C2 = C1[5]
      length C2
      C3 = C1 ++ C1[6]
      length C3
    Text      
      This function always prunes the input complex, so might involve 
      computation.
    Example
      M1 = S^1/(a*b, c*d, a*c, b*c)
      M2 = S^1/(a*b, c*d, a*c)
      C4 = freeResolution M1
      C5 = freeResolution M2
      f = map(M1, M2, 1)
      C6 = coker extend(C4, C5, matrix f)
      concentration C6
      length C6
      prune C6
      concentration prune C6
   SeeAlso
     (prune, Complex)
     (concentration, Complex)
///

doc ///
    Key
        (isHomogeneous, Complex)
    Headline
         whether a complex is homogeneous
    Usage
         isHomogeneous C
    Inputs
         C:Complex
    Outputs
         :Boolean
             that is true when {\tt C} is a homogeneous (i.e. graded) complex
    Description
        Text
            A complex is homogeneous (graded) if the base ring is graded,
            all of the component objects are graded, and
            all the component maps are graded of degree zero.
        Example
            S = ZZ/101[a,b,c,d];
            I = minors(2, matrix{{a,b,c},{b,c,d}})
            C = freeResolution (S^1/I)
            isHomogeneous C
            J = minors(2, matrix{{a,b,c},{b,c,d^2}})
            D = freeResolution (S^1/J)
            isHomogeneous D
    SeeAlso
        "Basic invariants and properties"
        isHomogeneous
        (isHomogeneous, ComplexMap)
///

doc ///
   Key
     (symbol**, Complex, Complex)
     (symbol**, Complex, Module)
     (symbol**, Module, Complex)
     (tensor, Complex, Complex)
   Headline
     tensor product of complexes
   Usage
     D = C1 ** C2
   Inputs
     C1:Complex
       or @ofClass Module@
     C2:Complex
       or @ofClass Module@
   Outputs
     D:Complex
       tensor product of {\tt C1} and {\tt C2}
   Description
    Text
      The tensor product is a complex $D$ whose $i$th component is
      the direct sum of $C1_j \otimes C2_k$ over all $i = j+k$.
      The differential on $C1_j \otimes C2_k$ is the differential 
      $dd^{C1} \otimes id_{C2} + (-1)^j id_{C1} \otimes dd^{C2}$.
      
      As the next example illustrates, the Koszul complex can be constructed via iterated tensor products.
    Example
      S = ZZ/101[a..c]
      Ca = complex {matrix{{a}}}
      Cb = complex {matrix{{b}}}
      Cc = complex {matrix{{c}}}
      Cab = Cb ** Ca
      dd^Cab
      assert isWellDefined Cab
      Cabc = Cc ** Cab
      Cc ** Cb ** Ca
      dd^Cabc
      assert isWellDefined Cabc
    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
     (Hom, Complex, Complex)
     (Hom, Complex, Module)
     (Hom, Module, Complex)     
     (Hom, Complex, Ring)
     (Hom, Ring, Complex)     
   Headline
     the complex of homomorphisms between two complexes
   Usage
     D = Hom(C1,C2)
   Inputs
     C1:Complex
       or @ofClass Module@, or @ofClass Ring@
     C2:Complex
       or @ofClass Module@, or @ofClass Ring@
   Outputs
     D:Complex
       the complex of homomorphisms between {\tt C1} and {\tt C2}
   Description
    Text
      The complex of homomorphisms is a complex $D$ whose $i$th component is
      the direct sum of $Hom(C1_j, C2_{j+i})$ over all $j$.
      The differential on $Hom(C1_j, C2_{j+i})$ is the differential 
      $Hom(id_{C1}, dd^{C2}) + (-1)^j Hom(dd^{C1}, id_{C2})$.
      $dd^{C1} \otimes id_{C2} + (-1)^j id_{C1} \otimes dd^{C2}$.

      In particular, for this operation to be well-defined, both
      arguments must have the same underlying ring.
    Example
      S = ZZ/101[a..c]
      C = freeResolution coker vars S
      D = Hom(C,C)
      dd^D
      assert isWellDefined D
    Text
      The homology of this complex is $Hom(C, ZZ/101)$
    Example
      prune HH D == Hom(C, coker vars S)
    Text
      If one of the arguments is a module or a ring, it is considered as a complex concentrated in homological degree 0.
    Example
      E = Hom(C, S^2)
      prune HH E
    Text
      There is a simple relationship between Hom complexes and @TO2 ((symbol SPACE, Complex, Array), "shifts")@.
      Specifically, shifting the first argument is the same as the negative shift of the result.  But
      shifting the second argument is only the same as the positive shift of the result
      up to a sign.
    Example
      Hom(C[3], C) == D[-3]
      Hom(C, C[-2]) == D[-2]
      Hom(C, C[-3]) != D[-3]
      Hom(C, C[-3]) == complex(- dd^(D[-3]))
    Text
      Specific maps and morphisms between complexes can be obtained
      with @TO (homomorphism, ComplexMap)@.
    Text
      Because the Hom complex can be regarded as the total complex of a double complex,
      each term comes with pairs of indices, labelling the summands.
    Example
      indices D_-1
      components D_-1
      indices D_-2
      components D_-2
   SeeAlso
     (homomorphism, ComplexMap)
     (homomorphism', ComplexMap)
     (randomComplexMap, Complex, Complex)
     indices
     components
     (Hom, ComplexMap, ComplexMap)
///

doc ///
    Key
        (homomorphism, ComplexMap)
    Headline
        get the homomorphism from an element of Hom
    Usage
        g = homomorphism f
    Inputs
        f:ComplexMap
            a map of the form $f : R^1 \to Hom(C, D)$, where
            $C$ and $D$ are complexes,
            $Hom(C,D)$ has been previously computed, and $R$ is
            the underlying ring of these complexes
    Outputs
        g:ComplexMap
            the corresponding map of chain complexes from $C$ to $D$
    Description
        Text
            As a first example, consider two Koszul complexes $C$ and $D$.
            From a random map $f : R^1 \to Hom(C, D)$, we construct 
            the corresponding map of chain complexes $g : C \to D$.
        Example
            R = ZZ/101[a,b,c]
            C = freeResolution ideal"a,b,c"
            D = freeResolution ideal"a2,b2,c2"
            H = Hom(C,D)
            f = randomComplexMap(H, complex R^{-2})
            isWellDefined f
            g = homomorphism f
            isWellDefined g
            assert not isCommutative g
        Text
            The map $g : C \to D$ corresponding to a random map into $Hom(C,D)$
            does not generally commute with the differentials.  However, if the
            element of $Hom(C,D)$ is a cycle, then the corresponding map does commute.
        Example
            f = randomComplexMap(H, complex R^{-2}, Cycle => true)
            isWellDefined f
            g = homomorphism f
            isWellDefined g
            assert isCommutative g
            assert(degree g === 0)
            assert(source g === C)
            assert(target g === D)
            assert(homomorphism' g == f)
        Text
            A homomorphism of non-zero degree can be encoded
            in (at least) two ways.
        Example
            f1 = randomComplexMap(H, complex R^1, Degree => -2)
            f2 = map(target f1, (source f1)[2], i -> f1_(i+2))
            assert isWellDefined f2
            g1 = homomorphism f1
            g2 = homomorphism f2
            assert(g1 == g2)
            assert isWellDefined g1
            assert isWellDefined g2
            homomorphism' g1 == f1
            homomorphism' g2 == f1
    SeeAlso
        "Working with Ext"
        (homomorphism, Matrix)
        (homomorphism, ZZ, Matrix, Complex)
        (homomorphism', ComplexMap)
        (Hom, Complex, Complex)
        (randomComplexMap, Complex, Complex)
///

doc ///
    Key
        (homomorphism', ComplexMap)
    Headline
        get the element of Hom from a map of complexes
    Usage
        f = homomorphism g
    Inputs
        g:ComplexMap
            from $C$ to $D$
    Outputs
        f:ComplexMap
            a map of the form $f : R^1 \to Hom(C, D)$, where
            $R$ is the underlying ring of these complexes
    Description
        Text
            As a first example, consider two Koszul complexes $C$ and $D$.
            From a random map $f : R^1 \to Hom(C, D)$, we construct 
            the corresponding map of chain complexes $g : C \to D$.
        Example
            R = ZZ/101[a,b,c]
            C = freeResolution ideal"a,b,c"
            D = freeResolution ideal"a2,b2,c2"
            g = randomComplexMap(D, C, InternalDegree => 2)
            isWellDefined g
            f = homomorphism' g
            isWellDefined f
        Text
            The map $g : C \to D$ corresponding to a random map into $Hom(C,D)$
            does not generally commute with the differentials.  However, if the
            element of $Hom(C,D)$ is a cycle, then the corresponding map does commute.
        Example
            g = randomComplexMap(D, C, Cycle => true, InternalDegree => 3)
            isWellDefined g
            f = homomorphism' g
            isWellDefined f
            assert isCommutative g
            assert(degree f === 0)
            assert(source f == complex(R^{-3}))
            assert(target g === D)
            assert(homomorphism f == g)
    SeeAlso
        "Working with Ext"
        (homomorphism', Matrix)
        (homomorphism, ComplexMap)
        (Hom, Complex, Complex)
        (randomComplexMap, Complex, Complex)
///

doc ///
    Key
        (homomorphism, ZZ, Matrix, Complex)
    Headline
        get the homomorphism from an element of Hom
    Usage
        g = homomorphism(i, f, E)
    Inputs
        i:ZZ
        f:Matrix
            a map of the form $f \colon R^1 \to E_i$
        E:Complex
            having the form
            $E = \operatorname{Hom}(C, D)$ for some complexes $C$ and $D$
    Outputs
        g:ComplexMap
            the corresponding map of chain complexes from $C$ to $D$ of degree $i$
    Description
        Text
            An element of the complex $\operatorname{Hom}(C, D)$ corresponds to a map of 
            complexes from $C$ to $D$.  Given an element in the $i$-th term, this
            method returns the corresponding map of complexes of degree $i$.
        Text
            As a first example, consider two Koszul complexes $C$ and $D$.
            From a random map $f \colon R^1 \to Hom(C, D)$, we construct 
            the corresponding map of chain complexes $g \colon C \to D$.
        Example
            R = ZZ/101[a,b,c];
            C = freeResolution ideal"a,b,c"
            D = freeResolution ideal"a2,b2,c2"
            E = Hom(C,D)
            f = random(E_2, R^{-5})
            g = homomorphism(2, f, E)
            assert isWellDefined g
            assert not isCommutative g
        Text
            The map $g \colon C \to D$ corresponding to a random map into $Hom(C,D)$
            does not generally commute with the differentials.  However, if the
            element of $Hom(C,D)$ is a cycle, then the corresponding map does commute.
        Example
            h = randomComplexMap(E, complex R^{-2}, Cycle => true, Degree => -1)
            f = h_0
            g = homomorphism(-1, f, E)
            assert isWellDefined g
            assert isCommutative g
            assert(degree g === -1)
            assert(source g === C)
            assert(target g === D)
            assert(homomorphism' g == h)
    SeeAlso
        "Working with Ext"
        (homomorphism, Matrix)
        (homomorphism', ComplexMap)
        (Hom, Complex, Complex)
        (randomComplexMap, Complex, Complex)
///

doc ///
    Key
        (betti,Complex)
    Headline
        display of degrees in a complex
    Usage
        betti C
    Inputs
        C:Complex
        Weights => List
            a list of integers whose dot product with the multidegree
            of a basis element is enumerated in the display returned.
            The default is the heft vector of the ring.  
            See @TO heft@.
    Outputs
        :BettiTally
            a diagram showing the degrees of the generators of the components in {\tt C}
    Description
        Text
            Column $j$ of the top row of the diagram gives the rank of
            the $j$-th component $C_j$ of the complex $C$.  The entry
            in column $j$ in the row labelled $i$ is the number of
            basis elements of (weighted) degree $i+j$ in $C_j$.  When
            the complex is the free resolution of a module the entries
            are the total and the graded Betti numbers of the module.
      
            As a first example, we consider the ideal in 18 variables
            which cuts out the variety of commuting 3 by 3 matrices.
        Example
            S = ZZ/101[vars(0..17)]
            m1 = genericMatrix(S,a,3,3)
            m2 = genericMatrix(S,j,3,3)
            J = ideal(m1*m2-m2*m1)
            C0 = freeResolution J
            betti C0
        Text
            From the display, we see that $J$ has 8 minimal
            generators, all in degree 2, and that there are 2 linear
            syzygies on these generators, and 31 quadratic syzygies.
            Since this complex is the free resolution of $S/J$, the
            projective dimension is 6, the index of the last column,
            and the regularity of $S/J$ is 4, the index of the last
            row in the diagram.
        Example
            length C0
            pdim betti C0
            regularity betti C0
        Text
            The betti display still makes sense if the complex is not a free resolution.
        Example
            betti dual C0
            C1 = Hom(C0, image matrix{{a,b}});
            betti C1
            C1_-6
        Text
            This module has 10 generators, 2 in degree $-9=(-6)+(-3)$,
            and 8 in degree $-8=(-6)+(-2)$.
        Text
            In the multi-graded case, the heft vector is used, by
	        default, as the weight vector for weighting the components
	        of the degree vectors of basis elements.
        Text
            The following example is a nonstandard $\mathbb{Z}$-graded
            polynomial ring.
        Example
            R = ZZ/101[a,b,c,Degrees=>{-1,-2,-3}];
            heft R
            C2 = freeResolution coker vars R
            betti C2
            betti(C2, Weights => {1})
        Text
            The following example is the Cox ring of the second
            Hirzebruch surface, and the complex is the free resolution
            of the irrelevant ideal.
        Example
            T = QQ[a,b,c,d,Degrees=>{{1,0},{-2,1},{1,0},{0,1}}];
            B = intersect(ideal(a,c),ideal(b,d))
            C3 = freeResolution B
            dd^C3
            heft T
            betti C3
            betti(C3, Weights => {1,0})
            betti(C3, Weights => {0,1})
            degrees C3_1
    SeeAlso
        "Basic invariants and properties"
        betti
        BettiTally
///

-- TODO: once we have Hom evaluation map,
-- let's add in the map from C to dual dual C.
doc ///
   Key
     (dual, Complex)
   Headline
     make the dual of a complex
   Usage
     dual C
   Inputs
     C:Complex
   Outputs
     :Complex
   Description
    Text
      The dual of a complex $C$ is by definition $Hom(C, R)$, where $R$ is the ring of $C$.
    Example
      S = ZZ/101[a..d];
      B = intersect(ideal(a,c),ideal(b,d))
      C1 = freeResolution B
      C2 = dual C1
      assert(C2 == Hom(C1, S^1))
      C1 == dual dual C1
      prune HH C2
    Text
      The double dual is not necessarily isomorphic to the original complex.
    Example
      I = ideal(a^2, a*b, b^2)
      J = ideal(b^3, b*c, c^3)
      K = intersect(I,J)
      f = map(S^1/I ++ S^1/J, S^1/K, {{1},{1}})
      g = map(S^1/(I+J), S^1/I ++ S^1/J, {{1,-1}})
      C = complex{g,f}
      assert isWellDefined C
      assert isExact C
      assert(dual C == 0)
      assert(C != dual dual C)
   SeeAlso
     (Hom, Complex, Complex)
     (dual, Module)
///

doc ///
    Key
        (part, List, Complex)
        (part, ZZ, Complex)
    Headline
        extract a graded component of a complex
    Usage
        part(d, C)
    Inputs
        d:List
            or @TO "ZZ"@, if the underlying ring $R$ is singly graded.
        C:Complex
            that is homogeneous over $R$
    Outputs
        :Complex
          a complex over the coefficient ring of $R$
    Description
        Text
          If $C$ is a graded (homogeneous) complex over a ring $R$, and $d$ is a degree, this method
          computes the degree $d$ part of the complex over the coefficient ring of $R$.
        Text
          Taking parts of a graded (homogeneous) complex commutes with taking homology.
        Example
          R = QQ[a,b,c,d];
          I = ideal(a*b, a*c, b*c, a*d)
          C = freeResolution I
          D = part(4,C)
          prune HH D == part(4, HH C)
          prune HH D == part(4, complex(R^1/I))
        Text
          Given a squarefree monomial ideal corresponding to a
          simplicial complex, in a polynomial ring equipped with the
          fine grading, parts of the dual of the free resolution of the monomial
          ideal are the chain complexes of the induced simplicial
          subcomplexes.
        Example
          S = QQ[a..d, DegreeRank=>4];
          I = intersect(ideal(a,b), ideal(c,d))
          C = dual freeResolution I
          prune HH (part({-1,-1,-1,-1}, C)) -- empty quadrilateral
          prune HH part({-1,-1,0,0}, C) -- 2 points
          prune HH part({0,0,-1,-1}, C) -- 2 points
          prune HH part({0,0,0,0}, C) -- solid quadrilateral
    SeeAlso
        "Making chain complexes"
        (part, List, ComplexMap)
        (truncate, List, Complex)
        (truncate, List, ComplexMap)
        (canonicalTruncation, Complex, Sequence)
        (naiveTruncation, Complex, ZZ, ZZ)
///

-- TODO Obtain the implicit equation of a surface by using this method
--      on a resolution over Rees algebra Mike and/or Greg thinks
--      about an example here.

doc ///
    Key
        (part, List, ComplexMap)
        (part, ZZ, ComplexMap)
    Headline
        extract a graded component of a map of complexes
    Usage
        part(d, f)
    Inputs
        d:List
            or @TO "ZZ"@, if the underlying ring $R$ is singly graded.
        f:ComplexMap
            that is homogeneous over $R$
    Outputs
        :ComplexMap
          a complex map over the coefficient ring of $R$
    Description
        Text
          If $f$ is a graded (homogeneous) map of complexes over a ring $R$, and $d$ is a degree, this method
          computes the degree $d$ part of the complex map over the coefficient ring of $R$.
        Text
          Taking parts of a graded (homogeneous) complex commutes with taking homology.
        Example
          kk = ZZ/7
          R = kk[a,b,c,d];
          I = ideal(a*b, a*c, b*c, a*d)
          J = I + ideal(b^3)
          C = freeResolution I
          D = freeResolution ((R^1/J) ** R^{{1}})
          f = randomComplexMap(D,C, Cycle=>true)
          g = part(2,f)
          assert(part(2, HH f) ==  prune HH part(2, f))
    SeeAlso
        "Making maps between chain complexes"
        (part, List, Complex)
        (truncate, List, Complex)
        (truncate, List, ComplexMap)
        (naiveTruncation, Complex, Sequence)
        (canonicalTruncation, Complex, ZZ, ZZ)
///

doc ///
    Key
        (truncate, List, Complex)
        (truncate, ZZ, Complex)
    Headline
        truncation of a complex 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:Complex
            that is homogeneous over $R$
    Outputs
        :Complex
          a complex 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 chain complexes.
        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 chain complex.
        Example
            R = QQ[a,b,c];
            I = ideal(a*b, a*c, b*c)
            C = freeResolution I
            D = truncate(3,C)
            assert isWellDefined D
            prune HH 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 = freeResolution I
            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 chain complexes"
        (truncate, List, Module)
        (truncate, List, ComplexMap)
        (canonicalTruncation, Complex, Sequence)
        (naiveTruncation, Complex, ZZ, ZZ)
        (part, List, Complex)
///

-- TODO Obtain the implicit equation of a surface by using this method
--      on a resolution over Rees algebra Mike and/or Greg thinks
--      about an example here.

-- TODO the following appears to be a bug in Truncations.m2
-*   R = QQ[a,b,c];
     I = ideal(a*b, a*c, b*c)
     C = freeResolution I
     D = truncate(3,C)
     assert isWellDefined D
     prune HH D
     truncate(3, HH C) -- BUG?
*-

doc ///
    Key
        (naiveTruncation, Complex, ZZ, ZZ)
        (naiveTruncation, Complex, InfiniteNumber, ZZ)
        (naiveTruncation, Complex, Nothing, ZZ)
        (naiveTruncation, Complex, Sequence)
        (naiveTruncation, Complex, ZZ, InfiniteNumber)
        (naiveTruncation, Complex, ZZ, Nothing)
        (naiveTruncation, Complex, InfiniteNumber, InfiniteNumber)
        naiveTruncation
    Headline
        drops all terms of a complex outside a given interval
    Usage
        naiveTruncation(C, lo, hi)
    Inputs
        C:Complex
        lo:ZZ
            or {\tt -infinity} or {\tt null} (the latter two give no lower bound)
        hi:ZZ
            or {\tt infinity} or {\tt null} (the latter two give no upper bound)
    Outputs
        :Complex
    Description
        Text
            Returns a new complex which drops (sets to zero) all modules 
            outside the given range.
        Example
            R = ZZ/101[a,b,c,d,e];
            I = intersect(ideal(a,b),ideal(c,d,e))
            C = freeResolution I
            naiveTruncation(C, 1, 2)
            C16 = naiveTruncation(C, 1, 6)
            isWellDefined C16
            naiveTruncation(C, 1, infinity)
            naiveTruncation(C, -13, 2)
            naiveTruncation(C, -infinity, 2)
            naiveTruncation(C, , 2)
        Text
            Truncation gives rise to a natural short exact sequence of complexes.
        Example
            C' = naiveTruncation(C,, 1)
            C'' = naiveTruncation(C, 2, infinity)
            f = inducedMap(C, C')
            g = inducedMap(C'', C)
            assert isShortExactSequence(g,f)
        Text
            There is another type of truncation, @TO "canonicalTruncation"@, which induces
            an isomorphism on (a range) of homology.
    SeeAlso
        "Making chain complexes"
        (naiveTruncation, ComplexMap, Sequence)
        (canonicalTruncation, Complex, ZZ, ZZ)
        (canonicalTruncation, ComplexMap, ZZ, ZZ)
        (truncate, List, Complex)
///

doc ///
    Key
        (canonicalTruncation, Complex, ZZ, ZZ)
        (canonicalTruncation, Complex, InfiniteNumber, ZZ)
        (canonicalTruncation, Complex, Nothing, ZZ)
        (canonicalTruncation, Complex, Sequence)
        (canonicalTruncation, Complex, ZZ, InfiniteNumber)
        (canonicalTruncation, Complex, ZZ, Nothing)
        (canonicalTruncation, Complex, InfiniteNumber, InfiniteNumber)
        canonicalTruncation
    Headline
        reducing the number of non-zero terms of a complex
    Usage
        canonicalTruncation(C, lo, hi)
    Inputs
        C:Complex
        lo:ZZ
            or {\tt -infinity} or {\tt null} (the latter two give no lower bound)
        hi:ZZ
            or {\tt infinity} or {\tt null} (the latter two give no upper bound)
    Outputs
        :Complex
    Description
        Text
            Returns a new complex which drops (sets to zero) all modules 
            outside the given range, and modifies the ends to preserve homology
            in the given range.
        Example
            R = ZZ/101[a,b,c,d,e];
            I = intersect(ideal(a,b),ideal(c,d,e))
            C = (dual freeResolution I)[-4]
            C1 = canonicalTruncation(C, 1, 2)
            assert isWellDefined C1
            HH C1
            naiveTruncation(HH C, 1, 2) == HH C1
            prune HH C1
        Text
            We illustrate various possibilities for the truncation interval.
        Example
            C2 = canonicalTruncation(C, 1, 6)
            assert isWellDefined C2
            C3 = canonicalTruncation(C, 1, infinity)
            C2 == C3
            C4 = canonicalTruncation(C, -13, 2)
            C5 = canonicalTruncation(C, -infinity, 2)
            C4 == C5
            C6 = canonicalTruncation(C, , 2)
            C4 == C6
        Text
            If the lower and upper bounds are equal in the canonical truncation, 
            the resulting complex has a single nonzero term consisting of the
            homology in that location.
        Example
            assert(canonicalTruncation(C, 1, 1) == naiveTruncation(HH C, 1, 1))
        Text
            If we truncate only from below, then we get an injection
            from the truncation into the original complex, whereas if
            we truncate only from above, we get a surjection onto
            the truncated complex.
        Example
            f = inducedMap(C, C3)
            assert isWellDefined f
            assert(ker f == 0)
            prune coker f
            C7 = canonicalTruncation(C, -infinity, 1)
            C7 != coker f
        Example
            g = inducedMap(C5, C)
            assert isWellDefined g
            assert(coker g == 0)
            C8 = canonicalTruncation(C, 2, infinity)
            prune C8
            prune ker g
        Text
            There is another type of truncation, @TO "naiveTruncation"@, which yields
            a short exact sequence of complexes.
    SeeAlso
        "Making chain complexes"
        (canonicalTruncation, ComplexMap, Sequence)
        (naiveTruncation, Complex, ZZ, ZZ)
        (naiveTruncation, ComplexMap, ZZ, ZZ)
        (truncate, List, Complex)
///

doc ///
    Key
        (symbol SPACE, RingMap, Complex)
    Headline
        apply a ring map
    Usage
        phi C
    Inputs
        phi:RingMap
            whose source is a ring $R$, and whose target is a ring $S$
        C:Complex
            over the ring $R$
    Outputs
        :Complex
            over the ring $S$
    Description
        Text
            We illustrate the image of a complex 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 = freeResolution I
            D = phi C
            isWellDefined D
            dd^D
            prune HH 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 complex.
        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 = freeResolution coker vars R
            D = phi C
            assert isWellDefined D
            assert isHomogeneous D
            prune HH D
    Caveat
        Every term in the complex must be free or a submodule of a free module.
        Otherwise, use @TO (tensor, RingMap, Complex)@.
    SeeAlso
        (symbol SPACE, RingMap, ComplexMap)
        (symbol **, RingMap, Complex)
///

doc ///
    Key
        (symbol**, RingMap, Complex)
        (symbol**, Complex, RingMap)
        (tensor, RingMap, Complex)
        (tensor, Complex, RingMap)
        (symbol**, Complex, Ring)
        (symbol**, Ring, Complex)
    Headline
        tensor a complex 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:Complex
            over the ring $R$
    Outputs
        :Complex
            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 complex 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 = freeResolution I
            D = phi ** C
            assert isWellDefined D
            dd^D
            prune HH 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 = complex {g}
            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 = freeResolution coker vars R
            D = f ** C
            D == f C
            assert isWellDefined D
            assert isHomogeneous D
            prune HH D
            C1 = Hom(C, image vars R)
            D1 = f ** C1
            isWellDefined D1
            assert isHomogeneous D1
    SeeAlso
        (symbol **, RingMap, ComplexMap)
        (symbol SPACE, RingMap, Complex)
///

doc ///
    Key
        (resolution, Complex)
    Headline
        minimal free resolution of a complex
    Usage
        resolution C
    Inputs
        C:Complex
        LengthLimit => ZZ
          this is used to limit somehow the computation where resolutions might be too long or infinite
        DegreeLimit =>
          unused
        HardDegreeLimit =>
          unused
        PairLimit =>
          unused
        SortStrategy =>
          unused
        StopBeforeComputation =>
          unused
        Strategy =>
          unused
        SyzygyLimit => 
          unused
    Outputs
        :Complex
    Description
        Text
            Given a complex $C$, this method produces a quasi-isomorphic complex $F$ 
            all of whose terms are free modules.  The algorithm used minimizes the
            ranks of the free modules in $F$.
        Example
            R = ZZ/101[a,b,c];
            I = ideal(a^2, a*b, b*c)
            C = Hom(freeResolution I, R^1/I)
            assert all(min C .. max C, i -> not isFreeModule C_i)
            fC = resolutionMap C
            FC = resolution C
            prune HH FC
            assert isQuasiIsomorphism fC
            assert isFree FC
            assert isWellDefined fC
            assert(0 == coker fC) -- showing that fC is surjective.
        Text
            The resolution of a short exact sequence is simply the 
            zero complex.
        Example
            J = ideal(a,b)
            K = ideal(b^2,c)
            g1 = map(R^1/(J+K), R^1/J ++ R^1/K, {{1,-1}})
            g2 = map(R^1/J ++ R^1/K, R^1/(intersect(J,K)), {{1},{1}})
            D = complex{g1, g2}
            assert isWellDefined D
            assert isShortExactSequence(g1,g2)
            fD = resolutionMap D
            assert isWellDefined fD
            assert isQuasiIsomorphism fD
            assert(0 == source fD) -- so fD is certainly not surjective!
        Text
            This method just accesses the cached value from
            the method @TO (resolutionMap, Complex)@, which 
            does the actual computation.
    SeeAlso
        (resolutionMap, Complex)
        (freeResolution, Module)
        (isQuasiIsomorphism, ComplexMap)
///

doc ///
    Key
        (minimalPresentation, Complex)
        (prune, Complex)
        (prune, ComplexMap)
        (minimalPresentation, ComplexMap)
    Headline
        minimal presentation of all terms in a complex
    Usage
        D = minimalPresentation C
        D = prune C
        h = minimalPresentation f
        h = prune f
    Inputs
        C:Complex
            or $f$ @ofClass ComplexMap@
        Exclude => 
            unused
    Outputs
        D:Complex
            isomorphic to the input, where each term is replaced
            by a minimally presented model, or $h$ @ofClass ComplexMap@
            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 complexes and complex maps.
        Text
            In particular, homology often needs 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 = dual freeResolution I
            C = HH F
            D = prune C
            g = D.cache.pruningMap
            assert isWellDefined g
            assert isComplexMorphism 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 complexes 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 = freeResolution I
            FJ = freeResolution J
            f = randomComplexMap(FJ, FI ** S^{-1}, Cycle => true)
            C = image f
            D = prune C
            g = D.cache.pruningMap
            assert isWellDefined g
            assert isComplexMorphism 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 complexes $f$.
        Example
            h = prune f
            assert(source h === prune source f)
            assert(target h === prune target f)
   SeeAlso
       "Making chain complexes"
       (minimize, Complex)
       (minimalPresentation, Module)
       randomComplexMap
       freeResolution
       isComplexMorphism
///

doc ///
    Key
        (minimize, Complex)
        minimize
        minimizingMap
    Headline
        a quasi-isomorphic complex whose terms have minimal rank
    Usage
        D = minimize C
    Inputs
        C:Complex
            graded, whose terms are all free modules
    Outputs
        D:Complex
            graded, whose terms are all free modules of minimal rank
    Consequences
        Item
            The projection morphism $g : C \to D$ is available as 
            @TT "g = D.cache.minimizingMap"@.  
    Description
        Text
            This method essentially removes all scalar units 
            from the matrices in the differential of $C$.
            
            We illustrate this in a simple example.
        Example
            S = ZZ/32003[a,b];
            I = ideal(a^2-b^2, a*b)
            C = freeResolution(I, Strategy => Nonminimal)
            betti C
            D = minimize C
            assert(isWellDefined D and isHomogeneous D)
            betti D
            g = D.cache.minimizingMap
            assert isWellDefined g
            assert(isComplexMorphism g and isQuasiIsomorphism g)
            assert(source g == C)
            assert(target g == D)
            assert(coker g == 0)
        Text
            The minimal complex $D$ is a direct summand of the
            original complex $C$.  The natural inclusion
            of $D$ into $C$ can be constructed as follows.
        Example
            f = liftMapAlongQuasiIsomorphism(id_D, g)
            g*f == id_D
            assert(source f == D)
            assert(target f == C)
            assert(ker f == 0)
            f*g
        Text
            The chain complex $D$ is a direct summand of $C$,
            giving rise to a split short exact sequence of
            chain complexes.
        Example
            h = prune canonicalMap(C, ker g)
            assert isShortExactSequence(g, h)
        Text
            Warning: If the input complex is not homogeneous, then
            the output is probably not what one would expect.
        Example
            S = ZZ/32003[a..d]
            J = ideal(a*b*c-b*c, a*d-c, a^3-d^2*c)
            CJ = freeResolution J
            assert not isHomogeneous CJ
            D = minimize CJ
            isWellDefined D
            prune HH D == prune HH CJ
   SeeAlso
       freeResolution
       (resolution, Complex)
       (resolutionMap, Complex)
       (minimalPresentation, Complex)
///

/// -- comment about the above node
-- The following fails due to 'prune' (May 2020, see git issue #1116)
            SZZ = ZZ (monoid S);
            CZZ = complex hashTable for i from min C + 1 to max C list i => sub(dd^C_i, SZZ)
            isWellDefined CZZ
            betti CZZ
            DZZ = minimize CZZ
            assert isWellDefined DZZ
            assert isHomogeneous DZZ -- !! BUG
            betti DZZ
            g = D.cache.minimizingMap
            assert isWellDefined g
            assert isComplexMorphism g
            assert isQuasiIsomorphism g
            assert(source g == C)
            assert(target g == D)
            assert(coker g == 0)
///

/// -- comment about minimize and pruneComplex:
  -- this code can be run for the example ini (minimize,Complex).
  needsPackage "PruneComplex"
  C' = chainComplex C
  D' = pruneComplex(C', UnitTest => isScalar)
  g' = D'.cache.pruningMap
  D = complex D'
  g = complex g'
  source g == D
  target g == C
  isComplexMorphism g
///

doc ///
   Key
     isExact
     (isExact, Complex)
     (isExact, Complex, InfiniteNumber, InfiniteNumber)
     (isExact, Complex, InfiniteNumber, Number)
     (isExact, Complex, Number, InfiniteNumber)
     (isExact, Complex, Number, Number)
   Headline
     whether a complex is exact
   Usage
     isExact C
     isExact(C, lo, hi)
   Inputs
     C:Complex
     lo:Number
       or -infinity
     hi:Number
       or infinity
   Outputs
     :Boolean
       that is true when {\tt C} is exact
   Description
    Text
      The complex $C$ is exact if and only if the homology group
      $H^i(C)$ is the zero module, for all $i$.  If bounds are given,
      then true is returned if $H^i(C) = 0$ for all $lo \le i \le
      hi$.
    Text
      A resolution $C$ is an exact complex except in homological degree 0. 
      The augmented complex $C'$ is exact everywhere.
    Example
      S = ZZ/101[a..d];
      I = monomialCurveIdeal(S, {1,3,4})
      C = freeResolution I
      prune HH C
      assert not isExact C
      assert isExact(C, 1, infinity)
      C' = cone inducedMap(complex(S^1/I), C)[1]
      prune HH C'
      assert isExact C'
   SeeAlso
     (homology, Complex)
     cone
     freeResolution
     prune
///

doc ///
    Key
        (sum, Complex)
        (sum, ComplexMap)
    Headline
        make the direct sum of all terms
    Usage
        sum C
        sum f
    Inputs
        C:Complex
            or {\tt f}, @ofClass ComplexMap@
    Outputs
        :Module
            or @ofClass Matrix@, if the input is a complex map
    Description
        Text
            This is the forgetful functor from the
            category of chain complexes to the category of modules.
            A chain complex $C$ is sent to the direct sum 
            $\bigoplus_i C_i$ of its terms.
            A map of chain complexes $f \colon C \to D$ is sent to the
            direct sum $\bigoplus_i f_i \colon \bigoplus_i C_i \to \bigoplus_i D_i$.
        Example
            S = ZZ/101[a,b,c];
            C = koszulComplex {a,b,c}
            sum C
            assert(rank sum C == 2^3)
        Example
            f = randomComplexMap(C, C, InternalDegree => 1, Cycle => true)
            g = sum f
            assert(g^2 === sum f^2)
            assert(target g === sum target f)
            assert(source g === sum source f)
            h = sum dd^C
            assert(h^2 == 0)
    SeeAlso
        "Basic invariants and properties"
        (directSum, Complex)
        koszulComplex
        randomComplexMap
///
 
doc ///
  Key
    (isFree, Complex)
    isFree
  Headline
    whether a complex consists of free modules
  Usage
    isFree C
  Inputs
    C:Complex
  Outputs
    :Boolean
      that is true when each $C_i$ is a free module
  Description
    Text
      This method checks whether the given representation of each
      module $C_i$ is free. To determine whether the complex $C$ is
      isomorphic to a free complex, use @TO2((prune,Complex), "prune")@.
    Text
      The following example demonstrates that the presentation of a module
      might not reveal the property of being free.
    Example
      S = ZZ/101[a,b];
      M = kernel vars S
      assert not isFreeModule M
      assert isFreeModule prune M
    Text
      By definition, a free resolution $C$ consists of free modules.
      In contrast, the augmented complex $C'$ might or might not
      consist of free modules.
    Example
      C = freeResolution M
      assert isFree C
      C' = cone map(complex M, C, i -> map(M, C_0, 1))[1]
      isWellDefined C'
      assert not isFree C'
      prune C'
      assert isFree prune C'
  SeeAlso
    isFreeModule
    freeResolution
    (prune, Complex)
///

doc ///
    Key
        (yonedaExtension, Matrix)
        yonedaExtension
    Headline
        creates a chain complex representing an extension of modules
    Usage
        C = yonedaExtension f
    Inputs
        f:Matrix
            over a ring $R$, from $R^1$ to $\operatorname{Ext}^d(M,N)$,
            which represents an element in the Ext module
    Outputs
        C:Complex
            which represents the extension corresponding to 
            the element in the Ext module
    Description
        Text
            The module $\operatorname{Ext}^d(M,N)$ corresponds to equivalence classes
            of extensions of $N$ by $M$.  In particular, an element 
            of this module is represented by an exact sequence of the form
            \[
              0 \leftarrow M \leftarrow F_0 \leftarrow F_1 \leftarrow \dots
              \leftarrow F_{d-2} \leftarrow P \leftarrow N \leftarrow 0
            \]
            where $F_0 \leftarrow F_1 \leftarrow \dots$
            is a free resolution of $M$, and $P$ is the pushout of the maps
            $g : F_d \rightarrow N$ and $F_d \rightarrow F_{d-1}$.
            The element corresponding to $f$ in $\operatorname{Ext}^d(M,N)$ lifts to 
            the map $g$.
        Text
            In our first example, the module 
            $\operatorname{Ext}^1(M,R^1)$
            has one generator, in degree 0.
            The middle term in the corresponding short exact sequence
            determines an irreducible rank 2 vector bundle 
            on the elliptic curve, which can be verified by computing
            Fitting ideals.
        Example
            R = ZZ/101[x,y,z]/(y^2*z-x*(x-z)*(x-2*z));
            M = image vars R
            f = basis(0, Ext^1(M, R^1))
            C = yonedaExtension f
            assert isWellDefined C
            assert isShortExactSequence(dd^C_1, dd^C_2)
            E = C_1
            fittingIdeal(1, E)
            saturate fittingIdeal(2, E)
        Text
            For higher Ext modules, we get longer exact sequences.
            When the map $f$ has degree 0, the corresponding exact sequence
            is homogeneous.
        Example
            x = symbol x;
            S = ZZ/101[x_0..x_5];
            I = borel monomialIdeal(x_2*x_3)
            E = Ext^4(S^1/I, S^{-5})
            f = E_{0}
            assert(isHomogeneous f and degree f === {0})
            C = yonedaExtension f
            assert isWellDefined C
            assert isHomogeneous C
            assert(HH C == 0)
        Text
            The inverse operation is given by @TO yonedaExtension'@.
        Example
            f' = yonedaExtension' C
            assert(f' == f)
    SeeAlso
        "Working with Ext"
        (yonedaMap, Matrix)
        (yonedaMap', ComplexMap)
        (yonedaExtension', Complex)
        (yonedaProduct, Module, Module)
        (homomorphism, ComplexMap)
        (homomorphism', ComplexMap)
        fittingIdeal
///

doc ///
    Key
        (yonedaExtension', Complex)
        yonedaExtension'
        [yonedaExtension', MinimalGenerators]
    Headline
        identifies the element of Ext corresponding to an extension
    Usage
        f = yonedaExtension' C
    Inputs
        C:Complex
          exact, of length $d$ over a ring $R$
        MinimalGenerators => Boolean
            whether to @TO prune@ the Ext module
    Outputs
        f:Matrix
          a map from $R^1$ to $\operatorname{Ext}^d(C_0, C_d)$
    Description
        Text
            The module $\operatorname{Ext}^d(M,N)$ corresponds to equivalence classes
            of extensions of $N$ by $M$.  In particular, an element 
            of this module is represented by an exact sequence of the form
            \[
              0 \leftarrow M \leftarrow C_1 \leftarrow C_2 \leftarrow \dots
              \leftarrow C_{d-1} \leftarrow N \leftarrow 0
            \]
            In particular, we have $M = C_0$ and $N = C_d$.
            For any such exact sequence, this method returns the map $f
            \colon R^1 \to \operatorname{Ext}^d(M,N)$
            corresponding to the element in the Ext module.
        Text
            In our first example, the module 
            $\operatorname{Ext}^1(M,R^1)$
            has one generator, in degree 0.
            The middle term in the corresponding short exact sequence
            determines an irreducible rank 2 vector bundle 
            on the elliptic curve.
        Example
            R = ZZ/101[x,y,z]/(y^2*z-x*(x-z)*(x-2*z));
            M = image matrix {{z,y,x}}
            N = R^1;
            E = coker map(R^{3:-1} ++ R^1,,{
                    {y, x, 0, 0}, 
                    {-z, 0, x, -y*z}, 
                    {0, -z, -y, x^2-3*x*z+2*z^2}, 
                    {x^2-3*x*z+2*z^2, y*z, 0, 0}
                    })
            d1 = map(M, E, (cover E)^[0])
            d2 = map(E, N, (cover E)_[1])
            C = complex{d1,d2}
            assert isWellDefined C
            assert isHomogeneous C
            assert isShortExactSequence C
            f = yonedaExtension' C
        Text
            Although the complex representing $f$ is only defined up
            to equivalence of extensions, this method returns the same 
            complex in this example.
        Example
            assert(C == yonedaExtension f)
            assert(basis(0, Ext^1(M,N)) == f)
        Text
            The trivial extension corresponds to the zero element
            in the Ext module.
        Example
            R = ZZ/101[a,b,c,d,e];
            M = coker matrix"a,b,d,e"
            N = coker matrix"c,d,e"
            Ext^3(M,N)
            C = complex{id_M, map(M, R^0, 0), map(R^0, N, 0), id_N}
            assert isWellDefined C
            assert(HH C == 0)
            f = yonedaExtension' C
            assert(target f === Ext^3(M,N))
            assert(f == 0)
            D = yonedaExtension f
            assert(C != D)
    SeeAlso
        "Working with Ext"
        (yonedaMap, Matrix)
        (yonedaMap', ComplexMap)
        (yonedaExtension, Matrix)
        (yonedaProduct, Module, Module)
///

doc ///
    Key
        (yonedaMap, Matrix)
        yonedaMap
        [yonedaMap, LengthLimit]
    Headline
        creates a chain complex map representing an extension of modules
    Usage
        g = yonedaMap f
    Inputs
        f:Matrix
            over a ring $R$, from $R^1$ to $\operatorname{Ext}^d_R(M,N)$,
            which represents an element in the Ext module
        LengthLimit => ZZ
            determines the maximum length of the free resolutions used
    Outputs
        g:ComplexMap
            of degree $-d$ from the free resolution of $M$ to the free
            resolution of $N$ corresponding to the given element in the
            Ext module
    Description
        Text
            The module $\operatorname{Ext}^d_R(M,N)$ is constructed from
            a free resolution $F$ of $M$,
            \[
              0 \leftarrow M \leftarrow F_0 \leftarrow F_1 \leftarrow \dots
              \leftarrow F_d \leftarrow \ldots,
            \]
            by taking the homology of the complex $\operatorname{Hom}_R(F, N)$.
            An element of $\operatorname{Ext}^d_R(M,N)$ is represented by
            an element of $\operatorname{Hom}_R(F_d, N)$.  This map extends to a map
            of degree $-d$ from $F$ to the free resolution of $N$.
        Text
            We illustrate this method by choosing a random element
            in an Ext module.  This particular Ext module may be regarded
            as a possible obstruction space for deformations of the ideal $I$.
        Example
            S = ZZ/101[a..d]
            I = ideal"a2,ab,ac,b3"
            E = Ext^1(I, S^1/I)
            B = basis(0, E)
            f = B * random(S^16, S^1)
            g = yonedaMap f
            assert isWellDefined g
            assert(degree g === -1)
            assert isCommutative g            
            assert isHomogeneous g
            source g -- free resolution of I
            target g -- free resolution of S/I
            assert(yonedaMap' g == f)
        Text
            If the free resolutions are not finite in length,
            one needs to choose a truncation via the optional
            argument {\tt LengthLimit}.
        Example
            R = ZZ/101[x,y,z]/(y^2*z-x*(x-z)*(x-2*z));
            M = image vars R
            prune Ext^3(M, M)
            B = basis(-4, Ext^3(M, M))
            f = B_{2}
            g = yonedaMap(f, LengthLimit => 8)
            assert isHomogeneous g
            assert isWellDefined g
            assert isCommutative g
            assert(degree g === -3)
            assert(yonedaMap' g == map(target f, R^1, f, Degree => -4))
            assert(isHomogeneous yonedaMap' g)
    SeeAlso
        "Working with Ext"
        (yonedaMap', ComplexMap)
        (yonedaExtension, Matrix)
        (yonedaExtension', Complex)
        (yonedaProduct, Matrix, Matrix)
        (yonedaProduct, Module, Module)
///

doc ///
    Key
        (yonedaMap', ComplexMap)
        yonedaMap'
        [yonedaMap', MinimalGenerators]
    Headline
        identifies the element of Ext corresponding to a map of free resolutions
    Usage
        f = yonedaMap' g
    Inputs
        g:ComplexMap
            of degree $-d$ from the free resolution of $M$ to the free
            resolution of $N$
        MinimalGenerators => Boolean
            whether to @TO prune@ the Ext module
    Outputs
        f:Matrix
            over a ring $R$, from $R^1$ to $\operatorname{Ext}^d_R(M,N)$,
            which represents the corresponding element in the Ext module
    Description
        Text
            The module $\operatorname{Ext}^d_R(M,N)$ is constructed from
            a free resolution $F$ of $M$,
            \[
              0 \leftarrow M \leftarrow F_0 \leftarrow F_1 \leftarrow \dots
              \leftarrow F_d \leftarrow \ldots,
            \]
            by taking the homology of the complex $\operatorname{Hom}_R(F, N)$.
            An element of $\operatorname{Ext}^d_R(M,N)$ is represented by
            an element of $\operatorname{Hom}_R(F_d, N)$.  Given a map $g$ extending
            a map of degree $-d$ from $F$ to the free resolution of $N$,
            this method returns the corresponding element in the Ext module.
        Text
            We illustrate this method by choosing a random element
            in an Ext module, constructing the corresponding map  $g$ between free resolutions.
        Example
            S = ZZ/101[a..d]
            I = ideal"a2,ab,ac,b3"
            E = Ext^1(I, S^1/I)
            B = basis(0, E)
            f0 = B * random(S^16, S^1)
            g = yonedaMap f0
            assert(degree g === -1)
            f = yonedaMap' g
            assert isWellDefined f
            assert(degree f == {0})
            assert isHomogeneous f
            source f === S^1
            target f === E
            assert(f == f0)
        Text
            The method @TO yonedaMap'@ is only a one-sided inverse
            to @TO yonedaMap@.
        Example
            R = ZZ/101[x,y,z]/(y^2*z-x*(x-z)*(x-2*z));
            M = image vars R
            B = basis(-4, Ext^3(M, M))
            f0 = B_{2}
            g = yonedaMap(f0, LengthLimit => 8)
            f = yonedaMap' g
            assert isWellDefined f
            assert isHomogeneous f
            assert(degree f === {-4})
            assert(f != f0)
            assert(yonedaMap(f, LengthLimit => 8) == g)
    SeeAlso
        "Working with Ext"
        (yonedaMap, Matrix)
        (yonedaExtension, Matrix)
        (yonedaExtension', Complex)
        (yonedaProduct, Matrix, Matrix)
        (yonedaProduct, Module, Module)
///

doc ///
    Key
        (yonedaProduct, Matrix, Matrix)
        yonedaProduct
    Headline
        make the product of two elements in Ext modules
    Usage
        h = yonedaProduct(f,g)
    Inputs
        f:Matrix
            of the form $f \colon R \to \operatorname{Ext}_R^d(L,M)$
        g:Matrix
            of the form $g \colon R \to \operatorname{Ext}_R^e(M,N)$
    Outputs
        h:Matrix
            of the form $h \colon R \to \operatorname{Ext}_R^{d+e}(L,N)$
    Description
        Text
            Given a triple $(L, M, N)$ of $R$-modules, the Yoneda product is a pairing between $\operatorname{Ext}$-modules
            
            $\phantom{WWWW}
             \operatorname{Ext}_R^d(L,M) \otimes \operatorname{Ext}_R^e(M,N) \to \operatorname{Ext}_R^{d+e}(L,N).
            $


            For an element of $\operatorname{Ext}_R^{e}(M,N)$, thought of as an extension

            $\phantom{WWWW}
             0 \leftarrow M \leftarrow F_{0} \leftarrow F_{1} \leftarrow \dotsb \leftarrow F_{e-2} \leftarrow P \leftarrow N \leftarrow 0,
            $

            and for an element of $\operatorname{Ext}_R^{d}(L,M)$, thought of as an extension

            $\phantom{WWWW}
             0 \leftarrow L \leftarrow G_{0} \leftarrow G_1 \leftarrow \dotsb \leftarrow G_{d-2} \leftarrow Q \leftarrow M \leftarrow 0,
            $

            the Yoneda product corresponds to

            $\phantom{WWWW}
             0 \leftarrow L \leftarrow G_{0} \leftarrow G_{1} \leftarrow \dotsb \leftarrow Q \leftarrow F_{0}
             \leftarrow F_{1} \leftarrow \dotsb \leftarrow P \leftarrow N \leftarrow 0,
            $

            where the map from $F_0$ to $Q$ factors through $M$.  For more information about extensions,
            see @TO yonedaExtension@.
        Text
            Alternatively, the module $\operatorname{Ext}^d_R(L,M)$ is constructed from
            a free resolution $G$ of $L$,

            $\phantom{WWWW}
              0 \leftarrow L \leftarrow G_0 \leftarrow G_1 \leftarrow \dotsb
              \leftarrow G_d \leftarrow \dotsb,
            $

            by taking the homology of the complex $\operatorname{Hom}_R(G, M)$.
            An element of $\operatorname{Ext}^d_R(L,M)$ is represented by
            an element of $\operatorname{Hom}_R(G_d, M)$.  This map extends to a complex map
            having degree $-d$ from $G$ to the free resolution $F$ of $M$.
            The Yoneda product is the composition of the map of chain complexes from 
            $G$ to $F$ with the map of chain complexes having degree $-e$ from $F$ to 
            a free resolution of $N$.
            For more information about these maps, see @TO yonedaMap@.
        Text
            As an example, we take two distinct elements of an $\operatorname{Ext}^1$-module
            to obtain a non-zero element of the $\operatorname{Ext}^2$-module.
        Example
            S = ZZ/101[x_0..x_3];
            I = borel monomialIdeal(x_1*x_2)
            E1 = Ext^1(S^1/I, S^1/I)
            (f, g) = (E1_{6}, E1_{9})
            h = yonedaProduct(f, g)
            assert isWellDefined h
            assert(target h == Ext^2(S^1/I, S^1/I))
            C = yonedaExtension h
            assert isWellDefined C
            assert isHomogeneous C
            assert(HH C == 0)
            assert(coker yonedaProduct(E1,E1) == 0)
        Text
            In our second example, all three modules in the triple are distinct
            and the image of the Yoneda product is not surjective.
        Example
            R = S/(x_0*x_1, x_2*x_3);
            E1 = Ext^1(R^1/(x_0, x_2), R^1/(x_0, x_2, x_3))
            E2 = Ext^2(R^1/(x_0, x_2, x_3), R^1/(x_0, x_1, x_2, x_3))
            E3 = Ext^3(R^1/(x_0, x_2), R^1/(x_0, x_1, x_2, x_3))
            h = yonedaProduct(E1_{0}, E2_{1})
            assert isWellDefined h
            assert(target h == E3)
            C = yonedaExtension h
            assert isWellDefined C
            assert isHomogeneous C
            assert(HH C == 0)
            assert(coker yonedaProduct(E1, E2) != 0)
    SeeAlso
        "Working with Ext"
        (yonedaProduct, Module, Module)
///

doc ///
    Key
        (yonedaProduct, Module, Module)
    Headline
        make the product map between Ext modules
    Usage
        yonedaProduct(D,E)
    Inputs
        D:Module
            having the form $\operatorname{Ext}_R^d(L,M)$
        E:Module
            having the form $\operatorname{Ext}_R^e(M,N)$
    Outputs
        :Matrix
            defining a map from $\operatorname{Ext}_R^d(L,M) \otimes_R \operatorname{Ext}_R^e(M,N)$ to 
            $\operatorname{Ext}_R^{d+e}(L,N)$
    Description
        Text
            For any triple $(L, M, N)$ of $R$-modules, the Yoneda product is a pairing between $\operatorname{Ext}$-modules
            
            $\phantom{WWWW}
             \operatorname{Ext}_R^d(L,M) \otimes \operatorname{Ext}_R^e(M,N) \to \operatorname{Ext}_R^{d+e}(L,N).
            $

            Given $D = \operatorname{Ext}_R^d(L,M)$ and  $E = \operatorname{Ext}_R^e(M,N)$,
            this method returns this pairing. To compute the product of a pair of elements, 
            see @TO (yonedaProduct, Matrix, Matrix)@.

            Specifically, for an element of $\operatorname{Ext}_R^{e}(M,N)$, thought of as an extension

            $\phantom{WWWW}
             0 \leftarrow M \leftarrow F_{0} \leftarrow F_{1} \leftarrow \dotsb \leftarrow F_{e-2} \leftarrow P \leftarrow N \leftarrow 0,
            $

            and for an element of $\operatorname{Ext}_R^{d}(L,M)$, thought of as an extension

            $\phantom{WWWW}
             0 \leftarrow L \leftarrow G_{0} \leftarrow G_1 \leftarrow \dotsb \leftarrow G_{d-2} \leftarrow Q \leftarrow M \leftarrow 0,
            $

            the Yoneda product corresponds to

            $\phantom{WWWW}
             0 \leftarrow L \leftarrow G_{0} \leftarrow G_{1} \leftarrow \dotsb \leftarrow Q \leftarrow F_{0}
             \leftarrow F_{1} \leftarrow \dotsb \leftarrow P \leftarrow N \leftarrow 0,
            $

            where the map from $F_0$ to $Q$ factors through $M$.  For more information about extensions,
            see @TO yonedaExtension@.
        Text
            Alternatively, the module $\operatorname{Ext}^d_R(L,M)$ is constructed from
            a free resolution $G$ of $L$,

            $\phantom{WWWW}
              0 \leftarrow L \leftarrow G_0 \leftarrow G_1 \leftarrow \dotsb
              \leftarrow G_d \leftarrow \dotsb,
            $

            by taking the homology of the complex $\operatorname{Hom}_R(G, M)$.
            An element of $\operatorname{Ext}^d_R(L,M)$ is represented by
            an element of $\operatorname{Hom}_R(G_d, M)$.  This map extends to a complex map
            having degree $-d$ from $G$ to the free resolution $F$ of $M$.
            The Yoneda product is the composition of the map of chain complexes from 
            $G$ to $F$ with the map of chain complexes having degree $-e$ from $F$ to 
            a free resolution of $N$.
            For more information about these maps, see @TO yonedaMap@.
        Text
            In our first example, the image of the tensor product of 
            two $\operatorname{Ext}^1$-modules happens to generate the
            the $\operatorname{Ext}^2$-module.
        Example
            S = ZZ/101[x_0..x_3];
            I = borel monomialIdeal(x_1*x_2)
            E1 = Ext^1(S^1/I, S^1/I)
            h = yonedaProduct(E1, E1)
            assert isWellDefined h
            assert(target h == Ext^2(S^1/I, S^1/I))
            coker h == 0
        Text
            In our second example, all three modules in the triple are distinct
            and the image of the Yoneda product is not surjective.
        Example
            R = S/(x_0*x_1, x_2*x_3);
            E1 = Ext^1(R^1/(x_0, x_2), R^1/(x_0, x_2, x_3))
            E2 = Ext^2(R^1/(x_0, x_2, x_3), R^1/(x_0, x_1, x_2, x_3))
            E3 = Ext^3(R^1/(x_0, x_2), R^1/(x_0, x_1, x_2, x_3))
            h = yonedaProduct(E1, E2)
            assert isWellDefined h
            assert(target h == E3)
            prune coker h
    SeeAlso
        "Working with Ext"
        (yonedaProduct, Matrix, Matrix)
///

doc ///
    Key
        (koszulComplex, Matrix)
        (koszulComplex, List)
        koszulComplex
        [(koszulComplex, Matrix), Concentration]
        [(koszulComplex, List), Concentration]
    Headline
        makes the Koszul complex
    Usage
        K = koszulComplex f
    Inputs
        f:Matrix
            having one row, or a @ofClass List@ of ring elements
        Concentration => Sequence
            a pair {\tt (lo, hi)} which limits the non-zero terms in the output
    Outputs
        :Complex
            the Koszul complex (or a subcomplex)
    Description
        Text
            Let $R$ be a commutative ring and let $E$ be a free $R$-module of finite rank $r$.
            Given a linear map $f \colon E \to R$, the Koszul complex associated to $f$
            is the chain complex of $R$-modules

            $\phantom{WWWW}
              0 \leftarrow R \leftarrow \bigwedge^1 E \leftarrow \bigwedge^2 E \leftarrow \dotsb \leftarrow \bigwedge^r E 
              \leftarrow 0,
            $

            where the differential is given by 

            $\phantom{WWWW}
              dd_k(e_1 \wedge e_2 \wedge \dotsb \wedge e_k) = 
              \sum_{i=1}^k (-1)^{i+1} f(e_i) \, e_1 \wedge e_2 \wedge \dotsb \wedge \widehat{e_i} \wedge \dotsb \wedge e_k,
            $
            
            and the superscript hat means the term is omitted.  For this method, the linear map $f$ is
            given as either a matrix with one row, or a list of ring elements.
        Example
            S = QQ[a..d]
            koszulComplex {a}
            C = koszulComplex {a^2+b^2,c^3}
            dd^C
            K4 = koszulComplex vars S
            dd^K4
            assert isWellDefined K4
        Text
            To obtain natural subcomplexes, use the @TT "Concentration"@ option.
        Example
            koszulComplex(vars S, Concentration => (2,3))
            koszulComplex(vars S, Concentration => (-1,5))
        Text
            The koszul complex can be constructed as an iterated tensor product.
            The maps are identical, except that the even indexed differentials
            have the opposite sign.
        Example
            C = koszulComplex {d} ** (koszulComplex {c} ** (koszulComplex {b} ** koszulComplex {a}))
            K = koszulComplex {a,b,c,d}
            netList {{dd^C, dd^K}}
    SeeAlso
        "Making chain complexes"
        (symbol**, Complex, Complex)
///

doc ///
    Key
        (poincare, Complex)
    Headline
        assemble degrees of a chain complex into a polynomial
    Usage
        poincare C
    Inputs
        C:Complex
    Outputs
        :RingElement
            in the @TO2((degreesRing,Ring), "ring of degrees")@ of the underlying ring of $C$
    Description
        Text
            This method encodes information about the degrees of the generators of each term
            in a chain complex. It returns an element in the degrees ring, which
            is the ring of Laurent polynomials whose monomials
            correspond to the degrees of the monomials in the underlying ring of $C$.
            When the $i$-th term $C_i$ of the complex $C$ 
            is generated by elements of degree $d_{i,1}, d_{i,2}, \dotsc$,
            this Laurent polynomial is 
            $\sum_i (-1)^i \sum_j T^{d_{i,j}}$,
            where we use multi-index notation $T^d =
            T_0^{d_0} T_1^{d_1} \dotsb T_r^{d_r}$.
        Example
            R = ZZ/32003[a..f];
            K = koszulComplex vars R
            betti K
            p = poincare K
            factor p
        Example
            C = freeResolution ideal(a*b, b*c*d, c*d*e^2)
            betti C
            poincare C
        Text
            Since the number of variables in the degrees ring is 
            equal to the rank of the grading group, the Poincare 
            polynomial may have more than one variable.
        Example
            S = ZZ/101[x,y,z, DegreeRank => 3];
            L = koszulComplex vars S
            poincare L
        Text
            If the terms in the complex are not free, then
            this method uses just the degrees of the generators of each term.
        Example
            D = C ** coker vars R
            poincare D
            betti D
        Text
            This is equivalent to computing the Poincare polynomial of the Betti table.
        Example
            poincare betti D
    SeeAlso
        "Basic invariants and properties"
        poincare
        (poincareN, Complex)
        betti
///

-- TODO: add in the key poincareN, once Complexes replaces ChainComplexes...
doc ///
    Key
        (poincareN, Complex)
    Headline
        assemble degrees of a chain complex into a polynomial
    Usage
        poincareN C
    Inputs
        C:Complex
    Outputs
        :RingElement
    Description
        Text
            This method encodes information about the internal and
            homological degrees of the generators of each term in a
            chain complex. It returns an element in the ring of
            Laurent polynomials whose monomials correspond to the
            degrees of the monomials in the underlying ring of $C$,
            together with a variable to record the homological degree.
            When the $i$-th term $C_i$ of the complex $C$ is generated
            by elements of degree $d_{i,1}, d_{i,2}, \dotsc$, this
            Laurent polynomial is $\sum_i (-1)^i \sum_j S^i
            T^{d_{i,j}}$, where we use multi-index notation $T^d =
            T_0^{d_0} T_1^{d_1} \dotsb T_r^{d_r}$.
        Example
            R = ZZ/32003[a..f];
            K = koszulComplex vars R
            betti K
            p = poincareN K
            factor p
        Example
            C = freeResolution ideal(a*b, b*c*d, c*d*e^2)
            betti C
            poincareN C
        Text
            Since the number of variables in the degrees ring is 
            equal to the rank of the grading group, the Poincare 
            polynomial may have more than one variable.
        Example
            S = ZZ/101[x,y,z, DegreeRank => 3];
            L = koszulComplex vars S
            poincareN L
        Text
            If the terms in the complex are not free, then
            this method uses just the degrees of the generators of each term.
        Example
            D = C ** coker vars R
            poincareN D
            betti D
    SeeAlso
        "Basic invariants and properties"
        (poincare, Complex)
        betti
///

doc ///
    Key
        (regularity, Complex)
    Headline
        compute the Castelnuovo-Mumford regularity
    Usage
        regularity C
    Inputs
        C:Complex
        Weights => List
            for more information, see @TO [regularity, Weights]@
    Outputs
        :ZZ
    Description
        Text
            Given a free complex $C$ over a standard graded polynomial ring,
            the regularity $r$ of $C$ is the smallest integer such that
            each basis element of $C_i$ has degree at most $i + r$.
        Example
            R = ZZ/101[a..d];
            I = ideal(b^2-a*c, b*c-a*d, c^2-b*d)
            C = freeResolution(R^1/I)
            betti C
            regularity C
            regularity I
            regularity (R^1/I)
            assert(regularity C === regularity(R^1/I))
        Text
            The regularity is the label of the last row of the Betti table of $C$.
        Example
            betti C
            betti(C[3])
            regularity(C[3])
        Text
            Here is a slightly more complicated example.
        Example
            J = ideal(a^3, b^3, c^3, d^3, (a+b+c+d)^3);
            FJ = freeResolution J
            betti FJ
            regularity FJ
        Text
            Although Castelnuovo-Mumford regularity is defined
            in more general settings (e.g. toric varieties with multi-degrees)
            this method does not currently handle these 
            extensions.  Similarly, Castelnuovo-Mumford
            regularity can be defined for non-free complexes,
            but this method doesn't handle that case either.
    SeeAlso
        "Basic invariants and properties"
        regularity
        betti
        freeResolution
///

///
    Key
    Headline
    Usage
    Inputs
    Outputs
    Description
        Text
        Example
    Caveat
    SeeAlso
///
