Matrix product using macro definition

This is a discussion on Matrix product using macro definition within the C Programming forums, part of the General Programming Boards category; Hi, I have to code a matrix product using the macro-definition Code: #define I2D(i, j, nc) ((i)*(nc)+(j)) I have to ...

  1. #1
    Registered User
    Join Date
    Dec 2012
    Posts
    3

    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

  2. #2
    Registered User
    Join Date
    Nov 2012
    Posts
    1,194
    Quote Originally Posted by ElNoob View Post
    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 View Post
    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.

  3. #3
    Registered User
    Join Date
    Oct 2011
    Posts
    854
    Quote Originally Posted by ElNoob View Post
    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)])
    instead?

    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.

  4. #4
    Registered User
    Join Date
    Dec 2012
    Posts
    3
    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) ;
    			}
    		}
    
    
    	}
    }

  5. #5
    Registered User
    Join Date
    Nov 2012
    Posts
    1,194
    Quote Originally Posted by ElNoob View Post
    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.

  6. #6
    Registered User
    Join Date
    Dec 2012
    Posts
    3
    Yup C2 !

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multiple definition error, one definition
    By frog in forum C++ Programming
    Replies: 9
    Last Post: 10-21-2010, 03:15 AM
  2. what is wrong with the macro definition....
    By sanddune008 in forum C Programming
    Replies: 7
    Last Post: 04-28-2010, 01:26 AM
  3. Macro definition
    By aayu09 in forum C Programming
    Replies: 11
    Last Post: 04-12-2010, 02:33 PM
  4. Matrix product
    By Cotizo in forum C++ Programming
    Replies: 4
    Last Post: 08-03-2008, 10:10 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21