[Matrix-SIG] Nonlinear optimization routines anyone?

Ryszard Czerminski ryszard@moldyn.com
Tue, 16 Mar 1999 08:09:08 -0500 (EST)


On 15 Mar 1999, Janne Sinkkonen wrote:

> David Ascher <da@ski.org> writes:
> 
> > I suspect that if I knew enough about optimization I could code up
> > the subset that I need, but I'm not sure I'd trust my own code to do
> > this...
> 
> Coding CG or some such with a simple line search is easy enough, but
> getting the line search robust may be more difficult. And robust stuff
> is hard to code also because it may "work" (although suboptimally) even
> with grave errors in the code. :)
> 
> -- 
> Janne

I have coded this up few month ago (based on NR).
It is simple line search (without derivatives though).
It seems to work OK.

Ryszard

def SIGN(a,b):
    if b < 0: return -abs(a)
    else    : return  abs(a)

def SWAP(a,b): return b,a

def mnbrak(ax,bx,cx,fa,fb,fc,func):
#
# brakets minimum of 1D function
# i.e. returns a,b,c values such that fb < min(fa,fb)
#
   GOLD = 1.618034; GLIMIT = 100.; TINY = 1.0e-20; dum = 0.

   fa = func(ax); fb = func(bx)

   if fb > fa:
      ax,bx = SWAP(ax,bx)
      fa,fb = SWAP(fa,fb)

   cx = bx + GOLD*(bx-ax)  # first guess for c
   fc = func(cx)

   #print 'mnbrak> a,b,c,fa,fb,fc = ',ax,bx,cx,fa,fb,fc

   #iter = 0
   while fb > fc:
      #iter = iter + 1
      #print 'mnbrak> iter,a,b,c,fa,fb,fc = ',iter,ax,bx,cx,fa,fb,fc
      r = (bx-ax)*(fb-fc)
      q = (bx-cx)*(fb-fa)
      u = bx - ((bx-cx)*q - (bx-ax)*r) / (2*SIGN(max(abs(q-r),TINY),q-r))
      ulim = bx + GLIMIT*(cx-bx)

      if (bx-u)*(u-cx) > 0:
         fu = func(u)
         if fu < fc:
            ax = bx; bx = u
            fa = fb; fb = fu
            return ax,bx,cx,fa,fb,fc
         elif fu > fb:
            cx = u; fc = fu
            return ax,bx,cx,fa,fb,fc

         u = cx + GOLD*(cx-bx)
         fu = func(u)

      elif (cx-u)*(u-ulim) > 0:
         fu = func(u)
         if fu < fc:
            bx = cx; cx = u; u = cx + GOLD*(cx-bx)
            fb = fc; fc = fu; fu = func(u)
            
      else:
         u = cx + GOLD*(cx-bx)
         fu = func(u)

      ax = bx; bx = cx; cx = u
      fa = fb; fb = fc; fc = fu

   return ax,bx,cx,fa,fb,fc

def brent(ax,bx,cx,f,tol,maxiter):
#
# minimizes 1D function
#
   ZEPS = 1.0e-10
   CGOLD = 0.381966

   a = min(ax,cx)
   b = max(ax,cx)
   x = w = v = bx
   fx = fw = fv = f(x)

   e = 0.

   iter = 0

   while iter < maxiter:
      iter = iter + 1
      xm = (a+b)/2
      tol1 = tol*abs(x) + ZEPS
      tol2 = 2*tol1

      if abs(x-xm) < (tol2-(b-a)/2): # test for convergence
         return x, fx

      if abs(e) > tol:
         r = (x-w)*(fx-fv)
         q = (x-v)*(fx-fw)
         p = (x-v)*q - (x-w)*r
         q = 2*(q-r)

         if q > 0: p = -p

         q = abs(q)
         etemp = e
         e = d

         if abs(p) >= abs(q*etemp/2) or p <= q*(a-x) or p >= q*(b-x):
            if x >= xm: e = a-x
            else      : e = b-x
            d = CGOLD*e
         else:
            d = p/q
            u = x + d
            if u-a < tol2 or b-u < tol2: d = SIGN(tol1,xm-x)

      else:
         if x >= xm: e = a-x
         else      : e = b-x
         d = CGOLD*e

      if abs(d) >= tol1: u = x + d
      else             : u = x + SIGN(tol1,d)
      fu = f(u)

      if fu < fx:

         if u >= x : a = x
         else      : b = x

         v  = w;  w =  x;  x =  u
         fv = w; fw = fx; fx = fu

      else:

         if u < x : a = u
         else     : b = u

         if fu <= fw or w == x:
            v = w; w = u; fv = fw; fw = fu
         elif fu <= fv or v == x or v == w:
            v = u; fv = fu

   print 'brent> error: iter, maxiter = ',iter, maxiter
   return x, fx