#include "linalg.h"

/****************************************************************************/
/**                                                                        **/
/**                              Utility Funtions                          **/
/**                       Adapted from the f2c distribution                **/
/**                                                                        **/
/****************************************************************************/

LOCAL VOID z_mul P3C(dcomplex *, c, dcomplex *, a, dcomplex *, b)
{
  dcomplex v;
  v.r = a->r * b->r - a->i * b->i;
  v.i = a->r * b->i + a->i * b->r;
  c->r = v.r;
  c->i = v.i;
}

VOID d_cnjg P2C(dcomplex *, r, dcomplex *, z)
{
  r->r = z->r;
  r->i = - z->i;
}

double dcabs1 P1C(dcomplex *, z)
{
  return abs(z->r) + abs(z->i);
}

double d_int P1C(double *, x)
{
  return( (*x>0) ? floor(*x) : -floor(- *x) );
}

double POW2 P1C(double, x) { return x * x; }
double ABS P1C(double, x) { return abs(x); }


/****************************************************************************/
/**                                                                        **/
/**                           Level 1 BLAS routines                        **/
/**                       translated by f2c and modified                   **/
/**                                                                        **/
/****************************************************************************/

double blas_dasum P3C(int, n, double *, dx, int, incx)
{
  /* Local variables */
  int m;
  double dtemp;

  /* takes the sum of the absolute values. */
  /* jack dongarra, linpack, 3/11/78. */
  /* modified 3/93 to return if incx .le. 0. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  dtemp = 0.0;
  if (n <= 0)
    return dtemp;
  if (incx != 1) {
    /* code for increment not equal to 1 */
    if (incx < 0) dx -= (n - 1) * incx;
    while (n-- > 0) {
      dtemp += ABS(*dx);
      dx += incx;
    }
  }
  else {
    /* code for increment equal to 1 */

    /* clean-up loop */
    m = n % 6;
    if (m != 0) {
      n -= m;
      while (m-- > 0) {
	dtemp += ABS(*dx);
	dx++;
      }
    }
    for (; n > 0; n -= 6, dx += 6)
      dtemp +=
	ABS(dx[0]) + ABS(dx[1]) + ABS(dx[2]) +
	  ABS(dx[3]) + ABS(dx[4]) + ABS(dx[5]);
  }
  return dtemp;
}

VOID blas_daxpy P6C(int, n,
		    double, da,
		    double *, dx,
		    int, incx,
		    double *, dy,
		    int, incy)
{
  /* Local variables */
  int m;

  /* constant times a vector plus a vector. */
  /* uses unrolled loops for increments equal to one. */
  /* jack dongarra, linpack, 3/11/78. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  if (n <= 0 || da == 0.0)
    return;
  if (incx != 1 || incy != 1) {
    /* code for unequal increments or equal increments */
    /* not equal to 1 */
    if (incx < 0) dx -= (n - 1) * incx;
    if (incy < 0) dy -= (n - 1) * incy;
    while (n-- > 0) {
      *dy += da * *dx;
      dx += incx;
      dy += incy;
    }
  }
  else {
    /* code for both increments equal to 1 */

    /* clean-up loop */
    m = n % 4;
    if (m != 0) {
      n -= m;
      while (m-- > 0)
	*dy++ += da * *dx++;
    }
    for (; n > 0; n -= 4, dx += 4, dy += 4) {
      dy[0] += da * dx[0];
      dy[1] += da * dx[1];
      dy[2] += da * dx[2];
      dy[3] += da * dx[3];
    }
  }
}

VOID blas_dcopy P5C(int, n, double *, dx, int, incx, double *, dy, int, incy)
{
  /* Local variables */
  int m;

  /* copies a vector, x, to a vector, y. */
  /* uses unrolled loops for increments equal to one. */
  /* jack dongarra, linpack, 3/11/78. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  if (n <= 0)
    return;
  if (incx != 1 || incy != 1) {
    /* code for unequal increments or equal increments not equal to 1 */
    if (incx < 0) dx -= (n - 1) * incx;
    if (incy < 0) dy -= (n - 1) * incy;
    while (n-- > 0) {
      *dy = *dx;
      dx += incx;
      dy += incy;
    }
  }
  else {
    /* code for both increments equal to 1 */

    /* clean-up loop */
    m = n % 7;
    if (m != 0) {
      n -= m;
      while (m-- > 0)
	*dy++ = *dx++;
    }
    for (; n > 0; n -= 7, dx += 7, dy += 7) {
      dy[0] = dx[0];
      dy[1] = dx[1];
      dy[2] = dx[2];
      dy[3] = dx[3];
      dy[4] = dx[4];
      dy[5] = dx[5];
      dy[6] = dx[6];
    }
  }
}

double blas_ddot P5C(int, n, double *, dx, int, incx, double *, dy, int, incy)
{
  /* Local variables */
  int m;
  double dtemp;

  /* forms the dot product of two vectors. */
  /* uses unrolled loops for increments equal to one. */
  /* jack dongarra, linpack, 3/11/78. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  dtemp = 0.0;
  if (n <= 0)
    return dtemp;
  if (incx != 1 || incy != 1) {
    /* code for unequal increments or equal increments not equal to 1 */
    if (incx < 0) dx -= (n - 1) * incx;
    if (incy < 0) dy -= (n - 1) * incy;
    while (n-- > 0) {
      dtemp += *dx * *dy;
      dx += incx;
      dy += incy;
    }
  }
  else {
    /* code for both increments equal to 1 */

    /* clean-up loop */
    m = n % 5;
    if (m != 0) {
      n -= m;
      while (m-- > 0)
	dtemp += *dx++ * *dy++;
    }
    for (; n > 0; n -= 5, dx += 5, dy += 5)
      dtemp +=
	dx[0] * dy[0] + dx[1] * dy[1] + dx[2] * dy[2] +
	  dx[3] * dy[3] + dx[4] * dy[4];
  }
  return dtemp;
}

double blas_dnrm2 P3C(int, n, double *, x, int, incx)
{
  /* Local variables */
  double norm, scale, absxi;
  double ssq;

  /*  DNRM2 returns the euclidean norm of a vector via the function */
  /*  name, so that */

  /*     DNRM2 := sqrt( x'*x ) */

  /*  -- This version written on 25-October-1982. */
  /*     Modified on 14-October-1993 to inline the call to DLASSQ. */
  /*     Sven Hammarling, Nag Ltd. */

  /* Function Body */
  if (n < 1)
    norm = 0.0;
  else if (n == 1)
    norm = ABS(*x);
  else {
    if (incx < 0) x -= (n - 1) * incx;
    scale = 0.0;
    ssq = 1.0;

    /* The following loop is equivalent to this call to the LAPACK */
    /* auxiliary routine: */
    /* CALL DLASSQ( N, X, INCX, SCALE, SSQ ) */
    while (n-- > 0) {
      if (*x != 0.0) {
	absxi = ABS(*x);
	if (scale < absxi) {
	  ssq = ssq * POW2(scale / absxi) + 1.0;
	  scale = absxi;
	}
	else
	  ssq += POW2(absxi / scale);
      }
      x += incx;
    }
    norm = scale * sqrt(ssq);
  }

  return norm;
}

VOID blas_drot P7C(int, n,
		   double *, dx,
		   int, incx,
		   double *, dy,
		   int, incy,
		   double, c,
		   double, s)
{
  /* Local variables */
  double dtemp;

  /* applies a plane rotation. */
  /* jack dongarra, linpack, 3/11/78. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  if (n <= 0)
    return;
  if (incx != 1 || incy != 1) {
    /* code for unequal increments or equal increments not equal to 1 */
    if (incx < 0) dx -= (n - 1) * incx;
    if (incy < 0) dy -= (n - 1) * incy;
    while (n-- > 0) {
      dtemp = c * *dx + s * *dy;
      *dy   = c * *dy - s * *dx;
      *dx = dtemp;
      dx += incx;
      dy += incy;
    }
  }
  else {
    /* code for both increments equal to 1 */
    for (; n > 0; n--, dx++, dy++) {
      dtemp = c * *dx + s * *dy;
      *dy   = c * *dy - s * *dx;
      *dx = dtemp;
    }
  }
}

VOID blas_drotg P4C(double *, da, double *, db, double *, c, double *, s)
{
  /* Initialized data */
  static double one = 1.0;

  /* Local variables */
  double r, scale, z, roe;

  /* construct givens plane rotation. */
  /* jack dongarra, linpack, 3/11/78. */

  roe = *db;
  if (ABS(*da) > ABS(*db))
    roe = *da;
  scale = ABS(*da) + ABS(*db);
  if (scale == 0.0) {
    *c = 1.0;
    *s = 0.0;
    r = 0.0;
    z = 0.0;
  }
  else {
    double d__1 = POW2(*da / scale);
    double d__2 = POW2(*db / scale);
    r = scale * sqrt(d__1 + d__2);
    r = d_sign(&one, &roe) * r;
    *c = *da / r;
    *s = *db / r;
    z = 1.0;
    if (ABS(*da) > ABS(*db))
      z = *s;
    if (ABS(*db) >= ABS(*da) && *c != 0.0)
      z = 1.0 / *c;
  }
  *da = r;
  *db = z;
}

VOID blas_dscal P4C(int, n, double, da, double *, dx, int, incx)
{
  /* Local variables */
  int m;

  /* scales a vector by a constant. */
  /* uses unrolled loops for increment equal to one. */
  /* jack dongarra, linpack, 3/11/78. */
  /* modified 3/93 to return if incx .le. 0. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  if (n <= 0)
    return;
  if (incx != 1) {
    /* code for increment not equal to 1 */
    if (incx < 0) dx -= (n - 1) * incx;
    while (n-- > 0) {
      *dx = da * *dx;
      dx += incx;
    }
  }
  else {
    /* code for increment equal to 1 */

    /* clean-up loop */
    m = n % 5;
    if (m != 0) {
      n -= m;
      while (m-- > 0) {
	*dx = da * *dx;
	dx++;
      }
    }
    for (; n > 0; n -= 5, dx += 5) {
      dx[0] = da * dx[0];
      dx[1] = da * dx[1];
      dx[2] = da * dx[2];
      dx[3] = da * dx[3];
      dx[4] = da * dx[4];
    }
  }
}

VOID blas_dswap P5C(int, n, double *, dx, int, incx, double *, dy, int, incy)
{
  /* Local variables */
  int m;
  double dtemp;

  /* interchanges two vectors. */
  /* uses unrolled loops for increments equal one. */
  /* jack dongarra, linpack, 3/11/78. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  if (n <= 0)
    return;
  if (incx != 1 || incy != 1) {
    /* code for unequal increments or equal increments not equal to 1 */
    if (incx < 0) dx -= (n - 1) * incx;
    if (incy < 0) dy -= (n - 1) * incy;
    while (n-- > 0) {
      dtemp = *dx;
      *dx = *dy;
      *dy = dtemp;
      dx += incx;
      dy += incy;
    }
  }
  else {
    /* code for both increments equal to 1 */

    /* clean-up loop */
    m = n % 3;
    if (m != 0) {
      n -= m;
      while (m-- > 0) {
	dtemp = *dx;
	*dx = *dy;
	*dy = dtemp;
	dx++;
	dy++;
      }
    }
    for (; n > 0; n -= 3, dx += 3, dy += 3) {
      dtemp = dx[0];
      dx[0] = dy[0];
      dy[0] = dtemp;
      dtemp = dx[1];
      dx[1] = dy[1];
      dy[1] = dtemp;
      dtemp = dx[2];
      dx[2] = dy[2];
      dy[2] = dtemp;
    }
  }
}

int blas_idamax P3C(int, n, double *, dx, int, incx)
{
  /* System locals */
  int ret_val;

  /* Local variables */
  double dmax;
  int i;

  /* finds the index of element having max. absolute value. */
  /* jack dongarra, linpack, 3/11/78. */
  /* modified 3/93 to return if incx .le. 0. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  if (n < 1)
    return -1;
  ret_val = 0;
  if (n == 1)
    return ret_val;
  if (incx != 1) {
    /* code for increment not equal to 1 */
    if (incx < 0) dx -= (n - 1) * incx;
    dmax = ABS(*dx);
    dx += incx;
    for (i = 1; i < n; i++, dx += incx) {
      if (ABS(*dx) > dmax) {
	ret_val = i;
	dmax = ABS(*dx);
      }
    }
  }
  else {
    /* code for increment equal to 1 */
    dmax = ABS(*dx++);
    for (i = 1; i < n; i++, dx++) {
      if (ABS(*dx) > dmax) {
	ret_val = i;
	dmax = ABS(*dx);
      }
    }
  }
  return ret_val;
}

double blas_dzasum P3C(int, n, dcomplex *, zx, int, incx)
{
  /* Local variables */
  static double stemp;


  /* takes the sum of the absolute values. */
  /* jack dongarra, 3/11/78. */
  /* modified 3/93 to return if incx .le. 0. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  stemp = 0.0;
  if (n <= 0)
    return stemp;
  if (incx != 1) {
    /* code for increment not equal to 1 */
    if (incx < 0) zx -= (n - 1) * incx;
    while (n-- > 0) {
      stemp += dcabs1(zx);
      zx += incx;
    }
  }
  else {
    /* code for increment equal to 1 */
    while (n-- > 0)
      stemp += dcabs1(zx++);
  }
  return stemp;
}

double blas_dznrm2 P3C(int, n, dcomplex *, x, int, incx)
{
  /* Local variables */
  double temp, norm, scale;
  double ssq;

  /*  DZNRM2 returns the euclidean norm of a vector via the function */
  /*  name, so that */

  /*     DZNRM2 := sqrt( conjg( x' )*x ) */

  /*  -- This version written on 25-October-1982. */
  /*     Modified on 14-October-1993 to inline the call to ZLASSQ. */
  /*     Sven Hammarling, Nag Ltd. */

  /* Function Body */
  if (n < 1)
    norm = 0.0;
  else {
    if (incx < 0) x -= (n - 1) * incx;
    scale = 0.;
    ssq = 1.;

    /* The following loop is equivalent to this call to the LAPACK */
    /* auxiliary routine: */
    /* CALL ZLASSQ( N, X, INCX, SCALE, SSQ ) */
    while (n-- > 0) {
      if (x->r != 0.0) {
	temp = ABS(x->r);
	if (scale < temp) {
	  ssq = ssq * POW2(scale / temp) + 1.0;
	  scale = temp;
	}
	else
	  ssq += POW2(temp / scale);
      }
      if (x->i != 0.0) {
	temp = ABS(x->i);
	if (scale < temp) {
	  ssq = ssq * POW2(scale / temp) + 1.0;
	  scale = temp;
	}
	else
	  ssq += POW2(temp / scale);
      }
      x += incx;
    }
    norm = scale * sqrt(ssq);
  }

  return norm;
}

int blas_izamax P3C(int, n, dcomplex *, zx, int, incx)
{
  /* System generated locals */
  int ret_val;

  /* Local variables */
  double smax;
  int i;
  
  /* finds the index of element having max. absolute value. */
  /* jack dongarra, 1/15/85. */
  /* modified 3/93 to return if incx .le. 0. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  if (n < 1)
    return -1;
  ret_val = 0;
  if (n == 1)
    return ret_val;
  if (incx != 1) {
    /* code for increment not equal to 1 */
    if (incx < 0) zx -= (n - 1) * incx;
    smax = dcabs1(zx);
    zx += incx;
    for (i = 1; i < n; i++, zx += incx) {
      if (dcabs1(zx) > smax) {
	ret_val = i;
	smax = dcabs1(zx);
      }
    }
  }
  else {
    /* code for increment equal to 1 */
    smax = dcabs1(zx);
    zx++;
    for (i = 1; i < n; i++, zx++) {
      if (dcabs1(zx) > smax) {
	ret_val = i;
	smax = dcabs1(zx);
      }
    }
  }
  return ret_val;
}

VOID blas_zaxpy P6C(int, n,
		    dcomplex *, za,
		    dcomplex *, zx,
		    int, incx,
		    dcomplex *, zy,
		    int, incy)
{
  /* System locals */
  dcomplex z__1;

  /* constant times a vector plus a vector. */
  /* jack dongarra, 3/11/78. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  if (n <= 0)
    return;
  if (dcabs1(za) == 0.0)
    return;
  if (incx != 1 || incy != 1) {
    /* code for unequal increments or equal increments not equal to 1 */
    if (incx < 0) zx -= (n - 1) * incx;
    if (incy < 0) zy -= (n - 1) * incy;
    while (n-- > 0) {
      z__1.r = za->r * zx->r - za->i * zx->i;
      z__1.i = za->r * zx->i + za->i * zx->r;
      zy->r = zy->r + z__1.r;
      zy->i = zy->i + z__1.i;
      zx += incx;
      zy += incy;
    }
  }
  else {
    /* code for both increments equal to 1 */
    for (; n > 0; n--, zx++, zy++) {
      z__1.r = za->r * zx->r - za->i * zx->i;
      z__1.i = za->r * zx->i + za->i * zx->r;
      zy->r = zy->r + z__1.r;
      zy->i = zy->i + z__1.i;
    }
  }
}

VOID blas_zcopy P5C(int, n,
		    dcomplex *, zx,
		    int, incx,
		    dcomplex *, zy,
		    int, incy)
{
  /* copies a vector, x, to a vector, y. */
  /* jack dongarra, linpack, 4/11/78. */
  /* modified 12/3/93, array(1) declarations changed to array(*) */

  /* Function Body */
  if (n <= 0)
    return;
  if (incx != 1 || incy != 1) {
    /* code for unequal increments or equal increments not equal to 1 */
    if (incx < 0) zx -= (n - 1) * incx;
    if (incy < 0) zy -= (n - 1) * incy;
    while (n-- > 0) {
      zy->r = zx->r;
      zy->i = zx->i;
      zx += incx;
      zy += incy;
    }
  }
  else {
    /* code for both increments equal to 1 */
    while (n-- > 0) {
      zy->r = zx->r;
      zy->i = zx->i;
      zx++;
      zy++;
    }
  }
}

VOID blas_zdotc P6C(dcomplex *, ret_val,
		    int, n,
		    dcomplex *, zx,
		    int, incx,
		    dcomplex *, zy,
		    int, incy)
{
  /* System generated locals */
  dcomplex z__2, z__3;

  /* Local variables */
  dcomplex ztemp;

  /* forms the dot product of a vector. */
  /* jack dongarra, 3/11/78. */

  /* Function Body */
  ztemp.r = 0., ztemp.i = 0.;
  ret_val->r = 0.,  ret_val->i = 0.;
  if (n <= 0)
    return;
  if (incx != 1 || incy != 1) {
    /* code for unequal increments or equal increments */
    /* not equal to 1 */
    if (incx < 0) zx -= (n - 1) * incx;
    if (incy < 0) zy -= (n - 1) * incy;
    while (n-- > 0) {
      d_cnjg(&z__3, zx);
      z__2.r = z__3.r * zy->r - z__3.i * zy->i;
      z__2.i = z__3.r * zy->i + z__3.i * zy->r;
      ztemp.r += z__2.r;
      ztemp.i += z__2.i;
      zx += incx;
      zy += incy;
    }
  }
  else {
    /* code for both increments equal to 1 */
    for (; n > 0; n--, zx++, zy++) {
      d_cnjg(&z__3, zx);
      z__2.r = z__3.r * zy->r - z__3.i * zy->i;
      z__2.i = z__3.r * zy->i + z__3.i * zy->r;
      ztemp.r += z__2.r;
      ztemp.i += z__2.i;
    }
  }
  ret_val->r = ztemp.r,  ret_val->i = ztemp.i;
  return ;
}

VOID blas_zdotu P6C(dcomplex *, ret_val,
		    int, n,
		    dcomplex *, zx,
		    int, incx,
		    dcomplex *, zy,
		    int, incy)
{
  /* System generated locals */
  dcomplex z__2;

  /* Local variables */
  static dcomplex ztemp;

  /* forms the dot product of two vectors. */
  /* jack dongarra, 3/11/78. */

  /* Function Body */
  ztemp.r = 0., ztemp.i = 0.;
  ret_val->r = 0.,  ret_val->i = 0.;
  if (n <= 0)
    return;
  if (incx != 1 || incy != 1) {
    /* code for unequal increments or equal increments */
    /* not equal to 1 */
    if (incx < 0) zx -= (n - 1) * incx;
    if (incy < 0) zy -= (n - 1) * incy;
    while (n-- > 0) {
      z__2.r = zx->r * zy->r - zx->i * zy->i;
      z__2.i = zx->r * zy->i + zx->i * zy->r;
      ztemp.r += z__2.r;
      ztemp.i += z__2.i;
      zx += incx;
      zy += incy;
    }
  }
  else {
    /* code for both increments equal to 1 */
    for (; n > 0; n--, zx++, zy++) {
      z__2.r = zx->r * zy->r - zx->i * zy->i;
      z__2.i = zx->r * zy->i + zx->i * zy->r;
      ztemp.r += z__2.r;
      ztemp.i += z__2.i;
    }
  }
  ret_val->r = ztemp.r,  ret_val->i = ztemp.i;
  return ;
}

VOID blas_zdrot P7C(int, n,
		    dcomplex *, zx,
		    int, incx,
		    dcomplex *, zy,
		    int, incy,
		    double, c,
		    double, s)
{
  /* Local variables */
  dcomplex ztemp;

  /* applies a plane rotation, where the cos and sin (c and s) are */
  /* double precision and the vectors zx and zy are double complex. */
  /* jack dongarra, linpack, 3/11/78. */

  /* Function Body */
  if (n <= 0)
    return;
  if (incx != 1 || incy != 1) {
    /* code for unequal increments or equal increments not equal to 1 */
    if (incx < 0) zx -= (n - 1) * incx;
    if (incy < 0) zy -= (n - 1) * incy;
    while (n-- > 0) {
      ztemp.r = c * zx->r + s * zy->r;
      ztemp.i = c * zx->i + s * zy->i;
      zy->r = c * zy->r - s * zx->r;
      zy->i = c * zy->i - s * zx->i;
      zx->r = ztemp.r;
      zx->i = ztemp.i;
      zx += incx;
      zy += incy;
    }
  }
  else {
    /* code for both increments equal to 1 */
    for (; n > 0; n--, zx++, zy++) {
      ztemp.r = c * zx->r + s * zy->r;
      ztemp.i = c * zx->i + s * zy->i;
      zy->r = c * zy->r - s * zx->r;
      zy->i = c * zy->i - s * zx->i;
      zx->r = ztemp.r;
      zx->i = ztemp.i;
    }
  }
}

VOID blas_zdscal P4C(int, n,
		     double, da,
		     dcomplex *, zx,
		     int, incx)
{
  /* scales a vector by a constant. */
  /* jack dongarra, 3/11/78. */
  /* modified to correct problem with negative increment, 8/21/90. */

  /* Function Body */
  if (n <= 0)
    return;
  if (incx != 1) {
    /* code for increment not equal to 1 */
    if (incx < 0) zx -= (n - 1) * incx;
    while (n-- > 0) {
      zx->r = da * zx->r;
      zx->i = da * zx->i;
      zx += incx;
    }
  }
  else {
    /* code for increment equal to 1 */
    for (; n > 0; n--, zx++) {
      zx->r = da * zx->r;
      zx->i = da * zx->i;
    }
  }
}

VOID blas_zrotg P4C(dcomplex *, ca,
		    dcomplex *, cb,
		    double *, c,
		    dcomplex *, s)
{
  /* System generated locals */
  dcomplex z__1, z__2, z__3, z__4;

  /* Local variables */
  double norm;
  dcomplex alpha;
  double scale;

  if (z_abs(ca) == 0.0) {
    *c = 0.0;
    s->r = 1.0;
    s->i = 0.0;
    ca->r = cb->r;
    ca->i = cb->i;
  }
  else {
    double d__1, d__2;
    scale = z_abs(ca) + z_abs(cb);
    z__2.r = scale;
    z__2.i = 0.0;
    z_div(&z__1, ca, &z__2);
    z__4.r = scale;
    z__4.i = 0.0;
    z_div(&z__3, cb, &z__4);
    d__1 = POW2(z_abs(&z__1));
    d__2 = POW2(z_abs(&z__3));
    norm = scale * sqrt(d__1 + d__2);
    d__1 = z_abs(ca);
    z__1.r = ca->r / d__1;
    z__1.i = ca->i / d__1;
    alpha.r = z__1.r;
    alpha.i = z__1.i;
    *c = z_abs(ca) / norm;
    d_cnjg(&z__3, cb);
    z__2.r = alpha.r * z__3.r - alpha.i * z__3.i;
    z__2.i = alpha.r * z__3.i + alpha.i * z__3.r;
    z__1.r = z__2.r / norm;
    z__1.i = z__2.i / norm;
    s->r = z__1.r;
    s->i = z__1.i;
    z__1.r = norm * alpha.r;
    z__1.i = norm * alpha.i;
    ca->r = z__1.r;
    ca->i = z__1.i;
  }
}

VOID blas_zscal P4C(int, n,
		    dcomplex *, za,
		    dcomplex *, zx,
		    int, incx)
{
  /* System generated locals */
  dcomplex z__1;

  /* scales a vector by a constant. */
  /* jack dongarra, 3/11/78. */
  /* modified to correct problem with negative increment, 8/21/90. */

  /* Function Body */
  if (n <= 0)
    return;
  if (incx != 1) {
    /* code for increment not equal to 1 */
    if (incx < 0) zx -= (n - 1) * incx;
    while (n-- > 0) {
      z__1.r = za->r * zx->r - za->i * zx->i;
      z__1.i = za->r * zx->i + za->i * zx->r;
      zx->r = z__1.r;
      zx->i = z__1.i;
      zx += incx;
    }
  }
  else {
    /* code for increment equal to 1 */
    for (; n > 0; n--, zx++) {
      z__1.r = za->r * zx->r - za->i * zx->i;
      z__1.i = za->r * zx->i + za->i * zx->r;
      zx->r = z__1.r;
      zx->i = z__1.i;
    }
  }
}

VOID blas_zswap P5C(int, n,
		    dcomplex *, zx,
		    int, incx,
		    dcomplex *, zy,
		    int, incy)
{
  /* Local variables */
  dcomplex ztemp;
  
  /* interchanges two vectors. */
  /* jack dongarra, 3/11/78. */

  /* Function Body */
  if (n <= 0)
    return;
  if (incx != 1 || incy != 1) {
    /* code for unequal increments or equal increments not equal to 1 */
    if (incx < 0) zx -= (n - 1) * incx;
    if (incy < 0) zy -= (n - 1) * incy;
    while (n-- > 0) {
      ztemp.r = zx->r;
      ztemp.i = zx->i;
      zx->r = zy->r;
      zx->i = zy->i;
      zy->r = ztemp.r;
      zy->i = ztemp.i;
      zx += incx;
      zy += incy;
    }
  }
  else {
    /* code for both increments equal to 1 */
    for (; n > 0; n--, zx++, zy++) {
      ztemp.r = zx->r;
      ztemp.i = zx->i;
      zx->r = zy->r;
      zx->i = zy->i;
      zy->r = ztemp.r;
      zy->i = ztemp.i;
    }
  }
}


/****************************************************************************/
/**                                                                        **/
/**                           Level 2 BLAS routines                        **/
/**                       translated by f2c and modified                   **/
/**                                                                        **/
/****************************************************************************/

LOCAL VOID blas_dzero P3C(int, n, double *, x, int, incx)
{
  if (incx < 0) x -= (n - 1) * incx;
  for (; n > 0; n--, x += incx)
    *x = 0.0;
}

LOCAL VOID blas_zzero P3C(int, n, dcomplex *, z, int, incz)
{
  if (incz < 0) z -= (n - 1) * incz;
  for (; n > 0; n--, z += incz) {
    z->r = 0.0;
    z->i = 0.0;
  }
}

LOCAL VOID blas_zconj P3C(int, n, dcomplex *, z, int, incz)
{
  if (incz < 0) z -= (n - 1) * incz;
  for (; n > 0; n--, z += incz)
    z->i = -z->i;
}
  
VOID blas_dgemv P11C(char *, trans,
		     int, m,
		     int, n,
		     double, alpha,
		     double *, a,
		     int, lda,
		     double *, x,
		     int, incx,
		     double, beta,
		     double *, y,
		     int, incy)
{
  /* Local variables */
  int leny;

  /*
   * DGEMV  performs one of the matrix-vector operations
   *
   *     y := alpha*A*x + beta*y,   or   y := alpha*A'*x + beta*y,
   *
   *  where alpha and beta are scalars, x and y are vectors and A is an
   *  m by n matrix.
   *
   *  Level 2 Blas routine.
   */

  /* Quick return if possible. */
  if (m == 0 || n == 0 || (alpha == 0.0 && beta == 1.0))
    return;

  /* Set LENY, the length of the vector y. */
  leny = (*trans == 'n' || *trans == 'N') ? m : n;

  /* First form  y := beta*y. */
  if (beta != 1.0) {
    if (beta == 0.0)
      blas_dzero(leny, y, incy);
    else
      blas_dscal(leny, beta, y, incy);
  }

  if (alpha == 0.0)
    return;

  if (*trans == 'n' || *trans == 'N') {
    /* Form  y := alpha*A*x + y. */
    if (incx < 0) x -= (n - 1) * incx;
    for (; n > 0; n--, a += lda, x += incx)
      if (*x != 0.0)
	blas_daxpy(m, alpha * *x, a, 1, y, incy);
  }
  else {
    /* Form  y := alpha*A'*x + y. */
    if (incy < 0) y -= (n - 1) * incy;
    for (; n > 0; n--, a += lda, y += incy)
      *y += alpha * blas_ddot(m, a, 1, x, incx);
  }
  return;
}

VOID blas_dtrmv P8C(char *, uplo,
		    char *, trans,
		    char *, diag,
		    int, n,
		    double *, a,
		    int, lda,
		    double *, x,
		    int, incx)
{
  /* Local variables */
  int j;
  int jx, kx;
  int nounit;
  int jx1, jlda;

  /*
   * DTRMV  performs one of the matrix-vector operations
   *
   *     x := A*x,   or   x := A'*x,
   *
   *  where x is an n element vector and  A is an n by n unit, or non-unit,
   *  upper or lower triangular matrix.
   *
   *  Level 2 Blas routine.
   */

  /* Quick return if possible. */

  if (n == 0)
    return;

  nounit = *diag == 'n' || *diag == 'N';

  /* Set up the start point in X if the increment is not unity. This */
  /* will be  ( N - 1 )*INCX  too small for descending loops. */

  kx = (incx <= 0) ? - (n - 1) * incx : 0;

  /* Start the operations. In this version the elements of A are */
  /* accessed sequentially with one pass through A. */

  if (*trans == 'n' || *trans == 'N') {

    /* Form  x := A*x. */

    if (*uplo == 'u' || *uplo == 'U') {
      jx = kx;
      jlda = 0;
      for (j = 0; j < n; j++) {
	if (x[jx] != 0.0) {
	  jx1 = (incx < 0) ? jx - incx : 0;
	  blas_daxpy(j, x[jx], a + jlda, 1, x + jx1, incx);
	  if (nounit)
	    x[jx] *= a[j + jlda];
	}
	jx += incx;
	jlda += lda;
      }
    }
    else {
      kx += (n - 1) * incx;
      jx = kx;
      jlda = (n - 1) * lda;
      for (j = n - 1; j >= 0; j--) {
	if (x[jx] != 0.0) {
	  jx1 = (incx > 0) ? jx + incx : 0;
	  blas_daxpy(n - j - 1, x[jx], a + j + 1 + jlda, -1, x + jx1, -incx);
	  if (nounit)
	    x[jx] *= a[j + jlda];
	}
	jx -= incx;
	jlda -= lda;
      }
    }
  }
  else {

    /* Form  x := A'*x. */

    if (*uplo == 'u' || *uplo == 'U') {
      jx = kx + (n - 1) * incx;
      jlda = (n - 1) * lda;
      for (j = n - 1; j >= 0; j--) {
	if (nounit)
	  x[jx] *= a[j + jlda];
	jx1 = (incx < 0) ? jx - incx : 0;
	x[jx] += blas_ddot(j, a + jlda, -1, x + jx1, -incx);
	jx -= incx;
	jlda -= lda;
      }
    }
    else {
      jx = kx;
      jlda = 0;
      for (j = 0; j < n; j++) {
	if (nounit)
	  x[jx] *= a[j + jlda];
	jx1 = (incx > 0) ? jx + incx : 0;
	x[jx] += blas_ddot(n - j - 1, a + j + 1 + jlda, 1, x + jx1, incx);
	jx += incx;
	jlda += lda;
      }
    }
  }

  return;
}


VOID blas_dger P9C(int,  m,
		   int, n,
		   double, alpha,
		   double *, x,
		   int, incx,
		   double *, y,
		   int, incy,
		   double *, a,
		   int, lda)
{
  /* Local variables */
  int j;

  /*
   * DGER   performs the rank 1 operation
   *
   *     A := alpha*x*y' + A,
   *
   *  where alpha is a scalar, x is an m element vector, y is an n element 
   *  vector and A is an m by n matrix.
   *
   *  Level 2 Blas routine.
   */

  /* Quick return if possible. */
  if (m == 0 || n == 0 || alpha == 0.0)
    return;

  if (incy < 0) y -= (n - 1) * incy;

  /* Start the operations. In this version the elements of A are */
  /* accessed sequentially with one pass through A. */
  for (j = 0; j < n; j++, a += lda, y += incy)
    if (*y != 0.0)
      blas_daxpy(m, alpha * *y, x, incx, a, 1);

  return;
}

VOID blas_dtrsv P8C(char *, uplo,
		    char *, trans,
		    char *, diag,
		    int, n,
		    double *, a,
		    int, lda,
		    double *, x,
		    int, incx)
{
  /* Local variables */
  int j;
  int jx, kx;
  int nounit;
  int jx1, jlda;

  /*
   * DTRSV  solves one of the systems of equations
   *
   *     A*x = b,   or   A'*x = b,
   *
   *  where b and x are n element vectors and A is an n by n unit, or
   *  non-unit, upper or lower triangular matrix.
   *
   *  No test for singularity or near-singularity is included in this
   *  routine. Such tests must be performed before calling this routine.
   *
   *  Level 2 Blas routine.
   */

  /* Quick return if possible. */
  if (n == 0)
    return;

  nounit = *diag == 'n' || *diag == 'N';

  /* Set up the start point in X if the increment is not unity. This */
  /* will be  ( N - 1 )*INCX  too small for descending loops. */

  kx = (incx <= 0) ? - (n - 1) * incx : 0;

  /* Start the operations. In this version the elements of A are */
  /* accessed sequentially with one pass through A. */

  if (*trans == 'n' || *trans == 'N') {
    /* Form  x := inv( A )*x. */
    if (*uplo == 'u' || *uplo == 'U') {
      jx = kx + (n - 1) * incx;
      jlda = (n - 1) * lda;
      for (j = n - 1; j >= 0; j--) {
	if (x[jx] != 0.0) {
	  if (nounit)
	    x[jx] /= a[j + jlda];
	  jx1 = (incx < 0) ? jx - incx : 0;
	  blas_daxpy(j, -x[jx], a + jlda, -1, x + jx1, -incx);
	}
	jx -= incx;
	jlda -= lda;
      }
    }
    else {
      jx = kx;
      jlda = 0;
      for (j = 0; j < n; j++) {
	if (x[jx] != 0.0) {
	  if (nounit)
	    x[jx] /= a[j + jlda];
	  jx1 = (incx > 0) ? jx + incx : 0;
	  blas_daxpy(n - j - 1, -x[jx], a + j + 1 + jlda, 1, x + jx1, incx);
	}
	jx += incx;
	jlda += lda;
      }
    }
  }
  else {

    /* Form  x := inv( A' )*x. */

    if (*uplo == 'u' || *uplo == 'U') {
      jx = kx;
      jlda = 0;
      for (j = 0; j < n; j++) {
	jx1 = (incx < 0) ? jx - incx : 0;
	x[jx] -= blas_ddot(j, a + jlda, 1, x + jx1, incx);
	if (nounit)
	  x[jx] /= a[j + jlda];
	jx += incx;
	jlda += lda;
      }
    }
    else {
      jx = kx + (n - 1) * incx;
      jlda = (n - 1) * lda;
      for (j = n - 1; j >= 0; j--) {
	jx1 = (incx > 0) ? jx + incx : 0;
	x[jx] -= blas_ddot(n - j - 1, a + j + 1 + jlda, -1, x + jx1, -incx);
	if (nounit)
	  x[jx] /= a[j + jlda];
	jx -= incx;
	jlda -= lda;
      }
    }
  }

  return;
}

VOID blas_zgemv P11C(char *, trans,
		     int, m,
		     int, n,
		     dcomplex *, alpha,
		     dcomplex *, a,
		     int, lda,
		     dcomplex *, x,
		     int, incx,
		     dcomplex *, beta,
		     dcomplex *, y,
		     int, incy)
{
  /* Local variables */
  dcomplex temp;
  int leny;
  int noconj;

  /*
   * ZGEMV  performs one of the matrix-vector operations
   *
   *     y := alpha*A*x + beta*y,   or   y := alpha*A'*x + beta*y,   or
   *
   *     y := alpha*conjg( A' )*x + beta*y,
   *
   *  where alpha and beta are scalars, x and y are vectors and A is an
   *  m by n matrix.
   *
   *  Level 2 Blas routine.
   */

  /* Quick return if possible. */
  if (m == 0 || n == 0 ||
      (alpha->r == 0.0 && alpha->i == 0.0 &&
       (beta->r == 1.0 && beta->i == 0.0)))
    return;

  noconj = *trans == 't' || *trans == 'T';

  /* Set  LENY, the length of the vector y. */
  leny = (*trans == 'n' || *trans == 'N') ? m : n;

  /* Start the operations. In this version the elements of A are */
  /* accessed sequentially with one pass through A. */

  /* First form  y := beta*y. */
  if (beta->r != 1.0 || beta->i != 0.0) {
    if (beta->r == 0.0 && beta->i == 0.0)
      blas_zzero(leny, y, incy);
    else
      blas_zscal(leny, beta, y, incy);
  }

  if (alpha->r == 0.0 && alpha->i == 0.0)
    return;

  if (*trans == 'n' || *trans == 'N') {
    /* Form  y := alpha*A*x + y. */
    if (incx < 0) x -= (n - 1) * incx;
    for (; n > 0; n--, a += lda, x += incx)
      if (x->r != 0.0 || x->i != 0.0) {
	temp.r = alpha->r * x->r - alpha->i * x->i;
	temp.i = alpha->r * x->i + alpha->i * x->r;
	blas_zaxpy(m, &temp, a, 1, y, incy);
      }      
  }
  else {
    /* Form  y := alpha*A'*x + y  or  y := alpha*conjg( A' )*x + y. */
    if (incy < 0) y -= (leny - 1) * incy;
    for (; n > 0; n--, a += lda, y += incy) {
      if (noconj)
	blas_zdotu(&temp, m, a, 1, x, incx);
      else
	blas_zdotc(&temp, m, a, 1, x, incx);
      y->r += alpha->r * temp.r - alpha->i * temp.i;
      y->i += alpha->r * temp.i + alpha->i * temp.r;
    }
  }
  return;
}

VOID blas_ztrmv P8C(char *, uplo,
		    char *, trans,
		    char *, diag,
		    int, n,
		    dcomplex *, a,
		    int, lda,
		    dcomplex *, x,
		    int, incx)
{
  /* System generated locals */
  dcomplex z__1, z__2;

  /* Local variables */
  int j;
  int jx, kx;
  int nounit, noconj;
  int jx1, jlda;

  /*
   * ZTRMV  performs one of the matrix-vector operations
   *
   *     x := A*x,   or   x := A'*x,  or  x := conj( A' )*x
   *
   *  where x is an n element vector and  A is an n by n unit, or non-unit,
   *  upper or lower triangular matrix.
   *
   *  Level 2 Blas routine.
   */

  /* Quick return if possible. */
  if (n == 0)
    return;

  nounit = *diag == 'n' || *diag == 'N';
  noconj = *trans == 't' || *trans == 'T';

  /* Set up the start point in X if the increment is not unity. This */
  /* will be  ( N - 1 )*INCX  too small for descending loops. */

  kx = (incx <= 0) ? - (n - 1) * incx : 0;

  /* Start the operations. In this version the elements of A are */
  /* accessed sequentially with one pass through A. */

  if (*trans == 'n' || *trans == 'N') {

    /* Form  x := A*x. */

    if (*uplo == 'u' || *uplo == 'U') {
      jx = kx;
      jlda = 0;
      for (j = 0; j < n; j++) {
	if (x[jx].r != 0.0 || x[jx].i != 0.0) {
	  jx1 = (incx < 0) ? jx - incx : 0;
	  blas_zaxpy(j, &x[jx], a + jlda, 1, x + jx1, incx);
	  if (nounit) {
	    z__1.r = x[jx].r * a[j + jlda].r - x[jx].i * a[j + jlda].i;
	    z__1.i = x[jx].r * a[j + jlda].i + x[jx].i * a[j + jlda].r;
	    x[jx].r = z__1.r;
	    x[jx].i = z__1.i;
	  }
	}
	jx += incx;
	jlda += lda;
      }
    }
    else {
      kx += (n - 1) * incx;
      jx = kx;
      jlda = (n - 1) * lda;
      for (j = n - 1; j >= 0; --j) {
	if (x[jx].r != 0.0 || x[jx].i != 0.0) {
	  jx1 = (incx > 0) ? jx + incx : 0;
	  blas_zaxpy(n - j - 1, &x[jx], a + j + 1 + jlda, -1, x + jx1, -incx);
	  if (nounit) {
	    z__1.r = x[jx].r * a[j + jlda].r - x[jx].i * a[j + jlda].i;
	    z__1.i = x[jx].r * a[j + jlda].i + x[jx].i * a[j + jlda].r;
	    x[jx].r = z__1.r;
	    x[jx].i = z__1.i;
	  }
	}
	jx -= incx;
	jlda -= lda;
      }
    }
  }
  else {

    /* Form  x := A'*x or x := conj( A' )*x. */

    if (*uplo == 'u' || *uplo == 'U') {
      jx = kx + (n - 1) * incx;
      jlda = (n - 1) * lda;
      for (j = n - 1; j >= 0; j--) {
	if (nounit) {
	  if (noconj) {
	    z__1.r = a[j + jlda].r;
	    z__1.i = a[j + jlda].i;
	  }
	  else
	    d_cnjg(&z__1, a + j + jlda);
	  z__2.r = x[jx].r * z__1.r - x[jx].i * z__1.i;
	  z__2.i = x[jx].r * z__1.i + x[jx].i * z__1.r;
	  x[jx].r = z__2.r;
	  x[jx].i = z__2.i;
	}
	jx1 = (incx < 0) ? jx - incx : 0;
	if (noconj)
	  blas_zdotu(&z__1, j, a + jlda, -1, x + jx1, -incx); 
	else
	  blas_zdotc(&z__1, j, a + jlda, -1, x + jx1, -incx); 
	x[jx].r += z__1.r;
	x[jx].i += z__1.i;
	jx -= incx;
	jlda -= lda;
      }
    }
    else {
      jx = kx;
      jlda = 0;
      for (j = 0; j < n; j++) {
	if (nounit) {
	  if (noconj) {
	    z__1.r = a[j + jlda].r;
	    z__1.i = a[j + jlda].i;
	  }
	  else
	    d_cnjg(&z__1, a + j + jlda);
	  z__2.r = x[jx].r * z__1.r - x[jx].i * z__1.i;
	  z__2.i = x[jx].r * z__1.i + x[jx].i * z__1.r;
	  x[jx].r = z__2.r;
	  x[jx].i = z__2.i;
	}
	jx1 = (incx > 0) ? jx + incx : 0;
	if (noconj)
	  blas_zdotu(&z__1, n - j - 1, a + j + 1 + jlda, 1, x + jx1, incx);
	else
	  blas_zdotc(&z__1, n - j - 1, a + j + 1 + jlda, 1, x + jx1, incx);
	x[jx].r += z__1.r;
	x[jx].i += z__1.i;
	jx += incx;
	jlda += lda;
      }
    }
  }

  return;
}


VOID blas_zgerc P9C(int, m,
		    int, n,
		    dcomplex *, alpha,
		    dcomplex *, x,
		    int, incx,
		    dcomplex *, y,
		    int, incy,
		    dcomplex *, a,
		    int, lda)
{
  /* System generated locals */
  dcomplex z__1;

  /* Local variables */
  dcomplex temp;

  /*
   * ZGERC  performs the rank 1 operation
   *
   *     A := alpha*x*conjg( y' ) + A,
   *
   *  where alpha is a scalar, x is an m element vector, y is an n element 
   *  vector and A is an m by n matrix.
   *
   *  Level 2 Blas routine.
   */

  /* Quick return if possible. */
  if (m == 0 || n == 0 || (alpha->r == 0.0 && alpha->i == 0.0))
    return;

  /* Start the operations. In this version the elements of A are */
  /* accessed sequentially with one pass through A. */

  if (incy < 0) y -= (n - 1) * incy;
  for (; n > 0; n--, a += lda, y += incy)
    if (y->r != 0. || y->i != 0.) {
      d_cnjg(&z__1, y);
      temp.r = alpha->r * z__1.r - alpha->i * z__1.i;
      temp.i = alpha->r * z__1.i + alpha->i * z__1.r;
      blas_zaxpy(m, &temp, x, incx, a, 1);
    }
  return;
}

VOID blas_zgeru P9C(int, m,
		    int, n,
		    dcomplex *, alpha,
		    dcomplex *, x,
		    int, incx,
		    dcomplex *, y,
		    int, incy,
		    dcomplex *, a,
		    int, lda)
{
  /* Local variables */
  dcomplex temp;

  /*
   * ZGERU  performs the rank 1 operation
   *
   *     A := alpha*x*y' + A,
   *
   *  where alpha is a scalar, x is an m element vector, y is an n element
   *  vector and A is an m by n matrix.
   *
   *  Level 2 Blas routine.
   */

  /* Quick return if possible. */
  if (m == 0 || n == 0 || (alpha->r == 0.0 && alpha->i == 0.0))
    return;

  /* Start the operations. In this version the elements of A are */
  /* accessed sequentially with one pass through A. */

  if (incy < 0) y -= (n - 1) * incy;

  for (; n > 0; n--, a += lda, y += incy)
    if (y->r != 0. || y->i != 0.) {
      temp.r = alpha->r * y->r - alpha->i * y->i;
      temp.i = alpha->r * y->i + alpha->i * y->r;
      blas_zaxpy(m, &temp, x, incx, a, 1);
    }
  return;
}

VOID blas_ztrsv P8C(char *, uplo,
		    char *, trans,
		    char *, diag,
		    int, n,
		    dcomplex *, a,
		    int, lda,
		    dcomplex *, x,
		    int, incx)
{
  /* System generated locals */
  dcomplex z__1;

  /* Local variables */
  dcomplex temp;
  int j, jx, kx;
  int noconj, nounit;
  int jx1, jlda;

  /*
   * ZTRSV  solves one of the systems of equations
   *
   *     A*x = b,   or   A'*x = b,   or   conjg( A' )*x = b,
   *
   *  where b and x are n element vectors and A is an n by n unit, or
   *  non-unit, upper or lower triangular matrix.
   *
   *  No test for singularity or near-singularity is included in this
   *  routine. Such tests must be performed before calling this routine.
   *
   *  Level 2 Blas routine.
   */

  /* Quick return if possible. */

  if (n == 0)
    return;

  noconj = *trans == 't' || *trans == 'T';
  nounit = *diag == 'n' || *diag == 'N';

  /* Set up the start point in X if the increment is not unity. This */
  /* will be  ( N - 1 )*INCX  too small for descending loops. */

  kx = (incx <= 0) ? - (n - 1) * incx : 0;
  
  /* Start the operations. In this version the elements of A are */
  /* accessed sequentially with one pass through A. */

  if (*trans == 'n' || *trans == 'N') {

    /* Form  x := inv( A )*x. */

    if (*uplo == 'u' || *uplo == 'U') {
      jx = kx + (n - 1) * incx;
      jlda = (n - 1) * lda;
      for (j = n - 1; j >= 0; --j) {
	if (x[jx].r != 0.0 || x[jx].i != 0.0) {
	  if (nounit) {
	    z_div(&z__1, &x[jx], &a[j + jlda]);
	    x[jx].r = z__1.r;
	    x[jx].i = z__1.i;
	  }
	  temp.r = -x[jx].r;
	  temp.i = -x[jx].i;
	  jx1 = (incx < 0) ? jx - incx : 0;
	  blas_zaxpy(j, &temp, a + jlda, -1, x + jx1, -incx);
	}
	jx -= incx;
	jlda -= lda;
      }
    }
    else {
      jx = kx;
      jlda = 0;
      for (j = 0; j < n; ++j) {
	if (x[jx].r != 0. || x[jx].i != 0.) {
	  if (nounit) {
	    z_div(&z__1, x + jx, a + j + jlda);
	    x[jx].r = z__1.r;
	    x[jx].i = z__1.i;
	  }
	  temp.r = -x[jx].r;
	  temp.i = -x[jx].i;
	  jx1 = (incx < 0) ? 0 : jx + incx;
	  blas_zaxpy(n - j - 1, &temp, a + j + 1 + jlda, 1, x + jx1, incx);
	}
	jx += incx;
	jlda += lda;
      }
    }
  }
  else {

    /* Form  x := inv( A' )*x  or  x := inv( conjg( A' ) )*x. */

    if (*uplo == 'u' || *uplo == 'U') {
      jx = kx;
      jlda = 0;
      for (j = 0; j < n; ++j) {
	temp.r = x[jx].r, temp.i = x[jx].i;
	jx1 = (incx < 0) ? jx - incx : 0;
	if (noconj) {
	  blas_zdotu(&z__1, j, a + jlda, 1, x + jx1, incx);
	  temp.r -= z__1.r;
	  temp.i -= z__1.i;
	  if (nounit) {
	    z_div(&z__1, &temp, a + j + jlda);
	    temp.r = z__1.r;
	    temp.i = z__1.i;
	  }
	}
	else {
	  blas_zdotc(&z__1, j, a + jlda, 1, x + jx1, incx);
	  temp.r -= z__1.r;
	  temp.i -= z__1.i;
	  if (nounit) {
	    d_cnjg(&z__1, &a[j + jlda]);
	    z_div(&z__1, &temp, &z__1);
	    temp.r = z__1.r;
	    temp.i = z__1.i;
	  }
	}
	x[jx].r = temp.r;
	x[jx].i = temp.i;
	jx += incx;
	jlda += lda;
      }
    }
    else {
      jx = kx + (n - 1) * incx;;
      jlda = (n - 1) * lda;
      for (j = n - 1; j >= 0; --j) {
	temp.r = x[jx].r, temp.i = x[jx].i;
	jx1 = (incx < 0) ? 0 : jx + incx;
	if (noconj) {
	  blas_zdotu(&z__1, n - j - 1, a + j + 1 + jlda, -1, x + jx1, -incx);
	  temp.r -= z__1.r;
	  temp.i -= z__1.i;
	  if (nounit) {
	    z_div(&z__1, &temp, a + j + jlda);
	    temp.r = z__1.r;
	    temp.i = z__1.i;
	  }
	}
	else {
	  blas_zdotc(&z__1, n - j - 1, a + j + 1 + jlda, -1, x + jx1, -incx);
	  temp.r -= z__1.r;
	  temp.i -= z__1.i;
	  if (nounit) {
	    d_cnjg(&z__1, &a[j + jlda]);
	    z_div(&z__1, &temp, &z__1);
	    temp.r = z__1.r;
	    temp.i = z__1.i;
	  }
	}
	x[jx].r = temp.r;
	x[jx].i = temp.i;
	jx -= incx;
	jlda -= lda;
      }
    }
  }
  return;
}


/****************************************************************************/
/**                                                                        **/
/**                           Level 3 BLAS routines                        **/
/**                       translated by f2c and modified                   **/
/**                                                                        **/
/****************************************************************************/

VOID blas_dgemm P13C(char *, transa,
		     char *, transb,
		     int, m,
		     int, n,
		     int, k,
		     double, alpha,
		     double *, a,
		     int, lda,
		     double *, b,
		     int, ldb,
		     double, beta,
		     double *, c,
		     int, ldc)
{
  /* Local variables */
  int nota, notb, mm, kk;

  /*
   * DGEMM  performs one of the matrix-matrix operations
   *
   *     C := alpha*op( A )*op( B ) + beta*C,
   *
   *  where  op( X ) is one of
   *
   *     op( X ) = X   or   op( X ) = X',
   *
   *  alpha and beta are scalars, and A, B and C are matrices, with op( A )
   *  an m by k matrix,  op( B )  a  k by n matrix and  C an m by n matrix.
   *
   *  Level 3 Blas routine.
   */

  /* Set NOTA  as  true if  A is not transposed; compute dimensions. */
  nota = *transa == 'n' || *transa == 'N';
  mm = nota ? m : k;
  kk = nota ? k : m;

  /* Set NOTB  as  true if  B is not transposed. */
  notb = *transb == 'n' || *transb == 'N';

  /* Quick return if possible. */
  if (m == 0 || n == 0 || ((alpha == 0.0 || k == 0) && beta == 1.0))
    return;

  /* And if alpha == zero. */
  if (alpha == 0.0) {
    if (beta == 0.0)
      blas_dzero(m * n, c, 1);
    else if (beta != 1.0)
      blas_dscal(m * n, beta, c, 1);
    return;
  }

  /* Start the operations. */
  if (notb)
    /* Form  C := alpha*op(A)*B + beta*C. */
    for (; n > 0; n--, b += ldb, c += ldc)
      blas_dgemv(transa, mm, kk, alpha, a, lda, b, 1, beta, c, 1);
  else
    /* Form  C := alpha*op(A)*B' + beta*C */
    for (; n > 0; n--, b++, c += ldc)
      blas_dgemv(transa, mm, kk, alpha, a, lda, b, ldb, beta, c, 1);

  return;
}

VOID blas_dtrsm P11C(char *, side,
		     char *, uplo,
		     char *, transa,
		     char *, diag,
		     int, m,
		     int, n,
		     double, alpha,
		     double *, a,
		     int, lda,
		     double *, b,
		     int, ldb)
{
  /* Local variables */
  int lside, i;
  char *trans;

  /*
   * DTRSM  solves one of the matrix equations
   *
   *     op( A )*X = alpha*B,   or   X*op( A ) = alpha*B,
   *
   *  where alpha is a scalar, X and B are m by n matrices, A is a unit, or
   *  non-unit,  upper or lower triangular matrix  and  op( A )  is one  of 
   *
   *     op( A ) = A   or   op( A ) = A'.
   *
   *  The matrix X is overwritten on B.
   *
   *  Level 3 Blas routine.
   */

  /* Quick return if possible. */
  if (n == 0)
    return;

  /* And when  alpha == zero. */
  if (alpha == 0.0) {
    blas_dzero(m * n, b, 1);
    return;
  }

  /* Start the operations. */

  lside = *side == 'l' || *side == 'L';

  if (lside) {
    /* Form  B := alpha*inv( op( A ) )*B. */
    for (i = 0; i < n; i++, b += ldb) {
      if (alpha != 1.0)
	blas_dscal(m, alpha, b, 1);
      blas_dtrsv(uplo, transa, diag, m, a, lda, b, 1);
    }
  }
  else {
    trans = (*transa == 'n' || *transa == 'N') ? "T" : "N";
    /* Form  B := alpha*B*inv( op( A ) ). */
    for (i = 0; i < m; i++, b++) {
      if (alpha != 1.0)
	blas_dscal(n, alpha, b, ldb);
      blas_dtrsv(uplo, trans, diag, n, a, lda, b, ldb);
    }
  }
  return;
}

VOID blas_zgemm P13C(char *, transa,
		     char *, transb,
		     int, m,
		     int, n,
		     int, k,
		     dcomplex *, alpha,
		     dcomplex *, a,
		     int, lda,
		     dcomplex *, b,
		     int, ldb,
		     dcomplex *, beta,
		     dcomplex *, c,
		     int, ldc)
{
  /* Local variables */
  int nota, notb, conja, conjb, i, j, l;
  dcomplex temp;

  /*
   * ZGEMM  performs one of the matrix-matrix operations
   *
   *     C := alpha*op( A )*op( B ) + beta*C,
   *
   *  where  op( X ) is one of
   *
   *     op( X ) = X   or   op( X ) = X',
   *
   *  alpha and beta are scalars, and A, B and C are matrices, with op( A )
   *  an m by k matrix,  op( B )  a  k by n matrix and  C an m by n matrix.
   *
   *  Level 3 Blas routine.
   */

  /* Set  NOTA  and  NOTB  as  true if  A  and  B  respectively are not */
  /* conjugated or transposed, and set  CONJA and CONJB  as true if  A  */
  /* and  B  respectively are to be  transposed and conjugated.         */

  nota  = *transa == 'n' || *transa == 'N';
  notb  = *transb == 'n' || *transb == 'N';
  conja = *transa == 'c' || *transa == 'C';
  conjb = *transb == 'c' || *transa == 'C';

  /* Quick return if possible. */
  if (m == 0 || n == 0 ||
      (((alpha->r == 0.0 && alpha->i == 0.0) || k == 0) &&
       (beta->r == 1.0 && beta->i == 0.0)))
    return;

  /* And if alpha == zero (after initializing C). */
  if (beta->r == 0.0 && beta->i == 0.0)
    blas_zzero(m * n, c, 1);
  else if (beta->r != 1.0 || beta->i != 0.0)
    blas_zscal(m * n, beta, c, 1);
  if (alpha->r == 0.0 && alpha->i == 0.0)
    return;

  if (nota) {

    /* Form  C := alpha*A*op( B ) + beta*C. */

    for (j = 0; j < n; j++) {
      for (l = 0; l < k; l++) {
	if (notb)
	  z_mul(&temp, alpha, b + l + j * ldb);
	else if (conjb) {
	  d_cnjg(&temp, b + j + l * ldb);
	  z_mul(&temp, alpha, &temp);
	}
	else
	  z_mul(&temp, alpha, b + j + l *ldb);
	blas_zaxpy(m, &temp, a + l * lda, 1, c + j  * ldc, 1);
      }
    }
  }
  else {

    /* Form  C := alpha*conjg( A' )* op( B ) + beta*C, */
    /* or    C := alpha*A'         * op( B ) + beta*C. */

    for (j = 0; j < n; j++) {
      for (i = 0; i < m; i++) {
	if (conja) {
	  if (notb)
	    blas_zdotc(&temp, k, b + j * ldb, 1, a + i * lda, 1);
	  else if (conjb)
	    blas_zdotu(&temp, k, b + j, ldb, a + i * lda, 1);
	  else
	    blas_zdotc(&temp, k, b + j, ldb, a + i * lda, 1);
	  d_cnjg(&temp, &temp);
	}
	else {
	  if (notb)
	    blas_zdotu(&temp, k, b + j * ldb, 1, a + i * lda, 1);
	  else if (conjb)
	    blas_zdotc(&temp, k, b + j, ldb, a + i * lda, 1);
	  else
	    blas_zdotu(&temp, k, b + j, ldb, a + i * lda, 1);
	}
	z_mul(&temp, alpha, &temp);
	c[i + j * ldc].r += temp.r;
	c[i + j * ldc].i += temp.i;
      }
    }
  }
  return;
}

VOID blas_ztrsm P11C(char *, side,
		     char *, uplo,
		     char *, transa,
		     char *, diag,
		     int, m,
		     int, n,
		     dcomplex *, alpha,
		     dcomplex *, a,
		     int, lda,
		     dcomplex *, b,
		     int, ldb)
{
  /* Local variables */
  int lside, conj, i;
  char *trans;

  /*
   * ZTRSM  solves one of the matrix equations
   *
   *     op( A )*X = alpha*B,   or   X*op( A ) = alpha*B,
   *
   *  where alpha is a scalar, X and B are m by n matrices, A is a unit, or
   *  non-unit,  upper or lower triangular matrix  and  op( A )  is one  of 
   *
   *     op( A ) = A   or   op( A ) = A'.
   *
   *  The matrix X is overwritten on B.
   *
   *  Level 3 Blas routine.
   */

  /* Quick return if possible. */
  if (n == 0)
    return;

  /* And when  alpha == zero. */
  if (alpha->r == 0.0 && alpha->i == 0.0) {
    blas_zzero(m * n, b, 1);
    return;
  }

  /* Start the operations. */

  lside = *side == 'l' || *side == 'L';

  if (lside) {
    /* Form  B := alpha*inv( op( A ) )*B. */
    for (i = 0; i < n; i++, b += ldb) {
      if (alpha->r != 1.0 || alpha->i != 0.0)
	blas_zscal(m, alpha, b, 1);
      blas_ztrsv(uplo, transa, diag, m, a, lda, b, 1);
    }
  }
  else {
    trans = (*transa == 'n' || *transa == 'N') ? "T" : "N";
    conj = (*transa == 'c' || *transa == 'C');
    /* Form  B := alpha*B*inv( op( A ) ). */
    for (i = 0; i < m; i++, b++) {
      if (alpha->r != 1.0 || alpha->i != 0.0)
	blas_zscal(n, alpha, b, ldb);
      if (conj)
	blas_zconj(n, b, ldb);
      blas_ztrsv(uplo, trans, diag, n, a, lda, b, ldb);
      if (conj)
	blas_zconj(n, b, ldb);
    }
  }
  return;
}


/****************************************************************************/
/**                                                                        **/
/**                 XLISP-STAT interface to BLAS routines                  **/
/**                                                                        **/
/****************************************************************************/

LOCAL VOID getblasdvec P3C(int, n, double **, pdx, int *, pincr)
{
  LVAL x;
  int size, type, offset, incr;

  x = xlgatvec();
  size = gettvecsize(x);
  type = gettvectype(x);
  offset = getfixnum(xlgafixnum());
  incr = getfixnum(xlgafixnum());

  if (offset < 0 || size < offset + (n - 1) * abs(incr) + 1)
    xlerror("incompatible with access indices", x);

  switch(type) {
  case CD_FLOTYPE:
  case CD_DOUBLE:
    break;
  default:
    xlbadtype(x);
  }

  *pdx = ((double *) gettvecdata(x)) + offset;
  *pincr = incr;
}

LOCAL VOID getblaszvec P3C(int, n, dcomplex **, pzx, int *, pincr)
{
  LVAL x;
  int size, type, offset, incr;

  x = xlgatvec();
  size = gettvecsize(x);
  type = gettvectype(x);
  offset = getfixnum(xlgafixnum());
  incr = getfixnum(xlgafixnum());

  if (offset < 0 || size < offset + (n - 1) * abs(incr) + 1)
    xlerror("incompatible with access indices", x);

  switch(type) {
  case CD_CXFLOTYPE:
  case CD_DCOMPLEX:
    break;
  default:
    xlbadtype(x);
  }

  *pzx = ((dcomplex *) gettvecdata(x)) + offset;
  *pincr = incr;
}

LOCAL VOID getblasdmat P4C(int, m, int, n, double **, pda, int *, plda)
{
  LVAL a, aa;
  int size, type, offset, lda;

  aa = xlgetarg();
  offset = getfixnum(xlgafixnum());
  lda = getfixnum(xlgafixnum());

  a = darrayp(aa) ? getdarraydata(aa) : aa;
  if (! tvecp(a)) xlbadtype(aa);
  size = gettvecsize(a);
  type = gettvectype(a);

  if (n < 0 || m < 0 || lda < 0 || lda < m || offset < 0 ||
      size < offset + lda * (n - 1) + m)
    xlerror("incompatible with access indices", aa);

  switch(type) {
  case CD_FLOTYPE:
  case CD_DOUBLE:
    break;
  default:
    xlbadtype(aa);
  }

  *pda = ((double *) gettvecdata(a)) + offset;
  *plda = lda;
}

LOCAL VOID getblaszmat P4C(int, m, int, n, dcomplex **, pda, int *, plda)
{
  LVAL a, aa;
  int size, type, offset, lda;

  aa = xlgetarg();
  offset = getfixnum(xlgafixnum());
  lda = getfixnum(xlgafixnum());

  a = darrayp(aa) ? getdarraydata(aa) : aa;
  if (! tvecp(a)) xlbadtype(aa);
  size = gettvecsize(a);
  type = gettvectype(a);

  if (n < 0 || m < 0 || lda < 0 || lda < m || offset < 0 ||
      size < offset + lda * (n - 1) + m)
    xlerror("incompatible with access indices", aa);

  switch(type) {
  case CD_CXFLOTYPE:
  case CD_DCOMPLEX:
    break;
  default:
    xlbadtype(aa);
  }

  *pda = ((dcomplex *) gettvecdata(a)) + offset;
  *plda = lda;
}

LOCAL VOID getdcomplex P1C(dcomplex *, z)
{
  LVAL a = xlgetarg();
  switch(ntype(a)) {
  case FIXNUM:
    z->r = (FLOTYPE) getfixnum(a);
    z->i = 0.0;
    break;
  case FLONUM:
    z->r = getflonum(a);
    z->i = 0.0;
    break;
  case COMPLEX:
    z->r = makefloat(getreal(a));
    z->i = makefloat(getimag(a));
    break;
  default:
    xlbadtype(a);
  }
}

LVAL xblasdasum(V)
{
  int n, incx;
  double *dx;

  n = getfixnum(xlgafixnum());
  getblasdvec(n, &dx, &incx);
  xllastarg();

  return cvflonum((FLOTYPE) blas_dasum(n, dx, incx));
}

LVAL xblasdaxpy(V)
{
  int n, incx, incy;
  double a, *dx, *dy;

  n = getfixnum(xlgafixnum());
  a = makefloat(xlgetarg());
  getblasdvec(n, &dx, &incx);
  getblasdvec(n, &dy, &incy);
  xllastarg();

  blas_daxpy(n, a, dx, incx, dy, incy);
  return NIL;
}

LVAL xblasdcopy(V)
{
  int n, incx, incy;
  double *dx, *dy;

  n = getfixnum(xlgafixnum());
  getblasdvec(n, &dx, &incx);
  getblasdvec(n, &dy, &incy);
  xllastarg();

  blas_dcopy(n, dx, incx, dy, incy);
  return NIL;
}

LVAL xblasddot(V)
{
  int n, incx, incy;
  double *dx, *dy;

  n = getfixnum(xlgafixnum());
  getblasdvec(n, &dx, &incx);
  getblasdvec(n, &dy, &incy);
  xllastarg();

  return cvflonum((FLOTYPE) blas_ddot(n, dx, incx, dy, incy));
}

LVAL xblasdnrm2(V)
{
  int n, incx;
  double *dx;

  n = getfixnum(xlgafixnum());
  getblasdvec(n, &dx, &incx);
  xllastarg();

  return cvflonum((FLOTYPE) blas_dnrm2(n, dx, incx));
}

LVAL xblasdrot(V)
{
  int n, incx, incy;
  double *dx, *dy, c, s;

  n = getfixnum(xlgafixnum());
  getblasdvec(n, &dx, &incx);
  getblasdvec(n, &dy, &incy);
  c = makefloat(xlgetarg());
  s = makefloat(xlgetarg());
  xllastarg();

  blas_drot(n, dx, incx, dy, incy, c, s);
  return NIL;
}

LVAL xblasdrotg(V)
{
  double a, b, c, s;

  a = makefloat(xlgetarg());
  b = makefloat(xlgetarg());
  xllastarg();

  blas_drotg(&a, &b, &c, &s);

  xlnumresults = 0;
  xlresults[xlnumresults++] = cvflonum((FLOTYPE) a);
  xlresults[xlnumresults++] = cvflonum((FLOTYPE) b);
  xlresults[xlnumresults++] = cvflonum((FLOTYPE) c);
  xlresults[xlnumresults++] = cvflonum((FLOTYPE) s);
  return xlresults[0];
}

LVAL xblasdscal(V)
{
  int n, incx;
  double a, *dx;

  n = getfixnum(xlgafixnum());
  a = makefloat(xlgetarg());
  getblasdvec(n, &dx, &incx);
  xllastarg();

  blas_dscal(n, a, dx, incx);
  return NIL;
}

LVAL xblasdswap(V)
{
  int n, incx, incy;
  double *dx, *dy;

  n = getfixnum(xlgafixnum());
  getblasdvec(n, &dx, &incx);
  getblasdvec(n, &dy, &incy);
  xllastarg();

  blas_dswap(n, dx, incx, dy, incy);
  return NIL;
}

LVAL xblasidamax(V)
{
  int n, incx;
  double *dx;

  n = getfixnum(xlgafixnum());
  getblasdvec(n, &dx, &incx);
  xllastarg();

  return cvfixnum((FIXTYPE) blas_idamax(n, dx, incx));
}

LVAL xblasdzasum(V)
{
  int n, incx;
  dcomplex *zx;

  n = getfixnum(xlgafixnum());
  getblaszvec(n, &zx, &incx);
  xllastarg();

  return cvflonum((FLOTYPE) blas_dzasum(n, zx, incx));
}

LVAL xblasdznrm2(V)
{
  int n, incx;
  dcomplex *zx;

  n = getfixnum(xlgafixnum());
  getblaszvec(n, &zx, &incx);
  xllastarg();

  return cvflonum((FLOTYPE) blas_dznrm2(n, zx, incx));
}

LVAL xblasizamax(V)
{
  int n, incx;
  dcomplex *zx;

  n = getfixnum(xlgafixnum());
  getblaszvec(n, &zx, &incx);
  xllastarg();

  return cvfixnum((FIXTYPE) blas_izamax(n, zx, incx));
}

LVAL xblaszaxpy(V)
{
  int n, incx, incy;
  dcomplex za, *zx, *zy;

  n = getfixnum(xlgafixnum());
  getdcomplex(&za);
  getblaszvec(n, &zx, &incx);
  getblaszvec(n, &zy, &incy);
  xllastarg();

  blas_zaxpy(n, &za, zx, incx, zy, incy);
  return NIL;
}

LVAL xblaszcopy(V)
{
  int n, incx, incy;
  dcomplex *zx, *zy;

  n = getfixnum(xlgafixnum());
  getblaszvec(n, &zx, &incx);
  getblaszvec(n, &zy, &incy);
  xllastarg();

  blas_zcopy(n, zx, incx, zy, incy);
  return NIL;
}

LVAL xlbaszdotc(V)
{
  int n, incx, incy;
  dcomplex *zx, *zy, val;

  n = getfixnum(xlgafixnum());
  getblaszvec(n, &zx, &incx);
  getblaszvec(n, &zy, &incy);
  xllastarg();

  blas_zdotc(&val, n, zx, incx, zy, incy);
  return newdcomplex(val.r, val.i);
}

LVAL xlbaszdotu(V)
{
  int n, incx, incy;
  dcomplex *zx, *zy, val;

  n = getfixnum(xlgafixnum());
  getblaszvec(n, &zx, &incx);
  getblaszvec(n, &zy, &incy);
  xllastarg();

  blas_zdotu(&val, n, zx, incx, zy, incy);
  return newdcomplex(val.r, val.i);
}

LVAL xlbaszdrot(V)
{
  int n, incx, incy;
  dcomplex *zx, *zy;
  double c, s;

  n = getfixnum(xlgafixnum());
  getblaszvec(n, &zx, &incx);
  getblaszvec(n, &zy, &incy);
  c = makefloat(xlgetarg());
  s = makefloat(xlgetarg());
  xllastarg();

  blas_zdrot(n, zx, incx, zy, incy, c, s);
  return NIL;
}

LVAL xlbaszdscal(V)
{
  int n, incx;
  dcomplex *zx;
  double da;

  n = getfixnum(xlgafixnum());
  da = makefloat(xlgetarg());
  getblaszvec(n, &zx, &incx);
  xllastarg();

  blas_zdscal(n, da, zx, incx);
  return NIL;
}

LVAL xlbaszrotg(V)
{
  dcomplex a, b, s;
  double c;

  getdcomplex(&a);
  getdcomplex(&b);
  xllastarg();

  blas_zrotg(&a, &b, &c, &s);

  xlnumresults = 0;
  xlresults[xlnumresults++] = newdcomplex(a.r, a.i);
  xlresults[xlnumresults++] = newdcomplex(b.r, b.i);
  xlresults[xlnumresults++] = cvflonum((FLOTYPE) c);
  xlresults[xlnumresults++] = newdcomplex(s.r, s.i);
  return xlresults[0];
}

LVAL xlbaszscal(V)
{
  int n, incx;
  dcomplex *zx, da;

  n = getfixnum(xlgafixnum());
  getdcomplex(&da);
  getblaszvec(n, &zx, &incx);
  xllastarg();

  blas_zscal(n, &da, zx, incx);
  return NIL;
}

LVAL xlbaszswap(V)
{
  int n, incx, incy;
  dcomplex *zx, *zy;

  n = getfixnum(xlgafixnum());
  getblaszvec(n, &zx, &incx);
  getblaszvec(n, &zy, &incy);
  xllastarg();

  blas_zswap(n, zx, incx, zy, incy);
  return NIL;
}

LVAL xlblasdgemv(V)
{
  char *trans;
  int m, n, lda, incx, incy;
  double alpha, *a, *x, beta, *y;

  trans = getstring(xlgastring());
  m = getfixnum(xlgafixnum());
  n = getfixnum(xlgafixnum());
  alpha = makefloat(xlgetarg());
  getblasdmat(m, n, &a, &lda);
  getblasdvec(*trans == 'n' || *trans == 'N' ? n : m, &x, &incx);
  beta = makefloat(xlgetarg());
  getblasdvec(*trans == 'n' || *trans == 'N' ? m : n, &y, &incy);
  xllastarg();
  
  blas_dgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy);
  return NIL;
}

LVAL xlblasdtrmv(V)
{
  char *uplo, *trans, *diag;
  int n, lda, incx;
  double *a, *x;

  uplo = getstring(xlgastring());
  trans = getstring(xlgastring());
  diag = getstring(xlgastring());
  n = getfixnum(xlgafixnum());
  getblasdmat(n, n, &a, &lda);
  getblasdvec(n, &x, &incx);
  xllastarg();

  blas_dtrmv(uplo, trans, diag, n, a, lda, x, incx);
  return NIL;
}

LVAL xlblasdger(V)
{
  int m, n, incx, incy, lda;
  double alpha, *x, *y, *a;

  m = getfixnum(xlgafixnum());
  n = getfixnum(xlgafixnum());
  alpha = makefloat(xlgetarg());
  getblasdvec(m, &x, &incx);
  getblasdvec(n, &y, &incy);
  getblasdmat(m, n, &a, &lda);
  xllastarg();

  blas_dger(m, n, alpha, x, incx, y, incy, a, lda);
  return NIL;
}

LVAL xlblasdtrsv(V)
{
  char *uplo, *trans, *diag;
  int n, lda, incx, i, ilda;
  double *a, *x;

  uplo = getstring(xlgastring());
  trans = getstring(xlgastring());
  diag = getstring(xlgastring());
  n = getfixnum(xlgafixnum());
  getblasdmat(n, n, &a, &lda);
  getblasdvec(n, &x, &incx);
  xllastarg();

  for (i = 0, ilda = 0; i < n; i++, ilda += lda)
    if (a[ilda + i] == 0.0)
      xlfail("matrix is (numerically) singular");

  blas_dtrsv(uplo, trans, diag, n, a, lda, x, incx);
  return NIL;
}

LVAL xlblaszgemv(V)
{
  char *trans;
  int m, n, lda, incx, incy;
  dcomplex alpha, *a, *x, beta, *y;

  trans = getstring(xlgastring());
  m = getfixnum(xlgafixnum());
  n = getfixnum(xlgafixnum());
  getdcomplex(&alpha);
  getblaszmat(m, n, &a, &lda);
  getblaszvec(*trans == 'n' || *trans == 'N' ? n : m, &x, &incx);
  getdcomplex(&beta);
  getblaszvec(*trans == 'n' || *trans == 'N' ? m : n, &y, &incy);
  xllastarg();
  
  blas_zgemv(trans, m, n, &alpha, a, lda, x, incx, &beta, y, incy);
  return NIL;
}

LVAL xlblasztrmv(V)
{
  char *uplo, *trans, *diag;
  int n, lda, incx;
  dcomplex *a, *x;

  uplo = getstring(xlgastring());
  trans = getstring(xlgastring());
  diag = getstring(xlgastring());
  n = getfixnum(xlgafixnum());
  getblaszmat(n, n, &a, &lda);
  getblaszvec(n, &x, &incx);
  xllastarg();

  blas_ztrmv(uplo, trans, diag, n, a, lda, x, incx);
  return NIL;
}

LVAL xlblaszgerc(V)
{
  int m, n, incx, incy, lda;
  dcomplex alpha, *x, *y, *a;

  m = getfixnum(xlgafixnum());
  n = getfixnum(xlgafixnum());
  getdcomplex(&alpha);
  getblaszvec(m, &x, &incx);
  getblaszvec(n, &y, &incy);
  getblaszmat(m, n, &a, &lda);
  xllastarg();

  blas_zgerc(m, n, &alpha, x, incx, y, incy, a, lda);
  return NIL;
}

LVAL xlblaszgeru(V)
{
  int m, n, incx, incy, lda;
  dcomplex alpha, *x, *y, *a;

  m = getfixnum(xlgafixnum());
  n = getfixnum(xlgafixnum());
  getdcomplex(&alpha);
  getblaszvec(m, &x, &incx);
  getblaszvec(n, &y, &incy);
  getblaszmat(m, n, &a, &lda);
  xllastarg();

  blas_zgeru(m, n, &alpha, x, incx, y, incy, a, lda);
  return NIL;
}

LVAL xlblasztrsv(V)
{
  char *uplo, *trans, *diag;
  int n, lda, incx, i, ilda;
  dcomplex *a, *x;

  uplo = getstring(xlgastring());
  trans = getstring(xlgastring());
  diag = getstring(xlgastring());
  n = getfixnum(xlgafixnum());
  getblaszmat(n, n, &a, &lda);
  getblaszvec(n, &x, &incx);
  xllastarg();

  for (i = 0, ilda = 0; i < n; i++, ilda += lda)
    if (a[ilda + i].r == 0.0 && a[ilda + i].i == 0.0)
      xlfail("matrix is (numerically) singular");

  blas_ztrsv(uplo, trans, diag, n, a, lda, x, incx);
  return NIL;
}

LVAL xlblasdgemm(V)
{
  char *transa, *transb;
  int m, n, k, lda, ldb, ldc;
  double alpha, *a, *b, beta, *c;

  transa = getstring(xlgastring());
  transb = getstring(xlgastring());
  m = getfixnum(xlgafixnum());
  n = getfixnum(xlgafixnum());
  k = getfixnum(xlgafixnum());
  alpha = makefloat(xlgetarg());
  if (*transa == 'n' || *transa == 'N')
    getblasdmat(m, k, &a, &lda);
  else
    getblasdmat(k, m, &a, &lda);
  if (*transb == 'n' || *transb == 'N')
    getblasdmat(k, n, &b, &ldb);
  else
    getblasdmat(n, k, &b, &ldb);
  beta = makefloat(xlgetarg());
  getblasdmat(m, n, &c, &ldc);
  xllastarg();
  
  blas_dgemm(transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc);
  return NIL;
}

LVAL xlblasdtrsm(V)
{
  char *side, *uplo, *transa, *diag;
  int m, n, lda, ldb, i, ilda;
  double alpha, *a, *b;

  side = getstring(xlgastring());
  uplo = getstring(xlgastring());
  transa = getstring(xlgastring());
  diag = getstring(xlgastring());
  m = getfixnum(xlgafixnum());
  n = getfixnum(xlgafixnum());
  alpha = makefloat(xlgetarg());
  if (*side == 'l'|| *side == 'L')
    getblasdmat(m, m, &a, &lda);
  else
    getblasdmat(n, n, &a, &lda);
  getblasdmat(m, n, &b, &ldb);
  xllastarg();
  
  for (i = 0, ilda = 0; i < n; i++, ilda += lda)
    if (a[ilda + i] == 0.0)
      xlfail("matrix is (numerically) singular");

  blas_dtrsm(side, uplo, transa, diag, m, n, alpha, a, lda, b, ldb);
  return NIL;
}

LVAL xlblaszgemm(V)
{
  char *transa, *transb;
  int m, n, k, lda, ldb, ldc;
  dcomplex alpha, *a, *b, beta, *c;

  transa = getstring(xlgastring());
  transb = getstring(xlgastring());
  m = getfixnum(xlgafixnum());
  n = getfixnum(xlgafixnum());
  k = getfixnum(xlgafixnum());
  getdcomplex(&alpha);
  if (*transa == 'n' || *transa == 'N')
    getblaszmat(m, k, &a, &lda);
  else
    getblaszmat(k, m, &a, &lda);
  if (*transb == 'n' || *transb == 'N')
    getblaszmat(k, n, &b, &ldb);
  else
    getblaszmat(n, k, &b, &ldb);
  getdcomplex(&beta);
  getblaszmat(m, n, &c, &ldc);
  xllastarg();
  
  blas_zgemm(transa, transb, m, n, k, &alpha, a, lda, b, ldb, &beta, c, ldc);
  return NIL;
}

LVAL xlblasztrsm(V)
{
  char *side, *uplo, *transa, *diag;
  int m, n, lda, ldb, i, ilda;
  dcomplex alpha, *a, *b;

  side = getstring(xlgastring());
  uplo = getstring(xlgastring());
  transa = getstring(xlgastring());
  diag = getstring(xlgastring());
  m = getfixnum(xlgafixnum());
  n = getfixnum(xlgafixnum());
  getdcomplex(&alpha);
  if (*side == 'l'|| *side == 'L')
    getblaszmat(m, m, &a, &lda);
  else
    getblaszmat(n, n, &a, &lda);
  getblaszmat(m, n, &b, &ldb);
  xllastarg();
  
  for (i = 0, ilda = 0; i < n; i++, ilda += lda)
    if (a[ilda + i].r == 0.0 && a[ilda + i].i == 0.0)
      xlfail("matrix is (numerically) singular");

  blas_ztrsm(side, uplo, transa, diag, m, n, &alpha, a, lda, b, ldb);
  return NIL;
}


syntax highlighted by Code2HTML, v. 0.9.1