      real function smooth ( x, y, dy, npoint, s, v, a )
c  from  * a practical guide to splines *  by c. de boor    
calls  setupq, chol1d
c
c  constructs the cubic smoothing spline  f  to given data  (x(i),y(i)),
c  i=1,...,npoint, which has as small a second derivative as possible
c  while
c  s(f) = sum( ((y(i)-f(x(i)))/dy(i))**2 , i=1,...,npoint ) .le. s .
c
c******  i n p u t  ******
c  x(1),...,x(npoint)   data abscissae,  a s s u m e d  to be strictly
c        increasing .
c  y(1),...,y(npoint)     corresponding data ordinates .
c  dy(1),...,dy(npoint)     estimate of uncertainty in data,  a s s u m-
c        e d  to be positive .
c  npoint.....number of data points,  a s s u m e d  .gt. 1
c  s.....upper bound on the discrete weighted mean square distance of
c        the approximation  f  from the data .
c
c******  w o r k  a r r a y s  *****
c  v.....of size (npoint,7)
c  a.....of size (npoint,4)
c
c*****  o u t p u t  *****
c  a(.,1).....contains the sequence of smoothed ordinates .
c  a(i,j) = f^(j-1)(x(i)), j=2,3,4, i=1,...,npoint-1 ,  i.e., the
c        first three derivatives of the smoothing spline  f  at the
c        left end of each of the data intervals .
c     w a r n i n g . . .   a  would have to be transposed before it
c        could be used in  ppvalu .
c
c******  m e t h o d  ******
c     The matrices  Q-transp*d  and  Q-transp*D**2*Q  are constructed in
c   s e t u p q  from  x  and  dy , as is the vector  qty = Q-transp*y .
c  Then, for given  p , the vector  u  is determined in  c h o l 1 d  as
c  the solution of the linear system
c               (6(1-p)Q-transp*D**2*Q + p*Q)u  = qty  .
c  From  u , the smoothing spline  f  (for this choice of smoothing par-
c  ameter  p ) is obtained in the sense that
c                        f(x(.))  =  y - 6(1-p)D**2*Q*u        and
c                      f''(x(.))  =  6*p*u                      .
c     The smoothing parameter  p  is found (if possible) so that
c                sf(p)  =  s ,
c  with  sf(p) = s(f) , where  f  is the smoothing spline as it depends
c  on  p .  if  s = 0, then p = 1 . if  sf(0) .le. s , then p = 0 .
c  Otherwise, the secant method is used to locate an appropriate  p  in
c  the open interval  (0,1) . However, straightforward application of
c  the secant method, as done in the original version of this program,
c  can be very slow and is influenced by the units in which  x  and  y 
c  are measured, as C. Reinsch has pointed out. Instead, on recommend-
c  ation from C. Reinsch, the secant method is applied to the function
c           g:q |--> 1/sqrt{sfq(q)} - 1/sqrt{s} ,
c  with  sfq(q) := sf(q/(1+q)), since  1/sqrt{sfq}  is monotone increasing
c  and close to linear for larger  q . One starts at  q = 0  with a
c  Newton step, i.e., 
c                q_0 = 0,  q_1 = -g(0)/g'(0)
c  with  g'(0) = -(1/2) sfq(0)^{-3/2} dsfq, where dsfq = -12*u-transp*r*u ,
c  and  u  as obtained for  p = 0 . Iteration terminates as soon as 
c   abs(sf - s) .le. .01*s .
c
c     logical test 
c     parameter (test = .true.)
c     integer itercnt
      integer npoint,   i,npm1
      real a(npoint,4),dy(npoint),s,v(npoint,7),x(npoint),y(npoint)
     *     ,change,ooss,oosf,p,prevsf,prevq,q,sfq,sixp,six1mp,utru
      call setupq(x,dy,y,npoint,v,a(1,4))
      if (s .gt. 0.)                    go to 20
   10 p = 1.
      six1mp = 0.
      call chol1d(p,v,a(1,4),npoint,1,a(1,3),a(1,1))
      sfq = 0.
                                        go to 60
   20 p = 0.
      six1mp = 6.
      call chol1d(p,v,a(1,4),npoint,1,a(1,3),a(1,1))
      sfq = 0.
      do 21 i=1,npoint
   21    sfq = sfq + (a(i,1)*dy(i))**2
      sfq = sfq*36.
      if (sfq .le. s)                   go to 60
      utru = 0.
      do 25 i=2,npoint
   25    utru = utru + v(i-1,4)*(a(i-1,3)*(a(i-1,3)+a(i,3))+a(i,3)**2)
      ooss = 1./sqrt(s)
      oosf = 1./sqrt(sfq)
      q = -(oosf-ooss)*sfq/(6.*utru*oosf)
c  secant iteration for the determination of p starts here.
c     itercnt = 0
      prevq = 0.
      prevsf = oosf
   30 call chol1d(q/(1.+q),v,a(1,4),npoint,1,a(1,3),a(1,1))
      sfq = 0.
      do 35 i=1,npoint
   35    sfq = sfq + (a(i,1)*dy(i))**2
      sfq = sfq*36./(1.+q)**2
      if (abs(sfq-s) .le. .01*s)        go to 59
      oosf = 1./sqrt(sfq)
      change = (q-prevq)/(oosf-prevsf)*(oosf-ooss)
      prevq = q
      q = q - change
      prevsf = oosf
c     itercnt = itercnt + 1
                                        go to 30
   59 p = q/(1.+q)
      six1mp = 6./(1.+q)
correct value of p has been found.
compute pol.coefficients from  Q*u (in a(.,1)).
   60 smooth = sfq
c     if (test) then
c        print *, 'number of iterations = ', itercnt
c     end if
      do 61 i=1,npoint
   61    a(i,1) = y(i) - six1mp*dy(i)**2*a(i,1)
      sixp = 6.*p
      do 62 i=1,npoint
   62    a(i,3) = a(i,3)*sixp
      npm1 = npoint - 1
      do 63 i=1,npm1
         a(i,4) = (a(i+1,3)-a(i,3))/v(i,4)
   63    a(i,2) = (a(i+1,1)-a(i,1))/v(i,4)
     *                      - (a(i,3)+a(i,4)/3.*v(i,4))/2.*v(i,4)
                                        return
      end
