eigenmath/lisp/lisp.c

2847 lines
41 KiB
C

/* 9-20-00 add "if" function */
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define MEM 3000000 /* (3,000,000 nodes) * (12 bytes/node) = 36 megabytes */
#define TOS 100000
#define BUF 1000
#define STRBUF 10000
#define CONS 0
#define NUM 1
#define STR 2
#define SYM 3
#define ZAND 4
#define ZAPPEND 5
#define ZARGLIST 6
#define ZATOM 7
#define ZCAR 8
#define ZCDR 9
#define ZCOMPONENT 10
#define ZCOND 11
#define ZCONS 12
#define ZCONTRACT 13
#define ZDEFINE 14
#define ZDERIVATIVE 15
#define ZDOT 16
#define ZEQUAL 17
#define ZEVAL 18
#define ZEXIT 19
#define ZGC 20
#define ZGOTO 21
#define ZGREATERP 22
#define ZIF 23
#define ZINTEGERP 24
#define ZINTEGRAL 25
#define ZLENGTH 26
#define ZLESSP 27
#define ZLIST 28
#define ZLOAD 29
#define ZNOT 30
#define ZNULL 31
#define ZNUMBERP 32
#define ZOR 33
#define ZPOWER 34
#define ZPRINT 35
#define ZPRINTCARS 36
#define ZPRODUCT 37
#define ZPROG 38
#define ZQUOTE 39
#define ZRETURN 40
#define ZSETQ 41
#define ZSUM 42
#define ZSUBST 43
#define ZTENSOR 44
#define ZTRANSPOSE 45
#define iscons(p) ((p)->k == CONS)
#define isnum(p) ((p)->k == NUM)
#define isstr(p) ((p)->k == STR)
#define issym(p) ((p)->k >= SYM)
#define car(p) (iscons(p) ? (p)->u.cons.car : nil)
#define cdr(p) (iscons(p) ? (p)->u.cons.cdr : nil)
#define caar(p) car(car(p))
#define cadr(p) car(cdr(p))
#define cdar(p) cdr(car(p))
#define cddr(p) cdr(cdr(p))
#define caddr(p) car(cdr(cdr(p)))
#define cadar(p) car(cdr(car(p)))
#define cddar(p) cdr(cdr(car(p)))
#define cdddr(p) cdr(cdr(cdr(p)))
#define caaddr(p) car(car(cdr(cdr(p))))
#define cdaddr(p) cdr(car(cdr(cdr(p))))
#define cadaddr(p) car(cdr(car(cdr(cdr(p)))))
#define cddaddr(p) cdr(cdr(car(cdr(cdr(p)))))
#define cdddaddr(p) cdr(cdr(cdr(car(cdr(cdr(p))))))
#define caddaddr(p) car(cdr(cdr(car(cdr(cdr(p))))))
#define arg1(p) car(cdr(p))
#define arg2(p) car(cdr(cdr(p)))
#define arg3(p) car(cdr(cdr(cdr(p))))
#define A u.num.a
#define B u.num.b
typedef struct node {
char k, tag, gamma, pad;
union {
struct { struct node *car; struct node *cdr; } cons;
struct { struct node *binding; char *printname; } sym;
struct { int a, b; } num;
char *str;
} u;
} U;
U _nil, mem[MEM];
typedef struct {
U *p;
int a, b;
} ST;
ST stack[TOS];
U *_arg, *_arg1, *_arg2, *_arg3, *_arg4, *_arg5, *_arg6, *_arglist;
U *_cos;
U *derivative;
U *e;
U *eof;
U *freelist;
U *gamma[17];
U *indexlist;
U *_integral;
U *nil;
U *nothing;
U *_power;
U *_product;
U *quote;
U *read1();
U *read_expr();
U *scann();
U *_sin;
U *sum;
U *symtbl[64];
U *t;
U *_tensor;
U *_integral_list;
U *_meta_a;
U *_meta_b;
U *_meta_f;
U *_meta_n;
U *_meta_x;
FILE *infile;
int tos;
int tensor_op;
int index_i;
int index_j;
char buf[BUF];
int k;
char strbuf[STRBUF + 1];
/* gamma product matrix */
int gp[17][17] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,1,-6,-7,-8,-3,-4,-5,13,14,15,-16,9,10,11,-12,
0,0,6,-1,-11,10,-2,-15,14,12,-5,4,-9,16,-8,7,-13,
0,0,7,11,-1,-9,15,-2,-13,5,12,-3,-10,8,16,-6,-14,
0,0,8,-10,9,-1,-14,13,-2,-4,3,12,-11,-7,6,16,-15,
0,0,3,2,15,-14,1,11,-10,16,-8,7,13,12,-5,4,9,
0,0,4,-15,2,13,-11,1,9,8,16,-6,14,5,12,-3,10,
0,0,5,14,-13,2,10,-9,1,-7,6,16,15,-4,3,12,11,
0,0,13,12,-5,4,16,-8,7,-1,-11,10,-3,-2,-15,14,-6,
0,0,14,5,12,-3,8,16,-6,11,-1,-9,-4,15,-2,-13,-7,
0,0,15,-4,3,12,-7,6,16,-10,9,-1,-5,-14,13,-2,-8,
0,0,16,-9,-10,-11,-13,-14,-15,-3,-4,-5,1,-6,-7,-8,2,
0,0,9,-16,8,-7,-12,5,-4,-2,-15,14,6,-1,-11,10,3,
0,0,10,-8,-16,6,-5,-12,3,15,-2,-13,7,11,-1,-9,4,
0,0,11,7,-6,-16,4,-3,-12,-14,13,-2,8,-10,9,-1,5,
0,0,12,13,14,15,9,10,11,-6,-7,-8,-2,-3,-4,-5,-1,
};
U *ccons();
U *num();
U *str();
U *sym();
U *zand();
U *zappend();
U *zatom();
U *zcar();
U *zcdr();
U *zcomponent();
U *zcond();
U *zcons();
U *zcontract();
U *zdefine();
U *zderivative();
U *zdot();
U *zequal();
U *zeval();
U *zexit();
U *zfixp();
U *zgc();
U *zgoto();
U *zgreaterp();
U *zif();
U *zintegral();
U *zlessp();
U *zlist();
U *zload();
U *zlength();
U *znot();
U *znull();
U *znumberp();
U *zor();
U *zpower();
U *zprint();
U *zprintcars();
U *zproduct();
U *zprog();
U *zquote();
U *zreturn();
U *zsetq();
U *zsum();
U *zsubst();
U *ztensor();
U *ztranspose();
U *alloc();
U *append();
U *cons();
U *contract();
U *d();
U *dcos();
U *dd();
U *dfunction();
U *dpower();
U *dproduct();
U *dsin();
U *dsum();
U *eval();
U *eval_user_function();
U *eval_args();
U *expand(int, int);
U *inner_expand();
U *inner_product(U *, U *);
U *product(int, int);
U *ksum();
U *number();
U *pop();
U *power();
void push_factor(U *);
void push_term(U *);
U *subst();
U *symbol();
U *transpose();
void print(U *);
void print1(U *);
void untag(U *);
void add(int *, int *, int, int);
void mult(int *, int *, int, int);
void push(U *);
void pushvars(U *);
void popvars(U *);
void init(void);
void load(char *);
void stop(char *);
char *sdup(char *);
main(argc, argv)
int argc;
char *argv[];
{
int i;
U *p;
infile = stdin;
init();
load("startup.lisp");
for (i = 1; i < argc; i++)
load(argv[i]);
for (;;) {
printf("> ");
p = read1();
push(p); /* save from gc */
p = eval(p);
pop();
if (p != nothing)
print(p);
if (tos) {
tos = 0;
printf("stack error\n");
}
}
}
U *
eval(p)
U *p;
{
if (p->k == SYM)
return p->u.sym.binding; /* symbol's binding */
if (p->k != CONS)
return p; /* numbers, strings, etc. */
switch (p->u.cons.car->k) {
case SYM: return eval_user_function(p);
case ZAND: return zand(p);
case ZAPPEND: return zappend(p);
case ZATOM: return zatom(p);
case ZCAR: return zcar(p);
case ZCDR: return zcdr(p);
case ZCOMPONENT: return zcomponent(p);
case ZCOND: return zcond(p);
case ZCONS: return zcons(p);
case ZCONTRACT: return zcontract(p);
case ZDEFINE: return zdefine(p);
case ZDERIVATIVE: return zderivative(p);
case ZDOT: return zdot(p);
case ZEQUAL: return zequal(p);
case ZEVAL: return zeval(p);
case ZEXIT: return zexit(p);
case ZGC: return zgc(p);
case ZGOTO: return zgoto(p);
case ZGREATERP: return zgreaterp(p);
case ZIF: return zif(p);
case ZINTEGERP: return zfixp(p);
case ZINTEGRAL: return zintegral(p);
case ZLENGTH: return zlength(p);
case ZLESSP: return zlessp(p);
case ZLIST: return zlist(p);
case ZLOAD: return zload(p);
case ZNOT: return znot(p);
case ZNULL: return znull(p);
case ZNUMBERP: return znumberp(p);
case ZOR: return zor(p);
case ZPOWER: return zpower(p);
case ZPRINT: return zprint(p);
case ZPRINTCARS: return zprintcars(p);
case ZPRODUCT: return zproduct(p);
case ZPROG: return zprog(p);
case ZQUOTE: return zquote(p);
case ZRETURN: return zreturn(p);
case ZSETQ: return zsetq(p);
case ZSUM: return zsum(p);
case ZSUBST: return zsubst(p);
case ZTENSOR: return ztensor(p);
case ZTRANSPOSE: return ztranspose(p);
default: return p; /* a list with ? head */
}
}
U *
eval_user_function(p)
U *p;
{
U *q;
q = eval_args(cdr(p));
push(_arg->u.sym.binding);
push(_arg1->u.sym.binding);
push(_arg2->u.sym.binding);
push(_arg3->u.sym.binding);
push(_arg4->u.sym.binding);
push(_arg5->u.sym.binding);
push(_arg6->u.sym.binding);
push(_arglist->u.sym.binding);
_arglist->u.sym.binding = q;
_arg->u.sym.binding = car(q);
_arg1->u.sym.binding = car(q);
q = cdr(q);
_arg2->u.sym.binding = car(q);
q = cdr(q);
_arg3->u.sym.binding = car(q);
q = cdr(q);
_arg4->u.sym.binding = car(q);
q = cdr(q);
_arg5->u.sym.binding = car(q);
q = cdr(q);
_arg6->u.sym.binding = car(q);
p = car(p);
if (p->u.sym.binding->k == CONS)
/* normal function */
p = eval(p->u.sym.binding);
else
/* undefined function */
p = cons(p->u.sym.binding, _arglist->u.sym.binding);
_arglist->u.sym.binding = pop();
_arg6->u.sym.binding = pop();
_arg5->u.sym.binding = pop();
_arg4->u.sym.binding = pop();
_arg3->u.sym.binding = pop();
_arg2->u.sym.binding = pop();
_arg1->u.sym.binding = pop();
_arg->u.sym.binding = pop();
return p;
}
U *
eval_args(p)
U *p;
{
int i, n = 0;
while (iscons(p)) {
push(eval(car(p)));
n++;
p = cdr(p);
}
p = nil;
for (i = 0; i < n; i++)
p = cons(stack[tos - i - 1].p, p);
tos -= n;
return p;
}
U *
zand(p)
U *p;
{
p = cdr(p);
while (iscons(p)) {
if (eval(car(p)) == nil)
return nil;
p = cdr(p);
}
return t;
}
U *
zappend(p)
U *p;
{
U *p1, *p2;
p1 = eval(arg1(p));
push(p1);
p2 = eval(arg2(p));
pop();
p = append(p1, p2);
return p;
}
U *
append(p1, p2)
U *p1, *p2;
{
int i, n = 0;
while (iscons(p1)) {
push(car(p1));
n++;
p1 = cdr(p1);
}
for (i = 0; i < n; i++)
p2 = cons(stack[tos - i - 1].p, p2);
tos -= n;
return p2;
}
U *
zatom(p)
U *p;
{
p = eval(arg1(p));
if (iscons(p))
return nil;
else
return t;
}
U *
zcar(p)
U *p;
{
return car(eval(arg1(p)));
}
U *
zcdr(p)
U *p;
{
return cdr(eval(arg1(p)));
}
U *
zcomponent(p)
U *p;
{
U *p1, *p2;
p1 = eval(arg1(p));
push(p1);
p2 = eval_args(cddr(p));
push(p2);
indexlist = p2;
tensor_op = 1;
p = eval(p1);
tensor_op = 0;
pop();
pop();
return p;
}
U *
zcond(p)
U *p;
{
p = cdr(p);
while (iscons(p)) {
if (eval(caar(p)) != nil)
return eval(cadar(p));
p = cdr(p);
}
return nil;
}
U *
zcons(p)
U *p;
{
U *p1, *p2;
p1 = eval(arg1(p));
push(p1);
p2 = eval(arg2(p));
pop();
return cons(p1, p2);
}
U *
cons(p1, p2)
U *p1, *p2;
{
U *p;
if (freelist == nil) {
push(p1);
push(p2);
p = alloc();
pop();
pop();
} else {
p = freelist;
freelist = freelist->u.cons.cdr;
}
p->k = CONS;
p->u.cons.car = p1;
p->u.cons.cdr = p2;
return p;
}
U *
zcontract(p)
U *p;
{
int i, j;
i = tindex(eval(arg1(p)));
j = tindex(eval(arg2(p)));
p = eval(arg3(p));
if (i == 0 || j == 0 || i == j)
return p;
index_i = i;
index_j = j;
tensor_op = 2;
push(p);
p = eval(p);
pop();
tensor_op = 0;
return p;
}
tindex(p)
U *p;
{
if (isnum(p) && p->A > 0 && p->B == 1)
return p->A;
else
return 0;
}
/* just like setq except arg2 is not evaluated */
U *
zdefine(p)
U *p;
{
U *p1, *p2;
p1 = arg1(p);
p2 = arg2(p);
if (issym(p1))
p1->u.sym.binding = p2;
return nothing;
}
U *
zderivative(p)
U *p;
{
U *p1, *p2;
p1 = eval(arg1(p));
push(p1);
p2 = eval(arg2(p));
push(p2);
p = d(p1, p2);
tos -= 2;
return p;
}
U *
zdot(p)
U *p;
{
int h = tos;
p = cdr(p);
while (iscons(p)) {
push_factor(eval(car(p)));
p = cdr(p);
}
return product(1, tos - h);
}
U *
zequal(p)
U *p;
{
U *p1, *p2;
p1 = eval(arg1(p));
push(p1);
p2 = eval(arg2(p));
pop();
if (equal(p1, p2))
return t;
else
return nil;
}
equal(p1, p2)
U *p1, *p2;
{
if (p1 == p2)
return 1;
if (p1->k != p2->k)
return 0;
switch (p1->k) {
case CONS:
while (iscons(p1) && iscons(p2)) {
if (!equal(car(p1), car(p2)))
return 0;
p1 = cdr(p1);
p2 = cdr(p2);
}
return equal(p1, p2);
case NUM:
if (p1->A == p2->A && p1->B == p2->B)
return 1;
else
return 0;
case STR:
if (strcmp(p1->u.str, p2->u.str) == 0)
return 1;
else
return 0;
default:
return 0; /* symbols would have matched p1 == p2 */
}
}
U *
zeval(p)
U *p;
{
p = eval(arg1(p));
push(p);
p = eval(p);
pop();
return p;
}
U *
zexit(p)
U *p;
{
(void) p;
exit(1);
return nil;
}
U *
zfixp(p)
U *p;
{
p = eval(arg1(p));
if (p->k == NUM && p->u.num.b == 1)
return t;
else
return nil;
}
U *
zgc()
{
return number(gc(), 1);
}
gc()
{
int i, n = 0;
/* tag everything */
for (i = 0; i < MEM; i++)
mem[i].tag = 1;
/* untag what's used */
for (i = 0; i < 64; i++)
untag(symtbl[i]);
for (i = 0; i < tos; i++)
untag(stack[i].p);
/* collect everything that's still tagged */
freelist = nil;
for (i = 0; i < MEM; i++)
if (mem[i].tag) {
mem[i].u.cons.cdr = freelist;
freelist = mem + i;
n++;
}
return n;
}
void
untag(p)
U *p;
{
while (iscons(p) && p->tag) {
p->tag = 0;
untag(p->u.cons.car);
p = p->u.cons.cdr;
}
if (p->tag) {
p->tag = 0;
if (issym(p))
untag(p->u.sym.binding);
}
}
U *
zgoto(p)
U *p;
{
return p;
}
U *
zgreaterp(p)
U *p;
{
U *p1, *p2;
p1 = eval(arg1(p));
push(p1);
p2 = eval(arg2(p));
pop();
if (lessp(p2, p1))
return t;
else
return nil;
}
U *
zif(p)
U *p;
{
if (eval(arg1(p)) == nil)
return eval(arg3(p));
else
return eval(arg2(p));
}
/* example: p = (integral (power x 2) x) */
U *
zintegral(p)
U *p;
{
push(eval(arg1(p)));
push(eval(arg2(p)));
integral();
return pop();
}
U *
zlessp(p)
U *p;
{
U *p1, *p2;
p1 = eval(arg1(p));
push(p1);
p2 = eval(arg2(p));
pop();
if (lessp(p1, p2))
return t;
else
return nil;
}
lessp(p1, p2)
U *p1, *p2;
{
if (p1 == p2)
return 0;
if (p1 == nil)
return 1;
if (p2 == nil)
return 0;
if (isnum(p1) && isnum(p2))
if (p1->A * p2->B < p2->A * p1->B)
return 1;
else
return 0;
if (isnum(p1))
return 1;
if (isnum(p2))
return 0;
if (isstr(p1) && isstr(p2))
if (strcmp(p1->u.str, p2->u.str) < 0)
return 1;
else
return 0;
if (isstr(p1))
return 1;
if (isstr(p2))
return 0;
if (issym(p1) && issym(p2))
if (strcmp(p1->u.sym.printname, p2->u.sym.printname) < 0)
return 1;
else
return 0;
if (issym(p1))
return 1;
if (issym(p2))
return 0;
while (iscons(p1) && iscons(p2) && equal(car(p1), car(p2))) {
p1 = cdr(p1);
p2 = cdr(p2);
}
if (iscons(p1) && iscons(p2))
return lessp(car(p1), car(p2));
else
return lessp(p1, p2);
}
U *
zlist(p)
U *p;
{
int i, n = 0;
p = cdr(p);
while (iscons(p)) {
push(eval(car(p)));
n++;
p = cdr(p);
}
p = nil;
for (i = 0; i < n; i++)
p = cons(stack[tos - i - 1].p, p);
tos -= n;
return p;
}
U *
zload(p)
U *p;
{
p = eval(arg1(p));
if (isstr(p))
load(p->u.str);
else
printf("bad file name, string expected\n");
return nothing;
}
void
load(s)
char *s;
{
U *p;
FILE *f = infile;
infile = fopen(s, "r");
if (infile == NULL) {
printf("cannot open file %s\n", s);
infile = f;
return;
}
for (;;) {
p = read1();
if (p == eof)
break;
push(p);
p = eval(p);
if (p != nothing)
print(p);
pop();
}
fclose(infile);
infile = f;
}
U *
zlength(p)
U *p;
{
int n = 0;
p = eval(arg1(p));
while (iscons(p)) {
n++;
p = cdr(p);
}
return number(n, 1);
}
U *
znot(p)
U *p;
{
if (eval(arg1(p)) == nil)
return t;
else
return nil;
}
U *
znull(p)
U *p;
{
if (eval(arg1(p)) == nil)
return t;
else
return nil;
}
U *
znumberp(p)
U *p;
{
p = eval(arg1(p));
if (isnum(p))
return t;
else
return nil;
}
U *
zor(p)
U *p;
{
p = cdr(p);
while (iscons(p)) {
if (eval(car(p)) != nil)
return t;
p = cdr(p);
}
return nil;
}
U *
zprintcars(p)
U *p;
{
p = eval(arg1(p));
while (iscons(p)) {
print(car(p));
p = cdr(p);
}
return nothing;
}
void
add(pa, pb, a, b)
int *pa, *pb, a, b;
{
int k;
a = *pa * b + *pb * a;
b = *pb * b;
k = gcd(a, b);
a /= k;
b /= k;
*pa = a;
*pb = b;
}
U *
zpower(p)
U *p;
{
push(eval(arg1(p)));
push(eval(arg2(p)));
return power();
}
U *
zprint(p)
U *p;
{
p = cdr(p);
while (iscons(p)) {
print1(eval(car(p)));
p = cdr(p);
}
printf("\n");
return nothing;
}
void
print(p)
U *p;
{
print1(p);
printf("\n");
}
void
print1(p)
U *p;
{
static char buf[100];
switch (p->k) {
case CONS:
printf("(");
print1(car(p));
p = cdr(p);
while (iscons(p)) {
printf(" ");
print1(car(p));
p = cdr(p);
}
if (p != nil) {
printf(" . ");
print1(p);
}
printf(")");
break;
case STR:
printf("%s", p->u.str);
break;
case NUM:
if (p->B == 1)
printf("%d", p->A);
else
printf("%d/%d", p->A, p->B);
break;
default:
printf("%s", p->u.sym.printname);
break;
}
}
U *
zproduct(p)
U *p;
{
int h = tos;
p = cdr(p);
while (iscons(p)) {
push_factor(eval(car(p)));
p = cdr(p);
}
return product(0, tos - h);
}
U *
zprog(p)
U *p;
{
U *p1, *p2;
pushvars(cadr(p));
p1 = cddr(p);
while (iscons(p1)) {
p2 = eval(car(p1));
if (car(p2)->k == ZRETURN) {
push(p2);
p2 = eval(cadr(p2));
pop();
popvars(cadr(p));
return p2;
break;
}
if (car(p2)->k == ZGOTO) {
p1 = cddr(p);
p2 = cadr(p2);
while (iscons(p1) && car(p1) != p2)
p1 = cdr(p1);
}
p1 = cdr(p1);
}
popvars(cadr(p));
return nothing;
}
void
pushvars(p)
U *p;
{
while (iscons(p)) {
if (issym(car(p)))
push(car(p)->u.sym.binding);
p = cdr(p);
}
}
void
popvars(p)
U *p;
{
if (iscons(p)) {
popvars(cdr(p));
if (issym(car(p)))
car(p)->u.sym.binding = pop();
}
}
U *
zquote(p)
U *p;
{
return arg1(p);
}
U *
zreturn(p)
U *p;
{
return p;
}
U *
zsetq(p)
U *p;
{
U *p1, *p2;
p1 = arg1(p);
p2 = eval(arg2(p));
if (issym(p1))
p1->u.sym.binding = p2;
return nothing;
}
U *
zsubst(p)
U *p;
{
U *p1, *p2, *p3;
p1 = eval(arg1(p));
push(p1);
p2 = eval(arg2(p));
push(p2);
p3 = eval(arg3(p));
push(p3);
p = subst(p1, p2, p3);
pop();
pop();
pop();
return p;
}
/* substitute p1 for p2 in p3 */
U *
subst(p1, p2, p3)
U *p1, *p2, *p3;
{
U *p4, *p5;
if (equal(p2, p3))
return p1;
else if (iscons(p3)) {
p4 = subst(p1, p2, car(p3));
push(p4);
p5 = subst(p1, p2, cdr(p3));
pop();
return cons(p4, p5);
} else
return p3;
}
U *
zsum(p)
U *p;
{
int h = tos;
p = cdr(p);
while (iscons(p)) {
push_term(eval(car(p)));
p = cdr(p);
}
return ksum(tos - h);
}
U *
ztensor(p)
U *p;
{
switch (tensor_op) {
default:
return cons(_tensor, eval_args(cdr(p)));
case 1:
if (equal(cdr(p), indexlist))
return number(1, 1);
else
return number(0, 1);
case 2:
return contract(p, index_i, index_j);
case 3:
return transpose(p, index_i, index_j);
}
}
U *
contract(p, i, j)
U *p;
int i, j;
{
U *p1;
int k, n;
ST *s;
p1 = p;
n = 0;
s = stack + tos;
while (iscons(p1)) {
push(car(p1));
n++;
p1 = cdr(p1);
}
if (i >= n || j >= n) {
tos -= n;
return p;
}
if (!equal(s[i].p, s[j].p)) {
tos -= n;
return number(0, 1);
}
if (n == 3) {
tos -= n;
return number(1, 1);
}
p = nil;
for (k = n - 1; k >= 0; k--)
if (k != i && k != j)
p = cons(s[k].p, p);
tos -= n;
return p;
}
U *
transpose(p, i, j)
U *p;
int i, j;
{
U *p1;
int k, n;
ST *s;
p1 = p;
n = 0;
s = stack + tos;
while (iscons(p1)) {
push(car(p1));
n++;
p1 = cdr(p1);
}
if (i >= n || j >= n) {
tos -= n;
return p;
}
p = nil;
for (k = n - 1; k >= 0; k--)
if (k == i)
p = cons(s[j].p, p);
else if (k == j)
p = cons(s[i].p, p);
else
p = cons(s[k].p, p);
tos -= n;
return p;
}
void
mult(pa, pb, a, b)
int *pa, *pb, a, b;
{
int k;
a *= *pa;
b *= *pb;
k = gcd(a, b);
a /= k;
b /= k;
*pa = a;
*pb = b;
}
U *
ztranspose(p)
U *p;
{
int i, j;
i = tindex(eval(arg1(p)));
j = tindex(eval(arg2(p)));
p = eval(arg3(p));
if (i == 0 || j == 0 || i == j)
return p;
index_i = i;
index_j = j;
tensor_op = 3;
push(p);
p = eval(p);
pop();
tensor_op = 0;
return p;
}
void
init()
{
int i;
nil = &_nil;
nil->k = SYM;
nil->u.sym.binding = nil;
nil->u.sym.printname = "nil";
for (i = 0; i < 64; i++)
symtbl[i] = nil;
freelist = nil;
for (i = 0; i < MEM; i++) {
/* mem[i].gamma = 0; */
mem[i].u.cons.cdr = freelist;
freelist = mem + i;
}
symbol("and") ->k = ZAND;
symbol("append") ->k = ZAPPEND;
symbol("atom") ->k = ZATOM;
symbol("car") ->k = ZCAR;
symbol("cdr") ->k = ZCDR;
symbol("component") ->k = ZCOMPONENT;
symbol("cond") ->k = ZCOND;
symbol("cons") ->k = ZCONS;
symbol("contract") ->k = ZCONTRACT;
symbol("define") ->k = ZDEFINE;
symbol("derivative") ->k = ZDERIVATIVE;
symbol("equal") ->k = ZEQUAL;
symbol("eval") ->k = ZEVAL;
symbol("exit") ->k = ZEXIT;
symbol("gc") ->k = ZGC;
symbol("goto") ->k = ZGOTO;
symbol("greaterp") ->k = ZGREATERP;
symbol("if") ->k = ZIF;
symbol("integerp") ->k = ZINTEGERP;
symbol("integral") ->k = ZINTEGRAL;
symbol("lessp") ->k = ZLESSP;
symbol("list") ->k = ZLIST;
symbol("load") ->k = ZLOAD;
symbol("run") ->k = ZLOAD;
symbol("length") ->k = ZLENGTH;
symbol("not") ->k = ZNOT;
symbol("null") ->k = ZNULL;
symbol("numberp") ->k = ZNUMBERP;
symbol("or") ->k = ZOR;
symbol("power") ->k = ZPOWER;
symbol("print") ->k = ZPRINT;
symbol("printcars") ->k = ZPRINTCARS;
symbol("product") ->k = ZPRODUCT;
symbol("prog") ->k = ZPROG;
symbol("quote") ->k = ZQUOTE;
symbol("return") ->k = ZRETURN;
symbol("setq") ->k = ZSETQ;
symbol("sum") ->k = ZSUM;
symbol("subst") ->k = ZSUBST;
symbol("tensor") ->k = ZTENSOR;
symbol("transpose") ->k = ZTRANSPOSE;
symbol("dot") ->k = ZDOT;
gamma[2] = symbol("gamma0");
gamma[3] = symbol("gamma1");
gamma[4] = symbol("gamma2");
gamma[5] = symbol("gamma3");
gamma[6] = symbol("sigma1"); /* (product gamma1 gamma0) */
gamma[7] = symbol("sigma2"); /* (product gamma2 gamma0) */
gamma[8] = symbol("sigma3"); /* (product gamma3 gamma0) */
gamma[9] = symbol("isigma1"); /* (product gamma3 gamma2) */
gamma[10] = symbol("isigma2"); /* (product gamma1 gamma3) */
gamma[11] = symbol("isigma3"); /* (product gamma2 gamma1) */
gamma[12] = symbol("igamma0"); /* (product gamma3 gamma2 gamma1) */
gamma[13] = symbol("igamma1"); /* (product gamma0 gamma3 gamma2) */
gamma[14] = symbol("igamma2"); /* (product gamma0 gamma1 gamma3) */
gamma[15] = symbol("igamma3"); /* (product gamma0 gamma2 gamma1) */
gamma[16] = symbol("i"); /* (product gamma0 gamma1 gamma2 gamma3) */
gamma[2]->gamma = 2;
gamma[3]->gamma = 3;
gamma[4]->gamma = 4;
gamma[5]->gamma = 5;
gamma[6]->gamma = 6;
gamma[7]->gamma = 7;
gamma[8]->gamma = 8;
gamma[9]->gamma = 9;
gamma[10]->gamma = 10;
gamma[11]->gamma = 11;
gamma[12]->gamma = 12;
gamma[13]->gamma = 13;
gamma[14]->gamma = 14;
gamma[15]->gamma = 15;
gamma[16]->gamma = 16;
_arg = symbol("arg");
_arg1 = symbol("arg1");
_arg2 = symbol("arg2");
_arg3 = symbol("arg3");
_arg4 = symbol("arg4");
_arg5 = symbol("arg5");
_arg6 = symbol("arg6");
_arglist = symbol("arglist");
_cos = symbol("cos");
derivative = symbol("derivative");
e = symbol("e");
eof = symbol("eof");
_integral = symbol("integral");
_integral_list = symbol("integral-list");
_meta_a = symbol("meta-a");
_meta_b = symbol("meta-b");
_meta_f = symbol("meta-f");
_meta_n = symbol("meta-n");
_meta_x = symbol("meta-x");
nothing = symbol("nothing");
quote = symbol("quote");
_power = symbol("power");
_product = symbol("product");
_sin = symbol("sin");
sum = symbol("sum");
t = symbol("t");
_tensor = symbol("tensor");
}
void
stop(char *s)
{
printf("\nERROR %s\n", s);
exit(1);
}
/* the temp stack keeps intermediate results from garbage collection */
void
push(p)
U *p;
{
if (tos == TOS)
stop("stack overflow");
stack[tos++].p = p;
}
U *
pop()
{
if (tos == 0)
stop("stack underflow");
return stack[--tos].p;
}
void
push_term(p)
U *p;
{
if (car(p) == sum) {
p = cdr(p);
while (iscons(p)) {
push(car(p));
p = cdr(p);
}
} else
push(p);
}
void
push_factor(p)
U *p;
{
if (car(p) == _product) {
p = cdr(p);
while (iscons(p)) {
push(car(p));
p = cdr(p);
}
} else
push(p);
}
U *
alloc()
{
U *p;
if (freelist == nil) {
gc();
if (freelist == nil)
stop("out of memory");
}
p = freelist;
freelist = freelist->u.cons.cdr;
return p;
}
U *
number(a, b)
int a, b;
{
int k;
U *p;
k = gcd(a, b);
a /= k;
b /= k;
p = alloc();
p->k = NUM;
p->A = a;
p->B = b;
return p;
}
gcd(a, b)
int a, b;
{
int k, sign;
if (b == 0)
stop("divide by zero");
if (a == 0)
return b;
if (a < 0)
a = -a;
if (b < 0) {
b = -b;
sign = -1;
} else
sign = 1;
while (b) {
k = a % b;
a = b;
b = k;
}
return sign * a;
}
char *
sdup(char *s)
{
int j = k;
while (*s) {
if (k >= STRBUF)
stop("string buffer full");
strbuf[k++] = *s++;
}
strbuf[k++] = 0;
return strbuf + j;
}
U *
symbol(s)
char *s;
{
U *p;
int x;
if (strcmp(s, "nil") == 0)
return nil;
x = *s & 63;
p = symtbl[x];
while (iscons(p)) {
if (strcmp(car(p)->u.sym.printname, s) == 0)
return car(p);
p = cdr(p);
}
p = alloc();
p->k = SYM;
p->u.sym.printname = sdup(s);
p->u.sym.binding = p;
p = cons(p, symtbl[x]);
symtbl[x] = p;
return car(p);
}
U *
read1()
{
return read_expr(read_token());
}
U *
read_expr(c)
int c;
{
int i, n;
U *p;
while (c == ')' || c == '.') {
printf("discarding unexpected %c\n", c);
c = read_token();
}
switch (c) {
case EOF:
return eof;
case '(':
n = 0;
c = read_token();
while (c != EOF && c != ')' && c != '.') {
p = read_expr(c);
push(p);
n++;
c = read_token();
}
if (c == '.') {
c = read_token();
p = read_expr(c);
c = read_token();
} else
p = nil;
if (c != ')')
printf("missing )\n");
for (i = 0; i < n; i++)
p = cons(stack[tos - i - 1].p, p);
tos -= n;
return p;
case '\'':
c = read_token();
p = read_expr(c);
p = cons(p, nil);
p = cons(quote, p);
return p;
case 'n':
return scann(buf);
case 'q':
p = alloc();
p->k = STR;
p->u.str = sdup(buf);
return p;
case 's':
return symbol(buf);
default:
stop("bug in read_expr()");
return nil;
}
}
read_token()
{
int c, i;
/* skip spaces and comments */
for (;;) {
c = fgetc(infile);
if (c == ';')
while (c != EOF && c != '\n')
c = fgetc(infile);
if (c == EOF || !isspace(c))
break;
}
switch (c) {
case EOF:
return EOF;
case '(':
case ')':
case '.':
case '\'':
return c;
case '\"':
for (i = 0; i < BUF; i++) {
c = fgetc(infile);
if (c == EOF) {
printf("unexpected end of file\n");
break;
}
if (c == '\"')
break;
buf[i] = c;
}
if (i == BUF)
stop("input buffer overflow");
buf[i] = 0;
return 'q'; /* quoted string */
default:
buf[0] = c;
for (i = 1; i < BUF; i++) {
c = fgetc(infile);
if (c == EOF)
break;
if (isspace(c) || c == '(' || c == ')'
|| c == ';' || c == '.' || c == '\'') {
ungetc(c, infile);
break;
}
buf[i] = c;
}
if (i == BUF)
stop("input buffer overflow");
buf[i] = 0;
if (*buf == '+' || *buf == '-' || isdigit(*buf))
return 'n'; /* number */
else
return 's'; /* symbol */
}
}
U *
scann(s)
char *s;
{
int a, b, sgn;
a = 0;
b = 1;
sgn = 1;
if (*s == '+')
s++;
else if (*s == '-') {
s++;
sgn = -1;
}
if (!isdigit(*s)) {
printf("syntax error in number\n");
return nil;
}
while (isdigit(*s)) {
a = 10 * a + *s - '0';
s++;
}
if (*s == '/') {
s++;
b = 0;
while (isdigit(*s)) {
b = 10 * b + *s - '0';
s++;
}
}
if (*s) {
printf("syntax error in number\n");
return nil;
}
return number(sgn * a, b);
}
cmp(a, b)
ST *a, *b;
{
if (equal(a->p, b->p))
return 0;
else if (lessp(a->p, b->p))
return -1;
else
return 1;
}
U *
ksum(n)
int n;
{
int a, b, i, j;
U *p, *q;
ST *s;
s = stack + tos - n;
/* add numbers */
a = 0;
b = 1;
for (i = 0; i < n; i++) {
p = s[i].p;
if (isnum(p)) {
add(&a, &b, p->u.num.a, p->u.num.b);
s[i].p = nil;
}
}
/* remove numeric coefficients */
for (i = 0; i < n; i++) {
p = s[i].p;
if (car(p) == _product && isnum(cadr(p))) {
s[i].a = cadr(p)->u.num.a;
s[i].b = cadr(p)->u.num.b;
if (iscons(cdddr(p)))
p = cons(_product, cddr(p));
else
p = caddr(p);
s[i].p = p;
} else {
s[i].a = 1;
s[i].b = 1;
}
}
/* sort terms */
qsort(s, n, sizeof (ST), cmp);
/* combine terms */
for (i = 0; i < n - 1; i++) {
if (s[i].p == nil)
continue;
for (j = i + 1; j < n; j++) {
if (!equal(s[i].p, s[j].p))
break;
add(&s[i].a, &s[i].b, s[j].a, s[j].b);
s[j].p = nil;
if (s[i].a == 0) {
s[i].p = nil;
break;
}
}
}
/* put the coefficients back */
for (i = 0; i < n; i++) {
p = s[i].p;
if (p == nil)
continue;
if (s[i].a == 1 && s[i].b == 1)
continue;
q = number(s[i].a, s[i].b);
if (car(p) == _product)
p = cdr(p);
else {
push(q); /* save q from gc */
p = cons(p, nil);
pop();
}
p = cons(q, p);
p = cons(_product, p);
s[i].p = p;
}
/* add number */
if (a != 0) {
for (i = 0; i < n; i++)
if (s[i].p == nil)
break;
if (i == n)
stop("bug in ksum()");
s[i].p = number(a, b);
}
/* remove nils */
j = 0;
for (i = 0; i < n; i++)
if (s[i].p != nil)
s[j++].p = s[i].p;
/* sort terms */
qsort(s, j, sizeof (ST), cmp);
/* result */
switch (j) {
case 0:
p = number(0, 1);
break;
case 1:
p = s[0].p;
break;
default:
p = nil;
for (i = j - 1; i >= 0; i--)
p = cons(s[i].p, p);
p = cons(sum, p);
break;
}
tos -= n;
return p;
}
U *
product(inner, n)
int inner, n;
{
int a, b, flag, g, i, j, x;
U *p, *q;
ST *s;
s = stack + tos - n;
/* check for product of sum or sums */
for (i = 0; i < n; i++)
if (car(s[i].p) == sum)
return expand(inner, n);
/* multiply numbers, tensors and gammas */
a = 1;
b = 1;
g = -1;
for (i = 0; i < n; i++) {
p = s[i].p;
if (isnum(p)) {
if (p->A == 0) {
tos -= n;
return number(0, 1);
}
mult(&a, &b, p->A, p->B);
s[i].p = nil;
} else if (p->gamma) {
if (g == -1)
g = i;
else {
x = gp[s[g].p->gamma][p->gamma];
if (x < 0) {
x = -x;
a *= -1;
}
if (x == 1) {
s[g].p = nil;
s[i].p = nil;
g = -1;
} else {
s[g].p = gamma[x];
s[i].p = nil;
}
}
}
}
/* multiply tensors */
for (i = 0; i < n; i++) {
if (car(s[i].p) == _tensor) {
for (j = i + 1; j < n; j++) {
if (car(s[j].p) == _tensor) {
if (inner) {
s[i].p = inner_product(s[i].p, s[j].p);
s[j].p = nil;
if (isnum(s[i].p)) {
if (s[i].p->A == 0) {
tos -= n;
return number(0, 1);
} else {
s[i].p = nil;
i = j;
break;
}
}
} else {
s[i].p = append(s[i].p, cdr(s[j].p));
s[j].p = nil;
}
}
}
}
}
prep_exponents(n);
/* sort factors */
qsort(s, n, sizeof (ST), cmp);
/* combine factors */
for (i = 0; i < n - 1; i++) {
if (s[i].p == nil)
continue;
for (j = i + 1; j < n; j++) {
if (!equal(s[i].p, s[j].p))
break;
add(&s[i].a, &s[i].b, s[j].a, s[j].b);
s[j].p = nil;
if (s[i].a == 0) {
s[i].p = nil;
break;
}
/* quick bug fix while working on general solution... */
/* result is a number with exponent 1 */
if (isnum(s[i].p) && s[i].a == 1 && s[i].b == 1) {
mult(&a, &b, s[i].p->A, s[i].p->B);
s[i].p = nil;
break;
}
/* result is a number with exponent -1 */
if (isnum(s[i].p) && s[i].a == -1 && s[i].b == 1) {
mult(&a, &b, s[i].p->B, s[i].p->A);
s[i].p = nil;
break;
}
}
}
/* restore exponents */
for (i = 0; i < n; i++) {
p = s[i].p;
if (p == nil)
continue;
if (s[i].a == 1 && s[i].b == 1)
continue;
q = number(s[i].a, s[i].b);
if (car(p) == _power) {
if (caaddr(p) == _product)
q = cons(q, cdaddr(p));
else {
push(q); /* save from gc */
q = cons(q, cons(caddr(p), nil));
pop();
}
q = cons(_product, q);
q = cons(q, nil);
q = cons(cadr(p), q);
} else
q = cons(p, cons(q, nil));
q = cons(_power, q);
if (cadr(q) == sum && isnum(caddr(q)))
q = eval(q);
s[i].p = q;
}
/* restore coefficient */
if (a != 1 || b != 1) {
for (i = 0; i < n; i++)
if (s[i].p == nil)
break;
if (i == n)
stop("bug in product()");
s[i].p = number(a, b);
}
/* remove nils */
j = 0;
flag = 0;
for (i = 0; i < n; i++) {
p = s[i].p;
if (p != nil) {
s[j++].p = p;
if (car(p) == sum)
flag = 1;
}
}
if (flag) {
tos = tos - n + j;
return expand(inner, j);
}
/* sort factors */
qsort(s, j, sizeof (ST), cmp);
/* result */
switch (j) {
case 0:
p = number(1, 1);
break;
case 1:
p = s[0].p;
break;
default:
p = nil;
for (i = j - 1; i >= 0; i--)
p = cons(s[i].p, p);
p = cons(_product, p);
break;
}
tos -= n;
return p;
}
/* Here are the cases that must be handled:
input output
s[i].p s[i].a s[i].b s[i].p
------ ------ ------ ------
a 1 1 a
(power a b) 1 1 (power a b)
(power a 1/2) 1 2 a
(power a (product 1/2 b)) 1 2 (power a b)
(power a (product 1/2 b c)) 1 2 (power a (product b c))
Example for navigating cars and cdrs:
x = (power a (product 3 b c))
(car x) -> power
(cdr x) -> (a (product 3 b c))
(cadr x) -> a
(cddr x) -> ((product 3 b c))
(caddr x) -> (product 3 b c)
(caaddr x) -> product
(cdaddr x) -> (3 b c)
(cadaddr x) -> 3
(cddaddr x) -> (b c)
(caddaddr x) -> b
(cdddaddr x) -> (c)
*/
prep_exponents(n)
{
int i;
U *p, *q;
for (i = tos - n; i < tos; i++) {
stack[i].a = 1;
stack[i].b = 1;
p = stack[i].p;
if (car(p) != _power)
continue;
if (isnum(caddr(p))) {
stack[i].p = cadr(p);
stack[i].a = caddr(p)->A;
stack[i].b = caddr(p)->B;
} else if (caaddr(p) == _product && isnum(cadaddr(p))) {
if (cdddaddr(p) == nil)
q = caddaddr(p);
else
q = cons(_product, cddaddr(p));
q = cons(q, nil);
q = cons(cadr(p), q);
q = cons(_power, q);
stack[i].p = q;
stack[i].a = cadaddr(p)->A;
stack[i].b = cadaddr(p)->B;
}
}
}
U *
expand(inner, n)
int inner, n;
{
U *p;
int h, h1, h2, i, j, k, m;
h = tos - n;
/* stack[h + i].a = stack index of factor i */
/* stack[h + i].b = number of terms in factor i */
/* m = number of permutations */
m = 1;
for (i = 0; i < n; i++) {
p = stack[h + i].p;
if (car(p) == sum) {
stack[h + i].a = tos;
j = 0;
p = cdr(p);
while (iscons(p)) {
push(car(p));
p = cdr(p);
j++;
}
} else {
stack[h + i].a = h + i;
j = 1;
}
stack[h + i].b = j;
m = j * m;
}
h1 = tos;
for (i = 0; i < m; i++) {
k = i;
h2 = tos;
for (j = 0; j < n; j++) {
p = stack[stack[h + j].a + k % stack[h + j].b].p;
k = k / stack[h + j].b;
push_factor(p);
}
push_term(product(inner, tos - h2));
}
p = ksum(tos - h1);
tos = h;
return p;
}
U *
power()
{
int a, b, h, i, n;
U *p1, *p2;
p1 = stack[tos - 2].p;
p2 = stack[tos - 1].p;
/* (power ? 0) -> 1 */
if (isnum(p2) && p2->A == 0) {
tos -= 2;
return number(1, 1);
}
/* (power ? 1) -> ? */
if (isnum(p2) && p2->A == 1 && p2->B == 1) {
tos -= 2;
return p1;
}
/* (power 1 ?) -> 1 */
if (isnum(p1) && p1->A == 1 && p1->B == 1) {
tos -= 2;
return p1;
}
/* (power a (sum b c)) -> (product (power a b) (power a c)) */
if (car(p2) == sum) {
h = tos;
p2 = cdr(p2);
while (iscons(p2)) {
push(p1);
push(car(p2));
push_factor(power());
p2 = cdr(p2);
}
p1 = product(0, tos - h);
tos -= 2;
return p1;
}
/* (power (product a b) c) -> (product (power a c) (power b c)) */
if (car(p1) == _product) {
h = tos;
p1 = cdr(p1);
while (iscons(p1)) {
push(car(p1));
push(p2);
push_factor(power());
p1 = cdr(p1);
}
p1 = product(0, tos - h);
tos -= 2;
return p1;
}
/* (power (sum a b) 2) -> (sum (power a 2) (power b 2) (product 2 a b)) */
if (car(p1) == sum && isnum(p2) && p2->A > 1 && p2->B == 1) {
push(p1);
for (i = 1; i < p2->A; i++) {
push(p1);
push(expand(0, 2));
}
p1 = pop();
tos -= 2;
return p1;
}
/* (power (power a b) c) -> (power a (product b c)) */
if (car(p1) == _power) {
push(cadr(p1));
h = tos;
push_factor(caddr(p1));
push_factor(p2);
push(product(0, tos - h));
p1 = power();
tos -= 2;
return p1;
}
if (isnum(p1) && isnum(p2) && p2->B == 1) {
a = p1->A;
b = p1->B;
if (p2->A > 0)
n = p2->A;
else
n = -p2->A;
for (i = 1; i < n; i++)
mult(&a, &b, p1->A, p2->B);
if (p2->A > 0)
p1 = number(a, b);
else
p1 = number(b, a);
tos -= 2;
return p1;
}
p1 = cons(_power, cons(p1, cons(p2, nil)));
tos -= 2;
return p1;
}
U *
d(p, dx)
U *p, *dx;
{
// for example, (derivative x x) is 1
if (equal(p, dx))
return number(1, 1);
// for example, (derivative a x) is 0
if (!iscons(p) || car(p) == _tensor)
return number(0, 1);
if (car(p) == sum)
return dsum(p, dx);
if (car(p) == _product)
return dproduct(p, dx);
if (car(p) == _power)
return dpower(p, dx);
if (car(p) == derivative)
return dd(p, dx);
if (car(p) == _sin)
return dsin(p, dx);
if (car(p) == _cos)
return dcos(p, dx);
return dfunction(p, dx);
}
U *
dsum(p, dx)
U *p, *dx;
{
int h = tos;
p = cdr(p);
while (iscons(p)) {
push_term(d(car(p), dx)); /* result may be a sum */
p = cdr(p);
}
return ksum(tos - h);
}
U *
dproduct(p, dx)
U *p, *dx;
{
int h1, h2, i, j, n = 0;
U *p1;
p1 = cdr(p);
while (iscons(p1)) {
n++;
p1 = cdr(p1);
}
h1 = tos;
for (i = 0; i < n; i++) {
h2 = tos;
p1 = cdr(p);
for (j = 0; j < n; j++) {
if (i == j)
push_factor(d(car(p1), dx));
else
push(car(p1));
p1 = cdr(p1);
}
push_term(product(0, tos - h2));
}
return ksum(tos - h1);
}
U *
dpower(p, dx)
U *p, *dx;
{
int h = tos;
U *base, *exponent;
base = cadr(p);
exponent = caddr(p);
if (base == e) {
/* d exponent * e ^ exponent */
push_factor(d(exponent, dx)); /* result may be a product */
push(p);
return product(0, tos - h);
} else {
/* exponent * base ^ (exponent - 1) * d base */
push_factor(exponent); /* exponent may be a product */
push(base);
push(exponent); /* exponent is never a sum */
push(number(-1, 1));
push(ksum(2));
push(power());
push_factor(d(base, dx));
return product(0, tos - h);
}
}
/* derivative of derivative */
U *
dd(p, dx2)
U *p, *dx2;
{
U *dx1;
dx1 = caddr(p);
p = d(cadr(p), dx2);
push(p);
if (car(p) == derivative) {
dx2 = caddr(p);
p = cadr(p);
if (lessp(dx1, dx2)) {
p = cons(derivative, cons(p, cons(dx1, nil)));
pop();
push(p);
p = cons(derivative, cons(p, cons(dx2, nil)));
} else {
p = cons(derivative, cons(p, cons(dx2, nil)));
pop();
push(p);
p = cons(derivative, cons(p, cons(dx1, nil)));
}
} else
p = d(p, dx1);
pop();
return p;
}
/* derivative of a generic function */
U *
dfunction(p, dx)
U *p, *dx;
{
U *t;
t = cdr(p);
/* no arg list? */
if (t == nil)
return cons(derivative, cons(p, cons(dx, nil)));
/* check arg list */
while (iscons(t)) {
if (equal(car(t), dx))
return cons(derivative, cons(p, cons(dx, nil)));
t = cdr(t);
}
return number(0, 1);
}
U *
dsin(p, dx)
U *p, *dx;
{
int h = tos;
push_factor(d(cadr(p), dx));
push(cons(_cos, cons(cadr(p), nil)));
return product(0, tos - h);
}
U *
dcos(p, dx)
U *p, *dx;
{
int h = tos;
push(number(-1, 1));
push_factor(d(cadr(p), dx));
push(cons(_sin, cons(cadr(p), nil)));
return product(0, tos - h);
}
/* returns the inner product of two tensor args
p1 p2 return
(tensor 1) (tensor 1) 1
(tensor 1) (tensor 2) 0
(tensor 1 2) (tensor 1) 0
(tensor 1 2) (tensor 2) (tensor 1)
(tensor 1 2) (tensor 2 1) (tensor 1 1)
*/
U *
inner_product(p1, p2)
U *p1, *p2;
{
int i, n = 0;
while (iscons(p1)) {
push(car(p1));
n++;
p1 = cdr(p1);
}
if (equal(stack[tos - 1].p, cadr(p2))) {
p2 = cddr(p2);
for (i = 1; i < n; i++)
p2 = cons(stack[tos - i - 1].p, p2);
if (cdr(p2) == nil)
p2 = number(1, 1);
} else
p2 = number(0, 1);
tos -= n;
return p2;
}
#define f (_meta_f->u.sym.binding)
#define x (_meta_x->u.sym.binding)
#define a (_meta_a->u.sym.binding)
#define n (_meta_n->u.sym.binding)
integral()
{
U *tmp1, *tmp2;
tmp2 = pop();
tmp1 = pop();
push(f);
push(x);
push(a);
push(n);
f = tmp1;
x = tmp2;
if (does_not_depend_on_x(f))
integral_of_constant();
else if (car(f) == sum)
integral_of_sum();
else if (car(f) == _product)
integral_of_product();
else
integral_of_nub();
tmp1 = pop();
n = pop();
a = pop();
x = pop();
f = pop();
push(tmp1);
}
integral_of_constant()
{
push(f);
push(x);
push(product(0, 2));
}
integral_of_sum()
{
int h;
U *p;
h = tos;
p = cdr(f);
while (iscons(p)) {
push(car(p));
push(x);
integral();
push_term(pop());
p = cdr(p);
}
p = ksum(tos - h);
push(p);
}
integral_of_product()
{
int h1, h2;
U *p;
h1 = tos;
p = cdr(f);
while (iscons(p)) {
if (does_not_depend_on_x(car(p)))
push(car(p));
p = cdr(p);
}
if (tos == h1) {
integral_of_nub();
return;
}
h2 = tos;
p = cdr(f);
while (iscons(p)) {
if (depends_on_x(car(p)))
push(car(p));
p = cdr(p);
}
push(product(0, tos - h2));
push(x);
integral();
push_factor(pop());
push(product(0, tos - h1));
}
integral_of_nub()
{
int h;
U *p;
h = tos;
push(number(1, 1)); /* so meta variables can try the value 1 */
deconstruct(f);
p = _integral_list->u.sym.binding;
while (iscons(p)) {
if (match(caar(p), cddar(p), h)) {
p = eval(cadar(p));
tos = h;
push(p);
return;
}
p = cdr(p);
}
p = cons(_integral, cons(f, cons(x, nil)));
tos = h;
push(p);
}
depends_on_x(p)
U *p;
{
if (findx(p) || findf(p))
return 1;
else
return 0;
}
does_not_depend_on_x(p)
U *p;
{
if (findx(p) || findf(p))
return 0;
else
return 1;
}
/* yes if dx somewhere in p */
findx(p)
U *p;
{
if (p == x)
return 1;
while (iscons(p)) {
if (findx(car(p)))
return 1;
p = cdr(p);
}
return 0;
}
/* yes if anonymous function somewhere in p, i.e. p = (sum (f) 1) */
findf(p)
U *p;
{
if (iscons(p) && car(p)->k == SYM && cdar(p) == nil)
return 1;
while (iscons(p)) {
if (findf(car(p)))
return 1;
p = cdr(p);
}
return 0;
}
/* push constant expressions */
deconstruct(p)
U *p;
{
int h;
U *q;
if (does_not_depend_on_x(p)) {
push(p);
return;
}
if (car(p) != _product) {
p = cdr(p);
while (iscons(p)) {
deconstruct(car(p));
p = cdr(p);
}
return;
}
q = cdr(p);
while (iscons(q)) {
if (depends_on_x(car(q)))
deconstruct(car(q));
q = cdr(q);
}
h = tos;
p = cdr(p);
while (iscons(p)) {
if (does_not_depend_on_x(car(p)))
push(car(p));
p = cdr(p);
}
if (tos - h)
push(product(0, tos - h));
}
/* p form
l list of constraints
h Where constant expressions start on the stack
Juggle the constant expressions to try and match f and p.
*/
match(p, l, h)
U *p, *l;
int h;
{
int j1, j2;
U *q;
for (j1 = h; j1 < tos; j1++)
for (j2 = h; j2 < tos; j2++)
{
a = stack[j1].p;
n = stack[j2].p;
/* check constraints */
q = l;
while (iscons(q)) {
if (eval(car(q)) == nil)
break;
q = cdr(q);
}
if (iscons(q))
continue; /* constraint failed */
if (equal(f, eval(p)))
return 1;
}
return 0;
}