/* 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