// ---------------------------------------------------------------------------- // kmatrix.h // begin of file // Stephan Endrass, endrass@mathematik.uni-mainz.de // 23.7.99 // ---------------------------------------------------------------------------- #ifndef KMATRIX_H #define KMATRIX_H #include // ---------------------------------------------------------------------------- // template class for matrices with coefficients in the field K // K is a class representing elements of a field // The implementation of K is expected to have overloaded // the operators +, -, *, /, +=, -=, *= and /=. // The expressions (K)0 and (K)1 should cast to the 0 and 1 of K. // Additionally we use the following functions in class K: // // member functions: // // double complexity( void ); // // friend functions: // // friend K gcd( const K &a,const K &b ); // gcd(a,b) // friend K gcd( K* a,int k ); // gcd(a[0],...,a[k-1]) // // The complexity function should return a measure indicating // how complicated this number is in terms of memory usage // and arithmetic operations. For a rational p/q, one could // return max(|p|,|q|). This fuction is used for pivoting. // // The gcd of two numbers a,b should be a number g such that // the complexities of a/g and b/g are less or equal than those // of a and b. For rationals p1/q1, p2/q2 one could return the // quotient of integer gcd's gcd(p1,p2)/gcd(q1,q2). // // ---------------------------------------------------------------------------- template class KMatrix { private: K *a; // the entries ot the matrix int rows; // number of rows int cols; // number of columns public: KMatrix( ); // init zero KMatrix( const KMatrix& ); // copy constructor KMatrix( int,int ); // preallocate rows & columns ~KMatrix( ); // destructor void copy_delete ( void ); // delete associated memory void copy_new ( int ); // allocate associated memory void copy_zero ( void ); // init zero void copy_unit ( int ); // init as unit matrix void copy_shallow( KMatrix& ); // shallow copy void copy_deep ( const KMatrix& ); // deep copy K get( int,int ) const; // get an element void set( int,int,const K& ); // set an element int row_is_zero( int ) const; // test if row is zero int column_is_zero( int ) const; // test if column is zero int column_pivot( int,int ) const; int gausseliminate( void ); // Gauss elimination int rank( void ) const; // compute the rank int solve( K**,int* ); // solve Ax=b from (A|b) // elementary transformations K multiply_row( int,const K& ); K add_rows( int,int,const K&,const K& ); int swap_rows( int,int ); K set_row_primitive( int ); int is_quadratic( void ) const; int is_symmetric( void ) const; K determinant( void ) const; #ifdef KMATRIX_DEBUG void test_row( int ) const; void test_col( int ) const; #endif #ifdef KMATRIX_PRINT friend ostream & operator << ( ostream&,const KMatrix& ); #endif }; // ------------------------------------ // inline functions for class KMatrix // ------------------------------------ // ---------------------------------------------------------------------------- // Delete memory associated to a KMatrix // ---------------------------------------------------------------------------- template inline void KMatrix::copy_delete( void ) { if( a != (K*)NULL && rows > 0 && cols > 0 ) delete [] a; copy_zero( ); } // ---------------------------------------------------------------------------- // Allocate memory associated to a KMatrix // ---------------------------------------------------------------------------- template inline void KMatrix::copy_new( int k ) { if( k > 0 ) { a = new K[k]; #ifndef NDEBUG if( a == (K*)NULL ) { #ifdef KMATRIX_PRINT #ifdef KMATRIX_IOSTREAM cerr << "void KMatrix::copy_new( int k )"; cerr << ": no memory left ..." << endl; #else fprintf( stderr,"void KMatrix::copy_new( int k )" ); fprintf( stderr,": no memory left ...\n" ); #endif #endif exit( 1 ); } #endif } else if( k == 0 ) { a = (K*)NULL; } else { #ifdef KMATRIX_PRINT #ifdef KMATRIX_IOSTREAM cerr << "void KMatrix::copy_new( int k )"; cerr << ": k < 0 ..." << endl; #else fprintf( stderr,"void KMatrix::copy_new( int k )" ); fprintf( stderr,": k < 0 ...\n" ); #endif #endif exit( 1 ); } } // ---------------------------------------------------------------------------- // Initialize a KMatrix with 0 // ---------------------------------------------------------------------------- template inline void KMatrix::copy_zero( void ) { a = (K*)NULL; rows = cols = 0; } // ---------------------------------------------------------------------------- // Initialize a KMatrix with the unit matrix // ---------------------------------------------------------------------------- template inline void KMatrix::copy_unit( int rank ) { int r,n=rank*rank; copy_new( n ); rows = cols = rank; for( r=0; r inline void KMatrix::copy_shallow( KMatrix &m ) { a = m.a; rows = m.rows; cols = m.cols; } // ---------------------------------------------------------------------------- // Deep copy // ---------------------------------------------------------------------------- template inline void KMatrix::copy_deep( const KMatrix &m ) { if( m.a == (K*)NULL ) { copy_zero( ); } else { int n=m.rows*m.cols; copy_new( n ); rows = m.rows; cols = m.cols; for( int i=0; i inline KMatrix::KMatrix( ) { copy_zero( ); } // ---------------------------------------------------------------------------- // Copy constructor // ---------------------------------------------------------------------------- template inline KMatrix::KMatrix( const KMatrix &m ) { copy_deep( m ); } // ---------------------------------------------------------------------------- // Zero r by c matrix constructor // ---------------------------------------------------------------------------- template KMatrix::KMatrix( int r,int c ) { int n = r*c; copy_new( n ); rows = r; cols = c; for( int i=0; i KMatrix::~KMatrix( ) { copy_delete( ); } // ------------------------------------------------- // non-inline template functions for class KMatrix // ------------------------------------------------- // ---------------------------------------------------------------------------- // Debugging functions // ---------------------------------------------------------------------------- #ifdef KMATRIX_DEBUG template void KMatrix::test_row( int r ) const { if( r<0 || r>=rows ) { #ifdef KMATRIX_PRINT #ifdef KMATRIX_IOSTREAM cerr << "KMatrix::test_row( " << r << " )" << endl; cerr << " rows = " << rows << endl; cerr << " exiting...." << endl; #else fprintf( stderr,"KMatrix::test_row( %d )\n",r ); fprintf( stderr," rows = %d\n",rows ); fprintf( stderr," exiting....\n" ); #endif #endif exit( 1 ); } } template void KMatrix::test_col( int c ) const { if( c<0 || c>=cols ) { #ifdef KMATRIX_PRINT #ifdef KMATRIX_IOSTREAM cerr << "KMatrix::test_col( " << c << " )" << endl; cerr << " cols = " << cols << endl; cerr << " exiting...." << endl; #else fprintf( stderr,"KMatrix::test_col( %d )\n",c ); fprintf( stderr," cols = %d\n",cols ); fprintf( stderr," exiting....\n" ); #endif #endif exit( 1 ); } } #endif // ---------------------------------------------------------------------------- // get coefficient at row r and column c // return value: the coefficient // ---------------------------------------------------------------------------- template K KMatrix::get( int r,int c ) const { #ifdef KMATRIX_DEBUG test_row( r ); test_col( c ); #endif return a[r*cols+c]; } // ---------------------------------------------------------------------------- // sets coefficient at row r and column c to value // ---------------------------------------------------------------------------- template void KMatrix::set( int r,int c,const K &value ) { #ifdef KMATRIX_DEBUG test_row( r ); test_col( c ); #endif a[r*cols+c] = value; } // ---------------------------------------------------------------------------- // interchanges the rows r1 and r2 // return value: 1 if r1==r2 // return value: -1 if r1!=r2 // caution: the determinant changes its sign by the return value // ---------------------------------------------------------------------------- template int KMatrix::swap_rows( int r1,int r2 ) { #ifdef KMATRIX_DEBUG test_row( r1 ); test_row( r2 ); #endif if( r1 == r2 ) return 1; K tmp; for( int c=0; c K KMatrix::multiply_row( int r,const K &factor ) { #ifdef KMATRIX_DEBUG test_row( r ); #endif int i_src = r*cols; for( int i=0; i K KMatrix::add_rows( int src,int dest,const K &factor_src,const K &factor_dest ) { #ifdef KMATRIX_DEBUG test_row( src ); test_row( dest ); #endif int i; int i_src = src*cols; int i_dest = dest*cols; for( i=0; i int KMatrix::row_is_zero( int r ) const { #ifdef KMATRIX_DEBUG test_row( r ); #endif for( int c=0; c int KMatrix::column_is_zero( int c ) const { #ifdef KMATRIX_DEBUG test_col( c ); #endif for( int r=0; r int KMatrix::column_pivot( int r0,int c ) const { #ifdef KMATRIX_DEBUG test_row( r0 ); test_col( c ); #endif int r; // find first nonzero entry in column c for( r=r0; r K KMatrix::set_row_primitive( int r ) { #ifdef KMATRIX_DEBUG test_row( r ); #endif K g = gcd( &(a[r*cols]),cols ); for( int c=0; c int KMatrix::gausseliminate( void ) { int r,c,rank = 0; K g; // make sure that the elements of each row have gcd=1 // this is useful for pivoting for( r=0; r= 0 ) { swap_rows( rank,r ); for( r=rank+1; r int KMatrix::solve( K **solution,int *k ) { int r,c,rank = 0; K g; // ---------------------------------------------------- // make sure that the elements of each row have gcd=1 // this is useful for pivoting // ---------------------------------------------------- for( r=0; r= 0 ) { swap_rows( rank,r ); for( r=0; r int KMatrix::rank( void ) const { KMatrix dummy( *this ); return dummy.gausseliminate( ); } // ---------------------------------------------------------------------------- // print the matrix // return value: the output stream used // ---------------------------------------------------------------------------- #ifdef KMATRIX_PRINT template static void print_rational( ostream &s,int digits,const K &n ) { unsigned int num = digits - n.length( ); for( unsigned int i=0; i < num; i++ ) { #ifdef KMATRIX_IOSTREAM s << " "; #else fprintf( stdout," " ); #endif } s << n; } template ostream & operator << ( ostream &s,const KMatrix &m ) { int i,r,c,digits=0,tmp; for( i=0; i digits ) digits = tmp; } for( r=0; r"; #else fprintf( stdout," >" ); #endif } else if( r == 0 ) { #ifdef KMATRIX_IOSTREAM s << " \\" << endl; #else fprintf( stdout," \\\n" ); #endif } else if( r == m.rows - 1 ) { #ifdef KMATRIX_IOSTREAM s << " /"; #else fprintf( stdout," /" ); #endif } else { #ifdef KMATRIX_IOSTREAM s << " |" << endl; #else fprintf( stdout," |\n" ); #endif } } return s; } #endif // ---------------------------------------------------------------------------- // test if the matrix is quadratic // return value: TRUE or FALSE // ---------------------------------------------------------------------------- template int KMatrix::is_quadratic( void ) const { return ( rows == cols ? TRUE : FALSE ); } // ---------------------------------------------------------------------------- // test if the matrix is symmetric // return value: TRUE or FALSE // ---------------------------------------------------------------------------- template int KMatrix::is_symmetric( void ) const { if( is_quadratic( ) ) { int r,c; for( r=1; r K KMatrix::determinant( void ) const { if( !is_quadratic( ) ) { return 0; } KMatrix dummy( *this ); int r,c,rank = 0; K g; K frank,fr; K det = 1; // make sure that the elements of each row have gcd=1 // this is useful for pivoting for( r=0; r= 0 ) { det *= dummy.swap_rows( rank,r ); for( r=rank+1; r