


#ifndef  __MATRIX_H__
#define  __MATRIX_H__

#define  MATRIX_SAVE_FREE 50

#include <misc.h>

typedef struct matrix_struct {
  double **mat;
  int w, h;
#ifdef   MATRIX_SAVE_FREE
  struct matrix_struct *freelink;
#endif   
} *matrix;

typedef struct {
  int i, j;
  double v;
} MatrixSparseValue;

#define  matNULL  ((matrix) NULL)

#ifdef   MATRIX_CAREFUL
#else    
#define  matRef(m, i, j)  ((m)->mat[(i)][(j)])
#define  matWidth(m)      ((m)->w)
#define  matHeight(m)     ((m)->h)
#endif  


/* `R' suffix means you can specify result matrix */

extern matrix matAddR(matrix r, matrix a, matrix b); 
extern matrix matSubR(matrix r, matrix a, matrix b); 
extern matrix matMulR(matrix r, matrix a, matrix b); 
extern matrix matDivR(matrix r, matrix a, matrix b); 
extern matrix matInvR(matrix r, matrix a);    
extern matrix matTransR(matrix r, matrix a);  


/* these generate a new result */

#define  matAdd(a, b)  (matAddR(matNULL, (a), (b)))
#define  matSub(a, b)  (matSubR(matNULL, (a), (b)))
#define  matMul(a, b)  (matMulR(matNULL, (a), (b)))
#define  matDiv(a, b)  (matDivR(matNULL, (a), (b)))
#define  matInv(a)     (matInvR(matNULL, (a)))
#define  matTrans(a)   (matTransR(matNULL, (a)))


/* these put the result in the first argument */

#define  matAddA(a, b)  (matAddR((a), (a), (b)))
#define  matSubA(a, b)  (matSubR((a), (a), (b)))
#define  matMulA(a, b)  (matMulR((a), (a), (b)))
#define  matDivA(a, b)  (matDivR((a), (a), (b)))
#define  matInvA(a)     (matInvR((a), (a)))
#define  matTransA(a)   (matTransR((a), (a)))

extern matrix matNew(int h, int w);
extern void matFree(matrix m);

extern matrix matCopy(matrix r, matrix a);
#define  matNewCopy(a)      (matCopy(matNULL, (a)))

extern matrix matIdent(int w);

extern matrix matSetVal(matrix m, double val);
extern matrix matSet(matrix m, double *vals);
extern matrix matSetSparse(matrix m, int nvals, MatrixSparseValue *vals);

extern void matPrint(matrix m);


#endif   
