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 280 kB image not shown  

Quelle  HomalgFunctor.gi   Sprache: unbekannt

 
Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

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

##  Implementations for functors.

##  <#GAPDoc Label="Functors:intro">
##    Functors and their natural transformations form the heart of the &homalg; package. Usually, a functor is realized
##    in computer algebra systems as a procedure which can be applied to a certain type of objects. In <Cite Key="BR"/>
##    it was explained how to implement a functor of Abelian categories -- by itself -- as an object which can be
##    further manipulated (composed, derived, ...).
##    So in addition to the constructor <Ref Oper="CreateHomalgFunctor" Label="constructor for functors"/>
##    which is used to create functors from scratch, &homalg; provides further easy-to-use constructors
##    to create new functors out of existing ones:
##    <List>
##      <Item><Ref Oper="InsertObjectInMultiFunctor" Label="constructor for functors given a multi-functor and an object"/></Item>
##      <Item><Ref Oper="RightSatelliteOfCofunctor" Label="constructor of the right satellite of a contravariant functor"/></Item>
##      <Item><Ref Oper="LeftSatelliteOfFunctor" Label="constructor of the left satellite of a covariant functor"/></Item>
##      <Item><Ref Oper="RightDerivedCofunctor" Label="constructor of the right derived functor of a contravariant functor"/></Item>
##      <Item><Ref Oper="LeftDerivedFunctor" Label="constructor of the left derived functor of a covariant functor"/></Item>
##      <Item><Ref Oper="ComposeFunctors" Label="constructor for functors given two functors"/></Item>
##    </List>
##    In &homalg; each functor is implemented as a &GAP4; object.
##    <P/>
##    So-called installers (&see; <Ref Oper="InstallFunctor"/> and <Ref Oper="InstallDeltaFunctor"/>)
##    take such a functor object and create operations in order to apply the functor on objects, morphisms,
##    complexes (of objects or again of complexes), and chain morphisms. The installer <Ref Oper="InstallDeltaFunctor"/>
##    creates additional operations for <M>\delta</M>-functors in order to compute connecting homomorphisms,
##    exact triangles, and associated long exact sequences by starting with a short exact sequence.
##    <P/>
##    In &homalg; special emphasis is laid on the action of functors on <E>morphisms</E>, as an essential part of the
##    very definition of a functor. This is for no obvious reason often neglected in computer algebra systems.
##    Starting from a functor where the action on morphisms is also defined, all the above constructors
##    again create functors with actions both on objects and on morphisms (and hence on chain complexes and chain morphisms).
##    <P/>
##    It turned out that in a variety of situations a caching mechanism for functors is not only extremely
##    useful (e.g. to avoid repeated expensive computations) but also an absolute necessity for the coherence of data.
##    Functors in &homalg; are therefore endowed with a caching mechanism.
##    <P/>
##    If <M>R</M> is a &homalg; ring in which the component <M>R</M>!.<C>ByASmallerPresentation</C> is set to true
##    <Br/><Br/>
##    <C>R!.ByASmallerPresentation := true</C>;
##    <Br/><Br/>
##    any functor which returns an object over <M>R</M> will first apply
##    <C>ByASmallerPresentation</C> to its result before returning it. <P/>
##    One of the highlights in &homalg; is the computation of Grothendieck's spectral sequences connecting
##    the composition of the derivations of two functors with the derived functor of their composite.
##  <#/GAPDoc>

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

# a new representation for the GAP-category IsHomalgFunctor:

##  <#GAPDoc Label="IsHomalgFunctorRep">
##  <ManSection>
##    <Filt Type="Representation" Arg="E" Name="IsHomalgFunctorRep"/>
##    <Returns><C>true</C> or <C>false</C></Returns>
##    <Description>
##      The &GAP; representation of &homalg; (multi-)functors. <P/>
##      (It is a representation of the &GAP; category <Ref Filt="IsHomalgFunctor"/>.)
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
DeclareRepresentation( "IsHomalgFunctorRep",
        IsHomalgFunctor,
        [ ] );

# a new subrepresentation of the representation IsContainerForWeakPointersRep:

##
DeclareRepresentation( "IsContainerForWeakPointersOnComputedValuesOfFunctorRep",
        IsContainerForWeakPointersOnObjectsRep,
        [ "weak_pointers", "active", "deleted", "counter", "accessed", "cache_misses", "cache_hits" ] );

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

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

# a new type:
BindGlobal( "TheTypeHomalgFunctor",
        NewType(  TheFamilyOfHomalgFunctors,
                IsHomalgFunctorRep ) );

# a new type:
BindGlobal( "TheTypeContainerForWeakPointersOnComputedValuesOfFunctor",
        NewType( TheFamilyOfContainersForWeakPointers,
                IsContainerForWeakPointersOnComputedValuesOfFunctorRep ) );

####################################
#
# global values:
#
####################################

HOMALG.FunctorOn :=
  [ IsStructureObjectOrFinitelyPresentedObjectRep,
    IsStaticMorphismOfFinitelyGeneratedObjectsRep,
    [ IsComplexOfFinitelyPresentedObjectsRep, IsCocomplexOfFinitelyPresentedObjectsRep ],
    [ IsChainMorphismOfFinitelyPresentedObjectsRep, IsCochainMorphismOfFinitelyPresentedObjectsRep ] ];
  
####################################
#
# methods for operations:
#
####################################

##
InstallMethod( NaturalGeneralizedEmbedding,
        "for homalg objects being values of functors on objects",
        [ IsStaticFinitelyPresentedObjectRep ],
        
  function( FM )
    
    if not IsBound(FM!.NaturalGeneralizedEmbedding) then
        Error( "the object does not have a component \"NaturalGeneralizedEmbedding\"; either the object is not the result of a functor or the functor is not properly implemented (cf. arXiv:math/0701146)\n" );
    fi;
    
    return FM!.NaturalGeneralizedEmbedding;
    
end );

##
InstallMethod( NameOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    if not IsBound( Functor!.name ) then
        Error( "the provided functor is nameless\n" );
    fi;
    
    return Functor!.name;
    
end );

##
InstallMethod( OperationOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    local functor_operation;
    
    if not IsBound( Functor!.operation ) then
        Error( "unable to find the functor component \"operation\"\n" );
    fi;
    
    functor_operation := ValueGlobal( Functor!.operation );
    
    ## for this to work you need to declare one instance of the functor,
    ## although all methods will be installed using InstallOtherMethod!
    if not IsOperation( functor_operation ) and
       not IsFunction( functor_operation ) then
        Error( "the functor ", NameOfFunctor( Functor ), " neither points to an operation nor to a function\n" );
    fi;
    
    return functor_operation;
    
end );

##
InstallMethod( CategoryOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    if not IsBound( Functor!.category ) then
        Error( "unable to find the functor component \"category\"\n" );
    fi;
    
    return Functor!.category;
    
end );

##
InstallMethod( DescriptionOfCategory,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    local category;
    
    category := CategoryOfFunctor( Functor );
    
    if not IsBound( category!.description ) then
        Error( "unable to find the category component \"description\"\n" );
    fi;
    
    return category!.description;
    
end );

##
InstallMethod( ShortDescriptionOfCategory,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    local category;
    
    category := CategoryOfFunctor( Functor );
    
    if not IsBound( category!.short_description ) then
        Error( "unable to find the category component \"short_description\"\n" );
    fi;
    
    return category!.short_description;
    
end );

##
InstallMethod( IsSpecialFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    if IsBound( Functor!.special ) and Functor!.special = true then
        return true;
    fi;
    
    return false;
    
end );

##
InstallMethod( MultiplicityOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    if IsBound( Functor!.number_of_arguments ) then
        return Functor!.number_of_arguments;
    fi;
    
    return 1;
    
end );

##
InstallMethod( IsCovariantFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsInt ],
        
  function( Functor, pos )
    
    if pos < 1 then
        Error( "the second argument must be a positive integer\n" );
    fi;
    
    if IsBound( Functor!.(pos) ) then
        if Functor!.( pos )[1][1] = "covariant" then
            return true;
        elif Functor!.( pos )[1][1] = "contravariant" then
            return false;
        fi;
    fi;
    
    return fail;
    
end );

##
InstallMethod( IsCovariantFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    return IsCovariantFunctor( Functor, 1 );
    
end );

##
InstallMethod( IsDistinguishedArgumentOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt ],
        
  function( Functor, pos )
    local l;
    
    if IsBound( Functor!.(String( pos )) ) and IsBound( Functor!.(String( pos ))[1] ) then
        l := Length( Functor!.(String( pos ))[1] );
        
        if l > 1 and Functor!.(String( pos ))[1][l] = "distinguished" then
            return true;
        fi;
    fi;
    
    return false;
    
end );

##
InstallMethod( IsDistinguishedFirstArgumentOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    return IsDistinguishedArgumentOfFunctor( Functor, 1 );
    
end );

##
InstallMethod( IsAdditiveFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt ],
        
  function( Functor, pos )
    local prop;
    
    if IsBound( Functor!.(pos) ) and Length( Functor!.( pos )[1] ) > 1 then
        prop := Functor!.( pos )[1][2];
        if prop in [ "additive", "left exact", "right exact", "exact", "right adjoint", "left adjoint" ] then
            return true;
        fi;
    fi;
    
    return fail;
    
end );

##
InstallMethod( IsAdditiveFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    return IsAdditiveFunctor( Functor, 1 );
    
end );

##
InstallMethod( IsLeftExactFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt ],
        
  function( Functor, pos )
    local prop;
    
    if IsBound( Functor!.(pos) ) and Length( Functor!.( pos )[1] ) > 1 then
        prop := Functor!.( pos )[1][2];
        if prop in [ "left exact", "exact", "right adjoint" ] then
            return true;
        fi;
    fi;
    
    return fail;
    
end );

##
InstallMethod( IsLeftExactFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    return IsLeftExactFunctor( Functor, 1 );
    
end );

##
InstallMethod( IsRightExactFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt ],
        
  function( Functor, pos )
    local prop;
    
    if IsBound( Functor!.(pos) ) and Length( Functor!.( pos )[1] ) > 1 then
        prop := Functor!.( pos )[1][2];
        if prop in [ "right exact", "exact", "left adjoint" ] then
            return true;
        fi;
    fi;
    
    return fail;
    
end );

##
InstallMethod( IsRightExactFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    return IsRightExactFunctor( Functor, 1 );
    
end );

##
InstallMethod( IsIdenticalObjForFunctors,
        "for two objects",
        [ IsObject, IsObject ],
        
  function( o1, o2 )
    local l1, l2;
    
    if IsHomalgObjectOrMorphism( o1 ) then
        return IsIdenticalObj( o1, o2 );
    elif IsString( o1 ) and IsString( o2 ) then
        return o1 = o2;
    elif IsList( o1 ) and IsList( o2 ) then
        l1 := Length( o1 );
        l2 := Length( o2 );
        return l1 = l2 and
               ForAll( [ 1 .. l1 ], i -> IsIdenticalObjForFunctors( o1[i], o2[i] ) );
    fi;
    
    return IsIdenticalObj( o1, o2 );
    
end );

##
InstallMethod( GetContainerForWeakPointersOfFunctorCachedValue,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsHomalgCategory, IsString ],
        
  function( Functor, category, container )
    local name, containers;
    
    ## first we ask the functor
    if not IsBound( Functor!.( container ) ) then
        return fail;
    elif Functor!.( container ) = false and
      IsBound( category!.do_not_cache_values_of_some_functors ) and
      category!.do_not_cache_values_of_some_functors = true then
        return fail;
    fi;
    
    name := Concatenation( NameOfFunctor( Functor ), "_", container );
    
    containers := category!.containers;
    
    if IsBound( containers!.( name ) ) then
        container := containers!.( name );
        if IsContainerForWeakPointersRep( container ) then
            return container;
        fi;
        return fail;
    elif IsBound( category!.do_not_cache_values_of_functors ) then
        return fail;
    fi;
    
    container := ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
    
    containers!.( name ) := container;
    
    return container;
    
end );

##
InstallMethod( SetFunctorObjCachedValue,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsList, IsObject ],
        
  function( Functor, args_of_functor, obj )
    local arguments_of_functor, p, l, context_of_arguments, arg_all,
          genesis, a, category, container;
    
    ## convert subobjects into objects
    arguments_of_functor :=
      List( args_of_functor,
            function( a )
              if IsStaticFinitelyPresentedSubobjectRep( a ) then
                  return UnderlyingObject( a );
              else
                  return a;
              fi;
            end );
    
    if IsBound( Functor!.0 ) then
        p := 1;
    else
        p := 0;
    fi;
    l := Length( arguments_of_functor );
    
    context_of_arguments := List( arguments_of_functor{[ 1 + p .. l ]}, PositionOfTheDefaultPresentation );
    
    arg_all := rec( );
    
    arg_all.("arguments_of_functor") := arguments_of_functor;
    arg_all.("context_of_arguments") := context_of_arguments;
    arg_all.("Functor") := Functor;
    arg_all.("PositionOfTheDefaultPresentationOfTheOutput")
      := PositionOfTheDefaultPresentation( obj );
    
    arg_all := [ arg_all, obj ];
    
    if not HasGenesis( obj ) then
        SetGenesis( obj, [ arg_all ] );
    else
        genesis := Genesis( obj );
        if IsList( genesis ) then
            Add( genesis, arg_all );
        fi;
    fi;
    
    for a in args_of_functor do
        category := HomalgCategory( a );
        if category <> fail then
            break;
        fi;
    od;
    
    container := GetContainerForWeakPointersOfFunctorCachedValue(
                         Functor,
                         category,
                         "ContainerForWeakPointersOnComputedBasicObjects" );
    
    if container <> fail then
        _AddElmWPObj_ForHomalg( container, arg_all );
    fi;
    
    return obj;
    
end );

##
InstallMethod( GetFunctorObjCachedValue,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsList ],
        
  function( Functor, args_of_functor )
    local a, category, container, weak_pointers, lp, active, l_active,
          arguments_of_functor, functor_name, p, l, context_of_arguments,
          cache_hit, i, arg_old_obj, context, arg_old, obj;
    
    for a in args_of_functor do
        category := HomalgCategory( a );
        if category <> fail then
            break;
        fi;
    od;
    
    container := GetContainerForWeakPointersOfFunctorCachedValue(
                         Functor,
                         category,
                         "ContainerForWeakPointersOnComputedBasicObjects" );
    
    if container = fail then
        return fail;
    fi;
    
    weak_pointers := container!.weak_pointers;
    
    lp := LengthWPObj( weak_pointers );
    
    active := Filtered( container!.active, i -> i <= lp );
    
    l_active := Length( active );
    
    ## convert subobjects into objects
    arguments_of_functor :=
      List( args_of_functor,
            function( a )
              if IsStaticFinitelyPresentedSubobjectRep( a ) then
                  return UnderlyingObject( a );
              else
                  return a;
              fi;
            end );
    
    #=====# begin of the core procedure #=====#
    
    functor_name := NameOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) then
        p := 1;
    else
        p := 0;
    fi;
    l := Length( arguments_of_functor );
    context_of_arguments := List( arguments_of_functor{[ 1 + p .. l ]}, PositionOfTheDefaultPresentation );
    
    cache_hit := false;
    i := 1;
    while i <= l_active do
        arg_old_obj := ElmWPObj( weak_pointers, active[i] );
        if arg_old_obj <> fail then
            arg_old := arg_old_obj[1];
            context := arg_old.("context_of_arguments");
            arg_old := arg_old.("arguments_of_functor");
            obj := arg_old_obj[2];
            if l = Length( arg_old ) then
                
                if ForAny( arguments_of_functor, IsHomalgStaticObject ) then
                    
                    if ForAll( [ 1 .. l ], j -> IsIdenticalObjForFunctors( arg_old[j], arguments_of_functor[j] ) ) then
                        
                        if ForAll( [ 1 .. l - p ], j -> context[j] = context_of_arguments[j] ) then
                            
                            cache_hit := true;
                            break;
                            
                        elif ForAll( [ 1 .. l - p ],
                                function( j )
                                  if context[j] = context_of_arguments[j] then
                                      return true;
                                  else
                                      return IsIdenticalObj(
                                                      PartOfPresentationRelevantForOutputOfFunctors( arg_old[j+p], context[j] ),
                                                      PartOfPresentationRelevantForOutputOfFunctors( arguments_of_functor[j+p], context_of_arguments[j] ) );
                                  fi;
                                end ) then
                            
                            cache_hit := true;
                            break;
                            
                        elif ForAll( [ 1 .. l - p ],
                                function( j )
                                  return ComparePresentationsForOutputOfFunctors( arguments_of_functor[j+p], context_of_arguments[j], context[j] );
                                end ) then
                            
                            cache_hit := true;
                            break;
                            
                        elif IsBound( obj!.IgnoreContextOfArgumentsOfFunctor ) and
                          obj!.IgnoreContextOfArgumentsOfFunctor = true then
                            
                            cache_hit := true;
                            break;
                            
                        elif IsBound( Functor!.CompareArgumentsForFunctorObj ) and  ## no static objects
                          Functor!.CompareArgumentsForFunctorObj( arg_old, arguments_of_functor ) then
                            
                            cache_hit := true;
                            break;
                            
                        ##elif IsBound( Functor!.OnMorphisms ) then
                        ##    Error( "TODO: merge the new output with the old one\n" );
                        fi;
                    fi;
                    
                elif not ( IsBound( Functor!.DontCompareEquality ) and Functor!.DontCompareEquality ) and
                  ForAll( [ 1 .. l ], j -> arg_old[j] = arguments_of_functor[j] ) then ## no static objects
                    
                    ## this "elif" is extremely important:
                    ## To apply a certain functor (e.g. derived ones) to an object
                    ## we might need to apply another functor to a morphism A. This
                    ## morphisms could be the outcome of a third functor applied to another
                    ## morphism B, and although there is a caching for functors applied
                    ## to morphisms, B often becomes obsolete since it was only used in an
                    ## intermediat step and gets deleted after a while
                    ## (e.g. CompleteImageSquare( alpha1, Functor(morphism), beta1 )).
                    ## Hence B has to be recomputed to get B' and A has to be recomputed
                    ## using B' to get A'. Now A=A' but not identical!
                    
                    cache_hit := true;
                    break;
                    
                elif IsBound( Functor!.CompareArgumentsForFunctorObj ) and  ## no static objects
                  Functor!.CompareArgumentsForFunctorObj( arg_old, arguments_of_functor ) then
                    
                    cache_hit := true;
                    break;
                    
                fi;
                
            fi;
            i := i + 1;
        else  ## active[i] is no longer active
            Remove( active, i );
            l_active := l_active - 1;
        fi;
    od;
    
    container!.active := active;
    container!.deleted := Difference( [ 1 .. lp ], active );
    
    container!.accessed := container!.accessed + 1;
    container!.cache_misses := container!.cache_misses + i - 1;
    
    if cache_hit then
        container!.cache_hits := container!.cache_hits + 1;
        return obj;
    fi;
    
    return fail;
    
end );

##
InstallMethod( FunctorObj,
        "for homalg morphisms",
        [ IsHomalgFunctorRep, IsList ],
        
  function( Functor, args_of_functor )
    local arguments_of_functor, obj, genesis, Functor_orig, arg_pos,
          Functor_arg, Functor_post, Functor_pre, post_arg_pos,
          functor_orig_operation, m_orig, arg_orig,
          functor_pre_operation, m_pre, functor_post_operation, m_post,
          arg_pre, arg_post, R;
    
    ## convert subobjects into objects
    arguments_of_functor :=
      List( args_of_functor,
            function( a )
              if IsStaticFinitelyPresentedSubobjectRep( a ) then
                  return UnderlyingObject( a );
              else
                  return a;
              fi;
            end );
    
    obj := GetFunctorObjCachedValue( Functor, args_of_functor );
    if obj <> fail then
        return obj;
    fi;
    
    #=====# begin of the core procedure #=====#
    
    if HasGenesis( Functor ) then
        genesis := Genesis( Functor );
        if genesis[1] = "InsertObjectInMultiFunctor" then
            Functor_orig := genesis[2];
            arg_pos := genesis[3];
            Functor_arg := genesis[4];
        elif genesis[1] = "ComposeFunctors" then
            Functor_post := genesis[2][1];
            Functor_pre := genesis[2][2];
            post_arg_pos := genesis[3];
        fi;
    fi;
    
    if IsBound( Functor_orig ) then
        ## the functor is specialized: Functor := Functor_orig( ..., Functor_arg, ... )
        
        functor_orig_operation := OperationOfFunctor( Functor_orig );
        
        m_orig := MultiplicityOfFunctor( Functor_orig );
        
        if IsBound( Functor_orig!.0 ) then
            arg_orig := arguments_of_functor{[ 1 .. arg_pos ]};
        else
            arg_orig := arguments_of_functor{[ 1 .. arg_pos - 1 ]};
        fi;
        
        Add( arg_orig, Functor_arg );
        Append( arg_orig, arguments_of_functor{[ arg_pos + 1 .. m_orig ]} );
        
        obj := CallFuncList( functor_orig_operation, arg_orig );
        
    elif IsBound( Functor_post ) then
        ## the functor is composed: Functor := Functor_post @ Functor_pre
        
        functor_pre_operation := OperationOfFunctor( Functor_pre );
        
        functor_post_operation := OperationOfFunctor( Functor_post );
        
        m_pre := MultiplicityOfFunctor( Functor_pre );
        
        m_post := MultiplicityOfFunctor( Functor_post );
        
        arg_pre := arguments_of_functor{[ post_arg_pos .. post_arg_pos + m_pre - 1 ]};
        
        arg_post := Concatenation(
                            arguments_of_functor{[ 1 .. post_arg_pos - 1 ]},
                            [ CallFuncList( functor_pre_operation, arg_pre ) ],
                            arguments_of_functor{[ post_arg_pos + m_pre .. m_post + m_pre - 1 ]}
                            );
        
        obj := CallFuncList( functor_post_operation, arg_post );
        
    else
        
        obj := CallFuncList( Functor!.OnObjects, arguments_of_functor );
        
    fi;
    
    if IsHomalgStaticObject( obj ) then
        R := StructureObject( obj );
        if IsBound( R!.ByASmallerPresentation ) then
            ByASmallerPresentation( obj );
        fi;
    fi;
    
    #=====# end of the core procedure #=====#
    
    SetFunctorObjCachedValue( Functor, arguments_of_functor, obj );
    
    return obj;
    
end );

##
InstallMethod( FunctorMor,
        "for homalg morphisms",
        [ IsHomalgFunctorRep, IsMorphismOfFinitelyGeneratedObjectsRep, IsList ],
        
  function( Functor, phi, fixed_arguments_of_multi_functor )
    local container, weak_pointers, lp, active, l_active, functor_name,
          number_of_arguments, pos0, arg_positions, S, T, pos,
          arg_before_pos, arg_behind_pos, arg_all, cache_hit, i, l,
          arg_old_mor, arg_old, arg_source, arg_target, functor_operation,
          F_source, F_target, genesis, Functor_orig, arg_pos, Functor_arg,
          Functor_post, Functor_pre, post_arg_pos,
          functor_orig_operation, m_orig, arg_orig,
          functor_pre_operation, m_pre, functor_post_operation, m_post,
          arg_pre, arg_post, emb_source, emb_target, arg_phi, hull_phi, mor;
    
    if not fixed_arguments_of_multi_functor = [ ] and
       not ( ForAll( fixed_arguments_of_multi_functor, a -> IsList( a ) and Length( a ) = 2 and IsPosInt( a[1] ) ) ) then
        Error( "the last argument has a wrong syntax\n" );
    fi;
    
    container := GetContainerForWeakPointersOfFunctorCachedValue(
                         Functor,
                         HomalgCategory( phi ),
                         "ContainerForWeakPointersOnComputedBasicMorphisms" );
    if container <> fail then
        
        weak_pointers := container!.weak_pointers;
        
        lp := LengthWPObj( weak_pointers );
        
        active := Filtered( container!.active, i -> i <= lp );
        
        l_active := Length( active );
        
    fi;
    
    #=====# begin of the core procedure #=====#
    
    functor_name := NameOfFunctor( Functor );
    
    number_of_arguments := MultiplicityOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        number_of_arguments := number_of_arguments + 1;
        pos0 := 1;
    else
        pos0 := 0;
    fi;
    
    arg_positions := List( fixed_arguments_of_multi_functor, a -> a[1] );
    
    if Length( arg_positions ) <> number_of_arguments - 1 then
        Error( "the number of fixed arguments provided for the functor must be one less than the total number\n" );
    elif not IsDuplicateFree( arg_positions ) then
        Error( "the provided list of positions is not duplicate free: ", arg_positions, "\n" );
    elif arg_positions <> [ ] and Maximum( arg_positions ) > number_of_arguments then
        Error( "the list of positions must be a subset of [ 1 .. ", number_of_arguments, " ], but received: :",  arg_positions, "\n" );
    fi;
    
    S := Source( phi );
    T := Range( phi );
    
    pos := Filtered( [ 1 .. number_of_arguments ], a -> not a in arg_positions )[1];
    
    arg_positions := fixed_arguments_of_multi_functor;
    
    Sort( arg_positions, function( v, w ) return v[1] < w[1]; end );
    
    arg_before_pos := List( arg_positions{[ 1 .. pos - 1 ]}, a -> a[2] );
    arg_behind_pos := List( arg_positions{[ pos .. number_of_arguments - 1 ]}, a -> a[2] );
    
    arg_all := Concatenation( arg_before_pos, [ phi ], arg_behind_pos );
    
    if container <> fail then
        cache_hit := false;
        i := 1;
        while i <= l_active do
            arg_old_mor := ElmWPObj( weak_pointers, active[i] );
            if arg_old_mor <> fail then
                arg_old := arg_old_mor[1];
                l := Length( arg_old );
                if l = Length( arg_all ) then
                    if ForAll( [ 1 .. l ], j -> IsIdenticalObjForFunctors( arg_old[j], arg_all[j] ) ) then
                        cache_hit := true;
                        break;
                    fi;
                fi;
                i := i + 1;
            else ## active[i] is no longer active
                Remove( active, i );
                l_active := l_active - 1;
            fi;
        od;
        
        container!.active := active;
        container!.deleted := Difference( [ 1 .. lp ], active );
        
        container!.accessed := container!.accessed + 1;
        container!.cache_misses := container!.cache_misses + i - 1;
        
        if cache_hit then
            container!.cache_hits := container!.cache_hits + 1;
            return arg_old_mor[2];
        fi;
        
    fi;
    
    pos := pos - pos0;
    
    if IsCovariantFunctor( Functor, pos ) = true then
        arg_source := Concatenation( arg_before_pos, [ S ], arg_behind_pos );
        arg_target := Concatenation( arg_before_pos, [ T ], arg_behind_pos );
    elif IsCovariantFunctor( Functor, pos ) = false then ## not fail
        arg_source := Concatenation( arg_before_pos, [ T ], arg_behind_pos );
        arg_target := Concatenation( arg_before_pos, [ S ], arg_behind_pos );
    else
        Error( "the functor ", functor_name, " must be either co- or contravriant in its argument number ", pos, "\n" );
    fi;
    
    functor_operation := OperationOfFunctor( Functor );
    
    F_source := CallFuncList( functor_operation, arg_source );
    F_target := CallFuncList( functor_operation, arg_target );

    if ( HasIsZero( F_source ) and IsZero( F_source ) ) or ( HasIsZero( F_target ) and IsZero( F_target ) ) or ( HasIsZero( phi ) and IsZero( phi ) ) then

        mor := TheZeroMorphism( F_source, F_target );

    elif HasIsOne( phi ) and IsOne( phi ) then

        mor := TheIdentityMorphism( F_source );

    else
    
        if HasGenesis( Functor ) then
            genesis := Genesis( Functor );
            if genesis[1] = "InsertObjectInMultiFunctor" then
                Functor_orig := genesis[2];
                arg_pos := genesis[3];
                Functor_arg := genesis[4];
            elif genesis[1] = "ComposeFunctors" then
                Functor_post := genesis[2][1];
                Functor_pre := genesis[2][2];
                post_arg_pos := genesis[3];
            fi;
        fi;
    
        if IsBound( Functor_orig ) then
            ## the functor is specialized: Functor := Functor_orig( ..., Functor_arg, ... )
        
            functor_orig_operation := OperationOfFunctor( Functor_orig );
        
            m_orig := MultiplicityOfFunctor( Functor_orig );
        
            if IsBound( Functor_orig!.0 ) then
                arg_orig := arg_all{[ 1 .. arg_pos ]};
            else
                arg_orig := arg_all{[ 1 .. arg_pos - 1 ]};
            fi;
        
            Add( arg_orig, Functor_arg );
            Append( arg_orig, arg_all{[ arg_pos + 1 .. m_orig ]} );
        
            mor := CallFuncList( functor_orig_operation, arg_orig );
        
        elif IsBound( Functor_post ) then
            ## the functor is composed: Functor := Functor_post @ Functor_pre
        
            functor_pre_operation := OperationOfFunctor( Functor_pre );
        
            functor_post_operation := OperationOfFunctor( Functor_post );
        
            m_pre := MultiplicityOfFunctor( Functor_pre );
        
            m_post := MultiplicityOfFunctor( Functor_post );
        
            arg_pre := arg_all{[ post_arg_pos .. post_arg_pos + m_pre - 1 ]};
        
            arg_post := Concatenation(
                            arg_all{[ 1 .. post_arg_pos - 1 ]},
                            [ CallFuncList( functor_pre_operation, arg_pre ) ],
                            arg_all{[ post_arg_pos + m_pre .. m_post + m_pre - 1 ]}
                            );
        
            mor := CallFuncList( functor_post_operation, arg_post );
        
        elif IsBound( Functor!.IsIdentityOnObjects ) and Functor!.IsIdentityOnObjects then
        
            if IsBound( Functor!.OnMorphisms ) then
                arg_phi := Concatenation( arg_before_pos, [ phi ], arg_behind_pos );
                mor := CallFuncList( Functor!.OnMorphisms, arg_phi );
            
                if IsBound( Functor!.MorphismConstructor ) then
                    mor := Functor!.MorphismConstructor( mor, F_source, F_target );
                
                    ## otherwise the result mor cannot automatically be marked IsMorphism
                    SetIsMorphism( mor, true );
                fi;
            else
                mor := phi;
            fi;
        
        elif IsBound( Functor!.OnMorphisms ) then
        
            mor := Functor!.OnMorphisms( F_source, F_target, arg_before_pos, phi, arg_behind_pos );
        
        else ## old style, will be eliminated soon
        
            emb_source := NaturalGeneralizedEmbedding( F_source );
            emb_target := NaturalGeneralizedEmbedding( F_target );
        
            if IsBound( Functor!.OnMorphismsHull ) then
                arg_phi := Concatenation( arg_before_pos, [ phi ], arg_behind_pos );
                hull_phi := CallFuncList( Functor!.OnMorphismsHull, arg_phi );
            
                if IsBound( Functor!.MorphismConstructor ) then
                    hull_phi := Functor!.MorphismConstructor( hull_phi, Range( emb_source ), Range( emb_target ) );
                
                    ## otherwise the result mor cannot automatically be marked IsMorphism
                    SetIsMorphism( hull_phi, true );
                fi;
            else
                hull_phi := phi;
            fi;
        
            mor := CompleteImageSquare( emb_source, hull_phi, emb_target );
        
            ## CAUTION: this is experimental!!!
            if HasIsGeneralizedMonomorphism( emb_source ) and IsGeneralizedMonomorphism( emb_source ) and
               HasIsGeneralizedMonomorphism( emb_target ) and IsGeneralizedMonomorphism( emb_target ) and
               HasIsMorphism( phi ) and IsMorphism( phi ) then
            
                ## check assertion
                Assert( 3, IsMorphism( mor ) );
            
                SetIsMorphism( mor, true );
            fi;
        
        fi;
    
    fi;

    SetPropertiesOfFunctorMor( Functor, phi, mor, pos, arg_before_pos, arg_behind_pos );
    
    #=====# end of the core procedure #=====#
    
    arg_all := [ arg_all, mor ];
    
    if not HasGenesis( mor ) then
        SetGenesis( mor, [ arg_all ] );
    else
        Add( Genesis( mor ), arg_all );
    fi;
    
    if container <> fail then
        _AddElmWPObj_ForHomalg( container, arg_all );
    fi;
    
    return mor;
    
end );

##
InstallMethod( FunctorMor,
        "for homalg morphisms",
        [ IsHomalgFunctorRep, IsStaticMorphismOfFinitelyGeneratedObjectsRep ],
        
  function( Functor, phi )
    
    return FunctorMor( Functor, phi, [ ] );
    
end );

InstallMethod( SetPropertiesOfFunctorMor,
        "for homalg morphisms",
        [ IsHomalgFunctorRep, IsHomalgMorphism, IsHomalgMorphism, IsInt, IsList, IsList ],
        
  function( Functor, phi, mor, pos, arg_before_pos, arg_behind_pos )
    local alpha;
    
    if HasIsIsomorphism( phi ) and IsIsomorphism( phi ) then
        
        Assert( 3, IsIsomorphism( mor ) );
        SetIsIsomorphism( mor, true );
        
    fi;
        
    if HasIsMorphism( phi ) and IsMorphism( phi ) then
        
        Assert( 3, IsMorphism( mor ) );
        SetIsMorphism( mor, true );
        
    fi;
    
    if IsLeftExactFunctor( Functor, pos ) = true then
        
        if IsCovariantFunctor( Functor, pos ) = true then
            
            if  HasIsMonomorphism( phi ) and IsMonomorphism( phi ) then
                
                Assert( 3, IsMonomorphism( mor ) );
                SetIsMonomorphism( mor, true );
                
            fi;
            
            if HasKernelEmb( phi ) then
                alpha := GetFunctorObjCachedValue( Functor, Concatenation( arg_before_pos, [ KernelEmb( phi ) ], arg_behind_pos ) );
                if alpha <> fail then
                    SetKernelEmb( mor, alpha );
                fi;
            fi;
            
        fi;
        
        if IsCovariantFunctor( Functor, pos ) = false then
            
            if  HasIsEpimorphism( phi ) and IsEpimorphism( phi ) then
                
                Assert( 3, IsMonomorphism( mor ) );
                SetIsMonomorphism( mor, true );
                
            fi;
            
            if HasCokernelEpi( phi ) then
                alpha := GetFunctorObjCachedValue( Functor, Concatenation( arg_before_pos, [ CokernelEpi( phi ) ], arg_behind_pos ) );
                if alpha <> fail then
                    Error( "juhu 2" );
                    SetKernelEmb( mor, alpha );
                fi;
            fi;
            
        fi;
        
    fi;
    
    if IsRightExactFunctor( Functor, pos ) = true then
        
        if IsCovariantFunctor( Functor, pos ) = true then
            
            if  HasIsEpimorphism( phi ) and IsEpimorphism( phi ) then
                
                Assert( 3, IsEpimorphism( mor ) );
                SetIsEpimorphism( mor, true );
                
            fi;
            
            if HasCokernelEpi( phi ) then
                alpha := GetFunctorObjCachedValue( Functor, Concatenation( arg_before_pos, [ CokernelEpi( phi ) ], arg_behind_pos ) );
                if alpha <> fail then
                    SetCokernelEpi( mor, alpha );
                fi;
            fi;
            
        fi;
        
        if IsCovariantFunctor( Functor, pos ) = false then
            
            if  HasIsMonomorphism( phi ) and IsMonomorphism( phi ) then
                
                Assert( 3, IsEpimorphism( mor ) );
                SetIsEpimorphism( mor, true );
                
            fi;
            
            if HasKernelEmb( phi ) then
                alpha := GetFunctorObjCachedValue( Functor, Concatenation( arg_before_pos, [ KernelEmb( phi ) ], arg_behind_pos ) );
                if alpha <> fail then
                    SetCokernelEpi( mor, alpha );
                fi;
            fi;
            
        fi;
        
    fi;
    
    UpdateObjectsByMorphism( mor );
    
    return mor;
    
end );

##
InstallMethod( InstallFunctorOnObjects,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    local genesis, der_arg, functor_operation, number_of_arguments,
          natural_transformation,
          natural_transformation1, natural_transformation2,
          natural_transformation3, natural_transformation4,
          filter_obj, filter0, filter1_obj, filter2_obj, filter3_obj;
    
    if HasGenesis( Functor ) then
        genesis := Genesis( Functor );
        if IsBound( genesis[3] ) then
            der_arg := genesis[3];
        fi;
    fi;
    
    functor_operation := OperationOfFunctor( Functor );
    
    number_of_arguments := MultiplicityOfFunctor( Functor );
    
    if number_of_arguments = 1 then
        
        if not IsBound( Functor!.1[2] ) then
            Functor!.1[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.1[2][1] ) then
            return fail;
        fi;
        
        filter_obj := Functor!.1[2][1];
        
        if IsFilter( filter_obj ) then
            
            if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
                
                if Length( Functor!.0 ) = 1 then
                    filter0 := Functor!.0[1];
                else
                    filter0 := IsList;
                fi;
                
                InstallOtherMethod( functor_operation,
                        "for homalg objects",
                        [ filter0, filter_obj ],
                  function( c, o )
                    local obj;
                    
                    if IsStructureObject( o ) then
                        ## I personally prefer left objects:
                        obj := AsLeftObject( o );
                    else
                        obj := o;
                    fi;
                    
                    return FunctorObj( Functor, [ c, obj ] );
                    
                end );
                
            else
                
                if IsBound( Functor!.natural_transformation ) then
                    
                    natural_transformation := ValueGlobal( Functor!.natural_transformation );
                    
                    InstallOtherMethod( natural_transformation,
                            "for homalg objects",
                            [ filter_obj ],
                      function( o )
                        
                        functor_operation( o ); ## this should set the attribute named "natural_transformation"
                        
                        if not Tester( natural_transformation )( o ) then
                            Error( "the functor operation ", functor_operation,
                                   " did not succeed to set the attribute ",
                                   natural_transformation, "\n" );
                        fi;
                        
                        return natural_transformation( o );
                        
                    end );
                    
                fi;
                
                if IsBound( Functor!.natural_transformation1 ) then
                    
                    natural_transformation1 := ValueGlobal( Functor!.natural_transformation1 );
                    
                    InstallOtherMethod( natural_transformation1,
                            "for homalg objects",
                            [ filter_obj ],
                      function( o )
                        
                        functor_operation( o ); ## this should set the attribute named "natural_transformation"
                        
                        if not Tester( natural_transformation1 )( o ) then
                            Error( "the functor operation ", functor_operation,
                                   " did not succeed to set the attribute ",
                                   natural_transformation1, "\n" );
                        fi;
                        
                        return natural_transformation1( o );
                        
                    end );
                    
                fi;
                
                if IsBound( Functor!.natural_transformation2 ) then
                    
                    natural_transformation2 := ValueGlobal( Functor!.natural_transformation2 );
                    
                    InstallOtherMethod( natural_transformation2,
                            "for homalg objects",
                            [ filter_obj ],
                      function( o )
                        
                        functor_operation( o ); ## this should set the attribute named "natural_transformation"
                        
                        if not Tester( natural_transformation2 )( o ) then
                            Error( "the functor operation ", functor_operation,
                                   " did not succeed to set the attribute ",
                                   natural_transformation2, "\n" );
                        fi;
                        
                        return natural_transformation2( o );
                        
                    end );
                    
                fi;
                
                if IsBound( Functor!.natural_transformation3 ) then
                    
                    natural_transformation3 := ValueGlobal( Functor!.natural_transformation3 );
                    
                    InstallOtherMethod( natural_transformation3,
                            "for homalg objects",
                            [ filter_obj ],
                      function( o )
                        
                        functor_operation( o ); ## this should set the attribute named "natural_transformation"
                        
                        if not Tester( natural_transformation3 )( o ) then
                            Error( "the functor operation ", functor_operation,
                                   " did not succeed to set the attribute ",
                                   natural_transformation3, "\n" );
                        fi;
                        
                        return natural_transformation3( o );
                        
                    end );
                    
                fi;
                
                if IsBound( Functor!.natural_transformation4 ) then
                    
                    natural_transformation4 := ValueGlobal( Functor!.natural_transformation4 );
                    
                    InstallOtherMethod( natural_transformation4,
                            "for homalg objects",
                            [ filter_obj ],
                      function( o )
                        
                        functor_operation( o ); ## this should set the attribute named "natural_transformation"
                        
                        if not Tester( natural_transformation4 )( o ) then
                            Error( "the functor operation ", functor_operation,
                                   " did not succeed to set the attribute ",
                                   natural_transformation4, "\n" );
                        fi;
                        
                        return natural_transformation4( o );
                        
                    end );
                    
                fi;
                
                InstallOtherMethod( functor_operation,
                        "for homalg objects",
                        [ filter_obj ],
                  function( o )
                    local obj;
                    
                    if IsStructureObject( o ) then
                        ## I personally prefer left objects:
                        obj := AsLeftObject( o );
                    else
                        obj := o;
                    fi;
                    
                    return FunctorObj( Functor, [ obj ] );
                    
                end );
                
            fi;
            
        else
            
            Error( "wrong syntax: ", filter_obj, "\n" );
            
        fi;
        
    elif number_of_arguments = 2 then
        
        if not IsBound( Functor!.1[2] ) then
            Functor!.1[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.2[2] ) then
            Functor!.2[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.1[2][1] ) or not IsBound( Functor!.2[2][1] ) then
            return fail;
        fi;
        
        filter1_obj := Functor!.1[2][1];
        filter2_obj := Functor!.2[2][1];
        
        if IsFilter( filter1_obj ) and IsFilter( filter2_obj ) then
            
            if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
                
                if Length( Functor!.0 ) = 1 then
                    filter0 := Functor!.0[1];
                else
                    filter0 := IsList;
                fi;
                
                if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg objects",
                            [ filter0, filter1_obj ],
                      function( c, o )
                        local R;
                        
                        if IsStructureObject( o ) then
                            R := o;
                        else
                            R := StructureObject( o );
                        fi;
                        
                        return functor_operation( c, o, R );
                        
                    end );
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg objects",
                            [ IsInt, filter1_obj, IsString ],
                      function( c, o, s )
                        local R;
                        
                        if IsStructureObject( o ) then
                            R := o;
                        else
                            R := StructureObject( o );
                        fi;
                        
                        return functor_operation( c, o, R, s );
                        
                    end );
                    
                    if IsBound( der_arg ) and der_arg = 1 then
                        
                        InstallOtherMethod( functor_operation,
                                "for homalg objects",
                                [ filter1_obj ],
                          function( o )
                            local R;
                            
                            if IsStructureObject( o ) then
                                R := o;
                            else
                                R := StructureObject( o );
                            fi;
                            
                            return functor_operation( o, R );
                            
                        end );
                        
                    fi;
                    
                fi;
                
                InstallOtherMethod( functor_operation,
                        "for homalg objects",
                        [ filter0, filter1_obj, filter2_obj ],
                  function( c, o1, o2 )
                    local obj1, obj2;
                    
                    if IsHomalgStaticObject( o1 ) and IsHomalgStaticObject( o2 ) then ## the most probable case
                        obj1 := o1;
                        obj2 := o2;
                    elif IsHomalgStaticObject( o1 ) and IsStructureObject( o2 ) then
                        obj1 := o1;
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( o1 ) then
                            obj2 := AsLeftObject( o2 );
                        else
                            obj2 := AsRightObject( o2 );
                        fi;
                    elif IsStructureObject( o1 ) and IsHomalgStaticObject( o2 ) then
                        obj2 := o2;
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( o2 ) then
                            obj1 := AsLeftObject( o1 );
                        else
                            obj1 := AsRightObject( o1 );
                        fi;
                    elif IsStructureObject( o1 ) and IsStructureObject( o2 ) then
                        if not IsIdenticalObj( o1, o2 ) then
                            Error( "the two rings are not identical\n" );
                        fi;
                        
                        ## I personally prefer left objects:
                        obj1 := AsLeftObject( o1 );
                        obj2 := obj1;
                    else
                        ## the default:
                        obj1 := o1;
                        obj2 := o2;
                    fi;
                    
                    return FunctorObj( Functor, [ c, obj1, obj2 ] );
                    
                end );
                
                if IsBound( der_arg ) then
                    
                    if IsCovariantFunctor( Functor, der_arg ) then
                        
                        InstallOtherMethod( functor_operation,
                                "for homalg objects",
                                [ IsInt, filter1_obj, filter2_obj, IsString ],
                          function( n, o1, o2, s )
                            local H, C, j;
                            
                            if s <> "a" then
                                TryNextMethod( );
                            fi;
                            
                            H := functor_operation( 0, o1, o2 );
                            
                            C := HomalgComplex( H );
                            
                            for j in [ 1 .. n ] do
                                
                                H := functor_operation( j, o1, o2 );
                                
                                Add( C, H );
                                
                            od;
                            
                            return C;
                            
                        end );
                        
                    else
                        
                        InstallOtherMethod( functor_operation,
                                "for homalg objects",
                                [ IsInt, filter1_obj, filter2_obj, IsString ],
                          function( n, o1, o2, s )
                            local H, C, j;
                            
                            if s <> "a" then
                                TryNextMethod( );
                            fi;
                            
                            H := functor_operation( 0, o1, o2 );
                            
                            C := HomalgCocomplex( H );
                            
                            for j in [ 1 .. n ] do
                                
                                H := functor_operation( j, o1, o2 );
                                
                                Add( C, H );
                                
                            od;
                            
                            return C;
                            
                        end );
                        
                    fi;
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg objects",
                            [ filter1_obj, filter2_obj ],
                      function( o1, o2 )
                        local n;
                        
                        if der_arg = 1 then
                            n := LengthOfResolution( o1 );
                        else
                            n := LengthOfResolution( o2 );
                        fi;
                        
                        return functor_operation( n, o1, o2, "a" );
                        
                    end );
                    
                fi;
                
            else
                
                if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg objects",
                            [ filter1_obj ],
                      function( o )
                        local R;
                        
                        if IsStructureObject( o ) then
                            R := o;
                        else
                            R := StructureObject( o );
                        fi;
                        
                        return functor_operation( o, R );
                        
                    end );
                    
                fi;
                
                InstallOtherMethod( functor_operation,
                        "for homalg objects",
                        [ filter1_obj, filter2_obj ],
                  function( o1, o2 )
                    local obj1, obj2;
                    
                    if IsHomalgStaticObject( o1 ) and IsHomalgStaticObject( o2 ) then ## the most probable case
                        obj1 := o1;
                        obj2 := o2;
                    elif IsHomalgStaticObject( o1 ) and IsStructureObject( o2 ) then
                        obj1 := o1;
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( o1 ) then
                            obj2 := AsLeftObject( o2 );
                        else
                            obj2 := AsRightObject( o2 );
                        fi;
                    elif IsStructureObject( o1 ) and IsHomalgStaticObject( o2 ) then
                        obj2 := o2;
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( o2 ) then
                            obj1 := AsLeftObject( o1 );
                        else
                            obj1 := AsRightObject( o1 );
                        fi;
                    elif IsStructureObject( o1 ) and IsStructureObject( o2 ) then
                        if not IsIdenticalObj( o1, o2 ) then
                            Error( "the two rings are not identical\n" );
                        fi;
                        
                        ## I personally prefer left objects:
                        obj1 := AsLeftObject( o1 );
                        obj2 := obj1;
                    else
                        ## the default:
                        obj1 := o1;
                        obj2 := o2;
                    fi;
                    
                    return FunctorObj( Functor, [ obj1, obj2 ] );
                    
                end );
                
            fi;
            
        else
            
            Error( "wrong syntax: ", filter1_obj, filter2_obj, "\n" );
            
        fi;
        
    elif number_of_arguments = 3 then
        
        if not IsBound( Functor!.1[2] ) then
            Functor!.1[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.2[2] ) then
            Functor!.2[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.3[2] ) then
            Functor!.3[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.1[2][1] ) or
           not IsBound( Functor!.2[2][1] ) or
           not IsBound( Functor!.3[2][1] ) then
            return fail;
        fi;
        
        filter1_obj := Functor!.1[2][1];
        filter2_obj := Functor!.2[2][1];
        filter3_obj := Functor!.3[2][1];
        
        if IsFilter( filter1_obj ) and
           IsFilter( filter2_obj ) and
           IsFilter( filter3_obj ) then
            
            if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
                
                if Length( Functor!.0 ) = 1 then
                    filter0 := Functor!.0[1];
                else
                    filter0 := IsList;
                fi;
                
                if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg objects",
                            [ filter0, filter1_obj ],
                      function( c, o )
                        local R;
                        
                        if IsStructureObject( o ) then
                            R := o;
                        else
                            R := StructureObject( o );
                        fi;
                        
                        return functor_operation( c, o, R, R );
                        
                    end );
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg objects",
                            [ IsInt, filter1_obj, IsString ],
                      function( c, o, s )
                        local R;
                        
                        if IsStructureObject( o ) then
                            R := o;
                        else
                            R := StructureObject( o );
                        fi;
                        
                        return functor_operation( c, o, R, R, s );
                        
                    end );
                    
                fi;
                
                InstallOtherMethod( functor_operation,
                        "for homalg objects",
                        [ filter0, filter1_obj, filter2_obj, filter3_obj ],
                  function( c, o1, o2, o3 )
                    local obj1, obj2, obj3;
                    
                    if IsHomalgStaticObject( o1 ) and
                       IsHomalgStaticObject( o2 ) and
                       IsHomalgStaticObject( o3 ) then ## the most probable case
                        obj1 := o1;
                        obj2 := o2;
                        obj3 := o3;
                    elif IsHomalgStaticObject( o1 ) and IsStructureObject( o2 ) and IsStructureObject( o3 ) then
                        obj1 := o1;
                        
                        if not IsIdenticalObj( o2, o3 ) then
                            Error( "the last two rings are not identical\n" );
                        fi;
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( o1 ) then
                            obj2 := AsLeftObject( o2 );
                            obj3 := AsLeftObject( o3 );
                        else
                            obj2 := AsRightObject( o2 );
                            obj3 := AsRightObject( o3 );
                        fi;
                    ## FIXME: there are missing cases
                    elif ForAll( [ o1, o2, o3 ], IsStructureObject ) then
                        if not IsIdenticalObj( o1, o2 ) then
                            Error( "the first two rings are not identical\n" );
                        elif not IsIdenticalObj( o2, o3 ) then
                            Error( "the last two rings are not identical\n" );
                        fi;
                        
                        ## I personally prefer left objects:
                        obj1 := AsLeftObject( o1 );
                        obj2 := obj1;
                        obj3 := obj1;
                    else
                        ## the default:
                        obj1 := o1;
                        obj2 := o2;
                        obj3 := o3;
                    fi;
                    
                    return FunctorObj( Functor, [ c, obj1, obj2, obj3 ] );
                    
                end );
                
                if IsBound( der_arg ) then
                    
                    if IsCovariantFunctor( Functor, der_arg ) then
                        
                        InstallOtherMethod( functor_operation,
                                "for homalg objects",
                                [ IsInt, filter1_obj, filter2_obj, filter3_obj, IsString ],
                          function( n, o1, o2, o3, s )
                            local H, C, j;
                            
                            if s <> "a" then
                                TryNextMethod( );
                            fi;
                            
                            H := functor_operation( 0, o1, o2, o3 );
                            
                            C := HomalgComplex( H );
                            
                            for j in [ 1 .. n ] do
                                
                                H := functor_operation( j, o1, o2, o3 );
                                
                                Add( C, H );
                                
                            od;
                            
                            return C;
                            
                        end );
                        
                    else
                        
                        InstallOtherMethod( functor_operation,
                                "for homalg objects",
                                [ IsInt, filter1_obj, filter2_obj, filter3_obj, IsString ],
                          function( n, o1, o2, o3, s )
                            local H, C, j;
                            
                            if s <> "a" then
                                TryNextMethod( );
                            fi;
                            
                            H := functor_operation( 0, o1, o2, o3 );
                            
                            C := HomalgCocomplex( H );
                            
                            for j in [ 1 .. n ] do
                                
                                H := functor_operation( j, o1, o2, o3 );
                                
                                Add( C, H );
                                
                            od;
                            
                            return C;
                            
                        end );
                        
                    fi;
                    
                fi;
                
            else
                
                if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg objects",
                            [ filter1_obj ],
                      function( o )
                        local R;
                        
                        if IsStructureObject( o ) then
                            R := o;
                        else
                            R := StructureObject( o );
                        fi;
                        
                        return functor_operation( o, R, R );
                        
                    end );
                    
                fi;
                
                InstallOtherMethod( functor_operation,
                        "for homalg objects",
                        [ filter1_obj, filter2_obj, filter3_obj ],
                  function( o1, o2, o3 )
                    local obj1, obj2, obj3;
                    
                    if IsHomalgStaticObject( o1 ) and
                       IsHomalgStaticObject( o2 ) and
                       IsHomalgStaticObject( o3 ) then ## the most probable case
                        obj1 := o1;
                        obj2 := o2;
                        obj3 := o3;
                    elif IsHomalgStaticObject( o1 ) and IsStructureObject( o2 ) and IsStructureObject( o3 ) then
                        obj1 := o1;
                        
                        if not IsIdenticalObj( o2, o3 ) then
                            Error( "the last two rings are not identical\n" );
                        fi;
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( o1 ) then
                            obj2 := AsLeftObject( o2 );
                            obj3 := AsLeftObject( o3 );
                        else
                            obj2 := AsRightObject( o2 );
                            obj3 := AsRightObject( o3 );
                        fi;
                    ## FIXME: there are missing cases
                    elif ForAll( [ o1, o2, o3 ], IsStructureObject ) then
                        if not IsIdenticalObj( o1, o2 ) then
                            Error( "the first two rings are not identical\n" );
                        elif not IsIdenticalObj( o2, o3 ) then
                            Error( "the last two rings are not identical\n" );
                        fi;
                        
                        ## I personally prefer left objects:
                        obj1 := AsLeftObject( o1 );
                        obj2 := obj1;
                        obj3 := obj1;
                    else
                        ## the default:
                        obj1 := o1;
                        obj2 := o2;
                        obj3 := o3;
                    fi;
                    
                    return FunctorObj( Functor, [ obj1, obj2, obj3 ] );
                    
                end );
                
            fi;
            
        else
            
            Error( "wrong syntax: ", filter1_obj, filter2_obj, filter3_obj, "\n" );
            
        fi;
        
    fi;
    
    InstallNaturalTransformationsOfFunctor( Functor );
    
end );

##
InstallMethod( InstallNaturalTransformationsOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    local functor_operation, number_of_arguments, natural_transformations, arg0, filter_obj, i, natural_transformation, operation, main_argument;
    
    if not IsBound( Functor!.natural_transformations ) then
        return fail;
    fi;
    
    functor_operation := OperationOfFunctor( Functor );
    
    number_of_arguments := MultiplicityOfFunctor( Functor );
    
    natural_transformations := Functor!.natural_transformations;
    
    arg0 := IsBound( Functor!.0 );
    
    if arg0 then
        filter_obj := ShallowCopy( Functor!.0 );
    else
        filter_obj := [ ];
    fi;
    
    i := 1;
    while IsBound( Functor!.(i) ) do
        
        Add( filter_obj, Functor!.(i)[2][1] );
        
        i := i + 1;
    od;
    
    for natural_transformation in natural_transformations do
        
        operation := ValueGlobal( natural_transformation[1] );
        
        if IsBound( natural_transformation[2] ) then
            main_argument := natural_transformation[2];
        else
            if arg0 then
                main_argument := 2;
            else
                main_argument := 1;
            fi;
        fi;
        
        InstallOtherMethod( operation,
                "for homalg objects",
                filter_obj,
          function( arg )
            local context_of_arguments, l, arguments_of_functor, cache_arg, arg_old, context_old, M;
            
            context_of_arguments := List( arg, PositionOfTheDefaultPresentation );
            
            l := Length( context_of_arguments );
            
            arguments_of_functor := List( arg, function( a )
                                                 if IsStaticFinitelyPresentedSubobjectRep( a ) then
                                                     return UnderlyingObject( a );
                                                 else
                                                     return a;
                                                 fi;
                                               end );
            
            # if it is not set, call the functor
            CallFuncList( functor_operation, arguments_of_functor );     ## this sets the informations needed below
            
            M := arguments_of_functor[ main_argument ];
            
            # an return the natural transformation, which should be set now
            if IsBound( M!.natural_transformations ) then
                
                if IsBound( M!.natural_transformations!.(natural_transformation[1]) ) then
                    
                    for cache_arg in M!.natural_transformations!.(natural_transformation[1]) do
                        
                        if Length( cache_arg[1] ) = l then
                            
                            arg_old := cache_arg[1];
                            
                            context_old := cache_arg[2];
                            
                            if arg_old = arguments_of_functor then
                            
                                if context_of_arguments = context_old or 
                                   ForAll( [ 1 .. l ],
                                    function( j )
                                      if context_old[j] = context_of_arguments[j] then
                                          return true;
                                      else
                                          return IsIdenticalObj(
                                                          PartOfPresentationRelevantForOutputOfFunctors( arg_old[j], context_old[j] ),
                                                          PartOfPresentationRelevantForOutputOfFunctors( arguments_of_functor[j], context_of_arguments[j] ) );
                                      fi;
                                    end )
                                    then
                                
                                    return cache_arg[3];
                                
                                fi;
                                
                            fi;
                            
                        fi;
                        
                    od;
                    
                fi;
            fi;
            
            Error( "natural transformation not set by functor" );
            
        end );
        
    od;
    
end );

##
InstallMethod( SetNaturalTransformation,
        "for homalg functors",
        [ IsHomalgFunctor, IsList, IsString, IsObject ],
        
  function( Functor, args, name, nat )
    local pos, natural_transformation, main_argument;
    
    pos := PositionSorted( Functor!.natural_transformations, [ name ] );
    
    natural_transformation := Functor!.natural_transformations[ pos ];
    
    if IsBound( natural_transformation[2] ) then
        main_argument := natural_transformation[2];
    else
        if IsBound( Functor!.0 ) then
            main_argument := 2;
        else
            main_argument := 1;
        fi;
    fi;
    
    main_argument := args[ main_argument ];
    
    if not IsBound( main_argument!.natural_transformations ) then
        main_argument!.natural_transformations := rec( );
    fi;
    if not IsBound( main_argument!.natural_transformations!.(name) ) then
        main_argument!.natural_transformations!.(name) := [ ];
    fi;
    Add( main_argument!.natural_transformations!.(name), [ args, List( args, PositionOfTheDefaultPresentation ), nat ] );
    
end );

##
InstallMethod( InstallFunctorOnMorphisms,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    local genesis, der_arg, functor_operation, number_of_arguments, filter_mor,
          filter0, filter1_obj, filter1_mor, filter2_obj, filter2_mor,
          filter3_obj, filter3_mor;
    
    if HasGenesis( Functor ) then
        genesis := Genesis( Functor );
        if IsBound( genesis[3] ) then
            der_arg := genesis[3];
        fi;
    fi;
    
    functor_operation := OperationOfFunctor( Functor );
    
    number_of_arguments := MultiplicityOfFunctor( Functor );
    
    if number_of_arguments = 1 then
        
        if not IsBound( Functor!.1[2] ) then
            Functor!.1[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.1[2][2] ) then
            return fail;
        fi;
        
        filter_mor := Functor!.1[2][2];
        
        if IsFilter( filter_mor ) then
            
            if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
                
                if Length( Functor!.0 ) = 1 then
                    filter0 := Functor!.0[1];
                else
                    filter0 := IsList;
                fi;
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter0, filter_mor ],
                  function( c, m )
                    
                    return FunctorMor( Functor, m, [ [ 1, c ] ] );
                    
                end );
                
            else
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter_mor ],
                  function( m )
                    
                    return FunctorMor( Functor, m );
                    
                end );
                
            fi;
            
        else
            
            Error( "wrong syntax: ", filter_mor, "\n" );
            
        fi;
        
    elif number_of_arguments = 2 then
        
        if not IsBound( Functor!.1[2] ) then
            Functor!.1[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.2[2] ) then
            Functor!.2[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.1[2][1] ) or not IsBound( Functor!.2[2][1] ) or
           not IsBound( Functor!.1[2][2] ) or not IsBound( Functor!.2[2][2] ) then
            return fail;
        fi;
        
        filter1_obj := Functor!.1[2][1];
        filter1_mor := Functor!.1[2][2];
        
        filter2_obj := Functor!.2[2][1];
        filter2_mor := Functor!.2[2][2];
        
        if IsFilter( filter1_mor ) and IsFilter( filter2_mor ) then
            
            if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
                
                if Length( Functor!.0 ) = 1 then
                    filter0 := Functor!.0[1];
                else
                    filter0 := IsList;
                fi;
                
                if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ filter0, filter1_mor ],
                      function( c, m )
                        local R;
                        
                        R := StructureObject( m );
                        
                        return functor_operation( c, m, R );
                        
                    end );
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ IsInt, filter1_mor, IsString ],
                      function( c, m, s )
                        local R;
                        
                        R := StructureObject( m );
                        
                        return functor_operation( c, m, R, s );
                        
                    end );
                    
                fi;
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter0, filter1_mor, filter2_obj ],
                  function( c, m, o )
                    local obj;
                    
                    if IsHomalgStaticObject( o ) then ## the most probable case
                        obj := o;
                    elif IsStructureObject( o ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj := AsLeftObject( o );
                        else
                            obj := AsRightObject( o );
                        fi;
                    else
                        ## the default:
                        obj := o;
                    fi;
                    
                    return FunctorMor( Functor, m, [ [ 1, c ], [ 3, obj ] ] );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter0, filter1_obj, filter2_mor ],
                  function( c, o, m )
                    local obj;
                    
                    if IsHomalgStaticObject( o ) then ## the most probable case
                        obj := o;
                    elif IsStructureObject( o ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj := AsLeftObject( o );
                        else
                            obj := AsRightObject( o );
                        fi;
                    else
                        ## the default:
                        obj := o;
                    fi;
                    
                    return FunctorMor( Functor, m, [ [ 1, c ], [ 2, obj ] ] );
                    
                end );
                
                if IsCovariantFunctor( Functor, 1 ) = true and
                   IsCovariantFunctor( Functor, 2 ) = true then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ filter0, filter1_mor, filter2_mor ],
                      function( c, m1, m2 )
                        local Fm1, Fm2;
                        
                        Fm1 := functor_operation( c, m1, Source( m2 ) );
                        Fm2 := functor_operation( c, Range( m1 ), m2 );
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( Fm1 ) then
                            return Fm1 * Fm2;
                        else
                            return Fm2 * Fm1;
                        fi;
                        
                    end );
                
                elif IsCovariantFunctor( Functor, 1 ) = false and
                  IsCovariantFunctor( Functor, 2 ) = true then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ filter0, filter1_mor, filter2_mor ],
                      function( c, m1, m2 )
                        local Fm1, Fm2;
                        
                        Fm1 := functor_operation( c, m1, Source( m2 ) );
                        Fm2 := functor_operation( c, Source( m1 ), m2 );
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( Fm1 ) then
                            return Fm1 * Fm2;
                        else
                            return Fm2 * Fm1;
                        fi;
                        
                    end );
                
                fi;
                
                if IsBound( der_arg ) then
                    
                    if IsCovariantFunctor( Functor, der_arg ) then
                        
                        InstallOtherMethod( functor_operation,
                                "for homalg morphisms",
                                [ IsInt, filter1_mor, filter2_obj, IsString ],
                          function( q, m, o, s )
                            local S, T, HS, HT, Hm, c, j;
                            
                            if s <> "a" then
                                TryNextMethod( );
                            fi;
                            
                            S := Source( m );
                            T := Range( m );
                            
                            HS := functor_operation( q, S, o, "a" );
                            HT := functor_operation( q, T, o, "a" );
                            
                            Hm := functor_operation( 0, m, o );
                            
                            c := HomalgChainMorphism( Hm, HS, HT );
                            
                            for j in [ 1 .. q ] do
                                
                                Hm := functor_operation( j, m, o );
                                
                                Add( c, Hm );
                                
                            od;
                            
                            SetIsMorphism( c, true );
                            
                            return c;
                            
                        end );
                        
                    else
                        
                        InstallOtherMethod( functor_operation,
                                "for homalg morphisms",
                                [ IsInt, filter1_mor, filter2_obj, IsString ],
                          function( q, m, o, s )
                            local S, T, HS, HT, Hm, c, j;
                            
                            if s <> "a" then
                                TryNextMethod( );
                            fi;
                            
                            S := Source( m );
                            T := Range( m );
                            
                            HS := functor_operation( q, S, o, "a" );
                            HT := functor_operation( q, T, o, "a" );
                            
                            Hm := functor_operation( 0, m, o );
                            
                            c := HomalgChainMorphism( Hm, HT, HS );
                            
                            for j in [ 1 .. q ] do
                                
                                Hm := functor_operation( j, m, o );
                                
                                Add( c, Hm );
                                
                            od;
                            
                            SetIsMorphism( c, true );
                            
                            return c;
                            
                        end );
                        
                    fi;
                    
                fi;
                
            else
                
                if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ filter1_mor ],
                      function( m )
                        local R;
                        
                        R := StructureObject( m );
                        
                        return functor_operation( m, R );
                        
                    end );
                    
                fi;
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter1_mor, filter2_obj ],
                  function( m, o )
                    local obj;
                    
                    if IsHomalgStaticObject( o ) then ## the most probable case
                        obj := o;
                    elif IsStructureObject( o ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj := AsLeftObject( o );
                        else
                            obj := AsRightObject( o );
                        fi;
                    else
                        ## the default:
                        obj := o;
                    fi;
                    
                    return FunctorMor( Functor, m, [ [ 2, obj ] ] );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter1_obj, filter2_mor ],
                  function( o, m )
                    local obj;
                    
                    if IsHomalgStaticObject( o ) then ## the most probable case
                        obj := o;
                    elif IsStructureObject( o ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj := AsLeftObject( o );
                        else
                            obj := AsRightObject( o );
                        fi;
                    else
                        ## the default:
                        obj := o;
                    fi;
                    
                    return FunctorMor( Functor, m, [ [ 1, obj ] ] );
                    
                end );
                
                if IsCovariantFunctor( Functor, 1 ) = true and
                   IsCovariantFunctor( Functor, 2 ) = true then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ filter1_mor, filter2_mor ],
                      function( m1, m2 )
                        local Fm1, Fm2;
                        
                        Fm1 := functor_operation( m1, Source( m2 ) );
                        Fm2 := functor_operation( Range( m1 ), m2 );
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( Fm1 ) then
                            return Fm1 * Fm2;
                        else
                            return Fm2 * Fm1;
                        fi;
                        
                    end );
                
                elif IsCovariantFunctor( Functor, 1 ) = false and
                  IsCovariantFunctor( Functor, 2 ) = true then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ filter1_mor, filter2_mor ],
                      function( m1, m2 )
                        local Fm1, Fm2;
                        
                        Fm1 := functor_operation( m1, Source( m2 ) );
                        Fm2 := functor_operation( Source( m1 ), m2 );
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( Fm1 ) then
                            return Fm1 * Fm2;
                        else
                            return Fm2 * Fm1;
                        fi;
                        
                    end );
                
                fi;
                
            fi;
            
        else
            
            Error( "wrong syntax: ", filter1_mor, filter2_mor, "\n" );
            
        fi;
        
    elif number_of_arguments = 3 then
        
        if not IsBound( Functor!.1[2] ) then
            Functor!.1[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.2[2] ) then
            Functor!.2[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.3[2] ) then
            Functor!.3[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.1[2][1] ) or not IsBound( Functor!.2[2][1] ) or not IsBound( Functor!.3[2][1] ) or
           not IsBound( Functor!.1[2][2] ) or not IsBound( Functor!.2[2][2] ) or not IsBound( Functor!.3[2][2] ) then
            return fail;
        fi;
        
        filter1_obj := Functor!.1[2][1];
        filter1_mor := Functor!.1[2][2];
        
        filter2_obj := Functor!.2[2][1];
        filter2_mor := Functor!.2[2][2];
        
        filter3_obj := Functor!.3[2][1];
        filter3_mor := Functor!.3[2][2];
        
        if IsFilter( filter1_mor ) and IsFilter( filter2_mor ) and IsFilter( filter3_mor ) then
            
            if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
                
                if Length( Functor!.0 ) = 1 then
                    filter0 := Functor!.0[1];
                else
                    filter0 := IsList;
                fi;
                
                if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ filter0, filter1_mor ],
                      function( c, m )
                        local R;
                        
                        R := StructureObject( m );
                        
                        return functor_operation( c, m, R, R );
                        
                    end );
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ IsInt, filter1_mor, IsString ],
                      function( c, m, s )
                        local R;
                        
                        R := StructureObject( m );
                        
                        return functor_operation( c, m, R, R, s );
                        
                    end );
                    
                fi;
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter0, filter1_mor, filter2_obj, filter3_obj ],
                  function( c, m, o2, o3 )
                    local obj2, obj3;
                    
                    if IsHomalgStaticObject( o2 ) then ## the most probable case
                        obj2 := o2;
                    elif IsStructureObject( o2 ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj2 := AsLeftObject( o2 );
                        else
                            obj2 := AsRightObject( o2 );
                        fi;
                    else
                        ## the default:
                        obj2 := o2;
                    fi;
                    
                    if IsHomalgStaticObject( o3 ) then ## the most probable case
                        obj3 := o3;
                    elif IsStructureObject( o3 ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj3 := AsLeftObject( o3 );
                        else
                            obj3 := AsRightObject( o3 );
                        fi;
                    else
                        ## the default:
                        obj3 := o3;
                    fi;
                    
                    return FunctorMor( Functor, m, [ [ 1, c ], [ 3, obj2 ], [ 4, obj3 ] ] );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter0, filter1_obj, filter2_mor, filter3_obj ],
                  function( c, o1, m, o3 )
                    local obj1, obj3;
                    
                    if IsHomalgStaticObject( o1 ) then ## the most probable case
                        obj1 := o1;
                    elif IsStructureObject( o1 ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj1 := AsLeftObject( o1 );
                        else
                            obj1 := AsRightObject( o1 );
                        fi;
                    else
                        ## the default:
                        obj1 := o1;
                    fi;
                    
                    if IsHomalgStaticObject( o3 ) then ## the most probable case
                        obj3 := o3;
                    elif IsStructureObject( o3 ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj3 := AsLeftObject( o3 );
                        else
                            obj3 := AsRightObject( o3 );
                        fi;
                    else
                        ## the default:
                        obj3 := o3;
                    fi;
                    
                    return FunctorMor( Functor, m, [ [ 1, c ], [ 2, obj1 ], [ 4, obj3 ] ] );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter0, filter1_obj, filter2_obj, filter3_mor ],
                  function( c, o1, o2, m )
                    local obj1, obj2;
                    
                    if IsHomalgStaticObject( o1 ) then ## the most probable case
                        obj1 := o1;
                    elif IsStructureObject( o1 ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj1 := AsLeftObject( o1 );
                        else
                            obj1 := AsRightObject( o1 );
                        fi;
                    else
                        ## the default:
                        obj1 := o1;
                    fi;
                    
                    if IsHomalgStaticObject( o2 ) then ## the most probable case
                        obj2 := o2;
                    elif IsStructureObject( o2 ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj2 := AsLeftObject( o2 );
                        else
                            obj2 := AsRightObject( o2 );
                        fi;
                    else
                        ## the default:
                        obj2 := o2;
                    fi;
                    
                    return FunctorMor( Functor, m, [ [ 1, c ], [ 2, obj1 ], [ 3, obj2 ] ] );
                    
                end );
                
                if IsCovariantFunctor( Functor, 1 ) = true and
                   IsCovariantFunctor( Functor, 2 ) = true and
                   IsCovariantFunctor( Functor, 3 ) = true then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ filter0, filter1_mor, filter2_mor, filter3_mor ],
                      function( c, m1, m2, m3 )
                        local Fm1, Fm2, Fm3;
                        
                        Fm1 := functor_operation( c, m1, Source( m2 ), Source( m3 ) );
                        Fm2 := functor_operation( c, Range( m1 ), m2, Source( m3 ) );
                        Fm3 := functor_operation( c, Range( m1 ), Range( m2 ), m3 );
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( Fm1 ) then
                            return Fm1 * Fm2 * Fm3;
                        else
                            return Fm3 * Fm2 * Fm1;
                        fi;
                        
                    end );
                    
                    ## FIXME: add more cases
                    
                fi;
                
                if IsBound( der_arg ) then
                    
                    if IsCovariantFunctor( Functor, der_arg ) then
                        
                        InstallOtherMethod( functor_operation,
                                "for homalg morphisms",
                                [ IsInt, filter1_mor, filter2_obj, filter3_obj, IsString ],
                          function( q, m, o2, o3, s )
                            local S, T, HS, HT, Hm, c, j;
                            
                            if s <> "a" then
                                TryNextMethod( );
                            fi;
                            
                            S := Source( m );
                            T := Range( m );
                            
                            HS := functor_operation( q, S, o2, o3, "a" );
                            HT := functor_operation( q, T, o2, o3, "a" );
                            
                            Hm := functor_operation( 0, m, o2, o3 );
                            
                            c := HomalgChainMorphism( Hm, HS, HT );
                            
                            for j in [ 1 .. q ] do
                                
                                Hm := functor_operation( j, m, o2, o3 );
                                
                                Add( c, Hm );
                                
                            od;
                            
                            SetIsMorphism( c, true );
                            
                            return c;
                            
                        end );
                        
                    else
                        
                        InstallOtherMethod( functor_operation,
                                "for homalg morphisms",
                                [ IsInt, filter1_mor, filter2_obj, filter3_obj, IsString ],
                          function( q, m, o2, o3, s )
                            local S, T, HS, HT, Hm, c, j;
                            
                            if s <> "a" then
                                TryNextMethod( );
                            fi;
                            
                            S := Source( m );
                            T := Range( m );
                            
                            HS := functor_operation( q, S, o2, o3, "a" );
                            HT := functor_operation( q, T, o2, o3, "a" );
                            
                            Hm := functor_operation( 0, m, o2, o3 );
                            
                            c := HomalgChainMorphism( Hm, HT, HS );
                            
                            for j in [ 1 .. q ] do
                                
                                Hm := functor_operation( j, m, o2, o3 );
                                
                                Add( c, Hm );
                                
                            od;
                            
                            SetIsMorphism( c, true );
                            
                            return c;
                            
                        end );
                        
                    fi;
                    
                fi;
                
            else
                
                if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ filter1_mor ],
                      function( m )
                        local R;
                        
                        R := StructureObject( m );
                        
                        return functor_operation( m, R, R );
                        
                    end );
                    
                fi;
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter1_mor, filter2_obj, filter3_obj ],
                  function( m, o2, o3 )
                    local obj2, obj3;
                    
                    if IsHomalgStaticObject( o2 ) then ## the most probable case
                        obj2 := o2;
                    elif IsStructureObject( o2 ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj2 := AsLeftObject( o2 );
                        else
                            obj2 := AsRightObject( o2 );
                        fi;
                    else
                        ## the default:
                        obj2 := o2;
                    fi;
                    
                    return FunctorMor( Functor, m, [ [ 2, obj2 ], [ 3, obj3 ] ] );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter1_obj, filter2_mor, filter3_obj ],
                  function( o1, m, o3 )
                    local obj1, obj3;
                    
                    if IsHomalgStaticObject( o1 ) then ## the most probable case
                        obj1 := o1;
                    elif IsStructureObject( o1 ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj1 := AsLeftObject( o1 );
                        else
                            obj1 := AsRightObject( o1 );
                        fi;
                    else
                        ## the default:
                        obj1 := o1;
                    fi;
                    
                    if IsHomalgStaticObject( o3 ) then ## the most probable case
                        obj3 := o3;
                    elif IsStructureObject( o3 ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj3 := AsLeftObject( o3 );
                        else
                            obj3 := AsRightObject( o3 );
                        fi;
                    else
                        ## the default:
                        obj3 := o3;
                    fi;
                    
                    return FunctorMor( Functor, m, [ [ 1, obj1 ], [ 3, obj3 ] ] );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg morphisms",
                        [ filter1_mor, filter2_obj, filter3_obj ],
                  function( m, o2, o3 )
                    local obj2, obj3;
                    
                    if IsHomalgStaticObject( o2 ) then ## the most probable case
                        obj2 := o2;
                    elif IsStructureObject( o2 ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj2 := AsLeftObject( o2 );
                        else
                            obj2 := AsRightObject( o2 );
                        fi;
                    else
                        ## the default:
                        obj2 := o2;
                    fi;
                    
                    if IsHomalgStaticObject( o3 ) then ## the most probable case
                        obj3 := o3;
                    elif IsStructureObject( o3 ) then
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( m ) then
                            obj3 := AsLeftObject( o3 );
                        else
                            obj3 := AsRightObject( o3 );
                        fi;
                    else
                        ## the default:
                        obj3 := o3;
                    fi;
                    
                    return FunctorMor( Functor, m, [ [ 2, obj2 ], [ 3, obj3 ] ] );
                    
                end );
                
                if IsCovariantFunctor( Functor, 1 ) = true and
                   IsCovariantFunctor( Functor, 2 ) = true and
                   IsCovariantFunctor( Functor, 3 ) = true then
                    
                    InstallOtherMethod( functor_operation,
                            "for homalg morphisms",
                            [ filter1_mor, filter2_mor, filter3_mor ],
                      function( m1, m2, m3 )
                        local Fm1, Fm2, Fm3;
                        
                        Fm1 := functor_operation( m1, Source( m2 ), Source( m3 ) );
                        Fm2 := functor_operation( Range( m1 ), m2, Source( m3 ) );
                        Fm3 := functor_operation( Range( m1 ), Range( m2 ), m3 );
                        
                        if IsHomalgLeftObjectOrMorphismOfLeftObjects( Fm1 ) then
                            return Fm1 * Fm2 * Fm3;
                        else
                            return Fm3 * Fm2 * Fm1;
                        fi;
                        
                    end );
                    
                    ## FIXME: add more cases
                    
                fi;
                
            fi;
            
        else
            
            Error( "wrong syntax: ", filter1_mor, filter2_mor, filter3_mor, "\n" );
            
        fi;
        
    fi;
    
end );

## for the special functors: Cokernel, Kernel, and DefectOfExactness
InstallMethod( InstallSpecialFunctorOnMorphisms,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    local functor_operation, filter_mor, filter_special;
    
    functor_operation := OperationOfFunctor( Functor );
    
    if not IsBound( Functor!.1[2] ) or not IsBound( Functor!.1[2][2] ) or not IsList( Functor!.1[2][2] ) then
        return fail;
    fi;
    
    filter_mor := Functor!.1[2][2][1];
    filter_special := Functor!.1[2][2][2];
    
    if IsIdenticalObj( OperationOfFunctor( Functor ), ValueGlobal( "Cokernel" ) ) then
        
        InstallOtherMethod( functor_operation,
                "for homalg special chain morphisms",
                [ filter_mor and filter_special ], 10001,
                function( sq )
            local dS, dT, phi, epiS, epiT;
            
            dS := SourceOfSpecialChainMorphism( sq );
            dT := RangeOfSpecialChainMorphism( sq );
            
            phi := CertainMorphismOfSpecialChainMorphism( sq );
            
            epiS := CokernelEpi( dS );
            epiT := CokernelEpi( dT );
            
            return CompleteKernelSquare( epiS, phi, epiT );
            
        end );
        
    else
        
        InstallOtherMethod( functor_operation,
                "for homalg special chain morphisms",
                [ filter_mor and filter_special ], 10001,
                function( sq )
            local dS, dT, phi, muS, muT, psi;
            
            dS := SourceOfSpecialChainMorphism( sq );
            dT := RangeOfSpecialChainMorphism( sq );
            
            phi := CertainMorphismOfSpecialChainMorphism( sq );
            
            muS := NaturalGeneralizedEmbedding( functor_operation( dS ) );
            muT := NaturalGeneralizedEmbedding( functor_operation( dT ) );
            
            psi := CompleteImageSquare( muS, phi, muT );
            
            Assert( 3, IsMorphism( psi ) );
            
            SetIsMorphism( psi, true );
            
            return psi;
            
        end );
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallUnivariateFunctorOnComplexes,
  function( Functor, filter_cpx, complex_or_cocomplex, i )
    local functor_operation, filter0;
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsAdditiveFunctor( Functor ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter0, filter_cpx ],
              function( q, c )
                local degrees, l, morphisms, Fc, m;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( q, CertainObject( c, degrees[1] ) ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( q, morphisms[1] ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( q, m ) );
                    od;
                fi;
                
                if HasIsGradedObject( c ) and IsGradedObject( c ) then;
                    SetIsGradedObject( Fc, true );
                elif HasIsSplitShortExactSequence( c ) and IsSplitShortExactSequence( c ) then
                    SetIsSplitShortExactSequence( Fc, true );
                elif HasIsComplex( c ) and IsComplex( c ) then
                    SetIsComplex( Fc, true );
                elif HasIsSequence( c ) and IsSequence ( c ) then
                    SetIsSequence( Fc, true );
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter0, filter_cpx ],
              function( q, c )
                local degrees, l, morphisms, Fc, m;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( q, CertainObject( c, degrees[1] ) ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( q, morphisms[1] ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( q, m ) );
                    od;
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        fi;
        
    else
        
        if IsAdditiveFunctor( Functor ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter_cpx ],
              function( c )
                local degrees, l, morphisms, Fc, m;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( CertainObject( c, degrees[1] ) ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( morphisms[1] ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( m ) );
                    od;
                fi;
                
                if HasIsGradedObject( c ) and IsGradedObject( c ) then;
                    SetIsGradedObject( Fc, true );
                elif HasIsSplitShortExactSequence( c ) and IsSplitShortExactSequence( c ) then
                    SetIsSplitShortExactSequence( Fc, true );
                elif HasIsComplex( c ) and IsComplex( c ) then
                    SetIsComplex( Fc, true );
                elif HasIsSequence( c ) and IsSequence ( c ) then
                    SetIsSequence( Fc, true );
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter_cpx ],
              function( c )
                local degrees, l, morphisms, Fc, m;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( CertainObject( c, degrees[1] ) ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( morphisms[1] ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( m ) );
                    od;
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallFirstArgumentOfBivariateFunctorOnComplexes,
  function( Functor, filter2_obj, filter1_cpx, complex_or_cocomplex, i )
    local functor_operation, filter0;
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter0, filter1_cpx ],
              function( q, c )
                local R;
                
                R := StructureObject( c );
                
                return functor_operation( q, c, R );
                
            end );
            
        fi;
        
        if IsAdditiveFunctor( Functor, 1 ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter0, filter1_cpx, filter2_obj ],
              function( q, c, o )
                local obj, degrees, l, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( q, CertainObject( c, degrees[1] ), obj ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( q, morphisms[1], obj ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( q, m, obj ) );
                    od;
                fi;
                
                if HasIsGradedObject( c ) and IsGradedObject( c ) then;
                    SetIsGradedObject( Fc, true );
                elif HasIsSplitShortExactSequence( c ) and IsSplitShortExactSequence( c ) then
                    SetIsSplitShortExactSequence( Fc, true );
                elif HasIsComplex( c ) and IsComplex( c ) then
                    SetIsComplex( Fc, true );
                elif HasIsSequence( c ) and IsSequence ( c ) then
                    SetIsSequence( Fc, true );
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter0, filter1_cpx, filter2_obj ],
              function( q, c, o )
                local obj, degrees, l, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( q, CertainObject( c, degrees[1] ), obj ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( q, morphisms[1], obj ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( q, m, obj ) );
                    od;
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        fi;
        
    else
        
        if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter1_cpx ],
              function( c )
                local R;
                
                R := StructureObject( c );
                
                return functor_operation( c, R );
                
            end );
            
        fi;
        
        if IsAdditiveFunctor( Functor, 1 ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter1_cpx, filter2_obj ],
              function( c, o )
                local obj, degrees, l, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( CertainObject( c, degrees[1] ), obj ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( morphisms[1], obj ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( m, obj ) );
                    od;
                fi;
                
                if HasIsGradedObject( c ) and IsGradedObject( c ) then;
                    SetIsGradedObject( Fc, true );
                elif HasIsSplitShortExactSequence( c ) and IsSplitShortExactSequence( c ) then
                    SetIsSplitShortExactSequence( Fc, true );
                elif HasIsComplex( c ) and IsComplex( c ) then
                    SetIsComplex( Fc, true );
                elif HasIsSequence( c ) and IsSequence ( c ) then
                    SetIsSequence( Fc, true );
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter1_cpx, filter2_obj ],
              function( c, o )
                local obj, degrees, l, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( CertainObject( c, degrees[1] ), obj ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( morphisms[1], obj ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( m, obj ) );
                    od;
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallSecondArgumentOfBivariateFunctorOnComplexes,
  function( Functor, filter1_obj, filter2_cpx, complex_or_cocomplex, i )
    local functor_operation, filter0;
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsAdditiveFunctor( Functor, 2 ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter0, filter1_obj, filter2_cpx ],
              function( q, o, c )
                local obj, degrees, l, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( q, obj, CertainObject( c, degrees[1] ) ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( q, obj, morphisms[1] ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( q, obj, m ) );
                    od;
                fi;
                
                if HasIsGradedObject( c ) and IsGradedObject( c ) then;
                    SetIsGradedObject( Fc, true );
                elif HasIsSplitShortExactSequence( c ) and IsSplitShortExactSequence( c ) then
                    SetIsSplitShortExactSequence( Fc, true );
                elif HasIsComplex( c ) and IsComplex( c ) then
                    SetIsComplex( Fc, true );
                elif HasIsSequence( c ) and IsSequence ( c ) then
                    SetIsSequence( Fc, true );
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter0, filter1_obj, filter2_cpx ],
              function( q, o, c )
                local obj, degrees, l, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( q, obj, CertainObject( c, degrees[1] ) ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( q, obj, morphisms[1] ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( q, obj, m ) );
                    od;
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        fi;
        
    else
        
        if IsAdditiveFunctor( Functor, 2 ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter1_obj, filter2_cpx ],
              function( o, c )
                local obj, degrees, l, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( obj, CertainObject( c, degrees[1] ) ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( obj, morphisms[1] ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( obj, m ) );
                    od;
                fi;
                
                if HasIsGradedObject( c ) and IsGradedObject( c ) then;
                    SetIsGradedObject( Fc, true );
                elif HasIsSplitShortExactSequence( c ) and IsSplitShortExactSequence( c ) then
                    SetIsSplitShortExactSequence( Fc, true );
                elif HasIsComplex( c ) and IsComplex( c ) then
                    SetIsComplex( Fc, true );
                elif HasIsSequence( c ) and IsSequence ( c ) then
                    SetIsSequence( Fc, true );
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter1_obj, filter2_cpx ],
              function( o, c )
                local obj, degrees, l, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                if l = 1 then
                    Fc := complex_or_cocomplex( functor_operation( obj, CertainObject( c, degrees[1] ) ), degrees[1] );
                else
                    morphisms := MorphismsOfComplex( c );
                    Fc := complex_or_cocomplex( functor_operation( obj, morphisms[1] ), degrees[i] );
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( obj, m ) );
                    od;
                fi;
                
                if HasIsATwoSequence( c ) and
                   IsATwoSequence( c ) then
                    SetIsATwoSequence( Fc, true );
                    Fc := AsATwoSequence( Fc );
                fi;
                
                return Fc;
                
            end );
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallFirstArgumentOfBivariateFunctorOnMorphismsAndSecondArgumentOnComplexes,
  function( Functor, filter_mor, filter_cpx )
    local functor_operation, covariant1, filter0;
    
    functor_operation := OperationOfFunctor( Functor );
    
    covariant1 := IsCovariantFunctor( Functor, 1 );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsAdditiveFunctor( Functor, 1 ) = true then
            ## FIXME: add code
        fi;
        
    else
        
        if IsAdditiveFunctor( Functor, 1 ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter_mor, filter_cpx ],
              function( m, c )
                local degrees, l, objects, Fc_source, Fc_target, Fc, o;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                objects := ObjectsOfComplex( c );
                
                if covariant1 = true then
                    Fc_source := functor_operation( Source( m ), c );
                    Fc_target := functor_operation( Range( m ), c );
                else
                    Fc_target := functor_operation( Source( m ), c );
                    Fc_source := functor_operation( Range( m ), c );
                fi;
                
                Fc := HomalgChainMorphism( functor_operation( m, objects[1] ), Fc_source, Fc_target );
                
                for o in objects{[ 2 .. l ]} do
                    Add( Fc, functor_operation( m, o ) );
                od;
                
                if HasIsGradedObject( c ) and IsGradedObject( c ) then;
                    SetIsGradedMorphism( Fc, true );
                elif HasIsComplex( c ) and IsComplex( c ) then
                    SetIsMorphism( Fc, true );
                fi;
                
                return Fc;
                
            end );
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallFirstAndSecondArgumentOfBivariateFunctorOnComplexes,
  function( Functor, filter1_cpx, filter2_cpx )
    local functor_operation, covariant1, filter0;
    
    covariant1 := IsCovariantFunctor( Functor, 1 );
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsAdditiveFunctor( Functor, 1 ) = true then
            ## FIXME: add code
        fi;
        
    else
        
        if IsAdditiveFunctor( Functor, 1 ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ filter1_cpx, filter2_cpx ],
              function( c, C )
                local degrees, l, morphisms, Fc, m;
                
                degrees := ObjectDegreesOfComplex( c );
                
                l := Length( degrees );
                
                morphisms := MorphismsOfComplex( c );
                
                if l = 1 then
                    if IsComplexOfFinitelyPresentedObjectsRep( c ) then
                        if covariant1 = true then
                            Fc := HomalgComplex( functor_operation( CertainObject( c, degrees[1] ), C ), degrees[1] );
                        else
                            Fc := HomalgCocomplex( functor_operation( CertainObject( c, degrees[1] ), C ), degrees[1] );
                        fi;
                    else
                        if covariant1 = true then
                            Fc := HomalgCocomplex( functor_operation( CertainObject( c, degrees[1] ), C ), degrees[1] );
                        else
                            Fc := HomalgComplex( functor_operation( CertainObject( c, degrees[1] ), C ), degrees[1] );
                        fi;
                    fi;
                else
                    morphisms := MorphismsOfComplex( c );
                    if IsComplexOfFinitelyPresentedObjectsRep( c ) then
                        if covariant1 then
                            Fc := HomalgComplex( functor_operation( morphisms[1], C ), degrees[2] );
                        else
                            Fc := HomalgCocomplex( functor_operation( morphisms[1], C ), degrees[1] );
                        fi;
                    else
                        if covariant1 then
                            Fc := HomalgCocomplex( functor_operation( morphisms[1], C ), degrees[1] );
                        else
                            Fc := HomalgComplex( functor_operation( morphisms[1], C ), degrees[2] );
                        fi;
                    fi;
                    for m in morphisms{[ 2 .. l - 1 ]} do
                        Add( Fc, functor_operation( m, C ) );
                    od;
                fi;
                
                if HasIsGradedObject( c ) and IsGradedObject( c ) then;
                    SetIsGradedObject( Fc, true );
                elif HasIsSplitShortExactSequence( c ) and IsSplitShortExactSequence( c ) then
                    SetIsSplitShortExactSequence( Fc, true );
                elif HasIsComplex( c ) and IsComplex( c ) then
                    SetIsComplex( Fc, true );
                elif HasIsSequence( c ) and IsSequence ( c ) then
                    SetIsSequence( Fc, true );
                fi;
                
                return Fc;
                
            end );
            
        fi;
        
    fi;
    
end );

##
InstallMethod( InstallFunctorOnComplexes,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    local number_of_arguments, filter_cpx,
          filter1_obj, filter1_cpx, filter2_obj, filter2_cpx,
          ar, i, complex, cocomplex, head;
    
    number_of_arguments := MultiplicityOfFunctor( Functor );
    
    if number_of_arguments = 1 then
        
        if not IsBound( Functor!.1[2] ) then
            Functor!.1[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.1[2][3] ) then
            return fail;
        fi;
        
        filter_cpx := Functor!.1[2][3];
        
        if IsList( filter_cpx ) and Length( filter_cpx ) = 2 and ForAll( filter_cpx, IsFilter ) then
            
            if IsCovariantFunctor( Functor ) = true then
                complex := [ HomalgComplex, 2 ];
                cocomplex := [ HomalgCocomplex, 1 ];
            else
                complex := [ HomalgCocomplex, 1 ];
                cocomplex := [ HomalgComplex, 2  ];
            fi;
            
            head := [ Functor ];
            
            complex := Concatenation( head, [ filter_cpx[1] ], complex );
            cocomplex := Concatenation( head, [ filter_cpx[2] ], cocomplex );
            
            CallFuncList( HelperToInstallUnivariateFunctorOnComplexes, complex );
            CallFuncList( HelperToInstallUnivariateFunctorOnComplexes, cocomplex );
            
        else
            
            Error( "wrong syntax: ", filter_cpx, "\n" );
            
        fi;
        
    elif number_of_arguments = 2 then
        
        if not IsBound( Functor!.1[2] ) then
            Functor!.1[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.2[2] ) then
            Functor!.2[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.1[2][1] ) or not IsBound( Functor!.2[2][1] ) or
           not IsBound( Functor!.1[2][3] ) or not IsBound( Functor!.2[2][3] ) then
            return fail;
        fi;
        
        filter1_obj := Functor!.1[2][1];
        filter1_cpx := Functor!.1[2][3];
        
        filter2_obj := Functor!.2[2][1];
        filter2_cpx := Functor!.2[2][3];
        
        if IsList( filter1_cpx ) and Length( filter1_cpx ) = 2 and ForAll( filter1_cpx, IsFilter ) and
           IsList( filter2_cpx ) and Length( filter2_cpx ) = 2 and ForAll( filter2_cpx, IsFilter ) then
            
            ar := [ [ filter2_obj, filter1_cpx, HelperToInstallFirstArgumentOfBivariateFunctorOnComplexes ],
                    [ filter1_obj, filter2_cpx, HelperToInstallSecondArgumentOfBivariateFunctorOnComplexes ] ];
            
            for i in [ 1 .. number_of_arguments ] do
                
                if IsCovariantFunctor( Functor, i ) = true then
                    complex :=  [ HomalgComplex, 2 ];
                    cocomplex := [ HomalgCocomplex, 1 ];
                else
                    complex := [ HomalgCocomplex, 1 ];
                    cocomplex := [ HomalgComplex, 2 ];
                fi;
                
                head := [ Functor, ar[i][1] ];
                
                complex := Concatenation( head, [ ar[i][2][1] ], complex );
                cocomplex := Concatenation( head, [ ar[i][2][2] ], cocomplex );
                
                CallFuncList( ar[i][3], complex );
                CallFuncList( ar[i][3], cocomplex );
                
            od;
            
            HelperToInstallFirstArgumentOfBivariateFunctorOnMorphismsAndSecondArgumentOnComplexes( Functor, IsHomalgMorphism, IsHomalgComplex );
            HelperToInstallFirstAndSecondArgumentOfBivariateFunctorOnComplexes( Functor, IsHomalgComplex, IsHomalgComplex );
            
        else
            
            Error( "wrong syntax: ", filter1_cpx, filter2_cpx, "\n" );
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallUnivariateFunctorOnChainMorphisms,
  function( Functor, filter_chm, source_target, i )
    local functor_operation, filter0;
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsAdditiveFunctor( Functor ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter0, filter_chm ],
              function( q, c )
                local d, degrees, l, source, target, morphisms, Fc, m;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( q, source_target[1]( c ) );
                target := functor_operation( q, source_target[2]( c ) );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( q, morphisms[1] ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( q, m ) );
                od;
                
                if HasIsMorphism( c ) and IsMorphism( c ) then
                    SetIsMorphism( Fc, true );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter0, filter_chm ],
              function( q, c )
                local d, degrees, l, source, target, morphisms, Fc, m;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( q, source_target[1]( c ) );
                target := functor_operation( q, source_target[2]( c ) );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( q, morphisms[1] ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( q, m ) );
                od;
                
                return Fc;
                
            end );
            
        fi;
        
    else
        
        if IsAdditiveFunctor( Functor ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter_chm ],
              function( c )
                local d, degrees, l, source, target, morphisms, Fc, m;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( source_target[1]( c ) );
                target := functor_operation( source_target[2]( c ) );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( morphisms[1] ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( m ) );
                od;
                
                if HasIsMorphism( c ) and IsMorphism( c ) then
                    SetIsMorphism( Fc, true );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter_chm ],
              function( c )
                local d, degrees, l, source, target, morphisms, Fc, m;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( source_target[1]( c ) );
                target := functor_operation( source_target[2]( c ) );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( morphisms[1] ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( m ) );
                od;
                
                return Fc;
                
            end );
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallFirstArgumentOfBivariateFunctorOnChainMorphisms,
  function( Functor, filter2_obj, filter1_chm, source_target, i )
    local functor_operation, filter0;
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter0, filter1_chm ],
              function( q, c )
                local R;
                
                R := StructureObject( c );
                
                return functor_operation( q, c, R );
                
            end );
            
        fi;
        
        if IsAdditiveFunctor( Functor, 1 ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter0, filter1_chm, filter2_obj ],
              function( q, c, o )
                local obj, d, degrees, l, source, target, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( q, source_target[1]( c ), obj );
                target := functor_operation( q, source_target[2]( c ), obj );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( q, morphisms[1], obj ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( q, m, obj ) );
                od;
                
                if HasIsMorphism( c ) and IsMorphism( c ) then
                    SetIsMorphism( Fc, true );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter0, filter1_chm, filter2_obj ],
              function( q, c, o )
                local obj, d, degrees, l, source, target, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( q, source_target[1]( c ), obj );
                target := functor_operation( q, source_target[2]( c ), obj );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( q, morphisms[1], obj ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( q, m, obj ) );
                od;
                
                return Fc;
                
            end );
            
        fi;
        
    else
        
        if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter1_chm ],
              function( c )
                local R;
                
                R := StructureObject( c );
                
                return functor_operation( c, R );
                
            end );
            
        fi;
        
        if IsAdditiveFunctor( Functor, 1 ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter1_chm, filter2_obj ],
              function( c, o )
                local obj, d, degrees, l, source, target, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( source_target[1]( c ), obj );
                target := functor_operation( source_target[2]( c ), obj );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( morphisms[1], obj ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( m, obj ) );
                od;
                
                if HasIsMorphism( c ) and IsMorphism( c ) then
                    SetIsMorphism( Fc, true );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter1_chm, filter2_obj ],
              function( c, o )
                local obj, d, degrees, l, source, target, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( source_target[1]( c ), obj );
                target := functor_operation( source_target[2]( c ), obj );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( morphisms[1], obj ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( m, obj ) );
                od;
                
                return Fc;
                
            end );
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallSecondArgumentOfBivariateFunctorOnChainMorphisms,
  function( Functor, filter1_obj, filter2_chm, source_target, i )
    local functor_operation, filter0;
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsAdditiveFunctor( Functor, 2 ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter0, filter1_obj, filter2_chm ],
              function( q, o, c )
                local obj, d, degrees, l, source, target, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( q, obj, source_target[1]( c ) );
                target := functor_operation( q, obj, source_target[2]( c ) );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( q, obj, morphisms[1] ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( q, obj, m ) );
                od;
                
                if HasIsMorphism( c ) and IsMorphism( c ) then
                    SetIsMorphism( Fc, true );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter0, filter1_obj, filter2_chm ],
              function( q, o, c )
                local obj, d, degrees, l, source, target, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( q, obj, source_target[1]( c ) );
                target := functor_operation( q, obj, source_target[2]( c ) );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( q, obj, morphisms[1] ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( q, obj, m ) );
                od;
                
                return Fc;
                
            end );
            
        fi;
        
    else
        
        if IsAdditiveFunctor( Functor, 2 ) = true then
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter1_obj, filter2_chm ],
              function( o, c )
                local obj, d, degrees, l, source, target, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( obj, source_target[1]( c ) );
                target := functor_operation( obj, source_target[2]( c ) );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( obj, morphisms[1] ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( obj, m ) );
                od;
                
                if HasIsMorphism( c ) and IsMorphism( c ) then
                    SetIsMorphism( Fc, true );
                fi;
                
                return Fc;
                
            end );
            
        else
            
            InstallOtherMethod( functor_operation,
                    "for homalg chain morphisms",
                    [ filter1_obj, filter2_chm ],
              function( o, c )
                local obj, d, degrees, l, source, target, morphisms, Fc, m;
                
                if IsHomalgStaticObject( o ) then ## the most probable case
                    obj := o;
                elif IsStructureObject( o ) then
                    if IsHomalgLeftObjectOrMorphismOfLeftObjects( c ) then
                        obj := AsLeftObject( o );
                    else
                        obj := AsRightObject( o );
                    fi;
                else
                    ## the default:
                    obj := o;
                fi;
                
                d := DegreeOfMorphism( c );
                
                degrees := DegreesOfChainMorphism( c );
                
                l := Length( degrees );
                
                source := functor_operation( obj, source_target[1]( c ) );
                target := functor_operation( obj, source_target[2]( c ) );
                
                morphisms := MorphismsOfChainMorphism( c );
                
                Fc := HomalgChainMorphism( functor_operation( obj, morphisms[1] ), source, target, [ degrees[1] + i * d, (-1)^i * d ] );
                
                for m in morphisms{[ 2 .. l ]} do
                    Add( Fc, functor_operation( obj, m ) );
                od;
                
                return Fc;
                
            end );
            
        fi;
        
    fi;
    
end );

##
InstallMethod( InstallFunctorOnChainMorphisms,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    local number_of_arguments, filter_chm,
          filter1_obj, filter1_chm, filter2_obj, filter2_chm,
          ar, i, chainmorphism, cochainmorphism, head;
    
    number_of_arguments := MultiplicityOfFunctor( Functor );
    
    if number_of_arguments = 1 then
        
        if not IsBound( Functor!.1[2] ) then
            Functor!.1[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.1[2][4] ) then
            return fail;
        fi;
        
        filter_chm := Functor!.1[2][4];
        
        if IsList( filter_chm ) and Length( filter_chm ) = 2 and ForAll( filter_chm, IsFilter ) then
            
            if IsCovariantFunctor( Functor ) = true then
                chainmorphism := [ [ Source, Range ], 0 ];
                cochainmorphism := [ [ Source, Range ], 0 ];
            else
                chainmorphism := [ [ Range, Source ], 1 ];
                cochainmorphism := [ [ Range, Source ], 1 ];
            fi;
            
            head := [ Functor ];
            
            chainmorphism := Concatenation( head, [ filter_chm[1] ], chainmorphism );
            cochainmorphism := Concatenation( head, [ filter_chm[2] ], cochainmorphism );
            
            CallFuncList( HelperToInstallUnivariateFunctorOnChainMorphisms, chainmorphism );
            CallFuncList( HelperToInstallUnivariateFunctorOnChainMorphisms, cochainmorphism );
            
        else
            
            Error( "wrong syntax: ", filter_chm, "\n" );
            
        fi;
        
    elif number_of_arguments = 2 then
        
        if not IsBound( Functor!.1[2] ) then
            Functor!.1[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.2[2] ) then
            Functor!.2[2] := HOMALG.FunctorOn;
        fi;
        
        if not IsBound( Functor!.1[2][1] ) or not IsBound( Functor!.2[2][1] ) or
           not IsBound( Functor!.1[2][4] ) or not IsBound( Functor!.2[2][4] ) then
            return fail;
        fi;
        
        filter1_obj := Functor!.1[2][1];
        filter1_chm := Functor!.1[2][4];
        
        filter2_obj := Functor!.2[2][1];
        filter2_chm := Functor!.2[2][4];
        
        if IsList( filter1_chm ) and Length( filter1_chm ) = 2 and ForAll( filter1_chm, IsFilter ) and
           IsList( filter2_chm ) and Length( filter2_chm ) = 2 and ForAll( filter2_chm, IsFilter ) then
            
            ar := [ [ filter2_obj, filter1_chm, HelperToInstallFirstArgumentOfBivariateFunctorOnChainMorphisms ],
                    [ filter1_obj, filter2_chm, HelperToInstallSecondArgumentOfBivariateFunctorOnChainMorphisms ] ];
            
            for i in [ 1 .. number_of_arguments ] do
                
                if IsCovariantFunctor( Functor, i ) = true then
                    chainmorphism := [ [ Source, Range ], 0 ];
                    cochainmorphism := [ [ Source, Range ], 0 ];
                else
                    chainmorphism := [ [ Range, Source ], 1 ];
                    cochainmorphism := [ [ Range, Source ], 1 ];
                fi;
                
                head := [ Functor, ar[i][1] ];
                
                chainmorphism := Concatenation( head, [ ar[i][2][1] ], chainmorphism );
                cochainmorphism := Concatenation( head, [ ar[i][2][2] ], cochainmorphism );
                
                CallFuncList( ar[i][3], chainmorphism );
                CallFuncList( ar[i][3], cochainmorphism );
                
            od;
            
        else
            
            Error( "wrong syntax: ", filter1_chm, filter2_chm, "\n" );
            
        fi;
        
    fi;
    
end );

##  <#GAPDoc Label="InstallFunctor">
##  <ManSection>
##    <Oper Arg="F" Name="InstallFunctor"/>
##    <Description>
##      Install several methods for &GAP; operations that get declared under the name of the &homalg; (multi-)functor
##      <A>F</A> (&see; <Ref Oper="NameOfFunctor"/>). These methods are used to apply the functor to objects, morphisms,
##      (co)complexes of objects, and (co)chain morphisms. The objects in the (co)complexes might again be (co)complexes.
##      <P/>
##      (For purely technical reasons the multiplicity of the functor might at most be three.
##       This restriction should disappear in future versions.)
##      <Listing Type="Code"><![CDATA[
InstallMethod( InstallFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    InstallFunctorOnObjects( Functor );
    
    if IsSpecialFunctor( Functor ) then
        
        InstallSpecialFunctorOnMorphisms( Functor );
        
    else
        
        InstallFunctorOnMorphisms( Functor );
        
        InstallFunctorOnComplexes( Functor );
        
        InstallFunctorOnChainMorphisms( Functor );
        
    fi;
    
end );
##  ]]></Listing>
##      The method does not return anything.
##    </Description>
##  </ManSection>
##  <#/GAPDoc>

##
InstallGlobalFunction( HelperToInstallUnivariateDeltaFunctor,
  function( Functor )
    local genesis, der, original_operation, functor_operation,
          filter0;
    
    genesis := Genesis( Functor );
    
    der := genesis[1];
    
    original_operation := OperationOfFunctor( genesis[2] );
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsAdditiveFunctor( Functor ) = true and genesis[3] = 1 then
            
            if der = "LeftDerivedFunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, E, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnM, Fn_1N, j_n, b_n, i_n_1;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnM := functor_operation( n, M );
                    Fn_1N := functor_operation( n - 1, N );
                    
                    j_n := CertainMorphism( d_psi, n );
                    b_n := CertainMorphism( dE, n );
                    i_n_1 := CertainMorphism( d_phi, n - 1 );
                    
                    j_n := original_operation( j_n );
                    b_n := original_operation( b_n );
                    i_n_1 := original_operation( i_n_1 );
                    
                    return ConnectingHomomorphism( FnM, j_n, b_n, i_n_1, Fn_1N );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, E, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n, M, "a" );
                    HN := functor_operation( n, N, "a" );
                    
                    delta := functor_operation( 1, E, "c" );
                    
                    c := HomalgChainMorphism( delta, HM, HN, [ 1, -1 ] );
                    
                    for j in [ 2 .. n ] do
                        
                        delta := functor_operation( j, E, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, E, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n, psi, "a" );
                    Hphi := functor_operation( n, phi, "a" );
                    
                    delta := functor_operation( n, E, "a" );
                    
                    T := HomalgComplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence ],
                  function( E )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n, E, "t" );
                    
                end );
                
            elif der = "RightDerivedCofunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, E, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnN, Fnp1M, i_n, b_np1, j_np1, b_n;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n + 1, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnN := functor_operation( n, N );
                    Fnp1M := functor_operation( n + 1, M );
                    
                    i_n := CertainMorphism( d_phi, n );
                    b_np1 := CertainMorphism( dE, n + 1 );
                    j_np1 := CertainMorphism( d_psi, n + 1 );
                    
                    i_n := original_operation( i_n );
                    b_n := original_operation( b_np1 );
                    j_np1 := original_operation( j_np1 );
                    
                    return ConnectingHomomorphism( FnN, i_n, b_n, j_np1, Fnp1M );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, E, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n + 1, M, "a" );
                    HN := functor_operation( n + 1, N, "a" );
                    
                    delta := functor_operation( 0, E, "c" );
                    
                    c := HomalgChainMorphism( delta, HN, HM, [ 0, 1 ] );
                    
                    for j in [ 1 .. n ] do
                        
                        delta := functor_operation( j, E, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, E, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n + 1, psi, "a" );
                    Hphi := functor_operation( n + 1, phi, "a" );
                    
                    delta := functor_operation( n, E, "a" );
                    
                    T := HomalgCocomplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence ],
                  function( E )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n - 1, E, "t" );
                    
                end );
                
            fi;
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallFirstArgumentOfBivariateDeltaFunctor,
  function( Functor )
    local genesis, der, original_operation, functor_operation,
          filter0;
    
    genesis := Genesis( Functor );
    
    der := genesis[1];
    
    original_operation := OperationOfFunctor( genesis[2] );
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
              function( n, E, s )
                local R;
                
                R := StructureObject( E );
                
                return functor_operation( n, E, R, s );
                
            end );
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence ],
              function( E )
                local R;
                
                R := StructureObject( E );
                
                return functor_operation( E, R );
                
            end );
            
        fi;
        
        if IsAdditiveFunctor( Functor, 1 ) = true and genesis[3] = 1 then
            
            if der = "LeftDerivedFunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnM, Fn_1N, j_n, b_n, i_n_1;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnM := functor_operation( n, M, o );
                    Fn_1N := functor_operation( n - 1, N, o );
                    
                    j_n := CertainMorphism( d_psi, n );
                    b_n := CertainMorphism( dE, n );
                    i_n_1 := CertainMorphism( d_phi, n - 1 );
                    
                    j_n := original_operation( j_n, o );
                    b_n := original_operation( b_n, o );
                    i_n_1 := original_operation( i_n_1, o );
                    
                    return ConnectingHomomorphism( FnM, j_n, b_n, i_n_1, Fn_1N );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n, M, o, "a" );
                    HN := functor_operation( n, N, o, "a" );
                    
                    delta := functor_operation( 1, E, o, "c" );
                    
                    c := HomalgChainMorphism( delta, HM, HN, [ 1, -1 ] );
                    
                    for j in [ 2 .. n ] do
                        
                        delta := functor_operation( j, E, o, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n, psi, o, "a" );
                    Hphi := functor_operation( n, phi, o, "a" );
                    
                    delta := functor_operation( n, E, o, "a" );
                    
                    T := HomalgComplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep ],
                  function( E, o )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n, E, o, "t" );
                    
                end );
                
            elif der = "RightDerivedCofunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnN, Fnp1M, i_n, b_np1, j_np1, b_n;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n + 1, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnN := functor_operation( n, N, o );
                    Fnp1M := functor_operation( n + 1, M, o );
                    
                    i_n := CertainMorphism( d_phi, n );
                    b_np1 := CertainMorphism( dE, n + 1 );
                    j_np1 := CertainMorphism( d_psi, n + 1 );
                    
                    i_n := original_operation( i_n, o );
                    b_n := original_operation( b_np1, o );
                    j_np1 := original_operation( j_np1, o );
                    
                    return ConnectingHomomorphism( FnN, i_n, b_n, j_np1, Fnp1M );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n + 1, M, o, "a" );
                    HN := functor_operation( n + 1, N, o, "a" );
                    
                    delta := functor_operation( 0, E, o, "c" );
                    
                    c := HomalgChainMorphism( delta, HN, HM, [ 0, 1 ] );
                    
                    for j in [ 1 .. n ] do
                        
                        delta := functor_operation( j, E, o, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n + 1, psi, o, "a" );
                    Hphi := functor_operation( n + 1, phi, o, "a" );
                    
                    delta := functor_operation( n, E, o, "a" );
                    
                    T := HomalgCocomplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep ],
                  function( E, o )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n - 1, E, o, "t" );
                    
                end );
                
            fi;
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallSecondArgumentOfBivariateDeltaFunctor,
  function( Functor )
    local genesis, der, covariant, original_operation, functor_operation,
          filter0;
    
    genesis := Genesis( Functor );
    
    der := genesis[1];
    
    original_operation := OperationOfFunctor( genesis[2] );
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsAdditiveFunctor( Functor, 2 ) = true and genesis[3] = 2 then
            
            if der = "LeftDerivedFunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o, E, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnM, Fn_1N, j_n, b_n, i_n_1;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnM := functor_operation( n, o, M );
                    Fn_1N := functor_operation( n - 1, o, N );
                    
                    j_n := CertainMorphism( d_psi, n );
                    b_n := CertainMorphism( dE, n );
                    i_n_1 := CertainMorphism( d_phi, n - 1 );
                    
                    j_n := original_operation( o, j_n );
                    b_n := original_operation( o, b_n );
                    i_n_1 := original_operation( o, i_n_1 );
                    
                    return ConnectingHomomorphism( FnM, j_n, b_n, i_n_1, Fn_1N );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o, E, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n, o, M, "a" );
                    HN := functor_operation( n, o, N, "a" );
                    
                    delta := functor_operation( 1, o, E, "c" );
                    
                    c := HomalgChainMorphism( delta, HM, HN, [ 1, -1 ] );
                    
                    for j in [ 2 .. n ] do
                        
                        delta := functor_operation( j, o, E, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o, E, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n, o, psi, "a" );
                    Hphi := functor_operation( n, o, phi, "a" );
                    
                    delta := functor_operation( n, o, E, "a" );
                    
                    T := HomalgComplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence ],
                  function( o, E )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n, o, E, "t" );
                    
                end );
                
            elif der = "RightDerivedCofunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o, E, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnN, Fnp1M, i_n, b_np1, j_np1, b_n;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n + 1, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnN := functor_operation( n, o, N );
                    Fnp1M := functor_operation( n + 1, o, M );
                    
                    i_n := CertainMorphism( d_phi, n );
                    b_np1 := CertainMorphism( dE, n + 1 );
                    j_np1 := CertainMorphism( d_psi, n + 1 );
                    
                    i_n := original_operation( o, i_n );
                    b_n := original_operation( o, b_np1 );
                    j_np1 := original_operation( o, j_np1 );
                    
                    return ConnectingHomomorphism( FnN, i_n, b_n, j_np1, Fnp1M );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o, E, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n + 1, o, M, "a" );
                    HN := functor_operation( n + 1, o, N, "a" );
                    
                    delta := functor_operation( 0, o, E, "c" );
                    
                    c := HomalgChainMorphism( delta, HN, HM, [ 0, 1 ] );
                    
                    for j in [ 1 .. n ] do
                        
                        delta := functor_operation( j, o, E, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o, E, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n + 1, o, psi, "a" );
                    Hphi := functor_operation( n + 1, o, phi, "a" );
                    
                    delta := functor_operation( n, o, E, "a" );
                    
                    T := HomalgCocomplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence ],
                  function( o, E )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n - 1, o, E, "t" );
                    
                end );
                
            fi;
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallFirstArgumentOfTrivariateDeltaFunctor,
  function( Functor )
    local genesis, der, original_operation, functor_operation,
          filter0;
    
    genesis := Genesis( Functor );
    
    der := genesis[1];
    
    original_operation := OperationOfFunctor( genesis[2] );
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsDistinguishedFirstArgumentOfFunctor( Functor ) then
            
            InstallOtherMethod( functor_operation,
                    "for homalg complexes",
                    [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
              function( n, E, s )
                local R;
                
                R := StructureObject( E );
                
                return functor_operation( n, E, R, R, s );
                
            end );
            
        fi;
        
        if IsAdditiveFunctor( Functor, 1 ) = true and genesis[3] = 1 then
            
            if der = "LeftDerivedFunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o2, o3, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnM, Fn_1N, j_n, b_n, i_n_1;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnM := functor_operation( n, M, o2, o3 );
                    Fn_1N := functor_operation( n - 1, N, o2, o3 );
                    
                    j_n := CertainMorphism( d_psi, n );
                    b_n := CertainMorphism( dE, n );
                    i_n_1 := CertainMorphism( d_phi, n - 1 );
                    
                    j_n := original_operation( j_n, o2, o3 );
                    b_n := original_operation( b_n, o2, o3 );
                    i_n_1 := original_operation( i_n_1, o2, o3 );
                    
                    return ConnectingHomomorphism( FnM, j_n, b_n, i_n_1, Fn_1N );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o2, o3, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n, M, o2, o3, "a" );
                    HN := functor_operation( n, N, o2, o3, "a" );
                    
                    delta := functor_operation( 1, E, o2, o3, "c" );
                    
                    c := HomalgChainMorphism( delta, HM, HN, [ 1, -1 ] );
                    
                    for j in [ 2 .. n ] do
                        
                        delta := functor_operation( j, E, o2, o3, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o2, o3, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n, psi, o2, o3, "a" );
                    Hphi := functor_operation( n, phi, o2, o3, "a" );
                    
                    delta := functor_operation( n, E, o2, o3, "a" );
                    
                    T := HomalgComplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep ],
                  function( E, o2, o3 )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n, E, o2, o3, "t" );
                    
                end );
                
            elif der = "RightDerivedCofunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o2, o3, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnN, Fnp1M, i_n, b_np1, j_np1, b_n;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n + 1, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnN := functor_operation( n, N, o2, o3 );
                    Fnp1M := functor_operation( n + 1, M, o2, o3 );
                    
                    i_n := CertainMorphism( d_phi, n );
                    b_np1 := CertainMorphism( dE, n + 1 );
                    j_np1 := CertainMorphism( d_psi, n + 1 );
                    
                    i_n := original_operation( i_n, o2, o3 );
                    b_n := original_operation( b_np1, o2, o3 );
                    j_np1 := original_operation( j_np1, o2, o3 );
                    
                    return ConnectingHomomorphism( FnN, i_n, b_n, j_np1, Fnp1M );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o2, o3, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n + 1, M, o2, o3, "a" );
                    HN := functor_operation( n + 1, N, o2, o3, "a" );
                    
                    delta := functor_operation( 0, E, o2, o3, "c" );
                    
                    c := HomalgChainMorphism( delta, HN, HM, [ 0, 1 ] );
                    
                    for j in [ 1 .. n ] do
                        
                        delta := functor_operation( j, E, o2, o3, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, E, o2, o3, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n + 1, psi, o2, o3, "a" );
                    Hphi := functor_operation( n + 1, phi, o2, o3, "a" );
                    
                    delta := functor_operation( n, E, o2, o3, "a" );
                    
                    T := HomalgCocomplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep ],
                  function( E, o2, o3 )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n - 1, E, o2, o3, "t" );
                    
                end );
                
            fi;
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallSecondArgumentOfTrivariateDeltaFunctor,
  function( Functor )
    local genesis, der, covariant, original_operation, functor_operation,
          filter0;
    
    genesis := Genesis( Functor );
    
    der := genesis[1];
    
    original_operation := OperationOfFunctor( genesis[2] );
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsAdditiveFunctor( Functor, 2 ) = true and genesis[3] = 2 then
            
            if der = "LeftDerivedFunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, o1, E, o3, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnM, Fn_1N, j_n, b_n, i_n_1;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnM := functor_operation( n, o1, M, o3 );
                    Fn_1N := functor_operation( n - 1, o1, N, o3 );
                    
                    j_n := CertainMorphism( d_psi, n );
                    b_n := CertainMorphism( dE, n );
                    i_n_1 := CertainMorphism( d_phi, n - 1 );
                    
                    j_n := original_operation( o1, j_n, o3 );
                    b_n := original_operation( o1, b_n, o3 );
                    i_n_1 := original_operation( o1, i_n_1, o3 );
                    
                    return ConnectingHomomorphism( FnM, j_n, b_n, i_n_1, Fn_1N );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, o1, E, o3, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n, o1, M, o3, "a" );
                    HN := functor_operation( n, o1, N, o3, "a" );
                    
                    delta := functor_operation( 1, o1, E, o3, "c" );
                    
                    c := HomalgChainMorphism( delta, HM, HN, [ 1, -1 ] );
                    
                    for j in [ 2 .. n ] do
                        
                        delta := functor_operation( j, o1, E, o3, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, o1, E, o3, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n, o1, psi, o3, "a" );
                    Hphi := functor_operation( n, o1, phi, o3, "a" );
                    
                    delta := functor_operation( n, o1, E, o3, "a" );
                    
                    T := HomalgComplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep ],
                  function( o1, E, o3 )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n, o1, E, o3, "t" );
                    
                end );
                
            elif der = "RightDerivedCofunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, o1, E, o3, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnN, Fnp1M, i_n, b_np1, j_np1, b_n;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n + 1, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnN := functor_operation( n, o1, N, o3 );
                    Fnp1M := functor_operation( n + 1, o1, M, o3 );
                    
                    i_n := CertainMorphism( d_phi, n );
                    b_np1 := CertainMorphism( dE, n + 1 );
                    j_np1 := CertainMorphism( d_psi, n + 1 );
                    
                    i_n := original_operation( o1, i_n, o3 );
                    b_n := original_operation( o1, b_np1, o3 );
                    j_np1 := original_operation( o1, j_np1, o3 );
                    
                    return ConnectingHomomorphism( FnN, i_n, b_n, j_np1, Fnp1M );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, o1, E, o3, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n + 1, o1, M, o3, "a" );
                    HN := functor_operation( n + 1, o1, N, o3, "a" );
                    
                    delta := functor_operation( 0, o1, E, o3, "c" );
                    
                    c := HomalgChainMorphism( delta, HN, HM, [ 0, 1 ] );
                    
                    for j in [ 1 .. n ] do
                        
                        delta := functor_operation( j, o1, E, o3, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
                  function( n, o1, E, o3, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n + 1, o1, psi, o3, "a" );
                    Hphi := functor_operation( n + 1, o1, phi, o3, "a" );
                    
                    delta := functor_operation( n, o1, E, o3, "a" );
                    
                    T := HomalgCocomplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsStructureObjectOrFinitelyPresentedObjectRep ],
                  function( o1, E, o3 )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n - 1, o1, E, o3, "t" );
                    
                end );
                
            fi;
            
        fi;
        
    fi;
    
end );

##
InstallGlobalFunction( HelperToInstallThirdArgumentOfTrivariateDeltaFunctor,
  function( Functor )
    local genesis, der, covariant, original_operation, functor_operation,
          filter0;
    
    genesis := Genesis( Functor );
    
    der := genesis[1];
    
    original_operation := OperationOfFunctor( genesis[2] );
    
    functor_operation := OperationOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) and IsList( Functor!.0 ) then
        
        if Length( Functor!.0 ) = 1 then
            filter0 := Functor!.0[1];
        else
            filter0 := IsList;
        fi;
        
        if IsAdditiveFunctor( Functor, 3 ) = true and genesis[3] = 3 then
            
            if der = "LeftDerivedFunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o1, o2, E, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnM, Fn_1N, j_n, b_n, i_n_1;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnM := functor_operation( n, o1, o2, M );
                    Fn_1N := functor_operation( n - 1, o1, o2, N );
                    
                    j_n := CertainMorphism( d_psi, n );
                    b_n := CertainMorphism( dE, n );
                    i_n_1 := CertainMorphism( d_phi, n - 1 );
                    
                    j_n := original_operation( o1, o2, j_n );
                    b_n := original_operation( o1, o2, b_n );
                    i_n_1 := original_operation( o1, o2, i_n_1 );
                    
                    return ConnectingHomomorphism( FnM, j_n, b_n, i_n_1, Fn_1N );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o1, o2, E, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n, o1, o2, M, "a" );
                    HN := functor_operation( n, o1, o2, N, "a" );
                    
                    delta := functor_operation( 1, o1, o2, E, "c" );
                    
                    c := HomalgChainMorphism( delta, HM, HN, [ 1, -1 ] );
                    
                    for j in [ 2 .. n ] do
                        
                        delta := functor_operation( j, o1, o2, E, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o1, o2, E, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n, o1, o2, psi, "a" );
                    Hphi := functor_operation( n, o1, o2, phi, "a" );
                    
                    delta := functor_operation( n, o1, o2, E, "a" );
                    
                    T := HomalgComplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence ],
                  function( o1, o2, E )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n, o1, o2, E, "t" );
                    
                end );
                
            elif der = "RightDerivedCofunctor" then
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o1, o2, E, s )
                    local M, N, horse_shoe, d_psi, d_phi, dE, FnN, Fnp1M, i_n, b_np1, j_np1, b_n;
                    
                    if s <> "c" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    horse_shoe := Resolution( n + 1, E );
                    
                    d_psi := LowestDegreeMorphism( horse_shoe );
                    d_phi := HighestDegreeMorphism( horse_shoe );
                    
                    dE := Source( d_psi );
                    
                    FnN := functor_operation( n, o1, o2, N );
                    Fnp1M := functor_operation( n + 1, o1, o2, M );
                    
                    i_n := CertainMorphism( d_phi, n );
                    b_np1 := CertainMorphism( dE, n + 1 );
                    j_np1 := CertainMorphism( d_psi, n + 1 );
                    
                    i_n := original_operation( o1, o2, i_n );
                    b_n := original_operation( o1, o2, b_np1 );
                    j_np1 := original_operation( o1, o2, j_np1 );
                    
                    return ConnectingHomomorphism( FnN, i_n, b_n, j_np1, Fnp1M );
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o1, o2, E, s )
                    local M, N, HM, HN, delta, c, j;
                    
                    if s <> "a" then
                        TryNextMethod( );
                    fi;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    HM := functor_operation( n + 1, o1, o2, M, "a" );
                    HN := functor_operation( n + 1, o1, o2, N, "a" );
                    
                    delta := functor_operation( 0, o1, o2, E, "c" );
                    
                    c := HomalgChainMorphism( delta, HN, HM, [ 0, 1 ] );
                    
                    for j in [ 1 .. n ] do
                        
                        delta := functor_operation( j, o1, o2, E, "c" );
                        
                        Add( c, delta );
                        
                    od;
                    
                    SetIsMorphism( c, true );
                    
                    return c;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence, IsString ],
                  function( n, o1, o2, E, s )
                    local psi, phi, Hpsi, Hphi, delta, T;
                    
                    if s <> "t" then
                        TryNextMethod( );
                    fi;
                    
                    psi := LowestDegreeMorphism( E );
                    phi := HighestDegreeMorphism( E );
                    
                    Hpsi := functor_operation( n + 1, o1, o2, psi, "a" );
                    Hphi := functor_operation( n + 1, o1, o2, phi, "a" );
                    
                    delta := functor_operation( n, o1, o2, E, "a" );
                    
                    T := HomalgCocomplex( Hpsi );
                    Add( T, Hphi );
                    Add( T, delta );
                    
                    SetIsExactTriangle( T, true );
                    
                    return T;
                    
                end );
                
                InstallOtherMethod( functor_operation,
                        "for homalg complexes",
                        [ IsStructureObjectOrFinitelyPresentedObjectRep, IsStructureObjectOrFinitelyPresentedObjectRep, IsComplexOfFinitelyPresentedObjectsRep and IsShortExactSequence ],
                  function( o1, o2, E )
                    local M, N, n, psi, phi, Hpsi, Hphi, delta, T;
                    
                    M := LowestDegreeObject( E );
                    N := HighestDegreeObject( E );
                    
                    n := Maximum( List( [ M, N ], LengthOfResolution ) );
                    
                    return functor_operation( n - 1, o1, o2, E, "t" );
                    
                end );
                
            fi;
            
        fi;
        
    fi;
    
end );

##  <#GAPDoc Label="InstallDeltaFunctor">
##  <ManSection>
##    <Oper Arg="F" Name="InstallDeltaFunctor"/>
##    <Description>
##      In case <A>F</A> is a <M>\delta</M>-functor in the sense of Grothendieck the procedure installs several
##      operations under the name of the &homalg; (multi-)functor <A>F</A> (&see; <Ref Oper="NameOfFunctor"/>)
##      allowing one to compute connecting homomorphisms, exact triangles, and associated long exact sequences.
##      The input of these operations is a short exact sequence.
##      <P/>
##      (For purely technical reasons the multiplicity of the functor might at most be three.
##       This restriction should disappear in future versions.)
##      <Listing Type="Code"><![CDATA[
InstallMethod( InstallDeltaFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    local number_of_arguments;
    
    number_of_arguments := MultiplicityOfFunctor( Functor );
    
    if number_of_arguments = 1 then
        
        HelperToInstallUnivariateDeltaFunctor( Functor );
        
    elif number_of_arguments = 2 then
        
        HelperToInstallFirstArgumentOfBivariateDeltaFunctor( Functor );
        HelperToInstallSecondArgumentOfBivariateDeltaFunctor( Functor );
        
    elif number_of_arguments = 3 then
        
        HelperToInstallFirstArgumentOfTrivariateDeltaFunctor( Functor );
        HelperToInstallSecondArgumentOfTrivariateDeltaFunctor( Functor );
        HelperToInstallThirdArgumentOfTrivariateDeltaFunctor( Functor );
        
    fi;
    
end );
##  ]]></Listing>
##      The method does not return anything.
##    </Description>
##  </ManSection>
##  <#/GAPDoc>

##
InstallGlobalFunction( CallOperationFromCategory,
  function( name, args )
    local M, category;
    
    M := First( args, IsStructureObjectOrObjectOrMorphism );
    
    if M = fail then
        Error( "no argument points to a category\n" );
    fi;
    
    category := HomalgCategory( M );
    
    if not IsBound( category!.(name) ) then
        Error( "there is no component called ", name, " in the category record" );
    elif not IsFunction( category!.(name) ) then
        Error( "the component called ", name, " in the category record is not a function" );
    fi;
    
    return CallFuncList( category!.(name), args );
    
end );

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

##  <#GAPDoc Label="CreateHomalgFunctor">
##  <ManSection>
##    <Func Arg="list1, list2, ..." Name="CreateHomalgFunctor" Label="constructor for functors"/>
##    <Returns>a &homalg; functor</Returns>
##    <Description>
##      This constructor is used to create functors for &homalg; from scratch. <A>listN</A> is of the form
##      <A>listN = [ stringN, valueN ]</A>. <A>stringN</A> will be the name of a component of the created functor and
##      <A>valueN</A> will be its value. This constructor is listed here for the sake of completeness.
##      Its documentation is rather better placed in a &homalg; programmers guide. The remaining constructors
##      create new functors out of existing ones and are probably more interesting for end users.
##      <P/>
##      The constructor does <E>not</E> invoke <Ref Oper="InstallFunctor"/>. This has to be done manually!
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallGlobalFunction( CreateHomalgFunctor,
  function( arg )
    local ar, functor, type;
    
    functor := rec( );
    
    for ar in arg do
        if not IsString( ar ) and IsList( ar ) and Length( ar ) = 2 and IsString( ar[1] ) then
            functor.( ar[1] ) := ar[2];
        fi;
    od;
    
    type := TheTypeHomalgFunctor;
    
    ## Objectify:
    Objectify( type, functor );
    
    SetGenesis( functor, Concatenation( [ "CreateHomalgFunctor" ], arg ) );
    
    return functor;
    
end );

##  <#GAPDoc Label="InsertObjectInMultiFunctor">
##  <ManSection>
##    <Oper Arg="F, p, obj, H" Name="InsertObjectInMultiFunctor" Label="constructor for functors given a multi-functor and an object"/>
##    <Returns>a &homalg; functor</Returns>
##    <Description>
##      Given a &homalg; multi-functor <A>F</A> with multiplicity <M>m</M> and a string <A>H</A> return the functor
##      <C>Functor_</C><A>H</A> <M>:=</M> <A>F</A><M>(...,</M><A>obj</A><M>,...)</M>, where <A>obj</A> is inserted at
##      the <A>p</A>-th position. Of course <A>obj</A> must be an object (e.g. ring, module, ...) that can be inserted
##      at this particular position. The string <A>H</A> becomes the name of the returned functor
##      (&see; <Ref Oper="NameOfFunctor"/>). The variable <C>Functor_</C><A>H</A> will automatically be assigned if free,
##      otherwise a warning is issued.
##      <P/>
##      The constructor automatically invokes <Ref Oper="InstallFunctor"/> which installs several necessary operations
##      under the name <A>H</A>.
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );
##  Z
##  gap> zz * 1;
##  <The free right module of rank 1 on a free generator>
##  gap> InsertObjectInMultiFunctor( Functor_Hom_for_fp_modules, 2, zz * 1, "Hom_ZZ" );
##  <The functor Hom_ZZ for f.p. modules and their maps over computable rings>
##  gap> Functor_Hom_ZZ_for_fp_modules; ## got automatically defined
##  <The functor Hom_ZZ for f.p. modules and their maps over computable rings>
##  gap> Hom_ZZ; ## got automatically defined
##  <Operation "Hom_ZZ">
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( InsertObjectInMultiFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsString, IsString ],
        
  function( Functor, p, o, name, operation )
    local m, functor_name, functor_operation, functor_data, data, i, Fp, fname;
    
    m := MultiplicityOfFunctor( Functor );
    
    if p < 1 then
        Error( "the second argument must be a positive integer\n" );
    elif p > m then
        Error( "the second argument exceeded the multiplicity of the functor\n" );
    fi;
    
    functor_name := NameOfFunctor( Functor );
    
    functor_operation := OperationOfFunctor( Functor );
    
    if m = 1 then
        return functor_operation( o );
    fi;
    
    functor_data := List( [ 1 .. m ], i -> StructuralCopy( Functor!.(i) ) );
    
    if IsBound( Functor!.0 ) then
        data := [ [ "0", Functor!.0 ] ];
    else
        data := [ ];
    fi;
    
    for i in [ 1 .. m ] do
        if i < p then
            Add( data, [ String(i), functor_data[i] ] );
        elif i > p then
            Add( data, [ String(i - 1), functor_data[i] ] );
        fi;
    od;
    
    data := Concatenation(
                    [ [ "name", name ],
                      [ "category", CategoryOfFunctor( Functor ) ],
                      [ "operation", operation ],
                      [ "number_of_arguments", m - 1 ] ],
                    data );
    
    Fp := CallFuncList( CreateHomalgFunctor, data );
    
    SetGenesis( Fp, [ "InsertObjectInMultiFunctor", Functor, p, o ] );
    
    if m > 1 then
        Fp!.ContainerForWeakPointersOnComputedBasicObjects :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
        Fp!.ContainerForWeakPointersOnComputedBasicMorphisms :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
    fi;
    
    if IsBoundGlobal( operation ) then
        if not IsOperation( ValueGlobal( operation ) ) then
            Error( operation, " is bound but is not an operation\n" );
        fi;
    else
        ## it is only important to declare and almost regardless how
        DeclareOperation( operation, [ IsHomalgObjectOrMorphism ] );
    fi;
    
    InstallFunctor( Fp );
    
    fname := Concatenation( [ "Functor_", name, ShortDescriptionOfCategory( Functor ) ] );
    
    ConvertToStringRep( fname );
    
    if IsBoundGlobal( fname ) then
        Info( InfoWarning, 1, "unable to save the specialized functor under the default name ", fname, " since it is reserved" );
    else
        BindGlobal( fname, Fp );
    fi;
    
    Fp!.GlobalName := fname;
    
    return Fp;
    
end );

##
InstallMethod( InsertObjectInMultiFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsInt, IsStructureObjectOrFinitelyPresentedObjectRep, IsString ],
        
  function( Functor, p, o, name )
    
    return InsertObjectInMultiFunctor( Functor, p, o, name, name );
    
end );

##  <#GAPDoc Label="ComposeFunctors">
##  <ManSection>
##    <Oper Arg="F[, p], G[, H]" Name="ComposeFunctors" Label="constructor for functors given two functors"/>
##    <Returns>a &homalg; functor</Returns>
##    <Description>
##      Given two &homalg; (multi-)functors <A>F</A> and <A>G</A> and a string <A>H</A> return the composed functor
##      <C>Functor_</C><A>H</A> <M>:=</M> <A>F</A><M>(...,</M><A>G</A><M>(...),...)</M>, where <A>G</A> is inserted at
##      the <A>p</A>-th position. Of course <A>G</A> must be a functor that can be inserted
##      at this particular position. The string <A>H</A> becomes the name of the returned functor
##      (&see; <Ref Oper="NameOfFunctor"/>). The variable <C>Functor_</C><A>H</A> will automatically be assigned if free,
##      otherwise a warning is issued.
##      <P/>
##      If <A>p</A> is not specified it is assumed <M>1</M>. If the string <A>H</A> is not specified the names
##      of <A>F</A> and <A>G</A> are concatenated in this order (&see; <Ref Oper="NameOfFunctor"/>).
##      <P/>
##      <A>F</A> * <A>G</A> is a shortcut for <C>ComposeFunctors</C>(<A>F</A>,1,<A>G</A>).
##      <P/>
##      The constructor automatically invokes <Ref Oper="InstallFunctor"/> which installs several necessary operations
##      under the name <A>H</A>.
##      <P/>
##      Check this:
##      <Example><![CDATA[
##  gap> Functor_Hom_for_fp_modules * Functor_TensorProduct_for_fp_modules;
##  <The functor HomTensorProduct for f.p. modules and their maps over computable \
##  rings>
##  gap> Functor_HomTensorProduct_for_fp_modules; ## got automatically defined
##  <The functor HomTensorProduct for f.p. modules and their maps over computable \
##  rings>
##  gap> HomTensorProduct; ## got automatically defined
##  <Operation "HomTensorProduct">
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( ComposeFunctors,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsInt, IsHomalgFunctorRep, IsString, IsString ],
        
  function( Functor_post, p, Functor_pre, name, operation )
    local m_post, m_pre, data_post, data_pre, m, data, i, d, property, fname,
          GF;
    
    if p < 1 then
        Error( "the second argument must be a positive integer\n" );
    fi;
    
    if IsBound( Functor_post!.0 ) or IsBound(  Functor_pre!.0 ) then
        Error( "ComposeFunctors does not support functors with a zero-th argument yet\n" );
    fi;
    
    m_post := MultiplicityOfFunctor( Functor_post );
    m_pre := MultiplicityOfFunctor( Functor_pre );
    
    data_post := List( [ 1 .. m_post ], i -> StructuralCopy( Functor_post!.(i) ) );
    data_pre := List( [ 1 .. m_pre ], i -> StructuralCopy( Functor_pre!.(i) ) );
    
    m := m_post + m_pre - 1;
    
    data := [ ];
    
    for i in [ 1 .. m ] do
        if i < p then
            Add( data, [ String(i), data_post[i] ] );
        elif i > p + m_pre - 1 then
            Add( data, [ String(i), data_post[i - m_pre + 1] ] );
        else
            d := [ ];
            if IsCovariantFunctor( Functor_post, p ) = true and
               IsCovariantFunctor( Functor_pre, i - p + 1 ) = true then
                property := "covariant";
            elif IsCovariantFunctor( Functor_post, p ) = true and
              IsCovariantFunctor( Functor_pre, i - p + 1 ) = false then
                property := "contravariant";
            elif IsCovariantFunctor( Functor_post, p ) = false and
              IsCovariantFunctor( Functor_pre, i - p + 1 ) = true then
                property := "contravariant";
            elif IsCovariantFunctor( Functor_post, p ) = false and
              IsCovariantFunctor( Functor_pre, i - p + 1 ) = false then
                property := "covariant";
            fi;
            if IsBound( property ) then
                Add( d, property );
            fi;
            if IsAdditiveFunctor( Functor_post, p ) and
               IsAdditiveFunctor( Functor_pre, i - p + 1 ) then
                Add( d, "additive" );
            fi;
            if IsDistinguishedArgumentOfFunctor( Functor_post, p ) and
               IsDistinguishedArgumentOfFunctor( Functor_pre, i - p + 1 ) then
                Add( d, "distinguished" );
            fi;
            Add( data, [ String(i), [ d, data_pre[i - p + 1][2] ] ] );
        fi;
    od;
    
    data := Concatenation(
                    [ [ "name", name ],
                      [ "category", CategoryOfFunctor( Functor_pre ) ],
                      [ "operation", operation ],
                      [ "number_of_arguments", m ] ],
                    data );
    
    GF := CallFuncList( CreateHomalgFunctor, data );
    
    SetGenesis( GF, [ "ComposeFunctors", [ Functor_post, Functor_pre ], p ] );
    
    if m > 1 then
        GF!.ContainerForWeakPointersOnComputedBasicObjects :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
        GF!.ContainerForWeakPointersOnComputedBasicMorphisms :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
    fi;
    
    if IsBoundGlobal( operation ) then
        if not IsOperation( ValueGlobal( operation ) ) then
            Error( operation, " is bound but is not an operation\n" );
        fi;
    else
        ## it is only important to declare and almost regardless how
        DeclareOperation( operation, [ IsHomalgObjectOrMorphism ] );
    fi;
    
    InstallFunctor( GF );
    
    fname := Concatenation( [ "Functor_", name, ShortDescriptionOfCategory( Functor_pre ) ] );
    
    ConvertToStringRep( fname );
    
    if IsBoundGlobal( fname ) then
        Info( InfoWarning, 1, "unable to save the composed functor under the default name ", fname, " since it is reserved" );
    else
        BindGlobal( fname, GF );
    fi;
    
    GF!.GlobalName := fname;
    
    return GF;
    
end );

##
InstallMethod( ComposeFunctors,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsInt, IsHomalgFunctorRep ],
        
  function( Functor_post, p, Functor_pre )
    local name;
    
    if p = 1 then
        name := Concatenation( NameOfFunctor( Functor_post ), NameOfFunctor( Functor_pre ) );
    else
        name := Concatenation( NameOfFunctor( Functor_post ), String( p ), NameOfFunctor( Functor_pre ) );
    fi;
    
    return ComposeFunctors( Functor_post, p, Functor_pre, name );
    
end );

##
InstallMethod( ComposeFunctors,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsHomalgFunctorRep, IsString, IsString ],
        
  function( Functor_post, Functor_pre, name, operation )
    
    return ComposeFunctors( Functor_post, 1, Functor_pre, name, operation );
    
end );

##
InstallMethod( ComposeFunctors,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsHomalgFunctorRep, IsString ],
        
  function( Functor_post, Functor_pre, name )
    
    return ComposeFunctors( Functor_post, Functor_pre, name, name );
    
end );

##
InstallMethod( ComposeFunctors,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsInt, IsHomalgFunctorRep, IsString ],
        
  function( Functor_post, p, Functor_pre, name )
    
    return ComposeFunctors( Functor_post, p, Functor_pre, name, name );
    
end );

##
InstallMethod( ComposeFunctors,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsHomalgFunctorRep ],
        
  function( Functor_post, Functor_pre )
    
    return ComposeFunctors( Functor_post, 1, Functor_pre );
    
end );

##
InstallMethod( \*,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsHomalgFunctorRep ],
        
  function( Functor_post, Functor_pre )
    
    return ComposeFunctors( Functor_post, Functor_pre );
    
end );

##  <#GAPDoc Label="RightSatelliteOfCofunctor">
##  <ManSection>
##    <Oper Arg="F[, p][, H]" Name="RightSatelliteOfCofunctor" Label="constructor of the right satellite of a contravariant functor"/>
##    <Returns>a &homalg; functor</Returns>
##    <Description>
##      Given a &homalg; (multi-)functor <A>F</A> and a string <A>H</A> return the right satellite of
##      <A>F</A> with respect to its <A>p</A>-th argument. <A>F</A> is assumed contravariant in its <A>p</A>-th argument.
##      The string <A>H</A> becomes the name of the returned functor (&see; <Ref Oper="NameOfFunctor"/>).
##      The variable <C>Functor_</C><A>H</A> will automatically be assigned if free, otherwise a warning is issued.
##      <P/>
##      If <A>p</A> is not specified it is assumed <M>1</M>. If the string <A>H</A> is not specified the
##      letter 'S' is added to the left of the name of <A>F</A> (&see; <Ref Oper="NameOfFunctor"/>).
##      <P/>
##      The constructor automatically invokes <Ref Oper="InstallFunctor"/> which installs several necessary operations
##      under the name <A>H</A>.
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( RightSatelliteOfCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt, IsString, IsString ],
        
  function( Functor, p, name, operation )
    local functor_name, functor_operation, _Functor_OnObjects, _Functor_OnMorphisms,
          m, z, data, i, SF, fname;
    
    if IsCovariantFunctor( Functor, p ) <> false then
        Error( "the functor does not seem to be contravariant in its ", p, ". argument\n" );
    fi;
    
    functor_name :=  NameOfFunctor( Functor );
    
    functor_operation := OperationOfFunctor( Functor );
    
    _Functor_OnObjects :=
      function( arg )
        local c, mu, ar, F_mu, sat;
        
        c := arg[1];
        
        if c < 0 then
            Error( "the negative ", c, ". right satellite is not defined\n" );
        fi;
        
        mu := SyzygiesObjectEmb( c, arg[p + 1] );
        
        ar := Concatenation( arg{[ 2 .. p ]}, [ mu ], arg{[ p + 2 .. Length( arg ) ]} );
        
        F_mu := CallFuncList( functor_operation, ar );
        
        sat := Cokernel( F_mu );
        
        SetAsCokernel( sat, F_mu );
        
        return sat;
        
    end;
    
    _Functor_OnMorphisms :=
      function( F_source, F_target, arg_before_pos, phi, arg_behind_pos )
        local arg, c, d, d_c_1, mu, ar, hull_phi, emb_source, emb_target;
        
        arg := Concatenation( arg_before_pos, [ phi ], arg_behind_pos );
        
        c := arg[1];
        
        if c < 0 then
            Error( "the negative ", c, ". right satellite is not defined\n" );
        fi;
        
        if c - 1 > -1 then
            d := Resolution( c - 1, arg[p + 1] );
        else
            d := Resolution( 0, arg[p + 1] );
        fi;
        
        if IsHomalgStaticMorphism( arg[p + 1] ) then
            if c = 0 then
                mu := arg[p + 1];
            else
                d_c_1 := CertainMorphismAsKernelSquare( d, c - 1 );
                mu := Kernel( d_c_1 );
            fi;
        else
            ## the following is not really mu but Source( mu ):
            mu := SyzygiesObject( c, arg[p + 1] );
        fi;
        
        ar := Concatenation( arg{[ 2 .. p ]}, [ mu ], arg{[ p + 2 .. Length( arg ) ]} );
        
        hull_phi := CallFuncList( functor_operation, ar );
        
        emb_source := NaturalGeneralizedEmbedding( F_source );
        emb_target := NaturalGeneralizedEmbedding( F_target );
        
        return CompleteImageSquare( emb_source, hull_phi, emb_target );
        
        ## HasIsIsomorphism( phi ) and IsIsomorphism( phi ), resp.
        ## HasIsMorphism( phi ) and IsMorphism( phi ), and
        ## UpdateObjectsByMorphism( mor )
        ## will be taken care of in FunctorMor
        
    end;
    
    m := MultiplicityOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) then
        if IsList( Functor!.0 ) then
            z := Concatenation( [ IsInt ], Functor!.0 );
        else
            Error( "the zeroth argument of the functor is not a list" );
        fi;
    else
        z := [ IsInt ];
    fi;
    
    data := List( [ 1 .. m ], i -> [ String( i ), StructuralCopy( Functor!.(String( i )) ) ] );
    
    for i in [ 1 .. m ] do
        if IsBound( data[i][2] ) and IsBound( data[i][2][1] ) and IsBound( data[i][2][1][2] ) and
           data[i][2][1][2] in [ "left exact", "right exact", "right adjoint", "left adjoint" ] then
            data[i][2][1][2] := "additive";
            if i = p or functor_name = "Hom" then
                Add( data[i][2][1], "delta-functor", 3 );
                Add( data[i][2][1], "effaceable", 4 );
            fi;
        fi;
    od;
    
    data := Concatenation(
                    [ [ "name", name ],
                      [ "category", CategoryOfFunctor( Functor ) ],
                      [ "operation", operation ],
                      [ "number_of_arguments", m ] ],
                    [ [ "0", z ] ],
                    data,
                    [ [ "OnObjects", _Functor_OnObjects ] ],
                    [ [ "OnMorphisms", _Functor_OnMorphisms ] ] );
    
    SF := CallFuncList( CreateHomalgFunctor, data );
    
    SetGenesis( SF, [ "RightSatelliteOfCofunctor", Functor, p ] );
    
    if m > 1 then
        SF!.ContainerForWeakPointersOnComputedBasicObjects :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
        SF!.ContainerForWeakPointersOnComputedBasicMorphisms :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
    fi;
    
    if IsBoundGlobal( operation ) then
        if not IsOperation( ValueGlobal( operation ) ) then
            Error( operation, " is bound but is not an operation\n" );
        fi;
    else
        ## it is only important to declare and almost regardless how
        DeclareOperation( operation, [ IsHomalgObjectOrMorphism ] );
    fi;
    
    InstallFunctor( SF );
    
    fname := Concatenation( [ "Functor_", name, ShortDescriptionOfCategory( Functor ) ] );
    
    ConvertToStringRep( fname );
    
    if IsBoundGlobal( fname ) then
        Info( InfoWarning, 1, "unable to save the right satellite under the default name ", fname, " since it is reserved" );
    else
        BindGlobal( fname, SF );
    fi;
    
    SF!.GlobalName := fname;
    
    return SF;
    
end );

##
InstallMethod( RightSatelliteOfCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt, IsString ],
        
  function( Functor, p, name )
    
    return RightSatelliteOfCofunctor( Functor, p, name, name );
    
end );

##
InstallMethod( RightSatelliteOfCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt ],
        
  function( Functor, p )
    local name;
    
    name := NameOfFunctor( Functor );
    
    name := Concatenation( "S", name );
    
    return RightSatelliteOfCofunctor( Functor, p, name );
    
end );

##
InstallMethod( RightSatelliteOfCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsString, IsString ],
        
  function( Functor, name, operation )
    
    return RightSatelliteOfCofunctor( Functor, 1, name, operation );
    
end );

##
InstallMethod( RightSatelliteOfCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsString ],
        
  function( Functor, name )
    
    return RightSatelliteOfCofunctor( Functor, 1, name );
    
end );

##
InstallMethod( RightSatelliteOfCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    return RightSatelliteOfCofunctor( Functor, 1 );
    
end );

##  <#GAPDoc Label="LeftSatelliteOfFunctor">
##  <ManSection>
##    <Oper Arg="F[, p][, H]" Name="LeftSatelliteOfFunctor" Label="constructor of the left satellite of a covariant functor"/>
##    <Returns>a &homalg; functor</Returns>
##    <Description>
##      Given a &homalg; (multi-)functor <A>F</A> and a string <A>H</A> return the left satellite of
##      <A>F</A> with respect to its <A>p</A>-th argument. <A>F</A> is assumed covariant in its <A>p</A>-th argument.
##      The string <A>H</A> becomes the name of the returned functor (&see; <Ref Oper="NameOfFunctor"/>).
##      The variable <C>Functor_</C><A>H</A> will automatically be assigned if free, otherwise a warning is issued.
##      <P/>
##      If <A>p</A> is not specified it is assumed <M>1</M>. If the string <A>H</A> is not specified
##      the string <Q>S_</Q> is added to the left of the name of <A>F</A> (&see; <Ref Oper="NameOfFunctor"/>).
##      <P/>
##      The constructor automatically invokes <Ref Oper="InstallFunctor"/> which installs several necessary operations
##      under the name <A>H</A>.
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( LeftSatelliteOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt, IsString, IsString ],
        
  function( Functor, p, name, operation )
    local functor_name, functor_operation, _Functor_OnObjects, _Functor_OnMorphisms,
          m, z, data, i, SF, fname;
    
    if IsCovariantFunctor( Functor, p ) <> true then
        Error( "the functor does not seem to be covariant in its ", p, ". argument\n" );
    fi;
    
    functor_name :=  NameOfFunctor( Functor );
    
    functor_operation := OperationOfFunctor( Functor );
    
    _Functor_OnObjects :=
      function( arg )
        local functor_operation, c, mu, ar, F_mu, sat;
        
        functor_operation := OperationOfFunctor( Functor );
        
        c := arg[1];
        
        if c < 0 then
            Error( "the negative ", c, ". left satellite is not defined\n" );
        fi;
        
        mu := SyzygiesObjectEmb( c, arg[p + 1] );
        
        ar := Concatenation( arg{[ 2 .. p ]}, [ mu ], arg{[ p + 2 .. Length( arg ) ]} );
        
        F_mu := CallFuncList( functor_operation, ar );
        
        sat := Kernel( F_mu );
        
        SetAsKernel( sat, F_mu );
        
        return sat;
        
    end;
    
    _Functor_OnMorphisms :=
      function( F_source, F_target, arg_before_pos, phi, arg_behind_pos )
        local arg, c, d, d_c_1, mu, ar, hull_phi, emb_source, emb_target;
        
        arg := Concatenation( arg_before_pos, [ phi ], arg_behind_pos );
        
        c := arg[1];
        
        if c < 0 then
            Error( "the negative ", c, ". left satellite is not defined\n" );
        fi;
        
        if c - 1 > -1 then
            d := Resolution( c - 1, arg[p + 1] );
        else
            d := Resolution( 0, arg[p + 1] );
        fi;
        
        if IsHomalgStaticMorphism( arg[p + 1] ) then
            if c = 0 then
                mu := arg[p + 1];
            else
                d_c_1 := CertainMorphismAsKernelSquare( d, c - 1 );
                mu := Kernel( d_c_1 );
            fi;
        else
            ## the following is not really mu but Source( mu ):
            mu := SyzygiesObject( c, arg[p + 1] );
        fi;
        
        ar := Concatenation( arg{[ 2 .. p ]}, [ mu ], arg{[ p + 2 .. Length( arg ) ]} );
        
        hull_phi := CallFuncList( functor_operation, ar );
        
        emb_source := NaturalGeneralizedEmbedding( F_source );
        emb_target := NaturalGeneralizedEmbedding( F_target );
        
        return CompleteImageSquare( emb_source, hull_phi, emb_target );
        
        ## HasIsIsomorphism( phi ) and IsIsomorphism( phi ), resp.
        ## HasIsMorphism( phi ) and IsMorphism( phi ), and
        ## UpdateObjectsByMorphism( mor )
        ## will be taken care of in FunctorMor
        
    end;
    
    m := MultiplicityOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) then
        if IsList( Functor!.0 ) then
            z := Concatenation( [ IsInt ], Functor!.0 );
        else
            Error( "the zeroth argument of the functor is not a list" );
        fi;
    else
        z := [ IsInt ];
    fi;
    
    data := List( [ 1 .. m ], i -> [ String( i ), StructuralCopy( Functor!.(String( i )) ) ] );
    
    for i in [ 1 .. m ] do
        if IsBound( data[i][2] ) and IsBound( data[i][2][1] ) and IsBound( data[i][2][1][2] ) and
           data[i][2][1][2] in [ "left exact", "right exact", "right adjoint", "left adjoint" ] then
            data[i][2][1][2] := "additive";
            if i = p or functor_name = "TensorProduct" then
                Add( data[i][2][1], "delta-functor", 3 );
                Add( data[i][2][1], "coeffaceable", 4 );
            fi;
        fi;
    od;
    
    data := Concatenation(
                    [ [ "name", name ],
                      [ "category", CategoryOfFunctor( Functor ) ],
                      [ "operation", operation ],
                      [ "number_of_arguments", m ] ],
                    [ [ "0", z ] ],
                    data,
                    [ [ "OnObjects", _Functor_OnObjects ] ],
                    [ [ "OnMorphisms", _Functor_OnMorphisms ] ] );
    
    SF := CallFuncList( CreateHomalgFunctor, data );
    
    SetGenesis( SF, [ "LeftSatelliteOfFunctor", Functor, p ] );
    
    if m > 1 then
        SF!.ContainerForWeakPointersOnComputedBasicObjects :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
        SF!.ContainerForWeakPointersOnComputedBasicMorphisms :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
    fi;
    
    if IsBoundGlobal( operation ) then
        if not IsOperation( ValueGlobal( operation ) ) then
            Error( operation, " is bound but is not an operation\n" );
        fi;
    else
        ## it is only important to declare and almost regardless how
        DeclareOperation( operation, [ IsHomalgObjectOrMorphism ] );
    fi;
    
    InstallFunctor( SF );
    
    fname := Concatenation( [ "Functor_", name, ShortDescriptionOfCategory( Functor ) ] );
    
    ConvertToStringRep( fname );
    
    if IsBoundGlobal( fname ) then
        Info( InfoWarning, 1, "unable to save the left satellite under the default name ", fname, " since it is reserved" );
    else
        BindGlobal( fname, SF );
    fi;
    
    SF!.GlobalName := fname;
    
    return SF;
    
end );

##
InstallMethod( LeftSatelliteOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt, IsString ],
        
  function( Functor, p, name )
    
    return LeftSatelliteOfFunctor( Functor, p, name, name );
    
end );

##
InstallMethod( LeftSatelliteOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt ],
        
  function( Functor, p )
    local name;
    
    name := NameOfFunctor( Functor );
    
    name := Concatenation( "S_", name );
    
    return LeftSatelliteOfFunctor( Functor, p, name );
    
end );

##
InstallMethod( LeftSatelliteOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsString, IsString ],
        
  function( Functor, name, operation )
    
    return LeftSatelliteOfFunctor( Functor, 1, name, operation );
    
end );

##
InstallMethod( LeftSatelliteOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsString ],
        
  function( Functor, name )
    
    return LeftSatelliteOfFunctor( Functor, 1, name );
    
end );

##
InstallMethod( LeftSatelliteOfFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    return LeftSatelliteOfFunctor( Functor, 1 );
    
end );

##  <#GAPDoc Label="RightDerivedCofunctor">
##  <ManSection>
##    <Oper Arg="F[, p][, H]" Name="RightDerivedCofunctor" Label="constructor of the right derived functor of a contravariant functor"/>
##    <Returns>a &homalg; functor</Returns>
##    <Description>
##      Given a &homalg; (multi-)functor <A>F</A> and a string <A>H</A> return the right derived functor of
##      <A>F</A> with respect to its <A>p</A>-th argument. <A>F</A> is assumed contravariant in its <A>p</A>-th argument.
##      The string <A>H</A> becomes the name of the returned functor (&see; <Ref Oper="NameOfFunctor"/>).
##      The variable <C>Functor_</C><A>H</A> will automatically be assigned if free, otherwise a warning is issued.
##      <P/>
##      If <A>p</A> is not specified it is assumed <M>1</M>. If the string <A>H</A> is not specified
##      the letter 'R' is added to the left of the name of <A>F</A> (&see; <Ref Oper="NameOfFunctor"/>).
##      <P/>
##      The constructor automatically invokes <Ref Oper="InstallFunctor"/> and <Ref Oper="InstallDeltaFunctor"/>
##      which install several necessary operations under the name <A>H</A>.
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( RightDerivedCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt, IsString, IsString ],
        
  function( Functor, p, name, operation )
    local functor_name, functor_operation, _Functor_OnObjects, _Functor_OnMorphisms,
          m, z, data, i, RF, fname;
    
    if IsCovariantFunctor( Functor, p ) <> false then
        Error( "the functor does not seem to be contravariant in its ", p, ". argument\n" );
    fi;
    
    functor_name :=  NameOfFunctor( Functor );
    
    functor_operation := OperationOfFunctor( Functor );
    
    _Functor_OnObjects :=
      function( arg )
        local c, dd, ar, F_dd, der;
        
        c := arg[1];
        
        if c < 0 then
            Error( "the negative ", c, ". right derived cofunctor is not defined\n" );
        fi;
        
        dd := SubResolution( c, arg[p + 1] );
        
        ar := Concatenation( arg{[ 2 .. p ]}, [ dd ], arg{[ p + 2 .. Length( arg ) ]} );
        
        F_dd := CallFuncList( functor_operation, ar );
        
        der := DefectOfHoms( F_dd );
        
        return der;
        
    end;
    
    _Functor_OnMorphisms :=
      function( F_source, F_target, arg_before_pos, phi, arg_behind_pos )
        local arg, c, d, d_c, ar, hull_phi, emb_source, emb_target;
        
        arg := Concatenation( arg_before_pos, [ phi ], arg_behind_pos );
        
        c := arg[1];
        
        if c < 0 then
            Error( "the negative ", c, ". right derived cofunctor is not defined\n" );
        fi;
        
        d := Resolution( c, arg[p + 1] );
        
        if IsHomalgStaticMorphism( arg[p + 1] ) then
            d_c := CertainMorphism( d, c );
        else
            d_c := CertainObject( d, c );
        fi;
        
        ar := Concatenation( arg{[ 2 .. p ]}, [ d_c ], arg{[ p + 2 .. Length( arg ) ]} );
        
        hull_phi := CallFuncList( functor_operation, ar );
        
        emb_source := NaturalGeneralizedEmbedding( F_source );
        emb_target := NaturalGeneralizedEmbedding( F_target );
        
        return CompleteImageSquare( emb_source, hull_phi, emb_target );
        
        ## HasIsIsomorphism( phi ) and IsIsomorphism( phi ), resp.
        ## HasIsMorphism( phi ) and IsMorphism( phi ), and
        ## UpdateObjectsByMorphism( mor )
        ## will be taken care of in FunctorMor
        
    end;
    
    m := MultiplicityOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) then
        if IsList( Functor!.0 ) then
            z := Concatenation( [ IsInt ], Functor!.0 );
        else
            Error( "the zeroth argument of the functor is not a list" );
        fi;
    else
        z := [ IsInt ];
    fi;
    
    data := List( [ 1 .. m ], i -> [ String( i ), StructuralCopy( Functor!.(String( i )) ) ] );
    
    for i in [ 1 .. m ] do
        if IsBound( data[i][2] ) and IsBound( data[i][2][1] ) and IsBound( data[i][2][1][2] ) and
           data[i][2][1][2] in [ "left exact", "right exact", "right adjoint", "left adjoint" ] then
            data[i][2][1][2] := "additive";
            if i = p or functor_name = "Hom" then
                Add( data[i][2][1], "delta-functor", 3 );
                Add( data[i][2][1], "effaceable", 4 );
            fi;
        fi;
    od;
    
    data := Concatenation(
                    [ [ "name", name ],
                      [ "category", CategoryOfFunctor( Functor ) ],
                      [ "operation", operation ],
                      [ "number_of_arguments", m ] ],
                    [ [ "0", z ] ],
                    data,
                    [ [ "OnObjects", _Functor_OnObjects ] ],
                    [ [ "OnMorphisms", _Functor_OnMorphisms ] ] );
    
    RF := CallFuncList( CreateHomalgFunctor, data );
    
    SetGenesis( RF, [ "RightDerivedCofunctor", Functor, p ] );
    
    if m > 1 then
        RF!.ContainerForWeakPointersOnComputedBasicObjects :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
        RF!.ContainerForWeakPointersOnComputedBasicMorphisms :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
    fi;
    
    if IsBoundGlobal( operation ) then
        if not IsOperation( ValueGlobal( operation ) ) then
            Error( operation, " is bound but is not an operation\n" );
        fi;
    else
        ## it is only important to declare and almost regardless how
        DeclareOperation( operation, [ IsHomalgObjectOrMorphism ] );
    fi;
    
    InstallFunctor( RF );
    
    InstallDeltaFunctor( RF );
    
    fname := Concatenation( [ "Functor_", name, ShortDescriptionOfCategory( Functor ) ] );
    
    ConvertToStringRep( fname );
    
    if IsBoundGlobal( fname ) then
        Info( InfoWarning, 1, "unable to save the right derived cofunctor under the default name ", fname, " since it is reserved" );
    else
        BindGlobal( fname, RF );
    fi;
    
    RF!.GlobalName := fname;
    
    return RF;
    
end );

##
InstallMethod( RightDerivedCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt, IsString ],
        
  function( Functor, p, name )
    
    return RightDerivedCofunctor( Functor, p, name, name );
    
end );

##
InstallMethod( RightDerivedCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt ],
        
  function( Functor, p )
    local name;
    
    name := NameOfFunctor( Functor );
    
    name := Concatenation( "R", name );
    
    return RightDerivedCofunctor( Functor, p, name );
    
end );

##
InstallMethod( RightDerivedCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsString, IsString ],
        
  function( Functor, name, operation )
    
    return RightDerivedCofunctor( Functor, 1, name, operation );
    
end );

##
InstallMethod( RightDerivedCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsString ],
        
  function( Functor, name )
    
    return RightDerivedCofunctor( Functor, 1, name );
    
end );

##
InstallMethod( RightDerivedCofunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    return RightDerivedCofunctor( Functor, 1 );
    
end );

##  <#GAPDoc Label="LeftDerivedFunctor">
##  <ManSection>
##    <Oper Arg="F[, p][, H]" Name="LeftDerivedFunctor" Label="constructor of the left derived functor of a covariant functor"/>
##    <Returns>a &homalg; functor</Returns>
##    <Description>
##      Given a &homalg; (multi-)functor <A>F</A> and a string <A>H</A> return the left derived functor of
##      <A>F</A> with respect to its <A>p</A>-th argument. <A>F</A> is assumed covariant in its <A>p</A>-th argument.
##      The string <A>H</A> becomes the name of the returned functor (&see; <Ref Oper="NameOfFunctor"/>).
##      The variable <C>Functor_</C><A>H</A> will automatically be assigned if free, otherwise a warning is issued.
##      <P/>
##      If <A>p</A> is not specified it is assumed <M>1</M>. If the string <A>H</A> is not specified
##      the letter <Q>S_</Q> is added to the left of the name of <A>F</A> (&see; <Ref Oper="NameOfFunctor"/>).
##      <P/>
##      The constructor automatically invokes <Ref Oper="InstallFunctor"/> and <Ref Oper="InstallDeltaFunctor"/>
##      which install several necessary operations under the name <A>H</A>.
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( LeftDerivedFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt, IsString, IsString ],
        
  function( Functor, p, name, operation )
    local functor_name, functor_operation, _Functor_OnObjects, _Functor_OnMorphisms,
          m, z, data, i, LF, fname;
    
    if IsCovariantFunctor( Functor, p ) <> true then
        Error( "the functor does not seem to be covariant in its ", p, ". argument\n" );
    fi;
    
    functor_name :=  NameOfFunctor( Functor );
    
    functor_operation := OperationOfFunctor( Functor );
    
    _Functor_OnObjects :=
      function( arg )
        local c, dd, ar, F_dd, der;
        
        c := arg[1];
        
        if c < 0 then
            Error( "the negative ", c, ". left derived functor is not defined\n" );
        fi;
        
        dd := SubResolution( c, arg[p + 1] );
        
        ar := Concatenation( arg{[ 2 .. p ]}, [ dd ], arg{[ p + 2 .. Length( arg ) ]} );
        
        F_dd := CallFuncList( functor_operation, ar );
        
        der := DefectOfHoms( F_dd );
        
        return der;
        
    end;
    
    _Functor_OnMorphisms :=
      function( F_source, F_target, arg_before_pos, phi, arg_behind_pos )
        local arg, c, d, d_c, ar, hull_phi, emb_source, emb_target;
        
        arg := Concatenation( arg_before_pos, [ phi ], arg_behind_pos );
        
        c := arg[1];
        
        if c < 0 then
            Error( "the negative ", c, ". left derived functor is not defined\n" );
        fi;
        
        d := Resolution( c, arg[p + 1] );
        
        if IsHomalgStaticMorphism( arg[p + 1] ) then
            d_c := CertainMorphism( d, c );
        else
            d_c := CertainObject( d, c );
        fi;
        
        ar := Concatenation( arg{[ 2 .. p ]}, [ d_c ], arg{[ p + 2 .. Length( arg ) ]} );
        
        hull_phi := CallFuncList( functor_operation, ar );
        
        emb_source := NaturalGeneralizedEmbedding( F_source );
        emb_target := NaturalGeneralizedEmbedding( F_target );
        
        return CompleteImageSquare( emb_source, hull_phi, emb_target );
        
        ## HasIsIsomorphism( phi ) and IsIsomorphism( phi ), resp.
        ## HasIsMorphism( phi ) and IsMorphism( phi ), and
        ## UpdateObjectsByMorphism( mor )
        ## will be taken care of in FunctorMor
        
    end;
    
    m := MultiplicityOfFunctor( Functor );
    
    if IsBound( Functor!.0 ) then
        if IsList( Functor!.0 ) then
            z := Concatenation( [ IsInt ], Functor!.0 );
        else
            Error( "the zeroth argument of the functor is not a list" );
        fi;
    else
        z := [ IsInt ];
    fi;
    
    data := List( [ 1 .. m ], i -> [ String( i ), StructuralCopy( Functor!.(String( i )) ) ] );
    
    for i in [ 1 .. m ] do
        if IsBound( data[i][2] ) and IsBound( data[i][2][1] ) and IsBound( data[i][2][1][2] ) and
           data[i][2][1][2] in [ "left exact", "right exact", "right adjoint", "left adjoint" ] then
            data[i][2][1][2] := "additive";
            if i = p or functor_name = "Hom" then
                Add( data[i][2][1], "delta-functor", 3 );
                Add( data[i][2][1], "coeffaceable", 4 );
            fi;
        fi;
    od;
    
    data := Concatenation(
                    [ [ "name", name ],
                      [ "category", CategoryOfFunctor( Functor ) ],
                      [ "operation", operation ],
                      [ "number_of_arguments", m ] ],
                    [ [ "0", z ] ],
                    data,
                    [ [ "OnObjects", _Functor_OnObjects ] ],
                    [ [ "OnMorphisms", _Functor_OnMorphisms ] ] );
    
    LF := CallFuncList( CreateHomalgFunctor, data );
    
    SetGenesis( LF, [ "LeftDerivedFunctor", Functor, p ] );
    
    if m > 1 then
        LF!.ContainerForWeakPointersOnComputedBasicObjects :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
        LF!.ContainerForWeakPointersOnComputedBasicMorphisms :=
          ContainerForWeakPointers( TheTypeContainerForWeakPointersOnComputedValuesOfFunctor );
    fi;
    
    if IsBoundGlobal( operation ) then
        if not IsOperation( ValueGlobal( operation ) ) then
            Error( operation, " is bound but is not an operation\n" );
        fi;
    else
        ## it is only important to declare and almost regardless how
        DeclareOperation( operation, [ IsHomalgObjectOrMorphism ] );
    fi;
    
    InstallFunctor( LF );
    
    InstallDeltaFunctor( LF );
    
    fname := Concatenation( [ "Functor_", name, ShortDescriptionOfCategory( Functor ) ] );
    
    ConvertToStringRep( fname );
    
    if IsBoundGlobal( fname ) then
        Info( InfoWarning, 1, "unable to save the left derived functor under the default name ", fname, " since it is reserved" );
    else
        BindGlobal( fname, LF );
    fi;
    
    LF!.GlobalName := fname;
    
    return LF;
    
end );

##
InstallMethod( LeftDerivedFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt, IsString ],
        
  function( Functor, p, name )
    
    return LeftDerivedFunctor( Functor, p, name, name );
    
end );

##
InstallMethod( LeftDerivedFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsPosInt ],
        
  function( Functor, p )
    local name;
    
    name := NameOfFunctor( Functor );
    
    name := Concatenation( "L", name );
    
    return LeftDerivedFunctor( Functor, p, name );
    
end );

##
InstallMethod( LeftDerivedFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsString, IsString ],
        
  function( Functor, name, operation )
    
    return LeftDerivedFunctor( Functor, 1, name, operation );
    
end );

##
InstallMethod( LeftDerivedFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep, IsString ],
        
  function( Functor, name )
    
    return LeftDerivedFunctor( Functor, 1, name );
    
end );

##
InstallMethod( LeftDerivedFunctor,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( Functor )
    
    return LeftDerivedFunctor( Functor, 1 );
    
end );

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

##
InstallMethod( ViewObj,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( o )
    
    Print( "<The functor ", NameOfFunctor( o ), " for ", DescriptionOfCategory( o ), ">" );
    
end );

##
InstallMethod( Display,
        "for homalg functors",
        [ IsHomalgFunctorRep ],
        
  function( o )
    
    Print( NameOfFunctor( o ), "\n" );
    
end );

##
InstallMethod( ViewObj,
        "for containers of weak pointers on the computed values of a functor",
        [ IsContainerForWeakPointersOnComputedValuesOfFunctorRep ],
        
  function( o )
    local a, e;
    
    UpdateContainerOfWeakPointers( o );
    
    a := Length( o!.active );
    
    if not IsBound( o!.Functor ) and a > 0 then
        e := ElmWPObj( o!.weak_pointers, o!.active[1] );
        if e <> fail then
            if IsList( e ) and Length( e ) > 0 then
                e := e[1];
                if IsRecord( e ) and IsBound( e.Functor ) then
                    o!.Functor := e.Functor;
                fi;
            fi;
        fi;
    fi;
    
    Print( "<A container for weak pointers on computed values of " );
    
    if IsBound( o!.Functor ) then
        ViewObj( o!.Functor );
    else
        Print( "a functor" );
    fi;
    
    Print( ": active = ", a, ", deleted = ", o!.counter - a, ", counter = ", o!.counter, ", accessed = ", o!.accessed, ", cache_misses = ", o!.cache_misses, ", cache_hits = ", o!.cache_hits, ">" );
    
end );

[0.266QuellennavigatorsProjekt 2026-05-01]