|
|
1.1 root 1: subroutine Buram(npts,mesh,fn,m,n,p,q,delk)
2: integer npts,m,n;
3: real mesh(npts),fn(npts),p(1),q(1),delk;
4:
5: # Buram is a double precision subroutine which finds a
6: # a rational function which is the best approximation,
7: # in the uniform or minimax sense, to a given discrete
8: # function. The rational function is represented as
9: # the quotient of two polynomials each expanded in terms
10: # of Tchebychev polynomials. This routine is a shell
11: # which in turn calls the routine Burm1 with certain
12: # default values for the initial approximation and for
13: # the stopping criteria.
14:
15: # Input:
16: # npts - the number of mesh points.
17: # mesh - the array of mesh points.
18: # fn - the array of function values.
19: # m - the degree of the desired numerator polynomial.
20: # n - the degree of the desired denominator polynomial.
21:
22: # Output:
23: # p - the array of coefficients for the numerator polynomial.
24: # q - the array of coefficients for the denominator polynomial.
25: # delk - the maximum error in the approximation.
26:
27: # Error States (asterisk indicates recoverable):
28: # 1 - invalid degree
29: # 2 - too few mesh points
30: # 3 - mesh is not strictly monotone
31: # 4* - approximation equals function
32: # 5* - no improvement in approximation
33: # 6* - reached 50 iterations
34:
35: integer nitr,maxitr,itol,Nerror,ier;
36: real fnmax,fnmin;
37: logical Smonor;
38: common /dfccom/ nitr;
39:
40: call Enter(1);
41: if (m<0 | n<0)
42: call Seterr(" Buram - invalid degree",23,1,2);
43: if (npts < m+n+2)
44: call Seterr(" Buram - too few mesh points",28,2,2);
45: if (!(Smonor(mesh,npts,1)))
46: call Seterr(" Buram - mesh is not strictly monotone",38,3,2);
47:
48: # Initialize the numerator and demoninator polynomials.
49: fnmax = fn(1); fnmin = fn(1);
50: do i=2,npts
51: {
52: if (fnmax < fn(i))
53: fnmax = fn(i);
54: else if (fn(i) < fnmin)
55: fnmin = fn(i);
56: }
57: call Setr(m+1,0.0e0,p); p(1) = 0.5e0*(fnmax + fnmin);
58: call Setr(n+1,0.0e0,q); q(1) = 1.0e0
59: delk = fnmax - p(1); nitr = 0;
60:
61: if (! (m==0 & n==0))
62: {
63: maxitr = 50; itol = 2;
64: call Burm1(npts,mesh,fn,maxitr,itol,m,n,p,q,delk);
65: if (nerror(ier)!=0)
66: {
67: if (ier == 7)
68: call Newerr(" Buram - approximation equals function",39,4,1);
69: else if (ier == 8)
70: call Newerr(" Buram - no improvement in approximation",40,5,1);
71: else if (ier == 9)
72: call Newerr(" Buram - reached 50 iterations",30,6,1);
73: else
74: call Eprint;
75: }
76: }
77: call Leave;
78: return
79: end
80: subroutine Burm1(npts,mesh,fn,maxitr,itol,m,n,p,q,delk)
81: integer npts,maxitr,itol,m,n;
82: real mesh(npts),fn(npts),p(1),q(1),delk;
83:
84: # Burm1 is a double precision subroutine which finds a
85: # a rational function which is the best approximation,
86: # in the uniform or minimax sense, to a given discrete
87: # function. The rational function is represented as
88: # the quotient of two polynomials each expanded in terms
89: # of Tchebychev polynomials. This routine starts from an
90: # initial approximation and terminates for one of four
91: # reasons: (1) the error curve equioscillates and the
92: # alternating extrema match to ITOL digits, (2) the number
93: # of iterations exceeds MAXITR, (3) the approximation
94: # cannot be improved, or (4) the approximation is essentially
95: # equal to the given discrete function.
96:
97: # Input:
98: # npts - the number of mesh points.
99: # mesh - the array of mesh points.
100: # fn - the array of function values.
101: # maxitr - the maximum number of iterations.
102: # itol - the number of digits to which the extrema should match.
103: # m - the degree of the desired numerator polynomial.
104: # n - the degree of the desired denominator polynomial.
105: # p - the array of coefficients for the initial numerator.
106: # q - the array of coefficients for the initial denominator.
107:
108: # Output:
109: # p - the array of coefficients for the numerator polynomial.
110: # q - the array of coefficients for the denominator polynomial.
111: # delk - the maximum error in the approximation.
112:
113: # Error States (asterisk indicates recoverable):
114: # 1 - invalid degree
115: # 2 - too few mesh points
116: # 3 - mesh is not strictly monotone
117: # 4 - maxitr .lt. 0
118: # 5 - invalid accuracy request
119: # 6 - denominator is nonpositive
120: # 7* - approximation equals function
121: # 8* - no improvement in approximation
122: # 9* - reached maximum no. of iterations
123:
124: integer idig,Iflr,I1mach,Istkgt,npptr,nqptr,enptr,qkptr,iexptr;
125: real R1mach,Float,qlrg;
126: logical Smonor;
127:
128: common /cstak/ dstak(500)
129: long real dstak
130: integer istak(1000)
131: real ws(1000)
132:
133: equivalence dstak,istak
134: equivalence dstak,ws
135: call Enter(1);
136: if (m<0 | n<0)
137: call Seterr(" Burm1 - invalid degree",23,1,2);
138: if (npts < m+n+2)
139: call Seterr(" Burm1 - too few mesh points",28,2,2);
140: if (!(Smonor(mesh,npts,1)))
141: call Seterr(" Burm1 - mesh is not strictly monotone",38,3,2);
142: if (maxitr < 0)
143: call Seterr(" Burm1 - maxitr .lt. 0",22,4,2);
144: idig = Iflr(R1mach(5)*Float(I1mach(11)));
145: if (itol < 1 | idig < itol)
146: call Seterr(" Burm1 - invalid accuracy request",36,5,2);
147: qlrg = Abs(q(1));
148: for (j=2, j<=n+1, j=j+1)
149: if (qlrg < abs(q(j)))
150: qlrg = abs(q(j));
151: if (qlrg == 0.e0)
152: call Seterr(" Burm1 - denominator is nonpositive",35,6,2)
153: else
154: {
155: for (j=1, j<=n+1, j=j+1)
156: q(j) = q(j)/qlrg;
157: for (j=1, j<=m+1, j=j+1)
158: p(j) = p(j)/qlrg;
159: }
160:
161: npptr = Istkgt(m+1,3);
162: nqptr = Istkgt(n+1,3);
163: enptr = Istkgt(npts,3);
164: qkptr = Istkgt(npts,3);
165: iexptr = Istkgt(npts,2);
166:
167: call B1rm1(npts,mesh,fn,maxitr,itol,m,n,p,q,delk,ws(npptr),ws(nqptr),
168: ws(enptr),ws(qkptr),istak(iexptr));
169:
170: call Leave;
171: return;
172: end
173: subroutine B1rm1(npts,x,fn,maxitr,itol,m,n,p,q,delk,newp,newq,en,qk,iext)
174: integer npts,maxitr,itol,m,n,iext(npts);
175: real x(npts),fn(npts),p(1),q(1),delk,newp(1),newq(1),
176: en(npts),qk(npts);
177:
178: integer nitr,nex,imax,imin,ilrg,Lrgex ,Nerror,ier;
179: real eps,bnd,R1mach,delnew;
180: common /dfccom/ nitr;
181:
182: eps = R1mach(4)*10.0e0**itol;
183: call Extrmr(npts,fn,nex,iext,imax,imin,ilrg);
184: bnd = Abs(fn(ilrg))*eps;
185:
186: call Enqk(npts,x,fn,m,n,p,q,qk,en);
187: do i=1,npts
188: if (qk(i) <= 0.0e0)
189: call Seterr(" Burm1 - denominator is nonpositive",35,6,2);
190:
191: call Extrmr(npts,en,nex,iext,imax,imin,ilrg);
192: delk = Abs(en(ilrg)); delnew = delk;
193: call Movefr(m+1,p,newp); call Movefr(n+1,q,newq);
194:
195: for (nitr=0, nitr<maxitr, nitr=nitr+1)
196: {
197: # call Outpt3 (x,npts,p,q,delk,m,n,en,iext,nex)
198: if (delk <= bnd)
199: {
200: call Seterr(" Burm1 - approximation equals function",39,7,1);
201: return;
202: }
203: # Test for optimal solution.
204: if (Lrgex (npts,en,nex,iext,ilrg,itol) >= m+n+2)
205: return;
206:
207: call Lpstp(npts,x,fn,qk,delnew,m,n,newp,newq)
208: if (Nerror(ier) != 0)
209: call Erroff;
210:
211: call Enqk(npts,x,fn,m,n,newp,newq,qk,en);
212: call Extrmr(npts,en,nex,iext,imax,imin,ilrg);
213: delnew = Abs(en(ilrg));
214: if (delk <= delnew)
215: {
216: call Seterr(" Burm1 - no improvement in approximation",40,8,1);
217: return;
218: }
219: call Movefr(m+1,newp,p); call Movefr(n+1,newq,q);
220: delk = delnew;
221: }
222: call Seterr(" Burm1 - reached maximum no. of iterations",42,9,1);
223:
224: return;
225: end
226: subroutine Enqk( npts,X,fn,m,n,p,q,Qk,en)
227: integer npts,m,n;
228: real X(npts),fn(npts),p(1),q(1),Qk(npts),en(npts);
229: #
230: # Subroutine Enqk computes en & Qk.
231: # en=error values at mesh points.
232: # Qk=value of denominator polynomial at mesh points.
233: #
234: real Tchbp,Pk;
235: if (npts<=0 | m<0 | n<0)
236: call seterr ("enQk-invalid dimension",22,1,2)
237: do i=1,npts
238: {
239: Qk(i)=Tchbp(n,q,X(i),X(1),X(npts))
240: if (Qk(i)==0.e0)
241: call seterr ("enQk-divisor .eq. 0.",20,2,2)
242: Pk=Tchbp(m,p,X(i),X(1),X(npts))
243: en(i)=(fn(i)*Qk(i)-Pk)/Qk(i)
244: }
245: return
246: end
247: integer function Lrgex (npts,en,nex,iext,ilrg,tol)
248: #
249: # Function Lrgex finds the no. of error extrema with magnitudes
250: # within tolerance of magnitude of largest error.
251: #
252: integer npts,nex,iext(nex),ilrg,j,k,L,tol
253: real en(npts),hold
254: if (npts<=0)
255: call Seterr ("Lrgex -invalid dimension",24,1,2)
256: if (nex<=0 | ilrg<=0)
257: call Seterr ("Lrgex -invalid index",20,2,2)
258: k=0
259: do j=1,nex
260: {
261: L=iext(j)
262: hold=Abs(en(ilrg))-Abs(en(L))
263: if (hold<=10.**(-tol)*Abs(en(ilrg)))
264: k=k+1
265: }
266: Lrgex =k
267: return
268: end
269: subroutine Lpstp(npts,mesh,fn,Qk,delk,m,n,p,q)
270: integer npts,m,n;
271: real mesh(npts),fn(npts),Qk(npts),delk,p(1),q(1);
272:
273: # Lpstp defines the linear programming subproblem of the
274: # Differential Correction algorithm. It also provides
275: # the interface to the general purpose linear programming
276: # package.
277:
278: # Input:
279: # npts - the number of mesh points.
280: # mesh - the array of mesh points.
281: # fn - the array of function values.
282: # Qk - the array of current denominator values.
283: # delk - the current minimax error.
284: # m - the degree of the numerator polynomial.
285: # n - the degree of the denominator polynomial.
286: # p - the current numerator polynomial.
287: # q - the current denominator polynomial.
288:
289: # Output:
290: # p - the array of coefficients for the numerator polynomial.
291: # q - the array of coefficients for the denominator polynomial.
292:
293: # Error States (asterisk indicates fatal):
294: # 1* - invalid degree
295: # 2* - too few mesh points
296: # 3* - nonpositive delk
297: # 4 - no improvement in the lp subproblem
298:
299: integer aptr,bptr,cptr,xptr;
300:
301: common /cstak/ dstak(500)
302: long real dstak
303: integer istak(1000)
304: real ws(1000)
305:
306: equivalence dstak,istak
307: equivalence dstak,ws
308:
309: call Enter(1);
310: if (m<0 | n<0)
311: call Seterr(" Lpstp - invalid degree",23,1,2);
312: if (npts < m+n+2)
313: call Seterr(" Lpstp - too few mesh points",28,2,2);
314:
315: aptr = Istkgt((3*npts+1),3);
316: bptr = Istkgt((2*(npts+n+1)),3);
317: cptr = Istkgt((m+n+3),3);
318: xptr = Istkgt((m+n+3),3);
319:
320: call L9stp(npts,mesh,fn,Qk,delk,m,n,p,q,ws(aptr),ws(bptr),
321: ws(cptr),ws(xptr));
322:
323: call Leave;
324: return;
325: end
326: subroutine L9stp(npts,mesh,fn,Qk,delk,m,n,p,q,A,B,C,X)
327: integer npts,m,n;
328: real mesh(npts),fn(npts),Qk(npts),delk,p(1),q(1),
329: A(1),B(1),C(1),X(1);
330:
331: integer nptsc,mc,nc,i1,i2,i3,i4,mm,nn,Nerror,ierr;
332: real ctx,ctxnew,qlrg,Float,R1mach;
333: external Difmt;
334: common /difcom/ nptsc,mc,nc,i1,i2,i3,i4;
335:
336:
337: nptsc = npts; mc = m;
338: nc = n;
339: i1 = npts; i2 = i1 + npts;
340: i3 = i2 + n + 1; i4 = i3 + n + 1;
341: mm = i4; nn = m+n+3;
342:
343: call Movefr(n+1,q,X); call Movefr(m+1,p,X(n+2));
344: X(nn) = 0.e0;
345: call Setr(i2,0.0e0,B); call Setr((i4-i2),-1.0e0,B(i2+1));
346: call Setr(nn,0.0e0,C); C(nn) = -1.0e0;
347: call Movefr(npts,mesh,A); call Movefr(npts,fn,A(npts+1));
348: call Movefr(npts,Qk,A(2*npts+1));
349: if (delk <= 0.0e0)
350: call Seterr(" Lpstp - nonpositive delk",25,3,2)
351: A(3*npts+1) = delk; ctx = 0.0e0;
352:
353: # Solve the LP problem: max C(T)X subject to AX >= B.
354: # The subroutine Difmt derives the matrix A from
355: # the data stored in the array A.
356:
357: call Lpph2(A,mm,nn, Difmt,B,C,X,4*mm,ctxnew)
358: if (Nerror(ier) != 0)
359: call Erroff;
360: if (ctx < ctxnew)
361: {
362: qlrg = 0.0e0;
363: for (j=1, j<=n+1, j=j+1)
364: if (qlrg < abs(X(j))) qlrg = abs(X(j));
365: for (j=1, j<=n+1, j=j+1)
366: q(j) = X(j)/qlrg;
367: i = 0;
368: for (j=n+2, j<=m+n+2, j=j+1)
369: {
370: i = i+1; p(i) = X(j)/qlrg;
371: }
372: }
373: else
374: call Seterr(" Lpstp - no improvement in the lp subproblem",44,4,1);
375:
376: return;
377: end
378: subroutine Difmt(inprod,A,mm,nn,irow,X,dinprd)
379: integer mm,nn,irow;
380: real A(1),X(nn),dinprd;
381: logical inprod;
382:
383: # Difmt handles references by the LP routine to
384: # the matrix for the linear programming subproblem.
385:
386: integer npts,m,n,i1,i2,i3,i4,irm1,irm2,irm3,zptr,
387: fnptr,qzptr,jp,maxmn;
388: real fct,fdelk,delk,z,fn,qz,Tchbp;
389: common /difcom/ npts,m,n,i1,i2,i3,i4;
390:
391: call Enter(1);
392: if (mm != i4 | nn ~= m+n+3)
393: call Seterr(" Difmt - invalid dimension",26,1,2)
394: if (irow<0 | mm<irow)
395: call Seterr(" Difmt - invalid index",22,2,2)
396:
397: irm1 = irow - i1;
398: irm2 = irow - i2;
399: irm3 = irow - i3;
400: if (inprod & i2 < irow)
401: {
402: if (i3 < irow)
403: dinprd = -X(irm3);
404: else
405: dinprd = X(irm2);
406: }
407: else if (i2 < irow)
408: {
409: call Setr(nn,0.0e0,X);
410: if (i3 < irow)
411: X(irm3) = -1.0e0;
412: else
413: X(irm2) = 1.0e0;
414: }
415: else
416: {
417: if (i1 < irow)
418: {
419: fct = -1.0e0; zptr = irm1;
420: }
421: else
422: {
423: fct = 1.0e0; zptr = irow;
424: }
425: z = A(zptr);
426: fnptr = zptr+npts; fn = A(fnptr);
427: qzptr = fnptr+npts; qz = A(qzptr);
428: delk = A(3*npts+1); fdelk = fct*fn + delk;
429: if ( inprod )
430: dinprd = fdelk*Tchbp(n,X,z,A(1),A(npts)) -
431: fct*Tchbp(m,X(n+2),z,A(1),A(npts)) + qz*X(nn);
432: else
433: {
434: maxmn = Max0(m,n);
435: call Tchcf(z,A(1),A(npts),maxmn,X);
436: for (j=m+1, 1<=j, j=j-1)
437: {
438: jp = j+n+1; X(jp) = -fct*X(j);
439: }
440: for (j=1, j<=n+1, j=j+1)
441: X(j) = fdelk*X(j);
442: X(nn) = qz;
443: }
444: }
445: call Leave;
446: return;
447: end
448: subroutine Tchcf (x,a,b,deg,XX)
449: #
450: # Subroutine Tchcf computes the deg+1 Tchebycheff
451: # coefficients of the point x.
452: #
453: integer deg,i
454: real a,b,twoxx,x,XX(1)
455: call enter(1)
456: if (deg<0)
457: call seterr (" Tchcf-invalid degree",21,1,2)
458: XX(1)=1.e0
459: if (deg>0)
460: if (b<=a)
461: call seterr (" Tchcf-invalid interval",23,2,2)
462: else #scale x to the interval (-1.e0,1.e0)
463: XX(2)=2.e0*(x-(a+b)/2.e0)/(b-a)
464: if (deg>1)
465: twoxx=2.e0*XX(2)
466: for (i=3,i<=deg+1,i=i+1)
467: XX(i)=twoxx*XX(i-1)-XX(i-2)
468: call leave
469: return
470: end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.