home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
fish
/
applications
/
xlispstat
/
src
/
src2.lzh
/
XLisp-Stat
/
matrices2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-02
|
7KB
|
252 lines
/* matrices2 - 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 "xlisp.h"
#include "osdef.h"
#ifdef ANSI
#include "xlproto.h"
#include "xlsproto.h"
#else
#include "xlfun.h"
#include "xlsfun.h"
#endif ANSI
/* Built in MAKE-SWEEP-MATRIX function */
LVAL xsmakesweepmatrix()
{
LVAL x, x_data, y, w, x_mean, y_mean, pp, dim, result, result_data;
int n, p, i, j, k;
double val, dxi, dyi, dv, dw, sum_w, dxik, dxjk, dyj,
dx_meani, dx_meanj, dy_mean;
/* protect some pointers */
xlstkcheck(8);
xlsave(x);
xlsave(y);
xlsave(w);
xlsave(x_mean);
xlsave(pp);
xlsave(y_mean);
xlsave(dim);
xlsave(result);
x = xsgetmatrix();
y = xlgetarg();
w = (moreargs()) ? xlgetarg() : NIL;
xllastarg();
y = coerce_to_vector(y);
if (numrows(x) != getsize(y)) xlfail("dimensions do not match");
if (w != NIL) {
w = coerce_to_vector(w);
if (numrows(x) != getsize(w)) xlfail("dimensions do not match");
}
x_data = arraydata(x);
/* find dimensions */
n = getsize(y);
p = numcols(x);
/* make the result matrix and the mean vector */
pp = cvfixnum((FIXTYPE) p + 2);
dim = list2(pp, pp);
result = newarray(dim, NIL, NIL);
result_data = arraydata(result);
x_mean = newvector(p);
/* find the mean of y */
for (val = 0.0, sum_w = 0.0, i = 0; i < n; i++) {
dyi = makedouble(getelement(y, i));
if (w != NIL) {
dw = makedouble(getelement(w, i));
sum_w = f_plus(sum_w, dw);
dyi = f_times(dyi, dw);
}
val = f_plus(val, dyi);
}
if (w == NIL) sum_w = n;
if (sum_w <= 0) xlfail("non positive sum of weights");
y_mean = cvflonum((FLOTYPE) val / sum_w);
/* find the column means */
for (j = 0; j < p; j++) {
for (val = 0.0, i = 0; i < n; i++) {
dxi = makedouble(getelement(x_data, p * i + j));
if (w != NIL) {
dw = makedouble(getelement(w, i));
dxi = f_times(dxi, dw);
}
val = f_plus(val, dxi);
}
setelement(x_mean, j, cvflonum((FLOTYPE) val / sum_w));
}
/* put 1/sum_w in topleft, means on left, minus means on top */
setelement(result_data, 0, cvflonum((FLOTYPE) 1.0 / sum_w));
for (i = 0; i < p; i++) {
setelement(result_data, i + 1,
cvflonum((FLOTYPE) - getflonum(getelement(x_mean, i))));
setelement(result_data, (i + 1) * (p + 2), getelement(x_mean, i));
}
setelement(result_data, p + 1, cvflonum((FLOTYPE) - getflonum(y_mean)));
setelement(result_data, (p + 1) * (p + 2), y_mean);
/* put sums of adjusted cross products in body */
for (i = 0; i < p; i ++) {
for (j = i; j < p; j++) {
for (val = 0.0, k = 0; k < n; k++) {
dxik = makedouble(getelement(x_data, p * k + i));
dxjk = makedouble(getelement(x_data, p * k + j));
dx_meani = getflonum(getelement(x_mean, i));
dx_meanj = getflonum(getelement(x_mean, j));
dv = f_times(f_minus(dxik, dx_meani), f_minus(dxjk, dx_meanj));
if (w != NIL) {
dw = makedouble(getelement(w, k));
dv = f_times(dv, dw);
}
val = f_plus(val, dv);
}
setelement(result_data, (i + 1) * (p + 2) + (j + 1),
cvflonum((FLOTYPE) val));
setelement(result_data, (j + 1) * (p + 2) + (i + 1),
cvflonum((FLOTYPE) val));
}
for (val = 0.0, j = 0; j < n; j++) {
dxik = makedouble(getelement(x_data, p * j + i));
dyj = makedouble(getelement(y, j));
dx_meani = getflonum(getelement(x_mean, i));
dy_mean = getflonum(y_mean);
dv = f_times(f_minus(dxik, dx_meani), f_minus(dyj, dy_mean));
if (w != NIL) {
dw = makedouble(getelement(w, j));
dv = f_times(dv, dw);
}
val = f_plus(val, dv);
}
setelement(result_data, (i + 1) * (p + 2) + (p + 1),
cvflonum((FLOTYPE) val));
setelement(result_data, (p + 1) * (p + 2) + (i + 1),
cvflonum((FLOTYPE) val));
}
for (val = 0.0, j = 0; j < n; j++) {
dyj = makedouble(getelement(y, j));
dy_mean = getflonum(y_mean);
dv = f_times(f_minus(dyj, dy_mean), f_minus(dyj, dy_mean));
if (w != NIL) {
dw = makedouble(getelement(w, j));
dv = f_times(dv, dw);
}
val = f_plus(val, dv);
}
setelement(result_data, (p + 1) * (p + 2) + (p + 1),
cvflonum((FLOTYPE) val));
/* restore the stack frame */
xlpopn(8);
return(result);
}
/* Internal sweeping algorithm */
int sweep_in_place(a, k, tol)
LVAL a;
int k;
double tol;
{
LVAL data;
int rows, cols, i, j;
double pivot, aij, aik, akj, akk, meps;
if (! matrixp(a)) xlerror("not a matrix", a);
if ((k < 0) || (k >= numrows(a)) || (k >= numcols(a)))
xlfail("index out of range");
meps = macheps();
if (tol < meps) tol = meps;
rows = numrows(a);
cols = numcols(a);
data = arraydata(a);
pivot = makedouble(getelement(data, cols * k + k));
if ((pivot > tol) || (pivot < -tol)) {
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
if ((i != k) && (j != k)) {
aij = makedouble(getelement(data, cols * i + j));
aik = makedouble(getelement(data, cols * i + k));
akj = makedouble(getelement(data, cols * k + j));
aij = aij - f_divide(f_times(aik, akj), pivot);
setelement(data, cols * i + j, cvflonum((FLOTYPE) aij));
}
for (i = 0; i < rows; i++) {
aik = makedouble(getelement(data, cols * i + k));
if (i != k) {
aik = f_divide(aik, pivot);
setelement(data, cols * i + k, cvflonum((FLOTYPE) aik));
}
}
for (j = 0; j < cols; j++) {
akj = makedouble(getelement(data, cols * k + j));
if (j != k) {
akj = -f_divide(akj, pivot);
setelement(data, cols * k + j, cvflonum((FLOTYPE) akj));
}
}
akk = f_divide(1.0, pivot);
setelement(data, cols * k + k, cvflonum((FLOTYPE) akk));
return (1);
}
else
return (0);
}
/* Built in SWEEP-OPERATOR function. Should allow in place sweep as option */
LVAL xssweepoperator()
{
LVAL a, columns, sweptcolumns, tolerances, col;
LVAL result;
int c;
double tol = .000001;
/* create a new stack frame */
xlstkcheck(3);
xlsave(sweptcolumns);
xlsave(tolerances);
xlsave(result);
a = xsgetmatrix();
columns = xsgetsequence();
columns = coerce_to_list(columns);
tolerances = (moreargs()) ? xsgetsequence() : NIL;
tolerances = coerce_to_list(tolerances);
xllastarg();
result = copyarray(a);
sweptcolumns = NIL;
for (; consp(columns);
columns = cdr(columns),
tolerances = (consp(tolerances)) ? cdr(tolerances) : NIL) {
col = car(columns);
if (! fixp(col)) xlerror("not an integer", col);
c = getfixnum(col);
tol = (consp(tolerances)) ? makedouble(car(tolerances)) : tol;
if (sweep_in_place(result, c, tol)) sweptcolumns = cons(col, sweptcolumns);
}
result = list2(result, sweptcolumns);
/* restore the previous stack frame */
xlpopn(3);
return(result);
}