This is a matrix manipulation package which does all kinds of cool stuff. I wrote this for my Scientific Applications Programming course. I love matrices!! (dork!) Note: The commenting style was forced upon me (or, yes I realize it's C code using C++-style // comments).

// Author: Tom M
// Description: A matrix class that handles basic matrix operations, such as
// 		adding, multiplying, transposing, eliminating, permuting,
//		gaussian techniques, as well as reading and printing a matrix.
// $Id: matrix.c,v 1.2 98/10/22 12:34:24 tommut Exp Locker: tommut $
// Revisions:
//Revision 1.7  1998/10/15 21:35:12  tommut
// added Vandermonde matrices, Cholesky factorization, and Normal Equations
// method
//
//Revision 1.6  98/09/19  23:37:34  tommut
// modified gaussian algorithm to use pivoting
//
//Revision 1.5  98/09/15  15:37:20  tommut
// Added permutations
//
//Revision 1.4  98/09/15  15:37:16  tommut
// implemented the back substitution in gaussian function
  
#include 
#include 
    
typedef struct Mat_Cell {
    int rows, cols;
    float **elements;
} Matrix;	     

Matrix *newMatrix( int rows, int cols ) ;
Matrix *readMatrix( char *filename );
Matrix *transpose( Matrix *m );
Matrix *permutationMatrix( int size, int *map );
Matrix *eliminationMatrix( int k, Matrix *m );
Matrix *multiplyMatrix( Matrix *m1, Matrix *m2 );
Matrix *addMatrix( Matrix *m1, Matrix *m2 );
Matrix *gaussMatrix( Matrix *A, Matrix *B );
Matrix *vandermondeMatrix( Matrix *A, int cols );
Matrix *choleskyMatrix( Matrix *A );
Matrix *normalMatrix( Matrix *A, Matrix *B );
float errorAnalysis( Matrix *Lt, Matrix *ret, Matrix *y ); 
void printMatrix( Matrix *m, FILE *f );
void freeMatrix( Matrix *m );

// the main function just tests all of the functions of this class
int main() {
    FILE *fp = fopen( "output", "a" );    

    int map[] = {1, 3, 0, 2};
    Matrix *m1 = readMatrix( "m1" );
    Matrix *m2 = readMatrix( "m" );
    Matrix *m3 = normalMatrix( m1, m2 );
    
    printMatrix( m3 );

    freeMatrix( m1 ); freeMatrix( m2 ); freeMatrix( m3 );
    
    return ( 0 );
}

// Name . newMatrix
// Description . this function allocates memory for a new Matrix structure
// 		 - it runs through each element or the arrays and allocates
//		 memory for it.

Matrix *newMatrix( int rows, int cols ) {
    int i, j;
    Matrix *temp = (Matrix*)malloc( sizeof( Matrix ) );

    temp->rows = rows;
    temp->cols = cols;
    temp->elements = (float**)malloc( (unsigned)rows * sizeof( float* ) );
    for ( i = 0; i < rows; i++ ) {
 	temp->elements[i] = (float*)malloc( (unsigned)cols * sizeof( float )); 
    }
    for ( i = 0; i < rows; i++ ) {
 	for ( j = 0; j < rows; j++ ) {
	    temp->elements[i][j] = 0.0; 
	}
    }
    
    return (temp);
}

// Name . readMatrix
// Description . reads in a matrix from a given filename. 
// the file must be in the following format:
// row column
// 1.0 2.0 3.4 ...
// 3.0 -.1 9.7 ...
// ...  ... ...
  
Matrix *readMatrix( char *filename ) {
    Matrix *temp;
    int rows, cols;
    int i, j;
    FILE *fp = fopen( filename, "r" );

    fscanf( fp, "%d %d", &rows, &cols ) ;
    temp = newMatrix( rows, cols );

    for ( i = 0; i < rows; i++ ) {
	for ( j = 0; j < cols; j++ ) {
	    fscanf( fp, "%f", &temp->elements[i][j] );
        }
    }
    return temp;
}
 
// Name . printMatrix
// Description . just runs through each row and column and prints out the
// 		 individual element
 
void printMatrix( Matrix *m, FILE *f ) {
    int i, j;
    for ( i = 0; i < m->rows; i++ ) {
 	for ( j = 0; j < m->cols; j++ ) {
    	    fprintf( f, "%16.7f", m->elements[i][j] );
	}
	fprintf( f, "\n" );

    }
}

// Name . addMatrix
// Description . does matrix addition on two matrices.  It just adds up each
//		 corresponding matrices elements and stores the result in a 
//		 new matrix.

Matrix *addMatrix( Matrix *m1, Matrix *m2 ){
    int i, j;
    Matrix *temp = newMatrix( m1->rows, m1->cols );
    
    for ( i = 0; i < m1->rows; i++ ) {
	for ( j = 0; j< m1->cols; j++ ) {
	    temp->elements[i][j] = m1->elements[i][j] + m2->elements[i][j];
  	}
    }
    return temp;
} 
    
// Name . multiplyMatrix
// Description . does matrix multiplication on two matrices
// 		 the result[i][k] is the summation of the multiplication of 
//		 the m1->row * m2->cols

Matrix *multiplyMatrix( Matrix *m1, Matrix *m2 ) {
    Matrix *temp = newMatrix( m1->rows, m2->cols );
    float sum1 = 0;
    int i, j, k;

    if ( m1->cols != m2->rows )  {
        printf( "Warning: M1 cols %d not equal to M2 rows %d\n",
						m1->cols, m2->rows );
    }
    for ( k = 0; k < temp->cols; k++ ) {
	for ( i = 0; i < m1->rows; i++ ) {
	    for ( j = 0; j< m1->cols; j++ ) {
		temp->elements[i][k]+=m1->elements[i][j] * 
				     m2->elements[j][k];
	    }
	}
    }
    return ( temp );
}
    
// Name . transpose
// Description . simply transposes a given matrix :
//		 element[i][j] = element[j][i]

Matrix *transpose( Matrix *m ){
    Matrix *temp = newMatrix( m->cols, m->rows );
    int i, j;

    for ( i = 0; i < m->cols; i++ ) {
	for ( j = 0; j< m->rows; j++ ) {
	    temp->elements[i][j] = m->elements[j][i];
        }
    }
    return temp;
} 
    
// Name . eliminationMatrix
// Description . forms an elimination matrix of a given matrix m, for column k.  
Matrix *eliminationMatrix( int k, Matrix *m ){
    Matrix *temp = newMatrix( m->cols, m->rows );
    int i, j = 0;

    // fill the diagonal with 1's
    for ( i = 0; i < m->cols; i++ ) {
	temp->elements[i][i] = 1; 
    }

    // compute the values for row k below the diagonal
    for ( i = k+1; i < temp->rows; i++ ) {
	temp->elements[i][k] = -m->elements[i][k] /
	    		        m->elements[k][k];
    }
    return temp;
}

// Name . gaussMatrix 	
// Description . compute a gaussMatrix with two given matrices.  Matrix A is 
//		 the original known matrix and B is the answer 
//		 This function returns the computed answer to fill in the
//		 unknown variables.

Matrix *gaussMatrix( Matrix *A, Matrix *B ){
    Matrix *ret = newMatrix( A->rows, 1);
    Matrix *Adopple = A; // a copy (doppleganger) of A to preserve the original
    Matrix *Bdopple = B; // a copy (doppleganger) of B to preserve the original
    Matrix *elim = newMatrix( A->rows, A->cols );// hold the elimination matrix
    Matrix *ans = newMatrix( A->rows, A->cols ); // answer of A*elimination
    Matrix *elimans = newMatrix( A->rows, A->cols ); // answer of B*elimination
    Matrix *permMat = newMatrix( A->rows, A->cols ); // for perm matrix
    float x;  // highest value for pivot
    int i, j;
    int xrow;
    int map[A->cols];  

    // first, reduce the matrix through elimination and pivoting
    for ( i = 0; i < Adopple->cols-1; i++ ) {
	x = Adopple->elements[i][i];
	xrow = i;

	// find the highest coefficient
	for ( j = i; j < Adopple->rows; j++ ) {
	    if ( Adopple->elements[j][i] > x ) {
		x = Adopple->elements[j][i];
		xrow = j;
	    }
	}

	// set the permutation map
	for ( j = 0; j < Adopple->cols; j++ ) {
	    map[j] = j;
	}
	j = map[i];
	map[i] = map[xrow]; 
	map[xrow] = j;

	// permute matrix B
	x = Bdopple->elements[xrow][0];
	Bdopple->elements[xrow][0] = Bdopple->elements[i][0];
	Bdopple->elements[i][0] = x;
    
	// permute Matrix A
	permMat = permutationMatrix( Adopple->cols, map );
	elim = multiplyMatrix( permMat, Adopple );
	Adopple = elim;
	    
	// Multiply A and B by their elimination matrix
	elim = eliminationMatrix( i, Adopple );
	//printf( "elim\n" );	
	//printMatrix( elim, stdout );
	elimans = multiplyMatrix( elim, Bdopple );
	//printf( "elimans\n" );	
	//printMatrix( elimans, stdout );
	ans = multiplyMatrix( elim, Adopple );
	//printf( "ans\n" );	
	//printMatrix( ans, stdout );
	Adopple = ans;
	Bdopple = elimans;
    }
    
    // now, use back substitution to get the final variables
    for( i = ret->rows - 1; i >= 0; i--){
        ret->elements[i][0] = Bdopple->elements[i][0];
        for( j = i+1; j < Adopple->cols; j++){ 
            ret->elements[i][0] -= (Adopple->elements[i][j] *
		    		    ret->elements[j][0]);
        }
        ret->elements[i][0] /= Adopple->elements[i][i];
    }

    // free all temporary matrices
    freeMatrix (Adopple); freeMatrix (Bdopple );
    freeMatrix (elim ); freeMatrix (ans );
    freeMatrix (elimans ); freeMatrix (permMat );

    return ret;
}

// Name . permutationMatrix
// Desription . create a permuted square matrix of size X size  and using the
// 		map array to place the 1's

Matrix *permutationMatrix( int size, int *map ){
    Matrix *temp = newMatrix( size, size );
    int i;
    for ( i = 0; i < temp->rows; i++ ) {
	temp->elements[i][*(map++)] = 1;
    }
    return temp;
}

// Name . freeMatrix
// Desription . frees up allocated memory used by matrix
//

void freeMatrix( Matrix *m ) {
    int i;

    for ( i = 0; i < m->rows; i++ ) {
 	free( m->elements[i] ); 
    }
    
    free ( m->elements );
    free ( m );
}

// Name . vandermondeMatrix
// Description . takes in a matrix and the desired degree and forms a 
//		 Vandermonde matrix 
//

Matrix *vandermondeMatrix( Matrix *A, int cols ){
    Matrix *result = newMatrix( A->rows, cols );
    int i, j = 0;
    for ( j = 0; j < cols; j++ ) {
	for ( i = 0; i < A->rows; i++ ) {
	    result->elements[i][j] = pow( A->elements[i][0], j ) ;
	}
    }
    return result;
}

// Name . normalMatrix
// Description . takes in two matrices and uses the normal equations method
// 		 to return the result
//

Matrix *normalMatrix( Matrix *t, Matrix *b ){
    Matrix *A = vandermondeMatrix( t, 4  );
    Matrix *result1 = multiplyMatrix( transpose( A ), A );
    Matrix *result2 = multiplyMatrix( transpose( A ), b ); 
    Matrix *L = choleskyMatrix( result1 );
    Matrix *Lt = transpose( L );

    Matrix *y  = newMatrix( A->cols, 1 );
    Matrix *ret = newMatrix( A->cols, 1 );
    int i, j = 0;

    // print out some information
    printf( "Vandermonde Matrix: A\n" );
    printMatrix( A, stdout );
    printf( "\n\nA^T * A: \n" );
    printMatrix( result1, stdout );
    printf( "\n\nA^T * b: \n" );
    printMatrix( result2, stdout );
    printf( "\n\nCholesky( A^t * A ): L\n" );
    printMatrix( L, stdout );
    printf( "\n\nL^T\n" );
    printMatrix( Lt, stdout );

    // forward subs to solve y
    y->elements[0][0] = result2->elements[0][0]/L->elements[0][0];

    for( i = 1; i < L->cols; i++){
        y->elements[i][0] = result2->elements[i][0];
        for( j = 0; j < i; j++){ 
            y->elements[i][0] -= ( L->elements[i][j] *
		    		    y->elements[j][0] );
        }
        y->elements[i][0] /= L->elements[i][i];
    }


    // and now back subs to solve the x
    for( i = ret->rows - 1; i >= 0; i--){
        ret->elements[i][0] = y->elements[i][0];
        for( j = i+1; j < Lt->cols; j++){ 
            ret->elements[i][0] -= (Lt->elements[i][j] *
		    		    ret->elements[j][0]);
        }
        ret->elements[i][0] /= Lt->elements[i][i];
    }
    
    

    // print results
    printf( "\n\nLy = A^Tb : solve for y with forward subs.:\n" );
    printMatrix( y, stdout );
    printf( "\n\nL^Tx = y : solve for x using back subs:\n" );
    printMatrix( ret, stdout );

    errorAnalysis( A, ret, b); 
    
    // free all temp matrices
    freeMatrix( A );  freeMatrix( result1 ); freeMatrix( result2 );
    freeMatrix( L );  freeMatrix( Lt ); freeMatrix( y );

    return ret;
}


// Name . choleskyMatrix
// Description . takes in a matrix and performs Choleksy factorization on it
//		 and returns the result
//

Matrix *choleskyMatrix( Matrix *A ){
    Matrix *result = newMatrix( A->rows, A->cols );
    int i, j, k;
    double total;

    for( i = 0; i < A->rows; i++){
        total=0;
        for( j = i - 1; j >= 0; j--){
            total += ( result->elements[i][j] ) * ( result->elements[i][j] );
        }
        result->elements[i][i] = pow( A->elements[i][i] - total,0.5 );
        total=0;
        for( j = i + 1; j < A->rows; j++){
            for( k = i - 1; k >= 0; k--){
                total += ( result->elements[i][k] * result->elements[j][k] );
            }
	     
	    // now scale by the square root diagonol 
            result->elements[j][i]=( (A->elements[j][i] - total) /
                                      result->elements[i][i]);
        }
    }
    return result;
}


// Name . errorAnalysis
// Description . calculates the error by finding the norm of the residual 
// 		 vector.
//

float errorAnalysis( Matrix *A, Matrix *x, Matrix *b ){ 
    Matrix *result = newMatrix( A->rows, 1 );
    Matrix *AX = multiplyMatrix( A,x ); 
    float value = 0.0;
    int i = 0;
    float sum = 0;
    
    printf( "b\n" );
    printMatrix( b, stdout );
    printf( "AX\n" );
    printMatrix( AX, stdout );

    for ( i = 0; i < AX->rows; i++ ) {
	value = b->elements[i][0] - AX->elements[i][0];
	result->elements[i][0] = value * value;
	sum += value*value; 
    }
    printf( "Residual Vector\n" );
    printMatrix( result, stdout );

    printf( "Norm of Residual Vector: %20.15f\n", sum );

    freeMatrix( AX );

    return value;
}