/* * Euler - a numerical lab * * platform : neutral * * file : feval.c -- math solvers */ #include #include #include #include #include "stack.h" #include "output.h" #include "builtin.h" #include "udf.h" #include "mainloop.h" static double fevalreal (char *fname, double x, int argn, header *args, long size) { char *ram=newram; header *arg,*hdudf; arg=new_real(x,""); if (error) return 0; if (size>0) { memmove(nextof(arg),args,size); newram+=size; } if (!exec_builtin(fname,1,arg)) { hdudf=searchudf(fname); if (error || !hdudf) { error=1; newram=ram; return 0; } interpret_udf(hdudf,arg,1+argn,0); } newram=ram; if (arg->type!=s_real) { error=1; return 0; } return *realof(arg); } #define CGOLD 0.3819660112501051 #undef SHFT #define SHFT(a,b,c,d) (a)=(b);(b)=(c);(c)=(d); #undef SIGN #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a)) static double brent (double ax, double bx, double cx, char *fname, int argn, header *args, long size, double tol) { int iter; double a,b,d=1,etemp,fu,fv,fw,fx,p,q,r,tol1,tol2,u,v,w,x,xm; double e=0.0; a=(ax < cx ? ax : cx); b=(ax > cx ? ax : cx); x=w=v=bx; fw=fv=fx=fevalreal(fname,x,argn,args,size); for (iter=1;iter<=1000;iter++) { if (test_key()==escape) { error=1; return 0; } xm=0.5*(a+b); tol2=2.0*(tol1=tol*fabs(x)+epsilon); if (fabs(x-xm) <= (tol2-0.5*(b-a))) { return x; } if (fabs(e) > tol1) { r=(x-w)*(fx-fv); q=(x-v)*(fx-fw); p=(x-v)*q-(x-w)*r; q=2.0*(q-r); if (q > 0.0) p = -p; q=fabs(q); etemp=e; e=d; if (fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a-x) || p >= q*(b-x)) d=CGOLD*(e=(x >= xm ? a-x : b-x)); else { d=p/q; u=x+d; if (u-a < tol2 || b-u < tol2) d=SIGN(tol1,xm-x); } } else { d=CGOLD*(e=(x >= xm ? a-x : b-x)); } u=(fabs(d) >= tol1 ? x+d : x+SIGN(tol1,d)); fu=fevalreal(fname,u,argn,args,size); if (fu <= fx) { if (u >= x) a=x; else b=x; SHFT(v,w,x,u) SHFT(fv,fw,fx,fu) } else { if (u < x) a=u; else b=u; if (fu <= fw || w == x) { v=w; w=u; fv=fw; fw=fu; } else if (fu <= fv || v == x || v == w) { v=u; fv=fu; } } } output("Too many iterations in brent\n"); error=1; return x; } void mbrent (header *hd) { header *st=hd,*hd1,*hd2,*hd3,*args,*h,*result; double x,d,x1,x2,y,y1,y2; long size; int argn; char *fname; if ((header *)newram<=hd) wrong_arg_in("brent"); hd1=nextof(hd); if ((header *)newram<=hd1) wrong_arg_in("brent"); hd2=nextof(hd1); if ((header *)newram<=hd2) wrong_arg_in("brent"); hd3=nextof(hd2); if ((header *)newram<=hd3) wrong_arg_in("brent"); args=nextof(hd3); size=newram-(char *)args; argn=0; if (size>0) { h=args; while (h<(header *)newram) { argn++; h=nextof(h); } } hd=getvalue(hd); if (error) return; hd1=getvalue(hd1); if (error) return; hd2=getvalue(hd2); if (error) return; hd3=getvalue(hd3); if (error) return; if (hd->type!=s_string || hd1->type!=s_real || hd2->type!=s_real || hd3->type!=s_real) wrong_arg_in("brent"); x=*realof(hd1); d=*realof(hd2); if (d<=epsilon) d=epsilon; fname=stringof(hd); y=fevalreal(fname,x,argn,args,size); if (error) return; x1=x+d; y1=fevalreal(fname,x1,argn,args,size); if (error) return; if (y1type!=s_real) { error=1; return 0; } return *realof(arg); } #define NMAX 5000 #define SWAP(a,b) {swap=(a);(a)=(b);(b)=swap;} static double *ptry=0; static double amotry(double **p, double y[], double psum[], int ndim, char *fname, int argn, header *args, long size, int ihi, double fac) { int j; double fac1,fac2,ytry; fac1=(1.0-fac)/ndim; fac2=fac1-fac; for (j=0;jy[1] ? (inhi=1,0) : (inhi=0,1); for (i=0;i y[ihi]) { inhi=ihi; ihi=i; } else if (y[i] > y[inhi] && i != ihi) inhi=i; } rtol=2.0*fabs(y[ihi]-y[ilo]); if (rtol < ftol) { SWAP(y[0],y[ilo]) for (i=0;i= NMAX) { output("Two many iterations in nelder\n"); error=1; goto stop; } nfunk +=2; ytry=amotry(p,y,psum,ndim,fname,argn,args,size,ihi,-1.0); if (error) return; if (ytry <= y[ilo]) { amotry(p,y,psum,ndim,fname,argn,args,size,ihi,2.0); if (error) goto stop; } else if (ytry >= y[inhi]) { ysave=y[ihi]; ytry=amotry(p,y,psum,ndim,fname,argn,args,size,ihi,0.5); if (error) goto stop; if (ytry >= ysave) { for (i=0;i0) { h=args; while (h<(header *)newram) { argn++; h=nextof(h); } } hd=getvalue(hd); if (error) return; hd1=getvalue(hd1); if (error) return; hd2=getvalue(hd2); if (error) return; hd3=getvalue(hd3); if (error) return; if (hd->type!=s_string || hd1->type!=s_matrix || hd2->type!=s_real || hd3->type!=s_real || dimsof(hd1)->r!=1 || dimsof(hd1)->c<2) wrong_arg_in("nelder"); n=dimsof(hd1)->c; m=matrixof(hd1); p=(double **)malloc((n+1)*sizeof(double *)); for (i=0; i<=n; i++) p[i]=(double *)malloc(n*sizeof(double)); y=(double *)malloc((n+1)*sizeof(double)); ptry=(double *)malloc(n*sizeof(double)); fname=stringof(hd); for (j=0; j1) { if (argx->type!=s_matrix || dimsof(argx)->r!=1 || dimsof(argx)->c!=n) { error=1; return; } m=matrixof(argx); } else { if (argx->type!=s_real) { error=1; return; } m=realof(argx); } for (i=0; i0) { h=args; while (h<(header *)newram) { argn++; h=nextof(h); } } hd=getvalue(hd); if (error) return; hdx1=getvalue(hdx1); if (error) return; hdx2=getvalue(hdx2); if (error) return; hdn=getvalue(hdn); if (error) return; hdy=getvalue(hdy); if (error) return; if (hd->type!=s_string || hdx1->type!=s_real || hdx2->type!=s_real || ((hdy->type!=s_matrix || dimsof(hdy)->r!=1) && hdy->type!=s_real) || hdn->type!=s_real) wrong_arg_in("runge1"); if (hdy->type!=s_real) { my=matrixof(hdy); n=dimsof(hdy)->c; } else { my=realof(hdy); n=1; } if (n<1) wrong_arg_in("runge1"); steps=(int)*realof(hdn); if (steps<1) steps=1; fname=stringof(hd); y=(double *)malloc(n*sizeof(double)); for (i=0; itype==s_matrix) { result=new_matrix(1,n,""); if (error) goto stop; m=matrixof(result); for (i=0; ib) return a; else return b; } static void rkck(double y[], double dydx[], int n, double x, double h, double yout[], double yerr[], char *fname, int argn, header *args, long size) { double *ytemp=ytemp1; int i; static double a2=0.2,a3=0.3,a4=0.6,a5=1.0,a6=0.875,b21=0.2, b31=3.0/40.0,b32=9.0/40.0,b41=0.3,b42 = -0.9,b43=1.2, b51 = -11.0/54.0, b52=2.5,b53 = -70.0/27.0,b54=35.0/27.0, b61=1631.0/55296.0,b62=175.0/512.0,b63=575.0/13824.0, b64=44275.0/110592.0,b65=253.0/4096.0,c1=37.0/378.0, c3=250.0/621.0,c4=125.0/594.0,c6=512.0/1771.0, dc5 = -277.0/14336.0; double dc1=c1-2825.0/27648.0,dc3=c3-18575.0/48384.0, dc4=c4-13525.0/55296.0,dc6=c6-0.25; for (i=0; i 1.0) { h=SAFETY*h*pow(errmax,PSHRNK); if (h < 0.1*h) h *= 0.1; xnew=(*x)+h; if (xnew == *x) { output("Stepsize underflow in runge2\n"); error=1; return; } } else { if (errmax > ERRCON) *hnext=SAFETY*h*pow(errmax,PGROW); else *hnext=5.0*h; *x += (*hdid=h); for (i=0; i 0.0) h=b-x; rkqs(y,dydx,n,&x,h,eps,yscal,&hdid,&hnext, fname,argn,args,size); if ((x-b)*(b-a) >= -fabs(hnext*0.0001)) { for (i=0; i0) { h=args; while (h<(header *)newram) { argn++; h=nextof(h); } } hd=getvalue(hd); if (error) return; hdx1=getvalue(hdx1); if (error) return; hdx2=getvalue(hdx2); if (error) return; hdeps=getvalue(hdeps); if (error) return; hdstep=getvalue(hdstep); if (error) return; hdy=getvalue(hdy); if (error) return; if (hd->type!=s_string || hdx1->type!=s_real || hdx2->type!=s_real || ((hdy->type!=s_matrix || dimsof(hdy)->r!=1) && hdy->type!=s_real) || hdeps->type!=s_real || hdstep->type!=s_real) wrong_arg_in("runge2"); if (hdy->type!=s_real) { my=matrixof(hdy); n=dimsof(hdy)->c; } else { my=realof(hdy); n=1; } if (n<1) wrong_arg_in("runge2"); fname=stringof(hd); y=(double *)malloc(n*sizeof(double)); for (i=0; itype==s_matrix) { result=new_matrix(1,n,""); if (error) goto stop; m=matrixof(result); for (i=0; i