dynobud-1.9.0.0: src/Dyno/NlpSolver.hs
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Dyno.NlpSolver
( NlpSolver
, runNlpSolver
, RunNlpOptions(..)
, runNlpSolverWith
, defaultRunnerOptions
, withNlpSolver
, withNlpSolver'
-- * solve
, solve
, solve'
-- * inputs
, setX0
, setP
, setLbx
, setUbx
, setLbg
, setUbg
, setLamX0
, setLamG0
, getX0
, getP
, getLbx
, getUbx
, getLbg
, getUbg
, getLamX0
, getLamG0
-- * outputs
, getF
, getX
, getG
, getLamX
, getLamG
, getStat
, getNlpOut
-- * kkt conditions, evalKKT is in user units, evalScaledKKT is the internal one
, evalGradF
, evalJacG
, evalHessF
, evalHessLambdaG
, evalKKT
, evalScaledGradF
, evalScaledJacG
, evalScaledHessLag
, evalScaledHessF
, evalScaledHessLambdaG
, evalScaledKKT
-- * options
, Op.Opt(..)
-- * other
, MonadIO
, liftIO
, generateAndCompile
) where
import Control.Exception ( AsyncException( UserInterrupt ), try )
import Control.Concurrent ( forkIO, newEmptyMVar, takeMVar, putMVar )
import qualified Control.Applicative as A
import Control.Monad ( when, void )
import "mtl" Control.Monad.Reader ( MonadIO(..), MonadReader(..), ReaderT(..) )
import Data.IORef ( newIORef, readIORef, writeIORef )
import qualified Data.Map as M
import Data.Maybe ( fromMaybe )
import Data.Proxy ( Proxy(..) )
import qualified Data.Traversable as T
import Data.Time.Clock ( getCurrentTime, diffUTCTime )
import Data.Vector ( Vector )
import qualified Data.Vector as V
import Foreign.C.Types ( CInt )
import System.Process ( callProcess, showCommandForUser )
import Text.Printf ( printf )
import Casadi.Core.Enums ( InputOutputScheme(..) )
import qualified Casadi.Core.Classes.Function as C
import qualified Casadi.Core.Classes.NlpSolver as C
import qualified Casadi.Core.Classes.GenericType as C
import qualified Casadi.Core.Classes.IOInterfaceFunction as C
import Casadi.Callback ( makeCallback )
import Casadi.CMatrix ( CMatrix )
import qualified Casadi.CMatrix as CM
import Casadi.DMatrix ( DMatrix, dnonzeros )
import Casadi.Function ( Function, evalDMatrix', externalFunction, generateCode )
import Casadi.IOScheme ( mxFunctionWithSchemes )
import Casadi.MX ( MX, symV )
import qualified Casadi.Option as Op
import qualified Casadi.GenericC as Gen
import Dyno.FormatTime ( formatSeconds )
import qualified Dyno.View.M as M
import Dyno.Nlp ( NlpOut(..), KKT(..), Bounds )
import Dyno.NlpScaling ( ScaleFuns(..), scaledFG, mkScaleFuns )
import Dyno.SolverInternal ( SolverInternal(..) )
import Dyno.Solvers ( Solver(..), getSolverInternal )
import Dyno.Vectorize ( Id(..) )
import Dyno.View.View ( View(..), J, S, JV, fmapJ, d2v, v2d, jfill, unzipJ )
import Dyno.View.M ( M )
import Dyno.View.Unsafe ( mkM, unM )
type VD a = J a (Vector Double)
type VMD a = J a (Vector (Maybe Double))
timeIt :: IO a -> IO (a, Double)
timeIt action = do
t0 <- getCurrentTime
ret <- action
t1 <- getCurrentTime
return (ret, realToFrac (diffUTCTime t1 t0))
getStat :: String -> NlpSolver x p g C.GenericType
getStat name = do
nlpState <- ask
liftIO $ C.function_getStat (isSolver nlpState) name
setInput ::
View xg
=> (ScaleFuns x g DMatrix -> (J xg DMatrix -> J xg DMatrix))
-> (NlpState x p g -> Int)
-> String
-> J xg (V.Vector Double)
-> NlpSolver x p g ()
setInput scaleFun getLen name x0 = do
nlpState <- ask
let x = unM $ scaleFun (isScale nlpState) $ mkM $ CM.fromDVector (unM x0)
let nActual = (CM.size1 x, CM.size2 x)
nTypeLevel = (getLen nlpState, 1)
when (nTypeLevel /= nActual) $ error $
name ++ " dimension mismatch, " ++ show nTypeLevel ++
" (type-level) /= " ++ show nActual ++ " (given)"
liftIO $ C.ioInterfaceFunction_setInput__0 (isSolver nlpState) x name
return ()
setX0 :: forall x p g. View x => VD x -> NlpSolver x p g ()
setX0 = setInput xToXBar isNx "x0"
inf :: Double
inf = read "Infinity"
toLb :: View x => J x (Vector (Maybe Double)) -> J x (Vector Double)
toLb = fmapJ (fromMaybe (-inf))
toUb :: View x => J x (Vector (Maybe Double)) -> J x (Vector Double)
toUb = fmapJ (fromMaybe inf )
setLbx :: View x => VMD x -> NlpSolver x p g ()
setLbx = setInput xToXBar isNx "lbx" . toLb
setUbx :: View x => VMD x -> NlpSolver x p g ()
setUbx = setInput xToXBar isNx "ubx" . toUb
setLbg :: View g => VMD g -> NlpSolver x p g ()
setLbg = setInput gToGBar isNg "lbg" . toLb
setUbg :: View g => VMD g -> NlpSolver x p g ()
setUbg = setInput gToGBar isNg "ubg" . toUb
setP :: View p => VD p -> NlpSolver x p g ()
setP p = do
nlpState <- ask
isSetParam nlpState p
setInput (const id) isNp "p" p
setLamX0 :: View x => VD x -> NlpSolver x p g ()
setLamX0 = setInput lamXToLamXBar isNx "lam_x0"
setLamG0 :: View g => VD g -> NlpSolver x p g ()
setLamG0 = setInput lamGToLamGBar isNg "lam_g0"
getInput ::
View xg
=> (ScaleFuns x g DMatrix -> (J xg DMatrix -> J xg DMatrix))
-> String -> NlpSolver x p g (J xg (Vector Double))
getInput scaleFun name = do
nlpState <- ask
dmat <- liftIO $ C.ioInterfaceFunction_getInput__0 (isSolver nlpState) name
let scale = scaleFun (isScale nlpState)
return (mkM $ dnonzeros $ unM $ scale (mkM dmat))
getX0 :: View x => NlpSolver x p g (VD x)
getX0 = getInput xbarToX "x0"
getLbx :: View x => NlpSolver x p g (VD x)
getLbx = getInput xbarToX "lbx"
getUbx :: View x => NlpSolver x p g (VD x)
getUbx = getInput xbarToX "ubx"
getLbg :: View g => NlpSolver x p g (VD g)
getLbg = getInput gbarToG "lbg"
getUbg :: View g => NlpSolver x p g (VD g)
getUbg = getInput gbarToG "ubg"
getP :: View p => NlpSolver x p g (VD p)
getP = getInput (const id) "p"
getLamX0 :: View x => NlpSolver x p g (VD x)
getLamX0 = getInput lamXBarToLamX "lam_x0"
getLamG0 :: View g => NlpSolver x p g (VD g)
getLamG0 = getInput lamGBarToLamG "lam_g0"
getOutput ::
View xg
=> (ScaleFuns x g DMatrix -> (J xg DMatrix -> J xg DMatrix))
-> String -> NlpSolver x p g (J xg (Vector Double))
getOutput scaleFun name = do
nlpState <- ask
dmat <- liftIO $ C.ioInterfaceFunction_getOutput__0 (isSolver nlpState) name
let scale = scaleFun (isScale nlpState)
return (mkM $ dnonzeros $ unM $ scale (mkM dmat))
getF :: NlpSolver x p g (VD (JV Id))
getF = getOutput fbarToF "f"
getX :: View x => NlpSolver x p g (VD x)
getX = getOutput xbarToX "x"
getG :: View g => NlpSolver x p g (VD g)
getG = getOutput gbarToG "g"
getLamX :: View x => NlpSolver x p g (VD x)
getLamX = getOutput lamXBarToLamX "lam_x"
getLamG :: View g => NlpSolver x p g (VD g)
getLamG = getOutput lamGBarToLamG "lam_g"
evalScaledGradF :: forall x p g . (View x, View g, View p)
=> NlpSolver x p g (J x DMatrix, S DMatrix)
evalScaledGradF = do
x0bar <- getInput (const id) "x0" :: NlpSolver x p g (J x (Vector Double))
pbar <- getInput (const id) "p" :: NlpSolver x p g (J p (Vector Double))
nlpState <- ask
let solver = isSolver nlpState :: C.NlpSolver
liftIO $ do
gradF <- C.nlpSolver_gradF solver
result <- evalDMatrix' gradF (M.fromList [("x", unM (v2d x0bar)), ("p", unM (v2d pbar))])
let mret = do
grad <- M.lookup "grad" result
f <- M.lookup "f" result
return (mkM grad, mkM f)
case mret of
Nothing -> error $ "evalScaledGradF: error looking up output\n"
++ "fields available: " ++ show (M.keys result)
Just r -> return r
evalGradF :: forall x p g . (View x, View g, View p)
=> NlpSolver x p g (J x DMatrix, S DMatrix)
evalGradF = do
nlpState <- ask
let scale = isScale nlpState
(gradF, f) <- evalScaledGradF
return (gradFBarToGradF scale gradF, fbarToF scale f)
evalScaledJacG :: forall x p g . (View x, View g, View p)
=> NlpSolver x p g (M g x DMatrix, J g DMatrix)
evalScaledJacG = do
x0bar <- getInput (const id) "x0" :: NlpSolver x p g (J x (Vector Double))
pbar <- getInput (const id) "p" :: NlpSolver x p g (J p (Vector Double))
nlpState <- ask
let solver = isSolver nlpState :: C.NlpSolver
-- todo: remove this workaround when casadi fixes https://github.com/casadi/casadi/issues/1345
if size (Proxy :: Proxy g) == 0
then return (M.zeros, M.zeros)
else liftIO $ do
jacG <- C.nlpSolver_jacG solver
result <- evalDMatrix' jacG (M.fromList [("x", unM (v2d x0bar)), ("p", unM (v2d pbar))])
let mret = do
jac <- M.lookup "jac" result
g <- M.lookup "g" result
return (mkM jac, mkM g)
case mret of
Nothing -> error $ "evalScaledJacG: error looking up output\n"
++"fields available: " ++ show (M.keys result)
Just r -> return r
evalJacG :: forall x p g . (View x, View g, View p)
=> NlpSolver x p g (M g x DMatrix, J g DMatrix)
evalJacG = do
(jacG, g) <- evalScaledJacG
nlpState <- ask
let scale = isScale nlpState
return (jacGBarToJacG scale jacG, gbarToG scale g)
evalScaledHessLag :: forall x p g . (View x, View g, View p)
=> NlpSolver x p g (M x x DMatrix)
evalScaledHessLag = do
x0bar <- getInput (const id) "x0" :: NlpSolver x p g (J x (Vector Double))
pbar <- getInput (const id) "p" :: NlpSolver x p g (J p (Vector Double))
lamGbar <- getInput (const id) "lam_g0" :: NlpSolver x p g (J g (Vector Double))
nlpState <- ask
let solver = isSolver nlpState :: C.NlpSolver
liftIO $ do
hessLag <- C.nlpSolver_hessLag solver
result <- evalDMatrix' hessLag $
M.fromList
[ ("der_x", unM (v2d x0bar))
, ("der_p", unM (v2d pbar))
, ("adj0_f", 1.0)
, ("adj0_g", unM (v2d lamGbar))
]
case M.lookup "jac" result of -- ????????????????
Nothing -> error $ "evalScaledHessLag: error looking up hess lag output\n"
++ "available fields are: " ++ show (M.keys result)
Just r -> return (mkM r)
-- | only valid at the solution
evalHessLag :: forall x p g . (View x, View g, View p)
=> NlpSolver x p g (M x x DMatrix)
evalHessLag = do
hess <- evalScaledHessLambdaG
nlpState <- ask
let scale = isScale nlpState
return (hessLagBarToHessLag scale hess)
evalScaledHessF :: forall x p g . (View x, View g, View p)
=> NlpSolver x p g (M x x DMatrix)
evalScaledHessF = do
x0bar <- getInput (const id) "x0" :: NlpSolver x p g (J x (Vector Double))
pbar <- getInput (const id) "p" :: NlpSolver x p g (J p (Vector Double))
let lamGbar = jfill 0 :: J g (Vector Double)
nlpState <- ask
let solver = isSolver nlpState :: C.NlpSolver
liftIO $ do
hessLag <- C.nlpSolver_hessLag solver
result <- evalDMatrix' hessLag $
M.fromList
[ ("der_x", unM (v2d x0bar))
, ("der_p", unM (v2d pbar))
, ("adj0_f", 1.0)
, ("adj0_g", unM (v2d lamGbar))
]
case M.lookup "jac" result of -- ????????????????
Nothing -> error $ "evalScaledHessF: error looking up hess lag output\n"
++ "available fields are: " ++ show (M.keys result)
Just r -> return (mkM r)
evalHessF :: forall x p g . (View x, View g, View p)
=> NlpSolver x p g (M x x DMatrix)
evalHessF = do
hess <- evalScaledHessLag
nlpState <- ask
let scale = isScale nlpState
return (hessFBarToHessF scale hess)
evalScaledHessLambdaG :: forall x p g . (View x, View g, View p)
=> NlpSolver x p g (M x x DMatrix)
evalScaledHessLambdaG = do
x0bar <- getInput (const id) "x0" :: NlpSolver x p g (J x (Vector Double))
pbar <- getInput (const id) "p" :: NlpSolver x p g (J p (Vector Double))
lamGbar <- getInput (const id) "lam_g0" :: NlpSolver x p g (J g (Vector Double))
nlpState <- ask
let solver = isSolver nlpState :: C.NlpSolver
liftIO $ do
hessLag <- C.nlpSolver_hessLag solver
result <- evalDMatrix' hessLag $
M.fromList
[ ("der_x", unM (v2d x0bar))
, ("der_p", unM (v2d pbar))
, ("adj0_f", 0.0)
, ("adj0_g", unM (v2d lamGbar))
]
case M.lookup "jac" result of -- ????????????????
Nothing -> error $ "evalScaledHessLambdaG: error looking up hess lag output\n"
++ "available fields are: " ++ show (M.keys result)
Just r -> return (mkM r)
-- | only valid at solution
evalHessLambdaG :: forall x p g . (View x, View g, View p)
=> NlpSolver x p g (M x x DMatrix)
evalHessLambdaG = do
hess <- evalScaledHessLambdaG
nlpState <- ask
let scale = isScale nlpState
return (hessLamGBarToHessLamG scale hess)
evalKKT :: (View x, View p, View g) => NlpSolver x p g (KKT x g)
evalKKT = do
(gradF,f) <- evalGradF
(jacG, g) <- evalJacG
hessF <- evalHessF
hessLambdaG <- evalHessLambdaG
hessLag <- evalHessLag
return $
KKT
{ kktF = f
, kktJacG = jacG
, kktG = g
, kktGradF = gradF
, kktHessLag = hessLag
, kktHessF = hessF
, kktHessLambdaG = hessLambdaG
}
evalScaledKKT :: (View x, View p, View g) => NlpSolver x p g (KKT x g)
evalScaledKKT = do
(gradF,f) <- evalScaledGradF
(jacG, g) <- evalScaledJacG
hessL <- evalScaledHessLag
hessF <- evalScaledHessF
hessLambdaG <- evalScaledHessLambdaG
return $
KKT
{ kktF = f
, kktJacG = jacG
, kktG = g
, kktGradF = gradF
, kktHessLag = hessL
, kktHessF = hessF
, kktHessLambdaG = hessLambdaG
}
-- | solve with current inputs, return success or failure code
solve :: NlpSolver x p g (Either String String)
solve = do
nlpState <- ask
let nlp = isSolver nlpState
solveStatus <- liftIO $ do
stop <- newEmptyMVar -- mvar that will be filled when nlp finishes
_ <- forkIO (C.function_evaluate nlp >> putMVar stop ())
-- wait until nlp finishes
ret <- try (takeMVar stop)
case ret of Right () -> return () -- no exceptions
Left UserInterrupt -> do -- got ctrl-C
isInterrupt nlpState -- tell nlp to stop iterations
_ <- takeMVar stop -- wait for nlp to return
return ()
Left _ -> void (takeMVar stop) -- don't handle this one
genericStat <- C.function_getStat nlp "return_status"
strStat <- Gen.fromGeneric genericStat :: IO (Maybe String)
intStat <- Gen.fromGeneric genericStat :: IO (Maybe Int)
statDescription <- Gen.getDescription genericStat
case strStat of
Just strStat' -> return strStat'
Nothing -> case intStat of
Just intStat' -> return (show intStat')
Nothing -> error $ "nlp solver error: return status is not {string,int}, it's " ++
statDescription
return $ if solveStatus `elem` isSuccessCodes nlpState
then Right solveStatus
else Left solveStatus
-- | solve with current inputs, return lots of info on success, or message on failure
solve' :: (View x, View g) => NlpSolver x p g (Either String String, NlpOut x g (Vector Double))
solve' = do
solveStatus <- solve
nlpOut <- getNlpOut
return (solveStatus, nlpOut)
getNlpOut :: (View x, View g) => NlpSolver x p g (NlpOut x g (Vector Double))
getNlpOut = do
fopt <- getF
xopt <- getX
gopt <- getG
lamXOpt <- getLamX
lamGOpt <- getLamG
let nlpOut = NlpOut { fOpt = fopt
, xOpt = xopt
, gOpt = gopt
, lambdaXOpt = lamXOpt
, lambdaGOpt = lamGOpt
}
return nlpOut
data NlpState (x :: * -> *) (p :: * -> *) (g :: * -> *) =
NlpState
{ isNx :: Int
, isNg :: Int
, isNp :: Int
, isSolver :: C.NlpSolver
, isInterrupt :: IO ()
, isSuccessCodes :: [String]
, isScale :: ScaleFuns x g DMatrix
, isSetParam :: J p (Vector Double) -> NlpSolver x p g ()
}
newtype NlpSolver (x :: * -> *) (p :: * -> *) (g :: * -> *) a =
NlpSolver (ReaderT (NlpState x p g) IO a)
deriving ( Functor
, A.Applicative
, Monad
, MonadReader (NlpState x p g)
, MonadIO
)
generateAndCompile :: String -> Function -> IO Function
generateAndCompile name f = do
putStrLn $ "generating " ++ name ++ ".c"
let opts = M.fromList [("generate_main", Op.Opt True)]
writeFile (name ++ ".c") (generateCode f opts)
let cmd = "clang"
args = ["-fPIC","-shared","-Wall","-Wno-unused-variable",name++".c","-o",name++".so"]
putStrLn (showCommandForUser cmd args)
callProcess cmd args
externalFunction ("./"++name++".so") M.empty
data RunNlpOptions =
RunNlpOptions
{ verbose :: Bool
}
defaultRunnerOptions :: RunNlpOptions
defaultRunnerOptions =
RunNlpOptions
{ verbose = False
}
runNlpSolver ::
forall x p g a .
(View x, View p, View g)
=> Solver
-> (J x MX -> J p MX -> (S MX, J g MX))
-> Maybe (J x (Vector Double))
-> Maybe (J g (Vector Double))
-> Maybe Double
-> Maybe (J x (Vector Double) -> J p (Vector Double) -> IO Bool)
-> NlpSolver x p g a
-> IO a
runNlpSolver = runNlpSolverWith defaultRunnerOptions
runNlpSolverWith ::
forall x p g a .
(View x, View p, View g)
=> RunNlpOptions
-> Solver
-> (J x MX -> J p MX -> (S MX, J g MX))
-> Maybe (J x (Vector Double))
-> Maybe (J g (Vector Double))
-> Maybe Double
-> Maybe (J x (Vector Double) -> J p (Vector Double) -> IO Bool)
-> NlpSolver x p g a
-> IO a
runNlpSolverWith runnerOptions solverStuff nlpFun scaleX scaleG scaleF callback' (NlpSolver nlpMonad) = do
inputsX <- mkM <$> symV "x" (size (Proxy :: Proxy x))
inputsP <- mkM <$> symV "p" (size (Proxy :: Proxy p))
let scale :: forall sfa . CMatrix sfa => ScaleFuns x g sfa
scale = mkScaleFuns scaleX scaleG scaleF
(obj, g) = scaledFG scale nlpFun inputsX inputsP
inputsXMat = unM inputsX
inputsPMat = unM inputsP
objMat = unM obj
gMat = unM g
when (verbose runnerOptions) $ do
putStrLn "************** initializing dynobud runNlpSolver ******************"
putStrLn "making nlp..."
(nlp, nlpTime) <- timeIt $ mxFunctionWithSchemes "nlp"
(SCHEME_NLPInput, M.fromList [("x", inputsXMat), ("p", inputsPMat)])
(SCHEME_NLPOutput, M.fromList [("f", objMat), ("g", gMat)])
(M.fromList (functionOptions solverStuff))
when (verbose runnerOptions) $ printf "nlp initialized in %s\n"
(formatSeconds nlpTime)
when (verbose runnerOptions) $ putStrLn "function call..."
-- in case the user wants to do something (like codegen?)
(_, functionCallTime) <- timeIt $ functionCall solverStuff nlp
when (verbose runnerOptions) $ printf "function called in %s\n" (formatSeconds functionCallTime)
-- let eval 0 = error "finished"
-- eval k = do
-- putStrLn "setting input"
-- ioInterfaceFunction_setInput''' nlp (unM nlpX0') (0::Int)
-- putStrLn $ "evaluating " ++ show k
-- C.function_evaluate nlp
-- eval (k-1 :: Int)
-- eval (300::Int)
-- casadiOptions_stopProfiling
-- _ <- error "done"
-- jac_sparsity <- C.function_jacSparsity nlp 0 1 True False
-- C.sparsity_spyMatlab jac_sparsity "jac_sparsity_reorder.m"
-- add callback if user provides it
when (verbose runnerOptions) $ putStrLn "create callback..."
intref <- newIORef False
paramRef <- newIORef (jfill 0)
let cb :: Function -> IO CInt
cb function' = do
callbackRet <- case callback' of
Nothing -> return True
Just callback -> do
xval <- fmap (d2v . xbarToX scale . mkM . CM.densify) $
C.ioInterfaceFunction_getOutput__2 function' 0
pval <- readIORef paramRef
callback xval pval
interrupt <- readIORef intref
return $ if callbackRet && not interrupt then 0
else fromIntegral (solverInterruptCode (getSolverInternal solverStuff))
casadiCallback <- makeCallback cb >>= C.genericType__1
-- make the solver
solverOptions <-
T.mapM Gen.mkGeneric $
M.fromList $
("iteration_callback", Op.Opt casadiCallback)
: defaultSolverOptions (getSolverInternal solverStuff)
++ options solverStuff
when (verbose runnerOptions) $ putStrLn "create solver..."
(solver, solverInitTime) <-
timeIt $ C.nlpSolver__5 "nlpSolver"
(solverName (getSolverInternal solverStuff)) (C.castFunction nlp)
solverOptions
when (verbose runnerOptions) $
printf "solver initialized in %s\n" (formatSeconds solverInitTime)
-- grad_f <- gradient nlp 0 0
-- soInit grad_f
-- jac_g <- jacobian nlp 0 1 True False
-- soInit jac_g
--
-- let eval 0 = error "finished"
-- eval k = do
-- putStrLn "setting input"
-- ioInterfaceFunction_setInput''' jac_g (unM nlpX0') (0::Int)
-- putStrLn $ "evaluating " ++ show k
-- C.function_evaluate jac_g
-- eval (k-1 :: Int)
-- eval (40::Int)
-- nlp' <- generateAndCompile "nlp" nlp
-- grad_f' <- generateAndCompile "grad_f" grad_f
-- jac_g' <- generateAndCompile "jac_g" jac_g
-- _ <- error "lal"
-- Op.setOption solver "grad_f" grad_f'
-- Op.setOption solver "jac_g" jac_g'
let proxy :: J f b -> Proxy f
proxy = const Proxy
nlpState = NlpState { isNx = size (proxy inputsX)
, isNp = size (proxy inputsP)
, isNg = size (proxy g)
, isSolver = solver
, isInterrupt = writeIORef intref True
, isSuccessCodes = successCodes (getSolverInternal solverStuff)
, isScale = scale
, isSetParam = liftIO . writeIORef paramRef
}
when (verbose runnerOptions) $ putStrLn "run NLP monad..."
(ret, retTime) <- timeIt $ liftIO $ runReaderT nlpMonad nlpState
when (verbose runnerOptions) $ printf "ran NLP monad in %s\n" (formatSeconds retTime)
return ret
withNlpSolver ::
forall x p g a .
(View x, View p, View g)
=> Solver
-> (J x MX -> J p MX -> (S MX, J g MX))
-> Maybe (J x (Vector Double))
-> Maybe (J g (Vector Double))
-> Maybe Double
-> Maybe (J x (Vector Double) -> J p (Vector Double) -> IO Bool)
-> ((J x (Vector Double) -> J p (Vector Double)
-> J x (Vector Bounds) -> J g (Vector Bounds)
-> NlpSolver x p g (Either String (NlpOut x g (Vector Double)))
) -> NlpSolver x p g a)
-> IO a
withNlpSolver = withNlpSolver' defaultRunnerOptions
withNlpSolver' ::
forall x p g a .
(View x, View p, View g)
=> RunNlpOptions
-> Solver
-> (J x MX -> J p MX -> (S MX, J g MX))
-> Maybe (J x (Vector Double))
-> Maybe (J g (Vector Double))
-> Maybe Double
-> Maybe (J x (Vector Double) -> J p (Vector Double) -> IO Bool)
-> ((J x (Vector Double) -> J p (Vector Double)
-> J x (Vector Bounds) -> J g (Vector Bounds)
-> NlpSolver x p g (Either String (NlpOut x g (Vector Double)))
) -> NlpSolver x p g a)
-> IO a
withNlpSolver' opts solver fg sx sg sf cb userFun =
runNlpSolverWith opts solver fg sx sg sf cb action
where
action :: NlpSolver x p g a
action = userFun solveOne
where
solveOne ::
J x (Vector Double) -> J p (Vector Double)
-> J x (Vector Bounds) -> J g (Vector Bounds)
-> NlpSolver x p g (Either String (NlpOut x g (Vector Double)))
solveOne x0 p xbnds gbnds = do
setX0 x0
setP p
let (lbx, ubx) = unzipJ xbnds
(lbg, ubg) = unzipJ gbnds
setLbx lbx
setUbx ubx
setLbg lbg
setUbg ubg
(status, out) <- solve'
return $ case status of
Left msg -> Left msg
Right _ -> Right out