#ifndef LINMATRIX_H
#define LINMATRIX_H

#include <assert.h>
#include <string.h>
#include <stdlib.h>

#define SCALE_DELTA 0.2
#define EPS 1e-15

typedef struct _linmatrix{
	int rows;
	int cols;
        double eps;
	double* data;
} linmx;

linmx* linmx_create(int rows, int cols);
void   linmx_dispose(linmx* mx);
int    linmx_copy(linmx* from,linmx* to);

inline double linmx_getat(linmx* mx,int i, int j);/*get element at row i, column j using 1 based indexing*/
inline double linmx_setat(linmx* mx,int i, int j, double val);/*set element at row i, column j using 1 based indexing*/

inline double linmx_getrowfactor(linmx* mx,int row);
inline double linmx_getcolfactor(linmx* mx,int col);

inline double linmx_setrowfactor(linmx* mx,int row,double val);
inline double linmx_setcolfactor(linmx* mx,int col,double val);

inline double linmx_updaterowfactor(linmx* mx,int row,double val);
inline double linmx_updatecolfactor(linmx* mx,int col,double val);

inline double linmx_getrhs(linmx* mx,int row);
double*       linmx_getrhsvect(linmx* mx);
inline double linmx_setrhs(linmx* mx,int row,double val);

double* linmx_getcol(linmx* mx,int col);
void	 linmx_setcol(linmx* mx,int col, double val[]);

double* linmx_getrow(linmx* mx,int row);
void	 linmx_setrow(linmx* mx,int row, double val[]);

double   linmx_getcond(linmx* mx);

/******************************************************************************************/
inline double linmx_getat(linmx* mx,int i, int j){
        assert(i>=1&&i<=mx->rows&&j>=1&&j<=mx->cols);
        return mx->data[i*(mx->cols+2)+j];
}
/******************************************************************************************/
inline double linmx_setat(linmx* mx,int i, int j, double val){
        assert(i>=1&&i<=mx->rows&&j>=1&&j<=mx->cols);
        mx->data[i*(mx->cols+2)+j]=val;
        return val;
}
/******************************************************************************************/
inline double linmx_getrowfactor(linmx* mx,int row){
        assert(1<=row&&row<=mx->rows);
        return mx->data[row*(mx->cols+2)];
}
/******************************************************************************************/
inline double linmx_getcolfactor(linmx* mx,int col){
        assert(1<=col&&col<=mx->cols);
        return mx->data[col];
}

/******************************************************************************************/
inline double linmx_setrowfactor(linmx* mx,int row,double val){
        assert(1<=row&&row<=mx->rows);
        assert(val!=0);
        mx->data[row*(mx->cols+2)]=val;
        return val;
}
/******************************************************************************************/
inline double linmx_setcolfactor(linmx* mx,int col,double val){
        assert(1<=col&&col<=mx->cols);
        assert(val!=0);        
        mx->data[col]=val;
        return val;
}

/******************************************************************************************/
inline double linmx_updaterowfactor(linmx* mx,int row,double val){
        assert(1<=row&&row<=mx->rows);
        assert(val!=0);
        mx->data[row*(mx->cols+2)]*=val;
        return val;
}
/******************************************************************************************/
inline double linmx_updatecolfactor(linmx* mx,int col,double val){
        assert(1<=col&&col<=mx->cols);
        assert(val!=0);
        mx->data[col]*=val;
        return val;
}

/******************************************************************************************/
inline double linmx_getrhs(linmx* mx,int row){
        assert(1<=row&&row<=mx->rows);
        return mx->data[row*(mx->cols+2)+mx->cols+1];
}
/******************************************************************************************/
inline double linmx_setrhs(linmx* mx,int row,double val){
        assert(1<=row&&row<=mx->rows);
        mx->data[row*(mx->cols+2)+mx->cols+1]=val;
        return val;
}
#endif
