packages feed

dynobud-1.9.0.0: src/Dyno/GoldenSectionSearch.hs

{-# OPTIONS_GHC -Wall #-}

module Dyno.GoldenSectionSearch
       ( Golden(..)
       , goldenSectionSearch
       , goldenSectionSearch'
       ) where

tau :: Floating a => a
tau = 2 / (1 + sqrt 5)

data Golden a =
  Golden
  { goldenX :: a
  , goldenY :: a
  , goldenBox :: (a, a)
  } deriving (Show, Eq, Ord)

-- | Iterate a golden section search until the
-- bounding box is withing a given tolerance.
goldenSectionSearch :: (Ord a, Floating a) => a -> (a -> a) -> (a, a) -> (a, a)
goldenSectionSearch eps f bnds = g $ goldenSectionSearch' f bnds
  where
    g ((Golden x fx (lbx, ubx)):gs)
      | ubx - lbx < eps = (x, fx)
      | otherwise = g gs
    g _ = error "goldenSectionSearch': hit the end of an infinite list"

-- | Return an infinite list of the iterations of a golden section search.
goldenSectionSearch' :: (Ord a, Floating a) => (a -> a) -> (a, a) -> [Golden a]
goldenSectionSearch' f (y0, y3) = gss (y0, y1, y2, y3)
  where
    y1 = y0 + (y3 - y0) * (1 - tau)
    y2 = y0 + (y3 - y0) * tau

    gss (x0, x1, x2, x3)
      | f x1 < f x2 = Golden x1 (f x1) (x0, x2) : gss (x0, x1', x1,  x2)
      | otherwise   = Golden x2 (f x2) (x1, x3) : gss (x1, x2,  x2', x3)
      where
        x1' = x0 + (x2 - x0) * (1 - tau)
        x2' = x1 + (x3 - x1) * tau