/* mats2 - Linear algebra routines and Multreg Style Sweep             */
/* Operator. Tolerance should be determined from a keyword variable;   */
/* default tolerance from a global variable.                           */ 
/* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney                  */
/* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz    */
/* You may give out copies of this software; for conditions see the    */
/* file COPYING included with this distribution.                       */
 
#include "linalg.h"

LOCAL VOID mkswpmat P7C(int, n,
			int, p,
			double *, x,
			double *, y,
			double *, w,
			double *, sm,
			double *, xmean)
{
  int i, j, k;
  double val, sum_w, xmeani, xmeanj, ymean;
  double *pwk, *pxki, *pxkj, *pyk;
  
  /* find the sum of the weights and the mean of y */
  for (sum_w = 0.0, val = 0.0, k = 0, pyk = y, pwk = w;
       k < n;
       k++, pyk++, pwk++) {
    sum_w += *pwk;
    val += *pyk * *pwk;
  }
  if (sum_w <= 0)
    xlfail("non positive sum of weights");
  ymean = val / sum_w;
  
  /* find the column means */
  for (i = 0; i < p; i++) {
    for (val = 0.0, k = 0, pxki = x + i, pwk = w;
	 k < n;
	 k++, pxki += p, pwk++)
      val += *pxki * *pwk;
    xmean[i] = val / sum_w;
  }

  /* put 1 / sum_w in topleft, means on left, minus means on top */
  sm[0] = 1.0 / sum_w;
  for (i = 0; i < p; i++) {
    sm[i + 1] = -xmean[i];
    sm[(i + 1) * (p + 2)] = xmean[i];
  }
  sm[p + 1] = -ymean;
  sm[(p + 1) * (p + 2)] = ymean;
  
  /* put sums of adjusted cross products in body */
  for (i = 0; i < p; i ++) {
    xmeani = xmean[i];
    for (j = i; j < p; j++) {
      xmeanj = xmean[j];
      for (val = 0.0, k = 0, pxki = x + i, pxkj = x + j, pwk = w;
	   k < n;
	   k++, pxki += p, pxkj += p, pwk++)
	val += (*pxki - xmeani) * (*pxkj - xmeanj) * *pwk;
      sm[(i + 1) * (p + 2) + (j + 1)] = val;
      sm[(j + 1) * (p + 2) + (i + 1)] = val;
    }
    for (val = 0.0, k = 0, pxki = x + i, pyk = y, pwk = w;
	 k < n;
	 k++, pxki += p, pyk++, pwk++)
      val += (*pxki - xmeani) * (*pyk - ymean) * *pwk;
    sm[(i + 1) * (p + 2) + (p + 1)] = val;
    sm[(p + 1) * (p + 2) + (i + 1)] = val;
  }
  for (val = 0.0, k = 0, pyk = y, pwk = w; k < n; k++, pyk++, pwk++)
    val += (*pyk - ymean) * (*pyk - ymean) * *pwk;
  sm[(p + 1) * (p + 2) + (p + 1)] = val;
}

LOCAL int sweepinplace P5C(int, rows,
			   int, cols,
			   double *, a,
			   int, k,
			   double, tol)
{
  int i, j;
  double pivot, *paij, *pak0, *pakk, *paik, *pakj, meps;
  
  if (k < 0 || k >= rows || k >= rows)
    xlfail("index out of range");
  
  meps = macheps();
  if (tol < meps) tol = meps;
  
  pak0 = a + cols * k;
  pakk = pak0 + k;
  pivot = *pakk;
  
  if (pivot > tol || pivot < -tol) {
    for (i = 0, paij = a, paik = a + k; i < rows; i++, paik += cols)
      for (j = 0, pakj = pak0; j < cols; j++, paij++, pakj++)
	if (i != k && j != k) {
	  *paij -= ((*paik * *pakj) / pivot);
	}
    for (i = 0, paik = a + k; i < rows; i++, paik += cols)
      if (i != k)
	*paik /= pivot;
    for (j = 0, pakj = pak0; j < cols; j++, pakj++)
      if (j != k)
	*pakj /= -pivot;
    *pakk = 1.0 / pivot;
    return TRUE;
  }
  else
    return FALSE;
}

LOCAL VOID getsweepdata P2C(int, n, double **, pdx)
{
  LVAL arg, x;
  int size, type;

  arg = xlgetarg();
  x = darrayp(arg) ? getdarraydata(arg) : arg;
  if (! tvecp(x)) xlbadtype(arg);
  size = gettvecsize(x);
  type = gettvectype(x);

  if (size < n)
    xlerror("incompatible size", arg);

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

  *pdx = ((double *) gettvecdata(x));
}

/* Built in BASE-MAKE-SWEEP-MATRIX function */
LVAL xsbasemkswpmat(V)
{
  int n, p;
  double *x, *y, *w, *sm, *xmean;
  
  n = getfixnum(xlgafixnum());
  p = getfixnum(xlgafixnum());
  getsweepdata(n * p, &x);
  getsweepdata(n, &y);
  getsweepdata(n, &w);
  getsweepdata((p + 2) * (p + 2), &sm);
  getsweepdata(p, &xmean);
  xllastarg();

  mkswpmat(n, p, x, y, w, sm, xmean);
  return NIL;
}

LVAL xssweepinplace(V)
{
  int rows, cols, k;
  double *a, tol;

  rows = getfixnum(xlgafixnum());
  cols = getfixnum(xlgafixnum());
  getsweepdata(rows * cols, &a);
  k = getfixnum(xlgafixnum());
  tol = makefloat(xlgetarg());

  return sweepinplace(rows, cols, a, k, tol) ? s_true : NIL;
}


syntax highlighted by Code2HTML, v. 0.9.1