0

I'd like to make an array (called Csend) and then create a function which modifies it slightly, such as by adding 0.05 to every element. The problem I'm having is with the formatting of the array, I'm not sure how to pass it into a function properly. I've allocated the memory in this way following this guide so that I can later put it in MPI_Send and MPI_Recv.

Here is my attempt:

#include "stdio.h"
#include "stdlib.h"
#include "mpi.h"
#include "math.h"


int main(int argc, char **argv) {

  int N = 32;
  int dim = 3;
  float a = 10.0; // size of 3D box
  int size, rank, i, j, k, q;
  float **C, **Csend, **Crecv;
  float stepsize = 0.05;

  MPI_Init(&argc, &argv);
  MPI_Comm_size(MPI_COMM_WORLD, &size);
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  float **alloc_2d_float(int rows, int cols) {
    float *data = (float *)malloc(N*dim*sizeof(float));
    float **array= (float **)malloc(N*sizeof(float*));
    for(i=0; i<N; i++) {
        array[i] = &(data[dim*i]);
     }
    return array;
}

  C = alloc_2d_float(N,dim);
  Csend = alloc_2d_float(N,dim);
  Crecv = alloc_2d_float(N,dim);

if(rank == 0) {
for (i = 0; i < N; i++) {
    for (j = 0; j < dim; j++) {
        Csend[i][j] = (float)rand()/(float)(RAND_MAX/a);
  }}
}

  // FUNCTION TO MODIFY MATRIX //
  float randomsteps(float *matrix, int N, int dim) {
  int i, j;
for(i = 0; i < N; i = i+2) {
        for (j = 0; j < dim; j++) {
*((matrix+i*N) + j) = *((matrix+i*N) + j) + stepsize;
}
}
return matrix;
  } 

C = randomsteps(Csend, 32, 3);
  for (i=0; i<N; i++){
    for (j=0; j<dim; j++){
      printf("%f, %f\n", Csend[i][j], C[i][j]);
    }
  }

 MPI_Finalize();

  return 0;
}

The problem I'm having is that formatted like it is here, I get error messages, and formatted in ways that didn't give error messages, C was just empty.

Here is the error message:

test.c: In function ‘randomsteps’:
test.c:46: error: incompatible types when returning type ‘float *’ but ‘float’ was expected
test.c: In function ‘main’:
test.c:49: warning: passing argument 1 of ‘randomsteps’ from incompatible pointer type
test.c:39: note: expected ‘float *’ but argument is of type ‘float **’
test.c:49: error: incompatible types when assigning to type ‘float **’ from type ‘float’

Thanks for the help!

Community
  • 1
  • 1
Chylomicron
  • 251
  • 1
  • 3
  • 10
  • It will be better if you can post a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). It's difficult to understand what your program is doing by looking at the posted code. – R Sahu Nov 19 '15 at 03:35
  • Well, what's wrong with it? (i.e. what are the error messages?) – user253751 Nov 19 '15 at 03:35
  • Sorry, I've edited it so there is more of the program. In this case, the error is "incompatible types when returning type ‘float *’ but ‘float’ was expected" which seems like a small problem, but every time I try to fix one thing it seems to spiral into three more problems. – Chylomicron Nov 19 '15 at 03:42
  • Where does the error occur? – mbaitoff Nov 19 '15 at 04:49
  • We will need to see the minimum complete example. Currently, there is no way to tell what the results of `Csend = alloc_2d_float(N,dim);` are, etc. The first comment requests a [**MCVE**](http://stackoverflow.com/help/mcve). Otherwise, all we can do is guess. One guess if you are using `malloc` instead of `calloc` in `alloc_2d_float`, then you are likely attempting to read from uninitialized values - which will not work... – David C. Rankin Nov 19 '15 at 04:52
  • Sorry, I've edited it further. I think it should be a good MCVE now. I also included the full error message I get in the post. The error is in the randomsteps function. – Chylomicron Nov 19 '15 at 05:04
  • 1
    Possible duplicate of [How to send a 2D array in MPI with variation for each processor](http://stackoverflow.com/questions/33773256/how-to-send-a-2d-array-in-mpi-with-variation-for-each-processor) – talonmies Nov 19 '15 at 05:35

1 Answers1

2

You are confusing between 1 dimensional representation of a matrix and a two dimensional pointer to pointer approach of it.

*((matrix+i*N) + j) = *((matrix+i*N) + j) + stepsize; -> This line implies that matrix is just linear collection and it is accessed like a matrix using index manipulation.

float **C; -> This implies you want a matrix which can be accessed as C[i][j].

Stick to any one of the representations. Also, since your function returns a matrix, the return type should be either float* (if the 2d matrix is considered linear with array manipulation) of float** if you want a 2d matrix without index manipulation access.

float* matrix = malloc(row * cols * sizeof(float)); // This is a linear version.
// matrix[i*cols + j] gives you the (i, j)th element.

float** matrix = malloc(rows * sizeof(float*)); 
for(int i = 0; i < rows; ++i)
    matrix[i] = malloc(cols * sizeof(float));
// Now you can access matrix[i][j] as the (i, j)th element.

Here is a way to interconvert between the two formats.

float* linearize(float** matrix, unsigned int rows, unsigned int cols)
{
    float* linear = malloc(rows * cols * sizeof(float));
    if(linear)
    {
        for(unsigned int i = 0; i < rows; ++i)
            for(unsigned int j = 0; j < cols; ++j)
                linear[i*cols + j] = matrix[i][j] ;
    }
    return linear ;
}


float** unlinearize(float* linear, unsigned int rows, unsigned int cols)
{
    float** matrix = malloc(rows * sizeof(float*));
    if(matrix)
    {
        for(unsigned int i = 0; i < rows; ++i)
        {
            matrix[i] = malloc(cols * sizeof(float));
            if(matrix[i])
            {
                for(unsigned int j = 0; j < cols; ++j)
                    matrix[i][j] = linear[i*cols + j] ;
            }
        }
    }
    return matrix ;
}
a_pradhan
  • 3,285
  • 1
  • 18
  • 23
  • If you look closer at `alloc_2d_float`, you'll see that what the function does is to allocate a linear block of memory and then construct a vector of pointers to the beginning of each row. This is a very common idiom when working with MPI as it both allows the use of the `arr[i][j]` notation and keeps the memory contiguous as expected by MPI. 1D access is also possible as `*(arr[0] + i*dim + j)` since `arr[0]` points to the beginning of the entire block. Using `arr` instead in the latter case is just a rookie mistake. – Hristo Iliev Nov 19 '15 at 07:58
  • Thank you! Those functions are really helpful. I should be able to switch the line `*((matrix+i*N) + j) = *((matrix+i*N) + j) + stepsize;` with `matrix[i][j] = matrix[i][j] + stepsize;` ? I don't think that's right, because that's turning those values to 0.05 instead of the old value + 0.05. – Chylomicron Nov 19 '15 at 15:10
  • Oh, I got it! I just had to make a new matrix, like `newmatrix[i][j] = matrix[i][j] + stepsize;` instead. Thank you again for the help! – Chylomicron Nov 19 '15 at 15:27