# Matrix product using macro definition

• 12-07-2012
ElNoob
Matrix product using macro definition
Hi,

I have to code a matrix product using the macro-definition

Code:

`#define I2D(i, j, nc) ((i)*(nc)+(j))`
I have to use the scalar product in my matrix product function:

Code:

```double pScalC(double *v1, double *v2, int n, int d2) {         double sum = 0;         int i;         for (i = 0; i < n; i++) {                 sum += v1[i] * v2[i];         }         return sum; }```
My matrix product function is:

Code:

`void pMatC(double *m1, double *m2, int l1, int c1, int c2, double *m3)`
I have to return m3 who is a matrix of l1*c2

I don't really know what to do...

Thanks
• 12-07-2012
c99tutorial
Quote:

Originally Posted by ElNoob
Hi,

I have to code a matrix product using the macro-definition

Code:

`#define I2D(i, j, nc) ((i)*(nc)+(j))`

This macro will convert a typical (i,j) -style array reference into a single-subscript [...] suitable for use in a C function. For example, to assign 123.456 to the cell (5,5) (assuming there are 100 columns)

v1[I2D(5,5,100)] = 123.456;

Quote:

Originally Posted by ElNoob
I have to return m3 who is a matrix of l1*c2

I don't really know what to do...

Thanks

If you want an approach that lets you write it reliably: first write out a small example or two by hand. What steps did you take to do it by hand? That is your algorithm. Write out the algorithm in your code that at least will get those small examples working with the correct result. Then, if needed, generalize your code such that other, larger examples will also give the correct result.
• 12-08-2012
Nominal Animal
Quote:

Originally Posted by ElNoob
Code:

`#define I2D(i, j, nc) ((i)*(nc)+(j))`

Why would anyone torture themselves like that?

I mean, why not define
Code:

`#define ELEMENT(matrix, row, column, stride) ((matrix)[(column) + (row)*(stride)])`

If you compared that to the I2Dmacro, the above has row==i, column==j, and stride==nc. matrix is an array of or a pointer to matrix elements, say doubles, and the others are some integer type; desired row and column in the matrix, and the stride of the matrix rows. (Since C uses row-major order, consecutive columns on the same row are consecutive in memory, and thus have unit stride, 1. The row stride is at least the number of columns.)

Instead of dragging the data pointer, the number of rows, the number of columns, and the row stride, you can make the code much more readable by using a trivial structure:
Code:

```typedef struct {     int    rows;     int    cols;     int    stride;     double *data; } matrix_t; #define ELEMENT(matrix, row, col) ((matrix).data[(row)*(matrix).stride + (col)])```
which simplifies your matrix multiplication function to
Code:

`int pMatC(const matrix_t *const left, const matrix_t *const right, matrix_t *const result);`
which could return 0 if successful, and a nonzero errno code otherwise (like incompatible matrix sizes, for example).

You often need transposes and views to other matrices. Consider a further jump into deeper waters:
Code:

```struct data {     struct data *next;     long          refcount;     size_t      size;     double      data[]; }; typedef struct {     long        rows;     long        cols;     long        rowstep;     long        colstep;     double      *origin;     struct data *owner; } matrix_t; typedef struct {     long        size;     long        step;     double      *origin;     struct data *owner; } vector_t; #define MATRIX_INIT { 0L, 0L, 0L, 0L, NULL, NULL } #define VECTOR_INIT { 0L, 0L, NULL, NULL } #define MATRIX(m, row, col) ((m).origin[(m).rowstep * (row) + (m).colstep * (col)]) #define VECTOR(m, row, col) ((m).origin[(m).rowstep * (row) + (m).colstep * (col)])```
These are truly powerful. They give you the ability to create "views" to other matrices, and e.g. transpose a matrix without copying a single element. You can even create a vector that is really the diagonal elements of a matrix. When you modify the matrix, the changes are also reflected in the vector. With a practically insignificant added cost to element access, you now have a vastly more powerful abstract matrix and vector types.

As long as you destroy each matrix after you're done with it, the reference counting in the actual data structures will release the matrix and vector data when it is no longer needed (referred to). You will never need to worry about whether a matrix was unique or shared elements with another matrix or vector, just destroy each matrix you use after you no longer need it.

Memory management can be done even easier, using regions. Nginx and Apache sources call these pools, and I like that better, so that's what I'll call them. Basically, you'd also have
Code:

```void *pool_new(void); void *pool_destroy(void *const pool);```
and pass void *const pool to each matrix or vector function that may need to dynamically allocate memory, unless they only need it for internal (temporary) data. Each matrix and vector will effectively belong to exactly one pool. Unless you are creating or destroying matrices or vectors, the pools are completely invisible; they are not a boundary for use, only for allocation/deallocation.

Instead of worrying about managing each vector and matrix, you start by creating a new pool for your temporary needs. After you're done, you use a helper function to move the final result matrix or vector out from the temporary pool to the caller's pool, and destroy the entire temporary pool at once. (No problems with circular references, forgotten temporary matrices or vectors .. this is an extremely robust approach, and completely frees you from worrying about memory management details. And it is super efficient, too.)

It's pretty funny, isn't it? First you have to learn a lot of stuff (three distinct "learning steps" in above, by my count), and then you can implement ways to do complicated stuff very easily.

I don't know the level of your course or learning, so I cannot say which point of the above would be optimal for you (considering the learning curve et cetera). It just hurts my brain to see learners led away from this path.

If you want to see how I would implement any of the stages above, just let me know.
• 12-08-2012
ElNoob
Hi Nominal Animal.

Actually, i have the obligation to use the macrodefinition above, because it's for a practical work.
I'm a beginner in C programming. If it was not for a practical work I would use what you've done because it is so powerful and so nice coding! I will surely use this in my future work.

Many thanks !

I have made this but it doesn't work..

Code:

```void pMatC(double *m1, double *m2, int l1, int c1, int c2, double *m3) {         int i, j, k;         for (i = 0; i <= l1; i++) {                 for (j = 0; j <= c2; j++) {                         m3[I2D(i,j, c2)] = 0;                         for (k = 0; k <= c1; k++){                                 m3[I2D(i,j,k)] += pScalC(m1, m2, k, 1) ;                         }                 }         } }```
• 12-08-2012
c99tutorial
Quote:

Originally Posted by ElNoob
Code:

```            for (k = 0; k <= c1; k++){                 m3[I2D(i,j,k)] += pScalC(m1, m2, k, 1) ;             }```

I think your I2D macro takes 3 arguments where argument 3 is the number of columns in the matrix, which does not change. Therefore I2D(i,j,k) should probably be either I2D(i,j,c1) or I2D(i,j,c2) depending on how many columns m3 is supposed to have.
• 12-08-2012
ElNoob
Yup C2 !