dynobud-1.8.0.0: src/Dyno/DirectCollocation/FormulateCov.hs
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PolyKinds #-}
module Dyno.DirectCollocation.FormulateCov
( CollCovProblem(..)
, CovTraj(..)
, makeCollCovProblem
) where
import Data.Maybe ( fromMaybe )
import Data.Proxy ( Proxy(..) )
import Data.Vector ( Vector )
import qualified Data.Foldable as F
import Linear.V
import Casadi.DMatrix ( DMatrix )
import Casadi.MX ( MX )
import Dyno.View.View ( View(..), J, jfill, v2d, d2v )
import Dyno.View.Cov ( Cov )
import Dyno.View.JV ( JV, catJV, catJV', splitJV' )
import Dyno.View.HList ( (:*:)(..) )
import Dyno.View.Fun
import Dyno.View.JVec( JVec(..), jreplicate )
import Dyno.Vectorize ( Vectorize(..), Id(..), None(..), fill )
import Dyno.TypeVecs ( Vec )
import qualified Dyno.TypeVecs as TV
import Dyno.Nlp ( Nlp(..), Bounds )
import Dyno.Ocp
import Dyno.DirectCollocation.Types
import Dyno.DirectCollocation.Dynamic ( DynPlotPoints )
import Dyno.DirectCollocation.Quadratures ( timesFromTaus )
import Dyno.DirectCollocation.Robust
import Dyno.DirectCollocation.Formulate
data CollCovProblem ocp n deg sx sw sh shr sc =
CollCovProblem
{ ccpNlp :: Nlp
(CollTrajCov sx ocp n deg)
(JV None)
(CollOcpCovConstraints ocp n deg sh shr sc) MX
, ccpPlotPoints :: J (CollTrajCov sx ocp n deg) (Vector Double) -> IO (DynPlotPoints Double)
, ccpOutputs ::
J (CollTrajCov sx ocp n deg) (Vector Double)
-> IO ( Vec n (StageOutputs (X ocp) (O ocp) (H ocp) (Q ocp) (QO ocp) (PO ocp) deg Double)
, Vec n (J (Cov (JV sx)) (Vector Double))
, J (Cov (JV sx)) (Vector Double)
)
, ccpSensitivities :: MXFun
(J (CollTraj' ocp n deg))
(CovarianceSensitivities (JV sx) (JV sw) n)
, ccpCovariances :: MXFun
(J (Cov (JV sx)) :*: J (CollTraj (X ocp) (Z ocp) (U ocp) (P ocp) n deg))
(J (CovTraj sx n))
, ccpDirCollOpts :: DirCollOptions
}
makeCollCovProblem ::
forall ocp x z u p fp r o c h q qo po sx sz sw sr sh shr sc deg n .
( Dim deg, Dim n, Vectorize x, Vectorize p, Vectorize u, Vectorize z
, Vectorize sr, Vectorize sw, Vectorize sz, Vectorize sx
, Vectorize r, Vectorize o, Vectorize h, Vectorize c, Vectorize q, Vectorize po
, Vectorize qo
, View sh, Vectorize shr, View sc
, x ~ X ocp
, q ~ Q ocp
, qo ~ QO ocp
, h ~ H ocp
, c ~ C ocp
, o ~ O ocp
, r ~ R ocp
, p ~ P ocp
, u ~ U ocp
, z ~ Z ocp
, po ~ PO ocp
, fp ~ None
, None ~ FP ocp
)
=> DirCollOptions
-> OcpPhase' ocp
-> OcpPhaseInputs x z u p c h fp
-> OcpPhaseWithCov ocp sx sz sw sr sh shr sc
-> J (CollTraj x z u p n deg) (Vector Double)
-> IO (CollCovProblem ocp n deg sx sw sh shr sc)
makeCollCovProblem dirCollOpts ocp ocpInputs ocpCov guess = do
let -- the collocation points
roots = collocationRoots dirCollOpts
taus :: Vec deg Double
taus = mkTaus roots
computeSensitivities <- mkComputeSensitivities roots (ocpCovDae ocpCov)
computeCovariances <- mkComputeCovariances continuousToDiscreetNoiseApprox
(computeSensitivities) (ocpCovSq ocpCov)
sbcFun <- toSXFun "sbc" $ \(x0:*:x1) -> ocpCovSbc ocpCov x0 x1
shFun <- toSXFun "sh" $ \(x0:*:x1) -> ocpCovSh ocpCov (splitJV' x0) x1
mayerFun <- toSXFun "cov mayer" $ \(x0:*:x1:*:x2:*:x3:*:x4) ->
catJV' $ Id $ ocpCovMayer ocpCov (unId (splitJV' x0)) (splitJV' x1) (splitJV' x2) x3 x4
lagrangeFun <- toSXFun "cov lagrange" $ \(x0:*:x1:*:x2:*:x3) ->
catJV' $ Id $ ocpCovLagrange ocpCov (unId (splitJV' x0)) (splitJV' x1) x2 (unId (splitJV' x3))
cp0 <- makeCollProblem dirCollOpts ocp ocpInputs guess
robustify <- mkRobustifyFunction (ocpCovProjection ocpCov) (ocpCovRobustifyPathC ocpCov)
let nlp0 = cpNlp cp0
gammas' = ocpCovGammas ocpCov :: shr Double
gammas :: J (JV shr) MX
gammas = catJV' (fmap realToFrac gammas')
rpathCUb :: shr Bounds
rpathCUb = fill (Nothing, Just 0)
robustPathCUb :: J (JV shr) (Vector Bounds)
robustPathCUb = catJV rpathCUb
-- the NLP
fg :: J (CollTrajCov sx ocp n deg) MX
-> J (JV fp) MX
-> (J (JV Id) MX, J (CollOcpCovConstraints ocp n deg sh shr sc) MX)
fg = getFgCov taus
computeCovariances
gammas
(robustify :: (J (JV shr) MX -> J (JV p) MX -> J (JV x) MX -> J (Cov (JV sx)) MX -> J (JV shr) MX))
(sbcFun :: SXFun (J (Cov (JV sx)) :*: J (Cov (JV sx))) (J sc))
(shFun :: SXFun (J (JV x) :*: J (Cov (JV sx))) (J sh))
(lagrangeFun :: SXFun (J (JV Id) :*: J (JV x) :*: J (Cov (JV sx)) :*: J (JV Id)) (J (JV Id)))
(mayerFun :: SXFun (J (JV Id) :*: (J (JV x) :*: (J (JV x) :*: (J (Cov (JV sx)) :*: J (Cov (JV sx)))))) (J (JV Id)))
(nlpFG nlp0)
computeCovariancesFun' <- toMXFun "compute covariances" (\(x :*: y) -> computeCovariances x y)
-- callbacks
let getPlotPoints :: J (CollTrajCov sx ocp n deg) (Vector Double) -> IO (DynPlotPoints Double)
getPlotPoints collTrajCov = do
let CollTrajCov _ collTraj = split collTrajCov
cpPlotPoints cp0 collTraj (catJV None)
getOutputs :: J (CollTrajCov sx ocp n deg) (Vector Double)
-> IO ( Vec n (StageOutputs x o h q qo po deg Double)
, Vec n (J (Cov (JV sx)) (Vector Double))
, J (Cov (JV sx)) (Vector Double)
)
getOutputs collTrajCov = do
let CollTrajCov p0 collTraj = split collTrajCov
outputs <- (cpOutputs cp0) collTraj (catJV None)
covTraj <- fmap split $ eval computeCovariancesFun' (v2d p0 :*: v2d collTraj)
let covs' = ctAllButLast covTraj
pF = ctLast covTraj
let covs = unJVec (split covs') :: Vec n (J (Cov (JV sx)) DMatrix)
return (outputs, fmap d2v covs, d2v pF)
nlp =
Nlp
{ nlpFG = fg
, nlpBX = cat $ CollTrajCov (ocpCovS0bnd ocpCov) (nlpBX nlp0)
, nlpBG = cat $ CollOcpCovConstraints
{ cocNormal = nlpBG nlp0
, cocCovPathC = jreplicate (ocpCovShBnds ocpCov)
, cocCovRobustPathC = jreplicate robustPathCUb
, cocSbc = ocpCovSbcBnds ocpCov
}
, nlpX0 = cat $ CollTrajCov (jfill 0) (nlpX0 nlp0)
, nlpP = catJV None
, nlpLamX0 = Nothing
, nlpLamG0 = Nothing
, nlpScaleF = ocpObjScale ocp
, nlpScaleX = Just $ cat $
CollTrajCov (fromMaybe (jfill 1) (ocpCovSScale ocpCov)) $
cat $ fillCollTraj
(fromMaybe (fill 1) (ocpXScale ocp))
(fromMaybe (fill 1) (ocpZScale ocp))
(fromMaybe (fill 1) (ocpUScale ocp))
(fromMaybe (fill 1) (ocpPScale ocp))
(fromMaybe 1 (ocpTScale ocp))
, nlpScaleG = Just $ cat $ CollOcpCovConstraints
{ cocNormal = cat $ fillCollConstraints
(fromMaybe (fill 1) (ocpXScale ocp))
(fromMaybe (fill 1) (ocpResidualScale ocp))
(fromMaybe (fill 1) (ocpBcScale ocp))
(fromMaybe (fill 1) (ocpPathCScale ocp))
, cocCovPathC = jreplicate (fromMaybe (jfill 1) (ocpCovPathCScale ocpCov))
, cocCovRobustPathC = jreplicate $
fromMaybe (jfill 1) $
fmap catJV (ocpCovRobustPathCScale ocpCov)
, cocSbc = fromMaybe (jfill 1) (ocpCovSbcScale ocpCov)
}
}
computeSensitivitiesFun' <- toMXFun "compute sensitivities" computeSensitivities
return $ CollCovProblem { ccpNlp = nlp
, ccpPlotPoints = getPlotPoints
, ccpOutputs = getOutputs
, ccpSensitivities = computeSensitivitiesFun'
, ccpCovariances = computeCovariancesFun'
, ccpDirCollOpts = dirCollOpts
}
getFgCov ::
forall ocp x z u p r c h fp sx sh shr sc n deg .
( Dim deg, Dim n, Vectorize x, Vectorize z, Vectorize u, Vectorize p
, Vectorize h, Vectorize c, Vectorize r, Vectorize fp
, Vectorize sx, View sc, View sh, Vectorize shr
, X ocp ~ x
, Z ocp ~ z
, U ocp ~ u
, P ocp ~ p
, R ocp ~ r
, C ocp ~ c
, H ocp ~ h
, FP ocp ~ fp
)
-- taus
=> Vec deg Double
-> (J (Cov (JV sx)) MX -> J (CollTraj x z u p n deg) MX -> J (CovTraj sx n) MX)
-- gammas
-> J (JV shr) MX
-- robustify
-> (J (JV shr) MX -> J (JV p) MX -> J (JV x) MX -> J (Cov (JV sx)) MX -> J (JV shr) MX)
-- sbcFun
-> SXFun (J (Cov (JV sx)) :*: J (Cov (JV sx))) (J sc)
-- shFun
-> SXFun (J (JV x) :*: J (Cov (JV sx))) (J sh)
-- lagrangeFun
-> SXFun
(J (JV Id) :*: J (JV x) :*: J (Cov (JV sx)) :*: J (JV Id)) (J (JV Id))
-- mayerFun
-> SXFun
(J (JV Id) :*: J (JV x) :*: J (JV x) :*: J (Cov (JV sx)) :*: J (Cov (JV sx))) (J (JV Id))
-> (J (CollTraj' ocp n deg) MX -> J (JV fp) MX -> (J (JV Id) MX, J (CollOcpConstraints' ocp n deg) MX)
)
-> J (CollTrajCov sx ocp n deg) MX
-> J (JV fp) MX
-> (J (JV Id) MX, J (CollOcpCovConstraints ocp n deg sh shr sc) MX)
getFgCov
taus computeCovariances
gammas robustify sbcFun shFun lagrangeFun mayerFun
normalFG collTrajCov nlpParams =
(obj0 + objectiveLagrangeCov + objectiveMayerCov, cat g)
where
CollTrajCov p0 collTraj = split collTrajCov
(obj0, g0) = normalFG collTraj nlpParams
g = CollOcpCovConstraints
{ cocNormal = g0
, cocCovPathC = cat (JVec covPathConstraints)
, cocCovRobustPathC = cat (JVec robustifiedPathC)
, cocSbc = call sbcFun (p0 :*: pF)
}
-- split up the design vars
CollTraj tf parm stages' xf = split collTraj
stages = unJVec (split stages') :: Vec n (J (CollStage (JV x) (JV z) (JV u) deg) MX)
spstages = fmap split stages :: Vec n (CollStage (JV x) (JV z) (JV u) deg MX)
objectiveMayerCov = call mayerFun (tf :*: x0 :*: xf :*: p0 :*: pF)
-- timestep
dt = tf / fromIntegral n
n = reflectDim (Proxy :: Proxy n)
-- times at each collocation point
t0s :: Vec n (J (JV Id) MX)
(t0s, _) = TV.tvunzip $ timesFromTaus 0 (fmap realToFrac taus) dt
-- initial point at each stage
x0s :: Vec n (J (JV x) MX)
x0s = fmap (\(CollStage x0' _) -> x0') spstages
x0 = (\(CollStage x0' _) -> x0') (TV.tvhead spstages)
-- sensitivities = call computeSensitivities collTraj
covs :: Vec n (J (Cov (JV sx)) MX)
covs = unJVec (split covs')
covs' :: J (JVec n (Cov (JV sx))) MX -- all but last covariance
pF :: J (Cov (JV sx)) MX -- last covariances
CovTraj covs' pF = split (computeCovariances p0 collTraj)
-- lagrange term
objectiveLagrangeCov = (lagrangeF + lagrange0s) / fromIntegral n
where
lagrangeF = call lagrangeFun (tf :*: xf :*: pF :*: tf)
lagrange0s =
sum $ F.toList $
TV.tvzipWith3 (\tk xk pk -> call lagrangeFun (tk :*: xk :*: pk :*: tf)) t0s x0s covs
covPathConstraints :: Vec n (J sh MX)
covPathConstraints = TV.tvzipWith (\xk pk -> call shFun (xk:*:pk)) x0s covs
robustifiedPathC :: Vec n (J (JV shr) MX)
robustifiedPathC = TV.tvzipWith (robustify gammas parm) x0s covs