Using sparse matrix library files in C - c

I'm working on a large scale project in which I'm designing a sparse matrix vector application but I'm still working to understand the code. I'm beginning by building the foundation for the application but I've run into a segmentation fault when executing the program. I've tracked the problem to this loop within the MatrixRead function and am enclosing the code below. When the program is executed I tried programming in some test messages and the program appears to execute all the loops but it returns the segmentation fault at the end. Of course, this is all just speculation. Any help would be awesome. Thanks!
while (ret != EOF && row <= mat->rows)
{
if (row != curr_row) // Won't execute for first iteration
{
/* store this row */
MatrixSetRow(mat, curr_row, len, ind, val);
/* check if the previous row is zero */
i = 1;
while(row != curr_row + i)
{
mat->lens[curr_row+i-1] = 0;
mat->inds[curr_row+i-1] = 0;
mat->vals[curr_row+i-1] = 0;
i++;
}
curr_row = row;
/* reset row pointer */
len = 0;
}
ind[len] = col;
val[len] = value;
len++;
ret = fscanf(file, "%lf %lf %lf", &r1, &c1, &value);
col = (int) (c1);
row = (int) (r1);
}
/* Store the final row */
if (ret == EOF || row > mat->rows)
MatrixSetRow(mat, mat->rows, len, ind, val);
Here's the code for the MatrixSetRow function:
/*--------------------------------------------------------------------------
* MatrixSetRow - Set a row in a matrix. Only local rows can be set.
* Once a row has been set, it should not be set again, or else the
* memory used by the existing row will not be recovered until
* the matrix is destroyed. "row" is in global coordinate numbering.
*--------------------------------------------------------------------------*/
void MatrixSetRow(Matrix *mat, int row, int len, int *ind, double *val)
{
row -= 1;
mat->lens[row] = len;
mat->inds[row] = (int *) MemAlloc(mat->mem, len*sizeof(int));
mat->vals[row] = (double *) MemAlloc(mat->mem, len*sizeof(double));
if (ind != NULL)
memcpy(mat->inds[row], ind, len*sizeof(int));
if (val != NULL)
memcpy(mat->vals[row], val, len*sizeof(double));
}
I'm also including the code for the Matrix.h file that went with it, where the members of Matrix are defined:
#include <stdio.h>
#include "Common.h"
#include "Mem.h"
#ifndef _MATRIX_H
#define _MATRIX_H
typedef struct
{
int rows;
int columns;
Mem *mem;
int *lens;
int **inds;
double **vals;
}
Matrix;

Related

Unable to read a maze of chars and put it into a bidimensional array

I am making a maze solving game. There is a function in the middle of the game that saves the progress and prints everything into the file. But now i want to read the maze, the character, etc from the file and put it into a bidimensional array but i am not being able to do so.
The array is declared globally (because of its use in several functions) and it is maze[30][30]. N is also declared globally as a variable size but at this point it should be 10. filePath too and it gives the name of the file.
This is how they are declared globally.
int N = 10;
char* filePath = "./save.txt";
char maze[30][30];
This is the read function:
void ler()
{
int i, j;
ex=1; ey=0;
sx=N-2; sy=N-1;
int aux;
FILE *fp = fopen(filePath, "r");
if (fp == NULL)
{
printf("Unable to perform.");
return;
}
system("cls");
for(i=0 ; i<N ; i++)
{
for(j=0 ; j<N ; j++)
{
fscanf(fp, "%c", maze[j][i]);
}
}
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
printf("%c", maze[j][i]); //Double print just for visuals
printf("%c", maze[j][i]);
}
printf("\n");
}
fclose(fp);
}
This is the save function:
void save(char maze[30][30]){
int i,j;
FILE *fp = fopen(filePath, "w");
if(fp==NULL){
printf("Unable to perform.");
return;
}
for(i=0 ; i<N ; i++){
for(j=0 ; j<N ; j++){
fprintf(fp, "%c", maze[j][i]);
fprintf(fp, "%c", maze[j][i]);
}
fprintf(fp, "\n", maze[j][i]);
}
fclose(fp);}
At this point it should only be possible to print the maze but it is not doing even that.
What save.txt file looks like after saving
The weird II is the caharcter and the other is like a highscore thing.
Using multidimensional arrays in C is actually more pain than they're worth. A much better option is to use a structure with a dynamically allocated array describing the maze, and accessor functions to examine and change the maze cells. Instead of putting markers in the maze data, you can put start/end/current location coordinates in the structure.
(I do realize that this does not answer the OP's stated question, but this is an answer to the underlying problem OP is trying to solve.)
Consider the following example. It limits the maze size to 255×255, but because each coordinate and maze cell is always just one byte, the save files are portable between architectures, as there is no byte order (endianness) to worry about. (You, as the programmer, do need to choose to use only codes 0..255 in the maze, though, to keep the data portable; the functions below won't enforce that.)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct {
unsigned char row;
unsigned char col;
} mazepoint;
typedef struct {
unsigned char rows;
unsigned char cols;
unsigned char *cell;
mazepoint player;
} maze;
#define OUTSIDE 0
static inline unsigned char maze_get(maze *const m,
const int row,
const int col)
{
if (m &&
row >= 0 && row < (int)(m->rows) &&
col >= 0 && col < (int)(m->cols))
return m->cell[ (size_t)col + (size_t)(m->cols) * (size_t)row ];
else
return OUTSIDE;
}
static inline unsigned char maze_set(maze *const m,
const int row,
const int col,
const unsigned char val)
{
if (m &&
row >= 0 && row < (int)(m->rows) &&
col >= 0 && col < (int)(m->cols))
return m->cell[ (size_t)col + (size_t)(m->cols) * (size_t)row ] = val;
else
return OUTSIDE;
}
static inline void maze_free(maze *const m)
{
if (m) {
free(m->cell);
m->rows = 0;
m->cols = 0;
m->cell = NULL;
}
}
int maze_create(maze *const m,
const int rows,
const int cols)
{
size_t cells = (size_t)rows * (size_t)cols;
unsigned char *cell;
if (!m)
return -1; /* NULL reference to a maze variable! */
if (rows < 1 || rows > 255 ||
cols < 1 || cols > 255)
return -1; /* Invalid number of rows or columns! */
cell = malloc(cells); /* sizeof (unsigned char) == 1. */
if (!cell)
return -1;
/* Initialize all maze cells to OUTSIDE. */
memset(cell, OUTSIDE, cells);
m->rows = rows;
m->cols = cols;
m->cell = cell;
/* Let's initialize player location to upper left corner. */
m->player.row = 0;
m->player.col = 0;
return 0; /* Success. */
}
int maze_save(maze *const m, const char *filename)
{
size_t cells;
FILE *out;
if (!m || m->rows < 1 || m->cols < 1)
return -1; /* No maze to save! */
if (!filename || !filename[0])
return -1; /* NULL or empty filename! */
cells = (size_t)(m->rows) * (size_t)(m->cols);
out = fopen(filename, "wb");
if (!out)
return -1; /* Cannot open file for writing! */
do {
/* First byte is the number of rows. */
if (fputc(m->rows, out) == EOF)
break;
/* Second byte is the number of columns. */
if (fputc(m->cols, out) == EOF)
break;
/* rows*cols bytes of maze data follows. */
if (fwrite(m->cell, 1, cells, out) != cells)
break;
/* Player location follows. */
if (fputc(m->player.row, out) == EOF)
break;
if (fputc(m->player.col, out) == EOF)
break;
/* You can save additional data at this point. */
/* That completes the save file. Ensure it is correctly saved. */
if (fflush(out))
break;
if (fclose(out))
break;
/* Maze successfully saved. */
return 0;
} while (0);
/* Save failed. */
fclose(out);
remove(filename);
return -1;
}
int maze_load(maze *const m, const char *filename)
{
size_t cells;
unsigned char *cell;
int rows, cols, r, c;
FILE *in;
if (!m)
return -1; /* No reference to a maze variable to load into! */
/* Just in case, we clear the maze first. Might help finding bugs! */
m->rows = 0;
m->cols = 0;
m->cell = NULL;
if (!filename || !filename[0])
return -1; /* NULL or empty filename! */
in = fopen(filename, "rb");
if (!in)
return -1; /* Cannot open file for reading. */
rows = fgetc(in);
cols = fgetc(in);
if (rows == EOF || rows < 1 || rows > 255 ||
cols == EOF || cols < 1 || cols > 255) {
fclose(in);
return -1; /* Not a saved maze! */
}
cells = (size_t)(rows) * (size_t)(cols);
cell = malloc(cells);
if (!cell) {
fclose(in);
return -1; /* Not enough memory available! */
}
do {
/* Read maze cell data. */
if (fread(cell, 1, cells, in) != cells)
break;
/* Player location. */
r = fgetc(in);
c = fgetc(in);
if (r == EOF || r < 0 || r > 255 ||
c == EOF || c < 0 || c > 255)
break;
m->player.row = r;
m->player.col = c;
/* Load other saved data here. */
/* All data read successfully. */
fclose(in);
m->rows = rows;
m->cols = cols;
m->cell = cell;
return 0;
} while (0);
/* Read error. */
fclose(in);
free(cell);
return -1;
}
In your own program, you'd create a maze thus:
maze m;
/* Create a 20-row, 30-column maze. */
if (maze_create(&m, 20, 30)) {
/* Failed to create maze! Show an error message. */
exit(EXIT_FAILURE);
}
To save the maze to say maze.dat, you use
m.player.row = /* row where the player is */
m.player.col = /* column where the player is */
if (maze_save(&m, "maze.dat")) {
/* Failed! Show an error message. */
exit(EXIT_FAILURE);
}
If you look at the example code, you can add additional data, especially points like the player place, to be saved and loaded along with the maze cells themselves.
To destroy a maze when it is no longer needed, use
maze_free(&m);
To load a saved maze, say from maze.dat, use
if (maze_load(&m, "maze.dat")) {
/* Failed! Show an error message. */
exit(EXIT_FAILURE);
}
/* Restore player place from m.player.row and m.player.col */
The accessor function maze_get() is not limited to the valid coordinates (0 through rows-1 or cols-1, inclusive). If you examine outside the maze itself, it will just return the value of the OUTSIDE macro. For example,
if (maze_get(&m, row, col) == 5) {
/* That cell has value 5 */
} else {
/* Either the cell has a different value,
or row,col is outside the maze. */
}
Similarly, you can try to set any cell value safely. It will only "stick" if it is within the valid maze coordinate range, however; elsewhere it will return OUTSIDE:
if (maze_set(&m, row, col, 5) == 5) {
/* Changed cell value to 5 */
} else {
/* row,col is outside the maze. */
}
The reason I wrote the accessor macros that way, is that it makes rendering only a part of the maze very simple. If the view is viewrows by viewcols in size, centered at row and col, then you can render the view using a simple loop:
const int top = row - viewrows / 2;
const int left = col - viewcols / 2;
int vr, vc;
for (vr = 0; vr < viewrows; vr++) {
for (vc = 0; vc < viewcols; vc++) {
const unsigned char v = maze_get(&m, top+vr, left+vc);
/* Draw v at row vr, col vc */
}
}
and the cells are even drawn in the same order as you read this text; from top to bottom, left to right.
Note that instead of using the maze cell values for character codes, you should use a lookup table instead. For example,
int cell_char[256];
Instead of printing cell values directly, you'd print the corresponding cell_char, for example
fputc(cell_char[maze_get(&m, row, col)], stdout);
That way you can group e.g. different wall characters into a consecutive range, or even use the individual bits in the 8-bit cell value as identifiers. The maze cells then describe the logical contents in that maze cell, rather than its visual representation, with the logical-to-visual mapping in a separate array.
If you used Gtk+, you could have an array of GtkImage pointers,
GtkImage *cell_image[256] = {0}; /* All NULL by default */
or using SDL, you could have the maze cells as textures you can render,
SDL_Texture *cell_texture[256] = {0}; /* All NULL by default */
and in both cases, read them from either one large image (say, divided into 16×16 exact same size rectangles), or from individual image files.
For example, you could decide that the four least significant bits in the cell value specify whether movement from that cell up (previous row), down (next row), left (previous column), or right (next column) is possible:
#define CAN_GO_UP(value) ((value) & (1 << 0)) /* == 1 */
#define CAN_GO_DOWN(value) ((value) & (1 << 1)) /* == 2 */
#define CAN_GO_LEFT(value) ((value) & (1 << 2)) /* == 4 */
#define CAN_GO_RIGHT(value) ((value) & (1 << 3)) /* == 8 */
Note that this allows you to do "trap walls": passages that only work one way. Maze cell values that are multiples of 16 (0, 16, 32, 48, 64, 80, 96, ..., 208, 224, and 240) represent completely blocked cells: no way out. +1 allows passage up; +2 allows passage down; +3 allows passage up and down; +4 allows passage left; +5 allows passage left and up; +6 allows passage left and down; +7 allows passage up, left, and down; +8 allows passage right; +9 allows passage up and right; +10 allows passage down and right; +11 allows passage up, down, and right; +12 allows passage left and right; +13 allows passage up, left, and right; +14 allows passage down, left, and right; and +15 allows passage up, down, left, and right.
I would personally also recommend using the wide version of the ncurses library (ncursesw). (I do not use Windows, so I am not exactly sure how you install and use it in windows, but the ncurses home page does have downloads when using mingw.)
Then, you would have a much wider variety of glyphs you could use. (When using UTF-8 locales, potentially the entire Unicode glyph set -- the Box Drawing block especially would be useful for maze drawing, and most of those glyphs are also available in the old CP437 codepage, which means they should work both in Windows and non-Windows terminals nicely.)
In that case, you'd probably use
cchar_t cell_char[256];
As I mentioned above, you could even do a graphical version (perhaps later on, extending your terminal version?) in C using SDL or GTK+. (Note that the above separation between logical maze cell content value and the visual describing the cell also means you can, at runtime, choose between "themes", by having more than one set of cell images. That allows you to start with crude informational versions, for debugging, and then add visual goodness.)
The approach shown in this answers allows you to start with a simple terminal-based game, and if you decide you want to, add support for graphical UI, with image-based maze cells, without having to rewrite any of your core maze code.

Input in specific format (matrix)

I have an issue with input in my homework. On stdin, I will get a specifically formatted input.
In first line, there will be 2 integers, that determine the size of a matrix (rows and cols). All the lines after represent rows of the matrix.
I essentially want to do something like getline(), but I don't want to use getline(). In fact I can't, its forbidden in the homework. Therefore I have to scan int by int (or char by char I guess). The issue here is I need it to be bulletproof (almost). Dummy-proof at least.
I'm imagining a big while loop that keeps going until EOF and inside that another loop (perhaps?) which always reads a line, saves it to my allocated matrix and carries on to the next. I'm aware that I'm supposed to be checking for '\n', but I kind of lack the ability to think of a solution today.
Here's what I'm working with: My matrices are a structure.
struct Matrix{
int nrows;
int ncols;
int** matrix;
};
I then have multiple functions.
A function to dynamically allocate space for the matrix of specific size:
struct Matrix init_matrix(int r, int c)
{
struct Matrix mat;
mat.nrows = r;
mat.ncols = c;
mat.matrix = calloc(r, sizeof(int *));
for(int i = 0; i < r; ++i)
{
*(mat.matrix+i) = calloc(c, sizeof(int));
}
return mat;
}
A function to free the previously allocated space:
void free_matrix(struct Matrix mat)
{
int top = mat.nrows;
for(int i = 0; i < top; ++i)
{
free(mat.matrix[i]);
}
free(mat.matrix);
}
Those 2 functions work perfectly fine.
Now I'm trying to make a function create_matrix(void) (at least I think it shouldn't take any args), that will read the input I'm supposed to receive, for example:
3 3
1 2 3
4 5 6
7 8 9
when the function reads the input, it could tell if the input is incorrect or is in incorrect format and exit the program with corresponding exit value (like 100 f.e.) If the input is correct and in correct format, it calls init_matrix() and then saves input to the matrix.
For your deeper understanding: the whole input I'm supposed to receive is:
matrix A (like above, size in first line, values in lines after)
an operation (+,-,*)
matrix B
Then execute the operation (A*B, A+B etc.). I'm trying to make most things into functions, so the main would be very simple, f.e.
int main(int argc, char *argv[])
{
struct Matrix mat1 = create_matrix();
char operation = get_operation();
struct Matrix mat2 = create_matrix();
struct Matrix result = compute(mat1,mat2, operation);
return 0;
}
Something in those lines, if you get me. The thing is I want to make the program complex enough so that I could later edit it to handle a bigger sequence (up to 100) of matrices than just two. Right now I could do it the dirty way, make it work for two matrices with one operation, but that's not what I really want.
Well, here's how I solved it. It works. It's not anywhere close to perfect, but it works, upload system took it and gave it full amount of points, so I'm satisfied.
struct Matrix read_matrix(FILE *fp)
{
struct Matrix mat;
//FIRST LINE
int ch;
int i = 0;
int n = 20;
char* line = calloc(n,sizeof(char));
while((ch = fgetc(fp)) != EOF && ch != '\n')
{
*(line + i++) = ch;
}
*(line + n-1) = '\0';
int r,c;
int k = sscanf(line,"%d %d", &r, &c);
if(k != 2)
{
fprintf(stderr, "Error: Chybny vstup!\n");
exit(100);
}
free(line);
//MATRIX
line = calloc(c, sizeof(int));
mat = init_matrix(r, c);
i = 0;
r = 0;
while(r < mat.nrows && (ch = fgetc(fp)))
{
if(ch == '\n' || ch == EOF)
{
*(line + i) = '\0';
int offset;
char *data = line;
for(int j = 0; j < mat.ncols; ++j)
{
int d = sscanf(data, " %d%n", &mat.matrix[r][j], &offset);
if(d != 1){
fprintf(stderr, "Error: Chybny vstup!\n");
exit(100);
}
data += offset;
}
i = 0;
++r;
if(ch == EOF){
break;
}
} else
{
*(line + i++) = ch;
}
}
free(line);
return mat;
}

rand() generating different values when used in valgrind

I'm trying to randomly generate rooms in a two-dimensional array of size 100x100. If the room being generated collides with an already existing room, it generates new points for the room. The generation code makes sense conceptually, but when I try to run, the program loops endlessly, and checking the log reveals why.
Room created successfully with dimensions x=0, y=0, width=976761120, height=809120052
For some reason, at lines 65-68, inside create_room(), the width and height for the room are being randomly assigned huge numbers, when they should be between 1 and 11. Just for fun, I ran the program through Valgrind using the options --track-origins=yes -v, and I what I found surprised me. Suddenly, the program would run!
Room created successfully with dimensions x=0, y=0, width=0, height=0
While still not exactly what I wanted, this at least prevents an infinite loop of collisions being detected with an impossibly huge room.
So, my question is, why is the code generating such large numbers when executed normally, but generate smaller numbers when in Valgrind?
Here's the code for the program.
#include <time.h>
#include <stdlib.h>
#include "global.h"
#include "draw.h"
#include "log.h"
#include "generate.h"
#define NUM_ROOMS 10
#define ROOM_SIZE 10
#define MAP_HEIGHT 100
#define MAP_WIDTH 100
static struct ROOM* create_room (unsigned int);
struct ROOM {
int x, y, width, height;
int feature;
};
struct ROOM* rooms[NUM_ROOMS] = {NULL};
static FILE* gen_log;
static WINDOW* gen_window;
int** generate_dungeon(unsigned int seed){
char* log_entry = malloc (80);
int i = 0, j, k;
gen_window = create_window (0, 0, LINES, COLS);
gen_log = log_open (GEN_LOG);
if (seed == 0){
time_t t;
seed = time (&t);
}
srand (seed);
for (int i = 0; i < NUM_ROOMS; i++){
rooms[i] = create_room (seed);
sprintf (log_entry,"Room created successfully with dimensions x=%d, y=%d, width=%d, height=%d\n", rooms[i]->x, rooms[i]->y, rooms[i]->width, rooms[i]->height);
LOG_DEBUG (gen_log,log_entry);
}
LOG_DEBUG(gen_log, "Beginning to draw rooms\n");
for (i=0;i < NUM_ROOMS;i++){
sprintf (log_entry, "Drawing room %d\n", i);
LOG_DEBUG (gen_log, log_entry);
for (j = rooms[i]->y; j < rooms[i]->y + rooms[i]->height; j++){
for (k = rooms[i]->x; k < rooms[i]->x + rooms[i]->width; k++){
sprintf (log_entry, "Clearing %d,%d]\n", j,k);
LOG_DEBUG (gen_log, log_entry);
map_array[j][k] = 1;
}
}
}
destroy_window (gen_window);
}
static struct ROOM* create_room (unsigned int seed){
int i = 0, flag;
srand (seed);
if (rooms[0] == NULL)
flag = 0;
else
flag = 1;
char* log_entry = malloc (80);
struct ROOM* new_room = malloc (sizeof(struct ROOM));
while (flag){
draw_notify (gen_window, "Creating room\n");
new_room->x = (rand() % MAP_WIDTH);
new_room->y = (rand() % MAP_HEIGHT);
new_room->width = (rand() % ROOM_SIZE + 1);
new_room->height = (rand() % ROOM_SIZE + 1);
sprintf (log_entry, "New room created with points x=%d, y=%d,width=%d, height=%d\n", new_room->x, new_room->y, new_room->width, new_room->height);
LOG_DEBUG (gen_log, log_entry);
draw_notify (gen_window, "Log entry made\n");
if (new_room->x + new_room->width >= MAP_WIDTH || new_room->y + new_room->height >= MAP_HEIGHT){
LOG_DEBUG (gen_log, "Room out of bounds\n");
continue;
}
i=0;
draw_notify(gen_window, "Entering loop\n");
while (rooms[i] != NULL && i < NUM_ROOMS){
sprintf (log_entry, "Testing room %d\n", i);
draw_notify (gen_window, log_entry);
LOG_DEBUG(gen_log, log_entry);
if (new_room->x < rooms[i]->x + rooms[i]->width &&
new_room->x + new_room->width > rooms[i]->x &&
new_room->y < rooms[i]->y + rooms[i]->height &&
new_room->y + new_room->height > rooms[i]->y){
sprintf (log_entry, "Collision detected with room %d\n", i);
draw_notify (gen_window, log_entry);
LOG_DEBUG (gen_log, log_entry);
flag = 1;
break;
}
else{
sprintf (log_entry, "Room %d passed.\n", i);
flag = 0;
i++;
}
}
draw_notify(gen_window, "Exited loop\n");
}
return new_room;
}
You have some logic errors and end up with uninitialized values.
You initialize rooms to be an array of NULL pointers.
In create_room, you have:
if (rooms[0] == NULL)
flag = 0;
else
flag = 1;
First time around, flag will be set to 0. And then, you use:
struct ROOM* new_room = malloc (sizeof(struct ROOM));
while (flag){
since flag is set to 0, nothing under the while gets executed and you end up with uninitialized members in new_room.
You need to re-think your logic and make sure that you initialize members of new_room always.

Matrix calculation with PBLAS algorithm - multi threads with MPI

I'm currently developping a C code with mpi for matrix multiplication. I have functions already implemented as mult or multadd defined in an other file, working well.
But my file pblas.c compiles, but crashes when running.
I run my project on a university server, which has mli installed.
Where am i wrong in my pblas code ?
/**********************************************************************
This file is just a pattern for pblas parallel multiplication
There are comments beginning with TO ADD that tell what must be done
where they are placed. Thus, just add the correct lines of code and
everything will work fine !
*********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include "commfct.h"
#include "toolsfct.h"
void usage() {
fprintf(stderr,"usage : pblas bloc_size\n\t bloc_size : gives the size of blocs owned by each processor.\n");
exit(1);
}
int main(int argc, char **argv) {
int me,nbProc;
int ligMe,colMe;
int blockSize;
int i,j;
double t;
if (argc != 2) {
usage();
}
blockSize = atoi(argv[1]);
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &me);
MPI_Comm_size(MPI_COMM_WORLD, &nbProc);
int P = (int)sqrt(nbProc); // P = the number of rows of proc.
int Q = P; // Q = the number of columns of proc.
if ((P*Q) != nbProc) {
if (me == 0) {
fprintf(stderr,"!!! CRITICAL ERROR : number of processors must be 4, 9, 16, ...\nAborting\n");
}
exit(1);
}
createGridComm(me,P,Q);
ligMe = me / Q;
colMe = me % Q;
// allocate memory for matrices
double *A,*Btmp, *B,*C,*CC;
A = (double *)malloc(blockSize*blockSize*sizeof(double));
B = (double *)malloc(blockSize*blockSize*sizeof(double));
Btmp = (double *)malloc(blockSize*blockSize*sizeof(double));
C = (double *)malloc(blockSize*blockSize*sizeof(double));
CC = (double *)malloc(blockSize*blockSize*sizeof(double));
/* fill blocks with pseudo values
NOTE : these values should not be changed so that
the check below is valid
*/
for(i=0;i<blockSize*blockSize;i++) {
A[i] = 2.0+(double)me;
B[i] = 1.0+(double)colMe;
C[i] = (double)me / 10.0;
}
/* CAUTION : in the following, A,B C are supposed to be stored
column after column, with each column of size blockSize.
Thus A(0,0) and A(1,0) are contiguous in memory, but
A(0,0) and A(0,1) are separated by blockSize cells.
*/
t = dclock(CLOCK_S);
MPI_Status status;
//main Loop
for(i=0;i<P;i++) {
/*************************************
Etape 1 et 2: Transposition column i (in step i) of B-blocks . stock in Btmp.
**************************************/
if(colMe==i){
if(ligMe==colMe) {
MPI_Bcast(Btmp,blockSize*blockSize,MPI_DOUBLE,ligMe,commCol);
multadd(A,B,C,blockSize);
}
else {
int dest = colMe * Q + ligMe;
MPI_Send(B,blockSize*blockSize,MPI_DOUBLE,dest,TAG_TRANSPOSE, MPI_COMM_WORLD);
MPI_Bcast(Btmp,blockSize*blockSize,MPI_DOUBLE,dest%Q,commCol);
mult(A,Btmp,CC,blockSize);
}
}
else {
int dest = colMe*Q + ligMe;
if(dest%Q == i) {
MPI_Recv(Btmp,blockSize*blockSize,MPI_DOUBLE,dest,TAG_TRANSPOSE,MPI_COMM_WORLD,&status);
// Broadcast on the column
MPI_Bcast(Btmp,blockSize*blockSize,MPI_DOUBLE,colMe,commCol);
multadd(A,Btmp,C,blockSize);
}
else {
MPI_Bcast(Btmp,blockSize*blockSize,MPI_DOUBLE,i,commCol);
mult(A,Btmp,CC,blockSize);
}
}
if(colMe == i)
MPI_Reduce(MPI_IN_PLACE, C, blockSize*blockSize, MPI_DOUBLE, MPI_SUM, colMe, commLine);
else
MPI_Reduce(CC,NULL,blockSize*blockSize,MPI_DOUBLE,MPI_SUM,i,commLine);
}
t = dclock(CLOCK_S) -t;
printf("timing for %d : %f sec\n",me,t);
// checking for result correctness
int correct = 1;
double sum = 0.0;
for(i=0;i<P;i++) {
sum += 2.0+(ligMe*Q)+(double)i;
}
for(i=0;i<blockSize;i++) {
for(j=0;j<blockSize;j++) {
if (C[i+j*blockSize] != ((double)me/10.0 + sum*blockSize*(colMe+1.0))) {
correct = 0;
}
}
}
if (correct != 1) {
printf("multiplication result is not correct\n");
}
// free memory
free(A);
free(B);
free(C);
free(CC);
releaseGridComm();
MPI_Finalize();
return 0;
}
The trouble may come from indexes in MPI_Send(), MPI_Recv() or MPI_Bcast(). For instance, in MPI_Send(), the destinator shall call MPI_Recv(). In MPI_Recv(), the origin should have called MPI_Send(). Otherwise, you will get a deadlock. The code keeps on running, but it waits for messages.
From what you gave us, I guess you have two matrix A and B.
A0 | A1
...........
A2 | A3
To compute the first column of C, you need :
A0xB0 | A1xB2
...................
A2xB0 | A3xB2
I changed your code so that :
for each column i
i_th column of B is transposed in the i_th line of Btmp
i_th line of Btmp is broadcast to Btmp in each column.
Since the issue was about MPI, i reply with a MPI code that looks very close to yours, works but it does nothing, except communication operations...
/**********************************************************************
This file is just a pattern for pblas parallel multiplication
There are comments beginning with TO ADD that tell what must be done
where they are placed. Thus, just add the correct lines of code and
everything will work fine !
*********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include "mpi.h"
//#include "commfct.h"
//#include "toolsfct.h"
#define TAG_TRANSPOSE 42
void usage() {
fprintf(stderr,"usage : pblas bloc_size\n\t bloc_size : gives the size of blocs owned by each processor.\n");
exit(1);
}
int main(int argc, char **argv) {
int me,nbProc;
int ligMe,colMe;
int blockSize;
int i,j;
double t;
if (argc != 2) {
usage();
}
blockSize = atoi(argv[1]);
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &me);
MPI_Comm_size(MPI_COMM_WORLD, &nbProc);
int P = (int)sqrt(nbProc); // P = the number of rows of proc.
int Q = P; // Q = the number of columns of proc.
if ((P*Q) != nbProc) {
if (me == 0) {
fprintf(stderr,"!!! CRITICAL ERROR : number of processors must be 4, 9, 16, ...\nAborting\n");
}
exit(1);
}
//createGridComm(me,P,Q);
colMe = me / Q;
ligMe = me % Q;
MPI_Comm commCol, commLine;
//comes from http://static.msi.umn.edu/tutorial/scicomp/general/MPI/communicator.html
/* Split comm into row and column comms */
MPI_Comm_split(MPI_COMM_WORLD, ligMe, colMe, &commLine);
/* color by row, rank by column */
MPI_Comm_split(MPI_COMM_WORLD, colMe, ligMe, &commCol);
/* color by column, rank by row */
printf("[%d]:My coordinates are i j (%d,%d)\n",me,ligMe,colMe);
// allocate memory for matrices
double *A,*Btmp, *B,*C,*CC;
A = (double *)malloc(blockSize*blockSize*sizeof(double));
B = (double *)malloc(blockSize*blockSize*sizeof(double));
Btmp = (double *)malloc(blockSize*blockSize*sizeof(double));
C = (double *)malloc(blockSize*blockSize*sizeof(double));
CC = (double *)malloc(blockSize*blockSize*sizeof(double));
/* fill blocks with pseudo values
NOTE : these values should not be changed so that
the check below is valid
*/
for(i=0;i<blockSize*blockSize;i++) {
A[i] = 2.0+(double)me;
B[i] = 1.0+(double)colMe;
C[i] = (double)me / 10.0;
}
/* CAUTION : in the following, A,B C are supposed to be stored
column after column, with each column of size blockSize.
Thus A(0,0) and A(1,0) are contiguous in memory, but
A(0,0) and A(0,1) are separated by blockSize cells.
*/
// t = dclock(CLOCK_S);
MPI_Status status;
//main Loop
for(i=0;i<Q;i++) {
/*************************************
Etape 1 et 2: Transposition column i (in step i) of B-blocks . stock in Btmp.
**************************************/
if(colMe==i){
if(ligMe==colMe) {
MPI_Bcast(Btmp,blockSize*blockSize,MPI_DOUBLE,i,commCol);
// multadd(A,B,C,blockSize);
}
else {
int dest = ligMe * Q + i;//transpose !
MPI_Send(B,blockSize*blockSize,MPI_DOUBLE,dest,TAG_TRANSPOSE, MPI_COMM_WORLD);
MPI_Bcast(Btmp,blockSize*blockSize,MPI_DOUBLE,i,commCol);
// mult(A,Btmp,CC,blockSize);
}
}
else {
int from = i*Q + colMe;// transpose !
if(ligMe == i) {
MPI_Recv(Btmp,blockSize*blockSize,MPI_DOUBLE,from,TAG_TRANSPOSE,MPI_COMM_WORLD,&status);
// Broadcast on the column
MPI_Bcast(Btmp,blockSize*blockSize,MPI_DOUBLE,i,commCol);
// multadd(A,Btmp,C,blockSize);
}
else {
MPI_Bcast(Btmp,blockSize*blockSize,MPI_DOUBLE,i,commCol);
// mult(A,Btmp,CC,blockSize);
}
}
if(colMe == i)
MPI_Reduce(MPI_IN_PLACE, C, blockSize*blockSize, MPI_DOUBLE, MPI_SUM, colMe, commLine);
else
MPI_Reduce(CC,NULL,blockSize*blockSize,MPI_DOUBLE,MPI_SUM,i,commLine);
}
//t = dclock(CLOCK_S) -t;
printf("timing for %d : %f sec\n",me,t);
// checking for result correctness
int correct = 1;
double sum = 0.0;
for(i=0;i<P;i++) {
sum += 2.0+(ligMe*Q)+(double)i;
}
for(i=0;i<blockSize;i++) {
for(j=0;j<blockSize;j++) {
if (C[i+j*blockSize] <0.99999*((double)me/10.0 + sum*blockSize*(colMe+1.0)) || C[i+j*blockSize] >1.00001*((double)me/10.0 + sum*blockSize*(colMe+1.0)) ) {
correct = 0;
}
}
}
if (correct != 1) {
printf("multiplication result is not correct\n");
}
// free memory
free(A);
free(B);
free(C);
free(CC);
//releaseGridComm();
MPI_Finalize();
return 0;
}
Watch for the createGridComm(me,P,Q); I had to found something equivalent at http://static.msi.umn.edu/tutorial/scicomp/general/MPI/communicator.html
I also changed the test at the end of your code. Testing equality between double precision numbers will be too strict. Inequalities are better for floating-point numbers !
I hope this will help !
Bye,
Francis

Changing fixed bi-dimensional array to take size given at runtime

I've been trying to wrap my head around this the whole day...
The code that I have so far works as planed, the idea is that I'll have to change tCell * cells[3][5]; to take a size that's given at runtime. What changes do I need to make to retain the functionality?
typedef struct {
int active;
} tCell;
typedef struct {
tCell * cells[3][5];
} tGrid;
// creates a grid and initialize all the cells to NULL
tGrid *init_grid()
{
tGrid *grid= malloc(sizeof(tGrid));
if(grid == NULL)
exit(127); // failed to malloc
int i, j;
for(i=0; i < 3; i++)
for(j=0; j < 5; j++)
grid->cells[i][j]= NULL;
return grid;
}
// adds a cell to the grid
void add_cell(tGrid *grid)
{
tCell cell;
int y = rand() % 4;
if(grid->cells[0][y] != NULL)
exit(127); // cell is taken
cell.active = 1;
grid->cells[0][y] = &cell;
}
void remove_cell(tGrid *grid, int x, int y)
{
if(x < 0 || x > 3 || y < 0 || y > 5)
exit(127); // out of bounds
grid->cells[x][y]= NULL;
}
Basically, init_grid will have to take x and y as parameters:
tGrid *init_grid(int x, int y);
But then, how do I change tGrid struct definition? Whatever I've tried so far yielded a compiler error (e.g. tCell * cells[][];)
On a slightly related note, how do you read "tCell * cells[3][5];" outloud?
Note:
this is a C question
I'm using gcc 4.1 to compile the code
Easy.
typedef struct {
int rows;
int columns;
tCell **cells;
} tGrid;
And allocating:
tGrid *pGrid = (pGrid*)malloc(sizeof(tGrid));
/* check results etc */
pGrid->rows = rows;
pGrid->columns = columns;
pGrid->cells = (tCell**)malloc(sizeof(tCell*)*rows);
/* check results */
do{
pGrid->cells[rows-1] = (tCell*)malloc(sizeof(tCell)*columns);
/* check results */
} while (--rows);
Done.
Or, you can also do:
typedef struct {
int rows;
int columns;
tCell *cells;
} tGrid;
/*****whatever in the middle ***********/
pGrid->cells = (tCell*)malloc(sizeof(tCell)*rows*columns);
instead of the do-while loop. The difference is that in the first case, each row will be a separate array in the memory, which may be useful when handling the thing.
Of course, in the end, for each malloc there has to be a free.

Resources