home *** CD-ROM | disk | FTP | other *** search
- /* basics - Basic functions for manipulating compound data */
- /* 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
- #include "xlsvar.h"
-
- #ifdef ANSI
- int ordered_nneg_seq(LVAL),allfixargs(void),
- translate_index(int,LVAL,LVAL,LVAL,LVAL,LVAL,LVAL);
- void permute_indices(LVAL,LVAL,LVAL,int),indices_from_rowmajor(LVAL,int,LVAL),
- setcons(LVAL,LVAL,LVAL);
- #else
- int ordered_nneg_seq(),allfixargs(),
- translate_index();
- void permute_indices(),indices_from_rowmajor(),setcons();
- #endif ANSI
-
- /**************************************************************************/
- /** **/
- /** Sequence Predicate **/
- /** **/
- /**************************************************************************/
-
- /* internal sequencep */
- /*sequencep(x) defined as a macro in xlsdef.h JKL
- LVAL x;
- {
- return(listp(x) || simplevectorp(x));
- }
- */
- /* Built in SEQUENCEP */
- LVAL xssequencep()
- {
- LVAL x;
-
- x = xlgetarg();
- xllastarg();
- return((sequencep(x)) ? s_true : NIL);
- }
-
- /**************************************************************************/
- /** **/
- /** Copying Functions **/
- /** **/
- /**************************************************************************/
-
- /* Built in COPY-VECTOR function */
- LVAL xscopyvector()
- {
- LVAL v;
-
- v = xlgavector();
- xllastarg();
-
- return(copyvector(v));
- }
-
- #define copyseq(x) ((vectorp(x)) ? copyvector(x) : copylist(x))
-
- /* internal array copying function */
- LVAL copyarray(array)
- LVAL array;
- {
- LVAL dim, data, result;
-
- if (simplevectorp(array)) result = copyvector(array);
- else if (displacedarrayp(array)) {
-
- /* protext some pointers */
- xlstkcheck(3);
- xlsave(result);
- xlsave(dim);
- xlsave(data);
-
- dim = copyseq(displacedarraydim(array));
- data = copyvector(arraydata(array));
- result = makedisplacedarray(dim, data);
-
- /* restore the stack frame */
- xlpopn(3);
- }
- else xlerror("not an array", array);
-
- return(result);
- }
-
- LVAL xscopyarray()
- {
- LVAL array;
-
- array = xsgetarray();
- xllastarg();
-
- return(copyarray(array));
- }
-
- /**************************************************************************/
- /** **/
- /** Compound Data Decomposition Functions **/
- /** **/
- /**************************************************************************/
-
- /* Built in SPLIT-LIST function */
- LVAL xssplitlist()
- {
- LVAL data;
- int n;
-
- data = xlgalist();
- n = getfixnum(xlgafixnum());
- xllastarg();
-
- return(splitlist(data, n));
- }
-
- /**************************************************************************/
- /** **/
- /** WHICH Function **/
- /** **/
- /**************************************************************************/
-
- /* Built in WHICH function. Generates indices in the data sequence of */
- /* a compound data item where argument elements are not nil. Should do */
- /* something more reasonable for non sequence compound data. */
- LVAL xswhich()
- {
- LVAL x, result, data, index, tail;
- int i, n;
-
- /* protect the result pointer */
- xlstkcheck(3);
- xlsave(result);
- xlsave(index);
- xlsave(data);
-
- x = xlgetarg();
- xllastarg();
-
- if (compoundp(x)) {
- data = compounddataseq(x);
- n = compounddatalen(x);
- for (i = 0; i < n; i++)
- if (getnextelement(&x, i) != NIL) {
- index = cvfixnum((FIXTYPE) i);
- if (result == NIL) {
- result = consa(index);
- tail = result;
- }
- else {
- rplacd(tail, consa(index));
- tail = cdr(tail);
- }
- }
- }
- else xlbadtype(x);
-
- /* restore the stack frame */
- xlpopn(3);
-
- return(result);
- }
-
- /**************************************************************************/
- /** **/
- /** List Construction Functions **/
- /** **/
- /**************************************************************************/
-
- /* internal version of ISEQ function */
- LVAL iseq(m, n)
- int m, n;
- {
- int length, i;
- LVAL result, next;
-
- /* protect the result pointer */
- xlsave1(result);
-
- length = abs(n - m) + 1;
- result = mklist(length, NIL);
-
- for (next = result, i = m; consp(next); next = cdr(next),
- (m <= n) ? i++ : i--)
- rplaca(next, cvfixnum((FIXTYPE) i));
-
- /* restore the stack frame */
- xlpop();
-
- return(result);
- }
-
- /* Built in ISEQ function. Generates a list of consecutive integers */
- LVAL xsiseq()
- {
- int n, m;
-
- m = getfixnum(xlgafixnum());
- if (moreargs()) n = getfixnum(xlgafixnum());
- else if (m > 0) {
- n = m - 1;
- m = 0;
- }
- else if (m < 0) {
- m = m + 1;
- n = 0;
- }
- else return(NIL);
- xllastarg();
-
- return(iseq(m, n));
- }
-
- /* Built in REPEAT function */
- LVAL xsrepeat()
- {
- LVAL data, result;
- int reps;
-
- if (xlargc != 2) xlfail("wrong number of arguments");
- else if (compoundp(xlargv[1])) {
- xlsave1(result);
- result = subr_map_elements(xsrepeat);
- result = coerce_to_list(result);
- result = nested_list_to_list(result, 2);
- xlpop();
- }
- else {
- data = xlgetarg();
- reps = getfixnum(checknonnegint(xlgetarg()));
- xllastarg();
- result = lrepeat(data, reps);
- }
- return(result);
- }
-
- /**************************************************************************/
- /** **/
- /** Subset Selection and Mutation Functions **/
- /** **/
- /**************************************************************************/
-
- /* is x an ordered list of nonnegative positive integers? */
- LOCAL ordered_nneg_seq(x)
- LVAL x;
- {
- LVAL elem;
- int n, i, length;
-
- length = (simplevectorp(x)) ? getsize(x) : 0;
-
- if (sequencep(x)) {
- for (n = 0, i = 0; consp(x) || i < length; i++) {
- elem = checknonnegint(getnextelement(&x, i));
- if (n > getfixnum(elem)) return(FALSE);
- else n = getfixnum(elem);
- }
- return(TRUE);
- }
- else return(FALSE);
- }
-
- /* select or set the subsequence corresponding to the specified indices */
- LVAL subsequence(x, indices, set_values, values)
- LVAL x, indices, values;
- int set_values;
- {
- int rlen, dlen, vlen, i, j;
- LVAL data, result, nextx, nextr, index, elem;
-
- /* Check the input data */
- if (! sequencep(x)) xlerror("not a sequence", x);
- if (set_values && ! sequencep(values))
- xlerror(" bad value sequence", values);
-
- /* protect some pointers */
- xlstkcheck(2)
- xlsave(result);
- xlsave(data);
-
- /* Find the data sizes */
- data = (ordered_nneg_seq(indices)) ? x : coerce_to_vector(x);
- dlen = (vectorp(data)) ? getsize(data) : llength(data);
- rlen = (vectorp(indices)) ? getsize(indices) : llength(indices);
- if (set_values) {
- vlen = (vectorp(values)) ? getsize(values) : llength(values);
- if (vlen != rlen && indices != s_true)
- xlfail("value and index sequences do not match");
- }
-
- /* set up the result/value sequence */
- if (set_values) result = values;
- else result = (listp(x)) ? mklist(rlen, NIL) : newvector(rlen);
-
- /* get or set the sequence elements */
- if (indices == s_true) /* do all indices */
- if (set_values)
- for (i = 0; i < dlen; i++)
- setnextelement(&x, i, getnextelement(&values, i));
- else
- result = x;
- else if (sequencep(indices)) {
- if (set_values) {
- for (nextx = x, nextr = result, i = 0, j = 0; i < rlen; i++) {
- index = getnextelement(&indices, i);
- if (dlen <= getfixnum(index)) xlerror("index out of range", index);
- elem = getnextelement(&result, i);
- if (listp(x)) {
- if (j > getfixnum(index)) {
- j = 0;
- nextx = x;
- }
- for (; j < getfixnum(index) && consp(nextx);
- j++, nextx = cdr(nextx))
- ;
- rplaca(nextx, elem);
- }
- else
- setelement(x, getfixnum(index), elem);
- }
- }
- else
- for (nextx = data, nextr = result, i = 0, j = 0; i < rlen; i++) {
- index = getnextelement(&indices, i);
- if (dlen <= getfixnum(index)) xlerror("index out of range", index);
- if (listp(data)) { /* indices must be ordered */
- for (; j < getfixnum(index) && consp(nextx); j++, nextx = cdr(nextx))
- ;
- elem = car(nextx);
- }
- else
- elem = getelement(data, getfixnum(index));
- setnextelement(&nextr, i, elem);
- }
- }
- else xlerror("bad indices", indices);
-
- /* restore the stack frame */
- xlpopn(2);
-
- return(result);
- }
-
- /* translate row major index in resulting submatrix to row major index in */
- /* the original matrix */
- old_rowmajor_index(index, indices, dim, olddim)
- int index;
- LVAL indices, dim, olddim;
- {
- int face, oldface, rank, i, oldindex;
-
- rank = getsize(dim);
-
- for (face = 1, oldface = 1, i = 0; i < rank; i++) {
- face *= getfixnum(getelement(dim, i));
- oldface *= getfixnum(getelement(olddim, i));
- }
-
- for (oldindex = 0, i = 0; i < rank; i++) {
- face /= getfixnum(getelement(dim, i));
- oldface /= getfixnum(getelement(olddim, i));
- oldindex +=
- oldface *
- getfixnum(getelement(getelement(indices, i), index / face));
- index = index % face;
- }
- return(oldindex);
- }
-
- /* extract or set subarray for the indices from a displaced array */
- LVAL subarray(a, indexlist, set_values, values)
- LVAL a, indexlist, values;
- int set_values;
- {
- LVAL indices, index, dim, vdim, data, result_data, olddim, result;
- int rank, n, i, j, k;
-
- /* protect some pointers */
- xlstkcheck(4);
- xlsave(indices);
- xlsave(dim);
- xlsave(olddim);
- xlsave(result);
-
- if (! displacedarrayp(a)) xlerror("not a displaced array", a);
- if (! listp(indexlist)) xlerror("bad index list", indices);
- if (llength(indexlist) != arrayrank(a)) xlfail("wrong number of indices");
-
- indices = coerce_to_vector(indexlist);
-
- olddim = displacedarraydim(a);
- olddim = coerce_to_vector(olddim);
-
- /* compute the result dimension vector and fix up the indices */
- rank = arrayrank(a);
- dim = newvector(rank);
- for (i = 0; i < rank; i++) {
- index = getelement(indices, i);
- n = getfixnum(getelement(olddim, i));
- if (index == s_true) {
- index = newvector(n);
- setelement(indices, i, index);
- for (j = 0; j < n; j++)
- setelement(index, j, cvfixnum((FIXTYPE) j));
- }
- else {
- index = coerce_to_vector(index);
- k = getsize(index);
- for (j = 0; j < k; j++)
- if (n <= getfixnum(checknonnegint(getelement(index, j))))
- xlerror("index out of bounds", getelement(index, j));
- setelement(indices, i, index);
- }
- setelement(dim, i, cvfixnum((FIXTYPE) getsize(index)));
- }
-
- /* set up the result or check the values*/
- if (set_values) {
- if (! compoundp(values))
- result = newarray(dim, s_ielement, values);
- else {
- if (! displacedarrayp(values) || rank != arrayrank(values))
- xlerror("bad values array", values);
- vdim = displacedarraydim(values);
- for (i = 0; i < rank; i++)
- if (getfixnum(getnextelement(&vdim, i))
- != getfixnum(getelement(dim, i)))
- xlerror("bad value array dimensions", values);
- result = values;
- }
- }
- else
- result = newarray(dim, NIL, NIL);
-
- /* compute the result or set the values */
- data = arraydata(a);
- result_data = arraydata(result);
- n = getsize(result_data);
- for (i = 0; i < n; i++) {
- k = old_rowmajor_index(i, indices, dim, olddim);
- if (0 > k || k >= getsize(data)) xlfail("index out of range");
- if (set_values)
- setelement(data, k, getelement(result_data, i));
- else
- setelement(result_data, i, getelement(data, k));
- }
-
- /* restore the stack frame */
- xlpopn(4);
-
- return(result);
- }
-
- /* are all arguments beyond the first fixnums? */
- LOCAL allfixargs()
- {
- int i;
-
- for (i = 1; i < xlargc; i++)
- if (! fixp(xlargv[i])) return(FALSE);
- return(TRUE);
- }
-
- /* Built in SELECT function */
- LVAL xsselect()
- {
- LVAL x, indices, result;
-
- if (allfixargs()) {
- if (displacedarrayp(peekarg(0))) result = xsaref();
- else result = xselt();
- }
- else if (sequencep(peekarg(0))) {
- x = xlgetarg();
- indices = xlgetarg();
- result = subsequence(x, indices, FALSE, NIL);
- }
- else if (displacedarrayp(peekarg(0))) {
- xlsave1(indices);
- x = xlgetarg();
- indices = makearglist(xlargc, xlargv);
- result = subarray(x, indices, FALSE, NIL);
- xlpop();
- }
- else xlbadtype(xlgetarg());
-
- return(result);
- }
-
- static void setcons(x, first, rest)
- LVAL x, first, rest;
- {
- x->n_type = CONS;
- rplaca(x, first);
- rplacd(x, rest);
- }
-
- /* Built in SET-SELECT (SETF method for SELECT) */
- /* This function uses node data to avoid creating garbage nodes. */
- /* This use of nodes *should* be safe, since there *should* be */
- /* no chance of a garbage collection during this operation. */
- LVAL xssetselect()
- {
- LVAL x, indices, values, next;
- struct node index_node, value_node;
- LVAL i_list = &index_node, v_list = &value_node;
-
- xlsave1(indices);
- xlsave1(values);
-
- x = xlgetarg();
- indices = makearglist(xlargc, xlargv);
- if (! consp(cdr(indices))) xltoofew();
- else {
- for (next = indices; consp(cdr(cdr(next))); next = cdr(next))
- ;
- values = car(cdr(next));
- rplacd(next, NIL);
- }
-
- if (sequencep(x)) {
- if (! consp(indices)) xlerror("bad indices", indices);
- indices = car(indices);
- if (fixp(indices)) {
- setcons(i_list, indices, NIL);
- setcons(v_list, values, NIL);
- subsequence(x, i_list, TRUE, v_list);
- }
- else
- subsequence(x, indices, TRUE, values);
- }
- else if (displacedarrayp(x))
- subarray(x, indices, TRUE, values);
- else xlbadtype(x);
-
- xlpopn(2);
-
- return(values);
- }
-
- /**************************************************************************/
- /** **/
- /** Array Permutation Function **/
- /** **/
- /**************************************************************************/
-
-
- /* permute x into y using perm; all should be vectors; If check is TRUE */
- /* the routine will check to make sure no indices are reused, but x */
- /* will be destroyed. */
- static void permute_indices(x, y, perm, check)
- LVAL x, y, perm;
- int check;
- {
- LVAL index;
- int rank, i, k;
-
- rank = getsize(x);
- for (i = 0; i < rank; i++) {
- index = getelement(perm, i);
- if (! fixp(index)) xlerror("bad permutation sequence", perm);
- k = getfixnum(index);
- if (k < 0 || k >= rank) xlerror("bad permutation sequence", perm);
- setelement(y, i, getelement(x, k));
- if (check)
- setelement(x, k, NIL); /* to insure dimensions are not re-used */
- }
- }
-
- /* compute indices in a from rowmajor index k, put in vector result */
- /* The indices are stored in cons cells, which are treated locally */
- /* fixnums. This SEEMS to be safe since it is entirely local, but */
- /* it may be dangerous...... */
- static void indices_from_rowmajor(a, k, result)
- LVAL a, result;
- int k;
- {
- LVAL next, dim;
- int face, i, rank;
-
- if (! displacedarrayp(a)) xlerror("not a displaced array", a);
- if (0 > k || k >= getsize(arraydata(a))) xlfail("index out of range");
-
- dim = displacedarraydim(a);
- rank = arrayrank(a);
-
- for (i = 0, face = 1, next = dim; i < rank; i++)
- face *= getfixnum(getnextelement(&next, i));
-
- for (i = 0, next = dim; i < rank; i++) {
- face /= getfixnum(getnextelement(&next, i));
- setfixnum(getelement(result, i),(FIXTYPE) k / face);
- k = k % face;
- }
- }
-
- /* Translate row major index in original array to row major index in new */
- /* array. Use indices vectors and ilist for temporary storage. */
- static translate_index(i, result, x, perm, indices, oldindices, ilist)
- LVAL result, x, perm, indices, oldindices, ilist;
- int i;
- {
- LVAL next;
- int rank, k;
-
- rank = arrayrank(x);
-
- indices_from_rowmajor(x, i, oldindices);
- permute_indices(oldindices, indices, perm, FALSE);
-
- for (next = ilist, k = 0; k < rank && consp(next); k++, next = cdr(next))
- rplaca(next, getelement(indices, k));
-
- return(rowmajorindex(result, ilist, FALSE));
- }
-
- /* Built in PERMUTE-ARRAY function */
- LVAL xspermutearray()
- {
- LVAL x, perm, result, data, result_data, dim, olddim, indices;
- LVAL oldindices, ilist;
- int rank, i, k, n;
-
- /* protect some pointers */
- xlstkcheck(7);
- xlsave(result);
- xlsave(dim);
- xlsave(olddim);
- xlsave(indices);
- xlsave(oldindices);
- xlsave(perm);
- xlsave(ilist);
-
- /* Get and ckeck the arguments */
- x = xsgetdisplacedarray();
- perm = xsgetsequence();
- perm = coerce_to_vector(perm);
- if (getsize(perm) != arrayrank(x)) xlerror("bad permutation sequence", perm);
- xllastarg();
-
- /* get old dimension vector */
- olddim = coerce_to_vector(displacedarraydim(x));
- rank = getsize(perm);
-
- /* construct new dimension vector */
- dim = newvector(rank);
- olddim = copyvector(olddim); /* since permute_indices will destroy this */
- permute_indices(olddim, dim, perm, TRUE);
-
- /* make result array and the index vectors and lists */
- result = newarray(dim, NIL, NIL);
- indices = newvector(rank);
- oldindices = newvector(rank);
- for (i = 0; i < rank; i++)
- setelement(oldindices, i, consa(NIL));
- ilist = mklist(rank, NIL);
-
- /* fill in the result */
- data = arraydata(x);
- result_data = arraydata(result);
- if (getsize(data) != getsize(result_data)) xlfail("bad data");
- n = getsize(data);
- for (i = 0; i < n; i++) {
- k = translate_index(i, result, x, perm, indices, oldindices, ilist);
- setelement(result_data, k, getelement(data, i));
- }
-
- /* restore stack */
- xlpopn(7);
-
- return(result);
- }
-
- #ifdef SAVERESTORE
- /* xrestore - restore a saved memory image */
- LVAL xsrestore()
- {
- extern jmp_buf top_level;
- unsigned char *name;
- LVAL hlist;
-
- /* get the file name, verbose flag and print flag */
- name = getstring(xlgetfname());
- xllastarg();
-
- /* dispose of all hardware objects */
- if (consp(getvalue(s_hardware_objects))) {
- xlsave1(hlist);
- hlist = copylist(getvalue(s_hardware_objects));
- for (; consp(hlist); hlist = cdr(hlist))
- send_message(car(cdr(cdr(car(hlist)))), sk_dispose);
- xlpop();
- }
-
- /* restore the saved memory image */
- if (!xlirestore(name))
- return (NIL);
-
- /* restore hardware items (this may be dangerous) */
- if (symbolp(s_listener) && objectp(getvalue(s_listener)))
- send_message(getvalue(s_listener), sk_allocate);
- if (consp(getvalue(s_hardware_objects))) {
- xlsave1(hlist);
- hlist = copylist(getvalue(s_hardware_objects));
- setvalue(s_hardware_objects, NIL);
- for (; consp(hlist); hlist = cdr(hlist))
- send_message(car(cdr(cdr(car(hlist)))), sk_allocate);
- xlpop();
- }
-
- /* return directly to the top level */
- stdputstr("[ returning to the top level ]\n");
- longjmp(top_level,1);
- }
- #endif
-