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############################################################################# ## ## SparseMatrix.gi Gauss package Simon Goertzen ## ## Copyright 2007-2008 Lehrstuhl B f��r Mathematik, RWTH Aachen ## ## Implementation stuff for Gauss with sparse matrices. ## ############################################################################# ## DeclareRepresentation( "IsSparseMatrixRep", IsSparseMatrix, [ "nrows", "ncols", "indices", "entries", "ring" ] ); ## DeclareRepresentation( "IsSparseMatrixGF2Rep", IsSparseMatrix, [ "nrows", "ncols", "indices", "ring" ] ); ## BindGlobal( "TheFamilyOfSparseMatrices", NewFamily( "TheFamilyOfSparseMatrices" ) ); ## BindGlobal( "TheTypeSparseMatrix", NewType( TheFamilyOfSparseMatrices, IsSparseMatrixRep ) ); ## BindGlobal( "TheTypeSparseMatrixGF2", NewType( TheFamilyOfSparseMatrices, IsSparseMatrixGF2Rep ) ); ## <#GAPDoc Label="SparseMatrix"> ## <ManSection > ## <Func Arg="mat[, R]" Name="SparseMatrix" Label="constructor using gap matrices" /> ## <Returns>a sparse matrix over the ring <A>R</A></Returns> ## <Func Arg="nrows, ncols, indices" Name="SparseMatrix" Label="constructor using indices" /> ## <Returns>a sparse matrix over GF(2)</Returns> ## <Func Arg="nrows, ncols, indices, entries[, R]" Name="SparseMatrix" Label="constructor using indices and entries" /> ## <Returns>a sparse matrix over the ring <A>R</A></Returns> ## <Description> ## The sparse matrix constructor. ## In the one-argument form the SparseMatrix constructor converts a &GAP; matrix ## to a sparse matrix. If not provided the base ring <A>R</A> is found automatically. ## For the multi-argument form <A>nrows</A> and <A>ncols</A> are the dimensions ## of the matrix. <A>indices</A> must be a list of length <A>nrows</A> containing ## lists of the column indices of the matrix in ascending order. ## ## <Example><![CDATA[ ## gap> M := [ [ 0 , 1 ], [ 3, 0 ] ] * One( GF(2) ); ## [ [ 0*Z(2), Z(2)^0 ], [ Z(2)^0, 0*Z(2) ] ] ## gap> SM := SparseMatrix( M ); ## <a 2 x 2 sparse matrix over GF(2)> ## gap> IsSparseMatrix( SM ); ## true ## gap> Display( SM ); ## . 1 ## 1 . ## gap> SN := SparseMatrix( 2, 2, [ [ 2 ], [ 1 ] ] ); ## <a 2 x 2 sparse matrix over GF(2)> ## gap> SN = SM; ## true ## gap> SN := SparseMatrix( 2, 3, ## > [ [ 2 ], [ 1, 3 ] ], ## > [ [ 1 ], [ 3, 2 ] ] * One( GF(5) ) ); ## <a 2 x 3 sparse matrix over GF(5)> ## gap> Display( SN ); ## . 1 . ## 3 . 2 ## ]]></Example> ## </Description> ## </ManSection> ## <#/GAPDoc> ## InstallGlobalFunction( SparseMatrix, function( arg ) local nargs, M, nrows, ncols, i, j, indices, entries, ring; nargs := Length( arg ); if IsRing( arg[ nargs ] ) then ring := arg[ nargs ]; nargs := nargs - 1; fi; if nargs = 3 then return Objectify( TheTypeSparseMatrixGF2, rec( nrows := arg[1], ncols := arg[2], indices := arg[3], ring := GF(2) ) ); elif nargs = 4 then if not IsBound( ring ) then ring := FindRing( arg[4] ); fi; return Objectify( TheTypeSparseMatrix, rec( nrows := arg[1], ncols := arg[2], indices := arg[3], entries := arg[4], ring := ring ) ); elif nargs = 5 then return Objectify( TheTypeSparseMatrix, rec( nrows := arg[1], ncols := arg[2], indices := arg[3], entries := arg[4], ring := arg[5] ) ); fi; if nargs > 1 then Error( "wrong number of arguments! SparseMatrix expects nrows, ncols, indices, [entries], [ring]!" ); elif not IsList( arg[ 1 ] ) then Error( "SparseMatrix constructor with 1 argument expects a (dense) Matrix or List!" ); fi; M := arg[1]; nrows := Length( M ); if nrows = 0 then return SparseMatrix( 0, 0, [], [], "unknown" ); fi; ncols := Length( M[1] ); if ncols = 0 then return SparseMatrix( nrows, 0, List( [ 1 .. nrows ], i -> [] ), List( [ 1 .. nrows ], i -> [] ), "unknown" ); fi; if not IsBound( ring ) then ring := FindRing( List( M, i -> Filtered( i, j -> not IsZero(j) ) ) ); fi; if ring = GF(2) then indices := List( [ 1 .. nrows ], i -> Filtered( [ 1 .. ncols ], j -> IsOne( M[i][j] ) ) ); return SparseMatrix( nrows, ncols, indices ); fi; indices := []; entries := []; for i in [ 1..nrows ] do indices[i] := []; entries[i] := []; for j in [ 1..ncols ] do if not IsZero( M[i][j] ) then Add( indices[i], j ); Add( entries[i], M[i][j] ); fi; od; od; return SparseMatrix( nrows, ncols, indices, entries, ring ); end ); ## <#GAPDoc Label="ConvertSparseMatrixToMatrix"> ## <ManSection > ## <Meth Arg="sm" Name="ConvertSparseMatrixToMatrix" /> ## <Returns>a &GAP; matrix, [], or a list of empty lists</Returns> ## <Description> ## This function converts the sparse matrix <A>sm</A> into a &GAP; matrix. ## In case of <C>nrows(sm)=0</C> or <C>ncols(sm)=0</C> the return value is the ## empty list or a list of empty lists, respectively. ## <Example><![CDATA[ ## gap> M := [ [ 0 , 1 ], [ 3, 0 ] ] * One( GF(3) ); ## [ [ 0*Z(3), Z(3)^0 ], [ 0*Z(3), 0*Z(3) ] ] ## gap> SM := SparseMatrix( M ); ## <a 2 x 2 sparse matrix over GF(3)> ## gap> N := ConvertSparseMatrixToMatrix( SM ); ## [ [ 0*Z(3), Z(3)^0 ], [ 0*Z(3), 0*Z(3) ] ] ## gap> M = N; ## true ## ]]></Example> ## </Description> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( ConvertSparseMatrixToMatrix, [ IsSparseMatrix ], function( SM ) local indices, entries, i, j, ring, M; if SM!.nrows = 0 then return [ ]; elif SM!.ncols = 0 then return List( [ 1 .. SM!.nrows ], i -> [] ); fi; ring := SM!.ring; if ring = "unknown" then ring := Rationals; fi; indices := SM!.indices; entries := SM!.entries; M := NullMat( SM!.nrows, SM!.ncols, ring ); for i in [ 1 .. SM!.nrows ] do for j in [ 1 .. Length( indices[i] ) ] do M[ i ][ indices[i][j] ] := entries[i][j]; od; od; return M; end ); ## <#GAPDoc Label="CopyMat"> ## <ManSection > ## <Meth Arg="sm" Name="CopyMat" /> ## <Returns>a shallow copy of the sparse matrix <A>sm</A></Returns> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( CopyMat, [ IsSparseMatrix ], function( M ) local indices, entries, i; indices := []; entries := []; for i in [ 1 .. M!.nrows ] do indices[i] := ShallowCopy( M!.indices[i] ); entries[i] := ShallowCopy( M!.entries[i] ); od; return SparseMatrix( M!.nrows, M!.ncols, indices, entries, M!.ring ); end ); ## <#GAPDoc Label="GetEntry"> ## <ManSection > ## <Meth Arg="sm, i, j" Name="GetEntry" /> ## <Returns>a ring element.</Returns> ## <Description> ## This returns the entry <C>sm[i,j]</C> of the sparse matrix <A>sm</A> ## </Description> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( GetEntry, [ IsSparseMatrix, IsInt, IsInt ], function( M, i, j ) local p; p := PositionSet( M!.indices[i], j ); if p = fail then return Zero( M!.ring ); else return M!.entries[i][p]; fi; end ); ## <#GAPDoc Label="SetEntry"> ## <ManSection > ## <Meth Arg="sm, i, j, elm" Name="SetEntry" /> ## <Returns>nothing.</Returns> ## <Description> ## This sets the entry <C>sm[i,j]</C> of the sparse matrix <A>sm</A> to <A>elm</A>. ## </Description> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( SetEntry, [ IsSparseMatrix, IsInt, IsInt, IsRingElement ], function( M, i, j, e ) local ring, pos, res; ring := M!.ring; if not e in ring then Error( "the element has to be in ", ring, "!" ); fi; pos := PositionSorted( M!.indices[i], j ); if IsBound( M!.indices[i][pos] ) and M!.indices[i][pos] = j then if e = Zero( ring ) then Remove( M!.indices[i], pos ); Remove( M!.entries[i], pos ); else M!.entries[i][pos] := e; fi; else if e <> Zero( ring ) then Add( M!.indices[i], j, pos ); Add( M!.entries[i], e, pos ); fi; fi; end ); ## <#GAPDoc Label="AddToEntry"> ## <ManSection > ## <Meth Arg="sm, i, j, elm" Name="AddToEntry" /> ## <Returns><K>true</K> or a ring element</Returns> ## <Description> ## AddToEntry adds the element <A>elm</A> to the sparse matrix <A>sm</A> at the ## <A>(i,j)</A>-th position. This is a Method with a side effect which ## returns true if you tried to add zero or the sum of <C>sm[i,j]</C> and ## <A>elm</A> otherwise. Please use this method whenever possible. ## </Description> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( AddToEntry, [ IsSparseMatrix, IsInt, IsInt, IsRingElement ], function( M, i, j, e ) local ring, pos, res; ring := M!.ring; if not e in ring then Error( "the element has to be in ", ring, "!" ); fi; if e = Zero( ring ) then return true; fi; pos := PositionSorted( M!.indices[i], j ); if IsBound( M!.indices[i][pos] ) and M!.indices[i][pos] = j then res := M!.entries[i][pos] + e; if res = Zero( ring ) then Remove( M!.indices[i], pos ); Remove( M!.entries[i], pos ); else M!.entries[i][pos] := res; fi; return res; else Add( M!.indices[i], j, pos ); Add( M!.entries[i], e, pos ); return e; fi; end ); ############################### ## View and Display methods: ## ############################### ## InstallMethod( ViewObj, [ IsSparseMatrix ], function( M ) Print( "<a ", M!.nrows, " x ", M!.ncols, " sparse matrix over ", M!.ring, ">" ); end ); ## InstallMethod( Display, [ IsSparseMatrix ], function( M ) local str, ws, i, last, j; if M!.nrows = 0 or M!.ncols = 0 then Print( "(an empty ", M!.nrows, " x ", M!.ncols, " matrix)" ); elif Characteristic( M!.ring ) = 0 or ( HasDegreeOverPrimeField( M!.ring ) and DegreeOverPrimeField( M!.ring ) > 1 ) then Display( ConvertSparseMatrixToMatrix( M ) ); else str := ""; ws := ListWithIdenticalEntries( Length( String( Int( - One( M!.ring ) ) ) ), ' ' ); for i in [ 1 .. M!.nrows ] do last := 0; for j in [ 1 .. Length( M!.indices[i] ) ] do str := Concatenation( str, Concatenation( ListWithIdenticalEntries( M!.indices[i][j] - 1 - last, Concatenation( ws, "." ) ) ), ws{ [ 1 .. Length( ws ) + 1 - Length( String( Int( M!.entries[i][j] ) ) ) ] }, String( Int( M!.entries[i][j] ) ) ); last := M!.indices[i][j]; od; str := Concatenation( str, Concatenation( ListWithIdenticalEntries( M!.ncols - last, Concatenation( ws, "." ) ) ), "\n" ); od; Print( str ); fi; end ); ## InstallMethod( PrintObj, [ IsSparseMatrix ], function( M ) Print( "SparseMatrix( ", M!.nrows, ", ", M!.ncols, ", ", M!.indices, ", ", M!.entries, ", ", M!.ring, " )" ); end ); ############################### ## InstallMethod( FindRing, [ IsList ], function( entries ) local found_ring, i, ring; found_ring := false; i := 1; while found_ring = false and i <= Length( entries ) do if IsBound( entries[i][1] ) then ring := DefaultRing( entries[i][1] ); found_ring := true; fi; i := i + 1; od; if found_ring = true then return ring; else return "unknown"; fi; end ); ## <#GAPDoc Label="SparseZeroMatrix"> ## <ManSection > ## <Func Arg="nrows[, ring]" Name="SparseZeroMatrix" Label="constructor using number of rows" /> ## <Returns>a sparse <<A>nrows</A> x <A>nrows</A>> zero matrix over the ring <A>ring</A></Returns> ## <Func Arg="nrows, ncols[, ring]" Name="SparseZeroMatrix" Label="constructor using number of rows and columns"/> ## <Returns>a sparse <<A>nrows</A> x <A>ncols</A>> zero matrix over the ring <A>ring</A></Returns> ## </ManSection> ## <#/GAPDoc> ## InstallGlobalFunction( SparseZeroMatrix, function( arg ) local nargs, ring; nargs := Length( arg ); if IsRing( arg[ nargs ] ) or arg[ nargs ] = "unknown" then ring := arg[ Length( arg ) ]; nargs := nargs - 1; else ring := "unknown"; fi; if ring = GF(2) then if nargs = 1 then return SparseMatrix( arg[1], arg[1], List( [ 1 .. arg[1] ], i -> [] ) ); elif nargs = 2 then return SparseMatrix( arg[1], arg[2], List( [ 1 .. arg[1] ], i -> [] ) ); fi; elif nargs = 1 then return SparseMatrix( arg[1], arg[1], List( [ 1 .. arg[1] ], i -> [] ), List( [ 1 .. arg[1] ], i -> [] ), ring ); elif nargs = 2 then return SparseMatrix( arg[1], arg[2], List( [ 1 .. arg[1] ], i -> [] ), List( [ 1 .. arg[1] ], i -> [] ), ring ); fi; Error( "wrong number of arguments in SparseZeroMatrix!" ); end ); ## <#GAPDoc Label="SparseIdentityMatrix"> ## <ManSection > ## <Func Arg="dim[, ring]" Name="SparseIdentityMatrix" /> ## <Returns>a sparse <<A>dim</A> x <A>dim</A>> identity matrix over the ring <A>ring</A>. ## If no ring is specified (one should try to avoid this if possible) ## the Rationals are the default ring.</Returns> ## </ManSection> ## <#/GAPDoc> ## InstallGlobalFunction( SparseIdentityMatrix, function( arg ) local nargs, ring, indices, entries; nargs := Length( arg ); if IsRing( arg[ nargs ] ) then ring := arg[ Length( arg ) ]; nargs := nargs - 1; else ring := Rationals; fi; if nargs = 1 then indices := List( [ 1 .. arg[1] ], i -> [i] ); if ring = GF(2) then return SparseMatrix( arg[1], arg[1], indices ); else entries := List( [ 1 .. arg[1] ], i -> [ One( ring ) ] ); return SparseMatrix( arg[1], arg[1], indices, entries, ring ); fi; else Error( "wrong number of arguments in SparseIdentityMatrix!" );; fi; end ); ## InstallMethod( \=, [ IsSparseMatrix, IsSparseMatrix ], function( A, B ) return A!.nrows = B!.nrows and A!.ncols = B!.ncols and A!.ring = B!.ring and A!.indices = B!.indices and A!.entries = B!.entries; end ); ## <#GAPDoc Label="TransposedSparseMat"> ## <ManSection > ## <Meth Arg="sm" Name="TransposedSparseMat" /> ## <Returns>the transposed matrix of the sparse matrix <A>sm</A></Returns> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( TransposedSparseMat, [ IsSparseMatrix ], function( M ) local T, i, j; T := SparseZeroMatrix( M!.ncols, M!.nrows, M!.ring ); for i in [ 1 .. M!.nrows ] do for j in [ 1 .. Length( M!.indices[i] ) ] do Add( T!.indices[ M!.indices[i][j] ], i ); Add( T!.entries[ M!.indices[i][j] ], M!.entries[i][j] ); od; od; return T; end ); ## <#GAPDoc Label="CertainRows"> ## <ManSection > ## <Meth Arg="sm, list" Name="CertainRows" /> ## <Returns>the submatrix <C>sm{[list]}</C> as a sparse matrix</Returns> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( CertainRows, [ IsSparseMatrix, IsList ], function( M, L ) return SparseMatrix( Length( L ), M!.ncols, M!.indices{ L }, M!.entries{ L }, M!.ring ); end ); ## <#GAPDoc Label="CertainColumns"> ## <ManSection > ## <Meth Arg="sm, list" Name="CertainColumns" /> ## <Returns>the submatrix <C>sm{[1..nrows(sm)]}{[list]}</C> as a sparse matrix</Returns> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( CertainColumns, [ IsSparseMatrix, IsList ], function( M, L ) local indices, entries, list, i, j, column, p; indices := List( [ 1 .. M!.nrows ], i -> [] ); entries := List( [ 1 .. M!.nrows ], i -> [] ); for i in [ 1 .. M!.nrows ] do for j in [ 1 .. Length( L ) ] do column := L[j]; p := PositionSet( M!.indices[i], column); if p <> fail then Add( indices[i], j ); Add( entries[i], M!.entries[i][p] ); fi; od; od; return SparseMatrix( M!.nrows, Length( L ), indices, entries, M!.ring ); end ); ## <#GAPDoc Label="UnionOfRows"> ## <ManSection > ## <Meth Arg="A, B" Name="UnionOfRows" /> ## <Returns>the row union of the sparse matrices <A>A</A> and <A>B</A></Returns> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( UnionOfRows, [ IsSparseMatrix, IsSparseMatrix ], function( A, B ) return SparseMatrix( A!.nrows + B!.nrows, A!.ncols, Concatenation( A!.indices, B!.indices ), Concatenation( A!.entries, B!.entries ), A!.ring ); end ); ## <#GAPDoc Label="UnionOfColumns"> ## <ManSection > ## <Meth Arg="A, B" Name="UnionOfColumns" /> ## <Returns>the column union of the sparse matrices <A>A</A> and <A>B</A></Returns> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( UnionOfColumns, [ IsSparseMatrix, IsSparseMatrix ], function( A, B ) return SparseMatrix( A!.nrows, A!.ncols + B!.ncols, List( [ 1 .. A!.nrows ], i -> Concatenation( A!.indices[i], B!.indices[i] + A!.ncols ) ), List( [ 1 .. A!.nrows ], i -> Concatenation( A!.entries[i], B!.entries[i] ) ), A!.ring ); end ); ## <#GAPDoc Label="SparseDiagMat"> ## <ManSection > ## <Func Arg="list" Name="SparseDiagMat" /> ## <Returns>the block diagonal matrix composed of the ## sparse matrices in <A>list</A></Returns> ## </ManSection> ## <#/GAPDoc> ## InstallGlobalFunction( SparseDiagMat, function( e ) if Length( e ) = 1 then return e[1]; elif Length( e ) > 2 then return SparseDiagMat( Concatenation( [ SparseDiagMat( e{[1,2]} ) ], e{[ 3 .. Length( e ) ]} ) ); else if IsSparseMatrixGF2Rep( e[1] ) then return SparseMatrix( e[1]!.nrows + e[2]!.nrows, e[1]!.ncols + e[2]!.ncols, Concatenation( e[1]!.indices, e[2]!.indices + e[1]!.ncols ) ); else return SparseMatrix( e[1]!.nrows + e[2]!.nrows, e[1]!.ncols + e[2]!.ncols, Concatenation( e[1]!.indices, e[2]!.indices + e[1]!.ncols ), Concatenation( e[1]!.entries, e[2]!.entries ), e[1]!.ring ); fi; fi; end ); ## InstallMethod( \*, [ IsSparseMatrix, IsRingElement ], function( A, a ) local i, m; if IsZero( a ) then return SparseZeroMatrix( A!.nrows, A!.ncols, A!.ring ); else return SparseMatrix( A!.nrows, A!.ncols, A!.indices, A!.entries * a, A!.ring ); fi; end ); ## InstallMethod( \*, [ IsRingElement, IsSparseMatrix ], function( a, A ) local i, m; if IsZero( a ) then return SparseZeroMatrix( A!.nrows, A!.ncols, A!.ring ); else return SparseMatrix( A!.nrows, A!.ncols, A!.indices, A!.entries * a, A!.ring ); fi; end ); ## InstallMethod( \*, [ IsSparseMatrix, IsSparseMatrix ], function( A, B ) local C, i, j, rownr, m; if A!.ncols <> B!.nrows or A!.ring <> B!.ring then return fail; fi; C := SparseZeroMatrix( A!.nrows, B!.ncols, A!.ring ); for i in [ 1 .. C!.nrows ] do for j in [ 1 .. Length( A!.indices[i] ) ] do rownr := A!.indices[i][j]; m := MultRow( B!.indices[ rownr ], B!.entries[ rownr ], A!.entries[i][j] ); AddRow( m.indices, m.entries, C!.indices, C!.entries, i ); od; od; return C; end ); ## InstallMethod( \+, [ IsSparseMatrix, IsSparseMatrix ], function( A, B ) local C, i; C := CopyMat( A ); for i in [ 1 .. C!.nrows ] do AddRow( B!.indices[i], B!.entries[i], C!.indices, C!.entries, i ); od; return C; end ); ## InstallMethod( \-, [ IsSparseMatrix, IsSparseMatrix ], function( A, B ) return A + ( - One( B!.ring ) ) * B; end ); InstallOtherMethod( AINV_MUT,# strangely, doesn't have the filters for arith.op [IsSparseMatrix], function(A) return SparseMatrix( A!.nrows, A!.ncols, A!.indices, -A!.entries, A!.ring ); end); InstallOtherMethod(ComplexConjugate, [IsSparseMatrix], function(A) return SparseMatrix(A!.nrows,A!.ncols,A!.indices,ComplexConjugate(A!.entries),A!.ring); end); # no need to give it a new name -- here make the usual one available InstallOtherMethod(TransposedMat, [IsSparseMatrix], TransposedSparseMat); ## <#GAPDoc Label="Nrows"> ## <ManSection > ## <Meth Arg="sm" Name="Nrows" /> ## <Returns>the number of rows of the sparse matrix <A>sm</A>. ## This should be preferred to the equivalent <C>sm!.nrows</C>.</Returns> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( Nrows, [ IsSparseMatrix ], function( M ) return M!.nrows; end ); ## <#GAPDoc Label="Ncols"> ## <ManSection > ## <Meth Arg="sm" Name="Ncols" /> ## <Returns>the number of columns of the sparse matrix <A>sm</A>. ## This should be preferred to the equivalent <C>sm!.ncols</C>.</Returns> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( Ncols, [ IsSparseMatrix ], function( M ) return M!.ncols; end ); ## <#GAPDoc Label="IndicesOfSparseMatrix"> ## <ManSection > ## <Meth Arg="sm" Name="IndicesOfSparseMatrix" /> ## <Returns>the indices of the sparse matrix <A>sm</A> as a ListList. ## This should be preferred to the equivalent <C>sm!.indices</C>.</Returns> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( IndicesOfSparseMatrix, [ IsSparseMatrix ], function( M ) return M!.indices; end ); ## <#GAPDoc Label="EntriesOfSparseMatrix"> ## <ManSection > ## <Meth Arg="sm" Name="EntriesOfSparseMatrix" /> ## <Returns>the entries of the sparse matrix <A>sm</A> as a ListList of ring elements. ## This should be preferred to the equivalent <C>sm!.entries</C> and has the additional ## advantage of working for sparse matrices over GF(2) which do not have any entries.</Returns> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( EntriesOfSparseMatrix, [ IsSparseMatrix ], function( M ) if IsSparseMatrixGF2Rep( M ) then return List( M!.indices, row -> ListWithIdenticalEntries( Length( row ), One( GF(2) ) ) ); else return M!.entries; fi; end ); ## <#GAPDoc Label="RingOfDefinition"> ## <ManSection > ## <Meth Arg="sm" Name="RingOfDefinition" /> ## <Returns>the base ring of the sparse matrix <A>sm</A>. ## This should be preferred to the equivalent <C>sm!.ring</C>.</Returns> ## </ManSection> ## <#/GAPDoc> ## InstallMethod( RingOfDefinition, [ IsSparseMatrix ], function( M ) return M!.ring; end ); ## InstallMethod( IsSparseZeroMatrix, [ IsSparseMatrix ], function( M ) return List( [ 1 .. Length( M!.indices ) ], i -> Length( M!.indices[i] ) ) = List( [ 1 .. Length( M!.indices ) ], i -> 0 ); end ); ## InstallMethod( IsSparseIdentityMatrix, [ IsSparseMatrix ], function( M ) local one, i; one := One( M!.ring ); for i in [ 1 .. M!.nrows ] do if M!.indices[i] <> [i] or M!.entries[i] <> [ one ] then return false; fi; od; return true; end ); ## InstallMethod( IsSparseDiagonalMatrix, [ IsSparseMatrix ], function( M ) local i; for i in [ 1 .. M!.nrows ] do if M!.indices[i] <> [i] then return false; fi; od; return true; end ); ## InstallMethod( SparseKroneckerProduct, [ IsSparseMatrix, IsSparseMatrix ], function( A, B ) local indices, entries, i1, i2, rowindex, j1, j2, prod; indices := []; entries := []; for i1 in [ 1 .. A!.nrows ] do for i2 in [ 1 .. B!.nrows ] do rowindex := ( i1 - 1 ) * B!.nrows + i2; indices[ rowindex ] := []; entries[ rowindex ] := []; for j1 in [ 1 .. Length( A!.indices[i1] ) ] do for j2 in [ 1.. Length( B!.indices[i2] ) ] do prod := A!.entries[i1][j1] * B!.entries[i2][j2]; if not IsZero( prod ) then Add( indices[ rowindex ], ( A!.indices[i1][j1] - 1 ) * B!.ncols + B!.indices[i2][j2] ); Add( entries[ rowindex ], prod ); fi; od; od; od; od; return SparseMatrix( A!.nrows * B!.nrows, A!.ncols * B!.ncols, indices, entries, A!.ring ); end ); ## InstallMethod( SparseZeroRows, [ IsSparseMatrix ], function( M ) return Filtered( [ 1 .. M!.nrows ], i -> Length( M!.indices[i] ) = 0 ); end ); ## InstallMethod( SparseZeroColumns, [ IsSparseMatrix ], function( M ) return Difference( [ 1 .. M!.ncols ], Union( M!.indices ) ); end ); ## InstallMethod( MultRow, #no side effect! [ IsList, IsList, IsRingElement ], function( indices, entries, x ) local prod, list; if IsUnit( x ) then return rec( indices := indices, entries := entries * x ); else prod := entries * x; list := Filtered( [ 1 .. Length( prod ) ], i -> not IsZero( prod[i] ) ); return rec( indices := indices{ list }, entries := prod{ list } ); fi; end ); InstallOtherMethod(AddRow,[IsList,IsList,IsList,IsList,IsInt], function (row1_indices, row1_entries, p_sum_indices, p_sum_entries, i) # (row1_indices, row1_entries) is row1 # (p_sum_indices[i], p_sum_entries[i]) is row2 # modifies p_sum_indices[i] and p_sum_entriesi[] to make them equal row1 + row2 local pos1, pos2, len1, len2, row2_indices, row2_entries, sum_indices, sum_entries, index1, index2, s; len1 := Length(row1_indices); if len1 = 0 then return; fi; row2_indices := p_sum_indices[i]; row2_entries := p_sum_entries[i]; len2 := Length(row2_indices); pos1 := 1; pos2 := 1; p_sum_indices[i] := []; sum_indices := p_sum_indices[i]; p_sum_entries[i] := []; sum_entries := p_sum_entries[i]; while true do if pos1 > len1 then Append(sum_indices, row2_indices{[pos2..len2]}); Append(sum_entries, row2_entries{[pos2..len2]}); return; fi; if pos2 > len2 then Append(sum_indices, row1_indices{[pos1..len1]}); Append(sum_entries, row1_entries{[pos1..len1]}); return; fi; index1 := row1_indices[pos1]; index2 := row2_indices[pos2]; if index1 > index2 then Add(sum_indices, index2); Add(sum_entries, row2_entries[pos2]); pos2 := pos2 + 1; elif index1 < index2 then Add(sum_indices, index1); Add(sum_entries, row1_entries[pos1]); pos1 := pos1 + 1; else s := row1_entries[pos1] + row2_entries[pos2]; if not IsZero(s) then Add(sum_indices, index1); Add(sum_entries, s); fi; pos1 := pos1 + 1; pos2 := pos2 + 1; fi; od; end); ## InstallMethod( AddRow, #with desired side effect! [ IsList, IsList, IsList, IsList ], function( row1_indices, row1_entries, row2_indices, row2_entries ) local m, zero, j, i, index1, index2; m := Length( row1_indices ); if m = 0 then return rec( indices := row2_indices, entries := row2_entries ); fi; zero := Zero( row1_entries[1] ); i := 1; j := 1; while i <= m do if j > Length( row2_indices ) then Append( row2_indices, row1_indices{[ i .. m ]} ); Append( row2_entries, row1_entries{[ i .. m ]} ); break; fi; index1 := row1_indices[i]; index2 := row2_indices[j]; if index1 > index2 then j := j + 1; elif index1 < index2 then Add( row2_indices, index1, j ); Add( row2_entries, row1_entries[i], j ); i := i + 1; elif index1 = index2 then row2_entries[j] := row2_entries[j] + row1_entries[i]; if row2_entries[j] = zero then Remove( row2_entries, j ); Remove( row2_indices, j ); fi; i := i + 1; fi; od; return rec( indices := row2_indices, entries := row2_entries ); end );