hanalyze-0.1.0.0: bench/haskell/BenchBO.hs
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-full-laziness -fno-cse #-}
-- | Bayesian Optimization benchmarks (B5).
--
-- Branin (2D) and Hartmann6 (6D) for 5 seeds, budget = 30 evaluations.
-- Reports median wall time and median final f(x*).
module Main where
import qualified Hanalyze.Optim.BayesOpt as BO
import qualified System.Random.MWC as MWC
import qualified Data.Vector as V
import Data.Word (Word32)
import Data.List (sort)
import Control.Monad (forM)
import BenchUtil
-- ---------------------------------------------------------------------------
-- Test functions
-- ---------------------------------------------------------------------------
-- | Branin global minimum is f* = 0.397887 at three points.
branin :: [Double] -> IO Double
branin [x1, x2] =
let a = 1
b = 5.1 / (4 * pi * pi)
c = 5 / pi
r = 6
s = 10
t = 1 / (8 * pi)
in return $ a * (x2 - b * x1 * x1 + c * x1 - r) ** 2
+ s * (1 - t) * cos x1 + s
branin _ = return 1e30
braninBounds :: [(Double, Double)]
braninBounds = [(-5, 10), (0, 15)]
braninStar :: Double
braninStar = 0.397887
-- | Hartmann 6D, global min f* = -3.32237 at known x*.
hartmann6 :: [Double] -> IO Double
hartmann6 xs =
let alpha = [1.0, 1.2, 3.0, 3.2]
a = [ [10, 3, 17, 3.5, 1.7, 8]
, [0.05, 10, 17, 0.1, 8, 14]
, [3, 3.5, 1.7, 10, 17, 8]
, [17, 8, 0.05, 10, 0.1, 14] ]
p = [ [0.1312, 0.1696, 0.5569, 0.0124, 0.8283, 0.5886]
, [0.2329, 0.4135, 0.8307, 0.3736, 0.1004, 0.9991]
, [0.2348, 0.1451, 0.3522, 0.2883, 0.3047, 0.6650]
, [0.4047, 0.8828, 0.8732, 0.5743, 0.1091, 0.0381] ]
term i =
let aRow = a !! i
pRow = p !! i
inner = sum [ aRow !! j * (xs !! j - pRow !! j) ** 2 | j <- [0..5] ]
in alpha !! i * exp (- inner)
in return $ negate $ sum [term i | i <- [0..3]]
hartmann6Bounds :: [(Double, Double)]
hartmann6Bounds = replicate 6 (0, 1)
hartmann6Star :: Double
hartmann6Star = -3.32237
-- ---------------------------------------------------------------------------
-- Driver
-- ---------------------------------------------------------------------------
nSeeds :: Int
nSeeds = 5
mainBranin :: IO BenchRow
mainBranin = do
let cfg = BO.defaultBayesOptConfig
{ BO.boIterations = 30, BO.boInitPoints = 5 }
rs <- mapM (\s -> runND cfg branin braninBounds s) [1 .. nSeeds]
let (ts, ys) = unzip rs
medT = median ts
medY = median ys
return $ BenchRow "haskell" "bo" "Branin/BO" medT medY
braninStar
("median over " ++ show nSeeds ++ " seeds; star=" ++ show braninStar)
mainHartmann6 :: IO BenchRow
mainHartmann6 = do
let cfg = BO.defaultBayesOptConfig
{ BO.boIterations = 30, BO.boInitPoints = 10 }
rs <- mapM (\s -> runND cfg hartmann6 hartmann6Bounds s) [1 .. nSeeds]
let (ts, ys) = unzip rs
medT = median ts
medY = median ys
return $ BenchRow "haskell" "bo" "Hartmann6/BO" medT medY
hartmann6Star
("median over " ++ show nSeeds ++ " seeds; star=" ++ show hartmann6Star)
{-# NOINLINE runND #-}
runND :: BO.BayesOptConfig -> ([Double] -> IO Double) -> [(Double, Double)]
-> Int -> IO (Double, Double)
runND cfg f bs seed = do
gen <- MWC.initialize (V.singleton (fromIntegral seed) :: V.Vector Word32)
(ms, (_hist, (_xstar, ystar))) <- timeitIO 1 (\(_,(_,y)) -> y)
(\_ -> BO.bayesOptND cfg 20 f bs gen)
return (ms, ystar)
main :: IO ()
main = do
rs <- sequence [mainBranin, mainHartmann6]
writeRows "bench/results/haskell/bo.csv" rs
putStrLn $ "wrote " ++ show (length rs)
++ " rows → bench/results/haskell/bo.csv"
median :: Ord a => [a] -> a
median xs = sort xs !! (length xs `div` 2)