home *** CD-ROM | disk | FTP | other *** search
- /* 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);
- }
-