Annotation of 41BSD/cmd/efl/efltest/Buram.e, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.