/* mats1 - Elementary matrix operations */
/* 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"
/* forward declarations */
LOCAL LVAL facelist P1H(int);
LOCAL LVAL xsbindfaces P1H(int);
/*************************************************************************/
/** **/
/** Matrix Construction and Decomposition Functions **/
/** **/
/*************************************************************************/
/* Built in DIAGONAL function */
LVAL xsdiagonal(V)
{
LVAL arg, next, dim, val, data, result, result_data;
int n, m, i;
arg = xlgetarg();
xllastarg();
/* protect some pointers */
xlstkcheck(3);
xlsave(dim);
xlsave(val);
xlsave(result);
if (matrixp(arg)) {
/* extract diagonal from a matrix */
n = (numrows(arg) < numcols(arg)) ? numrows(arg) : numcols(arg);
m = numcols(arg);
result = mklist(n, NIL);
data = getdarraydata(arg);
for (i = 0, next = result; i < n; i++, next = cdr(next))
rplaca(next, gettvecelement(data, m * i + i));
}
else if (seqp(arg)) {
/* construct a diagonal matrix */
n = seqlen(arg);
dim = cvfixnum((FIXTYPE) n);
dim = list2(dim, dim);
val = cvfixnum((FIXTYPE) 0);
result = mkarray(dim, k_initelem, val, s_true);
result_data = getdarraydata(result);
for (i = 0; i < n; i++)
setelement(result_data, n * i + i, getnextelement(&arg, i));
}
else xlbadtype(arg);
/* restore the stack frame */
xlpopn(3);
return(result);
}
/* Return a list of rows or columns of a matrix read from the stack */
/***** this could be more efficient */
LOCAL LVAL facelist P1C(int, face)
{
LVAL a, result, next, vect, data, type;
int rows, cols, i, j;
a = xlgamatrix();
xllastarg();
rows = numrows(a);
cols = numcols(a);
/* protect some pointers */
xlsave1(result);
data = getdarraydata(a);
type = gettvecetype(data);
switch(face) {
case 0: /* rows */
result = mklist(rows, NIL);
for (next = result, i = 0; i < rows; i++, next = cdr(next)) {
vect = mktvec(cols, type);
rplaca(next, vect);
for (j = 0; j < cols; j++)
settvecelement(vect, j, gettvecelement(data, cols * i + j));
}
break;
case 1: /* columns */
result = mklist(cols, NIL);
for (next = result, j = 0; j < cols; j++, next = cdr(next)) {
vect = mktvec(rows, type);
rplaca(next, vect);
for (i = 0; i < rows; i++)
settvecelement(vect, i, gettvecelement(data, cols * i + j));
}
break;
default:
xlfail(" bad face selector");
}
/* restore the stack frame */
xlpop();
return(result);
}
/* Built in ROW-LIST and COLUMN-LIST functions */
LVAL xsrowlist(V) { return(facelist(0)); }
LVAL xscolumnlist(V) { return(facelist(1)); }
/* Bind list of sequences or matrices along rows or columns */
LOCAL LVAL xsbindfaces P1C(int, face)
{
LVAL next, data, dim, result, result_data;
int totalsize, rows=0, cols=0, c=0, r=0, n, i, j;
/* protect some pointers */
xlstkcheck(3);
xlsave(data);
xlsave(dim);
xlsave(result);
/* Check the first argument and establish size of the binding face */
next = peekarg(0);
switch (face) {
case 0:
if (matrixp(next)) cols = numcols(next);
else if (seqp(next)) cols = seqlen(next);
else if (! compoundp(next)) cols = 1;
else xlbadtype(next);
break;
case 1:
if (matrixp(next)) rows = numrows(next);
else if (seqp(next)) rows = seqlen(next);
else if (! compoundp(next)) rows = 1;
else xlbadtype(next);
break;
}
/* Pass through the arguments on the stack to determine the result size */
n = xlargc;
for (i = 0, totalsize = 0; i < n; i++) {
next = peekarg(i);
if (matrixp(next)) {
c = numcols(next);
r = numrows(next);
}
else if (seqp(next))
switch (face) {
case 0: c = seqlen(next); r = 1; break;
case 1: c = 1; r = seqlen(next); break;
}
else if (! compoundp(next)) {
c = 1;
r = 1;
}
else xlbadtype(next);
switch (face) {
case 0:
if (c != cols) xlfail("dimensions do not match");
else totalsize += r;
break;
case 1:
if (r != rows) xlfail("dimensions do not match");
else totalsize += c;
}
}
/* set up the result matrix */
dim = newvector(2);
switch (face) {
case 0:
setelement(dim, 0, cvfixnum((FIXTYPE) totalsize));
setelement(dim, 1, cvfixnum((FIXTYPE) cols));
break;
case 1:
setelement(dim, 0, cvfixnum((FIXTYPE) rows));
setelement(dim, 1, cvfixnum((FIXTYPE) totalsize));
break;
}
result = mkarray(dim, NIL, NIL, s_true);
result_data = getdarraydata(result);
/* compute the result */
for (r = 0, c = 0; moreargs();) {
next = xlgetarg();
if (matrixp(next)) {
rows = numrows(next);
cols = numcols(next);
data = getdarraydata(next);
}
else {
switch (face) {
case 0: rows = 1; break;
case 1: cols = 1; break;
}
data = (vectorp(next) || tvecp(next)) ?
next : coerce_to_tvec(next, s_true);
}
switch (face) {
case 0:
for (i = 0; i < rows; i++, r++)
for (j = 0; j < cols; j++)
setelement(result_data, cols * r + j,
gettvecelement(data, cols * i + j));
break;
case 1:
for (j = 0; j < cols; j++, c++)
for (i = 0; i < rows; i++)
setelement(result_data, totalsize * i + c,
gettvecelement(data, cols * i + j));
break;
}
}
/* restore the stack frame */
xlpopn(3);
return(result);
}
/* Built in BIND-ROWS and BIND-COLUMNS functions */
LVAL xsbindrows(V) { return(xsbindfaces(0)); }
LVAL xsbindcols(V) { return(xsbindfaces(1)); }
/* Built in TRANSPOSE-LIST function */
LVAL xstransposelist(V)
{
LVAL list, result, nextr, row, nextl;
int m, n;
list = xlgalist();
xllastarg();
xlstkcheck(2);
xlsave(result);
xlprotect(list);
list = copylist(list);
m = llength(list);
if (! consp(car(list))) xlerror("not a list", car(list));
n = llength(car(list));
result = mklist(n, NIL);
for (nextr = result; consp(nextr); nextr = cdr(nextr)) {
row = mklist(m, NIL);
rplaca(nextr, row);
for (nextl = list; consp(nextl); nextl = cdr(nextl)) {
if (!consp(car(nextl))) xlerror("not a list", car(nextl));
rplaca(row, car(car(nextl)));
row = cdr(row);
rplaca(nextl, cdr(car(nextl)));
}
}
xlpopn(2);
return(result);
}
syntax highlighted by Code2HTML, v. 0.9.1