/******************************************************************************
 *
 *       ELMER, A Computational Fluid Dynamics Program.
 *
 *       Copyright 1st April 1995 - , Center for Scientific Computing,
 *                                    Finland.
 *
 *       All rights reserved. No part of this program may be used,
 *       reproduced or transmitted in any form or by any means
 *       without the written permission of CSC.
 *
 ******************************************************************************/

/*******************************************************************************
 *
 *     MATC operator routines.
 *
 *******************************************************************************
 *
 *                     Author:       Juha Ruokolainen
 *
 *                    Address: Center for Scientific Computing
 *                                Tietotie 6, P.O. BOX 405
 *                                  02101 Espoo, Finland
 *                                  Tel. +358 0 457 2723
 *                                Telefax: +358 0 457 2302
 *                              EMail: Juha.Ruokolainen@csc.fi
 *
 *                       Date: 30 May 1996
 *
 *                Modified by:
 *
 *       Date of modification:
 *
 ******************************************************************************/
/***********************************************************************
|
|   Oper.C - Last Edited 15. 8. 1988
|
***********************************************************************/

/*======================================================================
|Syntax of the manual pages:
|
|FUNCTION NAME(...) params ...
|
$  usage of the function and type of the parameters
?  explane the effects of the function
=  return value and the type of value if not of type int
@  globals effected directly by this routine
!  current known bugs or limitations
&  functions called by this function
~  these functions may intrest you as an alternative function or
|  because they control this function somehow
=====================================================================*/


/*
 * $Id: oper.c,v 1.1.1.1 2005/04/14 13:29:14 vierinen Exp $ 
 *
 * $Log: oper.c,v $
 * Revision 1.1.1.1  2005/04/14 13:29:14  vierinen
 * initial matc automake package
 *
 * Revision 1.2  1998/08/01 12:34:51  jpr
 *
 * Added Id, started Log.
 * 
 *
 */

#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(type, nrow, ncol) int type, nrow, 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(mat) 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(mat) MATRIX *mat;
{
    if (mat == (MATRIX *)NULL) return;

    FREEMEM((char *)MATR(mat));
    FREEMEM((char *)mat);
}

MATRIX *opr_vector(A, B)
       MATRIX *A, *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(A, B)
       MATRIX *A, *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(A)
     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(A, B)
     MATRIX *A, *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(A)
     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(A, B)
     MATRIX *A, *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(A, B)
     MATRIX *A, *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(A, B)
     MATRIX *A, *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(A, B)
     MATRIX *A, *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(A,B)
     MATRIX *A, *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(A)
     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(A, B)
     MATRIX *A, *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(A, B)
     MATRIX *A, *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(A, B)
     MATRIX *A, *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(A, B)
     MATRIX *A, *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(A, B)
     MATRIX *A, *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(A, B)
     MATRIX *A, *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(A, B)
     MATRIX *A, *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(A, B)
     MATRIX *A, *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(A, B)
     MATRIX *A, *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(A)
     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;
}
