Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/homalg/gap/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 10.0.2024 mit Größe 59 kB image not shown  

Quelle  HomalgComplex.gi   Sprache: unbekannt

 
# SPDX-License-Identifier: GPL-2.0-or-later
# homalg: A homological algebra meta-package for computable Abelian categories
#
# Implementations
#

##  Implementation stuff for homalg complexes.

####################################
#
# representations:
#
####################################

##  <#GAPDoc Label="IsComplexOfFinitelyPresentedObjectsRep">
##  <ManSection>
##    <Filt Type="Representation" Arg="C" Name="IsComplexOfFinitelyPresentedObjectsRep"/>
##    <Returns><C>true</C> or <C>false</C></Returns>
##    <Description>
##      The &GAP; representation of complexes of finitley presented &homalg; objects. <P/>
##      (It is a representation of the &GAP; category <Ref Filt="IsHomalgComplex"/>,
##       which is a subrepresentation of the &GAP; representation <C>IsFinitelyPresentedObjectRep</C>.)
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareRepresentation( "IsComplexOfFinitelyPresentedObjectsRep",
        IsHomalgComplex and IsFinitelyPresentedObjectRep,
        [  ] );

##  <#GAPDoc Label="IsCocomplexOfFinitelyPresentedObjectsRep">
##  <ManSection>
##    <Filt Type="Representation" Arg="C" Name="IsCocomplexOfFinitelyPresentedObjectsRep"/>
##    <Returns><C>true</C> or <C>false</C></Returns>
##    <Description>
##      The &GAP; representation of cocomplexes of finitley presented &homalg; objects. <P/>
##      (It is a representation of the &GAP; category <Ref Filt="IsHomalgComplex"/>,
##       which is a subrepresentation of the &GAP; representation <C>IsFinitelyPresentedObjectRep</C>.)
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareRepresentation( "IsCocomplexOfFinitelyPresentedObjectsRep",
        IsHomalgComplex and IsFinitelyPresentedObjectRep,
        [  ] );

####################################
#
# families and types:
#
####################################

# a new family:
BindGlobal( "TheFamilyOfHomalgComplexes",
        NewFamily( "TheFamilyOfHomalgComplexes" ) );

# four new types:
BindGlobal( "TheTypeHomalgComplexOfLeftObjects",
        NewType( TheFamilyOfHomalgComplexes,
                IsComplexOfFinitelyPresentedObjectsRep and IsHomalgLeftObjectOrMorphismOfLeftObjects ) );

BindGlobal( "TheTypeHomalgComplexOfRightObjects",
        NewType( TheFamilyOfHomalgComplexes,
                IsComplexOfFinitelyPresentedObjectsRep and IsHomalgRightObjectOrMorphismOfRightObjects ) );

BindGlobal( "TheTypeHomalgCocomplexOfLeftObjects",
        NewType( TheFamilyOfHomalgComplexes,
                IsCocomplexOfFinitelyPresentedObjectsRep and IsHomalgLeftObjectOrMorphismOfLeftObjects ) );

BindGlobal( "TheTypeHomalgCocomplexOfRightObjects",
        NewType( TheFamilyOfHomalgComplexes,
                IsCocomplexOfFinitelyPresentedObjectsRep and IsHomalgRightObjectOrMorphismOfRightObjects ) );

####################################
#
# global variables:
#
####################################

HOMALG.PropertiesOfComplexes :=
  [ IsZero,
    IsSequence,
    IsComplex,
    IsAcyclic,
    IsRightAcyclic,
    IsLeftAcyclic,
    IsGradedObject,
    IsExactSequence,
    IsShortExactSequence,
    IsTriangle,
    IsExactTriangle,
    IsSplitShortExactSequence ];

####################################
#
# methods for operations:
#
####################################

##
InstallMethod( homalgResetFilters,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    local property;
    
    for property in HOMALG.PropertiesOfComplexes do
        ResetFilterObj( C, property );
    od;
    
    if HasBettiTable( C ) then
        ResetFilterObj( C, BettiTable );
        Unbind( C!.BettiTable );
    fi;
    
    if HasFiltrationByShortExactSequence( C ) then
        ResetFilterObj( C, FiltrationByShortExactSequence );
        Unbind( C!.FiltrationByShortExactSequence );
    fi;
    
    if IsBound( C!.HomologyGradedObject ) then
        Unbind( C!.HomologyGradedObject );
    fi;
    
    if IsBound( C!.CohomologyGradedObject ) then
        Unbind( C!.CohomologyGradedObject );
    fi;
    
    if IsBound( C!.resolutions ) then
        Unbind( C!.resolutions );
    fi;
    
end );

##
InstallMethod( StructureObject,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    
    return StructureObject( LowestDegreeObject( C ) );
    
end );

##
InstallMethod( HomalgCategory,
        "for homalg morphisms",
        [ IsHomalgComplex ],
        
  function( phi )
    
    return HomalgCategory( LowestDegreeObject( phi ) );
    
end );

## provided to avoid branching in the code and always returns fail
InstallMethod( PositionOfTheDefaultPresentation,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    
    return fail;
    
end );

##
InstallMethod( ObjectDegreesOfComplex,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    
    return C!.degrees;
    
end );

##
InstallMethod( MorphismDegreesOfComplex,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    local degrees, l;
    
    degrees := ObjectDegreesOfComplex( C );
    
    l := Length( degrees );
    
    if l = 1 then
        return [  ];
    elif IsComplexOfFinitelyPresentedObjectsRep( C ) then
        return degrees{[ 2 .. l ]};
    else
        return degrees{[ 1 .. l - 1 ]};
    fi;
    
end );

##
InstallMethod( CertainMorphism,
        "for homalg complexes",
        [ IsHomalgComplex, IsInt ],
        
  function( C, i )
    local m;
    
    if IsBound( C!.(String( i )) ) and IsHomalgMorphism( C!.(String( i )) ) then
        return C!.(String( i ));
    fi;
    
    if IsBound( C!.MorphismConstructor ) then
        m := C!.MorphismConstructor( i );
        C!.(String( i )) := m;
        return m;
    fi;
    
    return fail;
    
end );

##
InstallMethod( CertainObject,
        "for homalg complexes",
        [ IsHomalgComplex, IsInt ],
        
  function( C, i )
    local degrees, l, o;
    
    if IsBound( C!.(String( i )) ) then
        if IsHomalgObject( C!.(String( i )) ) then
            return C!.(String( i ));
        else
            return Source( C!.(String( i )) );
        fi;
    fi;
    
    degrees := ObjectDegreesOfComplex( C );
    l := Length( degrees );
    
    if IsComplexOfFinitelyPresentedObjectsRep( C ) and degrees[1] = i then
        return Range( CertainMorphism( C, i + 1 ) );
    elif IsCocomplexOfFinitelyPresentedObjectsRep( C ) and degrees[l] = i then
        return Range( CertainMorphism( C, i - 1 ) );
    fi;
    
    if IsBound( C!.ObjectConstructor ) then
        o := C!.ObjectConstructor( i );
        C!.(String( i )) := o;
        return o;
    fi;
    
    return fail;
    
end );

##
InstallMethod( MorphismsOfComplex,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    local degrees;
    
    degrees := MorphismDegreesOfComplex( C );
    
    if Length( degrees ) = 0 then
        return [  ];
    fi;
    
    return List( degrees, i -> CertainMorphism( C, i ) );
    
end );

##
InstallMethod( ObjectsOfComplex,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    local morphisms, l, objects;
    
    morphisms := MorphismsOfComplex( C );
    
    l := Length( morphisms );
    
    if l = 0 then
        return [ CertainObject( C, ObjectDegreesOfComplex( C )[1] ) ];
    elif IsComplexOfFinitelyPresentedObjectsRep( C ) then
        objects := List( morphisms, Range );
        Add( objects, Source( morphisms[l] ) );
    else
        objects := List( morphisms, Source );
        Add( objects, Range( morphisms[l] ) );
    fi;
    
    return objects;
    
end );

##
InstallMethod( LowestDegree,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    
    return ObjectDegreesOfComplex( C )[1];
    
end );

##
InstallMethod( HighestDegree,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    local degrees;
    
    degrees := ObjectDegreesOfComplex( C );
    
    return degrees[Length( degrees )];
    
end );

##
InstallMethod( LowestDegreeObject,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    
    return CertainObject( C, LowestDegree( C ) );
    
end );

##
InstallMethod( HighestDegreeObject,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    local degrees;
    
    degrees := ObjectDegreesOfComplex( C );
    
    return CertainObject( C, HighestDegree( C ) );
    
end );

##
InstallMethod( LowestDegreeMorphism,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    local degrees;
    
    degrees := MorphismDegreesOfComplex( C );
    
    return CertainMorphism( C, degrees[1] );
    
end );

##
InstallMethod( HighestDegreeMorphism,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    local degrees;
    
    degrees := MorphismDegreesOfComplex( C );
    
    return CertainMorphism( C, degrees[Length( degrees )] );
    
end );

##
InstallMethod( SupportOfComplex,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    local degrees, l, objects;
    
    degrees := ObjectDegreesOfComplex( C );
    
    l := Length( degrees );
    
    objects := ObjectsOfComplex( C );
    
    return degrees{ Filtered( [ 1 .. l ], i -> not IsZero( objects[i] ) ) };
    
end );

##  <#GAPDoc Label="Add:complex">
##  <ManSection>
##    <Oper Arg="C, phi" Name="Add" Label="to complexes given a morphism"/>
##    <Oper Arg="C, mat" Name="Add" Label="to complexes given a matrix"/>
##    <Returns>a &homalg; complex</Returns>
##    <Description>
##    In the first syntax the morphism <A>phi</A> is added to the (co)chain complex <A>C</A>
##    (&see; <Ref Sect="Complexes:Constructors"/>) as the new <E>highest</E> degree
##    morphism and the altered argument <A>C</A> is returned. In case <A>C</A> is a chain complex, the highest degree
##    object in <A>C</A> and the target of <A>phi</A> must be <E>identical</E>. In case <A>C</A> is a <E>co</E>chain
##    complex, the highest degree object in <A>C</A> and the source of <A>phi</A>  must be <E>identical</E>. <P/>
##    In the second syntax the matrix <A>mat</A> is interpreted as the matrix of the new <E>highest</E> degree morphism
##    <M>psi</M>, created according to the following rules:
##    In case <A>C</A> is a chain complex, the highest degree left (resp. right) object <M>C_d</M> in <A>C</A>
##    is declared as the target of <M>psi</M>, while its source is taken to be a free left (resp. right) object of rank
##    equal to <C>NumberRows</C>(<A>mat</A>) (resp. <C>NumberColumns</C>(<A>mat</A>)). For this <C>NumberColumns</C>(<A>mat</A>)
##    (resp. <C>NumberRows</C>(<A>mat</A>)) must coincide with the <C>NrGenerators</C>(<M>C_d</M>).
##    In case <A>C</A> is a <E>co</E>chain complex, the highest degree left (resp. right) object <M>C^d</M> in <A>C</A>
##    is declared as the source of <M>psi</M>, while its target is taken to be a free left (resp. right) object of rank
##    equal to <C>NumberColumns</C>(<A>mat</A>) (resp. <C>NumberRows</C>(<A>mat</A>)). For this <C>NumberRows</C>(<A>mat</A>)
##    (resp. <C>Columns</C>(<A>mat</A>)) must coincide with the <C>NrGenerators</C>(<M>C^d</M>).
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );
##  Z
##  gap> mat := HomalgMatrix( "[ 0, 1,   0, 0 ]", 2, 2, zz );
##  <A 2 x 2 matrix over an internal ring>
##  gap> phi := HomalgMap( mat );
##  <A homomorphism of left modules>
##  gap> C := HomalgComplex( phi );
##  <A non-zero acyclic complex containing a single morphism of left modules at de\
##  grees [ 0 .. 1 ]>
##  gap> Add( C, mat );
##  gap> C;
##  <A sequence containing 2 morphisms of left modules at degrees [ 0 .. 2 ]>
##  gap> Display( C );
##  -------------------------
##  at homology degree: 2
##  Z^(1 x 2)
##  -------------------------
##  [ [  0,  1 ],
##    [  0,  0 ] ]
##  
##  the map is currently represented by the above 2 x 2 matrix
##  ------------v------------
##  at homology degree: 1
##  Z^(1 x 2)
##  -------------------------
##  [ [  0,  1 ],
##    [  0,  0 ] ]
##  
##  the map is currently represented by the above 2 x 2 matrix
##  ------------v------------
##  at homology degree: 0
##  Z^(1 x 2)
##  -------------------------
##  gap> IsComplex( C );
##  true
##  gap> IsAcyclic( C );
##  true
##  gap> IsExactSequence( C );
##  false
##  gap> C;
##  <A non-zero acyclic complex containing 2 morphisms of left modules at degrees
##  [ 0 .. 2 ]>
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( Add,
        "for homalg complexes",
        [ IsComplexOfFinitelyPresentedObjectsRep, IsMorphismOfFinitelyGeneratedObjectsRep ],
        
  function( C, phi )
    local degrees, l, psi;
    
    if HasIsATwoSequence( C ) and IsATwoSequence( C ) then
        Error( "this complex is write-protected since IsATwoSequence = true\n" );
    fi;
    
    degrees := ObjectDegreesOfComplex( C );
    
    l := Length( degrees );
    
    if l = 1 then
        
        l := degrees[l];
        
        if IsHomalgChainMorphism( phi ) then
            if CertainObject( C, l ) <> Range( phi ) then
                Error( "the unique object in the complex and the target of the new chain morphism are not equal\n" );
            fi;
        else
            if not IsIdenticalObj( CertainObject( C, l ), Range( phi ) ) then
                Error( "the unique object in the complex and the target of the new morphism are not identical\n" );
            fi;
        fi;
        
        Unbind( C!.(String( l )) );
        
        Add( degrees, l + 1 );
        
        C!.(String( l + 1 )) := phi;
        
    else
        
        l := degrees[l];
        
        if IsHomalgChainMorphism( phi ) then
            if Source( CertainMorphism( C, l ) ) <> Range( phi ) then
                Error( "the source of the ", l, ". chain morphism in the complex (i.e. the highest one) and the target of the new one are not equal\n" );
            fi;
        else
            if not IsIdenticalObj( Source( CertainMorphism( C, l ) ), Range( phi ) ) then
                Error( "the source of the ", l, ". morphism in the complex (i.e. the highest one) and the target of the new one are not identical\n" );
            fi;
        fi;
        
        Add( degrees, l + 1 );
        
        C!.(String( l + 1 )) := phi;
        
    fi;
    
    ConvertToRangeRep( degrees );
    
    if HasIsGradedObject( C ) and IsGradedObject( C ) and
       HasIsMorphism( phi ) and IsMorphism( phi ) then
        homalgResetFilters( C );
        SetIsComplex( C, true );
    elif HasIsSequence( C ) and IsSequence( C ) and
      HasIsMorphism( phi ) and IsMorphism( phi ) then
        homalgResetFilters( C );
        SetIsSequence( C, true );
    else
        homalgResetFilters( C );
    fi;
    
    if Length( degrees ) = 3 then
        psi := LowestDegreeMorphism( C );
        if HasIsEpimorphism( psi ) and IsEpimorphism( psi ) and
           ( ( HasKernelEmb( psi ) and IsIdenticalObj( KernelEmb( psi ), phi ) ) or
             ( HasCokernelEpi( phi ) and IsIdenticalObj( CokernelEpi( phi ), psi ) ) ) then
            SetIsShortExactSequence( C, true );
        fi;
    fi;
    
    return C;
    
end );

##
InstallMethod( Add,
        "for homalg cocomplexes",
        [ IsMorphismOfFinitelyGeneratedObjectsRep, IsComplexOfFinitelyPresentedObjectsRep ],
        
  function( phi, C )
    local degrees, l, psi;
    
    degrees := ObjectDegreesOfComplex( C );
    
    l := Length( degrees );
    
    if l = 1 then
        
        l := degrees[1];
        
        if IsHomalgChainMorphism( phi ) then
            if CertainObject( C, l ) <> Source( phi ) then
                Error( "the unique object in the complex and the source of the new chain morphism are not equal\n" );
            fi;
        else
            if not IsIdenticalObj( CertainObject( C, l ), Source( phi ) ) then
                Error( "the unique object in the complex and the source of the new morphism are not identical\n" );
            fi;
        fi;
        
    else
        
        l := degrees[1];
        
        if IsHomalgChainMorphism( phi ) then
            if Range( CertainMorphism( C, l + 1 ) ) <> Source( phi ) then
                Error( "the target of the ", l + 1, ". chain morphism in the complex (i.e. the highest one) and the source of the new one are not equal\n" );
            fi;
        else
            if not IsIdenticalObj( Range( CertainMorphism( C, l + 1 ) ), Source( phi ) ) then
                Error( "the target of the ", l + 1, ". morphism in the complex (i.e. the highest one) and the source of the new one are not identical\n" );
            fi;
        fi;
        
    fi;
    
    C!.degrees := Concatenation( [ l - 1 ], degrees );
    
    C!.(String( l )) := phi;
    
    degrees := C!.degrees;
    
    ConvertToRangeRep( degrees );
    
    if HasIsGradedObject( C ) and IsGradedObject( C ) and
       HasIsMorphism( phi ) and IsMorphism( phi ) then
        homalgResetFilters( C );
        SetIsComplex( C, true );
    elif HasIsSequence( C ) and IsSequence( C ) and
      HasIsMorphism( phi ) and IsMorphism( phi ) then
        homalgResetFilters( C );
        SetIsSequence( C, true );
    else
        homalgResetFilters( C );
    fi;
    
    if Length( degrees ) = 3 then
        psi := LowestDegreeMorphism( C );
        if HasIsEpimorphism( psi ) and IsEpimorphism( psi ) and
           ( ( HasKernelEmb( psi ) and IsIdenticalObj( KernelEmb( psi ), phi ) ) or
             ( HasCokernelEpi( phi ) and IsIdenticalObj( CokernelEpi( phi ), psi ) ) ) then
            SetIsShortExactSequence( C, true );
        fi;
    fi;
    
    return C;
    
end );

##
InstallMethod( Add,
        "for homalg cocomplexes",
        [ IsCocomplexOfFinitelyPresentedObjectsRep, IsMorphismOfFinitelyGeneratedObjectsRep ],
        
  function( C, phi )
    local degrees, l, psi;
    
    degrees := ObjectDegreesOfComplex( C );
    
    l := Length( degrees );
    
    if l = 1 then
        
        if IsHomalgChainMorphism( phi ) then
            if CertainObject( C, degrees[1] ) <> Source( phi ) then
                Error( "the unique object in the cocomplex and the source of the new chain morphism are not equal\n" );
            fi;
        else
            if not IsIdenticalObj( CertainObject( C, degrees[1] ), Source( phi ) ) then
                Error( "the unique object in the cocomplex and the source of the new morphism are not identical\n" );
            fi;
        fi;
        
        Add( degrees, degrees[1] + 1 );
        
        C!.(String( degrees[1] )) := phi;
        
    else
        
        l := degrees[l - 1];
        
        if IsHomalgChainMorphism( phi ) then
            if Range( CertainMorphism( C, l ) ) <>  Source( phi ) then
                Error( "the target of the ", l, ". chain morphism in the cocomplex (i.e. the highest one) and the source of the new one are not equal\n" );
            fi;
        else
            if not IsIdenticalObj( Range( CertainMorphism( C, l ) ), Source( phi ) ) then
                Error( "the target of the ", l, ". morphism in the cocomplex (i.e. the highest one) and the source of the new one are not identical\n" );
            fi;
        fi;
        
        Add( degrees, l + 2 );
        
        C!.(String( l + 1 )) := phi;
        
    fi;
    
    ConvertToRangeRep( degrees );
    
    if HasIsGradedObject( C ) and IsGradedObject( C ) and
       HasIsMorphism( phi ) and IsMorphism( phi ) then
        homalgResetFilters( C );
        SetIsComplex( C, true );
    elif HasIsSequence( C ) and IsSequence( C ) and
      HasIsMorphism( phi ) and IsMorphism( phi ) then
        homalgResetFilters( C );
        SetIsSequence( C, true );
    else
        homalgResetFilters( C );
    fi;
    
    if Length( degrees ) = 3 then
        psi := LowestDegreeMorphism( C );
        if HasIsMonomorphism( psi ) and IsMonomorphism( psi ) and
           ( ( HasCokernelEpi( psi ) and IsIdenticalObj( CokernelEpi( psi ), phi ) ) or
             ( HasKernelEmb( phi ) and IsIdenticalObj( KernelEmb( phi ), psi ) ) ) then
            SetIsShortExactSequence( C, true );
        fi;
    fi;
    
    return C;
    
end );

##
InstallMethod( Add,
        "for homalg cocomplexes",
        [ IsMorphismOfFinitelyGeneratedObjectsRep, IsCocomplexOfFinitelyPresentedObjectsRep ],
        
  function( phi, C )
    local degrees, l, psi;
    
    degrees := ObjectDegreesOfComplex( C );
    
    l := Length( degrees );
    
    if l = 1 then
        
        l := degrees[1];
        
        if IsHomalgChainMorphism( phi ) then
            if CertainObject( C, l ) <> Range( phi ) then
                Error( "the unique object in the cocomplex and the range of the new chain morphism are not equal\n" );
            fi;
        else
            if not IsIdenticalObj( CertainObject( C, l ), Range( phi ) ) then
                Error( "the unique object in the cocomplex and the range of the new morphism are not identical\n" );
            fi;
        fi;
        
        C!.degrees := Concatenation( [ l - 1 ], degrees );
        
        C!.(String( l - 1 )) := phi;
        
    else
        
        l := degrees[1];
        
        if IsHomalgChainMorphism( phi ) then
            if Source( CertainMorphism( C, l ) ) <>  Range( phi ) then
                Error( "the source of the ", l, ". chain morphism in the cocomplex (i.e. the lowest one) and the target of the new one are not equal\n" );
            fi;
        else
            if not IsIdenticalObj( Source( CertainMorphism( C, l ) ), Range( phi ) ) then
                Error( "the source of the ", l, ". morphism in the cocomplex (i.e. the lowest one) and the target of the new one are not identical\n" );
            fi;
        fi;
        
        C!.degrees := Concatenation( [ l - 1 ], degrees );
        
        C!.(String( l - 1 )) := phi;
        
    fi;
    
    degrees := C!.degrees;
    
    ConvertToRangeRep( degrees );
    
    if HasIsSequence( C ) and IsSequence( C ) and
       HasIsMorphism( phi ) and IsMorphism( phi ) then
        homalgResetFilters( C );
        SetIsSequence( C, true );
    else
        homalgResetFilters( C );
    fi;
    
    ## FIXME: insert a SetIsShortExactSequence statement, analogous to the above Add method
    
    return C;
    
end );

##
InstallMethod( Add,
        "for homalg complexes",
        [ IsComplexOfFinitelyPresentedObjectsRep, IsStaticFinitelyPresentedObjectRep ],
        
  function( C, M )
    local T, grd, cpx, seq;
    
    T := HighestDegreeObject( C );
    
    if HasIsGradedObject( C ) then
        grd := IsGradedObject( C );
    elif HasIsComplex( C ) then
        cpx := IsComplex( C );
    elif HasIsSequence( C ) then
        seq := IsSequence ( C );
    fi;
    
    Add( C, TheZeroMorphism( M, T ) );
    
    if IsBound( grd ) then
        SetIsGradedObject( C, grd );
    elif IsBound( cpx ) then
        SetIsComplex( C, cpx );
    elif IsBound( seq ) then
        SetIsSequence( C, seq );
    fi;
    
end );

##
InstallMethod( Add,
        "for homalg complexes",
        [ IsCocomplexOfFinitelyPresentedObjectsRep, IsStaticFinitelyPresentedObjectRep ],
        
  function( C, M )
    local S, grd, cpx, seq;
    
    S := HighestDegreeObject( C );
    
    if HasIsGradedObject( C ) then
        grd := IsGradedObject( C );
    elif HasIsComplex( C ) then
        cpx := IsComplex( C );
    elif HasIsSequence( C ) then
        seq := IsSequence ( C );
    fi;
    
    Add( C, TheZeroMorphism( S, M ) );
    
    if IsBound( grd ) then
        SetIsGradedObject( C, grd );
    elif IsBound( cpx ) then
        SetIsComplex( C, cpx );
    elif IsBound( seq ) then
        SetIsSequence( C, seq );
    fi;
    
end );

##
InstallMethod( Add,
        "for homalg complexes",
        [ IsStaticFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep ],
        
  function( M, C )
    local T, grd, cpx, seq;
    
    T := LowestDegreeObject( C );
    
    if HasIsGradedObject( C ) then
        grd := IsGradedObject( C );
    elif HasIsComplex( C ) then
        cpx := IsComplex( C );
    elif HasIsSequence( C ) then
        seq := IsSequence ( C );
    fi;
    
    Add( TheZeroMorphism( T, M ), C );
    
    if IsBound( grd ) then
        SetIsGradedObject( C, grd );
    elif IsBound( cpx ) then
        SetIsComplex( C, cpx );
    elif IsBound( seq ) then
        SetIsSequence( C, seq );
    fi;
    
end );

##
InstallMethod( Add,
        "for homalg complexes",
        [ IsStaticFinitelyPresentedObjectRep, IsCocomplexOfFinitelyPresentedObjectsRep ],
        
  function( M, C )
    local S, grd, cpx, seq;
    
    S := LowestDegreeObject( C );
    
    if HasIsGradedObject( C ) then
        grd := IsGradedObject( C );
    elif HasIsComplex( C ) then
        cpx := IsComplex( C );
    elif HasIsSequence( C ) then
        seq := IsSequence ( C );
    fi;
    
    Add( TheZeroMorphism( M, S ), C );
    
    if IsBound( grd ) then
        SetIsGradedObject( C, grd );
    elif IsBound( cpx ) then
        SetIsComplex( C, cpx );
    elif IsBound( seq ) then
        SetIsSequence( C, seq );
    fi;
    
end );

##
InstallMethod( Shift,
        "for homalg complexes",
        [ IsHomalgComplex, IsInt ],
        
  function( C, s )
    local d, Cd, Cs;
    
    d := LowestDegree( C );
    
    Cd := LowestDegreeObject( C );
    
    if IsComplexOfFinitelyPresentedObjectsRep( C ) then
        Cs := HomalgComplex( Cd, d - s );
    else
        Cs := HomalgCocomplex( Cd, d - s );
    fi;
    
    Perform ( MorphismsOfComplex( C ), function( m ) Add( Cs, m ); end );
    
    if HasIsGradedObject( C ) and IsGradedObject( C ) then
        SetIsGradedObject( Cs, true );
    elif HasIsComplex( C ) and IsComplex( C ) then
        SetIsComplex( Cs, true );
    elif HasIsSequence( C ) and IsSequence( C ) then
        SetIsSequence( Cs, true );
    fi;
    
    return Cs;
    
end );

##
InstallMethod( Reflect,
        "for homalg complexes",
        [ IsHomalgComplex, IsInt ],
        
  function( C, s )
    local d, Cd, Cs;
    
    d := HighestDegree( C );
    
    Cd := HighestDegreeObject( C );
    
    if IsComplexOfFinitelyPresentedObjectsRep( C ) then
        Cs := HomalgCocomplex( Cd, - d - s );
    else
        Cs := HomalgComplex( Cd, - d - s );
    fi;
    
    Perform ( Reversed( MorphismsOfComplex( C ) ), function( m ) Add( Cs, m ); end );
    
    if HasIsGradedObject( C ) and IsGradedObject( C ) then
        SetIsGradedObject( Cs, true );
    elif HasIsComplex( C ) and IsComplex( C ) then
        SetIsComplex( Cs, true );
    elif HasIsSequence( C ) and IsSequence( C ) then
        SetIsSequence( Cs, true );
    fi;
    
    return Cs;
    
end );

##
InstallMethod( Reflect,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    
    return Reflect( C, 0 );
    
end );

##
InstallMethod( \+,
        "for two homalg complexes",
        [ IsHomalgComplex and IsGradedObject, IsHomalgComplex and IsGradedObject ],
        
  function( C1, C2 )
    local cpx, d1, d2, d, Cd, Cs, i;
    
    if IsComplexOfFinitelyPresentedObjectsRep( C1 ) and IsComplexOfFinitelyPresentedObjectsRep( C2 ) then
        cpx := true;
    elif IsCocomplexOfFinitelyPresentedObjectsRep( C1 ) and IsCocomplexOfFinitelyPresentedObjectsRep( C2 ) then
        cpx := false;
    else
        Error( "first and second argument must either be both complexes or both cocomplexes\n" );
    fi;
    
    d1 := LowestDegree( C1 );
    d2 := LowestDegree( C2 );
    
    d := Minimum( d1, d2 );
    
    if d1 < d2 then
        Cd := LowestDegreeObject( C1 );
    elif d2 < d1 then
        Cd := LowestDegreeObject( C2 );
    else
        Cd := LowestDegreeObject( C1 ) + LowestDegreeObject( C2 );
    fi;
    
    if cpx then
        Cs := HomalgComplex( Cd, d );
    else
        Cs := HomalgCocomplex( Cd, d );
    fi;
    
    d1 := ObjectDegreesOfComplex( C1 );
    d2 := ObjectDegreesOfComplex( C2 );
    
    for i in [ d + 1 .. Maximum( List( [ C1, C2 ], HighestDegree ) ) ] do
        if not i in d2 then
            Cd := CertainObject( C1, i );
        elif not i in d1 then
            Cd := CertainObject( C2, i );
        else
            Cd := CertainObject( C1, i ) + CertainObject( C2, i );
        fi;
        
        Add( Cs, Cd );
    od;
    
    SetIsGradedObject( Cs, true );
    
    return Cs;
    
end );

##
InstallMethod( Subcomplex,
        "for homalg complexes",
        [ IsComplexOfFinitelyPresentedObjectsRep, IsInt, IsInt ],
        
  function( C, i, j )
    local m, A, k;
    
    m := CertainMorphism( C, i + 1 );
    
    if m = fail then
        Error( "The complex does not have the demanded degree" );
    fi;
    
    A := HomalgComplex( m, i + 1 );
    
    for k in [ i + 2 .. j ] do
        
        m := CertainMorphism( C, k );
        
        if m = fail then
            Error( "The complex does not have the demanded degree" );
        fi;
        
        Add( A, m );
        
    od;
    
    if HasIsZero( C ) and IsZero( C ) then
        SetIsZero( A, true );
    elif HasIsGradedObject( C ) and IsGradedObject( C ) then
        SetIsGradedObject( A, true );
    elif HasIsComplex( C ) and IsComplex( C ) then
        SetIsComplex( A, true );
    fi;
    
    return A;
    
end );

##
InstallMethod( Subcomplex,
        "for homalg complexes",
        [ IsCocomplexOfFinitelyPresentedObjectsRep, IsInt, IsInt ],
        
  function( C, i, j )
    local m, A, k;
    
    m := CertainMorphism( C, i );
    
    if m = fail then
        Error( "The cocomplex does not have the demanded degree" );
    fi;
    
    A := HomalgCocomplex( m, i );
    
    for k in [ i+1 .. j-1 ] do
        
        m := CertainMorphism( C, k );
        
        if m = fail then
            Error( "The cocomplex does not have the demanded degree" );
        fi;
        
        Add( A, m );
        
    od;
    
    if HasIsZero( C ) and IsZero( C ) then
        SetIsZero( A, true );
    elif HasIsGradedObject( C ) and IsGradedObject( C ) then
        SetIsGradedObject( A, true );
    elif HasIsComplex( C ) and IsComplex( C ) then
        SetIsComplex( A, true );
    fi;
    
    return A;
    
end );

##
InstallMethod( CertainMorphismAsSubcomplex,
        "for homalg complexes",
        [ IsComplexOfFinitelyPresentedObjectsRep, IsInt ],
        
  function( C, i )
    local m, A;
    
    m := CertainMorphism( C, i );
    
    if m = fail then
        m := CertainMorphism( C, i + 1 );
        if m = fail then
            return fail;
        fi;
        m := CokernelEpi( m );
    fi;
    
    A := HomalgComplex( m, i );
    
    if HasIsZero( C ) and IsZero( C ) then
        SetIsZero( A, true );
    elif HasIsGradedObject( C ) and IsGradedObject( C ) then
        SetIsGradedObject( A, true );
    elif HasIsComplex( C ) and IsComplex( C ) then
        SetIsComplex( A, true );
    elif HasIsSequence( C ) and IsSequence( C ) then
        SetIsComplex( A, true ); ## this is not a mistake
    fi;
    
    return A;
    
end );

##
InstallMethod( CertainMorphismAsSubcomplex,
        "for homalg complexes",
        [ IsCocomplexOfFinitelyPresentedObjectsRep, IsInt ],
        
  function( C, i )
    local m, A;
    
    m := CertainMorphism( C, i );
    
    if m = fail then
        return fail;
    fi;
    
    A := HomalgCocomplex( m, i );
    
    if HasIsZero( C ) and IsZero( C ) then
        SetIsZero( A, true );
    elif HasIsGradedObject( C ) and IsGradedObject( C ) then
        SetIsGradedObject( A, true );
    elif HasIsComplex( C ) and IsComplex( C ) then
        SetIsComplex( A, true );
    elif HasIsSequence( C ) and IsSequence( C ) then
        SetIsComplex( A, true ); ## this is not a mistake
    fi;
    
    return A;
    
end );

##
InstallMethod( CertainTwoMorphismsAsSubcomplex,
        "for homalg complexes",
        [ IsComplexOfFinitelyPresentedObjectsRep, IsInt ],
        
  function( C, i )
    local m, A;
    
    m := CertainMorphism( C, i );
    
    if m = fail then
        return fail;
    fi;
    
    A := HomalgComplex( m, i );
    
    m := CertainMorphism( C, i + 1 );
    
    if m = fail then
        return fail;
    fi;
    
    Add( A, m );
    
    if HasIsZero( C ) and IsZero( C ) then
        SetIsZero( A, true );
    elif HasIsGradedObject( C ) and IsGradedObject( C ) then
        SetIsGradedObject( A, true );
    elif HasIsComplex( C ) and IsComplex( C ) then
        SetIsComplex( A, true );
    elif HasIsSequence( C ) and IsSequence( C ) then
        SetIsSequence( A, true );
    fi;
    
    SetIsATwoSequence( A, true );
    
    return A;
    
end );

##
InstallMethod( CertainTwoMorphismsAsSubcomplex,
        "for homalg complexes",
        [ IsCocomplexOfFinitelyPresentedObjectsRep, IsInt ],
        
  function( C, i )
    local m, A;
    
    m := CertainMorphism( C, i - 1 );
    
    if m = fail then
        return fail;
    fi;
    
    A := HomalgCocomplex( m, i - 1 );
    
    m := CertainMorphism( C, i );
    
    if m = fail then
        return fail;
    fi;
    
    Add( A, m );
    
    if HasIsZero( C ) and IsZero( C ) then
        SetIsZero( A, true );
    elif HasIsGradedObject( C ) and IsGradedObject( C ) then
        SetIsGradedObject( A, true );
    elif HasIsComplex( C ) and IsComplex( C ) then
        SetIsComplex( A, true );
    elif HasIsSequence( C ) and IsSequence( C ) then
        SetIsSequence( A, true );
    fi;
    
    SetIsATwoSequence( A, true );
    
    return A;
    
end );

##
InstallMethod( LongSequence,
        "for homalg complexes",
        [ IsComplexOfFinitelyPresentedObjectsRep and IsTriangle ],
        
  function( T )
    local mor, deg, C, j;
    
    mor := MorphismsOfComplex( T );
    
    deg := DegreesOfChainMorphism( mor[1] );
    
    C := HomalgComplex( CertainMorphism( mor[1], deg[1] ) );
    Add( C, CertainMorphism( mor[2], deg[1] ) );
    
    for j in deg{[ 2 .. Length( deg ) ]} do
        
        Add( C, CertainMorphism( mor[3], j ) );
        Add( C, CertainMorphism( mor[1], j ) );
        Add( C, CertainMorphism( mor[2], j ) );
        
    od;
    
    return C;
    
end );

##
InstallMethod( LongSequence,
        "for homalg complexes",
        [ IsCocomplexOfFinitelyPresentedObjectsRep and IsTriangle ],
        
  function( T )
    local mor, deg, C, j;
    
    mor := MorphismsOfComplex( T );
    
    deg := DegreesOfChainMorphism( mor[1] );
    
    C := HomalgCocomplex( CertainMorphism( mor[1], deg[1] ) );
    Add( C, CertainMorphism( mor[2], deg[1] ) );
    
    for j in deg{[ 2 .. Length( deg ) ]} do
        
        Add( C, CertainMorphism( mor[3], j - 1 ) );
        Add( C, CertainMorphism( mor[1], j ) );
        Add( C, CertainMorphism( mor[2], j ) );
        
    od;
    
    return C;
    
end );

##
InstallMethod( PreCompose,
        "for homalg complexes",
        [ IsComplexOfFinitelyPresentedObjectsRep,
          IsComplexOfFinitelyPresentedObjectsRep ],
        
  function( C1, C2 )
    local mor2, mor1, deg, C, l, m;
    
    mor2 := MorphismsOfComplex( C2 );
    
    if mor2 = [ ] then
        return C1;
    fi;
    
    mor1 := MorphismsOfComplex( C1 );
    
    if mor1 = [ ] then
        return C2;
    fi;
    
    deg := LowestDegree( C2 ) + 1;
    
    C := HomalgComplex( mor2[1], deg );
    
    l := Length( mor2 );
    
    for m in mor2{[ 2 .. l - 1 ]} do
        Add( C, m );
    od;
    
    Add( C, PreCompose( mor1[1], mor2[l] ) );
    
    for m in mor1{[ 2 .. Length( mor1 ) ]} do
        Add( C, m );
    od;
    
    return C;
    
end );

##
InstallMethod( PreCompose,
        "for homalg complexes",
        [ IsCocomplexOfFinitelyPresentedObjectsRep,
          IsCocomplexOfFinitelyPresentedObjectsRep ],
        
  function( C1, C2 )
    local mor1, mor2, deg, C, l, m;
    
    mor1 := MorphismsOfComplex( C1 );
    
    if mor1 = [ ] then
        return C2;
    fi;
    
    mor2 := MorphismsOfComplex( C2 );
    
    if mor2 = [ ] then
        return C1;
    fi;
    
    deg := LowestDegree( C1 );
    
    C := HomalgCocomplex( mor1[1], deg );
    
    l := Length( mor1 );
    
    for m in mor1{[ 2 .. l - 1 ]} do
        Add( C, m );
    od;
    
    Add( C, PreCompose( mor1[l], mor2[1] ) );
    
    for m in mor2{[ 2 .. Length( mor2 ) ]} do
        Add( C, m );
    od;
    
    return C;
    
end );

##
InstallMethod( DecideZero,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    
    List( ObjectsOfComplex( C ), DecideZero );
    
    if Length( ObjectDegreesOfComplex( C ) ) > 1 then
        List( MorphismsOfComplex( C ), DecideZero );
    fi;
    
    IsZero( C );
    
    return C;
    
end );

##  <#GAPDoc Label="ByASmallerPresentation:complex">
##  <ManSection>
##    <Meth Arg="C" Name="ByASmallerPresentation" Label="for complexes"/>
##    <Returns>a &homalg; complex</Returns>
##    <Description>
##    It invokes <C>ByASmallerPresentation</C> for &homalg; (static) objects.
##      <Listing Type="Code"><![CDATA[
InstallMethod( ByASmallerPresentation,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( C )
    
    List( ObjectsOfComplex( C ), ByASmallerPresentation );
    
    if Length( ObjectDegreesOfComplex( C ) ) > 1 then
        List( MorphismsOfComplex( C ), DecideZero );
    fi;
    
    IsZero( C );
    
    return C;
    
end );
##  ]]></Listing>
##      This method performs side effects on its argument <A>C</A> and returns it.
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );
##  Z
##  gap> M := HomalgMatrix( "[ 2, 3, 4,   5, 6, 7 ]", 2, 3, zz );
##  <A 2 x 3 matrix over an internal ring>
##  gap> M := LeftPresentation( M );
##  <A non-torsion left module presented by 2 relations for 3 generators>
##  gap> N := HomalgMatrix( "[ 2, 3, 4, 5,   6, 7, 8, 9 ]", 2, 4, zz );
##  <A 2 x 4 matrix over an internal ring>
##  gap> N := LeftPresentation( N );
##  <A non-torsion left module presented by 2 relations for 4 generators>
##  gap> mat := HomalgMatrix( "[ \
##  > 0, 3, 6, 9, \
##  > 0, 2, 4, 6, \
##  > 0, 3, 6, 9  \
##  > ]", 3, 4, zz );
##  <A 3 x 4 matrix over an internal ring>
##  gap> phi := HomalgMap( mat, M, N );
##  <A "homomorphism" of left modules>
##  gap> IsMorphism( phi );
##  true
##  gap> phi;
##  <A homomorphism of left modules>
##  gap> C := HomalgComplex( phi );
##  <A non-zero acyclic complex containing a single morphism of left modules at de\
##  grees [ 0 .. 1 ]>
##  gap> Display( C );
##  -------------------------
##  at homology degree: 1
##  [ [  2,  3,  4 ],
##    [  5,  6,  7 ] ]
##  
##  Cokernel of the map
##  
##  Z^(1x2) --> Z^(1x3),
##  
##  currently represented by the above matrix
##  -------------------------
##  [ [  0,  3,  6,  9 ],
##    [  0,  2,  4,  6 ],
##    [  0,  3,  6,  9 ] ]
##  
##  the map is currently represented by the above 3 x 4 matrix
##  ------------v------------
##  at homology degree: 0
##  [ [  2,  3,  4,  5 ],
##    [  6,  7,  8,  9 ] ]
##  
##  Cokernel of the map
##  
##  Z^(1x2) --> Z^(1x4),
##  
##  currently represented by the above matrix
##  -------------------------
##  ]]></Example>
##      And now:
##      <Example><![CDATA[
##  gap> ByASmallerPresentation( C );
##  <A non-zero acyclic complex containing a single morphism of left modules at de\
##  grees [ 0 .. 1 ]>
##  gap> Display( C );
##  -------------------------
##  at homology degree: 1
##  Z/< 3 > + Z^(1 x 1)
##  -------------------------
##  [ [  0,  0,  0 ],
##    [  2,  0,  0 ] ]
##  
##  the map is currently represented by the above 2 x 3 matrix
##  ------------v------------
##  at homology degree: 0
##  Z/< 4 > + Z^(1 x 2)
##  -------------------------
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>

##
InstallMethod( SetCurrentResolution,
        "for a homalg static object and a homalg complex",
        [ IsHomalgStaticObject, IsHomalgComplex ],
        
  function( M, P )
    local d1, pos;
    
    d1 := CertainMorphism( P, 1 );
    
    if not ( HasCokernelEpi( d1 ) and
             IsIdenticalObj( Range( CokernelEpi( d1 ) ), M ) ) then
        Error( "the object is not (known to be) the cokernel of the first morphism of the complex\n" );
    fi;
    
    pos := PositionOfTheDefaultPresentation( M );
    
    M!.Resolutions.(pos) := P;
    
end );

####################################
#
# constructor functions and methods:
#
####################################

##  <#GAPDoc Label="HomalgComplex">
##  <ManSection>
##    <Func Arg="M[, d]" Name="HomalgComplex" Label="constructor for complexes given an object"/>
##    <Func Arg="phi[, d]" Name="HomalgComplex" Label="constructor for complexes given a morphism"/>
##    <Func Arg="C[, d]" Name="HomalgComplex" Label="constructor for complexes given a complex"/>
##    <Func Arg="cm[, d]" Name="HomalgComplex" Label="constructor for complexes given a chain morphism"/>
##    <Returns>a &homalg; complex</Returns>
##    <Description>
##      The first syntax creates a complex (i.e. chain complex) with the single &homalg; object <A>M</A>
##      at (homological) degree <A>d</A>. <P/>
##      The second syntax creates a complex with the single &homalg; morphism <A>phi</A>, its source placed at
##      (homological) degree <A>d</A> (and its target at <A>d</A><M>-1</M>). <P/>
##      The third syntax creates a complex (i.e. chain complex) with the single &homalg; (co)complex <A>C</A>
##      at (homological) degree <A>d</A>. <P/>
##      The fourth syntax creates a complex with the single &homalg; (co)chain morphism <A>cm</A>
##      (&see; <Ref Func="HomalgChainMorphism" Label="constructor for chain morphisms given a morphism"/>), its source placed at
##      (homological) degree <A>d</A> (and its target at <A>d</A><M>-1</M>). <P/>
##      If <A>d</A> is not provided it defaults to zero in all cases. <Br/>
##      To add a morphism (resp. (co)chain morphism) to a complex use <Ref Oper="Add" Label="to complexes given a morphism"/>.
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );
##  Z
##  gap> M := HomalgMatrix( "[ 2, 3, 4,   5, 6, 7 ]", 2, 3, zz );
##  <A 2 x 3 matrix over an internal ring>
##  gap> M := LeftPresentation( M );
##  <A non-torsion left module presented by 2 relations for 3 generators>
##  gap> N := HomalgMatrix( "[ 2, 3, 4, 5,   6, 7, 8, 9 ]", 2, 4, zz );
##  <A 2 x 4 matrix over an internal ring>
##  gap> N := LeftPresentation( N );
##  <A non-torsion left module presented by 2 relations for 4 generators>
##  gap> mat := HomalgMatrix( "[ \
##  > 0, 3, 6, 9, \
##  > 0, 2, 4, 6, \
##  > 0, 3, 6, 9  \
##  > ]", 3, 4, zz );
##  <A 3 x 4 matrix over an internal ring>
##  gap> phi := HomalgMap( mat, M, N );
##  <A "homomorphism" of left modules>
##  gap> IsMorphism( phi );
##  true
##  gap> phi;
##  <A homomorphism of left modules>
##  ]]></Example>
##  The first possibility:
##      <Example><![CDATA[
##  gap> C := HomalgComplex( N );
##  <A non-zero graded homology object consisting of a single left module at degre\
##  e 0>
##  gap> Add( C, phi );
##  gap> C;
##  <A complex containing a single morphism of left modules at degrees [ 0 .. 1 ]>
##  ]]></Example>
##  The second possibility:
##      <Example><![CDATA[
##  gap> C := HomalgComplex( phi );
##  <A non-zero acyclic complex containing a single morphism of left modules at de\
##  grees [ 0 .. 1 ]>
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallGlobalFunction( HomalgComplex,
  function( arg )
    local nargs, C, complex, degrees, object, obj_or_mor, left, type;
    
    nargs := Length( arg );
    
    if nargs = 0 then
        Error( "empty input\n" );
    fi;
    
    C := rec( );
    
    if IsStringRep( arg[nargs] ) and ( arg[nargs] = "co" or arg[nargs] = "cocomplex" ) then
        complex := false;
        C.string := "cocomplex";
        C.string_plural := "cocomplexes";
    else
        complex := true;
        C.string := "complex";
        C.string_plural := "complexes";
    fi;
    
    if nargs > 1 and ( IsInt( arg[2] )
               or ( IsList( arg[2] ) and Length( arg[2] ) > 0 and ForAll( arg[2], IsInt ) ) ) then
        degrees := [ arg[2] ];
    elif complex and IsMorphismOfFinitelyGeneratedObjectsRep( arg[1] ) then
        degrees := [ 1 ];
    else
        degrees := [ 0 ];
    fi;
    
    if IsStructureObjectOrFinitelyPresentedObjectRep( arg[1] ) then
        object := true;
        if IsStructureObject( arg[1] ) then
            obj_or_mor := AsLeftObject( arg[1] );
        else
            obj_or_mor := arg[1];
        fi;
        C.degrees := degrees;
        left := IsHomalgLeftObjectOrMorphismOfLeftObjects( obj_or_mor );
    elif IsMorphismOfFinitelyGeneratedObjectsRep( arg[1] ) then
        object := false;
        obj_or_mor := arg[1];
        if complex then
            C.degrees := [ degrees[1] - 1, degrees[1] ];
        else
            C.degrees := [ degrees[1], degrees[1] + 1 ];
        fi;
    else
        Error( "the first argument must be either a homalg object or a homalg morphism\n" );
    fi;
    
    left := IsHomalgLeftObjectOrMorphismOfLeftObjects( obj_or_mor );
    
    C.( String( degrees[1] ) ) := obj_or_mor;
    
    if complex then
        if left then
            type := TheTypeHomalgComplexOfLeftObjects;
        else
            type := TheTypeHomalgComplexOfRightObjects;
        fi;
    else
        if left then
            type := TheTypeHomalgCocomplexOfLeftObjects;
        else
            type := TheTypeHomalgCocomplexOfRightObjects;
        fi;
    fi;
    
    ConvertToRangeRep( C.degrees );
    
    ## Objectify
    Objectify( type, C );
    
    if object then
        SetIsRightAcyclic( C, true );
        if HasIsZero( obj_or_mor ) then
            SetIsLeftAcyclic( C, IsZero( obj_or_mor ) );
            SetIsZero( C, IsZero( obj_or_mor ) );
        fi;
        SetIsGradedObject( C, true );
    elif HasIsIsomorphism( obj_or_mor ) and IsIsomorphism( obj_or_mor ) then
        SetIsExactSequence( C, true );
    elif HasIsEpimorphism( obj_or_mor ) and IsEpimorphism( obj_or_mor ) then
        if complex then
            SetIsLeftAcyclic( C, true );
        else
            SetIsRightAcyclic( C, true );
        fi;
    elif HasIsMonomorphism( obj_or_mor ) and IsMonomorphism( obj_or_mor ) then
        if complex then
            SetIsRightAcyclic( C, true );
        else
            SetIsLeftAcyclic( C, true );
        fi;
    elif HasIsMorphism( obj_or_mor ) and IsMorphism( obj_or_mor ) then
        SetIsAcyclic( C, true );
    fi;
    
    return C;
    
end );

##  <#GAPDoc Label="HomalgCocomplex">
##  <ManSection>
##    <Func Arg="M[, d]" Name="HomalgCocomplex" Label="constructor for cocomplexes given a object"/>
##    <Func Arg="phi[, d]" Name="HomalgCocomplex" Label="constructor for cocomplexes given a morphism"/>
##    <Func Arg="C[, d]" Name="HomalgCocomplex" Label="constructor for cocomplexes given a complex"/>
##    <Func Arg="cm[, d]" Name="HomalgCocomplex" Label="constructor for cocomplexes given a chain morphism"/>
##    <Returns>a &homalg; complex</Returns>
##    <Description>
##      The first syntax creates a cocomplex (i.e. cochain complex) with the single &homalg; object <A>M</A> at
##      (cohomological) degree <A>d</A>. <P/>
##      The second syntax creates a cocomplex with the single &homalg; morphism <A>phi</A>, its source placed at (cohomological)
##      degree <A>d</A> (and its target at <A>d</A><M>+1</M>). <P/>
##      The third syntax creates a cocomplex (i.e. cochain complex) with the single &homalg; cocomplex <A>C</A> at
##      (cohomological) degree <A>d</A>. <P/>
##      The fourth syntax creates a cocomplex with the single &homalg; (co)chain morphism <A>cm</A>
##      (&see; <Ref Func="HomalgChainMorphism" Label="constructor for chain morphisms given a morphism"/>), its source placed at
##      (cohomological) degree <A>d</A> (and its target at <A>d</A><M>+1</M>). <P/>
##      If <A>d</A> is not provided it defaults to zero in all cases. <Br/>
##      To add a morphism (resp. (co)chain morphism) to a cocomplex use <Ref Oper="Add" Label="to complexes given a morphism"/>.
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );
##  Z
##  gap> M := HomalgMatrix( "[ 2, 3, 4,   5, 6, 7 ]", 2, 3, zz );
##  <A 2 x 3 matrix over an internal ring>
##  gap> M := RightPresentation( Involution( M ) );
##  <A non-torsion right module on 3 generators satisfying 2 relations>
##  gap> N := HomalgMatrix( "[ 2, 3, 4, 5,   6, 7, 8, 9 ]", 2, 4, zz );
##  <A 2 x 4 matrix over an internal ring>
##  gap> N := RightPresentation( Involution( N ) );
##  <A non-torsion right module on 4 generators satisfying 2 relations>
##  gap> mat := HomalgMatrix( "[ \
##  > 0, 3, 6, 9, \
##  > 0, 2, 4, 6, \
##  > 0, 3, 6, 9  \
##  > ]", 3, 4, zz );
##  <A 3 x 4 matrix over an internal ring>
##  gap> phi := HomalgMap( Involution( mat ), M, N );
##  <A "homomorphism" of right modules>
##  gap> IsMorphism( phi );
##  true
##  gap> phi;
##  <A homomorphism of right modules>
##  ]]></Example>
##  The first possibility:
##      <Example><![CDATA[
##  gap> C := HomalgCocomplex( M );
##  <A non-zero graded cohomology object consisting of a single right module at de\
##  gree 0>
##  gap> Add( C, phi );
##  gap> C;
##  <A cocomplex containing a single morphism of right modules at degrees
##  [ 0 .. 1 ]>
##  ]]></Example>
##  The second possibility:
##      <Example><![CDATA[
##  gap> C := HomalgCocomplex( phi );
##  <A non-zero acyclic cocomplex containing a single morphism of right modules at\
##   degrees [ 0 .. 1 ]>
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallGlobalFunction( HomalgCocomplex,
  function( arg )
    
    return CallFuncList( HomalgComplex, Concatenation( arg, [ "cocomplex" ] ) );
    
end );

####################################
#
# constructors
#
####################################

##
InstallMethod( \*,
        "for a structure object and a complex",
        [ IsStructureObject, IsHomalgComplex ],
        
  function( R, C )
    
    return BaseChange( R, C );
    
end );

##
InstallMethod( \*,
        "for a complex and a structure object",
        [ IsHomalgComplex, IsStructureObject ],
        
  function( C, R )
    
    return R * C;
    
end );

##
InstallMethod( ShallowCopy,
        "for a complex",
        [ IsHomalgComplex ],
        
  function( C )
    
    return Shift( C, 0 );
    
end );

####################################
#
# View, Print, and Display methods:
#
####################################

##
InstallMethod( ViewObj,
        "for homalg complexes",
        [ IsHomalgComplex ],
        
  function( o )
    local cpx, first_attribute, degrees, l, oi;
    
    cpx := IsComplexOfFinitelyPresentedObjectsRep( o );
    
    first_attribute := false;
    
    Print( "<A" );
    
    if HasIsZero( o ) then ## if this method applies and HasIsZero is set we already know that o is a non-zero homalg (co)complex
        Print( " non-zero" );
        first_attribute := true;
    fi;
    
    if HasIsExactTriangle( o ) and IsExactTriangle( o ) then
        if not first_attribute then
            Print( "n" );
        fi;
        if cpx then
            Print( " exact triangle" );
        else
            Print( " exact cotriangle" );
        fi;
    elif HasIsSplitShortExactSequence( o ) and IsSplitShortExactSequence( o ) then
        if cpx then
            Print( " split short exact sequence" );
        else
            Print( " split short exact cosequence" );
        fi;
    elif HasIsShortExactSequence( o ) and IsShortExactSequence( o ) then
        if cpx then
            Print( " short exact sequence" );
        else
            Print( " short exact cosequence" );
        fi;
    elif HasIsExactSequence( o ) and IsExactSequence( o ) then
        if not first_attribute then
            Print( "n" );
        fi;
        if cpx then
            Print( " exact sequence" );
        else
            Print( " exact cosequence" );
        fi;
    elif HasIsRightAcyclic( o ) and IsRightAcyclic( o ) then
        if cpx then
            Print( " right acyclic complex" );
        else
            Print( " right acyclic cocomplex" );
        fi;
    elif HasIsLeftAcyclic( o ) and IsLeftAcyclic( o ) then
        if cpx then
            Print( " left acyclic complex" );
        else
            Print( " left acyclic cocomplex" );
        fi;
    elif HasIsAcyclic( o ) and IsAcyclic( o ) then
        if not first_attribute then
            Print( "n" );
        fi;
        if cpx then
            Print( " acyclic complex" );
        else
            Print( " acyclic cocomplex" );
        fi;
    elif HasIsComplex( o ) then
        if IsComplex( o ) then
            if cpx then
                Print( " complex" );
            else
                Print( " cocomplex" );
            fi;
        else
            if cpx then
                Print( " non-complex" );
            else
                Print( " non-cocomplex" );
            fi;
        fi;
    elif HasIsSequence( o ) then
        if IsSequence( o ) then
            if cpx then
                Print( " sequence" );
            else
                Print( " cosequence" );
            fi;
        else
            if cpx then
                Print( " sequence of non-well-definded morphisms" );
            else
                Print( " cosequence of non-well-definded morphisms" );
            fi;
        fi;
    else
        if cpx then
            Print( " \"complex\"" );
        else
            Print( " \"cocomplex\"" );
        fi;
    fi;
    
    Print( " containing " );
    
    degrees := ObjectDegreesOfComplex( o );
    
    l := Length( degrees );
    
    oi := CertainObject( o, degrees[1] );
    
    if l = 1 then
        
        Print( "a single " );
        
        if IsHomalgLeftObjectOrMorphismOfLeftObjects( o ) then
            Print( "left" );
        else
            Print( "right" );
        fi;
        
        if IsBound( oi!.string ) then
            Print( " ", oi!.string );
        else
            Print( " object" );
        fi;
        
        Print( " at degree ", degrees[1], ">" );
        
    else
        
        if l = 2 then
            Print( "a single morphism" );
        else
            Print( l - 1, " morphisms" );
        fi;
        
        Print( " of " );
        
        if IsBound( oi!.adjective ) then
            Print( oi!.adjective, " " );
        fi;
        
        if IsHomalgLeftObjectOrMorphismOfLeftObjects( o ) then
            Print( "left " );
        else
            Print( "right " );
        fi;
        
        if IsBound( oi!.string_plural ) then
            Print( oi!.string_plural );
        elif IsBound( oi!.string ) then
            Print( oi!.string, "s" );
        else
            Print( "objects" );
        fi;
        
        if HasIsExactTriangle( o ) and IsExactTriangle( o ) then
            if cpx then
                Print( " at degrees ", [ degrees[2], degrees[3], degrees[4], degrees[2] ], ">" );
            else
                Print( " at degrees ", [ degrees[1], degrees[2], degrees[3], degrees[1] ], ">" );
            fi;
        else
            Print( " at degrees ", degrees, ">" );
        fi;
        
    fi;
    
end );

##
InstallMethod( ViewObj,
        "for homalg complexes",
        [ IsHomalgComplex and IsGradedObject ],
        
  function( o )
    local degrees, l, oi;
    
    Print( "<A" );
    
    if HasIsZero( o ) then ## if this method applies and HasIsZero is set we already know that o is a non-zero homology object
        Print( " non-zero" );
    fi;
    
    Print( " graded " );
    
    if IsCocomplexOfFinitelyPresentedObjectsRep( o ) then
        Print( "co" );
    fi;
    
    Print( "homology object consisting of " );
    
    degrees := ObjectDegreesOfComplex( o );
    
    l := Length( degrees );
    
    if l = 1 then
        Print( "a single " );
    else
        Print( l, " " );
    fi;
    
    oi := CertainObject( o, degrees[1] );
    
    if IsBound( oi!.adjective ) then
        Print( oi!.adjective, " " );
    fi;
    
    if IsHomalgLeftObjectOrMorphismOfLeftObjects( o ) then
        Print( "left " );
    else
        Print( "right " );
    fi;
    
    if IsBound( oi!.string ) then
        if l = 1 then
            Print( oi!.string );
        else
            if IsBound( oi!.string_plural ) then
                Print( oi!.string_plural );
            else
                Print( oi!.string, "s" );
            fi;
        fi;
    else
        Print( "object" );
        if l > 1 then
            Print( "s" );
        fi;
    fi;
    
    Print( " at degree" );
    
    if l = 1 then
        Print( " ", degrees[1] );
    else
        Print( "s ", degrees );
    fi;
    
    Print( ">" );
    
end );

##
InstallMethod( ViewObj,
        "for homalg complexes",
        [ IsComplexOfFinitelyPresentedObjectsRep and IsZero ],
        
  function( o )
    local degrees, l;
    
    degrees := ObjectDegreesOfComplex( o );
    
    l := Length( degrees );
    
    Print( "<A zero " );
    
    if IsHomalgLeftObjectOrMorphismOfLeftObjects( o ) then
        Print( "left" );
    else
        Print( "right" );
    fi;
    
    Print( " complex with degree" );
    
    if l > 1 then
        Print( "s" );
    fi;
    
    Print( " ", degrees, ">" );
    
end );

##
InstallMethod( ViewObj,
        "for homalg complexes",
        [ IsCocomplexOfFinitelyPresentedObjectsRep and IsZero ],
        
  function( o )
    local degrees, l;
    
    degrees := ObjectDegreesOfComplex( o );
    
    l := Length( degrees );
    
    Print( "<A zero " );
    
    if IsHomalgLeftObjectOrMorphismOfLeftObjects( o ) then
        Print( "left" );
    else
        Print( "right" );
    fi;
    
    Print( " cocomplex with degree" );
    
    if l > 1 then
        Print( "s" );
    fi;
    
    Print( " ", degrees, ">" );
    
end );

##
InstallMethod( Display,
        "for homalg complexes",
        [ IsComplexOfFinitelyPresentedObjectsRep ],
        
  function( o )
    local degrees, l, i;
    
    degrees := ObjectDegreesOfComplex( o );
    
    l := Length( degrees );
    
    Print( "-------------------------\n" );
    Print( "at homology degree: ", degrees[l], "\n" );
    Display( CertainObject( o, degrees[l] ) );
    
    for i in Reversed( degrees{[ 1 .. l - 1 ]} ) do
        Print( "-------------------------\n" );
        Display( CertainMorphism( o, i + 1 ) );
        Print( "------------v------------\n" );
        Print( "at homology degree: ", i, "\n" );
        Display( CertainObject( o, i ) );
    od;
    
    Print( "-------------------------\n" );
    
end );

##
InstallMethod( Display,
        "for homalg complexes",
        [ IsCocomplexOfFinitelyPresentedObjectsRep ],
        
  function( o )
    local degrees, i;
    
    degrees := ObjectDegreesOfComplex( o );
    
    Print( "-------------------------\n" );
    
    for i in Reversed( degrees{[ 2 .. Length( degrees ) ]} ) do
        Print( "at cohomology degree: ", i, "\n" );
        Display( CertainObject( o, i ) );
        Print( "------------^------------\n" );
        Display( CertainMorphism( o, i - 1 ) );
        Print( "-------------------------\n" );
    od;
    
    Print( "at cohomology degree: ", degrees[1], "\n" );
    Display( CertainObject( o, degrees[1] ) );
    Print( "-------------------------\n" );
    
end );

##
InstallMethod( Display,
        "for homalg complexes",
        [ IsComplexOfFinitelyPresentedObjectsRep and IsGradedObject ],
        
  function( o )
    local i;
    
    for i in Reversed( ObjectDegreesOfComplex( o ) ) do
        Print( "-------------------------\n" );
        Print( "at homology degree: ", i, "\n" );
        Display( CertainObject( o, i ) );
    od;
    
    Print( "-------------------------\n" );
    
end );

##
InstallMethod( Display,
        "for homalg complexes",
        [ IsCocomplexOfFinitelyPresentedObjectsRep and IsGradedObject ],
        
  function( o )
    local i;
    
    for i in Reversed( ObjectDegreesOfComplex( o ) ) do
        Print( "---------------------------\n" );
        Print( "at cohomology degree: ", i, "\n" );
        Display( CertainObject( o, i ) );
    od;
    
    Print( "---------------------------\n" );
    
end );

##
InstallMethod( Display,
        "for homalg complexes",
        [ IsComplexOfFinitelyPresentedObjectsRep and IsZero ],
        
  function( o )
    
    Print( "0\n" );
    
end );

##
InstallMethod( Display,
        "for homalg complexes",
        [ IsCocomplexOfFinitelyPresentedObjectsRep and IsZero ],
        
  function( o )
    
    Print( "0\n" );
    
end );


[ Dauer der Verarbeitung: 0.31 Sekunden  (vorverarbeitet)  ]