{-# LINE 1 "Optimize/ASA.hsc" #-}
{-# OPTIONS -ffi -fglasgow-exts #-}
{-# LINE 2 "Optimize/ASA.hsc" #-}
-- | interface to the Adaptive Simulated Annealing algorithm.

module Optimize.ASA where 


{-# LINE 7 "Optimize/ASA.hsc" #-}

import Optimize.Parameter
import Foreign.C.Types
import Foreign.Storable
import Foreign.Ptr
import Foreign.Marshal.Array
import Foreign.Marshal.Alloc
import Random
import Data.Array.Unboxed
import Data.Int


newtype UserOptions = UserOptions (Ptr UserOptions)
type Doubles = UArray Int Double    

data ExitCode =  NormalExit | PTempTooSmall | CTempTooSmall | CostRepeating | TooManyInvalidStates | ImmediateExit | InvalidUserInput | InvalidCostFunction | InvalidCostFunctionDeriv 
    deriving(Eq,Ord,Enum,Show,Read)


data Results x = Results {
    optimalValue :: Double,
    optimalParam :: x,
    exitCode :: ExitCode
    }


type CostFunction =  Ptr Double -> Ptr Int -> IO Double

foreign import ccall "wrapper" mkCostFunction :: CostFunction -> IO (FunPtr CostFunction)  
foreign import ccall "asa_usr.h asa_main" asa_main :: FunPtr CostFunction -> CInt -> Ptr Double -> Ptr Double -> Ptr CInt -> Ptr Double -> Ptr Double -> Ptr CInt -> CInt -> IO CInt




asa :: UserOptions     -- Options
    -> (Doubles -> IO (Maybe Double)) -- cost function 
    -> Int64           -- random number seed
    -> Maybe Doubles   -- starting position
    -> Doubles         -- upper bounds
    -> Doubles         -- lower bounds
    -> UArray Int Bool -- parameters are integral
    -> IO (ExitCode,Doubles)      -- final answers
asa = undefined

toBasicCostFunction :: Parameter z x => z -> (x -> Double) -> CostFunction
toBasicCostFunction z fn = f where
    thePeek = peekParam z 
    f pd pf = do
        poke pf 1
        x <- thePeek pd
        let v = fn x
        --putStrLn $ ">> Haskell Function Called: " ++ show v 
        return $  v
        

minimize :: Parameter z x => z -> (x -> Double) -> IO x 
minimize z (fn :: x -> Double ) = do
    cf <- mkCostFunction (toBasicCostFunction z fn)
    let n = numParams (undefined :: x) z 
    let ps = paramInfo (undefined :: x) z []
    withArray (map limitLow ps) $ \lower_bounds -> do  
    withArray (map limitHigh ps) $ \upper_bounds -> do  
    withArray (map (\x -> if isIntegral x then (1) else (-1)) ps) $ \real_int -> do  
{-# LINE 70 "Optimize/ASA.hsc" #-}
    alloca $ \dummy_cost_val -> do 
    allocaArray n $ \ret -> do
    alloca $ \exit_code -> do 
    r <- randomIO
    asa_main cf (fromIntegral n) upper_bounds lower_bounds real_int dummy_cost_val ret exit_code (fromIntegral (r :: Int))
    --code <- peek exit_code
    --print (toEnum (fromIntegral code) :: ExitCode)
    peekParam z ret