#ifndef V_MATRIX_H
#define V_MATRIX_H

typedef struct matrix_s
{
	u32_t		rows,cols;
	vec_t		**cell;
	vec_t		*data;
}	matrix_t, *matrix_p;

#ifdef	__cplusplus
extern	"C" {
#endif	/* __cplusplus */
	/* returns memAlloc()'ed zero-filled matrix */
	matrix_p	V_GLOBAL	matAlloc(u32_t rows,u32_t cols);
	/* returns memAlloc()'ed matrix with elements equal to such in 'ref' */
	matrix_p	V_GLOBAL	matDuplicate(matrix_t *ref);
	/* matrices must be equal in size; otherwise will be assert() */
	void		V_GLOBAL	matCopy(matrix_t *dest,matrix_t *src);
	/* size of vector must be equal to number of columns of matrix */
	void		V_GLOBAL	matCopyRow(vector_t *dst,matrix_t *m,u32_t row);
	/* size of vector must be equal to number of rows of matrix */
	void		V_GLOBAL	matCopyCol(vector_t *dst,matrix_t *m,u32_t col);
	/* returns malloc()'ed block filled with contents of row */
	vector_p	V_GLOBAL	matDuplicateRow(matrix_t *m,u32_t row);
	/* returns malloc()'ed block filled with contents of col */
	vector_p	V_GLOBAL	matDuplicateCol(matrix_t *m,u32_t col);
	/* fills submatrix with given value */
	void		V_GLOBAL	matSetRect(matrix_p data,
		u32_t left,u32_t top,u32_t right,u32_t bottom,vec_t value);
	/* sets matrix to unit */
	void		V_GLOBAL	matUnit(matrix_t *m);
	/* matrices must be equal in size */
	void		V_GLOBAL	matAdd(matrix_t *dest,matrix_t *m1,
								   matrix_t *m2);
	void		V_GLOBAL	matSub(matrix_t *dest,matrix_t *m1,
								   matrix_t *m2);
	void		V_GLOBAL	matNegate(matrix_t *dest,matrix_t *m);
	vboolean	V_GLOBAL	matCompare(matrix_t *m1,matrix_t *m2);
	/* 'row' or 'col' can be NULL */
	void		V_GLOBAL	matMin(matrix_t *m,u32_t *row,u32_t *col);
	/* 'row' or 'col' can be NULL */
	void		V_GLOBAL	matMax(matrix_t *m,u32_t *row,u32_t *col);
	/* matrices must be equal in size; otherwise will be assert() */
	void		V_GLOBAL 	matScale(matrix_t *dest,matrix_t *m,
									 vec_t x);
	/* dest->size == m->rows, m->cols == v->size */
	void		V_GLOBAL	matVecMul(vector_t *dest,matrix_t *m,
									  vector_t *v);
	/*	ml->cols == mr->rows, dest->rows==ml->rows,
	 *	dest->cols == mr->cols */
	void		V_GLOBAL	matMul(matrix_t *dest,matrix_t *ml,
									  matrix_t *mr);
	/*	dest->cols == m->rows, m->cols==dest->rows */
	void		V_GLOBAL	matTranspose(matrix_t *dest,matrix_t *m);
	/*	m->cols == m->rows */
	void		V_GLOBAL	matTransposeIP(matrix_p m);
	/* circular copy (all indices will be taken modulo dest->cols/rows) */
	void	V_GLOBAL	matCopyElements(matrix_p dest,matrix_p source,
		s32_t dest_col,s32_t dest_row,
		u32_t src_left,u32_t src_top,u32_t src_right,u32_t src_bottom);
	/*	assert()'s if m->cols!=m->rows.
		if keepon==0 than 'm' trashed and than DELETED. */
	vec_t		V_GLOBAL	matDeterm(matrix_t *m,vboolean keepon);
	/*	If keepon!=0, result stored in vector 'b', else 'b' unmodified and
	 *	solution (in new vector) returned as result. */
	vector_p	V_GLOBAL	matSolve(matrix_t *a,vector_t *b,
									vboolean keepon);
	/*	If !keepon, result stored in given matrix, else 'm' unmodified and
	 *	new inversed matrix returned as result. */
	matrix_p	V_GLOBAL	matInverse(matrix_t *m,vboolean keepon);
#ifdef	MATRIX_NO_MACRO
	void		V_GLOBAL	matZero(matrix_t *m);
	u32_t			V_GLOBAL	matColCount(matrix_t *m);
	u32_t			V_GLOBAL	matRowCount(matrix_t *m);
#endif	/* MATRIX_NO_MACRO */
#ifdef  __cplusplus
}
#endif	/* __cplusplus */

#ifndef	MATRIX_NO_MACRO
#define	matZero(m)\
		v_zerodw((m)->data,(m)->rows*(m)->cols*(sizeof(vec_t)>>2));
#define	matRowCount(m)			((m)->rows)
#define	matColCount(m)			((m)->cols)
#endif	/* MATRIX_NO_MACRO */

#endif /* V_MATRIX_H */
