#include "elmer/matc.h"
#ifdef TYPE
#undef TYPE
#endif
#ifdef NROW
#undef NROW
#endif
#ifdef NCOL
#undef NCOL
#endif
#ifdef MATR
#undef MATR
#endif
#ifdef M
#undef M
#endif
#ifdef MATSIZE
#undef MATSIZE
#endif
#define TYPE(mat) (mat)->type
#define NROW(mat) (mat)->nrow
#define NCOL(mat) (mat)->ncol
#define MATR(mat) (mat)->data
#define MATSIZE(mat) (NROW(mat) * NCOL(mat) * sizeof(double))
#define MA(i,j) a[ncola * (i) + (j)]
#define MB(i,j) b[ncolb * (i) + (j)]
#define MC(i,j) c[ncolc * (i) + (j)]
MATRIX *mat_new(int type, int nrow, int ncol)
{
MATRIX *res;
res = (MATRIX *)ALLOCMEM(MATRIXSIZE);
TYPE(res) = type;
NROW(res) = nrow;
NCOL(res) = ncol;
MATR(res) = (double *)ALLOCMEM(MATSIZE(res));
return res;
}
MATRIX *mat_copy(MATRIX *mat)
{
MATRIX *res;
if (mat == (MATRIX *)NULL) return NULL;
res = mat_new(TYPE(mat), NROW(mat), NCOL(mat));
memcpy((char *)MATR(res), (char *)MATR(mat), MATSIZE(mat));
return res;
}
void mat_free(MATRIX *mat)
{
if (mat == (MATRIX *)NULL) return;
FREEMEM((char *)MATR(mat));
FREEMEM((char *)mat);
}
MATRIX *opr_vector(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i, n, inc;
double *a = MATR(A), *b = MATR(B), *c;
inc = ((int)*b > (int)*a) ? 1:(-1);
n = abs((int)*b - (int)*a) + 1;
C = mat_new(TYPE_DOUBLE, 1, n);
c = MATR(C);
for(i = 0; i < n; i++)
*c++ = (int)*a + i*inc;
return C;
}
MATRIX *opr_resize(MATRIX *A, MATRIX *B)
{
MATRIX *C;
double *a = MATR(A), *b = MATR(B), *c;
int i, j, n, m;
if (NCOL(B) >= 2)
{
i = *b++; j = *b++;
}
else
{
i = 1; j = *b;
}
if (i < 1 || j < 1)
error("resize: invalid size for and array");
C = mat_new(TYPE(A), i, j);
c = MATR(C);
n = i * j; m = NROW(A) * NCOL(A);
for(i = j = 0; i < n; i++)
{
*c++ = a[j++];
if (j == m) j = 0;
}
return C;
}
MATRIX *opr_apply(MATRIX *A)
{
VARIABLE *store, *ptr;
MATRIX *C = NULL;
store = var_temp_new(TYPE_STRING, NROW(A), NCOL(A));
REFCNT(store) = 0;
mat_free(store->this);
store->this = A;
REFCNT(store)++;
ptr = (VARIABLE *)com_apply(store);
var_delete_temp(store);
if ( ptr ) C = mat_copy(ptr->this);
return C;
}
MATRIX *opr_add(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
double value;
if (nrowa == nrowb && ncola == ncolb)
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = *a++ + *b++;
}
else if (nrowa == 1 && ncola == 1)
{
C = mat_new(TYPE(B), nrowb, ncolb); c = MATR(C);
value = *a; nrowb *= ncolb;
for(i = 0; i < nrowb; i++) *c++ = value + *b++;
}
else if (nrowb == 1 && ncolb == 1)
{
C = mat_new(TYPE(A), nrowa, ncola); c = MATR(C);
value = *b; nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = value + *a++;
}
else
error("Add: Incompatible for addition.\n");
return C;
}
MATRIX *opr_minus(MATRIX *A)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
double *a = MATR(A), *c;
C = mat_new(TYPE(A), nrowa, ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = -*a++;
return C;
}
MATRIX *opr_subs(MATRIX *A, MATRIX *B)
{
MATRIX *C;
double value;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if (nrowa == nrowb && ncola == ncolb)
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = *a++ - *b++;
}
else if (nrowa == 1 && ncola == 1)
{
C = mat_new(TYPE(B),nrowb, ncolb); c = MATR(C);
value = *a; nrowb *= ncolb;
for(i = 0; i < nrowb; i++) *c++ = value - *b++;
}
else if (nrowb == 1 && ncolb == 1)
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
value = *b; nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = *a++ - value;
}
else
error("Substr: Incompatible for addition.\n");
return C;
}
MATRIX *opr_mul(MATRIX *A, MATRIX *B)
{
MATRIX *C;
double value,s;
int i, j, k;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if (nrowa == 1 && ncola == 1)
{
C = mat_new(TYPE(B), nrowb, ncolb); c = MATR(C);
value = *a; nrowb *= ncolb;
for(i = 0; i < nrowb; i++) *c++ = value * *b++;
}
else if (nrowb == 1 && ncolb == 1)
{
C = mat_new(TYPE(A), nrowa, ncola); c = MATR(C);
value = *b; nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = value * *a++;
}
else if (ncola == nrowb)
{
C = mat_new(TYPE(A), nrowa,ncolb);
c = MATR(C);
for(i = 0; i < nrowa; i++)
{
for(j = 0; j < ncolb; j++)
{
s = 0;
for(k = 0; k < ncola; k++) s += a[k] * MB(k,j);
*c++ = s;
}
a += ncola;
}
}
else if ( ncola == ncolb && nrowa == nrowb )
{
C = mat_new(TYPE(A), nrowa,ncolb);
c = MATR(C);
k = 0;
for( i = 0; i < nrowa; i++ )
for( j = 0; j < ncolb; j++,k++ ) c[k] = a[k] * b[k];
}
else
{
error("Mul: Incompatible for multiplication.\n");
}
return C;
}
MATRIX *opr_pmul(MATRIX *A, MATRIX *B)
{
MATRIX *C;
double value;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if (nrowa == nrowb && ncola == ncolb)
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = *a++ * *b++;
}
else if (nrowa == 1 && ncola == 1)
{
C = mat_new(TYPE(B), nrowb, ncolb); c = MATR(C);
value = *a; nrowb *= ncolb;
for(i = 0; i < nrowb; i++) *c++ = value * *b++;
}
else if (nrowb == 1 && ncolb == 1)
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
value = *b; nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = *a++ * value;
}
else
error("PMul: Incompatible for pointwise multiplication.\n");
return C;
}
MATRIX *opr_div(MATRIX *A, MATRIX *B)
{
MATRIX *C;
double value;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if (nrowa == nrowb && ncola == ncolb)
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = *a++ / *b++;
}
else if (nrowa == 1 && ncola == 1)
{
C = mat_new(TYPE(B), nrowb, ncolb); c = MATR(C);
value = *a; nrowb *= ncolb;
for(i = 0; i < nrowb; i++) *c++ = value / *b++;
}
else if (nrowb == 1 && ncolb == 1)
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
value = *b; nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = *a++ / value;
}
else
error("Div: Incompatible for division.\n");
return C;
}
MATRIX *opr_pow(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i, j, k, l, power;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
int ncolc;
double *a = MATR(A), *b = MATR(B), *c;
double *v, value;
if (nrowb != 1 || ncolb != 1) error("Pow: Matrix ^ Matrix ?.\n");
if (nrowa == 1 || ncola != nrowa)
{
C = mat_new(TYPE(A), nrowa, ncola); c = MATR(C);
value = *b; nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = pow(*a++, value);
return C;
}
power = (int)*b;
if (power == 0) {
C = mat_new(TYPE(A), nrowa, ncola);
ncolc = ncola; c = MATR(C);
for(i = 0; i < nrowa; i++) MC(i,i) = 1;
}
else if (abs(power) == 1)
{
C = mat_copy(A);
}
else
{
v = (double *)ALLOCMEM(nrowa * sizeof(double));
C = mat_new(TYPE(A), nrowa, nrowa);
c = MATR(C); b = MATR(A);
for(l = 1; l < abs(power); l++) {
for(i = 0; i < nrowa; i++)
{
for(j = 0; j < nrowa; j++)
{
v[j] = 0.0;
for(k = 0; k < nrowa; k++) v[j] += b[k] * MA(k,j);
}
for(j = 0; j < nrowa; j++) *c++ = v[j];
b += nrowa;
}
a = MATR(A); b = c = MATR(C);
}
FREEMEM((char *)v);
}
if (power < 0)
{
VARIABLE *inv, *tmp;
tmp = (VARIABLE *)ALLOCMEM(VARIABLESIZE);
tmp -> this = C;
inv = mtr_inv(tmp);
mat_free(C);
FREEMEM((char *)tmp);
C = inv->this;
REFCNT(inv)++;
var_delete_temp(inv);
}
return C;
}
MATRIX *opr_trans(MATRIX *A)
{
MATRIX *C;
int i, j;
int ncola = NCOL(A), nrowa = NROW(A);
int ncolc;
double *a = MATR(A), *c;
C = mat_new(TYPE(A),ncola,nrowa);
c = MATR(C); ncolc = nrowa;
for(i = 0; i < nrowa; i++)
for(j = 0; j < ncola; j++) MC(j,i) = *a++;
return C;
}
MATRIX *opr_reduction(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if ((nrowa == nrowb) && (ncola == ncolb))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++, a++) *c++ = (*b++) ? (*a) : (0);
}
else
error("Incompatible for reduction.\n");
return C;
}
MATRIX *opr_lt(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if ((nrowa == 1) && (ncola == 1))
{
C = mat_new(TYPE(B),nrowb, ncolb); c = MATR(C);
nrowb *= ncolb;
for(i = 0; i < nrowb; i++,c++) if (*a < b[i]) *c = 1;
}
else if ((nrowb == 1) && (ncolb == 1))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] < *b) *c = 1;
}
else if ((nrowa == nrowb) && (ncola == ncolb))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] < b[i]) *c = 1;
}
else
error("lt: Incompatible for comparison.\n");
return C;
}
MATRIX *opr_le(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if ((nrowa == 1) && (ncola == 1))
{
C = mat_new(TYPE(B),nrowb,ncolb); c = MATR(C);
nrowb *= ncolb;
for(i = 0; i < nrowb; i++,c++) if (*a <= b[i]) *c = 1;
}
else if ((nrowb == 1) && (ncolb == 1))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] <= *b) *c = 1;
}
else if ((nrowa == nrowb) && (ncola == ncolb))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] <= b[i]) *c = 1;
}
else
error("le: Incompatible for comparison.\n");
return C;
}
MATRIX *opr_gt(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if ((nrowa == 1) && (ncola == 1))
{
C = mat_new(TYPE(B),nrowb,ncolb); c = MATR(C);
nrowb *= ncolb;
for(i = 0; i < nrowb; i++,c++) if (*a > b[i]) *c = 1;
}
else if ((nrowb == 1) && (ncolb == 1))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] > *b) *c = 1;
}
else if ((nrowa == nrowb) && (ncola == ncolb))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] > b[i]) *c = 1;
}
else
error("gt: Incompatible for comparison.\n");
return C;
}
MATRIX *opr_ge(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if ((nrowa == 1) && (ncola == 1))
{
C = mat_new(TYPE(B),nrowb,ncolb); c = MATR(C);
nrowb *= ncolb;
for(i = 0; i < nrowa; i++,c++) if (*a >= b[i]) *c = 1;
}
else if ((nrowb == 1) && (ncolb == 1))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] >= *b) *c = 1;
}
else if ((nrowa == nrowb) && (ncola == ncolb))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] >= b[i]) *c = 1;
}
else
error("ge: Incompatible for comparison.\n");
return C;
}
MATRIX *opr_eq(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if ((nrowa == 1) && (ncola == 1))
{
C = mat_new(TYPE(B),nrowb,ncolb); c = MATR(C);
nrowb *= ncolb;
for(i = 0; i < nrowb; i++,c++) if (*a == b[i]) *c = 1;
}
else if ((nrowb == 1) && (ncolb == 1))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] == *b) *c = 1;
}
else if ((nrowa == nrowb) && (ncola == ncolb))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] == b[i]) *c = 1;
}
else
error("eq: Incompatible for comparison.\n");
return C;
}
MATRIX *opr_neq(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if ((nrowa == 1) && (ncola == 1))
{
C = mat_new(TYPE(B),nrowb,ncolb); c = MATR(C);
nrowb *= ncolb;
for(i = 0; i < nrowb; i++,c++) if (*a != b[i]) *c = 1;
}
else if ((nrowb == 1) && (ncolb == 1))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] != *b) *c = 1;
}
else if ((nrowa == nrowb) && (ncola == ncolb))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (a[i] != b[i]) *c = 1;
}
else
error("neq: Incompatible for comparison.\n");
return C;
}
MATRIX *opr_or(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if ((nrowa == 1) && (ncola == 1))
{
C = mat_new(TYPE(B),nrowb,ncolb); c = MATR(C);
nrowb *= ncolb;
for(i = 0; i < nrowb; i++) *c++ = (*a) || (b[i]);
}
else if ((nrowb == 1) && (ncolb == 1))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = (a[i]) || (*b);
}
else if ((nrowa == nrowb) && (ncola == ncolb))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = (a[i]) || (b[i]);
}
else
error("or: Incompatible for comparison.\n");
return C;
}
MATRIX *opr_and(MATRIX *A, MATRIX *B)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
int nrowb = NROW(B), ncolb = NCOL(B);
double *a = MATR(A), *b = MATR(B), *c;
if ((nrowa == 1) && (ncola == 1))
{
C = mat_new(TYPE(B),nrowb,ncolb); c = MATR(C);
nrowb *= ncolb;
for(i = 0; i < nrowb; i++) *c++ = (*a) && (b[i]);
}
else if ((nrowb == 1) && (ncolb == 1))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = (a[i]) && (*b);
}
else if ((nrowa == nrowb) && (ncola == ncolb))
{
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++) *c++ = (a[i]) && (b[i]);
}
else
error("and: Incompatible for comparison.\n");
return C;
}
MATRIX *opr_not(MATRIX *A)
{
MATRIX *C;
int i;
int nrowa = NROW(A), ncola = NCOL(A);
double *a = MATR(A), *c;
C = mat_new(TYPE(A),nrowa,ncola); c = MATR(C);
nrowa *= ncola;
for(i = 0; i < nrowa; i++,c++) if (*a == 0) *c = 1;
return C;
}