Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
| Download
GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
Project: cocalc-sagemath-dev-slelievre
Views: 418346############################################################################# ## ## HomalgMap.gi Modules package Mohamed Barakat ## ## Copyright 2007-2010, Mohamed Barakat, University of Kaiserslautern ## ## Implementation stuff for homalg maps ( = module homomorphisms ). ## ############################################################################# ## <#GAPDoc Label="Maps:intro"> ## A &homalg; map is a data structures for maps (module homomorphisms) between finitely generated modules. ## Each map in &homalg; knows its source (&see; <Ref BookName="homalg" Attr="Source"/>) and its target ## (&see; <Ref BookName="homalg" Attr="Range"/>). A map is represented by a &homalg; matrix relative to the ## current set of generators of the source resp. target &homalg; module. As with modules ## (&see; Chapter <Ref Chap="Modules"/>), maps in &homalg; are realized in an intrinsic manner: ## If the presentations of the source or/and target module are altered after the map was constructed, ## a new adapted representation matrix of the map is automatically computed whenever needed. ## For this the internal transition matrices of the modules are used. &homalg; uses the so-called ## <E>associative</E> convention for maps. This means that maps of left modules are applied ## from the right, whereas maps of right modules from the left. ## <#/GAPDoc> #################################### # # representations: # #################################### ## <#GAPDoc Label="IsMapOfFinitelyGeneratedModulesRep"> ## <ManSection> ## <Filt Type="Representation" Arg="phi" Name="IsMapOfFinitelyGeneratedModulesRep"/> ## <Returns><C>true</C> or <C>false</C></Returns> ## <Description> ## The &GAP; representation of maps between finitley generated &homalg; modules. <P/> ## (It is a representation of the &GAP; category <Ref BookName="homalg" Filt="IsHomalgChainMorphism"/>, ## which is a subrepresentation of the &GAP; representation <C>IsStaticMorphismOfFinitelyGeneratedObjectsRep</C>.) ## </Description> ## </ManSection> ## <#/GAPDoc> ## DeclareRepresentation( "IsMapOfFinitelyGeneratedModulesRep", IsHomalgMap and IsStaticMorphismOfFinitelyGeneratedObjectsRep, [ "source", "target", "matrices", "index_pairs_of_presentations" ] ); #################################### # # families and types: # #################################### # a new family: BindGlobal( "TheFamilyOfHomalgMaps", NewFamily( "TheFamilyOfHomalgMaps" ) ); # four new types: BindGlobal( "TheTypeHomalgMapOfLeftModules", NewType( TheFamilyOfHomalgMaps, AdmissibleInputForHomalgFunctors and IsMapOfFinitelyGeneratedModulesRep and IsHomalgLeftObjectOrMorphismOfLeftObjects ) ); BindGlobal( "TheTypeHomalgMapOfRightModules", NewType( TheFamilyOfHomalgMaps, AdmissibleInputForHomalgFunctors and IsMapOfFinitelyGeneratedModulesRep and IsHomalgRightObjectOrMorphismOfRightObjects ) ); BindGlobal( "TheTypeHomalgSelfMapOfLeftModules", NewType( TheFamilyOfHomalgMaps, AdmissibleInputForHomalgFunctors and IsMapOfFinitelyGeneratedModulesRep and IsHomalgSelfMap and IsHomalgLeftObjectOrMorphismOfLeftObjects ) ); BindGlobal( "TheTypeHomalgSelfMapOfRightModules", NewType( TheFamilyOfHomalgMaps, AdmissibleInputForHomalgFunctors and IsMapOfFinitelyGeneratedModulesRep and IsHomalgSelfMap and IsHomalgRightObjectOrMorphismOfRightObjects ) ); #################################### # # methods for operations: # #################################### ## <#GAPDoc Label="HomalgRing:map"> ## <ManSection> ## <Oper Arg="phi" Name="HomalgRing"/> ## <Returns>a &homalg; ring</Returns> ## <Description> ## The &homalg; ring of the &homalg; map <A>phi</A>. ## <Example><![CDATA[ ## gap> ZZ := HomalgRingOfIntegers( ); ## Z ## gap> phi := HomalgIdentityMap( 2 * ZZ ); ## <The identity morphism of a non-zero left module> ## gap> R := HomalgRing( phi ); ## Z ## gap> IsIdenticalObj( R, ZZ ); ## true ## ]]></Example> ## </Description> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( HomalgRing, "for homalg maps", [ IsHomalgMap ], function( phi ) return HomalgRing( Source( phi ) ); end ); ## InstallMethod( homalgResetFilters, "for homalg maps", [ IsHomalgMap ], function( phi ) local property; for property in LIHOM.intrinsic_properties do ResetFilterObj( phi, ValueGlobal( property ) ); od; end ); ## provided to avoid branching in the code and always returns fail InstallMethod( PositionOfTheDefaultPresentation, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( M ) return fail; end ); ## InstallMethod( PairOfPositionsOfTheDefaultPresentations, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) local pos_s, pos_t; pos_s := PositionOfTheDefaultPresentation( Source( phi ) ); pos_t := PositionOfTheDefaultPresentation( Range( phi ) ); if IsHomalgLeftObjectOrMorphismOfLeftObjects( phi ) then return [ pos_s, pos_t ]; else return [ pos_t, pos_s ]; fi; end ); ## InstallMethod( MatrixOfMap, ## FIXME: make this optimal by finding shortest ways "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep, IsInt, IsInt ], function( phi, _pos_s, _pos_t ) local pos_s, pos_t, index_pair, l, dist, min, pos, matrix; if _pos_s < 1 then pos_s := PositionOfTheDefaultPresentation( Source( phi ) ); else pos_s := _pos_s; fi; if _pos_t < 1 then pos_t := PositionOfTheDefaultPresentation( Range( phi ) ); else pos_t := _pos_t; fi; if IsHomalgLeftObjectOrMorphismOfLeftObjects( phi ) then index_pair := [ pos_s, pos_t ]; else index_pair := [ pos_t, pos_s ]; fi; l := phi!.index_pairs_of_presentations; if not index_pair in l then dist := List( l, a -> AbsInt( index_pair[1] - a[1] ) + AbsInt( index_pair[2] - a[2] ) ); min := Minimum( dist ); pos := PositionProperty( dist, a -> a = min ); if IsHomalgLeftObjectOrMorphismOfLeftObjects( phi ) then matrix := TransitionMatrix( Source( phi ), pos_s, l[pos][1] ) * phi!.matrices.( String( l[pos] ) ) * TransitionMatrix( Range( phi ), l[pos][2], pos_t ); else matrix := TransitionMatrix( Range( phi ), pos_t, l[pos][1] ) * phi!.matrices.( String( l[pos] ) ) * TransitionMatrix( Source( phi ), l[pos][2], pos_s ); fi; phi!.matrices.( String( index_pair ) ) := matrix; Add( l, index_pair ); fi; if IsBound( phi!.reduced_matrices.( String( index_pair ) ) ) then return phi!.reduced_matrices.( String( index_pair ) ); else return phi!.matrices.( String( index_pair ) ); fi; end ); ## InstallMethod( MatrixOfMap, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep and IsHomalgSelfMap, IsPosInt ], function( phi, pos_s_t ) return MatrixOfMap( phi, pos_s_t, pos_s_t ); end ); ## InstallMethod( MatrixOfMap, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) return MatrixOfMap( phi, 0, 0 ); end ); ## InstallMethod( ZeroMutable, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) return TheZeroMorphism( Source( phi ), Range( phi ) ); end ); ## a synonym of `-<elm>': InstallMethod( AdditiveInverseMutable, "of homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) local psi; psi := MinusOne( HomalgRing( phi ) ) * phi; SetPropertiesOfAdditiveInverse( psi, phi ); # not needed because of "*" ? return psi; end ); ## InstallMethod( BasisOfModule, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) BasisOfModule( Source( phi ) ); BasisOfModule( Range( phi ) ); return phi; end ); ## InstallMethod( DecideZero, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) local rel, index_pair, matrix, reduced, zero; rel := RelationsOfModule( Range( phi ) ); index_pair := PairOfPositionsOfTheDefaultPresentations( phi ); matrix := MatrixOfMap( phi ); reduced := DecideZero( matrix, rel ); zero := IsZero( reduced ); SetIsZero( phi, zero ); if not zero then SetIsZero( Source( phi ), false ); SetIsZero( Range( phi ), false ); fi; ## replace the original matrix by the reduced one; this is important ## since we want to keep the reduced form of a matrix over a ## residue class ring, although they are ``equal'' when compared using = phi!.matrices.(String( index_pair )) := reduced; phi!.reduced_matrices.(String( index_pair )) := reduced; return phi; end ); ## InstallMethod( OnLessGenerators, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) OnLessGenerators( Source( phi ) ); OnLessGenerators( Range( phi ) ); return phi; end ); ## InstallMethod( UnionOfRelations, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) return UnionOfRelations( MatrixOfMap( phi ), Range( phi ) ); end ); ## InstallMethod( SyzygiesGenerators, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) local syz; syz := SyzygiesGenerators( MatrixOfMap( phi ), Range( phi ) ); if NrRelations( syz ) = 0 then SetIsMonomorphism( phi, true ); fi; return syz; end ); ## InstallMethod( ReducedSyzygiesGenerators, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) local syz; syz := ReducedSyzygiesGenerators( MatrixOfMap( phi ), Range( phi ) ); if NrRelations( syz ) = 0 then SetIsMonomorphism( phi, true ); fi; return syz; end ); ## InstallMethod( Preimage, "for a matrix and a homalg map", [ IsHomalgMatrix, IsMapOfFinitelyGeneratedModulesRep ], function( m, phi ) local M, rel, mat; M := Range( phi ); rel := MatrixOfRelations( M ); mat := MatrixOfMap( phi ); if IsHomalgLeftObjectOrMorphismOfLeftObjects( phi ) then return RightDivide( m, mat, rel ); else return LeftDivide( m, mat, rel ); fi; end ); ## InstallMethod( SuccessivePreimages, "for a matrix and a homalg selfmap", [ IsHomalgMatrix, IsHomalgSelfMap and IsMapOfFinitelyGeneratedModulesRep ], function( m, phi ) local preimages, pre, n; preimages := [ m ]; pre := Preimage( m, phi ); while IsHomalgMatrix( pre ) do Add( preimages, pre ); n := Length( preimages ); pre := Preimage( preimages[n], phi ); od; return preimages; end ); ## <#GAPDoc Label="PreInverse"> ## <ManSection> ## <Oper Arg="phi" Name="PreInverse"/> ## <Returns>a &homalg; map, <C>false</C>, or <C>fail</C></Returns> ## <Description> ## Compute a pre-inverse of the morphism <A>phi</A> in case one exists. ## For a pre-inverse to exist <A>phi</A> must be an epimorphism. For <E>commutative</E> rings ## &homalg; has an algorithm installed which decides the existence and returns ## a pre-inverse in case one exists. If a pre-inverse does not exist then <C>false</C> ## is returned. The algorithm finds a particular solution of a two-side inhomogeneous linear system ## over <M>R := </M><C>HomalgRing</C><M>( <A>phi</A> )</M>. ## For <E>non</E>commutative rings a heuristic method is installed. If it ## finds a pre-inverse it returns it, otherwise it returns <C>fail</C> ## (&see; <Ref Label="Modules-limitation" Text="Principal limitation"/>). ## The operation <C>PreInverse</C> is used to install a method for the property ## <Ref BookName="homalg" Prop="IsSplitEpimorphism"/>. <P/> ## <C>PreInverse</C> checks if it can decide the projectivity of <C>Range</C><M>( <A>phi</A> )</M>. ## </Description> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( PreInverse, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) local R, S, T, M, p, Ib, Ic, b, c, P, d, Id, PI, B, A, L, sigma; ## no need to search for phi!.PreInverse ## as this is not the highest priority method R := HomalgRing( phi ); if not ( HasIsCommutative( R ) and IsCommutative( R ) ) then TryNextMethod( ); fi; S := Source( phi ); T := Range( phi ); M := MatrixOfRelations( ReducedBasisOfModule( S ) ); p := MatrixOfMap( phi ); #=====# begin of the core procedure #=====# Ib := MatrixOfMap( TheIdentityMorphism( S ) ); Ic := MatrixOfMap( TheIdentityMorphism( T ) ); b := NrRows( Ib ); c := NrRows( Ic ); P := ReducedBasisOfModule( T ); d := NrRelations( P ); Id := HomalgIdentityMatrix( d, R ); P := MatrixOfRelations( P ); PI := Involution( P ); B := EntriesOfHomalgMatrix( Ic ); B := Concatenation( ListWithIdenticalEntries( b * d, Zero( R ) ), B ); if IsHomalgLeftObjectOrMorphismOfLeftObjects( phi ) then B := HomalgMatrix( B, 1, b * d + c * c, R ); A := UnionOfColumns( KroneckerMat( PI, Ib ), KroneckerMat( Ic, p ) ); L := DiagMat( [ KroneckerMat( Id, M ), KroneckerMat( Ic, P ) ] ); sigma := RightDivide( B, A, L ); else B := HomalgMatrix( B, b * d + c * c, 1, R ); A := UnionOfRows( KroneckerMat( Ib, PI ), KroneckerMat( p, Ic ) ); L := DiagMat( [ KroneckerMat( M, Id ), KroneckerMat( P, Ic ) ] ); sigma := LeftDivide( A, B, L ); fi; if IsBool( sigma ) then ## no split ## from a method below we already know that phi is an epimorphism if IsEpimorphism( phi ) then ## to be sure ;) ## so T is not projective since phi is not split SetIsProjective( T, false ); fi; phi!.PreInverse := false; return phi!.PreInverse; fi; ## we already have every thing to build the (matrix of the) split sigma sigma := EntriesOfHomalgMatrix( sigma ); if IsHomalgLeftObjectOrMorphismOfLeftObjects( phi ) then sigma := HomalgMatrix( sigma, c, b, R ); else sigma := HomalgMatrix( sigma, b, c, R ); fi; sigma := HomalgMap( sigma, T, S ); DecideZero( sigma ); Assert( 3, IsMonomorphism( sigma ) ); SetIsSplitEpimorphism( phi, true ); SetIsSplitMonomorphism( sigma, true ); ## a direct summand of a projective module is again projective [HS, I.4.5] if HasIsProjective( S ) and IsProjective( S ) then SetIsProjective( T, true ); fi; phi!.PreInverse := sigma; sigma!.PostInverse := phi; return sigma; end ); ## InstallMethod( PreInverse, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) local S, T, Id, A, L, sigma; if IsBound(phi!.PreInverse) then return phi!.PreInverse; fi; if not IsEpimorphism( phi ) then return false; elif IsIsomorphism( phi ) then ## only in case the standard method for IsIsomorphism wasn't triggered: UpdateObjectsByMorphism( phi ); sigma := phi ^ -1; phi!.PreInverse := sigma; phi!.PostInverse := sigma; sigma!.PreInverse := phi; sigma!.PostInverse := phi; return sigma; fi; DecideZero( phi ); S := Source( phi ); T := Range( phi ); Id := HomalgIdentityMatrix( NrGenerators( T ), HomalgRing( T ) ); A := MatrixOfMap( phi ); L := MatrixOfRelations( T ); if IsHomalgLeftObjectOrMorphismOfLeftObjects( phi ) then sigma := RightDivide( Id, A, L ); else sigma := LeftDivide( A, Id, L ); fi; if not IsHomalgMatrix( sigma ) then ## no split even on the level of matrices ## from above we already know that phi is an epimorphism, ## so T is not projective since phi is not split [HS, I.4.7.(3)] SetIsProjective( T, false ); phi!.PreInverse := false; return phi!.PreInverse; elif HasIsZero( sigma ) and IsZero( sigma ) then ## if the matrix is nonzero we still don't know if a split exists SetIsZero( T, true ); SetIsZero( phi, true ); sigma := TheZeroMorphism( T, S ); phi!.PreInverse := sigma; sigma!.PostInverse := phi; return sigma; fi; sigma := HomalgMap( sigma, T, S ); if IsMorphism( sigma ) then DecideZero( sigma ); Assert( 3, IsMonomorphism( sigma ) ); SetIsSplitEpimorphism( phi, true ); SetIsSplitMonomorphism( sigma, true ); ## a direct summand of a projective module is again projective [HS, I.4.5] if HasIsProjective( S ) and IsProjective( S ) then SetIsProjective( T, true ); fi; phi!.PreInverse := sigma; sigma!.PostInverse := phi; return sigma; fi; TryNextMethod( ); end ); ## InstallMethod( PostInverse, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) local S, T, A, chi; if IsBound(phi!.PostInverse) then return phi!.PostInverse; fi; if not IsMonomorphism( phi ) then return false; elif IsIsomorphism( phi ) then ## only in case the standard method for IsIsomorphism wasn't triggered: UpdateObjectsByMorphism( phi ); chi := phi ^ -1; phi!.PostInverse := chi; phi!.PreInverse := chi; chi!.PostInverse := phi; chi!.PreInverse := phi; return chi; fi; DecideZero( phi ); S := Source( phi ); T := Range( phi ); A := MatrixOfMap( phi ); if IsHomalgLeftObjectOrMorphismOfLeftObjects( phi ) then chi := RightInverse( A ); else chi := LeftInverse( A ); fi; ## a post-inverse might still exist even if Right/LeftInverse fails ## (this is fundamentally different from the situation in PreInverse) if IsBool( chi ) then TryNextMethod( ); fi; if HasIsZero( chi ) and IsZero( chi ) then ## if the matrix is nonzero we still don't know if a split exists SetIsZero( S, true ); SetIsZero( phi, true ); chi := TheZeroMorphism( T, S ); phi!.PostInverse := chi; chi!.PreInverse := phi; return chi; return TheZeroMorphism( T, S ); fi; chi := HomalgMap( chi, T, S ); if IsMorphism( chi ) then DecideZero( chi ); Assert( 3, IsEpimorphism( chi ) ); SetIsSplitMonomorphism( phi, true ); SetIsSplitEpimorphism( chi, true ); ## a direct factor of an injective module is again injective [HS, I.6.3] if HasIsInjective( T ) and IsInjective( T ) then SetIsInjective( S, true ); fi; phi!.PostInverse := chi; chi!.PreInverse := phi; return chi; fi; TryNextMethod( ); end ); ## InstallMethod( \/, "for a homalg map and a module of homomorphisms", [ IsMapOfFinitelyGeneratedModulesRep, IsFinitelyPresentedModuleRep ], function( phi, H ) local S_T, left, R, n, gen, proc, rel, map; if not FunctorOfGenesis( H ) = Functor_Hom_for_fp_modules then TryNextMethod( ); fi; S_T := Genesis( H )[1][1].arguments_of_functor; if not IsIdenticalObj( Source( phi ), S_T[1] ) or not IsIdenticalObj( Range( phi ), S_T[2] ) then return false; fi; if not IsMorphism( phi ) then return false; fi; left := IsHomalgLeftObjectOrMorphismOfLeftObjects( H ); if IsZero( phi ) then R := HomalgRing( phi ); n := NrGenerators( H ); if left then return HomalgZeroMatrix( 1, n, R ); else return HomalgZeroMatrix( n, 1, R ); fi; fi; gen := GeneratorsOfModule( H ); DecideZero( gen ); proc := ProcedureToNormalizeGenerators( gen ); rel := RelationsOfHullModule( gen ); BasisOfModule( rel ); gen := MatrixOfGenerators( H ); DecideZero( phi ); map := MatrixOfMap( phi ); map := CallFuncList( proc[1], Concatenation( [ map ], proc{[ 2 .. Length( proc ) ]} ) ); if left then ## H not phi !!! return RightDivide( map, gen, rel ); else return LeftDivide( gen, map, rel ); fi; end ); #################################### # # constructor functions and methods: # #################################### ## <#GAPDoc Label="HomalgMap"> ## <ManSection> ## <Func Arg="mat, M, N" Name="HomalgMap" Label="constructor for maps"/> ## <Func Arg="mat[, string]" Name="HomalgMap" Label="constructor for maps between free modules"/> ## <Returns>a &homalg; map</Returns> ## <Description> ## This constructor returns a map (homomorphism) of finitely presented modules. It is represented by the ## &homalg; matrix <A>mat</A> relative to the current set of generators of the source &homalg; module <A>M</A> ## and target module <A>N</A> (&see; <Ref Sect="Modules:Constructors"/>). Unless the source module is free ## <E>and</E> given on free generators the returned map will cautiously be indicated using ## parenthesis: <Q>homomorphism</Q>. To verify if the result is indeed a well defined map use ## <Ref BookName="homalg" Prop="IsMorphism"/>. If the presentations of the source or/and ## target module are altered after the map was constructed, a new adapted representation matrix of the map is ## automatically computed whenever needed. For this the internal transition matrices of the modules are used. ## If source and target are identical objects, and only then, the map is created as a selfmap (endomorphism). ## &homalg; uses the so-called <E>associative</E> convention for maps. This means that maps of left modules are ## applied from the right, whereas maps of right modules from the left. ## <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> N := HomalgMatrix( "[ 2, 3, 4, 5, 6, 7, 8, 9 ]", 2, 4, ZZ ); ## <A 2 x 4 matrix over an internal ring> ## gap> N := LeftPresentation( N ); ## <A non-torsion left module presented by 2 relations for 4 generators> ## gap> mat := HomalgMatrix( "[ \ ## > 1, 0, -2, -4, \ ## > 0, 1, 4, 7, \ ## > 1, 0, -2, -4 \ ## > ]", 3, 4, ZZ ); ## <A 3 x 4 matrix over an internal ring> ## gap> phi := HomalgMap( mat, M, N ); ## <A "homomorphism" of left modules> ## gap> IsMorphism( phi ); ## true ## gap> phi; ## <A homomorphism of left modules> ## gap> Display( phi ); ## [ [ 1, 0, -2, -4 ], ## [ 0, 1, 4, 7 ], ## [ 1, 0, -2, -4 ] ] ## ## the map is currently represented by the above 3 x 4 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> Display( phi ); ## [ [ 2, 1, 0, -1 ], ## [ 1, 0, -2, -4 ] ] ## ## the map is currently represented by the above 2 x 4 matrix ## gap> ByASmallerPresentation( N ); ## <A rank 2 left module presented by 1 relation for 3 generators> ## gap> Display( N ); ## Z/< 4 > + Z^(1 x 2) ## gap> Display( phi ); ## [ [ -8, 0, 0 ], ## [ -3, -1, -2 ] ] ## ## the map is currently represented by the above 2 x 3 matrix ## gap> ByASmallerPresentation( phi ); ## <A non-zero homomorphism of left modules> ## gap> Display( phi ); ## [ [ 0, 0, 0 ], ## [ 1, -1, -2 ] ] ## ## the map is currently represented by the above 2 x 3 matrix ## ]]></Example> ## To construct a map with source being a not yet specified free module ## <Example><![CDATA[ ## gap> N; ## <A rank 2 left module presented by 1 relation for 3 generators> ## gap> SetPositionOfTheDefaultSetOfGenerators( N, 1 ); ## gap> N; ## <A rank 2 left module presented by 2 relations for 4 generators> ## gap> psi := HomalgMap( mat, "free", N ); ## <A homomorphism of left modules> ## gap> Source( psi ); ## <A free left module of rank 3 on free generators> ## ]]></Example> ## To construct a map between not yet specified free left modules ## <Example><![CDATA[ ## gap> chi := HomalgMap( mat ); ## or chi := HomalgMap( mat, "l" ); ## <A homomorphism of left modules> ## gap> Source( chi ); ## <A free left module of rank 3 on free generators> ## gap> Range( chi ); ## <A free left module of rank 4 on free generators> ## ]]></Example> ## To construct a map between not yet specified free right modules ## <Example><![CDATA[ ## gap> kappa := HomalgMap( mat, "r" ); ## <A homomorphism of right modules> ## gap> Source( kappa ); ## <A free right module of rank 4 on free generators> ## gap> Range( kappa ); ## <A free right module of rank 3 on free generators> ## ]]></Example> ## </Description> ## </ManSection> ## <#/GAPDoc> ## InstallGlobalFunction( _HomalgMap, function( arg ) local nargs, source, pos_s, target, pos_t, R, type, matrix, left, matrices, reduced_matrices, mat, nr_rows, nr_columns, index_pair, morphism, option; nargs := Length( arg ); if IsHomalgRelations( arg[1] ) then mat := MatrixOfRelations( arg[1] ); fi; if nargs > 1 then if IsHomalgModule( arg[2] ) then source := arg[2]; pos_s := PositionOfTheDefaultPresentation( source ); elif arg[2] = "free" and nargs > 2 and IsHomalgModule( arg[3] ) and ( IsHomalgMatrix( arg[1] ) or IsHomalgRelations( arg[1] ) ) then if IsHomalgMatrix( arg[1] ) then mat := arg[1]; fi; if IsHomalgLeftObjectOrMorphismOfLeftObjects( arg[3] ) then nr_rows := NrRows( mat ); source := HomalgFreeLeftModule( nr_rows, HomalgRing( arg[3] ) ); else nr_columns := NrColumns( mat ); source := HomalgFreeRightModule( nr_columns, HomalgRing( arg[3] ) ); fi; pos_s := PositionOfTheDefaultPresentation( source ); elif IsHomalgRing( arg[2] ) and not ( IsList( arg[1] ) and nargs = 2 ) then source := "ring"; elif IsList( arg[2] ) and IsHomalgModule( arg[2][1] ) and IsPosInt( arg[2][2] ) then source := arg[2][1]; pos_s := arg[2][2]; if not IsBound( SetsOfRelations( source )!.( pos_s ) ) then Error( "the source module does not possess a ", arg[2][2], ". set of relations (this positive number is given as the second entry of the list provided as the second argument)\n" ); fi; fi; fi; if not IsBound( source ) then if IsHomalgMatrix( arg[1] ) then ResetFilterObj( arg[1], IsMutable ); matrix := arg[1]; elif IsHomalgRelations( arg[1] ) then matrix := MatrixOfRelations( arg[1] ); left := IsHomalgRelationsOfLeftModule( arg[1] ); elif IsHomalgRing( arg[nargs] ) then matrix := HomalgMatrix( arg[1], arg[nargs] ); else Error( "The second argument must be the source module or the last argument should be an IsHomalgRing\n" ); fi; R := HomalgRing( matrix ); if nargs > 1 and IsStringRep( arg[2] ) and Length( arg[2] ) > 0 and LowercaseString( arg[2]{[1..1]} ) = "r" then left := false; ## we explicitly asked for a morphism of right modules elif not IsBound( left ) then left := true; fi; if left then source := HomalgFreeLeftModule( NrRows( matrix ), R ); target := HomalgFreeLeftModule( NrColumns( matrix ), R ); type := TheTypeHomalgMapOfLeftModules; else source := HomalgFreeRightModule( NrColumns( matrix ), R ); target := HomalgFreeRightModule( NrRows( matrix ), R ); type := TheTypeHomalgMapOfRightModules; fi; matrices := rec( ); morphism := rec( matrices := matrices, reduced_matrices := rec( ), index_pairs_of_presentations := [ [ 1, 1 ] ]); matrices.( String( [ 1, 1 ] ) ) := matrix; ## Objectify: ObjectifyWithAttributes( morphism, type, Source, source, Range, target ); if ( HasNrRelations( source ) = true and NrRelations( source ) = 0 ) then SetIsMorphism( morphism, true ); fi; if HasIsZero( source ) and IsZero( source ) then SetIsGeneralizedMonomorphism( morphism, true ); ## we don't know yet if IsMorhphism( morphism ) = true fi; if HasIsZero( target ) and IsZero( target ) then SetIsGeneralizedEpimorphism( morphism, true ); ## we don't know yet if IsMorhphism( morphism ) = true fi; return morphism; fi; if nargs > 2 then if IsHomalgModule( arg[3] ) then target := arg[3]; pos_t := PositionOfTheDefaultPresentation( target ); elif arg[3] = "free" and IsHomalgModule ( source ) and ( IsHomalgMatrix( arg[1] ) or IsHomalgRelations( arg[1] ) ) then if IsHomalgLeftObjectOrMorphismOfLeftObjects( source ) then if IsHomalgMatrix( arg[1] ) then nr_columns := NrColumns( arg[1] ); elif IsHomalgRelations( arg[1] ) then nr_columns := NrColumns( MatrixOfRelations( arg[1] ) ); fi; target := HomalgFreeLeftModule( nr_columns, HomalgRing( arg[1] ) ); else if IsHomalgMatrix( arg[1] ) then nr_rows := NrRows( arg[1] ); elif IsHomalgRelations( arg[1] ) then nr_rows := NrRows( MatrixOfRelations( arg[1] ) ); fi; target := HomalgFreeRightModule( nr_rows, HomalgRing( arg[1] ) ); fi; pos_t := PositionOfTheDefaultPresentation( target ); elif IsHomalgRing( arg[3] ) then if source = "ring" then source := HomalgFreeLeftModule( 1, arg[2] ); if not IsIdenticalObj( arg[2], arg[3] ) then Error( "the source and target modules must be defined over the same ring\n" ); fi; target := source; ## we get an endomorphism pos_s := PositionOfTheDefaultPresentation( source ); pos_t := pos_s; else target := HomalgFreeLeftModule( 1, arg[3] ); pos_t := PositionOfTheDefaultPresentation( target ); fi; elif IsList( arg[3] ) and IsHomalgModule( arg[3][1] ) and IsPosInt( arg[3][2] ) then target := arg[3][1]; pos_t := arg[3][2]; if not IsBound( SetsOfRelations( target )!.( pos_t ) ) then Error( "the target module does not possess a ", arg[3][2], ". set of relations (this positive number is given as the second entry of the list provided as the third argument)\n" ); fi; fi; elif source = "ring" then source := HomalgFreeLeftModule( 1, arg[2] ); target := source; ## we get an endomorphism pos_s := PositionOfTheDefaultPresentation( source ); pos_t := pos_s; else pos_t := pos_s; fi; R := HomalgRing( source ); if IsBound( target ) and not IsIdenticalObj( source, target ) then if not IsIdenticalObj( R, HomalgRing( target ) ) then Error( "the source and target modules must be defined over the same ring\n" ); elif IsHomalgLeftObjectOrMorphismOfLeftObjects( source ) and IsHomalgLeftObjectOrMorphismOfLeftObjects( target ) then type := TheTypeHomalgMapOfLeftModules; elif IsHomalgRightObjectOrMorphismOfRightObjects( source ) and IsHomalgRightObjectOrMorphismOfRightObjects( target ) then type := TheTypeHomalgMapOfRightModules; else Error( "the source and target modules of a morphism must either both be left or both be right modules\n" ); fi; else target := source; if IsHomalgLeftObjectOrMorphismOfLeftObjects( source ) then type := TheTypeHomalgSelfMapOfLeftModules; else type := TheTypeHomalgSelfMapOfRightModules; fi; fi; if IsHomalgLeftObjectOrMorphismOfLeftObjects( source ) then nr_rows := NrGenerators( source, pos_s ); nr_columns := NrGenerators( target, pos_t ); index_pair := [ pos_s, pos_t ]; else nr_columns := NrGenerators( source, pos_s ); nr_rows := NrGenerators( target, pos_t ); index_pair := [ pos_t, pos_s ]; fi; matrices := rec( ); reduced_matrices := rec( ); morphism := rec( matrices := matrices, reduced_matrices := reduced_matrices, index_pairs_of_presentations := [ index_pair ]); if IsList( arg[1] ) and Length( arg[1] ) = 1 and IsString( arg[1][1] ) and Length( arg[1][1] ) > 0 then option := arg[1][1]; if Length( option ) > 3 and LowercaseString( option{[1..4]} ) = "zero" then ## the zero map: matrix := HomalgZeroMatrix( nr_rows, nr_columns, R ); matrices.( String( index_pair ) ) := matrix; reduced_matrices.( String( index_pair ) ) := matrix; ## Objectify: ObjectifyWithAttributes( morphism, type, Source, source, Range, target, IsZero, true ); if HasIsZero( source ) and IsZero( source ) then SetIsSplitMonomorphism( morphism, true ); fi; if HasIsZero( target ) and IsZero( target ) then SetIsSplitEpimorphism( morphism, true ); fi; elif Length( option ) > 7 and LowercaseString( option{[1..8]} ) = "identity" then ## the identity map: if nr_rows <> nr_columns then Error( "for a matrix of a morphism to be the identity matrix the number of generators of the source and target module must coincide\n" ); fi; matrix := HomalgIdentityMatrix( nr_rows, R ); matrices.( String( index_pair ) ) := matrix; if IsIdenticalObj( source, target ) then if pos_s = pos_t then ## Objectify: ObjectifyWithAttributes( morphism, type, Source, source, Range, target, IsMorphism, true, IsOne, true ); else ## Objectify: ObjectifyWithAttributes( morphism, type, Source, source, Range, target ); fi; else ## Objectify: ObjectifyWithAttributes( morphism, type, Source, source, Range, target, IsMorphism, true, IsEpimorphism, true ); fi; else Error( "wrong first argument: ", arg[1], "\n" ); fi; else if IsHomalgMatrix( arg[1] ) then if not IsIdenticalObj( HomalgRing( arg[1] ), R ) then Error( "the matrix and the modules are not defined over identically the same ring\n" ); fi; ResetFilterObj( arg[1], IsMutable ); matrix := arg[1]; elif IsHomalgRelations( arg[1] ) then if not IsIdenticalObj( HomalgRing( arg[1] ), R ) then Error( "the matrix and the modules are not defined over identically the same ring\n" ); fi; matrix := MatrixOfRelations( arg[1] ); elif IsString( arg[1] ) then if IsHomalgLeftObjectOrMorphismOfLeftObjects( source ) then nr_rows := NrGenerators( source, pos_s ); nr_columns := NrGenerators( target, pos_t ); elif IsHomalgRightObjectOrMorphismOfRightObjects( source ) then nr_rows := NrGenerators( target, pos_t ); nr_columns := NrGenerators( source, pos_s ); fi; matrix := HomalgMatrix( arg[1], nr_rows, nr_columns, R ); elif IsList( arg[1] ) then matrix := HomalgMatrix( arg[1], R ); else Error( "the first argument must be in { IsHomalgMatrix, IsHomalgRelations, IsMatrix, IsString, IsList } but received: ", arg[1], "\n" ); fi; if IsHomalgLeftObjectOrMorphismOfLeftObjects( source ) and ( NrGenerators( source, pos_s ) <> NrRows( matrix ) or NrGenerators( target, pos_t ) <> NrColumns( matrix ) ) then Error( "the dimensions of the matrix do not match the numbers of generators of the modules\n" ); elif IsHomalgRightObjectOrMorphismOfRightObjects( source ) and ( NrGenerators( source, pos_s ) <> NrColumns( matrix ) or NrGenerators( target, pos_t ) <> NrRows( matrix ) ) then Error( "the dimensions of the matrix do not match the numbers of generators of the modules\n" ); fi; matrices.( String( index_pair ) ) := matrix; ## Objectify: ObjectifyWithAttributes( morphism, type, Source, source, Range, target ); fi; if ( HasNrRelations( source ) = true and NrRelations( source ) = 0 ) then SetIsMorphism( morphism, true ); fi; if HasIsZero( source ) and IsZero( source ) then SetIsGeneralizedMonomorphism( morphism, true ); ## we don't know yet if IsMorhphism( morphism ) = true fi; if HasIsZero( target ) and IsZero( target ) then SetIsGeneralizedEpimorphism( morphism, true ); ## we don't know yet if IsMorhphism( morphism ) = true fi; return morphism; end ); ## InstallMethod( HomalgMap, "for three objects", [ IsObject, IsObject, IsObject ], _HomalgMap ); ## InstallMethod( HomalgMap, "for two objects", [ IsObject, IsObject ], _HomalgMap ); ## InstallMethod( HomalgMap, "for an object", [ IsObject ], _HomalgMap ); ## <#GAPDoc Label="HomalgZeroMap"> ## <ManSection> ## <Func Arg="M, N" Name="HomalgZeroMap" Label="constructor for zero maps"/> ## <Returns>a &homalg; map</Returns> ## <Description> ## The constructor returns the zero map between the source &homalg; module <A>M</A> ## and the target &homalg; module <A>N</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> N := HomalgMatrix( "[ 2, 3, 4, 5, 6, 7, 8, 9 ]", 2, 4, ZZ ); ## <A 2 x 4 matrix over an internal ring> ## gap> N := LeftPresentation( N ); ## <A non-torsion left module presented by 2 relations for 4 generators> ## gap> HomalgZeroMap( M, N ); ## <The zero morphism of left modules> ## ]]></Example> ## </Description> ## </ManSection> ## <#/GAPDoc> ## InstallGlobalFunction( HomalgZeroMap, function( arg ) return CallFuncList( HomalgMap, Concatenation( [ [ "zero" ] ], arg ) ); end ); ## <#GAPDoc Label="HomalgIdentityMap"> ## <ManSection> ## <Func Arg="M, N" Name="HomalgIdentityMap" Label="constructor for identity maps"/> ## <Returns>a &homalg; map</Returns> ## <Description> ## The constructor returns the identity map of the &homalg; module <A>M</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> HomalgIdentityMap( M ); ## <The identity morphism of a non-zero left module> ## ]]></Example> ## </Description> ## </ManSection> ## <#/GAPDoc> ## InstallGlobalFunction( HomalgIdentityMap, function( arg ) return CallFuncList( HomalgMap, Concatenation( [ [ "identity" ] ], arg ) ); end ); ## InstallMethod( OnAFreeSource, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) local psi; psi := HomalgMap( MatrixOfMap( phi ), "free", Range( phi ) ); if HasIsMorphism( phi ) and IsMorphism( phi ) or HasIsGeneralizedMorphismWithFullDomain( phi ) and IsGeneralizedMorphismWithFullDomain( phi ) then Assert( 3, IsMorphism( psi ) ); SetIsMorphism( psi, true ); fi; if HasIsEpimorphism( phi ) and IsEpimorphism( phi ) then Assert( 3, IsEpimorphism( psi ) ); SetIsEpimorphism( psi, true ); fi; return psi; end ); ## works without side effects InstallMethod( RemoveMorphismAid, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) return HomalgMap( MatrixOfMap( phi ), Source( phi ), Range( phi ) ); end ); ## works without side effects InstallMethod( GeneralizedMorphism, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep, IsObject ], function( phi, morphism_aid_map ) local morphism_aid_map1, psi; if not IsHomalgMap( morphism_aid_map ) and not ( IsList( morphism_aid_map ) and Length( morphism_aid_map ) = 1 and IsHomalgMap( morphism_aid_map[1] ) ) then return phi; fi; if not IsList( morphism_aid_map ) and not IsIdenticalObj( Range( phi ), Range( morphism_aid_map ) ) then Error( "the targets of the two morphisms must coincide or the aid must be a list\n" ); fi; if IsList( morphism_aid_map ) then morphism_aid_map1 := morphism_aid_map; else ## we don't need the source of the morphism aid map morphism_aid_map1 := OnAFreeSource( morphism_aid_map ); fi; ## prepare a copy of phi psi := HomalgMap( MatrixOfMap( phi ), Source( phi ), Range( phi ) ); SetMorphismAid( psi, morphism_aid_map1 ); ## some properties of the morphism phi imply ## properties for the generalized morphism psi SetPropertiesOfGeneralizedMorphism( psi, phi ); return psi; end ); ## works without side effects InstallMethod( AddToMorphismAid, "for homalg maps", [ IsHomalgMap, IsObject ], function( phi, morphism_aid_map ) local morphism_aid_map1, morphism_aid_map0; if not IsHomalgMap( morphism_aid_map ) then return phi; fi; if not IsIdenticalObj( Range( phi ), Range( morphism_aid_map ) ) then Error( "the targets of the two morphisms must coincide\n" ); fi; ## we don't need the source of the new morphism aid map morphism_aid_map1 := OnAFreeSource( morphism_aid_map ); if HasMorphismAid( phi ) then ## we don't need the source of the old morphism aid map morphism_aid_map0 := OnAFreeSource( MorphismAid( phi ) ); morphism_aid_map1 := CoproductMorphism( morphism_aid_map0, morphism_aid_map1 ); fi; return GeneralizedMorphism( phi, morphism_aid_map1 ); end ); ## InstallMethod( ShallowCopy, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( phi ) local psi; if HasMorphismAid( phi ) then TryNextMethod( ); fi; if IsHomalgEndomorphism( phi ) then psi := HomalgMap( MatrixOfMap( phi ), ShallowCopy( Source( phi ) ) ); else psi := HomalgMap( MatrixOfMap( phi ), ShallowCopy( Source( phi ) ), ShallowCopy( Range( phi ) ) ); fi; MatchPropertiesAndAttributes( phi, psi, LIHOM.intrinsic_properties, LIHOM.intrinsic_attributes ); return psi; end ); ## InstallMethod( UpdateObjectsByMorphism, "for homalg maps", [ IsHomalgMap and IsIsomorphism ], function( phi ) if HasIsZero( Source( phi ) ) or HasIsZero( Range( phi ) ) then IsZero( phi ); fi; MatchPropertiesAndAttributes( Source( phi ), Range( phi ), LIMOD.intrinsic_properties, LIMOD.intrinsic_attributes ); end ); ## InstallMethod( AnIsomorphism, "for homalg modules", [ IsFinitelyPresentedModuleRep ], function( M ) local rel, N, iso; rel := RelationsOfModule( M ); ## important since each set of relations knows the module it represents rel := ShallowCopy( rel ); N := Presentation( GeneratorsOfModule( M ), rel ); ## define the obvious isomorphism between N an M iso := HomalgIdentityMatrix( NrGenerators( M ), HomalgRing( M ) ); iso := HomalgMap( iso, N, M ); SetIsIsomorphism( iso, true ); ## copy the known properties and attributes of im to def UpdateObjectsByMorphism( iso ); return iso; end ); ## InstallMethod( Pullback, "for a ring map and a module map", [ IsHomalgRingMap, IsMapOfFinitelyGeneratedModulesRep ], function( phi, f ) local Sf, Tf, S, T, map; Sf := Source( f ); Tf := Range( f ); if IsBound( Sf!.distinguished ) and Sf!.distinguished = true then if IsHomalgLeftObjectOrMorphismOfLeftObjects( Sf ) then S := 1 * Range( phi ); else S := Range( phi ) * 1; fi; else S := Pullback( phi, Sf ); fi; if IsBound( Tf!.distinguished ) and Tf!.distinguished = true then if IsHomalgLeftObjectOrMorphismOfLeftObjects( Tf ) then T := 1 * Range( phi ); else T := Range( phi ) * 1; fi; else T := Pullback( phi, Tf ); fi; map := Pullback( phi, MatrixOfMap( f ) ); map := HomalgMap( map, S, T ); return map; end ); #################################### # # View, Print, and Display methods: # #################################### ## InstallMethod( Display, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep ], function( o ) Display( o, "" ); end ); ## InstallMethod( Display, "for homalg maps", [ IsMapOfFinitelyGeneratedModulesRep, IsString ], function( o, extra_information ) local T, mat; T := Range( o ); mat := MatrixOfMap( o ); Display( mat ); if extra_information <> "" then Print( "\nthe ", extra_information, " map is currently represented by the above ", NrRows( mat ), " x ", NrColumns( mat ), " matrix\n" ); else Print( "\nthe map is currently represented by the above ", NrRows( mat ), " x ", NrColumns( mat ), " matrix\n" ); fi; end );