`mod/rtable/Gausselim` := proc(A::Matrix,rank::{integer,name},
                               det::{integer,name})
  local    B, d, nrows, ncols, right_margin, i,j,
      col, row, s, t, p, Q;

  Q := type( A, 'Matrix( rational )' );
  if not Q and not type( A, 'Matrix( ratpoly( algnum ) )' ) then
      error "first argument must be a matrix over a finite field"
  end if;
  ( nrows, ncols ) := LinearAlgebra:-Dimensions( A );

  p := args[-1];
  right_margin := ncols;
  if type( args[-2], 'integer' ) then
      right_margin := args[-2]
  end if;

  if nargs > 3 and type( det, 'name' )
               and nrows <> right_margin then
    error "cannot compute determinant of a non-square matrix"
  end if;

  if Q then
      B := map( s -> s mod p,  A );
  else
      B := map( s -> 'Normal'( s ) mod p, A );
  end if;

  row := 1; # initialise the row
  d := 1; # initialise the determinant

  for col to right_margin while row <= nrows do
      # Find the first nonzero entry in this column
      for i from row to nrows while B[ i, col ] = 0 do
          # empty
      end do;
      if i > nrows then
          # found a zero column so determinant is zero
          d := 0;
          next
      end if;
      if i <> row then
          # interchange row i with row row
          B[ i, 1..-1 ], B[ row, 1..-1 ] :=
              B[ row, 1..-1 ], B[ i, 1 .. -1 ];
          d := -d mod p; # keep track of determinant
      end if;

      if nargs = 4 then
          d := 'Normal'( d * B[ row, col ] ) mod p
      end if;

      # Make all the nonzero entries below this one 
      # are equal to 1
      if Q then
          s := 1/B[ row, col ] mod p;
          for i from row + 1 to nrows do
              # do i-th row
              if B[ i, col ] = 0 then
                  next
              end if;
              t := s * B[ i, col ] mod p;
              for j from col + 1 to ncols do
                  B[ i, j ] := B[ i, j ] -
                               t * B[ row, j ] mod p
              end do;
              B[ i, col ] := 0
          end do
      else
          s := 'Normal'( 1 / B[ row, col ] ) mod p;
          for i from row + 1 to nrows do
              if B[ i, col ] = 0 then
                  next
              end if;
              t := 'Normal'( s * B[ i, col ] ) mod p;
              for j from col + 1 to ncols do
                B[i,j] := 'Normal'( B[ i, j ] -
                                    t * B[ row, j ] ) mod p
              end do;
              B[ i, col ] := 0
          end do
      end if;

      row := 1 + row # go to next row
  end do; # go to next column

  if nargs > 2 and type( rank, 'name' ) then
      rank := row-1
  end if;
  if nargs > 3 and type( det, 'name' ) then
      det := d
  end if;
  B
end proc: