#include #include #include #include #include #include "polynom.h" #include "funcs.h" #include "interval.h" #include "linear.h" #include "express.h" #include "output.h" #include "spread.h" #include "mainloop.h" #define wrong_arg() { error=26; output("Wrong argument\n"); return; } #define max(x,y) ((x)>(y)?(x):(y)) double *polynom; int degree; void peval (double *x, double *r) { int i; double *p=polynom+degree,res; res=*p--; for (i=degree-1; i>=0; i--) res=res**x+(*p--); *r=res; } static void cpeval (double *x, double *xi, double *z, double *zi) { int i; double *p,h,hi; p=polynom+(2l*degree); *z=*p; *zi=*(p+1); p-=2; for (i=degree-1; i>=0; i--) { complex_multiply(x,xi,z,zi,&h,&hi); *z= h + *p; *zi=hi+*(p+1); p-=2; } } void polyval (header *hd) { header *st=hd,*hd1,*result; int r,c; hd1=nextof(hd); equal_params_2(&hd,&hd1); getmatrix(hd,&r,&c,&polynom); if (r!=1) wrong_arg(); degree=c-1; if (degree<0) wrong_arg(); if (isinterval(hd)) result=map1i(ipeval,hd1); else result=map1(peval,cpeval,hd1); moveresult(st,result); } void polyadd (header *hd) { header *st=hd,*hd1,*result; int c,c1,c2,i,r; double *m1,*m2,*mr; complex *mc1,*mc2,*mcr; interval *mi1,*mi2,*mir; hd1=next_param(st); equal_params_2(&hd,&hd1); if (error) return; getmatrix(hd,&r,&c1,&m1); if (r!=1) wrong_arg(); getmatrix(hd1,&r,&c2,&m2); if (r!=1) wrong_arg(); c=max(c1,c2); if (iscomplex(hd)) /* complex values */ { mc1=(complex *)m1; mc2=(complex *)m2; result=new_cmatrix(1,c,""); if (error) return; mcr=(complex *)matrixof(result); for (i=0; i=c1) { c_copy(*mcr,*mc2); mcr++; mc2++; } else if (i>=c2) { c_copy(*mcr,*mc1); mcr++; mc1++; } else { c_add(*mc1,*mc2,*mcr); mc1++; mc2++; mcr++; } } } else if (isinterval(hd)) { mi1=(interval *)m1; mi2=(interval *)m2; result=new_imatrix(1,c,""); if (error) return; mir=(interval *)matrixof(result); for (i=0; i=c1) { i_copy(*mir,*mi2); mir++; mi2++; } else if (i>=c2) { i_copy(*mir,*mi1); mir++; mi1++; } else { i_add(*mi1,*mi2,*mir); mi1++; mi2++; mir++; } } } else if (isreal(hd)) { result=new_matrix(1,c,""); if (error) return; mr=matrixof(result); for (i=0; i=c1) { *mr++ = *m2++; } else if (i>=c2) { *mr++ = *m1++; } else { *mr++ = *m1++ + *m2++; } } } else wrong_arg(); moveresult(st,result); } void polymult (header *hd) { header *st=hd,*hd1,*result; int c,c1,c2,i,r,j,k; double *m1,*m2,*mr,x; complex *mc1,*mc2,*mcr,xc,hc; interval *mi1,*mi2,*mir,xi,hi; hd1=next_param(st); equal_params_2(&hd,&hd1); if (error) return; getmatrix(hd,&r,&c1,&m1); if (r!=1) wrong_arg(); getmatrix(hd1,&r,&c2,&m2); if (r!=1) wrong_arg(); if ((long)c1+c2-1>INT_MAX) wrong_arg(); c=c1+c2-1; if (iscomplex(hd)) { mc1=(complex *)m1; mc2=(complex *)m2; result=new_cmatrix(1,c,""); if (error) return; mcr=(complex *)matrixof(result); c_copy(xc,*mc1); mc1++; for (i=0; i=0; i--) { c_div(mch[c2+i-1],lc,xc); c_copy(mcr[i],xc); for(j=0; j=0.0) wrong_arg(); for (i=c1-c2; i>=0; i--) { i_div(mih[c2+i-1],li,xi); c_copy(mir[i],xi); for(j=0; j=0; i--) { x=mh[c2+i-1]/l; mr[i]=x; for(j=0; j=i; j--) { if (mc1[j][0]==mc1[j-i][0] && mc1[j][1]==mc1[j-i][1]) wrong_arg(); c_sub(mcr[j],mcr[j-1],hc1); c_sub(mc1[j],mc1[j-i],hc2); c_div(hc1,hc2,mcr[j]); } } } else if (isinterval(hd)) /* complex values */ { mi1=(complex *)m1; mi2=(complex *)m2; result=new_imatrix(1,c1,""); if (error) return; mir=(interval *)matrixof(result); memmove((char *)mir,(char *)mi2,c1*sizeof(interval)); for (i=1; i=i; j--) { i_sub(mir[j],mir[j-1],hi1); if (hi1[0]<=0 && hi1[1]>=0) { output("Interval points coincide\n"); error=1; return; } i_sub(mi1[j],mi1[j-i],hi2); i_div(hi1,hi2,mir[j]); } } } else if (isreal(hd)) { result=new_matrix(1,c1,""); if (error) return; mr=matrixof(result); memmove((char *)mr,(char *)m2,c1*sizeof(double)); for (i=1; i=i; j--) { if (m1[j]==m1[j-i]) wrong_arg(); mr[j]=(mr[j]-mr[j-1])/(m1[j]-m1[j-i]); } } } else wrong_arg(); moveresult(st,result); } double *divx,*divdif; static void rddeval (double *x, double *r) { int i; double *p=divdif+degree,res; res=*p--; for (i=degree-1; i>=0; i--) res=res*(*x-divx[i])+(*p--); *r=res; } static void cddeval (double *x, double *xi, double *z, double *zi) { int i; double *p,h,hi,*dd,xh,xhi; p=divdif+(2l*degree); dd=divx+(2l*(degree-1)); *z=*p; *zi=*(p+1); p-=2; for (i=degree-1; i>=0; i--) { xh=*x-*dd; xhi=*xi-*(dd+1); dd-=2; complex_multiply(&xh,&xhi,z,zi,&h,&hi); *z= h + *p; *zi=hi+*(p+1); p-=2; } } void ddval (header *hd) { header *st=hd,*hdd,*hd1,*result; int r,c,cd; hdd=nextof(st); hd1=nextof(hdd); equal_params_3(&hd,&hdd,&hd1); if (error) return; getmatrix(hd,&r,&c,&divx); if (r!=1 || c<1) wrong_arg(); getmatrix(hdd,&r,&cd,&divdif); if (r!=1 || c!=cd) wrong_arg(); degree=c-1; if (isinterval(hd)) result=map1i(iddeval,hd1); else result=map1(rddeval,cddeval,hd1); if (error) return; moveresult(st,result); } void polyzeros (header *hd) { header *st=hd,*result; int i,j,r,c; double *m,*mr,x; complex *mc,*mcr,xc,hc; hd=getvalue(hd); if (error) return; if (hd->type==s_real || hd->type==s_matrix) { getmatrix(hd,&r,&c,&m); if (r!=1) wrong_arg(); result=new_matrix(1,c+1,""); if (error) return; mr=matrixof(result); mr[0]=-m[0]; mr[1]=1.0; for (i=1; i=1; j--) mr[j]=mr[j-1]+x*mr[j]; mr[0]*=x; } } else if (hd->type==s_complex || hd->type==s_cmatrix) { getmatrix(hd,&r,&c,&m); mc=(complex *)m; if (r!=1) wrong_arg(); result=new_cmatrix(1,c+1,""); if (error) return; mcr=(complex *)matrixof(result); mcr[0][0]=-mc[0][0]; mcr[0][1]=-mc[0][1]; mcr[1][0]=1.0; mcr[1][1]=0.0; for (i=1; i=1; j--) { c_mult(xc,mcr[j],hc); c_add(hc,mcr[j-1],mcr[j]); } c_mult(xc,mcr[0],mcr[0]); } } else wrong_arg(); moveresult(st,result); } void polydd (header *hd) { header *st=hd,*hd1,*result; int c1,c2,i,j,r; double *m1,*m2,*mr,x; complex *mc1,*mc2,*mcr,hc,xc; hd1=next_param(st); equal_params_2(&hd,&hd1); if (error) return; getmatrix(hd,&r,&c1,&m1); if (r!=1) wrong_arg(); getmatrix(hd1,&r,&c2,&m2); if (r!=1) wrong_arg(); if (c1!=c2) wrong_arg(); if (iscomplex(hd)) /* complex values */ { mc1=(complex *)m1; mc2=(complex *)m2; result=new_cmatrix(1,c1,""); if (error) return; mcr=(complex *)matrixof(result); c_copy(mcr[c1-1],mc2[c1-1]); for (i=c1-2; i>=0; i--) { c_copy(xc,mc1[i]); c_mult(xc,mcr[i+1],hc); c_sub(mc2[i],hc,mcr[i]); for (j=i+1; j=0; i--) { x=m1[i]; mr[i]=m2[i]-x*mr[i+1]; for (j=i+1; jtype==s_matrix && dimsof(hd)->r==1) { m=matrixof(hd); for (i=dimsof(hd)->c-1; i>=0; i--) { if (fabs(m[i])>epsilon) break; } if (i<0) result=new_real(0.0,""); else { result=new_matrix(1,i+1,""); memmove((char *)matrixof(result),(char *)matrixof(hd), (i+1)*sizeof(double)); } } else if (hd->type==s_complex && dimsof(hd)->r==1) { mc=(complex *)matrixof(hd); for (i=dimsof(hd)->c-1; i>=0; i--) { if (fabs(mc[i][0])>epsilon && fabs(mc[i][1])>epsilon) break; } if (i<0) result=new_complex(0.0,0.0,""); else { result=new_cmatrix(1,i+1,""); memmove((char *)matrixof(result),(char *)matrixof(hd), (i+1)*sizeof(complex)); } } else wrong_arg(); moveresult(st,result); } /************** bauhuber algorithm ***************/ #define ITERMAX 200 #define EPS (64*DBL_EPSILON) #define QR 0.1 #define QI 0.8 #define EPSROOT (64*epsilon) #define BETA (2096*EPSROOT) static char *ram; static void quadloes (double ar, double ai, double br, double bi, double cr, double ci, double *treal, double *timag) { double pr,pi,qr,qi,h; pr=br*br-bi*bi; pi=2*br*bi; qr=ar*cr-ai*ci; qi=ar*ci+ai*cr; pr=pr-4*qr; pi=pi-4*qi; h=sqrt(pr*pr+pi*pi); qr=h+pr; if (qr<0.0) qr=0; qr=sqrt(qr/2); qi=h-pr; if (qi<0.0) qi=0; qi=sqrt(qi/2); if (pi<0.0) qi=-qi; h=qr*br+qi*bi; if (h>0.0) { qr=-qr; qi=-qi; } pr=qr-br; pi=qi-bi; h=pr*pr+pi*pi; *treal=2*(cr*pr+ci*pi)/h; *timag=2*(ci*pr-cr*pi)/h; } static int cxdiv (double ar, double ai, double br, double bi, double *cr, double *ci) { double temp; if (br==0.0 && bi==0.0) return 1; if (fabs(br)>fabs(bi)) { temp=bi/br; br=temp*bi+br; *cr=(ar+temp*ai)/br; *ci=(ai-temp*ar)/br; } else { temp=br/bi; bi=temp*br+bi; *cr=(temp*ar+ai)/bi; *ci=(temp*ai-ar)/bi; } return 0; } static double cxxabs (double ar, double ai) { if (ar==0.0) return fabs(ai); if (ai==0.0) return fabs(ar); return sqrt(ai*ai+ar*ar); } static void chorner (int n, int iu, double *ar, double *ai, double xr, double xi, double *pr, double *pi, double *p1r, double *p1i, double *p2r, double *p2i, double *rf1) { register int i,j; int i1; double temp,hh,tempr=0.0,tempi=0.0; *pr=ar[n]; *pi=ai[n]; *p1r=*p2r=0.0; *p1i=*p2i=0.0; *rf1=cxxabs(*pr,*pi); i1=n-iu; for (j=n-iu,i=n-1; i>=iu; i--,j--) { if (itemp) temp=hh; if (temp>*rf1) { *rf1=temp; i1=j-1; } if (i*scal) *scal=h; } ar[n]/=p; ai[n]/=p; if (*scal==0.0) *scal=1.0; for (p=1.0,i=n-1; i>=0; i--) { p*= *scal; ar[i]/=p; ai[i]/=p; } } #endif static void bauroot (int n, int iu, double *ar, double *ai, double *x0r, double *x0i) { int iter=0,i=0,aborted=0; double xoldr,xoldi,xnewr,xnewi,h,h1,h2,h3,h4,dzmax,dzmin, dxr=1,dxi=0,tempr,tempi,abs_pold,abs_pnew,abs_p1new, temp,ss,u,v, pr,pi,p1r,p1i,p2r,p2i,abs_pnoted=-1; dxr=dxi=xoldr=xoldi=0.0; if (n-iu==1) { quadloes(0.0,0.0,ar[n],ai[n], ar[n-1],ai[n-1],x0r,x0i); goto stop; } if (n-iu==2) { quadloes(ar[n],ai[n],ar[n-1],ai[n-1], ar[n-2],ai[n-2],x0r,x0i); goto stop; } xnewr=*x0r; xnewi=*x0i; chorner(n,iu,ar,ai,xnewr,xnewi,&pr,&pi,&p1r,&p1i,&p2r,&p2i,&ss); iter++; abs_pnew=cxxabs(pr,pi); if (abs_pnew==0) goto stop; abs_pold=abs_pnew; dzmin=BETA*(1+cxxabs(xnewr,xnewi)); while (!aborted) { abs_p1new=cxxabs(p1r,p1i); iter++; if (abs_pnew>abs_pold) /* Spiraling */ { i=0; temp=dxr; dxr=QR*dxr-QI*dxi; dxi=QR*dxi+QI*temp; } else /* Newton step */ { dzmax=1.0+cxxabs(xnewr,xnewi); h1=p1r*p1r-p1i*p1i-pr*p2r+pi*p2i; h2=2*p1r*p1i-pr*p2i-pi*p2r; if (abs_p1new>10*ss && cxxabs(h1,h2)>100*ss*ss) /* do a Newton step */ { i++; if (i>2) i=2; tempr=pr*p1r-pi*p1i; tempi=pr*p1i+pi*p1r; cxdiv(-tempr,-tempi,h1,h2,&dxr,&dxi); if (cxxabs(dxr,dxi)>dzmax) { temp=dzmax/cxxabs(dxr,dxi); dxr*=temp; dxi*=temp; i=0; } if (i==2 && cxxabs(dxr,dxi)0) { i=0; cxdiv(xnewr-xoldr,xnewi-xoldi,dxr,dxi,&h3,&h4); h3+=1; h1=h3*h3-h4*h4; h2=2*h3*h4; cxdiv(dxr,dxi,h1,h2,&h3,&h4); if (cxxabs(h3,h4)<50*dzmin) { dxr+=h3; dxi+=h4; } } xoldr=xnewr; xoldi=xnewi; abs_pold=abs_pnew; } else /* saddle point, minimize into direction pr+i*pi */ { i=0; h=dzmax/abs_pnew; dxr=h*pr; dxi=h*pi; xoldr=xnewr; xoldi=xnewi; abs_pold=abs_pnew; do { chorner(n,iu,ar,ai,xnewr+dxr,xnewi+dxi,&u,&v, &h,&h1,&h2,&h3,&h4); dxr*=2; dxi*=2; } while (fabs(cxxabs(u,v)/abs_pnew-1)5) break; if (iter>ITERMAX) { iter=0; if (abs_pnew<=abs_pnoted) break; abs_pnoted=abs_pnew; if (test_key()==escape) { error=700; return; } } } *x0r=xnewr; *x0i=xnewi; stop: ; /* chorner(n,iu,ar,ai,*x0r,*x0i,&pr,&pi,&p1r,&p1i,&p2r,&p2i,&ss); abs_pnew=cxxabs(pr,pi); printf("%20.5e +i* %20.5e, %20.5e\n", *x0r,*x0i,abs_pnew); */ } static void _polydiv (int n, int iu, double *ar, double *ai, double x0r, double x0i) { int i; for (i=n-1; i>iu; i--) { ar[i]+=ar[i+1]*x0r-ai[i+1]*x0i; ai[i]+=ai[i+1]*x0r+ar[i+1]*x0i; } } static void bauhuber (double *p, int n, double *result, int all, double startr, double starti) { double *ar,*ai,scalefak=1.0; int i; double x0r,x0i; ram=newram; if (!freeram(2*(n+1)*sizeof(double))) outofram(); ar=(double *)ram; ai=ar+n+1; for (i=0; i<=n; i++) { ar[i]=p[2*i]; ai[i]=p[2*i+1]; } /* scpoly(n,ar,ai,&scalefak); */ /* scalefak=1; */ x0r=startr; x0i=starti; for (i=0; i<(all?n:1); i++) { bauroot(n,i,ar,ai,&x0r,&x0i); ar[i]=scalefak*x0r; ai[i]=scalefak*x0i; if (error) { output("Bauhuber-Iteration failed!\n"); error=311; return; } _polydiv(n,i,ar,ai,x0r,x0i); x0i=-x0i; } for (i=0; itype==s_matrix) { make_complex(st); if (error) return; hd=getvalue(st); if (error) return; } if (hd->type!=s_cmatrix || dimsof(hd)->r!=1 || dimsof(hd)->c<2) { output("Need a complex polynomial\n"); error=300; return; } getmatrix(hd,&r,&c,&m); result=new_cmatrix(1,c-1,""); if (error) return; bauhuber(m,c-1,matrixof(result),1,0,0); moveresult(st,result); } void mzeros1 (header *hd) { header *st=hd,*hd1,*result; int r,c; double *m,xr,xi; hd1=nextof(hd); hd=getvalue(hd); if (error) return; if (hd->type==s_matrix) { make_complex(st); if (error) return; hd=getvalue(st); if (error) return; } hd1=getvalue(hd1); if (error) return; if (hd1->type==s_real) { xr=*realof(hd1); xi=0; } else if (hd1->type==s_complex) { xr=*realof(hd1); xi=*(realof(hd1)+1); } else { output("Need a starting value!\n"); error=300; return; } if (hd->type!=s_cmatrix || dimsof(hd)->r!=1 || dimsof(hd)->c<2) { output("Need a complex polynomial\n"); error=300; return; } getmatrix(hd,&r,&c,&m); result=new_complex(0,0,""); if (error) return; bauhuber(m,c-1,realof(result),0,xr,xi); moveresult(st,result); }