home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-05-05 | 39.3 KB | 1,443 lines |
- #############################################################################
- ##
- #A matrix.g GAP library Martin Schoenert
- ##
- #A @(#)$Id: matrix.g,v 3.22 1993/02/16 12:39:55 sam Rel $
- ##
- #Y Copyright 1990-1992, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
- ##
- ## This file contains those functions that mainly deal with matrices.
- ##
- #H $Log: matrix.g,v $
- #H Revision 3.22 1993/02/16 12:39:55 sam
- #H allowed '[]' as arguments in 'TriangulizeMat' etc.
- #H (although '[]' is not a matrix in the sense of GAP)
- #H
- #H Revision 3.21 1993/01/22 12:10:53 fceller
- #H fixed 'NullMat' and 'IdentityMat' to allow ring argument
- #H
- #H Revision 3.20 1993/01/20 18:25:25 sam
- #H moved added functions to directory grp ...
- #H
- #H Revision 3.19 1993/01/18 17:18:58 sam
- #H added GL, SL, SP, GU, SU in 'MatricesOps'
- #H
- #H Revision 3.18 1992/12/16 19:47:27 martin
- #H replaced quoted record names with escaped ones
- #H
- #H Revision 3.17 1992/11/25 13:41:51 fceller
- #H improved 'MinimalPolynomial' (this is due to CRLG and EOB)
- #H
- #H Revision 3.16 1992/10/19 14:08:50 fceller
- #H renamed 'WeightVecFFE' to 'DepthVector'
- #H
- #H Revision 3.15 1992/09/10 11:14:47 martin
- #H changed 'DiagonalizeMat' to use a better pivoting strategy
- #H
- #H Revision 3.14 1992/07/02 11:48:20 fceller
- #H improved 'FiniteFieldMatricesOps.*Polynomial'
- #H
- #H Revision 3.13 1992/07/01 11:39:07 fceller
- #H added 'FiniteFieldMatricesOps.MinimalPolynomial' and
- #H 'FiniteFieldMatricesOps.CharacteristicPolynomial'
- #H
- #H Revision 3.12 1992/06/05 09:53:08 fceller
- #H added dispatchers for minimal and characteristic polynomial
- #H
- #H Revision 3.11 1992/05/07 11:03:15 fceller
- #H added 'OrderScalar'
- #H
- #H Revision 3.10 1992/04/23 10:34:46 fceller
- #H added functions for finite field matrices
- #H
- #H Revision 3.9 1992/04/07 16:15:32 jmnich
- #H adapted to changes in the finite field module
- #H
- #H Revision 3.8 1992/04/03 16:25:56 martin
- #H fixed 'MatricesOps.in'
- #H
- #H Revision 3.7 1992/02/19 12:36:28 martin
- #H fixed another bug in 'NullspaceMat'
- #H
- #H Revision 3.6 1992/01/29 14:58:42 sam
- #H changed 'TransposedMat' (does no longer abuse 'Add')
- #H
- #H Revision 3.5 1992/01/16 12:57:00 martin
- #H changed 'Matrices' to inherit from 'GroupElements'
- #H
- #H Revision 3.4 1991/12/04 13:25:13 martin
- #H added 'KroneckerProduct'
- #H
- #H Revision 3.3 1991/11/08 16:13:41 martin
- #H changed 'matrix.g' to read 'matgrp.g' and 'matring.g' automatically
- #H
- #H Revision 3.2 1991/11/08 15:56:11 martin
- #H changed everything for new domain concept
- #H
- #H Revision 3.1 1991/06/03 10:47:23 fceller
- #H added 'Solution'
- #H
- #H Revision 3.0 1991/05/31 13:48:28 martin
- #H initial revision under RCS
- ##
-
-
- #############################################################################
- ##
- #F InfoMatrix1(...) . . . . . . . . . . . information function for matrices
- #F InfoMatrix2(...) . . . . . . . . . . . information function for matrices
- ##
- if not IsBound(InfoMatrix1) then InfoMatrix1 := Ignore; fi;
- if not IsBound(InfoMatrix2) then InfoMatrix2 := Ignore; fi;
-
-
- #############################################################################
- ##
- #V Matrices . . . . . . . . . . . . . . . . . . . . domain of all matrices
- #V MatricesOps . . . . . . . operation record of the domain of all matrices
- ##
- MatricesOps := Copy( GroupElementsOps );
-
- Matrices := rec(
- isDomain := true,
-
- name := "Matrices",
-
- isFinite := false,
- size := "infinity",
-
- operations := MatricesOps
- );
-
- MatricesOps.\in := function ( obj, Matrices )
- return IsMat( obj );
- end;
-
-
- #############################################################################
- ##
- #F MatricesOps.SpecialLinearGroup( Matrices, <n>, <q> )
- #F MatricesOps.GeneralLinearGroup( Matrices, <n>, <q> )
- #F MatricesOps.SymplecticGroup( Matrices, <n>, <q> )
- #F MatricesOps.GeneralUnitaryGroup( Matrices, <n>, <q> )
- #F MatricesOps.SpecialUnitaryGroup( Matrices, <n>, <q> )
- ##
- MatricesOps.SpecialLinearGroup := function ( M, n, q )
- return MatGroupLib( "SpecialLinearGroup", n, q );
- end;
-
- MatricesOps.GeneralLinearGroup := function ( M, n, q )
- return MatGroupLib( "GeneralLinearGroup", n, q );
- end;
-
- MatricesOps.SymplecticGroup := function ( M, n, q )
- return MatGroupLib( "SymplecticGroup", n, q );
- end;
-
- MatricesOps.GeneralUnitaryGroup := function ( M, n, q )
- return MatGroupLib( "GeneralUnitaryGroup", n, q );
- end;
-
- MatricesOps.SpecialUnitaryGroup := function ( M, n, q )
- return MatGroupLib( "SpecialUnitaryGroup", n, q );
- end;
-
-
- #############################################################################
- ##
- #F DimensionsMat( <mat> ) . . . . . . . . . . . . . dimensions of a matrix
- ##
- DimensionsMat := function ( mat )
- return [ Length(mat), Length(mat[1]) ];
- end;
-
-
- #############################################################################
- ##
- #F IdentityMat( <m> [, <F>] ) . . . . . . . identity matrix of a given size
- ##
- IdentityMat := function ( arg )
- local id, m, zero, one, row, i, k;
-
- # check the arguments and get dimension, zero and one
- if Length(arg) = 1 then
- m := arg[1];
- zero := 0;
- one := 1;
- elif Length(arg) = 2 and IsField(arg[2]) then
- m := arg[1];
- zero := arg[2].zero;
- one := arg[2].one;
- elif Length(arg) = 2 and IsRing(arg[2]) then
- if not IsBound(arg[2].one) then
- Error( "ring must be a ring-with-one" );
- fi;
- m := arg[1];
- zero := arg[2].zero;
- one := arg[2].one;
- elif Length(arg) = 2 then
- m := arg[1];
- zero := arg[2] - arg[2];
- one := arg[2] ^ 0;
- else
- Error("usage: IdentityMat( <m> [, <F>] )");
- fi;
-
- # make an empty row
- row := [];
- for k in [1..m] do row[k] := zero; od;
-
- # make the identity matrix
- id := [];
- for i in [1..m] do
- id[i] := ShallowCopy( row );
- id[i][i] := one;
- od;
-
- # return the identity matrix
- return id;
- end;
-
-
- #############################################################################
- ##
- #F NullMat( <m>, <n> [, <F>] ) . . . . . . . . . null matrix of a given size
- ##
- NullMat := function ( arg )
- local null, m, n, zero, row, i, k;
-
- if Length(arg) = 2 then
- m := arg[1];
- n := arg[2];
- zero := 0;
- elif Length(arg) = 3 and IsField(arg[3]) then
- m := arg[1];
- n := arg[2];
- zero := arg[3].zero;
- elif Length(arg) = 3 and IsRing(arg[3]) then
- m := arg[1];
- n := arg[2];
- zero := arg[3].zero;
- elif Length(arg) = 3 then
- m := arg[1];
- n := arg[2];
- zero := arg[3] - arg[3];
- else
- Error("usage: NullMat( <m>, <n> [, <F>] )");
- fi;
-
- # make an empty row
- row := [];
- for k in [1..n] do row[k] := zero; od;
-
- # make the null matrix
- null := [];
- for i in [1..m] do
- null[i] := ShallowCopy( row );
- od;
-
- # return the null matrix
- return null;
- end;
-
-
- #############################################################################
- ##
- #F RandomMat( <m>, <n> [, <R>] ) . . . . . . . . . . . make a random matrix
- ##
- ## 'RandomMat' returns a random matrix with <m> rows and <n> columns with
- ## elements taken from the ring <R>, which defaults to 'Integers'.
- ##
- RandomMat := function ( arg )
- local mat, m, n, R, i, row, k;
-
- # check the arguments and get the list of elements
- if Number(arg) = 2 then
- m := arg[1];
- n := arg[2];
- R := Integers;
- elif Number(arg) = 3 then
- m := arg[1];
- n := arg[2];
- R := arg[3];
- else
- Error("usage: RandomMat( <m>, <n> [, <F>] )");
- fi;
-
- # now construct the random matrix
- mat := [];
- for i in [1..m] do
- row := [];
- for k in [1..n] do
- row[k] := Random( R );
- od;
- mat[i] := row;
- od;
-
- return mat;
- end;
-
-
- #############################################################################
- ##
- #F RandomInvertableMat( <m> [, <R>] ) . . . make a random invertable matrix
- ##
- ## 'RandomInvertableMat' returns a invertable random matrix with <m> rows
- ## and columns with elements taken from the ring <R>, which defaults to
- ## 'Integers'.
- ##
- RandomInvertableMat := function ( arg )
- local mat, m, R, i, row, k;
-
- # check the arguments and get the list of elements
- if Number(arg) = 1 then
- m := arg[1];
- R := Integers;
- elif Length(arg) = 2 then
- m := arg[1];
- R := arg[2];
- else
- Error("usage: RandomInvertableMat( <m> [, <R>] )");
- fi;
-
- # now construct the random matrix
- mat := [];
- for i in [1..m] do
- repeat
- row := [];
- for k in [1..m] do
- row[k] := Random( R );
- od;
- mat[i] := row;
- until NullspaceMat( mat ) = [];
- od;
-
- return mat;
- end;
-
-
- #############################################################################
- ##
- #F RandomUnimodularMat( <m> ) . . . . . . . . . . random unimodular matrix
- ##
- RandomUnimodularMat := function ( m )
- local mat, c, i, j, k, l, a, b, v, w, gcd;
-
- # start with the identity matrix
- mat := IdentityMat( m );
-
- for c in [1..m] do
-
- # multiply two random rows with a random? unimodular 2x2 matrix
- i := RandomList([1..m])+1;
- repeat
- j := RandomList([1..m])+1;
- until j <> i;
- repeat
- a := Random( Integers ); b := Random( Integers );
- gcd := Gcdex( a, b );
- until gcd.gcd = 1;
- v := mat[i]; w := mat[j];
- mat[i] := gcd.coeff1 * v + gcd.coeff2 * w;
- mat[j] := gcd.coeff3 * v + gcd.coeff4 * w;
-
- # multiply two random cols with a random? unimodular 2x2 matrix
- k := RandomList([1..m])+1;
- repeat
- l := RandomList([1..m])+1;
- until l <> k;
- repeat
- a := Random( Integers ); b := Random( Integers );
- gcd := Gcdex( a, b );
- until gcd.gcd = 1;
- for i in [1..m] do
- v := mat[i][k]; w := mat[i][l];
- mat[i][k] := gcd.coeff1 * v + gcd.coeff2 * w;
- mat[i][l] := gcd.coeff3 * v + gcd.coeff4 * w;
- od;
-
- od;
-
- return mat;
- end;
-
-
- #############################################################################
- ##
- #F TransposedMat( <mat> ) . . . . . . . . . . . . . transposed of a matrix
- ##
- ## 'TransposedMat' returns the transposed of the matrix <mat>, i.e., a new
- ## matrix <trans> such that '<trans>[<i>][<k>]' is '<mat>[<k>][<i>]'.
- ##
- TransposedMat := function ( mat )
- local trn, col, n, m, i, j;
-
- if mat = [] then return []; fi;
-
- # initialize the transposed
- n := Length( mat[1] );
- m := Length( mat );
- trn := [];
-
- # copy the entries
- for j in [ 1 .. n ] do
- col := [];
- for i in [ 1 .. m ] do
- col[i] := mat[i][j];
- od;
- trn[j] := col;
- od;
-
- # return the transposed
- return trn;
- end;
-
-
- #############################################################################
- ##
- #F KroneckerProduct(<mat1>,<mat2>) . . . . Kronecker product of two matrices
- ##
- KroneckerProduct := function ( mat1, mat2 )
- local i, row1, row2, row, kroneckerproduct;
- kroneckerproduct := [];
- for row1 in mat1 do
- for row2 in mat2 do
- row := [];
- for i in row1 do
- Append( row, i * row2 );
- od;
- Add( kroneckerproduct, row );
- od;
- od;
- return kroneckerproduct;
- end;
-
-
- #############################################################################
- ##
- #F OrderMat( <mat> ) . . . . . . . . . . . . . . . . . . . order of a matrix
- #F MatricesOps.Order(<Matrices>,<mat>) . . . . . . . . . . order of a matrix
- ##
- OrderMatLimit := 1000;
-
- OrderMat := function ( mat )
- local ord, m, id, vec, v, o, i;
-
- # check that the argument is an invertable square matrix
- m := Length(mat);
- if m <> Length(mat[1]) then
- Error("OrderMat: <mat> must be a square matrix");
- fi;
- if RankMat( mat ) <> m then
- Error("OrderMat: <mat> must be invertable");
- fi;
- id := mat ^ 0;
-
- # loop over the standard basis vectors
- ord := 1;
- for i in [1..m] do
-
- # compute the length of the orbit of the <i>th standard basis vector
- vec := mat[i];
- v := vec * mat;
- o := 1;
- while v <> vec do
- v := v * mat;
- o := o + 1;
- if OrderMatLimit = o then
- Print("#W OrderMat: warning, order be infinite\n");
- fi;
- od;
-
- # raise the matrix to this length (new mat will fix basis vector)
- mat := mat ^ o;
- ord := ord * o;
- od;
-
- # return the order
- return ord;
- end;
-
- MatricesOps.Order := function ( Matrices, mat )
- return OrderMat( mat );
- end;
-
-
- #############################################################################
- ##
- #F TraceMat( <mat> ) . . . . . . . . . . . . . . . . . . . trace of a matrix
- ##
- TraceMat := function ( mat )
- local trc, m, i;
-
- # check that the element is a square matrix
- m := Length(mat);
- if m <> Length(mat[1]) then
- Error("TraceMat: <mat> must be a square matrix");
- fi;
-
- # sum all the diagonal entries
- trc := mat[1][1];
- for i in [2..m] do
- trc := trc + mat[i][i];
- od;
-
- # return the trace
- return trc;
- end;
-
-
- #############################################################################
- ##
- #F RankMat( <mat> ) . . . . . . . . . . . . . . . . . . . rank of a matrix
- ##
- RankMat := function ( mat )
- local m, n, i, j, k, row, zero;
-
- # make a copy to avoid changing the original argument
- m := Length(mat);
- n := Length(mat[1]);
- zero := 0*mat[1][1];
- mat := ShallowCopy( mat );
- InfoMatrix1("#I RankMat called\n");
- InfoMatrix2("#I nonzero columns: \c");
-
- # run through all columns of the matrix
- i := 0;
- for k in [1..n] do
-
- # find a nonzero entry in this column
- #N 26-Oct-91 martin if <mat> is an rational matrix look for a pivot
- j := i + 1;
- while j <= m and mat[j][k] = zero do j := j+1; od;
-
- # if there is a nonzero entry
- if j <= m then
-
- # increment the rank
- InfoMatrix2(k," \c");
- i := i + 1;
-
- # make its row the current row and normalize it
- row := mat[j]; mat[j] := mat[i]; mat[i] := row[k]^-1 * row;
-
- # clear all entries in this column
- for j in [i+1..m] do
- if mat[j][k] <> zero then
- mat[j] := mat[j] - mat[j][k] * mat[i];
- fi;
- od;
-
- fi;
-
- od;
-
- # return the rank (the number of linear independent rows)
- InfoMatrix2("\n");
- InfoMatrix1("#I RankMat returns ",i,"\n");
- return i;
- end;
-
-
- #############################################################################
- ##
- #F DeterminantMat( <mat> ) . . . . . . . . . . . . . determinant of a matrix
- ##
- DeterminantMat := function ( mat )
- local det, sgn, row, zero, m, i, j, k, l;
-
- # check that the argument is a square matrix and get the size
- m := Length(mat);
- zero := 0*mat[1][1];
- if m <> Length(mat[1]) then
- Error("DeterminantMat: <mat> must be a square matrix");
- fi;
-
- # make a copy to avoid changing the orginal argument
- mat := ShallowCopy( mat );
- InfoMatrix1("#I DeterminantMat called\n");
- InfoMatrix2("#I nonzero columns: \c");
-
- # run through all columns of the matrix
- i := 0; det := 1; sgn := 1;
- for k in [1..m] do
-
- # find a nonzero entry in this column
- #N 26-Oct-91 martin if <mat> is an rational matrix look for a pivot
- j := i + 1;
- while j <= m and mat[j][k] = zero do j := j+1; od;
-
- # if there is a nonzero entry
- if j <= m then
-
- # increment the rank
- InfoMatrix2(k," \c");
- i := i + 1;
-
- # make its row the current row
- if i <> j then
- row := mat[j]; mat[j] := mat[i]; mat[i] := row;
- sgn := -sgn;
- fi;
-
- # clear all entries in this column
- for j in [i+1..m] do
- mat[j] := (mat[i][k]*mat[j]-mat[j][k]*mat[i])/det;
- od;
-
- det := mat[i][k];
- fi;
-
- od;
-
- # return the determinant
- if i < m then det := zero; fi;
- InfoMatrix2("\n");
- InfoMatrix1("#I DeterminantMat returns ",sgn*det,"\n");
- return sgn * det;
- end;
-
-
- #############################################################################
- ##
- #F TriangulizeMat( <mat> ) . . . . . bring a matrix in upper triangular form
- ##
- TriangulizeMat := function ( mat )
- local m, n, i, j, k, row, zero;
-
- InfoMatrix1("#I TriangulizeMat called\n");
-
- if mat <> [] then
-
- # get the size of the matrix
- m := Length(mat);
- n := Length(mat[1]);
- zero := 0*mat[1][1];
- InfoMatrix2("#I nonzero columns: \c");
-
- # run through all columns of the matrix
- i := 0;
- for k in [1..n] do
-
- # find a nonzero entry in this column
- j := i + 1;
- while j <= m and mat[j][k] = zero do j := j + 1; od;
-
- # if there is a nonzero entry
- if j <= m then
-
- # increment the rank
- InfoMatrix2(k," \c");
- i := i + 1;
-
- # make its row the current row and normalize it
- row := mat[j]; mat[j] := mat[i]; mat[i] := row[k]^-1 * row;
-
- # clear all entries in this column
- for j in [1..m] do
- if i <> j and mat[j][k] <> zero then
- mat[j] := mat[j] - mat[j][k] * mat[i];
- fi;
- od;
-
- fi;
-
- od;
-
- fi;
-
- InfoMatrix2("\n");
- InfoMatrix1("#I TriangulizeMat returns\n");
- end;
-
-
- #############################################################################
- ##
- #F BaseMat( <mat> ) . . . . . . . . . . base for the row space of a matrix
- ##
- BaseMat := function ( mat )
- local base, m, n, i, k, zero;
-
- base := [];
-
- if mat <> [] then
-
- # make a copy to avoid changing the original argument
- mat := ShallowCopy( mat );
- m := Length(mat);
- n := Length(mat[1]);
- zero := 0*mat[1][1];
-
- # triangulize the matrix
- TriangulizeMat( mat );
-
- # and keep only the nonzero rows of the triangular matrix
- i := 1;
- for k in [1..n] do
- if i <= m and mat[i][k] <> zero then
- Add( base, mat[i] );
- i := i + 1;
- fi;
- od;
-
- fi;
-
- # return the base
- return base;
- end;
-
-
- #############################################################################
- ##
- #F NullspaceMat( <mat> ) . . . . . . basis of solutions of <vec> * <mat> = 0
- ##
- NullspaceMat := function ( mat )
- local nullspace, m, n, min, empty, i, k, row, tmp, zero, one;
-
- # triangulize the transposed of the matrix
- mat := TransposedMat( Reversed( mat ) );
- TriangulizeMat( mat );
- m := Length(mat);
- n := Length(mat[1]);
- zero := 0*mat[1][1];
- one := mat[1][1]^0;
- min := Minimum( m, n );
-
- # insert empty rows to bring the leading term of each row on the diagonal
- empty := 0*mat[1];
- i := 1;
- while i <= Length(mat) do
- if i < n and mat[i][i] = zero then
- for k in Reversed([i..Minimum(Length(mat),n-1)]) do
- mat[k+1] := mat[k];
- od;
- mat[i] := empty;
- fi;
- i := i+1;
- od;
- for i in [ Length(mat)+1 .. n ] do
- mat[i] := empty;
- od;
-
- # 'mat' now looks like [ [1,2,0,2], [0,0,0,0], [0,0,1,3], [0,0,0,0] ],
- # and the solutions can be read in those columns with a 0 on the diagonal
- # by replacing this 0 by a -1, in this example [2,-1,0,0], [2,0,3,-1].
- nullspace := [];
- for k in Reversed([1..n]) do
- if mat[k][k] = zero then
- row := [];
- for i in [1..k-1] do row[n-i+1] := -mat[i][k]; od;
- row[n-k+1] := one;
- for i in [k+1..n] do row[n-i+1] := zero; od;
- Add( nullspace, row );
- fi;
- od;
-
- return nullspace;
- end;
-
-
- #############################################################################
- ##
- #F DiagonalizeMat( <mat> ) . . . . . . . . . . diagonalize an integer matrix
- ##
- DiagonalizeMat := function ( mat )
- local i, # current position
- k, l, # row and column loop variables
- r, c, # row and column index of minimal element
- e, f, # entries of the matrix
- g, # (extended) gcd of <e> and <f>
- v, w, # rows of the matrix or row and column norms
- m, # maximal entry, only for information
- isClearCol; #
-
- InfoMatrix1("#I DiagonalizeMat called\n");
-
- if mat <> [] then
-
- InfoMatrix2("#I divisors: \c");
- m := 0;
-
- # loop over all rows respectively columns of the matrix
- for i in [1..Minimum( Length(mat), Length(mat[1]) )] do
-
- # compute the row and column norms
- v := 0 * [1..Length(mat)];
- w := 0 * [1..Length(mat[1])];
- for k in [i..Length(mat)] do
- for l in [i..Length(mat[1])] do
- e := mat[k][l];
- if 0 < e then
- v[k] := v[k] + e;
- w[l] := w[l] + e;
- else
- v[k] := v[k] - e;
- w[l] := w[l] - e;
- fi;
- od;
- od;
-
- # find the element with the smallest absolute value in the matrix
- f := 0;
- for k in [i..Length(mat)] do
- for l in [i..Length(mat[1])] do
- e := mat[k][l];
- if 0 < e and (f=0 or e<f or e=f and v[k]*w[l]<g) then
- f := e; r := k; c := l; g := v[k]*w[l];
- elif e < 0 and (f=0 or -e<f or -e=f and v[k]*w[l]<g) then
- f := -e; r := k; c := l; g := v[k]*w[l];
- fi;
- if 0 < e and m < e then
- m := e;
- elif e < 0 and m < -e then
- m := -e;
- fi;
- od;
- od;
-
- # if there is no nonzero entry we are done
- if f = 0 then
- InfoMatrix2("\n");
- InfoMatrix1("#I DiagonalizeMat returns\n");
- return;
- fi;
-
- # move the minimal element to position 'mat[i][i]' make it positive
- if i <> r then
- v := mat[i]; mat[i] := mat[r]; mat[r] := v;
- fi;
- if i <> c then
- for k in [i..Length(mat)] do
- e := mat[k][i]; mat[k][i] := mat[k][c]; mat[k][c] := e;
- od;
- fi;
- if mat[i][i] < 0 then
- mat[i] := - mat[i];
- fi;
-
- # now clear the column i and the row i
- isClearCol := false;
- while not isClearCol do
-
- # clear the column i using unimodular row operations such that
- # mat[i][i] becomes gcd(mat[i][i],mat[r][i]) and mat[r][i] = 0
- k := i + 1;
- while k <= Length(mat) do
- e := mat[i][i]; f := mat[k][i];
- if f mod e = 0 then
- mat[k] := mat[k] - f/e * mat[i];
- elif f <> 0 then
- g := Gcdex( e, f );
- v := mat[i]; w := mat[k];
- mat[i] := g.coeff1 * v + g.coeff2 * w;
- mat[k] := g.coeff3 * v + g.coeff4 * w;
- fi;
- k := k + 1;
- od;
-
- isClearCol := true;
-
- # clear the row i using unimodular column operations such that
- # mat[i][i] becomes gcd(mat[i][i],mat[i][c]) and mat[i][c] = 0
- # after such an operation we may have to clear column i again
- l := i + 1;
- while l <= Length(mat[1]) and isClearCol do
- e := mat[i][i]; f := mat[i][l];
- if f mod e = 0 then
- mat[i][l] := 0;
- elif f <> 0 then
- g := Gcdex( e, f );
- for k in [i..Length(mat)] do
- v := mat[k][i]; w := mat[k][l];
- mat[k][i] := g.coeff1 * v + g.coeff2 * w;
- mat[k][l] := g.coeff3 * v + g.coeff4 * w;
- od;
- isClearCol := false;
- fi;
- l := l + 1;
- od;
-
- od;
-
- InfoMatrix2(mat[i][i]," \c");
- od;
-
- InfoMatrix2("\n");
- InfoMatrix2("#I maximal entry ",m,"\n");
- fi;
-
- InfoMatrix1("#I DiagonalizeMat returns\n");
- end;
-
-
- #############################################################################
- ##
- #F ElementaryDivisorsMat( <mat> ) elementary divisors of an integer matrix
- ##
- ## 'ElementaryDivisors' returns a list of the elementary divisors, i.e., the
- ## unique <d> with '<d>[<i>]' divides '<d>[<i>+1]' and <mat> is equivalent
- ## to a diagonal matrix with the elements '<d>[<i>]' on the diagonal.
- ##
- ElementaryDivisorsMat := function ( mat )
- local divs, gcd, m, n, i, k;
-
- # make a copy to avoid changing the original argument
- mat := Copy( mat );
- m := Length(mat); n := Length(mat[1]);
-
- # diagonalize the matrix
- DiagonalizeMat( mat );
-
- # get the diagonal elements
- divs := [];
- for i in [1..Minimum(m,n)] do
- divs[i] := mat[i][i];
- od;
-
- # transform the divisors so that every divisor divides the next
- for i in [1..Length(divs)-1] do
- for k in [i+1..Length(divs)] do
- if divs[i] <> 0 and divs[k] mod divs[i] <> 0 then
- gcd := GcdInt( divs[i], divs[k] );
- divs[k] := divs[k] / gcd * divs[i];
- divs[i] := gcd;
- fi;
- od;
- od;
-
- return divs;
- end;
-
-
- #############################################################################
- ##
- #F SolutionMat(<mat>,<vec>) . . . . . . . . . . . one solution of equation
- ##
- ## One solution <x> of <x> * <mat> = <vec> or 'false'.
- ##
- SolutionMat := function ( mat, vec )
- local h, v, tmp, i, l, r, s, c, zero;
-
- # Transpose <mat> and solve <mat> * x = <vec>.
- mat := TransposedMat( mat );
- vec := Copy( vec );
- l := Length( mat );
- r := 0;
- zero := 0*mat[1][1];
- InfoMatrix1("#I SolutionMat called\n");
- InfoMatrix2("#I nonzero columns \c");
-
- # Run through all columns of the matrix.
- c := 1;
- while c <= Length( mat[ 1 ] ) and r < l do
-
- # Find a nonzero entry in this column.
- s := r + 1;
- while s <= l and mat[ s ][ c ] = zero do s := s + 1; od;
-
- # If there is a nonzero entry,
- if s <= l then
-
- # increment the rank.
- InfoMatrix2(c," \c");
- r := r + 1;
-
- # Make its row the current row and normalize it.
- tmp := mat[ s ][ c ] ^ -1;
- v := mat[ s ]; mat[ s ] := mat[ r ]; mat[ r ] := tmp * v;
- v := vec[ s ]; vec[ s ] := vec[ r ]; vec[ r ] := tmp * v;
-
- # Clear all entries in this column.
- for s in [ 1 .. Length( mat ) ] do
- if s <> r and mat[ s ][ c ] <> zero then
- tmp := mat[ s ][ c ];
- mat[ s ] := mat[ s ] - tmp * mat[ r ];
- vec[ s ] := vec[ s ] - tmp * vec[ r ];
- fi;
- od;
- fi;
- c := c + 1;
- od;
-
- # Find a solution.
- for i in [ r + 1 .. l ] do
- if vec[ i ] <> zero then return false; fi;
- od;
- h := [];
- s := Length( mat[ 1 ] );
- v := 0 * mat[ 1 ][ 1 ];
- r := 1;
- c := 1;
- while c <= s and r <= l do
- while c <= s and mat[ r ][ c ] = zero do
- c := c + 1;
- Add( h, v );
- od;
- if c <= s then
- Add( h, vec[ r ] );
- r := r + 1;
- c := c + 1;
- fi;
- od;
- while c <= s do Add( h, v ); c := c + 1; od;
-
- InfoMatrix2("\n");
- InfoMatrix1("#I SolutionMat returns\n");
- return h;
- end;
-
-
- #############################################################################
- ##
- #R Read . . . . . . . . . . . . . read other function from the other files
- ##
- ReadLib( "matgrp" );
- ReadLib( "matring" );
-
-
- #############################################################################
- ##
- #V FieldMatrices . . . . . . . . . . . . . . . . matrices over finite field
- ##
- FieldMatrices := Copy( Matrices );
- FieldMatrices.name := "FieldMatrices";
- FieldMatricesOps := FieldMatrices.operations;
-
-
- #############################################################################
- ##
- #F MinimalPolynomial( <D>, <A> ) . . . . . . . . . . . . minimal polynomial
- ##
- MinimalPolynomial := function( arg )
- local D, A;
-
- # get the domain <D> of <A>
- if Length(arg) = 2 then
- D := arg[1];
- A := arg[2];
- else
- A := arg[1];
- D := Domain([A]);
- fi;
-
- # return the minimal polynomial
- return D.operations.MinimalPolynomial(D, A);
-
- end;
-
-
- #############################################################################
- ##
- #F FieldMatricesOps.MinimalPolynomial( <D>, <A> ) . . min polynomial of <A>
- ##
- FieldMatricesOps.MinimalPolynomial := function( D, A )
- local I, F, L, d, p, P, M, N, one, R, h, v, w, i, j, W;
-
- # try to find the field of <A>
- if not IsBound(D.baseRing) then
- F := Field( Flat(A) );
- else
- F := D.baseRing;
- fi;
-
- # set up the other variables
- W := [];
- d := Length( A );
- P := [ Polynomial( F, [ F.one ] ) ];
- N := F.zero * A[1];
- M := ShallowCopy( N );
- Add( M, N[1] );
-
- # span the whole vector space
- for i in [ 1 .. d ] do
-
- # did we already see the <i>.th base vector
- if not IsBound( W[i] ) then
-
- # clear right and left sides <R>
- L := [];
- R := [];
-
- # start with the standard base vector
- v := ShallowCopy( N );
- v[i] := F.one;
-
- # <j>-1 gives the power of <A> we are looking at
- j := 1;
-
- # spin vector around and construct polynomial
- repeat
-
- # compute the head of <v>
- h := 1;
- while h <= d and v[h] = F.zero do
- h := h + 1;
- od;
-
- # start with appropriate polynomial x^(<j>-1)
- p := ShallowCopy( M );
- p[j] := F.one;
-
- # divide by known left sides
- w := v;
- while h <= d and IsBound( L[h] ) do
- p := p - w[h] * R[h];
- w := w - w[h] * L[h];
- while h <= d and w[h] = F.zero do
- h := h + 1;
- od;
- od;
-
- # if <v> is not the zero vector try next power
- if h <= d then
- R[h] := p * w[h]^-1;
- L[h] := w * w[h]^-1;
- W[h] := true;
- j := j + 1;
- v := v * A;
-
- # otherwise, we know our polynomial
- else
- Add( P, Polynomial( F, p ) );
- fi;
- until h > d;
- fi;
- od;
-
- # compute LCM of all polynomials
- return Lcm( P );
-
- end;
-
-
- #############################################################################
- ##
- #F CharacteristicPolynomial( <D>, <A> ) . . . . . characteristic polynomial
- ##
- CharacteristicPolynomial := function( arg )
- local D, A;
-
- # get the domain <D> of <A>
- if Length(arg) = 2 then
- D := arg[1];
- A := arg[2];
- else
- A := arg[1];
- D := Domain([A]);
- fi;
-
- # return the characteristic polynomial
- return D.operations.CharacteristicPolynomial(D, A);
-
- end;
-
-
- #############################################################################
- ##
- #F FieldMatricesOps.CharacteristicPolynomial( <D>, <A> ) . . char pol of <A>
- ##
- FieldMatricesOps.CharacteristicPolynomial := function( D, A )
- local F, L, d, p, P, M, N, one, R, h, v, w, i, j;
-
- # try to find the field of <A>
- if not IsBound(D.baseRing) then
- F := Field( Flat(A) );
- else
- F := D.baseRing;
- fi;
-
- # set up the other variables
- L := [];
- d := Length( A );
- P := [ Polynomial( F, [ F.one ] ) ];
- N := F.zero * A[1];
- M := ShallowCopy( N );
- Add( M, N[1] );
-
- # span the whole vector space
- for i in [ 1 .. d ] do
-
- # did we already see the <i>.th base vector
- if not IsBound( L[i] ) then
-
- # clear right sides <R>
- R := [];
-
- # start with the standard base vector
- v := ShallowCopy( N );
- v[i] := F.one;
-
- # <j>-1 gives the power of <A> we are looking at
- j := 1;
-
- # spin vector around and construct polynomial
- repeat
-
- # compute the head of <v>
- h := 1;
- while h <= d and v[h] = F.zero do
- h := h + 1;
- od;
-
- # start with appropriate polynomial x^(<j>-1)
- p := ShallowCopy( M );
- p[j] := F.one;
-
- # divide by known left sides
- w := v;
- while h <= d and IsBound( L[h] ) do
- if IsBound( R[h] ) then
- p := p - w[h] * R[h];
- fi;
- w := w - w[h] * L[h];
- while h <= d and w[h] = F.zero do
- h := h + 1;
- od;
- od;
-
- # if <v> is not the zero vector try next power
- if h <= d then
- R[h] := p * w[h]^-1;
- L[h] := w * w[h]^-1;
- j := j + 1;
- v := v * A;
-
- # otherwise, we know our polynomial
- else
- Add( P, Polynomial( F, p ) );
- fi;
- until h > d;
- fi;
- od;
-
- # compute the product of all polynomials
- return Product( P );
-
- end;
-
-
- #############################################################################
- ##
- #V FiniteFieldMatrices . . . . . . . . . . . . . . . . finite field matrices
- ##
- FiniteFieldMatrices := Copy( FieldMatrices );
- FiniteFieldMatrices.name := "FiniteFieldMatrices";
- FiniteFieldMatricesOps := FiniteFieldMatrices.operations;
-
-
- #############################################################################
- ##
- #F FiniteFieldMatricesOps.OrderScalar( <R>, <A> ) . . . . order mod scalars
- ##
- ## Return an integer n and a finite field element e such that <A>^n = eI.
- ##
- FiniteFieldMatricesOps.OrderScalar := function( R, A )
- local p, R;
-
- # construct the minimal polynomial of <A>
- p := R.operations.MinimalPolynomial( R, A );
-
- # check if <A> is invertible
- if p.coefficients[1] = 0 * p.coefficients[1] then
- Error( "<A> must be invertible" );
- fi;
-
- # compute the order of <p>
- R := DefaultRing( p );
- return R.operations.OrderScalar( R, p );
-
- end;
-
-
- #############################################################################
- ##
- #F FiniteFieldMatricesOps.Order( <R>, <A> ) . . . . . . . . . order of <A>
- ##
- FiniteFieldMatricesOps.Order := function( R, A )
- local o;
-
- o := R.operations.OrderScalar( R, A );
- return o[1] * OrderFFE(o[2]);
-
- end;
-
-
- #############################################################################
- ##
- #F FiniteFieldMatricesOps.MinimalPolynomial( <D>, <A> ) . . min polynomial
- ##
- FiniteFieldMatricesOps.MinimalPolynomial := function( D, A )
- local I, F, L, d, p, P, M, N, one, R, h, v, w, i, W;
-
- # try to find the field of <A>
- if not IsBound(D.baseRing) then
- F := Field( List( A, x -> Field(x).root ) );
- else
- F := D.baseRing;
- fi;
-
- # set up the other variables
- W := [];
- d := Length(A);
- P := [ Polynomial(F, [F.one]) ];
- N := F.zero * A[1];
- IsVector(N);
-
- # span the whole vector space
- for i in [ 1 .. d ] do
-
- # did we already see the <i>.th base vector
- if not IsBound(W[i]) then
-
- # clear right and left sides <R>
- L := [];
- R := [];
-
- # start with the standard base vector
- v := ShallowCopy(N);
- v[i] := F.one;
-
- # <j>-1 gives the power of <A> we are looking at
- M := [];
-
- # spin vector around and construct polynomial
- repeat
-
- # compute the head of <v>
- h := DepthVector(v);
-
- # start with appropriate polynomial x^(<j>-1)
- p := Copy(M);
- Add(p, F.one);
- Add(M, F.zero);
-
- # divide by known left sides
- w := Copy(v);
- while h <= Length(w) and IsBound(L[h]) do
- AddCoeffs(p, R[h], -w[h]);
- AddCoeffs(w, L[h], -w[h]);
- h := DepthVector(w);
- od;
-
- # if <v> is not the zero vector try next power
- if h <= Length(w) then
- R[h] := p * w[h]^-1;
- L[h] := w * w[h]^-1;
-
- # enter vectors seen in <W>
- while h <= Length(w) and IsBound(W[h]) do
- AddCoeffs(w, W[h], -w[h]);
- h := DepthVector(w);
- od;
- if h <= Length(w) then
- W[h] := w * w[h]^-1;
- fi;
-
- # next power of <A>
- v := v * A;
- h := 1;
-
- # otherwise, we know our polynomial
- else
- Add(P, Polynomial(F, p));
- h := 0;
- fi;
- until h = 0;
- fi;
- od;
-
- # compute LCM of all polynomials
- return Lcm(P);
-
- end;
-
-
- #############################################################################
- ##
- #F FiniteFieldMatricesOps.CharacteristicPolynomial( <D>, <A> ) . . char pol
- ##
- FiniteFieldMatricesOps.CharacteristicPolynomial := function( D, A )
- local F, L, d, p, P, M, N, one, R, h, v, w, i;
-
- # try to find the field of <A>
- if not IsBound(D.baseRing) then
- F := Field( List( A, x -> Field(x).root ) );
- else
- F := D.baseRing;
- fi;
-
- # set up the other variables
- L := [];
- d := Length(A);
- P := [ Polynomial( F, [F.one] ) ];
- N := F.zero * A[1];
- IsVector(N);
-
- # span the whole vector space
- for i in [ 1 .. d ] do
-
- # did we already see the <i>.th base vector
- if not IsBound(L[i]) then
-
- # clear right sides <R>
- R := [];
-
- # start with the standard base vector
- v := ShallowCopy(N);
- v[i] := F.one;
-
- # <j>-1 gives the power of <A> we are looking at
- M := [];
-
- # spin vector around and construct polynomial
- repeat
-
- # compute the head of <v>
- h := DepthVector(v);
-
- # start with appropriate polynomial x^(<j>-1)
- p := Copy(M);
- Add(p, F.one);
- Add(M, F.zero);
-
- # divide by known left sides
- w := Copy(v);
- while h <= Length(w) and IsBound(L[h]) do
- if IsBound(R[h]) then
- AddCoeffs(p, R[h], -w[h]);
- fi;
- AddCoeffs(w, L[h], -w[h]);
- h := DepthVector(w);
- od;
-
- # if <v> is not the zero vector try next power
- if h <= Length(w) then
- R[h] := p * w[h]^-1;
- L[h] := w * w[h]^-1;
- v := v * A;
-
- # otherwise, we know our polynomial
- else
- Add(P, Polynomial(F, p));
- fi;
- until h > Length(w);
- fi;
- od;
-
- # compute the product of all polynomials
- return Product(P);
-
- end;
-
-
- #############################################################################
- ##
- #E Emacs . . . . . . . . . . . . . . . . . . . . . . . local emacs variables
- ##
- ## Local Variables:
- ## mode: outline
- ## outline-regexp: "#F\\|#V\\|#E"
- ## eval: (hide-body)
- ## End:
- ##
-