bindings-eskit-0.0.1: src/Bindings/ESKit.hs
module Bindings.ESKit (OptimisationProblem(OptimisationProblem),
DistributionHandler(CMAHandler, SepCMAHandler, CSAHandler),
n, mu, lambda, fitnessFunction, distributionHandlerSettings,
optimize)
where
import qualified Bindings.ESKitLowlevel as LL
import Control.Monad
import Data.Maybe
import Foreign
import Foreign.C.Types
data OptimisationProblem = OptimisationProblem {
n :: Int,
mu :: Maybe Int,
lambda :: Maybe Int,
fitnessFunction :: [Double] -> Double,
distributionHandlerSettings :: DistributionHandler
};
data DistributionHandler =
CMAHandler (Double, Double) |
SepCMAHandler (Double, Double) |
CSAHandler (Double, Double)
setupDistribHandler :: CSize -> Ptr LL.C'ekOptimizer -> DistributionHandler -> IO (Ptr CChar)
setupDistribHandler np eo (CMAHandler (sigmalow, sigmahigh)) = do
p <- LL.c'mkekCMA np
LL.c'ekCMA_setSigma p (realToFrac sigmahigh) (realToFrac sigmalow)
LL.c'ekCMA_setOptimizer p eo
return $ castPtr p
setupDistribHandler np eo (SepCMAHandler (sigmalow, sigmahigh)) = do
p <- LL.c'mkekSepCMA np
LL.c'ekSepCMA_setSigma p (realToFrac sigmahigh) (realToFrac sigmalow)
LL.c'ekSepCMA_setOptimizer p eo
return $ castPtr p
setupDistribHandler np eo (CSAHandler (sigmalow, sigmahigh)) = do
p <- LL.c'mkekCSA np
LL.c'ekCSA_setSigma p (realToFrac sigmahigh) (realToFrac sigmalow)
LL.c'ekCSA_setOptimizer p eo
return $ castPtr p
destroyDistribHandler :: Ptr CChar -> DistributionHandler -> IO ()
destroyDistribHandler dh (CMAHandler _) =
LL.c'delekCMA (castPtr dh)
destroyDistribHandler dh (SepCMAHandler _) =
LL.c'delekSepCMA (castPtr dh)
destroyDistribHandler dh (CSAHandler _) =
LL.c'delekCSA (castPtr dh)
optimize :: OptimisationProblem -> Either String [Double]
optimize (OptimisationProblem { n = np, mu = mmu, lambda = mlambda,
fitnessFunction = fitness,
distributionHandlerSettings = dhsettings }) =
unsafePerformIO $ do
eo <- LL.c'mkekOptimizer (fromIntegral np)
dh <- setupDistribHandler (fromIntegral np) eo dhsettings
eod <- peek eo
let lambdav = (flip fromMaybe (fmap fromIntegral mlambda) (LL.c'ekOptimizer'lambda eod))
(LL.c'ekOptimizer_setMuLambda eo)
(flip fromMaybe (fmap fromIntegral mmu) (LL.c'ekOptimizer'mu eod))
lambdav
LL.c'ekOptimizer_start eo
let continueOptimization =
do
LL.c'ekOptimizer_sampleCloud eo
allPts <- liftM LL.c'ekOptimizer'points (peek eo)
forM_ [0..((fromIntegral lambdav)-1)] $ \i ->
do
ptp <- peekElemOff allPts i
pt <- peek ptp
let xcoordp = LL.c'ekPoint'x pt
xcoord <- mapM (liftM (realToFrac :: CDouble -> Double) . peekElemOff xcoordp) [0..(np-1)]
poke ptp (pt {LL.c'ekPoint'fitness = realToFrac $ fitness xcoord })
LL.c'ekOptimizer_update eo
stop <- LL.c'ekOptimizer_stop eo
if stop == 0
then
continueOptimization
else
return stop
whyStop <- continueOptimization
destroyDistribHandler dh dhsettings
ret <-
do
bestPoint <- liftM LL.c'ekOptimizer'bestPoint (peek eo)
let xcoordp = LL.c'ekPoint'x bestPoint
xcoord <- mapM (liftM (realToFrac :: CDouble -> Double) . peekElemOff xcoordp) [0..(np-1)]
return $ Right xcoord
{-
case ()
of
() | whyStop == LL.c'ekStopCriterionId_LowSigma ->
() | whyStop == LL.c'ekStopCriterionId_DistributionNotSet ->
return $ Left "No point distribution handler has been associated with the opimiser"
() | whyStop == LL.c'ekStopCriterionId_NoEffectAxis ->
return $ Left "Axes of the Gaussian distribution are beyond what numerical precision can handle"
() | whyStop == LL.c'ekStopCriterionId_NoEffectCoord ->
return $ Left "Eigen vector basis of the Gaussian distribution are beyond what numerical precision can handle"
() | whyStop == LL.c'ekStopCriterionId_ConditionCov ->
return $ Left "Covariance matrix conditionning is beyond what numerical precision can handle."
() ->
return $ Left "The eigenvalue solver failed."
-}
LL.c'delekOptimizer eo
return ret
{-
To do: tests:
optimize (OptimisationProblem { n = 2, mu = Nothing, lambda = Nothing, fitnessFunction = \(x:y:[]) -> (1-x)^2 + 100 * (y - x^2)^2, distributionHandlerSettings = CMAHandler (0.0001,1000)})
=> Should be close to [1,1]
optimize (OptimisationProblem { n = 1, mu = Nothing, lambda = Nothing, fitnessFunction = \(x:[]) -> abs((x-100) * (x - 200) * (x - 300) * (x + 400)), distributionHandlerSettings = CMAHandler (0.0001,1000)})
=> Several solutions (obviously).
-}