Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  HomalgModule.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
# Modules: A homalg based package for the Abelian category of finitely presented modules over computable rings
#
# Implementations
#

##  Implementation stuff for homalg modules.

##  <#GAPDoc Label="Modules:intro">
##  A &homalg; module is a data structure for a finitely presented module. A presentation is given by
##  a set of generators and a set of relations among these generators. The data structure for modules in &homalg;
##  has two novel features:
##  <List>
##    <Item> The data structure allows several presentations linked with so-called transition matrices.
##       One of the presentations is marked as the default presentation, which is usually the last added one.
##       A new presentation can always be added provided it is linked to the default presentation by a transition matrix.
##       If needed, the user can reset the default presentation by choosing one of the other presentations saved
##       in the data structure of the &homalg; module. Effectively, a module is then given by <Q>all</Q> its presentations
##       (as <Q>coordinates</Q>) together with isomorphisms between them (as <Q>coordinate changes</Q>).
##       Being able to <Q>change coordinates</Q> makes the realization of a module in &homalg; <E>intrinsic</E>
##       (or <Q>coordinate free</Q>). </Item>
##    <Item> To present a left/right module it suffices to take a matrix <A>M</A> and interpret its rows/columns
##       as relations among <M>n</M> <E>abstract</E> generators, where <M>n</M> is the number of columns/rows
##       of <A>M</A>. Only that these abstract generators are useless when it comes to specific modules like
##       modules of homomorphisms, where one expects the generators to be maps between modules. For this
##       reason a presentation of a module in &homalg; is not merely a matrix of relations, but together with
##       a set of generators. </Item>
##  </List>
##  <#/GAPDoc>

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

##  <#GAPDoc Label="IsFinitelyPresentedModuleOrSubmoduleRep">
##  <ManSection>
##    <Filt Type="Representation" Arg="M" Name="IsFinitelyPresentedModuleOrSubmoduleRep"/>
##    <Returns><C>true</C> or <C>false</C></Returns>
##    <Description>
##      The &GAP; representation of finitley presented &homalg; modules or submodules. <P/>
##      (It is a representation of the &GAP; category <Ref Filt="IsHomalgModule"/>,
##       which is a subrepresentation of the &GAP; representations
##      <C>IsStaticFinitelyPresentedObjectOrSubobjectRep</C>.)
##    <Listing Type="Code"><![CDATA[
DeclareRepresentation( "IsFinitelyPresentedModuleOrSubmoduleRep",
        IsHomalgModule and
        IsStaticFinitelyPresentedObjectOrSubobjectRep,
        [ ] );
##  ]]></Listing>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>

##  <#GAPDoc Label="IsFinitelyPresentedModuleRep">
##  <ManSection>
##    <Filt Type="Representation" Arg="M" Name="IsFinitelyPresentedModuleRep"/>
##    <Returns><C>true</C> or <C>false</C></Returns>
##    <Description>
##      The &GAP; representation of finitley presented &homalg; modules. <P/>
##      (It is a representation of the &GAP; category <Ref Filt="IsHomalgModule"/>,
##       which is a subrepresentation of the &GAP; representations
##      <C>IsFinitelyPresentedModuleOrSubmoduleRep</C>,
##      <C>IsStaticFinitelyPresentedObjectRep</C>, and <C>IsHomalgRingOrFinitelyPresentedModuleRep</C>.)
##    <Listing Type="Code"><![CDATA[
DeclareRepresentation( "IsFinitelyPresentedModuleRep",
        IsFinitelyPresentedModuleOrSubmoduleRep and
        IsStaticFinitelyPresentedObjectRep and
        IsHomalgRingOrFinitelyPresentedModuleRep,
        [ "SetsOfGenerators", "SetsOfRelations",
          "PresentationMorphisms",
          "Resolutions",
          "TransitionMatrices",
          "PositionOfTheDefaultPresentation" ] );
##  ]]></Listing>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>

##  <#GAPDoc Label="IsFinitelyPresentedSubmoduleRep">
##  <ManSection>
##    <Filt Type="Representation" Arg="M" Name="IsFinitelyPresentedSubmoduleRep"/>
##    <Returns><C>true</C> or <C>false</C></Returns>
##    <Description>
##      The &GAP; representation of finitley generated &homalg; submodules. <P/>
##      (It is a representation of the &GAP; category <Ref Filt="IsHomalgModule"/>,
##       which is a subrepresentation of the &GAP; representations
##      <C>IsFinitelyPresentedModuleOrSubmoduleRep</C>,
##      <C>IsStaticFinitelyPresentedSubobjectRep</C>, and <C>IsHomalgRingOrFinitelyPresentedModuleRep</C>.)
##    <Listing Type="Code"><![CDATA[
DeclareRepresentation( "IsFinitelyPresentedSubmoduleRep",
        IsFinitelyPresentedModuleOrSubmoduleRep and
        IsStaticFinitelyPresentedSubobjectRep and
        IsHomalgRingOrFinitelyPresentedModuleRep,
        [ "map_having_subobject_as_its_image" ] );
##  ]]></Listing>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>

##
DeclareRepresentation( "IsCategoryOfFinitelyPresentedLeftModulesRep",
        IsHomalgCategoryOfLeftObjectsRep and
        IsCategoryOfModules,
        [ ] );

##
DeclareRepresentation( "IsCategoryOfFinitelyPresentedRightModulesRep",
        IsHomalgCategoryOfRightObjectsRep and
        IsCategoryOfModules,
        [ ] );

DeclareFilter( "AdmissibleInputForHomalgFunctors" );

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

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

# two new types:
BindGlobal( "TheTypeHomalgLeftFinitelyPresentedModule",
        NewType( TheFamilyOfHomalgModules,
                AdmissibleInputForHomalgFunctors and
                IsFinitelyPresentedModuleRep and
                IsHomalgLeftObjectOrMorphismOfLeftObjects ) );

BindGlobal( "TheTypeHomalgRightFinitelyPresentedModule",
        NewType( TheFamilyOfHomalgModules,
                AdmissibleInputForHomalgFunctors and
                IsFinitelyPresentedModuleRep and
                IsHomalgRightObjectOrMorphismOfRightObjects ) );

# two new types:
BindGlobal( "TheTypeCategoryOfFinitelyPresentedLeftModules",
        NewType( TheFamilyOfHomalgCategories,
                IsCategoryOfFinitelyPresentedLeftModulesRep ) );

BindGlobal( "TheTypeCategoryOfFinitelyPresentedRightModules",
        NewType( TheFamilyOfHomalgCategories,
                IsCategoryOfFinitelyPresentedRightModulesRep ) );

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

##  <#GAPDoc Label="HomalgRing:module">
##  <ManSection>
##    <Oper Arg="M" Name="HomalgRing" Label="for modules"/>
##    <Returns>a &homalg; ring</Returns>
##    <Description>
##      The &homalg; ring of the &homalg; module <A>M</A>.
##      <#Include Label="HomalgRing:module:example">
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( HomalgRing,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    
    return M!.ring;
    
end );

##
InstallMethod( StructureObject,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    
    return M!.ring;
    
end );

##
InstallOtherMethod( Zero,
        "for homalg modules",
        [ IsHomalgModule and IsHomalgRightObjectOrMorphismOfRightObjects ], 10001, ## FIXME: is it O.K. to use such a high ranking
        
  function( M )
    
    return ZeroRightModule( HomalgRing( M ) );
    
end );

##
InstallOtherMethod( Zero,
        "for homalg modules",
        [ IsHomalgModule and IsHomalgLeftObjectOrMorphismOfLeftObjects ], 10001, ## FIXME: is it O.K. to use such a high ranking
        
  function( M )
    
    return ZeroLeftModule( HomalgRing( M ) );
    
end );

##
InstallMethod( SetsOfGenerators,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    
    if IsBound(M!.SetsOfGenerators) then
        return M!.SetsOfGenerators;
    fi;
    
    return fail;
    
end );

##
InstallMethod( SetsOfRelations,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    
    if IsBound(M!.SetsOfRelations) then
        return M!.SetsOfRelations;
    fi;
    
    return fail;
    
end );

##
InstallMethod( ListOfPositionsOfKnownSetsOfRelations,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    
    return SetsOfRelations( M )!.ListOfPositionsOfKnownSetsOfRelations;
    
end );

##
InstallMethod( PartOfPresentationRelevantForOutputOfFunctors,
        "for homalg modules",
        [ IsHomalgModule, IsInt ],
        
  GeneratorsOfModule );

##
InstallMethod( ComparePresentationsForOutputOfFunctors,
        "for a homalg module and two integers",
        [ IsFinitelyPresentedModuleRep, IsInt, IsInt ],
        
  function( M, p, q )
    
    return IsOne( TransitionMatrix( M, p, q ) );
    
end );

##
InstallMethod( PositionOfTheDefaultPresentation,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    
    if IsBound(M!.PositionOfTheDefaultPresentation) then
        return M!.PositionOfTheDefaultPresentation;
    fi;
    
    return fail;
    
end );

##
InstallMethod( SetPositionOfTheDefaultPresentation,
        "for homalg modules",
        [ IsHomalgModule, IsPosInt ],
        
  function( M, pos )
    
    M!.PositionOfTheDefaultPresentation := pos;
    
end );

##
InstallMethod( PositionOfLastStoredSetOfRelations,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    
    return PositionOfLastStoredSetOfRelations( SetsOfRelations( M ) );
    
end );

##
InstallMethod( SetAsOriginalPresentation,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    local pos;
    
    pos := PositionOfTheDefaultPresentation( M );
    
    M!.PositionOfOriginalPresentation := pos;
    
end );

##
InstallMethod( OnOriginalPresentation,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    local pos;
    
    if IsBound( M!.PositionOfOriginalPresentation ) then
        pos := M!.PositionOfOriginalPresentation;
        SetPositionOfTheDefaultPresentation( M, pos );
    fi;
    
    return M;
    
end );

##
InstallMethod( SetAsPreferredPresentation,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    local pos;
    
    pos := PositionOfTheDefaultPresentation( M );
    
    M!.PositionOfPreferredPresentation := pos;
    
end );

##
InstallMethod( OnPreferredPresentation,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    local pos;
    
    if IsBound( M!.PositionOfPreferredPresentation ) then
        pos := M!.PositionOfPreferredPresentation;
        SetPositionOfTheDefaultPresentation( M, pos );
    fi;
    
    return M;
    
end );

##
InstallMethod( OnFirstStoredPresentation,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    local pos;
    
    SetPositionOfTheDefaultPresentation( M, 1 );
    
    return M;
    
end );

##
InstallMethod( OnLastStoredPresentation,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    local pos;
    
    pos := PositionOfLastStoredSetOfRelations( M );
    
    SetPositionOfTheDefaultPresentation( M, pos );
    
    return M;
    
end );

##
InstallMethod( GeneratorsOfModule, ### defines: GeneratorsOfModule (GeneratorsOfPresentation)
        "for homalg modules",
        [ IsHomalgModule, IsPosInt ],
        
  function( M, pos )
    
    if IsBound(SetsOfGenerators(M)!.(pos)) then
        return SetsOfGenerators(M)!.(pos);
    fi;
    
    return fail;
    
end );

##
InstallMethod( GeneratorsOfModule, ### defines: GeneratorsOfModule (GeneratorsOfPresentation)
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    local gens;
    
    gens := GeneratorsOfModule( M, PositionOfTheDefaultSetOfGenerators( M ) );
    
    if not HasProcedureToNormalizeGenerators( gens ) and HasProcedureToNormalizeGenerators( M ) then
        SetProcedureToNormalizeGenerators( gens, ProcedureToNormalizeGenerators( M ) );
    fi;
    
    if not HasProcedureToReadjustGenerators( gens ) and HasProcedureToReadjustGenerators( M ) then
        SetProcedureToReadjustGenerators( gens, ProcedureToReadjustGenerators( M ) );
    fi;
    
    return gens;
    
end );

##
InstallMethod( GeneratingElements,
        "for homalg modules",
        [ IsHomalgModule and IsStaticFinitelyPresentedObjectRep ],
        
  function( M )
    local gen_set, n, R, gens;
    
    gen_set := GeneratorsOfModule( M );
    
    if IsBound( gen_set!.GeneratingElements ) then
        return gen_set!.GeneratingElements;
    fi;
    
    n := NrGenerators( M );
    
    R := HomalgRing( M );
    
    if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
        gens := StandardBasisRowVectors( n, R );
    else
        gens := StandardBasisColumnVectors( n, R );
    fi;
    
    gens := List( gens, b -> HomalgElement( MorphismConstructor( b, One( M ), M ) ) );
    
    gen_set!.GeneratingElements := gens;
    
    return gens;
    
end );

##
InstallMethod( GeneratingElements,
        "for homalg submodules",
        [ IsHomalgModule and IsStaticFinitelyPresentedSubobjectRep ],
        
  function( N )
    local gens, M;
    
    gens := MatrixOfGenerators( N );
    
    if IsHomalgLeftObjectOrMorphismOfLeftObjects( N ) then
        gens := List( [ 1 .. NumberRows( gens ) ], i -> CertainRows( gens, [ i ] ) );
    else
        gens := List( [ 1 .. NumberColumns( gens ) ], i -> CertainColumns( gens, [ i ] ) );
    fi;
    
    M := SuperObject( N );
    
    return List( gens, b -> HomalgElement( MorphismConstructor( b, One( M ), M ) ) );
    
end );

##
InstallMethod( RelationsOfModule, ### defines: RelationsOfModule (NormalizeInput)
        "for homalg modules",
        [ IsHomalgModule, IsPosInt ],
        
  function( M, pos )
    
    if IsBound(SetsOfRelations( M )!.(pos)) then;
        return SetsOfRelations( M )!.(pos);
    fi;
    
    return fail;
    
end );

##
InstallMethod( RelationsOfModule, ### defines: RelationsOfModule (NormalizeInput)
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    
    return RelationsOfModule( M, PositionOfTheDefaultPresentation( M ) );
    
end );

##
InstallMethod( RelationsOfHullModule, ### defines: RelationsOfHullModule
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    local gen;
    
    gen := GeneratorsOfModule( M );
    
    if gen <> fail then;
        return RelationsOfHullModule( gen );
    fi;
    
    return fail;
    
end );

##
InstallMethod( RelationsOfHullModule, ### defines: RelationsOfHullModule
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep, IsPosInt ],
        
  function( M, pos )
    local gen;
    
    gen := GeneratorsOfModule( M, pos );
    
    if gen <> fail then;
        return RelationsOfHullModule( gen );
    fi;
    
    return fail;
    
end );

##
InstallMethod( MatrixOfGenerators,
        "for homalg modules",
        [ IsHomalgModule ],
  function( M )
    
    return MatrixOfGenerators( GeneratorsOfModule( M ) );
    
end );

##
InstallMethod( MatrixOfGenerators,
        "for homalg modules",
        [ IsHomalgModule, IsPosInt ],
  function( M, pos )
    local gen;
    
    gen := GeneratorsOfModule( M, pos );
    
    if IsHomalgGenerators( gen ) then
        return MatrixOfGenerators( gen );
    fi;
    
    return fail;
    
end );

##
InstallMethod( MatrixOfRelations,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    local rel;
    
    rel := RelationsOfModule( M );
    
    if IsHomalgRelations( rel ) then
        return EvaluatedMatrixOfRelations( rel );
    fi;
    
    return fail;
    
end );

##
InstallMethod( MatrixOfRelations,
        "for homalg modules",
        [ IsHomalgModule, IsPosInt ],
        
  function( M, pos )
    local rel;
    
    rel := RelationsOfModule( M, pos );
    
    if IsHomalgRelations( rel ) then
        return MatrixOfRelations( rel );
    fi;
    
    return fail;
    
end );

##
InstallMethod( PresentationMorphism,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep, IsPosInt ],
        
  function( M, pos )
    local rel, pres, epi;
    
    if IsBound(M!.PresentationMorphisms.( pos )) then
        return M!.PresentationMorphisms.( pos );
    fi;
    
    rel := RelationsOfModule( M );
    
    ## "COMPUTE_SMALLER_BASIS" saves computations
    pres := ReducedBasisOfModule( rel, "COMPUTE_SMALLER_BASIS" );
    
    pres := HomalgMap( pres );
    
    if not HasCokernelEpi( pres ) then
        ## the zero'th component of the quasi-isomorphism,
        ## which in this case is simply the natural epimorphism onto the module
        epi := HomalgIdentityMap( Range( pres ), M );
        
        SetIsEpimorphism( epi, true );
        SetCokernelEpi( pres, epi );
    fi;
    
    M!.PresentationMorphisms.( pos ) := pres;
    
    return pres;
    
end );

##
InstallMethod( PresentationMorphism,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    
    return PresentationMorphism( M, PositionOfTheDefaultPresentation( M ) );
    
end );

##
InstallMethod( HasNrGenerators,
        "for homalg modules",
        [ IsHomalgModule ],
  function( M )
    
    return HasNrGenerators( GeneratorsOfModule( M ) );
    
end );

##
InstallMethod( NrGenerators,
        "for homalg modules",
        [ IsHomalgModule ],
  function( M )
    local g;
    
    g := NrGenerators( GeneratorsOfModule( M ) );
    
    if g = 0 then
        SetIsZero( M, true );
    elif IsFinitelyPresentedModuleOrSubmoduleRep( M ) and
      HasRankOfObject( M ) and RankOfObject( M ) = g then
        SetIsFree( M, true );
    fi;
    
    return g;
    
end );

##
InstallMethod( HasNrGenerators,
        "for homalg modules",
        [ IsHomalgModule, IsPosInt ],
  function( M, pos )
    local gen;
    
    gen := GeneratorsOfModule( M, pos );
    
    if IsHomalgGenerators( gen ) then
        return HasNrGenerators( gen );
    fi;
    
    return fail;
    
end );

##
InstallMethod( NrGenerators,
        "for homalg modules",
        [ IsHomalgModule, IsPosInt ],
  function( M, pos )
    local gen;
    
    gen := GeneratorsOfModule( M, pos );
    
    if IsHomalgGenerators( gen ) then
        return NrGenerators( gen );
    fi;
    
    return fail;
    
end );

##
InstallMethod( CertainGenerators,
        "for homalg modules",
        [ IsHomalgModule, IsList ],
        
  function( M, list )
    
    return CertainGenerators( GeneratorsOfModule( M ), list );
    
end );

##
InstallMethod( CertainGenerator,
        "for homalg modules",
        [ IsHomalgModule, IsPosInt ],
        
  function( M, pos )
    
    return CertainGenerator( GeneratorsOfModule( M ), pos );
    
end );

##
InstallMethod( GetGenerators,
        "for a homalg static object, fail, and a positive integer",
        [ IsHomalgStaticObject, IsObject, IsPosInt ],
        
  function( M, g, pos )
    
    return GetGenerators( M, [ 1 .. NrGenerators( M ) ], pos );
    
end );

##
InstallMethod( GetGenerators,
        "for a homalg module and two positive integers",
        [ IsHomalgModule, IsPosInt, IsPosInt ],
        
  function( M, g, pos )
    local AdjustedGenerators, G, Functor, proc;
    
    if not IsBound( M!.AdjustedGenerators ) then
        M!.AdjustedGenerators := rec( );
    fi;
    
    AdjustedGenerators := M!.AdjustedGenerators;
    
    if not IsBound( AdjustedGenerators.(String( pos )) ) then
        AdjustedGenerators.(String( pos )) := [ ];
    fi;
    
    AdjustedGenerators := AdjustedGenerators.(String( pos ));
    
    if IsBound( AdjustedGenerators[g] ) then
        return AdjustedGenerators[g];
    fi;
    
    G := GetGenerators( GeneratorsOfModule( M, pos ), g );
    
    # we want ot search the latest functor first, because this
    # functor should be able to override the functors it uses.
    for Functor in Reversed( FunctorsOfGenesis( M ) ) do
        
        if IsBound( Functor!.GlobalName ) then
            Functor := ValueGlobal( Functor!.GlobalName );
        fi;
        
        if IsHomalgFunctor( Functor )
          and HasProcedureToReadjustGenerators( Functor ) then
            proc := ProcedureToReadjustGenerators( Functor );
            G := CallFuncList( proc, Concatenation( [ G ], ArgumentsOfGenesis( M ) ) );
            break;
        fi;
    
    od;
    
    AdjustedGenerators[g] := G;
    
    return G;
    
end );

##
InstallMethod( GetGenerators,
        "for a homalg static object, a list, and a positive integer",
        [ IsHomalgStaticObject, IsList, IsPosInt ],
        
  function( M, g, pos )
    
    return List( g, i -> GetGenerators( M, i, pos ) );
    
end );

##
InstallMethod( GetGenerators,
        "for a homalg static object and a positive integer",
        [ IsHomalgStaticObject, IsPosInt ],
        
  function( M, g )
    
    return GetGenerators( M, g, PositionOfTheDefaultSetOfGenerators( M ) );
    
end );

##
InstallMethod( GetGenerators,
        "for a homalg static object, a list, and a positive integer",
        [ IsHomalgStaticObject, IsList ],
        
  function( M, g )
    
    return GetGenerators( M, g, PositionOfTheDefaultSetOfGenerators( M ) );
    
end );

##
InstallMethod( GetGenerators,
        "for a homalg static object, a list, and a positive integer",
        [ IsHomalgStaticObject ],
        
  function( M )
    
    return GetGenerators( M, [ 1 .. NrGenerators( M ) ] );
    
end );

##
InstallMethod( HasNrRelations,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    local rel;
    
    rel := RelationsOfModule( M );
    
    if IsHomalgRelations( rel ) then
        return HasNrRelations( rel );
    fi;
    
    return fail;
    
end );

##
InstallMethod( NrRelations,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    local rel, r;
    
    rel := RelationsOfModule( M );
    
    if IsHomalgRelations( rel ) then
        r := NrRelations( rel );
        if r = 0 then
            SetIsFree( M, true );
        fi;
        return r;
    fi;
    
    return fail;
    
end );

##
InstallMethod( HasNrRelations,
        "for homalg modules",
        [ IsHomalgModule, IsPosInt ],
        
  function( M, pos )
    local rel;
    
    rel := RelationsOfModule( M, pos );
    
    if IsHomalgRelations( rel ) then
        return HasNrRelations( rel );
    fi;
    
    return fail;
    
end );

##
InstallMethod( NrRelations,
        "for homalg modules",
        [ IsHomalgModule, IsPosInt ],
        
  function( M, pos )
    local rel;
    
    rel := RelationsOfModule( M, pos );
    
    if IsHomalgRelations( rel ) then
        return NrRelations( rel );
    fi;
    
    return fail;
    
end );

##
InstallMethod( TransitionMatrix,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep, IsInt, IsInt ],
        
  function( M, pos1, pos2 )
    local pres_a, pres_b, sets_of_generators, tr, sign, i, j;
    
    if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
        pres_a := pos2;
        pres_b := pos1;
    else
        pres_a := pos1;
        pres_b := pos2;
    fi;
    
    if pres_a < 1 then
        pres_a := PositionOfTheDefaultPresentation( M );
    fi;
    
    if pres_b < 1 then
        pres_b := PositionOfTheDefaultPresentation( M );
    fi;
    
    sets_of_generators := M!.SetsOfGenerators;
    
    if not IsBound( sets_of_generators!.( pres_a ) ) then
        
        Error( "the module given as the first argument has no ", pres_a, ". set of generators\n" );
        
    elif not IsBound( sets_of_generators!.( pres_b ) ) then
        
        Error( "the module given as the first argument has no ", pres_b, ". set of generators\n" );
        
    elif pres_a = pres_b then
        
        return HomalgIdentityMatrix( NrGenerators( sets_of_generators!.( pres_a ) ), HomalgRing( M ) );
        
    else
        
        ## starting with the identity is no waste of performance since the subpackage LIMAT is active:
        tr := HomalgIdentityMatrix(  NrGenerators( sets_of_generators!.( pres_a ) ), HomalgRing( M ) );
        
        sign := SignInt( pres_b - pres_a );
        
        i := pres_a;
        
        if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
            
            while AbsInt( pres_b - i ) > 0 do
                for j in pres_b - sign * [ 0 .. AbsInt( pres_b - i ) - 1 ]  do
                    if IsBound( M!.TransitionMatrices.( String( [ j, i ] ) ) ) then
                        tr := M!.TransitionMatrices.( String( [ j, i ] ) ) * tr;
                        i := j;
                        break;
                    fi;
                od;
            od;
            
        else
            
            while AbsInt( pres_b - i ) > 0 do
                for j in pres_b - sign * [ 0 .. AbsInt( pres_b - i ) - 1 ]  do
                    if IsBound( M!.TransitionMatrices.( String( [ i, j ] ) ) ) then
                        tr := tr * M!.TransitionMatrices.( String( [ i, j ] ) );
                        i := j;
                        break;
                    fi;
                od;
            od;
            
        fi;
        
        return tr;
        
    fi;
    
end );

##
InstallMethod( LockObjectOnCertainPresentation,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep, IsInt ],
        
  function( M, p )
    
    ## first save the current setting
    M!.LockObjectOnCertainPresentation := PositionOfTheDefaultPresentation( M );
    
    SetPositionOfTheDefaultPresentation( M, p );
    
end );

##
InstallMethod( LockObjectOnCertainPresentation,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    
    LockObjectOnCertainPresentation( M, PositionOfTheDefaultPresentation( M ) );
    
end );

##
InstallMethod( UnlockObject,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    
    ## first restore the saved settings
    if IsBound( M!.LockObjectOnCertainPresentation ) then
        SetPositionOfTheDefaultPresentation( M, M!.LockObjectOnCertainPresentation );
        Unbind( M!.LockObjectOnCertainPresentation );
    fi;
    
end );

##
InstallMethod( IsLockedObject,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( M )
    
    return IsBound( M!.LockObjectOnCertainPresentation );
    
end );

##
InstallMethod( AddANewPresentation,
        "for homalg modules",
        [ IsHomalgModule, IsGeneratorsOfFinitelyGeneratedModuleRep ],
        
  function( M, gen )
    local rels, gens, d, l, id, tr, itr;
    
    if not ( IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) and IsHomalgGeneratorsOfLeftModule( gen ) )
       and not ( IsHomalgRightObjectOrMorphismOfRightObjects( M ) and IsHomalgGeneratorsOfRightModule( gen ) ) then
        Error( "the module and the new set of generators must either be both left or both right\n" );
    fi;
    
    rels := SetsOfRelations( M );
    gens := SetsOfGenerators( M );
    
    d := PositionOfTheDefaultPresentation( M );
    
    l := PositionOfLastStoredSetOfRelations( rels );
    
    ## define the (l+1)st set of generators:
    gens!.(l+1) := gen;
    
    ## adjust the list of positions:
    gens!.ListOfPositionsOfKnownSetsOfGenerators[l+1] := l+1; ## the list is allowed to contain holes (sparse list)
    
    ## define the (l+1)st set of relations:
    if IsBound( rels!.(d) ) then
        rels!.(l+1) := rels!.(d);
    fi;
    
    ## adjust the list of positions:
    rels!.ListOfPositionsOfKnownSetsOfRelations[l+1] := l+1; ## the list is allowed to contain holes (sparse list)
    
    id := HomalgIdentityMatrix( NrGenerators( M ), HomalgRing( M ) );
    
    ## no need to distinguish between left and right modules here:
    M!.TransitionMatrices.( String( [ d, l+1 ] ) ) := id;
    M!.TransitionMatrices.( String( [ l+1, d ] ) ) := id;
    
    if d <> l then
        
        ## starting with the identity is no waste of performance since the subpackage LIMAT is active:
        tr := id; itr := id;
        
        if IsHomalgGeneratorsOfLeftModule( gen ) then
            
            tr := tr * TransitionMatrix( M, d, l );
            itr :=  TransitionMatrix( M, l, d ) * itr;
            
            M!.TransitionMatrices.( String( [ l+1, l ] ) ) := tr;
            M!.TransitionMatrices.( String( [ l, l+1 ] ) ) := itr;
            
        else
            
            tr := TransitionMatrix( M, l, d ) * tr;
            itr :=  itr * TransitionMatrix( M, d, l );
            
            M!.TransitionMatrices.( String( [ l, l+1 ] ) ) := tr;
            M!.TransitionMatrices.( String( [ l+1, l ] ) ) := itr;
            
        fi;
        
    fi;
    
    ## adjust the default position:
    if IsLockedObject( M ) then
        M!.LockObjectOnCertainPresentation := l+1;
    else
        SetPositionOfTheDefaultPresentation( M, l+1 );
    fi;
    
    if NrGenerators( gen ) = 0 then
        SetIsZero( M, true );
    elif NrGenerators( gen ) = 1 then
        SetIsCyclic( M, true );
    fi;
    
    return M;
    
end );

##
InstallMethod( AddANewPresentation,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep, IsRelationsOfFinitelyPresentedModuleRep ],
        
  function( M, rel )
    local rels, rev_lpos, d, gens, l, id, tr, itr;
    
    if not ( IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) and IsHomalgRelationsOfLeftModule( rel ) )
       and not ( IsHomalgRightObjectOrMorphismOfRightObjects( M ) and IsHomalgRelationsOfRightModule( rel ) ) then
        Error( "the module and the new set of relations must either be both left or both right\n" );
    fi;
    
    rels := SetsOfRelations( M );
    
    ## we reverse since we want to check the recent sets of relations first
    rev_lpos := Reversed( rels!.ListOfPositionsOfKnownSetsOfRelations );
    
    ## don't add an old set of relations, but let it be the default set of relations instead:
    for d in rev_lpos do
        if IsIdenticalObj( rel, rels!.(d) ) then
            
            if IsLockedObject( M ) then
                M!.LockObjectOnCertainPresentation := d;
            else
                SetPositionOfTheDefaultPresentation( M, d );
            fi;
            
            return M;
        fi;
    od;
    
    for d in rev_lpos do
        if MatrixOfRelations( rel ) = MatrixOfRelations( rels!.(d) ) then
            
            if IsLockedObject( M ) then
                M!.LockObjectOnCertainPresentation := d;
            else
                SetPositionOfTheDefaultPresentation( M, d );
            fi;
            
            return M;
        fi;
    od;
    
    gens := SetsOfGenerators( M );
    
    d := PositionOfTheDefaultPresentation( M );
    
    l := PositionOfLastStoredSetOfRelations( rels );
    
    ## define the (l+1)st set of generators:
    gens!.(l+1) := gens!.(d);
    
    ## adjust the list of positions:
    gens!.ListOfPositionsOfKnownSetsOfGenerators[l+1] := l+1; ## the list is allowed to contain holes (sparse list)
    
    ## define the (l+1)st set of relations:
    rels!.(l+1) := rel;
    
    ## adjust the list of positions:
    rels!.ListOfPositionsOfKnownSetsOfRelations[l+1] := l+1; ## the list is allowed to contain holes (sparse list)
    
    id := HomalgIdentityMatrix( NrGenerators( M ), HomalgRing( M ) );
    
    ## no need to distinguish between left and right modules here:
    M!.TransitionMatrices.( String( [ d, l+1 ] ) ) := id;
    M!.TransitionMatrices.( String( [ l+1, d ] ) ) := id;
    
    if d <> l then
        
        ## starting with the identity is no waste of performance since the subpackage LIMAT is active:
        tr := id; itr := id;
        
        if IsHomalgRelationsOfLeftModule( rel ) then
            
            tr := tr * TransitionMatrix( M, d, l );
            itr :=  TransitionMatrix( M, l, d ) * itr;
            
            M!.TransitionMatrices.( String( [ l+1, l ] ) ) := tr;
            M!.TransitionMatrices.( String( [ l, l+1 ] ) ) := itr;
            
        else
            
            tr := TransitionMatrix( M, l, d ) * tr;
            itr :=  itr * TransitionMatrix( M, d, l );
            
            M!.TransitionMatrices.( String( [ l, l+1 ] ) ) := tr;
            M!.TransitionMatrices.( String( [ l+1, l ] ) ) := itr;
            
        fi;
        
    fi;
    
    ## adjust the default position:
    if IsLockedObject( M ) then
        M!.LockObjectOnCertainPresentation := l+1;
    else
        SetPositionOfTheDefaultPresentation( M, l+1 );
    fi;
    
    SetParent( rel, M );
    
    INSTALL_TODO_LIST_ENTRIES_FOR_RELATIONS_OF_MODULES( rel, M );
    
    return M;
    
end );

##
InstallMethod( AddANewPresentation,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep, IsRelationsOfFinitelyPresentedModuleRep, IsHomalgMatrix, IsHomalgMatrix ],
        
  function( M, rel, T, TI )
    local rels, gens, d, l, gen, tr, itr;
    
    if not ( IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) and IsHomalgRelationsOfLeftModule( rel ) )
       and not ( IsHomalgRightObjectOrMorphismOfRightObjects( M ) and IsHomalgRelationsOfRightModule( rel ) ) then
        Error( "the module and the new set of relations must either be both left or both right\n" );
    fi;
    
    rels := SetsOfRelations( M );
    gens := SetsOfGenerators( M );
    
    d := PositionOfTheDefaultPresentation( M );
    
    l := PositionOfLastStoredSetOfRelations( rels );
    
    gen := TI * GeneratorsOfModule( M );
    
    ## define the (l+1)st set of generators:
    gens!.(l+1) := gen;
    
    ## adjust the list of positions:
    gens!.ListOfPositionsOfKnownSetsOfGenerators[l+1] := l+1; ## the list is allowed to contain holes (sparse list)
    
    ## define the (l+1)st set of relations:
    rels!.(l+1) := rel;
    
    ## adjust the list of positions:
    rels!.ListOfPositionsOfKnownSetsOfRelations[l+1] := l+1; ## the list is allowed to contain holes (sparse list)
    
    if IsHomalgRelationsOfLeftModule( rel ) then
        M!.TransitionMatrices.( String( [ d, l+1 ] ) ) := T;
        M!.TransitionMatrices.( String( [ l+1, d ] ) ) := TI;
    else
        M!.TransitionMatrices.( String( [ l+1, d ] ) ) := T;
        M!.TransitionMatrices.( String( [ d, l+1 ] ) ) := TI;
    fi;
    
    if d <> l then
        
        tr := TI; itr := T;
        
        if IsHomalgRelationsOfLeftModule( rel ) then
            
            tr := tr * TransitionMatrix( M, d, l );
            itr :=  TransitionMatrix( M, l, d ) * itr;
            
            M!.TransitionMatrices.( String( [ l+1, l ] ) ) := tr;
            M!.TransitionMatrices.( String( [ l, l+1 ] ) ) := itr;
            
        else
            
            tr := TransitionMatrix( M, l, d ) * tr;
            itr :=  itr * TransitionMatrix( M, d, l );
            
            M!.TransitionMatrices.( String( [ l, l+1 ] ) ) := tr;
            M!.TransitionMatrices.( String( [ l+1, l ] ) ) := itr;
            
        fi;
        
    fi;
    
    ## adjust the default position:
    if IsLockedObject( M ) then
        M!.LockObjectOnCertainPresentation := l+1;
    else
        SetPositionOfTheDefaultPresentation( M, l+1 );
    fi;
    
    if NrGenerators( rel ) = 0 then
        SetIsZero( M, true );
    elif NrGenerators( rel ) = 1 then
        SetIsCyclic( M, true );
    fi;
    
    SetParent( rel, M );
    
    INSTALL_TODO_LIST_ENTRIES_FOR_RELATIONS_OF_MODULES( rel, M );
    
    return M;
    
end );

##
InstallMethod( BasisOfModule, ### CAUTION: has the side effect of possibly affecting the module M
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    local rel, bas, mat, R, rk;
    
    rel := RelationsOfModule( M );
    
    if not ( HasCanBeUsedToDecideZeroEffectively( rel ) and CanBeUsedToDecideZeroEffectively( rel ) ) then
        bas := BasisOfModule( rel ); ## CAUTION: might have a side effect on rel
        
        if not IsIdenticalObj( rel, bas ) then
            AddANewPresentation( M, bas ); ## this might set CanBeUsedToDecideZeroEffectively( rel ) to true
        fi;
    fi;
    
    return RelationsOfModule( M );
    
end );

##
InstallMethod( OnBasisOfPresentation,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    
    BasisOfModule( M );
    
    return M;
    
end );

##
InstallMethod( DecideZero,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    local gen, red;
    
    gen := GeneratorsOfModule( M );
    
    if HasIsReduced( gen ) and IsReduced( gen ) then
        return gen;
    fi;
    
    red := DecideZero( gen );
    
    if IsIdenticalObj( gen, red ) then
        return gen;
    fi;
    
    AddANewPresentation( M, red );
    
    return red;
    
end );

##
InstallMethod( DecideZero,
        "for homalg modules",
        [ IsHomalgMatrix, IsFinitelyPresentedModuleRep ],
        
  function( mat, M )
    local rel;
    
    rel := RelationsOfModule( M );
    
    return DecideZero( mat, rel );
    
end );

##
InstallMethod( UnionOfRelations,
        "for homalg modules",
        [ IsHomalgMatrix, IsFinitelyPresentedModuleRep ],
        
  function( mat, M )
    
    return UnionOfRelations( mat, RelationsOfModule( M ) );
    
end );

##
InstallMethod( SyzygiesGenerators,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    
    return SyzygiesGenerators( RelationsOfModule( M ) );
    
end );

##
InstallMethod( SyzygiesGenerators,
        "for homalg modules",
        [ IsHomalgMatrix, IsFinitelyPresentedModuleRep ],
        
  function( mat, M )
    
    return SyzygiesGenerators( mat, RelationsOfModule( M ) );
    
end );

##
InstallMethod( ReducedSyzygiesGenerators,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    
    return ReducedSyzygiesGenerators( RelationsOfModule( M ) );
    
end );

##
InstallMethod( ReducedSyzygiesGenerators,
        "for homalg modules",
        [ IsHomalgMatrix, IsFinitelyPresentedModuleRep ],
        
  function( mat, M )
    
    return ReducedSyzygiesGenerators( mat, RelationsOfModule( M ) );
    
end );

##
InstallMethod( NonZeroGenerators,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    
    return NonZeroGenerators( BasisOfModule( RelationsOfModule( M ) ) ); ## don't delete RelationsOfModule, since we don't want to add too much new relations to the module in an early stage!
    
end );

##
InstallMethod( GetRidOfZeroGenerators, ### defines: GetRidOfZeroGenerators (BetterPresentation)
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    local bl, rel, id, T, TI;
    
    bl := NonZeroGenerators( M );
    
    if Length( bl ) < NrGenerators( M ) then
        
        rel := MatrixOfRelations( M );
        
        id := HomalgIdentityMatrix( NrGenerators( M ), HomalgRing( M ) );
        
        if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
            rel := CertainColumns( rel, bl );
            rel := CertainRows( rel, NonZeroRows( rel ) );
            rel := HomalgRelationsForLeftModule( rel, M );
            T := CertainColumns( id, bl );
            TI := CertainRows( id, bl );
        else
            rel := CertainRows( rel, bl );
            rel := CertainColumns( rel, NonZeroColumns( rel ) );
            rel := HomalgRelationsForRightModule( rel, M );
            T := CertainRows( id, bl );
            TI := CertainColumns( id, bl );
        fi;
        
        AddANewPresentation( M, rel, T, TI );
        
        if NrGenerators( M ) = 1 then
            SetIsCyclic( M, true );
        fi;
    fi;
    
    return M;
    
end );

#=======================================================================
# Compute a smaller presentation allowing the transformation of the generators
# (i.e. allowing column/row operations for left/right relation matrices)
#_______________________________________________________________________
##
InstallMethod( OnLessGenerators,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep and IsHomalgRightObjectOrMorphismOfRightObjects ],
        
  function( M )
    local R, rel_old, rel, U, UI;
    
    R := HomalgRing( M );
    
    rel_old := MatrixOfRelations( M );
    
    U := HomalgVoidMatrix( R );
    UI := HomalgVoidMatrix( R );
    
    rel := SimplerEquivalentMatrix( rel_old, U, UI, "", "", "" );
    
    if not rel_old = rel then
        
        rel := HomalgRelationsForRightModule( rel, M );
        
        AddANewPresentation( M, rel, U, UI );
        
    fi;
    
    return GetRidOfZeroGenerators( M );
    
end );

##
InstallMethod( OnLessGenerators,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep and IsHomalgLeftObjectOrMorphismOfLeftObjects ],
        
  function( M )
    local R, rel_old, rel, V, VI;
    
    R := HomalgRing( M );
    
    rel_old := MatrixOfRelations( M );
    
    V := HomalgVoidMatrix( R );
    VI := HomalgVoidMatrix( R );
    
    rel := SimplerEquivalentMatrix( rel_old, V, VI, "", "" );
    
    if not rel_old = rel then
        
        rel := HomalgRelationsForLeftModule( rel, M );
        
        AddANewPresentation( M, rel, V, VI );
        
    fi;
    
    return GetRidOfZeroGenerators( M );
    
end );

##  <#GAPDoc Label="ByASmallerPresentation:module">
##  <ManSection>
##    <Meth Arg="M" Name="ByASmallerPresentation" Label="for modules"/>
##    <Returns>a &homalg; module</Returns>
##    <Description>
##      Use different strategies to reduce the presentation of the given &homalg; module <A>M</A>.
##      This method performs side effects on its argument <A>M</A> and returns it.
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );;
##  gap> M := HomalgMatrix( "[ \
##  > 2, 3, 4, \
##  > 5, 6, 7  \
##  > ]", 2, 3, zz );
##  <A 2 x 3 matrix over an internal ring>
##  gap> M := LeftPresentation( M );
##  <A non-torsion left module presented by 2 relations for 3 generators>
##  gap> Display( M );
##  [ [  2,  3,  4 ],
##    [  5,  6,  7 ] ]
##  
##  Cokernel of the map
##  
##  Z^(1x2) --> Z^(1x3),
##  
##  currently represented by the above matrix
##  gap> ByASmallerPresentation( M );
##  <A rank 1 left module presented by 1 relation for 2 generators>
##  gap> Display( last );
##  Z/< 3 > + Z^(1 x 1)
##  gap> SetsOfGenerators( M );
##  <A set containing 2 sets of generators of a homalg module>
##  gap> SetsOfRelations( M );
##  <A set containing 2 sets of relations of a homalg module>
##  gap> M;
##  <A rank 1 left module presented by 1 relation for 2 generators>
##  gap> SetPositionOfTheDefaultPresentation( M, 1 );
##  gap> M;
##  <A rank 1 left module presented by 2 relations for 3 generators>
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( ByASmallerPresentation,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    local g, r, p, rel;
    
    while true do
        g := NrGenerators( M );
        r := NrRelations( M );
        p := PositionOfTheDefaultSetOfGenerators( M );
        OnLessGenerators( M );
        if NrGenerators( M ) = g then ## try to compute a basis first
            rel := RelationsOfModule( M, p );
            if not ( HasCanBeUsedToDecideZeroEffectively( rel ) and
                     CanBeUsedToDecideZeroEffectively( rel ) ) then
                SetPositionOfTheDefaultSetOfGenerators( M, p ); ## just in case
                if not ValueOption( "BasisOfModule" ) = false then
                    BasisOfModule( M );
                fi;
                OnLessGenerators( M );
            fi;
        fi;
        if NrGenerators( M ) = g then ## there is nothing we can do more!
            break;
        fi;
    od;
    
    if not ( IsBound( HOMALG_MODULES.ByASmallerPresentationDoesNotDecideZero ) and
             HOMALG_MODULES.ByASmallerPresentationDoesNotDecideZero = true )
       and NrRelations( M ) > 0 then
        ## Fixme: also generators of free modules can be reduced;
        ## this should become lazy with the introduction of intrinsic categories
        DecideZero( M );
    fi;
    
    return M;
    
end );

##
InstallMethod( ElementaryDivisors,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    local rel, b, R, RP, e;
    
    R := HomalgRing( M );
    
    RP := homalgTable( R );
    
    if IsBound( RP!.ElementaryDivisors ) then
        e := RP!.ElementaryDivisors( MatrixOfRelations( M ) );
        if IsString( e ) then
            e := StringToElementStringList( e );
            e := List( e, a -> HomalgRingElement( a, R ) );
        fi;
        
        ## since the computer algebra systems have different
        ## conventions for elementary divisors, we fix our own here:
        e := Filtered( e, x -> not IsOne( x ) and not IsZero( x ) );
        
        Append( e, ListWithIdenticalEntries( RankOfObject( M ), Zero( R ) ) );
        
        return e;
    fi;
    
    TryNextMethod( );
    
end );

##
InstallMethod( ElementaryDivisors,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep and IsZero ],
        
  function( M )
    
    return [ ];
    
end );

##
InstallMethod( ElementaryDivisors,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep and IsFree ],
        
  function( M )
    local R;
    
    R := HomalgRing( M );
    
    return ListWithIdenticalEntries( NrGenerators( M ), Zero( R ) );
    
end );

##
InstallMethod( SetUpperBoundForProjectiveDimension,
        "for homalg modules",
        [ IsHomalgModule, IsInfinity ],
        
  function( M, ub_pd )
    
    ## do nothing
    
end );

##
InstallMethod( SetUpperBoundForProjectiveDimension,
        "for homalg modules",
        [ IsHomalgModule, IsInt ],
        
  function( M, ub_pd )
    local left, R, ub, min;
    
    if not HasProjectiveDimension( M ) then ## otherwise don't do anything
        if ub_pd < 0 then
            ## decrease the upper bound by |ub_pd| *relative* to the left/right global dimension of the ring:
            left := IsHomalgLeftObjectOrMorphismOfLeftObjects( M );
            R := HomalgRing( M );
            if left and HasLeftGlobalDimension( R ) and IsInt( LeftGlobalDimension( R ) ) then
                ub := LeftGlobalDimension( R ) + ub_pd; ## recall, ub_pd < 0
                if ub < 0 then
                    SetProjectiveDimension( M, 0 );
                else
                    SetUpperBoundForProjectiveDimension( M, ub ); ## ub >= 0
                fi;
            elif not left and HasRightGlobalDimension( R ) and IsInt( RightGlobalDimension( R ) ) then
                ub := RightGlobalDimension( R ) + ub_pd; ## recall, ub_pd < 0
                if ub < 0 then
                    SetProjectiveDimension( M, 0 );
                else
                    SetUpperBoundForProjectiveDimension( M, ub ); ## ub >= 0
                fi;
            fi;
        else
            ## set the upper bound to ub_pd:
            if IsBound( M!.UpperBoundForProjectiveDimension ) then
                min := Minimum( M!.UpperBoundForProjectiveDimension, ub_pd );
            else
                min := ub_pd;
            fi;
            
            M!.UpperBoundForProjectiveDimension := min;
            
            if min = 0 then
                SetProjectiveDimension( M, 0 );
            elif min = 1 and HasIsProjective( M ) and not IsProjective( M ) then
                SetProjectiveDimension( M, 1 );
            fi;
        fi;
    fi;
    
end );

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

##
InstallMethod( ZeroLeftModule,
        "for homalg rings",
        [ IsHomalgRing ],
        
  function( R )
    local zero;
    
    if IsBound(R!.ZeroLeftModule) then
        return R!.ZeroLeftModule;
    fi;
    
    zero := HomalgZeroLeftModule( R );
    
    zero!.distinguished := true;
    
    R!.ZeroLeftModule := zero;
    
    return zero;
    
end );

##
InstallMethod( ZeroRightModule,
        "for homalg rings",
        [ IsHomalgRing ],
        
  function( R )
    local zero;
    
    if IsBound(R!.ZeroRightModule) then
        return R!.ZeroRightModule;
    fi;
    
    zero := HomalgZeroRightModule( R );
    
    zero!.distinguished := true;
    
    R!.ZeroRightModule := zero;
    
    return zero;
    
end );

##
InstallMethod( AsLeftObject,
        "for homalg rings",
        [ IsHomalgRing ],
        
  function( R )
    local left;
    
    if IsBound(R!.AsLeftObject) then
        return R!.AsLeftObject;
    fi;
    
    left := HomalgFreeLeftModule( 1, R );
    
    left!.distinguished := true;
    
    left!.not_twisted := true;
    
    R!.AsLeftObject := left;
    
    return left;
    
end );

##
InstallMethod( AsRightObject,
        "for homalg rings",
        [ IsHomalgRing ],
        
  function( R )
    local right;
    
    if IsBound(R!.AsRightObject) then
        return R!.AsRightObject;
    fi;
    
    right := HomalgFreeRightModule( 1, R );
    
    right!.distinguished := true;
    
    right!.not_twisted := true;
    
    R!.AsRightObject := right;
    
    return right;
    
end );

##
InstallMethod( HomalgCategory,
        "constructor for module categories",
        [ IsHomalgRing, IsString ],
        
  function( R, parity )
    local A;
    
    if parity = "right" and IsBound( R!.category_of_fp_right_modules ) then
        return R!.category_of_fp_right_modules;
    elif IsBound( R!.category_of_fp_left_modules ) then
        return R!.category_of_fp_left_modules;
    fi;
    
    A := ShallowCopy( HOMALG_MODULES.category );
    A.containers := rec( );
    A.ring := R;
    
    if parity = "right" then
        Objectify( TheTypeCategoryOfFinitelyPresentedRightModules, A );
        R!.category_of_fp_right_modules := A;
    else
        Objectify( TheTypeCategoryOfFinitelyPresentedLeftModules, A );
        R!.category_of_fp_left_modules := A;
    fi;
    
    if IsHomalgInternalRingRep( R ) then
        A!.do_not_cache_values_of_some_functors := true;
    fi;
    
    return A;
    
end );

##
InstallGlobalFunction( RecordForPresentation,
  function( R, gens, rels )
    local string, string_plural, M;
    
    if HasIsDivisionRingForHomalg( R ) and IsDivisionRingForHomalg( R ) then
        string := "vector space";
        string_plural := "vector spaces";
    else
        string := "module";
        string_plural := "modules";
    fi;
    
    M := rec( string := string,
              string_plural := string_plural,
              ring := R,
              SetsOfGenerators := gens,
              SetsOfRelations := rels,
              PresentationMorphisms := rec( ),
              Resolutions := rec( ),
              TransitionMatrices := rec( ),
              PositionOfTheDefaultPresentation := 1 );
    
    if IsHomalgRelationsOfLeftModule( rels ) then
        M.category := HomalgCategory( R, "left" );
    else
        M.category := HomalgCategory( R, "right" );
    fi;
    
    return M;
    
end );

##
InstallMethod( Presentation,
        "constructor for homalg modules",
        [ IsRelationsOfFinitelyPresentedModuleRep and IsHomalgRelationsOfLeftModule ],
        
  function( rel )
    local R, is_zero_module, gens, rels, M;
    
    R := HomalgRing( rel );
    
    if NrGenerators( rel ) = 0 then ## since one doesn't specify generators here giving no relations defines the zero module
        gens := CreateSetsOfGeneratorsForLeftModule( [ ], R );
        is_zero_module := true;
    else
        gens := CreateSetsOfGeneratorsForLeftModule(
                        HomalgIdentityMatrix( NrGenerators( rel ), R ), rel );
    fi;
    
    rels := CreateSetsOfRelationsForLeftModule( rel );
    
    M := RecordForPresentation( R, gens, rels );
    
    ## Objectify:
    if IsBound( is_zero_module ) then
        ObjectifyWithAttributes(
                M, TheTypeHomalgLeftFinitelyPresentedModule,
                LeftActingDomain, R,
                GeneratorsOfLeftOperatorAdditiveGroup, M!.SetsOfGenerators!.1,
                IsZero, true );
    else
        ObjectifyWithAttributes(
                M, TheTypeHomalgLeftFinitelyPresentedModule,
                LeftActingDomain, R,
                GeneratorsOfLeftOperatorAdditiveGroup, M!.SetsOfGenerators!.1 );
        
        if HasLeftGlobalDimension( R ) then
            SetUpperBoundForProjectiveDimension( M, LeftGlobalDimension( R ) );
        fi;
    fi;
    
#    SetParent( gens, M );
    SetParent( rel, M );
    
    INSTALL_TODO_LIST_ENTRIES_FOR_RELATIONS_OF_MODULES( rel, M );
    
    return M;
    
end );

##
InstallMethod( Presentation,
        "constructor for homalg modules",
        [ IsGeneratorsOfFinitelyGeneratedModuleRep and IsHomalgGeneratorsOfLeftModule,
          IsRelationsOfFinitelyPresentedModuleRep and IsHomalgRelationsOfLeftModule ],
        
  function( gen, rel )
    local R, is_zero_module, gens, rels, M;
    
    if NrGenerators( gen ) <> NrGenerators( rel ) then
        Error( "the first argument is a set of ", NrGenerators( gen ), " generator(s) while the second argument is a set of relations for ", NrGenerators( rel ), " generators\n" );
    fi;
    
    R := HomalgRing( rel );
    
    gens := CreateSetsOfGeneratorsForLeftModule( gen );
    
    if NrGenerators( rel ) = 0 then
        is_zero_module := true;
    fi;
    
    rels := CreateSetsOfRelationsForLeftModule( rel );
    
    M := RecordForPresentation( R, gens, rels );
    
    ## Objectify:
    if IsBound( is_zero_module ) then
        ObjectifyWithAttributes(
                M, TheTypeHomalgLeftFinitelyPresentedModule,
                LeftActingDomain, R,
                GeneratorsOfLeftOperatorAdditiveGroup, M!.SetsOfGenerators!.1,
                IsZero, true );
    else
        ObjectifyWithAttributes(
                M, TheTypeHomalgLeftFinitelyPresentedModule,
                LeftActingDomain, R,
                GeneratorsOfLeftOperatorAdditiveGroup, M!.SetsOfGenerators!.1 );
        
        if HasLeftGlobalDimension( R ) then
            SetUpperBoundForProjectiveDimension( M, LeftGlobalDimension( R ) );
        fi;
    fi;
    
#    SetParent( gens, M );
    SetParent( rel, M );
    
    INSTALL_TODO_LIST_ENTRIES_FOR_RELATIONS_OF_MODULES( rel, M );
    
    return M;
    
end );

##
InstallMethod( Presentation,
        "constructor for homalg modules",
        [ IsRelationsOfFinitelyPresentedModuleRep and IsHomalgRelationsOfRightModule ],
        
  function( rel )
    local R, is_zero_module, gens, rels, M;
    
    R := HomalgRing( rel );
    
    if NrGenerators( rel ) = 0 then ## since one doesn't specify generators here giving no relations defines the zero module
        gens := CreateSetsOfGeneratorsForRightModule( [ ], R );
        is_zero_module := true;
    else
        gens := CreateSetsOfGeneratorsForRightModule(
                        HomalgIdentityMatrix( NrGenerators( rel ), R ), rel );
    fi;
    
    rels := CreateSetsOfRelationsForRightModule( rel );
    
    M := RecordForPresentation( R, gens, rels );
    
    ## Objectify:
    if IsBound( is_zero_module ) then
        ObjectifyWithAttributes(
                M, TheTypeHomalgRightFinitelyPresentedModule,
                RightActingDomain, R,
                GeneratorsOfRightOperatorAdditiveGroup, M!.SetsOfGenerators!.1,
                IsZero, true );
    else
        ObjectifyWithAttributes(
                M, TheTypeHomalgRightFinitelyPresentedModule,
                RightActingDomain, R,
                GeneratorsOfRightOperatorAdditiveGroup, M!.SetsOfGenerators!.1 );
        
        if HasRightGlobalDimension( R ) then
            SetUpperBoundForProjectiveDimension( M, RightGlobalDimension( R ) );
        fi;
    fi;
    
#    SetParent( gens, M );
    SetParent( rel, M );
    
    INSTALL_TODO_LIST_ENTRIES_FOR_RELATIONS_OF_MODULES( rel, M );
    
    return M;
    
end );

##
InstallMethod( Presentation,
        "constructor for homalg modules",
        [ IsGeneratorsOfFinitelyGeneratedModuleRep and IsHomalgGeneratorsOfRightModule,
          IsRelationsOfFinitelyPresentedModuleRep and IsHomalgRelationsOfRightModule ],
        
  function( gen, rel )
    local R, is_zero_module, gens, rels, M;
    
    if NrGenerators( gen ) <> NrGenerators( rel ) then
        Error( "the first argument is a set of ", NrGenerators( gen ), " generator(s) while the second argument is a set of relations for ", NrGenerators( rel ), " generators\n" );
    fi;
    
    R := HomalgRing( rel );
    
    gens := CreateSetsOfGeneratorsForRightModule( gen );
    
    if NrGenerators( rel ) = 0 then
        is_zero_module := true;
    fi;
    
    rels := CreateSetsOfRelationsForRightModule( rel );
    
    M := RecordForPresentation( R, gens, rels );
    
    ## Objectify:
    if IsBound( is_zero_module ) then
        ObjectifyWithAttributes(
                M, TheTypeHomalgRightFinitelyPresentedModule,
                RightActingDomain, R,
                GeneratorsOfRightOperatorAdditiveGroup, M!.SetsOfGenerators!.1,
                IsZero, true );
    else
        ObjectifyWithAttributes(
                M, TheTypeHomalgRightFinitelyPresentedModule,
                RightActingDomain, R,
                GeneratorsOfRightOperatorAdditiveGroup, M!.SetsOfGenerators!.1 );
        
        if HasRightGlobalDimension( R ) then
            SetUpperBoundForProjectiveDimension( M, RightGlobalDimension( R ) );
        fi;
    fi;
    
#    SetParent( gens, M );
    SetParent( rel, M );
    
    INSTALL_TODO_LIST_ENTRIES_FOR_RELATIONS_OF_MODULES( rel, M );
    
    return M;
    
end );

##
InstallMethod( LeftPresentation,
        "constructor for homalg modules",
        [ IsList, IsHomalgRing ],
        
  function( rel, R )
    local gens, rels, M, is_zero_module;
    
    if Length( rel ) = 0 then ## since one doesn't specify generators here giving no relations defines the zero module
        gens := CreateSetsOfGeneratorsForLeftModule( [ ], R );
        is_zero_module := true;
    elif IsList( rel[1] ) and ForAll( rel[1], IsRingElement ) then
        gens := CreateSetsOfGeneratorsForLeftModule(
                        HomalgIdentityMatrix( Length( rel[1] ), R ), rel );
    else ## only one generator
        gens := CreateSetsOfGeneratorsForLeftModule(
                        HomalgIdentityMatrix( 1, R ), rel );
    fi;
    
    rels := CreateSetsOfRelationsForLeftModule( rel, R );
    
    M := RecordForPresentation( R, gens, rels );
    
    ## Objectify:
    if IsBound( is_zero_module ) then
        ObjectifyWithAttributes(
                M, TheTypeHomalgLeftFinitelyPresentedModule,
                LeftActingDomain, R,
                GeneratorsOfLeftOperatorAdditiveGroup, M!.SetsOfGenerators!.1,
                IsZero, true );
    else
        ObjectifyWithAttributes(
                M, TheTypeHomalgLeftFinitelyPresentedModule,
                LeftActingDomain, R,
                GeneratorsOfLeftOperatorAdditiveGroup, M!.SetsOfGenerators!.1 );
        
        if HasLeftGlobalDimension( R ) then
            SetUpperBoundForProjectiveDimension( M, LeftGlobalDimension( R ) );
        fi;
    fi;
    
#    SetParent( gens, M );
    SetParent( RelationsOfModule( M ), M );
    
    INSTALL_TODO_LIST_ENTRIES_FOR_RELATIONS_OF_MODULES( RelationsOfModule( M ), M );
    
    return M;
    
end );

##
InstallMethod( LeftPresentation,
        "constructor for homalg modules",
        [ IsList, IsList, IsHomalgRing ],
        
  function( gen, rel, R )
    local gens, rels, M;
    
    gens := CreateSetsOfGeneratorsForLeftModule( gen, R );
    
    if rel = [ ] and gen <> [ ] then
        rels := CreateSetsOfRelationsForLeftModule( "unknown relations", R );
    else
        rels := CreateSetsOfRelationsForLeftModule( rel, R );
    fi;
    
    M := RecordForPresentation( R, gens, rels );
    
    ## Objectify:
    ObjectifyWithAttributes(
            M, TheTypeHomalgLeftFinitelyPresentedModule,
            LeftActingDomain, R,
            GeneratorsOfLeftOperatorAdditiveGroup, M!.SetsOfGenerators!.1 );
    
    
    if HasLeftGlobalDimension( R ) then
        SetUpperBoundForProjectiveDimension( M, LeftGlobalDimension( R ) );
    fi;
    
#    SetParent( gens, M );
    SetParent( RelationsOfModule( M ), M );
    
    INSTALL_TODO_LIST_ENTRIES_FOR_RELATIONS_OF_MODULES( RelationsOfModule( M ), M );
    
    return M;
    
end );

##  <#GAPDoc Label="LeftPresentation">
##  <ManSection>
##    <Oper Arg="mat" Name="LeftPresentation" Label="constructor for left modules"/>
##    <Returns>a &homalg; module</Returns>
##    <Description>
##      This constructor returns the finitely presented left module with relations given by the
##      rows of the &homalg; matrix <A>mat</A>.
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );;
##  gap> M := HomalgMatrix( "[ \
##  > 2, 3, 4, \
##  > 5, 6, 7  \
##  > ]", 2, 3, zz );
##  <A 2 x 3 matrix over an internal ring>
##  gap> M := LeftPresentation( M );
##  <A non-torsion left module presented by 2 relations for 3 generators>
##  gap> Display( M );
##  [ [  2,  3,  4 ],
##    [  5,  6,  7 ] ]
##  
##  Cokernel of the map
##  
##  Z^(1x2) --> Z^(1x3),
##  
##  currently represented by the above matrix
##  gap> ByASmallerPresentation( M );
##  <A rank 1 left module presented by 1 relation for 2 generators>
##  gap> Display( last );
##  Z/< 3 > + Z^(1 x 1)
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( LeftPresentation,
        "constructor for homalg modules",
        [ IsHomalgMatrix ],
        
  function( mat )
    
    return Presentation( HomalgRelationsForLeftModule( mat ) );
    
end );

##
InstallMethod( RightPresentation,
        "constructor for homalg modules",
        [ IsList, IsHomalgRing ],
        
  function( rel, R )
    local gens, rels, M, is_zero_module;
    
    if Length( rel ) = 0 then ## since one doesn't specify generators here giving no relations defines the zero module
        gens := CreateSetsOfGeneratorsForRightModule( [ ], R );
        is_zero_module := true;
    elif IsList( rel[1] ) and ForAll( rel[1], IsRingElement ) then
        gens := CreateSetsOfGeneratorsForRightModule(
                        HomalgIdentityMatrix( Length( rel ), R ), rel );
    else ## only one generator
        gens := CreateSetsOfGeneratorsForRightModule(
                        HomalgIdentityMatrix( 1, R ), rel );
    fi;
    
    rels := CreateSetsOfRelationsForRightModule( rel, R );
    
    M := RecordForPresentation( R, gens, rels );
    
    ## Objectify:
    if IsBound( is_zero_module ) then
        ObjectifyWithAttributes(
                M, TheTypeHomalgRightFinitelyPresentedModule,
                RightActingDomain, R,
                GeneratorsOfRightOperatorAdditiveGroup, M!.SetsOfGenerators!.1,
                IsZero, true );
    else
        ObjectifyWithAttributes(
                M, TheTypeHomalgRightFinitelyPresentedModule,
                RightActingDomain, R,
                GeneratorsOfRightOperatorAdditiveGroup, M!.SetsOfGenerators!.1 );
        
        if HasRightGlobalDimension( R ) then
            SetUpperBoundForProjectiveDimension( M, RightGlobalDimension( R ) );
        fi;
    fi;
    
#    SetParent( gens, M );
    SetParent( RelationsOfModule( M ), M );
    
    INSTALL_TODO_LIST_ENTRIES_FOR_RELATIONS_OF_MODULES( RelationsOfModule( M ), M );
    
    return M;
    
end );

##
InstallMethod( RightPresentation,
        "constructor for homalg modules",
        [ IsList, IsList, IsHomalgRing ],
        
  function( gen, rel, R )
    local gens, rels, M;
    
    gens := CreateSetsOfGeneratorsForRightModule( gen, R );
    
    if rel = [ ] and gen <> [ ] then
        rels := CreateSetsOfRelationsForRightModule( "unknown relations", R );
    else
        rels := CreateSetsOfRelationsForRightModule( rel, R );
    fi;
    
    M := RecordForPresentation( R, gens, rels );
    
    ## Objectify:
    ObjectifyWithAttributes(
            M, TheTypeHomalgRightFinitelyPresentedModule,
            RightActingDomain, R,
            GeneratorsOfRightOperatorAdditiveGroup, M!.SetsOfGenerators!.1 );
    
        
    if HasRightGlobalDimension( R ) then
        SetUpperBoundForProjectiveDimension( M, RightGlobalDimension( R ) );
    fi;
    
#    SetParent( gens, M );
    SetParent( RelationsOfModule( M ), M );
    
    INSTALL_TODO_LIST_ENTRIES_FOR_RELATIONS_OF_MODULES( RelationsOfModule( M ), M );
    
    return M;
    
end );

##  <#GAPDoc Label="RightPresentation">
##  <ManSection>
##    <Oper Arg="mat" Name="RightPresentation" Label="constructor for right modules"/>
##    <Returns>a &homalg; module</Returns>
##    <Description>
##      This constructor returns the finitely presented right module with relations given by the
##      columns of the &homalg; matrix <A>mat</A>.
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );;
##  gap> M := HomalgMatrix( "[ \
##  > 2, 3, 4, \
##  > 5, 6, 7  \
##  > ]", 2, 3, zz );
##  <A 2 x 3 matrix over an internal ring>
##  gap> M := RightPresentation( M );
##  <A right module on 2 generators satisfying 3 relations>
##  gap> ByASmallerPresentation( M );
##  <A cyclic torsion right module on a cyclic generator satisfying 1 relation>
##  gap> Display( last );
##  Z/< 3 >
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( RightPresentation,
        "constructor for homalg modules",
        [ IsHomalgMatrix ],
        
  function( mat )
    
    return Presentation( HomalgRelationsForRightModule( mat ) );
    
end );

##  <#GAPDoc Label="HomalgFreeLeftModule">
##  <ManSection>
##    <Oper Arg="r, R" Name="HomalgFreeLeftModule" Label="constructor for free left modules"/>
##    <Returns>a &homalg; module</Returns>
##    <Description>
##      This constructor returns a free left module of rank <A>r</A> over the &homalg; ring <A>R</A>.
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );;
##  gap> F := HomalgFreeLeftModule( 1, zz );
##  <A free left module of rank 1 on a free generator>
##  gap> 1 * zz;
##  <The free left module of rank 1 on a free generator>
##  gap> F := HomalgFreeLeftModule( 2, zz );
##  <A free left module of rank 2 on free generators>
##  gap> 2 * zz;
##  <A free left module of rank 2 on free generators>
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( HomalgFreeLeftModule,
        "constructor for homalg free modules",
        [ IsInt, IsHomalgRing ],
        
  function( rank, R )
    
    return LeftPresentation( HomalgZeroMatrix( 0, rank, R ) );
    
end );

##  <#GAPDoc Label="HomalgFreeRightModule">
##  <ManSection>
##    <Oper Arg="r, R" Name="HomalgFreeRightModule" Label="constructor for free right modules"/>
##    <Returns>a &homalg; module</Returns>
##    <Description>
##      This constructor returns a free right module of rank <A>r</A> over the &homalg; ring <A>R</A>.
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );;
##  gap> F := HomalgFreeRightModule( 1, zz );
##  <A free right module of rank 1 on a free generator>
##  gap> zz * 1;
##  <The free right module of rank 1 on a free generator>
##  gap> F := HomalgFreeRightModule( 2, zz );
##  <A free right module of rank 2 on free generators>
##  gap> zz * 2;
##  <A free right module of rank 2 on free generators>
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( HomalgFreeRightModule,
        "constructor for homalg free modules",
        [ IsInt, IsHomalgRing ],
        
  function( rank, R )
    
    return RightPresentation( HomalgZeroMatrix( rank, 0, R ) );
    
end );

##  <#GAPDoc Label="HomalgZeroLeftModule">
##  <ManSection>
##    <Oper Arg="r, R" Name="HomalgZeroLeftModule" Label="constructor for zero left modules"/>
##    <Returns>a &homalg; module</Returns>
##    <Description>
##      This constructor returns a zero left module of rank <A>r</A> over the &homalg; ring <A>R</A>.
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );;
##  gap> F := HomalgZeroLeftModule( zz );
##  <A zero left module>
##  gap> 0 * zz;
##  <The zero left module>
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( HomalgZeroLeftModule,
        "constructor for homalg zero modules",
        [ IsHomalgRing ],
        
  function( R )
    
    return HomalgFreeLeftModule( 0, R );
    
end );

##  <#GAPDoc Label="HomalgZeroRightModule">
##  <ManSection>
##    <Oper Arg="r, R" Name="HomalgZeroRightModule" Label="constructor for zero right modules"/>
##    <Returns>a &homalg; module</Returns>
##    <Description>
##      This constructor returns a zero right module of rank <A>r</A> over the &homalg; ring <A>R</A>.
##      <Example><![CDATA[
##  gap> zz := HomalgRingOfIntegers( );;
##  gap> F := HomalgZeroRightModule( zz );
##  <A zero right module>
##  gap> zz * 0;
##  <The zero right module>
##  ]]></Example>
##    </Description>
##  </ManSection>
##  <#/GAPDoc>
##
InstallMethod( HomalgZeroRightModule,
        "constructor for homalg zero modules",
        [ IsHomalgRing ],
        
  function( R )
    
    return HomalgFreeRightModule( 0, R );
    
end );

##
InstallMethod( \*,
        "constructor for homalg free modules",
        [ IsInt, IsHomalgRing ],
        
  function( rank, R )
    
    if rank = 0 then
        return ZeroLeftModule( R );
    elif rank = 1 then
        return AsLeftObject( R );
    elif rank > 1 then
        return HomalgFreeLeftModule( rank, R );
    fi;
    
    Error( "virtual modules are not supported (yet)\n" );
    
end );

##
InstallMethod( \*,
        "constructor for homalg free modules",
        [ IsHomalgRing, IsInt ],
        
  function( R, rank )
    
    if rank = 0 then
        return ZeroRightModule( R );
    elif rank = 1 then
        return AsRightObject( R );
    elif rank > 1 then
        return HomalgFreeRightModule( rank, R );
    fi;
    
    Error( "virtual modules are not supported (yet)\n" );
    
end );

##
InstallMethod( RingMap,
        "for homalg rings",
        [ IsHomalgModule, IsHomalgRing, IsHomalgRing ],
        
  function( M, S, T )
    
    return RingMap( GeneratorsOfModule( M ), S, T );
    
end );

##
InstallMethod( Pullback,
        "for a ring map and a module",
        [ IsHomalgRingMap, IsFinitelyPresentedModuleRep ],
        
  function( phi, M )
    local rel;
    
    rel := MatrixOfRelations( M );
    
    rel := Pullback( phi, rel );
    
    if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
        return LeftPresentation( rel );
    else
        return RightPresentation( rel );
    fi;
    
end );

##
InstallMethod( IsRegularSequence,
        "for a list of ring elements and a module",
        [ IsList, IsFinitelyPresentedModuleRep ],
        
  function( a, M )
    local phi;
    
    for phi in a do
        
        phi := phi * HomalgIdentityMap( M );
        
        if not IsZero( KernelSubobject( phi ) ) then
            return false;
        fi;
        
        M := Cokernel( phi );
        
    od;
    
    if IsZero( M ) then
        return false;
    fi;
    
    return true;
    
end );

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

##
InstallMethod( ViewObj,
        "for categories of homalg modules",
        [ IsCategoryOfModules ],
        
  function( C )
    local parity;
    
    if IsCategoryOfFinitelyPresentedLeftModulesRep( C ) then
        parity := "left";
    else
        parity := "right";
    fi;
    
    Print( "<The Abelian category of f.p. ", parity, " modules over the ring " );
    ViewObj( C!.ring );
    Print( ">" );
    
end );

##
InstallMethod( ViewObj,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( o )
    
    if IsBound( o!.distinguished ) then
        Print( "<The" );
    else
        Print( "<A" );
    fi;
    
    Print( ViewString( o ) );
    
    Print( ">" );
        
end );

##
InstallMethod( ViewString,
        "for homalg modules",
        [ IsHomalgModule ],
        
  function( o )
    local R, num_gen, is_submodule, M, left_module, first_properties, properties, nz, num_rel,
          gen_string, rel_string, rel, locked;
    
    R := HomalgRing( o );
    
    num_gen := NrGenerators( o );

    if num_gen = 0 then
        SetIsZero( o, true );
    elif not HasRankOfObject( o ) and
       HasHasInvariantBasisProperty( R ) and HasInvariantBasisProperty( R ) and
       HasNrRelations( o ) = true and NrRelations( o ) = 0 then
        
        SetRankOfObject( o, num_gen );
        SetIsFree( o, true );
    fi;
    
    ## NrGenerators might set IsZero or more generally IsFree to true
    if HasIsFree( o ) and IsFree( o ) then
        return ViewString( o );
    fi;
    
    is_submodule := IsStaticFinitelyPresentedSubobjectRep( o );
    
    if is_submodule and HasEmbeddingInSuperObject( o ) then
        M := UnderlyingObject( o );
        if HasIsZero( M ) and IsZero( M ) then
            SetIsZero( o, true );
            return ViewString( o );
        elif HasIsFree( M ) and IsFree( M ) then
            SetIsFree( o, true );
            return ViewString( o );
        fi;
    else
        M := o;
    fi;
    
    R := HomalgRing( M );
    
    left_module := IsHomalgLeftObjectOrMorphismOfLeftObjects( M );
    
    num_gen := NrGenerators( M );
    
    ## NrGenerators might set IsZero or more generally IsFree to true
    if HasIsFree( M ) and IsFree( M ) then
        return ViewString( o );
    fi;
    
    if num_gen = 1 then
        SetIsCyclic( M, true );
        num_gen := "a cyclic";
    fi;
    
    first_properties := "";
    properties := "";
    
    if HasIsCyclic( M ) and IsCyclic( M ) then
        if is_submodule then
            Append( properties, " principal" );
        else
            Append( properties, " cyclic" );
        fi;
    fi;
    
    if HasIsStablyFree( M ) and IsStablyFree( M ) then
        Append( properties, " stably free" );
        if HasIsFree( M ) and not IsFree( M ) then ## the "not"s are obsolete but kept for better readability
            Append( properties, " non-free" );
            nz := true;
        fi;
    elif HasIsProjective( M ) and IsProjective( M ) then
        Append( properties, " projective" );
        if HasIsStablyFree( M ) and not IsStablyFree( M ) then
            Append( properties, " non-stably free" );
            nz := true;
        elif HasIsFree( M ) and not IsFree( M ) then
            Append( properties, " non-free" );
            nz := true;
        fi;
    elif HasIsReflexive( M ) and IsReflexive( M ) then
        Append( properties, " reflexive" );
        if HasIsProjective( M ) and not IsProjective( M ) then
            Append( properties, " non-projective" );
            nz := true;
        elif HasIsStablyFree( M ) and not IsStablyFree( M ) then
            Append( properties, " non-stably free" );
            nz := true;
        elif HasIsFree( M ) and not IsFree( M ) then
            Append( properties, " non-free" );
            nz := true;
        fi;
    elif HasIsTorsionFree( M ) and IsTorsionFree( M ) then
        if HasCodegreeOfPurity( M ) then
            if CodegreeOfPurity( M ) = [ 1 ] then
                Append( properties, Concatenation( " codegree-", String( 1 ), "-pure" ) );
            else
                Append( properties, Concatenation( " codegree-", String( CodegreeOfPurity( M ) ), "-pure" ) );
            fi;
            if not ( HasRankOfObject( M ) and RankOfObject( M ) > 0 ) then
                first_properties := Concatenation( first_properties, " torsion-free" );
            fi;
            nz := true;
        else
            Append( properties, " torsion-free" );
            if HasIsReflexive( M ) and not IsReflexive( M ) then
                Append( properties, " non-reflexive" );
                nz := true;
            elif HasIsProjective( M ) and not IsProjective( M ) then
                Append( properties, " non-projective" );
                nz := true;
            elif HasIsStablyFree( M ) and not IsStablyFree( M ) then
                Append( properties, " non-stably free" );
                nz := true;
            elif HasIsFree( M ) and not IsFree( M ) then
                Append( properties, " non-free" );
                nz := true;
            fi;
        fi;
    fi;
    
    if HasIsTorsion( M ) and IsTorsion( M ) then
        if HasGrade( M ) then
            if HasIsPure( M ) then
                if IsPure( M ) then
                    ## only display the purity information if the global dimension of the ring is > 1:
                    if not ( left_module and HasLeftGlobalDimension( R ) and LeftGlobalDimension( R ) <= 1 ) and
                       not ( not left_module and HasRightGlobalDimension( R ) and RightGlobalDimension( R ) <= 1 ) then
                        if HasCodegreeOfPurity( M ) then
                            if CodegreeOfPurity( M ) = [ 0 ] then
                                Append( properties, " reflexively " );
                            elif CodegreeOfPurity( M ) = [ 1 ] then
                                Append( properties, Concatenation( " codegree-", String( 1 ), "-" ) );
                            else
                                Append( properties, Concatenation( " codegree-", String( CodegreeOfPurity( M ) ), "-" ) );
                            fi;
                        else
                            Append( properties, " " );
                        fi;
                        Append( properties, "pure" );
                    fi;
                else
                    Append( properties, " non-pure" );
                fi;
            fi;
            
            ## only display the grade if the global dimension of the ring is > 1:
            if ( ( left_module and HasLeftGlobalDimension( R ) and LeftGlobalDimension( R ) <= 1 ) or
                 ( not left_module and HasRightGlobalDimension( R ) and RightGlobalDimension( R ) <= 1 ) )
               and ( HasIsZero( M ) and not IsZero( M ) ) ## we actually no that IsZero( M ) = false (but anyway)
               and not ( IsBound( nz ) and nz = true ) then
                properties := Concatenation( " non-zero", properties );
                Append( properties, " torsion" );
            else
                Append( properties, " grade " );
                Append( properties, String( Grade( M ) ) );
            fi;
        else
            if HasIsPure( M ) then
                if IsPure( M ) then
                    ## only display the purity information if the global dimension of the ring is > 1:
                    if not ( left_module and HasLeftGlobalDimension( R ) and LeftGlobalDimension( R ) <= 1 ) and
                       not ( not left_module and HasRightGlobalDimension( R ) and RightGlobalDimension( R ) <= 1 ) then
                        if HasCodegreeOfPurity( M ) then
                            if CodegreeOfPurity( M ) = [ 0 ] then
                                Append( properties, " reflexively " );
                            elif CodegreeOfPurity( M ) = [ 1 ] then
                                Append( properties, Concatenation( " codegree-", String( 1 ), "-" ) );
                            else
                                Append( properties, Concatenation( " codegree-", String( CodegreeOfPurity( M ) ), "-" ) );
                            fi;
                        else
                            Append( properties, " " );
                        fi;
                        Append( properties, "pure" );
                    fi;
                else
                    Append( properties, " non-pure" );
                fi;
            elif HasIsZero( M ) and not IsZero( M ) then
                properties := Concatenation( " non-zero", properties );
            fi;
            Append( properties, " torsion" );
        fi;
    else
        if HasIsPure( M ) and not IsPure( M ) then
            Append( properties, " non-pure" );
        fi;
        if HasRankOfObject( M ) then
            Append( properties, " rank " );
            Append( properties, String( RankOfObject( M ) ) );
            if RankOfObject( M ) = 0 and HasIsZero( M ) and not IsZero( M ) then
                properties := Concatenation( " non-zero", properties );
            fi;
        elif HasIsTorsion( M ) and not IsTorsion( M ) and
          not ( HasIsPure( M ) or ( HasIsTorsionFree( M ) and IsTorsionFree( M ) ) ) then
            Append( properties, " non-torsion" );
        elif HasIsZero( M ) and not IsZero( M ) and
          not ( HasIsPure( M ) and not IsPure( M ) ) and
          not ( IsBound( nz ) and nz = true ) then
            properties := Concatenation( " non-zero", properties );
        fi;
    fi;
    
    if left_module then
        
        if IsInt( num_gen ) then
            gen_string := " generators";
        else
            gen_string := " generator";
        fi;
        
        if not is_submodule then
            if HasNrRelations( o ) = true then
                num_rel := NrRelations( o );
                if num_rel = 0 then
                    num_rel := "";
                    rel_string := "no relations for ";
                elif num_rel = 1 then
                    rel_string := " relation for ";
                else
                    rel_string := " relations for ";
                fi;
            else
                rel := RelationsOfModule( o );
                if rel = "unknown relations" then
                    num_rel := "unknown";
                elif not HasEvaluatedMatrixOfRelations( rel ) then
                    num_rel := "yet unknown";
                else
                    num_rel := "an unknown number of";
                fi;
                rel_string := " relations for ";
            fi;
        fi;
        
        if IsLockedObject( o ) then
            locked := " (locked)";
        else
            locked := "";
        fi;
        
        if is_submodule then
            if ConstructedAsAnIdeal( o ) then
                if HasIsCommutative( R ) and IsCommutative( R ) then
                    if IsBound( HOMALG.SuppressParityInViewObjForCommutativeStructureObjects )
                       and HOMALG.SuppressParityInViewObjForCommutativeStructureObjects = true then
                        return Concatenation( first_properties, properties, " ideal given by ", String( num_gen ), gen_string, locked );
                    else
                        return Concatenation( first_properties, properties, " (left) ideal given by ", String( num_gen ), gen_string, locked );
                    fi;
                else
                    return Concatenation( first_properties, properties, " left ideal given by ", String( num_gen ), gen_string, locked );
                fi;
            else
                return Concatenation( first_properties, properties, " left submodule given by ", String( num_gen ), gen_string, locked );
            fi;
        else
            return Concatenation( first_properties, properties, " left module presented by ", String( num_rel ), rel_string, String( num_gen ), gen_string, locked );
        fi;
        
    else
        
        if is_submodule then
            if IsInt( num_gen ) then
                gen_string := " generators";
            else
                gen_string := " generator";
            fi;
        else
            if IsInt( num_gen ) then
                gen_string := " generators satisfying ";
            else
                gen_string := " generator satisfying ";
            fi;
        fi;
        
        if not is_submodule then
            if HasNrRelations( o ) = true then
                num_rel := NrRelations( o );
                if num_rel = 0 then
                    num_rel := "";
                    rel_string := "no relations";
                elif num_rel = 1 then
                    rel_string := " relation";
                else
                    rel_string := " relations";
                fi;
            else
                rel := RelationsOfModule( o );
                if rel = "unknown relations" then
                    num_rel := "unknown";
                elif not HasEvaluatedMatrixOfRelations( rel ) then
                    num_rel := "yet unknown";
                else
                    num_rel := "an unknown number of";
                fi;
                rel_string := " relations";
            fi;
        fi;
        
        if IsLockedObject( o ) then
            locked := " (locked)";
        else
            locked := "";
        fi;
        
        if is_submodule then
            if ConstructedAsAnIdeal( o ) then
                if HasIsCommutative( R ) and IsCommutative( R ) then
                    if IsBound( HOMALG.SuppressParityInViewObjForCommutativeStructureObjects )
                       and HOMALG.SuppressParityInViewObjForCommutativeStructureObjects = true then
                        return Concatenation( first_properties, properties, " ideal given by ", String( num_gen ), gen_string, locked );
                    else
                        return Concatenation( first_properties, properties, " (right) ideal given by ", String( num_gen ), gen_string, locked );
                    fi;
                else
                    return Concatenation( first_properties, properties, " right ideal given by ", String( num_gen ), gen_string, locked );
                fi;
            else
                return Concatenation( first_properties, properties, " right submodule given by ", String( num_gen ), gen_string, locked );
            fi;
        else
            return Concatenation( first_properties, properties, " right module on ", String( num_gen ), gen_string, String( num_rel ), rel_string, locked );
        fi;
        
    fi;
    
end );

##
InstallMethod( ViewString,
        "for homalg modules",
        [ IsHomalgModule and IsFree ], 1001, ## since we don't use the filter IsHomalgLeftObjectOrMorphismOfLeftObjects it is good to set the ranks high
        
  function( M )
    local R, vs, result, r, rk, l, rel, num_rel;
    
    R := HomalgRing( M );
    
    vs := HasIsDivisionRingForHomalg( R ) and IsDivisionRingForHomalg( R );
    
    result := "";
    
    if vs then
        Append( result, " " );
    else
        Append( result, " free " );
    fi;
    
    if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
        Append( result, "left" );
    else
        Append( result, "right" );
    fi;
    
    if vs then
        Append( result, " vector space" );
    else
        Append( result, " module" );
    fi;
    
    r := NrGenerators( M );
    
    if r = 0 then
        SetIsZero( M, true );
        return ViewString( M );
    elif not HasRankOfObject( M ) and
      HasHasInvariantBasisProperty( R ) and HasInvariantBasisProperty( R ) and
      HasNrRelations( M ) = true and NrRelations( M ) = 0 then
        
        SetRankOfObject( M, r );
    fi;
    
    if HasRankOfObject( M ) then
        rk := RankOfObject( M );
        if vs then
            Append( result, Concatenation( " of dimension ", String( rk ) ) );
        else
            Append( result, Concatenation( " of rank ", String( rk ) ) );
        fi;
        
        Append( result, " on " );
        if r = rk then
            if r = 1 then
                Append( result, "a free generator" );
            else
                Append( result, "free generators" );
            fi;
        else ## => r > 1
            Append( result, Concatenation( String( r ), " non-free generators satisfying " ) );
            if HasNrRelations( M ) = true then
                l := NrRelations( M );
                if l = 1 then
                    Append( result, "a single relation" );
                else
                    Append( result, Concatenation( String( l ), " relations" ) );
                fi;
            else
                rel := RelationsOfModule( M );
                if rel = "unknown relations" then
                    num_rel := "unknown";
                elif not HasEvaluatedMatrixOfRelations( rel ) then
                    num_rel := "yet unknown";
                else
                    num_rel := "an unknown number of";
                fi;
                Append( result, num_rel );
                Append( result, " relations" );
            fi;
        fi;
    else
        if vs then
            Append( result, " of yet unkown dimension" );
        else
            Append( result, " of yet unkown rank" );
        fi;
        
        Append( result, Concatenation( " on ", String( r ), " generators satisfying " ) );
        if HasNrRelations( M ) = true then
            l := NrRelations( M );
            if l = 1 then
                Append( result, "a single relation" );
            else
                Append( result, Concatenation( String( l ), " relations" ) );
            fi;
        else
            rel := RelationsOfModule( M );
            if rel = "unknown relations" then
                num_rel := "unknown";
            elif not HasEvaluatedMatrixOfRelations( rel ) then
                num_rel := "yet unknown";
            else
                num_rel := "an unknown number of";
            fi;
            Append( result, num_rel );
            Append( result, " relations" );
        fi;
    fi;
    
    return result;
    
end );

##
InstallMethod( ViewString,
        "for homalg modules",
        [ IsHomalgModule and IsZero ], 1001, ## since we don't use the filter IsHomalgLeftObjectOrMorphismOfLeftObjects we need to set the ranks high
        
  function( M )
    local R, vs, result;
    
    R := HomalgRing( M );
    
    vs := HasIsDivisionRingForHomalg( R ) and IsDivisionRingForHomalg( R );
    
    result := " zero ";
    
    if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
        Append( result, "left" );
    else
        Append( result, "right" );
    fi;
    
    if vs then
        Append( result, " vector space" );
    else
        Append( result, " module" );
    fi;
    
    return result;
    
end );

##
InstallMethod( Display,
        "for homalg modules",
        [ IsFinitelyPresentedModuleRep ],
        
  function( M )
    
    Display( M, "" );
    
end );

##
InstallMethod( Display,
        "for homalg modules",
        [ IsHomalgModule, IsString ],
        
  function( M, extra_information )
    local R, l, D, esc;
    
    R := HomalgRing( M );
    
    R := RingName( R );
    
    l := 10;
    
    if Length( R ) < l then
        D := R;
    else
        D := "R";
    fi;
    
    Display( MatrixOfRelations( M ) );
    
    if extra_information <> "" then
        Print( "\n", extra_information, "\n" );
    fi;
    
    Print( "\nCokernel of the map\n\n" );
    
    if IsBound( HOMALG.color_display ) and HOMALG.color_display = true then
        esc := "\033[0m";
        if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
            Print( D, "^(1x\033[01m", NrRelations( M ), esc, ") --> ", D, "^(1x\033[01m", NrGenerators( M ), esc, ")," );
        else
            Print( D, "^(\033[01m", NrRelations( M ), esc, "x1) --> ", D, "^(\033[01m", NrGenerators( M ), esc, "x1)," );
        fi;
    else
        esc := "";
        if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
            Print( D, "^(1x", NrRelations( M ), ") --> ", D, "^(1x", NrGenerators( M ), ")," );
        else
            Print( D, "^(", NrRelations( M ), "x1) --> ", D, "^(", NrGenerators( M ), "x1)," );
        fi;
    fi;
    
    if not IsSubset( R, "a way to display" ) and not Length( R ) < l then
        Print( " ( for ", D, " := ", R, esc, " )" );
    fi;
    
    Print( "\n\ncurrently represented by the above matrix\n" );
    
end );

##
InstallMethod( Display,
        "for homalg modules",
        [ IsHomalgModule, IsString ], 1000,
        
  function( M, extra_information )
    local r, rel, R, RP, name, elements, display, rk, get_string, color;
    
    r := NrRelations( M );
    
    rel := MatrixOfRelations( M );
    
    if not NrGenerators( M ) = 1 then
        TryNextMethod( );
    fi;
    
    R := HomalgRing( M );
    
    RP := homalgTable( R );
    
    name := RingName( R );
    
    if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
        elements := List( [ 1 .. r ], i -> rel[ i, 1 ] );
    else
        elements := List( [ 1 .. r ], j -> rel[ 1, j ] );
    fi;
    
    elements := Filtered( elements, x -> not IsZero( x ) );
    
    if IsHomalgInternalRingRep( R ) then
        get_string := String;
    else
        get_string := Name;
    fi;
    
    if IsBound( HOMALG.color_display ) and HOMALG.color_display = true then
        color := true;
    else
        color := false;
    fi;
    
    if elements <> [ ] then ## this will never happen, since the below method will catch it
        if color then
            display := List( elements, x -> [ "\033[01m", get_string( x ), "\033[0m, " ] );
        else
            display := List( elements, x -> [ get_string( x ), ", " ] );
        fi;
        display := Concatenation( display );
        display := Concatenation( display );
        Print( name, "/< ", display{ [ 1 .. Length( display ) - 2 ] }, " >" );
        
        if extra_information <> "" then
            Print( " ", extra_information );
        fi;
    
    else
        Print( "something went wrong!" );
    fi;
    
    Print( "\n" );
    
end );

##
InstallMethod( Display,
        "for homalg modules",
        [ IsHomalgModule, IsString ], 1001,
        
  function( M, extra_information )
    local rel, R, RP, name, diag, display, rk, get_string, color;
    
    rel := MatrixOfRelations( M );
    
    if not HasElementaryDivisors( M ) and
       not IsDiagonalMatrix( rel ) then
        TryNextMethod( );
    fi;
    
    R := HomalgRing( M );
    
    RP := homalgTable( R );
    
    name := RingName( R );
    
    if HasElementaryDivisors( M ) then
        diag := ElementaryDivisors( M );
        rk := Length( Filtered( diag, IsZero ) );
    else
        diag := DiagonalEntries( rel );
        rk := Length( Filtered( diag, IsZero ) ) + NrGenerators( M ) - Length( diag );
    fi;
    
    ## rk is the rank if R is a domain
    
    if HasIsIntegralDomain( R ) and IsIntegralDomain( R ) and not HasRankOfObject( M ) then
        SetRankOfObject( M, rk );
    fi;
    
    diag := Filtered( diag, x -> not IsOne( x ) and not IsZero( x ) );
    
    if IsHomalgInternalRingRep( R ) then
        get_string := String;
    else
        get_string := Name;
    fi;
    
    if IsBound( HOMALG.color_display ) and HOMALG.color_display = true then
        color := true;
    else
        color := false;
    fi;
    
    if diag <> [ ] then
        if color then
            display := List( diag, x -> [ name, "/< \033[01m", get_string( x ), "\033[0m > + " ] );
        else
            display := List( diag, x -> [ name, "/< ", get_string( x ), " > + " ] );
        fi;
        display := Concatenation( display );
        display := Concatenation( display );
    else
        BasisOfModule( M );
        SetIsFree( M, true );
        display := "";
    fi;
    
    if rk <> 0 then
        if IsHomalgLeftObjectOrMorphismOfLeftObjects( M ) then
            if color then
                Print( display, name, "^(1 x", " \033[01m", rk, "\033[0m)" );
            else
                Print( display, name, "^(1 x", " ", rk, ")" );
            fi;
        else
            if color then
                Print( display, name, "^(\033[01m", rk, "\033[0m x 1)" );
            else
                Print( display, name, "^(", rk, " x 1)" );
            fi;
        fi;
    elif HasIsZero( M ) and IsZero( M ) then ## MatrixOfRelations = [ [ 1 ] ]
        Print( "0" );
    else
        Print( display{ [ 1 .. Length( display ) - 2 ] } );
    fi;
    
    if extra_information <> "" then
        Print( " ", extra_information );
    fi;
    
    Print( "\n" );
    
end );

##
InstallMethod( Display,
        "for homalg modules",
        [ IsHomalgModule and IsZero, IsString ], 2001, ## since we don't use the filter IsHomalgLeftObjectOrMorphismOfLeftObjects we need to set the ranks high
        
  function( M, extra_information )
    
    Print( 0, extra_information, "\n" );
    
end );

##
InstallMethod( Display,
        "for homalg modules",
        [ IsHomalgModule, IsString ], 3001,
        
  function( M, extra_information )
    
    if not IsBound( M!.DisplayString ) then
        TryNextMethod( );
    fi;
    
    Print( M!.DisplayString, extra_information, "\n" );
    
end );

[Dauer der Verarbeitung: 0.34 Sekunden, vorverarbeitet 2026-05-06]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge