/*
Shaun Guth
CIS15BG, Lee-Klawender
November 8, 2006
Mac OSX 10.4.8
gcc 4.0.1 (build 5363)
Lab 5 (Matrices/Structs)
This program tests some two-dimensional array functions
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_DIMENSION 8
#define MIN_DIMENSION 2
#define MAX_DOUBLE 100.0
// define our 2-dimensional array struct
typedef struct {
double** data;
int rows;
int cols;
} MATRIX;
// testing framework
void get_dimensions (int* x, int* y);
MATRIX* init_matrix (MATRIX* m, int x, int y);
void free_matrix (MATRIX* m);
MATRIX* fill_matrix (MATRIX* m);
// matrix operations
void add_matrices (MATRIX* m1, MATRIX* m2, MATRIX* r);
void invert_matrix (MATRIX* m);
void multiply_matrices (MATRIX* m1, MATRIX* m2, MATRIX* r);
// output
void print_matrix (char* label, MATRIX* m);
/*-------------------------------------------------------------------------*/
// program entry point
int main (void) {
MATRIX matrix1, matrix2, matrix3; // matrices
int dx,dy; // actual dimensions generated
// seed random number generator
//srand(3);
srand( (unsigned)time(NULL) );
// set the initial dimensions for this run
get_dimensions(&dx, &dy);
// initialize the first matrix
if (NULL == init_matrix(&matrix1, dx, dy)) {
printf("Error allocating memory for matrix1, exiting!\n");
return 1;
}
// fill the first matrix with random numbers
fill_matrix(&matrix1);
// initialize the second matrix
if (NULL == init_matrix(&matrix2, dx, dy)) {
printf("Error allocating memory for matrix2, exiting!\n");
}
// fill the second matrix with random numbers
fill_matrix(&matrix2);
// print initial values to screen
print_matrix("First Matrix:", &matrix1);
print_matrix("Second Matrix:", &matrix2);
// add the first two matrices together, storing the sum in matrix3
add_matrices(&matrix1, &matrix2, &matrix3);
// print result
print_matrix("Sum Matrix:", &matrix3);
// invert the second matrix
invert_matrix(&matrix2);
// when printing, remember that the dimensions are now inverted
print_matrix("Inverted Matrix:", &matrix2);
/*
// multiply the first two matrices, storing product in third matrix
multiply_matrices(&matrix1, &matrix2, &matrix3);
// print the result of a multiplication
print_matrix("Product Matrix:", &matrix3);
*/
// successfully completed program
return 0;
}
/*-------------------------------------------------------------------------*/
MATRIX* init_matrix (MATRIX* m, int x, int y) {
/*
PURPOSE: Allocate memory for MATRIX m
ACCEPTS: m (MATRIX pointer)
x (int) num of rows
y (int) num of cols
RETURNS: NULL on error, m otherwise
REMARKS:
*/
int i; // loop index
// invalid dimensions
if (0 >= x || 0 >= y) {
return NULL;
}
free_matrix(m);
// allocate new array pointers
m->data = (double**)calloc(x, sizeof(double*));
if (NULL == m->data) {
return NULL;
}
// allocate data storage
for (i = 0; i < x; i++) {
m->data[i] = (double*)calloc(y, sizeof(double));
if (NULL == m->data[i]) {
return NULL;
}
}
// assign dimensions
m->rows = x;
m->cols = y;
// allocated successfully
return m;
}
/*-------------------------------------------------------------------------*/
void free_matrix (MATRIX* m) {
/*
PURPOSE: Frees memory for an allocated MATRIX m
ACCEPTS: m (MATRIX pointer)
RETURNS: (none)
REMARKS: Checks to see if there's anything to free first
*/
int i; // loop index
printf("Inside free_matrix()\n");
if (NULL != m->data && 0 < m->rows && 0 < m->cols) {
printf("m->data is NOT NULL, rows and cols are > 0\n");
for (i = 0; i < m->rows; i++) {
if (NULL != m->data[i]) {
printf(" freeing row %d\n", i);
free(m->data[i]);
}
}
printf("freeing m->data\n");
free(m->data);
}
m->data = NULL;
}
/*-------------------------------------------------------------------------*/
void get_dimensions (int* x, int* y) {
/*
PURPOSE: Get 2 random values from the set [MAX_DIMENSION,MIN_DIMENSION]
ACCEPTS: x, y (int pointers) to store values in
RETURNS: (none)
REMARKS: Random number generator should be seeded with a call to srand()
*/
*x = rand() % (MAX_DIMENSION-MIN_DIMENSION+1) + MIN_DIMENSION;
*y = rand() % (MAX_DIMENSION-MIN_DIMENSION+1) + MIN_DIMENSION;
return;
}
/*-------------------------------------------------------------------------*/
MATRIX* fill_matrix (MATRIX* m) {
/*
PURPOSE: Initialize a matrix of doubles with random values
ACCEPTS: m - MATRIX pointer
RETURNS: m
REMARKS: (none)
*/
int ix,iy; // loop indices
for (ix = 0; ix < m->rows; ix++) {
for (iy = 0; iy < m->cols; iy++) {
m->data[ix][iy] = (double)rand() / RAND_MAX * (MAX_DOUBLE+1);
}
}
return m;
}
/*-------------------------------------------------------------------------*/
void add_matrices (MATRIX* m1, MATRIX* m2, MATRIX* r) {
/*
PURPOSE: Add two matrices together
ACCEPTS: m1, m2, r - MATRIX pointers
RETURNS: (none)
REMARKS: The 'r' parameter stores the sum of m1 + m2
*/
int ix,iy; // loop indices
// free the old result matrix
free_matrix(r);
// check that m1 and m2 are the same size
if (m1->rows != m2->rows || m1->cols != m2->cols) {
return;
}
// initialize new result matrix
if (NULL == init_matrix(r, m1->rows, m1->cols)) {
return;
}
// add matrices
for (ix = 0; ix < m1->rows; ix++) {
for (iy = 0; iy < m1->cols; iy++) {
r->data[ix][iy] = m1->data[ix][iy] + m2->data[ix][iy];
}
}
return;
}
/*-------------------------------------------------------------------------*/
void invert_matrix (MATRIX* m) {
/*
PURPOSE: Inverts the given matrix
ACCEPTS: m - MATRIX to be inverted
RETURNS: (none)
REMARKS: After inversion, m->rows and m->cols are swapped
*/
int ix, iy; // loop indices
MATRIX tmp;
if (NULL == init_matrix(&tmp, m->cols, m->rows)) {
return;
}
for (ix = 0; ix < m->rows; ix++) {
for (iy = 0; iy < m->cols; iy++) {
tmp.data[iy][ix] = m->data[ix][iy];
}
}
free_matrix(m);
m->rows = tmp.rows;
m->cols = tmp.cols;
m->data = tmp.data;
return;
}
/*-------------------------------------------------------------------------*/
void multiply_matrices (MATRIX* m1, MATRIX* m2, MATRIX* r) {
/*
PURPOSE: Multiplies two matrices together
ACCEPTS: m1, m2, r - MATRIX pointers
RETURNS: (none)
REMARKS: m2 should be inversely sized from m1
ie, if m1 is 2x3, m2 should be 3x2
*/
int i, j, k; // loop indices
// free the old result matrix
free_matrix(r);
// check that m1 and m2 are inversely sized
if (m1->cols != m2->rows || m1->rows != m2->cols) {
return;
}
// initialize new result matrix (will be square)
if (NULL == init_matrix(r, m1->rows, m1->rows)) {
return;
}
// multiply
for (i = 0; i < m1->rows; i++ ) {
for (j = 0; j < m1->rows; j++) {
r->data[i][j] = 0.0; // initialize result
for (k = 0; k < m1->cols; k++) {
r->data[i][j] += m1->data[i][k] * m2->data[k][j];
}
}
}
return;
}
/*-------------------------------------------------------------------------*/
void print_matrix (char* label, MATRIX* m) {
/*
PURPOSE: Prints a matrix to the screen
ACCEPTS: label - string to print out before the matrix
m - MATRIX pointer
RETURNS: (none)
*/
int ix,iy; // loop indices
printf( "%s\n", label );
if (NULL == m->data) {
printf("Error with matrix.\n");
return;
}
for (ix = 0; ix < m->rows; ix++) {
for (iy = 0; iy < m->cols; iy++) {
printf( "% 8.2f ", m->data[ix][iy] );
}
printf( "\n" );
}
printf( "\n" );
return;
}
/*-------------------------------------------------------------------------*/