|
|
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.