#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
/* ------------------------------------------------------
* Data structure of a matrix
-------------------------------------------------------- */
#define STR_ELEM "%lf " /* String to read/write the item elem_t */
#define ELEMSEP "%lf, " /* String to write the result elem_t */
typedef double elem_t;
typedef struct matrix_t {
unsigned rows, cols;
unsigned start; /* Lower array bound */
unsigned end; /* Upper array row bound */
elem_t **data;
elem_t **_data; /* Pointer to the mem block */
} matrix_t;
/* ------------------------------------------------------
* Prints error messages
-------------------------------------------------------- */
void error(char *msg)
{
printf("Error: %s\n", msg);
exit(1);
}
/* ------------------------------------------------------
* Prints an error when there is not enough memory to
* allocate a matrix
-------------------------------------------------------- */
void error_not_enough_memory(void)
{
error("There is not enough memory to allocate a matrix");
}
/* ------------------------------------------------------
* Allocates memory for "rows" pointers.
* Then memory for "cols" numbers are allocated for rows
* between "start" and "end"
* Other rows aren't allocated
-------------------------------------------------------- */
matrix_t *matrix_alloc(unsigned rows, unsigned cols, unsigned start, unsigned end)
{
matrix_t *result = malloc(sizeof(matrix_t));
unsigned row;
if (!result)
error_not_enough_memory();
result->rows = rows;
result->cols = cols;
result->start = start;
result->end = end;
result->_data = malloc(rows * sizeof(elem_t *));
if (!result->_data)
error_not_enough_memory();
result->data = result->_data - start;
for (row = start; row < end; row++) {
result->data[row] = malloc(sizeof(elem_t) * cols);
if (!result->data[row])
error_not_enough_memory();
}
return result;
}
/* ------------------------------------------------------
* Reads a chunk of a matrix from file
------------------------------------------------------ */
matrix_t *matrix_read_chunk(char *fname, unsigned id, unsigned N)
{
unsigned start, end, chunk_size;
unsigned rows, cols, row, col;
unsigned div, rest;
matrix_t *r;
elem_t dummy;
FILE *f = fopen(fname, "rt");
if (!f) {
printf("No se pudo abrir fichero '%s\n'", fname);
exit(1);
}
fscanf(f, "%u %u\n", &rows, &cols);
div = rows / N;
rest = rows % N;
if (id < rest) {
chunk_size = div + 1;
start = id * chunk_size;
}
else {
chunk_size = div;
start = id * chunk_size + rest;
}
end = start + chunk_size;
r = matrix_alloc(chunk_size, cols, start, end);
for (row = 0; row < start; row++)
for (col = 0; col < cols; col++) {
fscanf(f, STR_ELEM, &dummy);
}
for (; row < end; row++)
for (col = 0; col < cols; col++) {
fscanf(f, STR_ELEM, &(r->data[row][col]));
}
fclose(f);
return r;
}
/* ------------------------------------------------------
* Reads a matrix from file
-------------------------------------------------------- */
matrix_t *matrix_read(char *fname)
{
return matrix_read_chunk(fname, 0, 1);
}
/* ------------------------------------------------------
* Reads a matrix from STDOUT
* ------------------------------------------------------ */
matrix_t *matrix_read_stdout()
{
unsigned rows, cols, r, c;
matrix_t *m;
scanf("%u %u", &rows, &cols);
m = matrix_alloc(rows, cols, 0, rows);
for (r = 0; r < rows; r++)
for (c = 0; c < cols; c++) {
scanf(STR_ELEM, &(m->data[r][c]));
}
return m;
}
/* ------------------------------------------------------
* Prints the content of a matrix, in a Perl format
-------------------------------------------------------- */
void matrix_print(matrix_t *m)
{
unsigned row, col;
if (!m) return;
printf("[ ");
for (row = m->start; row < m->end; row++) {
printf("[ ");
for (col = 0; col < m->cols; col++) {
printf(ELEMSEP, m->data[row][col]);
}
printf("],\n");
}
printf("]\n");
}
/* ------------------------------------------------------
* Returns the scalar product between the row "row_m1" of
* the matrix "m1" and the column "col_m2" of the matrix
* "m2"
-------------------------------------------------------- */
elem_t p_escalar(matrix_t *m1, matrix_t *m2, unsigned row_m1, unsigned col_m2)
{
unsigned i;
elem_t result = 0;
for (i = 0; i < m1->cols; i++)
result += m1->data[row_m1][i] * m2->data[i][col_m2];
return result;
}
/* ------------------------------------------------------
* Returns the product between the matrix "m1" and the
* matrix "m2"
------------------------------------------------------ */
matrix_t *matrix_mult(matrix_t *m1, matrix_t *m2)
{
matrix_t *r = NULL;
unsigned rows, cols;
unsigned row, col;
if (!m1 || !m2)
error("One of the matrix is null");
rows = m1->end - m1->start;
cols = m2->cols;
r = matrix_alloc(rows, cols, m1->start, m1->end);
for (row = m1->start; row < m1->end; row++)
for (col = 0; col < cols; col++)
r->data[row][col] = p_escalar(m1, m2, row, col);
return r;
}
/* ------------------------------------------------------
* Main program
-------------------------------------------------------- */
int main(int argc, char *argv[])
{
matrix_t *m1, *m2, *m3;
struct timeval ini, end;
double t1, t2;
unsigned id, N;
if (argc != 5) {
printf("Parameters: matrix <id> <N> <file m1> <file m2>\n");
printf("Con:\n");
printf("\t<id> Number of process (0..N-1)\n");
printf("\t<N> Total number of processes\n");
printf("\t<file m1> Matrix A\n");
printf("\t<file m2> Matrix B\n");
exit(2);
}
id = atoi(argv[1]);
N = atoi(argv[2]);
m1 = matrix_read_chunk(argv[3], id, N);
m2 = matrix_read(argv[4]);
//gettimeofday(&ini, NULL);
m3 = matrix_mult(m1, m2);
//gettimeofday(&end, NULL);
//t1 = ini.tv_sec+(ini.tv_usec/1000000.0);
//t2 = end.tv_sec+(end.tv_usec/1000000.0);
//printf("Elapsed Time: %.6lf seconds\n", (t2 - t1));
matrix_print(m3);
return EXIT_SUCCESS;
}