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

 
# 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
                        
--> --------------------

--> maximum size reached

--> --------------------

[ Verzeichnis aufwärts0.46unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]