next up previous contents
Next: rational_factorization Up: Description of the Previous: lattice_basis

bigint_matrix


bigint_matrix Linear algebra over


bigint_matrix is a class for doing linear algebra over the ring of rational integers. This class may either be used for representing a modul, which is generated by the columns of the matrix

or for representing an homomorphism by its matrix. In the first case, the class supports for example computing bases, hermite normal form, smith normal form etc., in the second case it may be used for computing the determinant, the characteristic polynomial, the image, the kernel etc. of the homomorphism.


A variable of type bigint_matrix

consists of a 2-dimensional array bigint ** value and two long integers ( rows, columns ) which store the number of rows and columns of the matrix, respectively. In the following descriptions we use to label the number of rows and to label the number of columns of matrix A. Moreover a variable of type bigint_matrix contains an integer print_mode which chooses, in which format the matrix is printed.

For some computations modular arithmetic is used, for which we use an external table of prime numbers. By default, this table is taken out of the file LIDIA_INSTALL_DIR/lib/LIDIA_PRIMES, where LIDIA_INSTALL_DIR denotes the directory, where LiDIA was installed by the installation procedure. For efficiency, we assume at first, that 300 prime numbers are sufficient. If this is not the case, the number of used prime numbers is doubled.

If you want to use some other file location for the file containing the prime numbers, you may set the environment variable LIDIA_PRIMES_NAME to point to this location. Depending on your architecture quite some gain in running time may be achieved by using lists of larger prime numbers, e. .g. if you have a 64 bit CPU using our list of 26 bit primes (optimized for SPARC V7/V8 architectures) is just a convenient though slow way to get our library to work. If you do computations with very large numbers, you might consider to start with a larger buffer for the prime numbers by setting the environment variable LIDIA_PRIMES_SIZE to some larger number, e. g. to 6000.

Constructors/Destructor

If or or v=NULL in one of the following constructors the error_handler is invoked. The behaviour of some of the following constructors is undefined, if the array v has less than a rows or less than b columns.

bigint_matrix() constructs a matrix initialized with zero.

bigint_matrix(long a) constructs an matrix initialized with zero.

bigint_matrix(long a, long b) constructs an matrix initialized with zero.

bigint_matrix(long a, long b, long ** v)

constructs an matrix initialized with the values of the 2-dimensional array v.

bigint_matrix(long a, long b, const bigint ** v)

constructs an matrix initialized with the values of the 2-dimensional array v.

bigint_matrix(const bigint_matrix & A)

constructs a copy of matrix A.

bigint_matrix()

Assignments

Let A be of type bigint_matrix .

The operator = is overloaded. For efficiency reasons, the following functions are also implemented:

void A.assign(const bigint_matrix & B)

void assign(bigint_matrix & A, const bigint_matrix & B)

sets the dimension of matrix A to the dimension of matrix B and copies each entry of B to the corresponding position in A.

Access Functions

Let A be of type bigint_matrix . Note that we begin the numeration of columns and rows with zero. Therefore the error_handler is invoked if i is negative in one of the following functions.

long A.get_no_of_rows() const

returns the number of rows of matrix A.

void A.set_no_of_rows(long i)

changes the number of rows of matrix A into i. If then the rows are discarded. If then this function adds new rows initialized with zero.

bigint * A.operator[ ](long i) const

bigint * A.row(long i) const

allocates memory and returns a copy of row i. If then the error_handler is invoked.

void A.sto_row(const bigint *v, long j, long i)

stores j entries of array v in row i of matrix A starting at column zero. If or the error_handler is invoked.

long A.get_no_of_columns() const

returns the number of columns of matrix A.

void A.set_no_of_columns(long i)

changes the number of columns of matrix A into i. If then the columns are discarded. If then this function adds new columns initialized with zero.

bigint * A.operator( )(long i) const

bigint * A.column(long i) const

allocates memory and returns a copy of column i. If then the error_handler is invoked.

void A.sto_column(const bigint *v, long j, long i)

stores j entries of array v in column i of matrix A starting at row zero. If or the error_handler is invoked.

bigint * A.operator( )(long i, long j) const

bigint A.member(long i, long j) const

returns the value of . If or the error_handler is invoked.

void A.sto(long i, long j, const bigint & x)

stores x as . If or the error_handler is invoked.

long A.get_print_mode() const

returns the print_mode for printing matrix A.

void A.set_print_mode(int i)

sets the print_mode for matrix A to i (see description of Input/Output for further information).

Arithmetical Operations

bigint_matrix supports the following operators: (unary) -
(binary) bigint_matrix op bigint_matrix with
(binary) bigint_matrix op bigint_matrix with
(binary) bigint_matrix op bigint with
(binary with assignment) bigint_matrix op bigint with
(binary) bigint_matrix * (bigint *)

Here the operators operating on two matrices and the unary minus implement the usual operations known from linear algebra. If the dimensions of the operands do not fulfill the usual restrictions known from linear algebra, the error_handler is invoked. The operator

bigint_matrix * (bigint *)

realizes the matrix--vector--multiplication.

The operators op which take a usual bigint as argument do perform the operation op componentwise on each entry of the matrix, e.g. bigint_matrix % bigint reduces each entry modulo the given bigint .

To avoid copying, all operators also exist as functions and of course the restrictions for the dimensions are still valid:

void add(bigint_matrix & C, const bigint_matrix & A,

const bigint_matrix & B) C=A+B.

void add(bigint_matrix & A, const bigint_matrix & B,

const bigint & e)

Let , .


void subtract(bigint_matrix & C, const bigint_matrix & A,

const bigint_matrix & B) C=A-B.

void subtract(bigint_matrix & A, const bigint_matrix & B,

const bigint & e)

Let , .


void multiply(bigint_matrix & C, const bigint_matrix & A,

const bigint_matrix & B) .

void multiply(bigint_matrix & A, const bigint_matrix & B,

const bigint & e)

void multiply(bigint * v, const bigint_matrix & A,

const bigint * w) assigns the result of the muliplication to v (matrix -- vector -- multiplication). If not enough memory has been allocated for vector v the error_handler is invoked.

void remainder(bigint_matrix & A, const bigint_matrix & B,

const bigint & e)

Let , .

The entries of A are non-negative values less than |e|.

void negate(bigint_matrix & B, const bigint_matrix & A) B = -A.

Comparisons

The binary operators == and != are overloaded and can be used for comparison by components. Let A be an instance of type bigint_matrix .

int A.equal(const bigint_matrix & B) const

int equal(const bigint_matrix & A, const bigint_matrix & B)

returns 1 if A and B have the same dimensions and A and B are identical, 0 otherwise.

int A.unequal(const bigint_matrix & B) const

returns 1 if A and B are different, 0 otherwise.

int unequal(const bigint_matrix & A, const bigint_matrix & B)

returns 0 if A and B have the same dimensions and A and B are identical, 1 otherwise.

int A.is_column_zero(long i) const

returns 1 if all entries of column i of matrix A are zero, 0 otherwise.

int is_column_zero(const bigint_matrix & A, long i)

returns 1 if all entries of column i of matrix A are zero, 0 otherwise.

int A.is_row_zero(long i) const

returns 1 if all entries of row i of matrix A are zero, 0 otherwise.

int is_row_zero(const bigint_matrix & A, long i)

returns 1 if all entries of row i of matrix A are zero, 0 otherwise.

Divide and Compose Functions

Let A be of type bigint_matrix . The following divide and compose functions allow area overlap of the submatrices.

If the given conditions in the descriptions of the following functions are not fulfilled, the error_handler is invoked.

void A.divide(bigint_matrix & B, bigint_matrix & C,

bigint_matrix & D, bigint_matrix & E)

partitions matrix A into the submatrices B, C, D and E, with

where the following conditions must be fulfilled:

.

void A.divide_h(bigint_matrix & B, bigint_matrix & C)

partitions matrix A into the submatrices B and C, with , where the following conditions must be fulfilled:

.

void A.divide_v(bigint_matrix & B, bigint_matrix & C)

partitions matrix A into the submatrices B and C, with , where the following conditions must be fulfilled:

.

void A.compose( const bigint_matrix & B,

const bigint_matrix & C, const bigint_matrix & D,

const bigint_matrix & E)

composes the matrices B, C, D and E to the matrix A, with

where the following conditions must be fulfilled:

.

void A.compose_h(const bigint_matrix & B,

const bigint_matrix & C) composes the matrices B and C to the matrix A, with where the following conditions must be fulfilled:

.

void A.compose_v(const bigint_matrix & B,

const bigint_matrix & C)

composes the matrices B and C to the matrix A, with where the following conditions must be fulfilled:

.

Swap Functions

void swap(bigint_matrix & A, bigint_matrix & B)

swap A and B.

void A.swap_columns(long i, long j)

swap the entries of the columns i and j in A. If not the error_handler is invoked.

void A.swap_rows(long i, long j)

swap the entries of the rows i and j in A. If not the error_handler is invoked.

Linear Algebra

If the dimensions of the arguments don't fulfill the usual restrictions known from linear algebra, the error_handler is invoked.

void A.adj(const bigint_matrix & B)

bigint_matrix adj(const bigint_matrix & B)

stores the adjoint matrix of B to A.

bigint * A.charpoly() const

bigint * charpoly(const bigint_matrix & A)

returns an array v of coefficients of the characteristic polynomial of A, where v[i] contains the coefficient of (see [32]).

bigint A.det() const

bigint det(const bigint_matrix & A)

returns the determinant of matrix A.

void A.det(x) const

.

void A.diag(const bigint & a, const bigint & b)

void diag(bigint_matrix & A, const bigint & a, const bigint & b)

stores a at all positions with and b at all other positions.

void A.hnf()

void hnf(bigint_matrix & A)

transforms A in hermite normal form. Since the efficiency of the specific HNF reduction algorithms always depends on the matrix, we implemented several reduction strategies. Out of these, hnf chooses the algorithm, which is the fastest on big, dense matrices. Depending on your application, you might want to choose some other algorithm out of the list of algorithms described in the next section.

void A.hnf(bigint_matrix & T)

void hnf(bigint_matrix & A, bigint_matrix & T)

transforms A in hermite normal form and sets T to the corresponding transformation matrix. That means: . Again, this is just an interface for choosing the generally fastest algorithm.

void A.image(const bigint_matrix & B)

stores a basis of the image of the homomorphism defined by B to A. That means, the columns of matrix A are a generating system of this image.

bigint_matrix image(const bigint_matrix & B)

returns a basis of the image of the homomorphism defined by B.

void A.invimage(const bigint_matrix & B, const bigint * v)

stores the solutions of the linear equation to matrix A. The last column of matrix A is a solution x of the system and the other columns form a generating system of the kernel of the homomorphism corresponding to matrix B. If there is no solution matrix A has only one column of zeros.

bigint_matrix invimage(const bigint_matrix & B, const bigint *v)

returns a bigint_matrix A with the following properties: The last column of matrix A is a solution x of the system and the other columns form a generating system of the kernel of the homomorphism corresponding to matrix B. If there is no solution matrix A has only one column of zeros.

void A.kernel(const bigint_matrix & B)

bigint_matrix kernel(const bigint_matrix & B) stores a basis of the kernel of the homomorphism with matrix B to A (see [32]), i.e., the columns of the matrix A form a generating system of the kernel.

bigint A.latticedet() const

bigint latticedet(const bigint_matrix & A)

returns a positive multiple of the determinant of the lattice generated by the columns of A (see [14]).

void A.latticedet(bigint & x) const

.

bigint A.latticedet2() const

bigint latticedet2(const bigint_matrix & A)

returns a positive multiple of the lattice determinant of A (see [14]), which gernerally is much smaller than the result of A.latticedet() . Note that this function takes more running time than A.latticedet() .

void A.latticedet2(bigint & x) const

.

long * A.lininc() const

long * lininc(const bigint_matrix & A)

returns an array of type long with the rank of A (at position zero) followed by the indices of the linearly independent columns of A.

long * A.lininr() const

long * lininr(const bigint_matrix & A)

returns an array of type long with the rank of A (at position zero) followed by the indices of the linearly independent rows of A (see [32]).

long A.rank() const

long rank(const bigint_matrix & A)

returns the rank of matrix A (see [32]).

bigint_matrix A.trans() const

bigint_matrix trans(const bigint_matrix & A)

returns .

void A.trans(const bigint_matrix & B)

void trans(bigint_matrix & A, const bigint_matrix & B)

stores to A.

void A.reginvimage(const bigint_matrix & B,

const bigint_matrix & C)

solves the equation systems in the following sense:
The function calculates bigint multipliers , ..., , where and a matrix X, such that

and sets the matrix

if B is regular. Otherwise the error_handler is invoked.

bigint_matrix reginvimage(const bigint_matrix & B,

const bigint_matrix & C)

solves the equation systems in the following sense:
The function calculates bigint multipliers , ..., , where and a matrix X, such that

and returns a matrix

if B is regular. Otherwise the error_handler is invoked.

void A.solve(const bigint_matrix & B, const bigint * v)

stores the solutions of the linear equation to matrix A. The last column of matrix A is a solution x of the system and the other columns form a generating system of the kernel of the homomorphism corresponding to matrix B. If there is no solution matrix A has only one column of zeros.

bigint_matrix solve(const bigint_matrix & B, const bigint *v)

returns a bigint_matrix A with the following properties: The last column of matrix A is a solution x of the system and the other columns form a generating system of the kernel of the homomorphism corresponding to matrix B. If there is no solution matrix A has only one column of zeros.

void A.snf()

void snf(bigint_matrix & A)

transforms A to Smith Normal Form. As was the case with the hnf, this is an interface for choosing the generally fastest implemented reduction algorithm.

void A.snf(bigint_matrix & B, bigint_matrix & C)

void snf(bigint_matrix & A, bigint_matrix & B,

bigint_matrix & C) transforms A to Smith Normal Form and B, C to the corresponding transformation matrices with snf. Again, this is just an interface for choosing the generally fastest algorithm.

Hermite Normal Form

The following functions transform the given matrix in Hermite Normal Form, that means an upper triangular matrix with:

In these functions we assume that for the given matrices the rank is equal to the number of rows. If this condition is not fulfilled the functions using modular methods for the computation (i.e., the functions, whose names start with hnfmod ) invoke the error_handler , whereas the other functions terminate at the position, where this is detected, returning a partially HNF-reduced matrix.

void A.hnf_simple()

void hnf_simple(bigint_matrix & A)

transforms A to Hermite Normal Form using Gauß--Elimination.

void A.hnf_simple(bigint_matrix & T)

void hnf_simple(bigint_matrix & A, bigint_matrix & T)

transforms A to Hermite Normal Form and sets T to the corresponding transformation matrix (i.e., HNF) using a variant of Gauß--Elimination.

void A.hnf_havas()

void hnf_havas(bigint_matrix & A)

transforms A to Hermite Normal Form using result of [19] [20] and [21].

void A.hnf_havas(bigint_matrix & B)

void hnf_havas(bigint_matrix & A, bigint_matrix & T)

transforms A to Hermite Normal Form and sets T to the corresponding transformation matrix (i.e., HNF) using results of [19] [20] and [21].

void A.hnfmod_dkt()

void hnfmod_dkt(bigint_matrix & A)

transforms A to Hermite Normal Form using the algorithms of [13].

void A.hnfmod_dkt(const bigint & x)

void hnfmod_dkt(bigint_matrix & A, const bigint & x)

transforms A to Hermite Normal Form using the algorithm of [13] assuming that x is a multiple of the lattice determinant.

void A.hnfmod_cohen()

transforms A to Hermite Normal Form using the algorithm of [11].

void A.hnfmod_cohen(const bigint & x)

transforms A to Hermite Normal Form using the algorithm of [11] assuming that x is a multiple of the lattice determinant.

void A.hnfmod_mueller(bigint_matrix & T)

void hnfmod_mueller(bigint_matrix & A, bigint_matrix & T)

transforms A to Hermite Normal Form and sets T to the corresponding transformation matrix with HNF (see [32]).

Smith Normal Form

The following functions tranform the given matrix into Smith Normal Form, that means into a diagonal matrix such that for all :

void A.snf_simple()

void snf_simple(bigint_matrix & A)

transforms A to Smith Normal Form using a variant of Gauß--Jordan elimination.

void A.snf_simple(bigint_matrix & C, bigint_matrix & B)

void snf_simple(bigint_matrix & A, bigint_matrix & C, bigint_matrix & B)

transforms A to Smith Normal Form and sets B and C to the corresponding transformation matrices (i.e., SNF) using a variant of Gauß--Jordan elimination.

void A.snf_hartley()

void snf_hartley(bigint_matrix & A)

transforms A to Smith Normal Form using a variant of the algorithm of Hartley and Hawkes.

void A.snf_hartley(bigint_matrix & C, bigint_matrix & B)

void snf_hartley(bigint_matrix & A, bigint_matrix & C, bigint_matrix & B)

transforms A to Smith Normal Form and sets B and C to the corresponding transformation matrices (i.e., SNF) using a variant of the algorithm of Hartley and Hawkes.

void A.snf_havas()

void snf_havas(bigint_matrix & A)

transforms A to Smith Normal Form using results of [19] [20] and [21].

void A.snf_havas(bigint_matrix & C, bigint_matrix & B)

void snf_havas(bigint_matrix & A, bigint_matrix & C, bigint_matrix & B)

transforms A to Smith Normal Form and sets B and C to the corresponding transformation matrices (i.e., SNF) using results of [19] [20] [21].

The following functions are based on results of [19], [20] and [21]. The extensions add , mult , new specify how column norms and row norms are combined for choosing the pivot strategy and the paramter k is used to select the --norm which is used as described in these papers (default: k = 1). If k < 0 the behaviour of the functions is undefined.

Member functions without matrix parameters and functions with one matrix parameter transform the given matrix in Smith Normal Form. All other functions compute also the corresponding transformation matrices B and C with SNF:

void A.snf_mult(long k)

void snf_mult(bigint_matrix & A)

void A.snf_mult(bigint_matrix & C, bigint_matrix & B, long k)

void snf_mult(bigint_matrix & A, bigint_matrix & C, bigint_matrix & B, long k)

void A.snf_add(long k)

void snf_add(bigint_matrix & A, long k)

void A.snf_add(bigint_matrix & C, bigint_matrix & B, long k)

void snf_add(bigint_matrix & A, bigint_matrix & C, bigint_matrix & B, long k)

void A.snf_new(long k)

void snf_new(bigint_matrix & A, long k)

void A.snf_new(bigint_matrix & C, bigint_matrix & B, long k)

void snf_new(bigint_matrix & A, bigint_matrix & C, bigint_matrix & B, long k)

The following functions use modular algorithms, which are based on [11] and [13].

void A.snfmod_dkt()

void snfmod_dkt(bigint_matrix & A)

transforms A to Smith Normal Form [13].

void A.snfmod_dkt(const bigint & x)

void snfmod_dkt(bigint_matrix & A, const bigint & x)

transforms A to Smith Normal Form assuming that x is a multiple of the lattice determinant [13].

void A.snfmod_cohen()

void snfmod_cohen(bigint_matrix & A)

transforms A to Smith Normal Form [11].

void A.snfmod_cohen(const bigint & x)

void snfmod_cohen(bigint_matrix & A, const bigint & x)

transforms A to Smith Normal Form assuming that x is a multiple of the lattice determinant [11].

Norms and Bounds

bigint A.max() const

bigint max(const bigint_matrix & A)

returns the maximum of all components of matrix A.

void A.max(bigint & x) const

.

bigint A.max_abs() const

bigint max_abs(const bigint_matrix & A)

returns the maximum of the absolute values of all components of matrix A.

void A.max_abs(bigint & x) const

x= max_abs

bigint A.min() const

bigint min(const bigint_matrix & A)

returns the minimum of all components of A.

void A.min(bigint & x) const


bigint A.min_abs() const

bigint min_abs(const bigint_matrix & A)

returns the minimum of the absolute values of all components of matrix A.

void A.min_abs(bigint & x) const

x= min_abs

bigint A.hadamard() const

bigint hadamard(const bigit_matrix & A)

returns the hadamard bound of A.

void A.hadamard(bigint & x) const

x= hadamard

void A.row_norm(bigint & x, long i, long j)

sets . If not the error_handler is invoked.

bigint A.row_norm(long i, long j)

bigint row_norm(const bigint_matrix & A, long i, long j)

returns . If not the error_handler is invoked.

void A.column_norm(bigint & x, long i, long j)

sets . If not the error_handler is invoked.

bigint A.column_norm(long i, long j)

bigint column_norm(const bigint_matrix & A, long i, long j)

returns . If not the error_handler is invoked.

Randomize

void A.randomize(const bigint & b)

fills matrix A with random values between 0 and b.

bigint_matrix randomize(long i, long j, const bigint & b)

returns a matrix with i rows and j columns and random values between 0 and b.

Input/Output

The istream operator >> and the ostream operator << are overloaded. The istream operator >> reads matrices in any of the supported formats from istream.

The ostream operator << outputs the matrix in the format given by the variable print_mode (See Access Functions for further information on how to set the print mode). By default, the ``beautify mode'' is used. The following table shows, which values of print_mode correspond to which format.

By LiDIA format we mean the following ASCII format:

where and .

By beautify format we mean the following ASCII format, which should be used only to output matrices on the screen, since it cannot be read by our library:

Interfaces

void A.write_to_stream(const ostream & out) const

writes matrix A to ostream out in LiDIA format.

void A.read_from_stream(const istream & in)

reads LiDIA - matrix A from istream in.

void A.write_to_gp(ostream & out) const

writes matrix A to ostream out in GP format.

void A.read_from_gp(istream & in)

reads GP - matrix A from istream.

void A.write_to_mathematica(ostream & out) const

writes matrix A to ostream out in MATHEMATICA format.

void A.read_from_mathematica(istream & in)

reads MATHEMATICA - matrix A from istream.

void A.write_to_maple(ostream & out) const

writes matrix A to ostream out in MAPLE format.

void A.read_from_maple(istream & in)

reads MAPLE - matrix A from istream.

void A.write_to_kash(ostream & out) const

writes matrix A to ostream out in KASH format.

void A.read_from_kash(istream & in)

reads KASH - matrix A from istream.


bigint.h


By now, the function reading and writing matrices in GP -- format don't understand the use of to merge two lines together.


By inspection of the file bigint_matrix.h you will discover additional routines for computing normal forms, kernel, .... These versions are not yet tested completely, but should be faster than the well tested functions, that are documented. In the next release these functions should be included. So, if you feel a bit adventurous you might try them and help us to debug them.


#include <LiDIA/bigint_matrix.h>
#include <LiDIA/timer.h>

main()
{
  long j,up;
  bigint G,DET;
  timer x;

  cout << "\nAnzahl der Stellen: " << flush;
  cin >> up;
  power(G,(bigint)10,up);

  ofstream dz("MessDet");
  x.set_print_mode(HMS_MODE);
  for (j=1;j<=20;j++)
    {
      cout << "\nDimension: " << 10*j << "\n" << flush;
      dz << "\nDimension: " << 10*j << "\n" << flush;
      bigint_matrix A = randomize(j*10,j*10,G);
      A.det(DET);
      x.stop_timer();

      cout << "det = " << DET << "\n" << flush;
      dz << DET << "\n" << flush;
      cout << "\n" <<" Time: " << flush;
      x.print();
    }
  dz.close();
}
For further examples please refer to

LiDIA/src/simple_classes/bigint_matrix_appl.c .


Stefan Neis, Patrick Theobald

Copyright 1995 by the LiDIA -Group, Universität des Saarlandes



next up previous contents
Next: rational_factorization Up: Description of the Previous: lattice_basis



LiDIA Administrator
Thu Aug 10 16:41:08 MET DST 1995