goal-simulation-0.1: Goal/Simulation/Optimization.hs
-- | The Map module provides tools for developing function space 'Manifold's.
-- A map is a 'Manifold' where the 'Point's of the Manifold represent
-- parametric functions between 'Manifold's. The defining feature of 'Map's is
-- that they have a particular 'Domain' and 'Codomain', which themselves are
-- 'Manifold's.
module Goal.Simulation.Optimization (
-- * Mean Squared Error
meanSquaredError
-- * Cauchy Sequences
, cauchyLimit
, cauchySequence
-- * Gradient Pursuit
, stochasticGradientDescent
, stochasticGradientAscent
, stochasticVanillaGradientDescent
, stochasticVanillaGradientAscent
, boundedStochasticVanillaGradientDescent
, boundedStochasticVanillaGradientAscent
-- * Least Squares
, designMatrix
, leastSquares
, leastSquares0
-- ** Newton
, newtonStep
, newtonSequence
-- ** Gauss Newton
, gaussNewtonStep
) where
--- Imports ---
import Prelude hiding (map,minimum,maximum)
-- Goal --
import Goal.Core
import Goal.Geometry
import Goal.Probability
import Goal.Simulation.Mealy
--- Stochastic Pursuit ---
type StochasticPursuit x c m = Mealy x (c :#: m)
--- Gradient Descent ---
stochasticGradientAscent :: (Riemannian c m, Manifold m)
=> Double -- ^ Step size
-> (c :#: m -> x -> forall s . RandST s (Differentials :#: Tangent c m)) -- ^ Gradient calculator
-> (c :#: m) -- ^ The initial point
-> RandST r (StochasticPursuit x c m) -- ^ The gradient ascent
stochasticGradientAscent eps0 f0' = accumulateRandomFunction (accumulator eps0 f0')
where accumulator eps f' x cm = do
dcm <- f' cm x
let cm' = gradientStep eps $ sharp dcm
return (cm',cm')
boundedStochasticVanillaGradientAscent :: Manifold m
=> Double -- ^ Step size
-> Double -- ^ Gradient Rejection Bound
-> (c :#: m -> x -> forall s . RandST s (Differentials :#: Tangent c m)) -- ^ Gradient calculator
-> (c :#: m) -- ^ The initial point
-> RandST r (StochasticPursuit x c m) -- ^ The gradient ascent
boundedStochasticVanillaGradientAscent eps0 bnd0 f0' = accumulateRandomFunction (accumulator eps0 bnd0 f0')
where accumulator eps bnd f' x cm = do
dcm <- f' cm x
let cm' = if maximum (abs <$> listCoordinates dcm) < bnd
then gradientStep eps $ breakChart dcm
else trace "Ping!" cm
return (cm',cm')
stochasticVanillaGradientAscent :: Manifold m
=> Double -- ^ Step size
-> (c :#: m -> x -> forall s . RandST s (Differentials :#: Tangent c m)) -- ^ Gradient calculator
-> (c :#: m) -- ^ The initial point
-> RandST r (StochasticPursuit x c m) -- ^ The gradient ascent
stochasticVanillaGradientAscent eps0 f0' = accumulateRandomFunction (accumulator eps0 f0')
where accumulator eps f' x cm = do
dcm <- f' cm x
let cm' = gradientStep eps $ breakChart dcm
return (cm',cm')
stochasticGradientDescent :: (Riemannian c m, Manifold m)
=> Double -- ^ Step size
-> (c :#: m -> x -> forall s . RandST s (Differentials :#: Tangent c m)) -- ^ Gradient calculator
-> (c :#: m) -- ^ The initial point
-> RandST r (StochasticPursuit x c m) -- ^ The gradient ascent
stochasticGradientDescent eps = stochasticGradientAscent (-eps)
boundedStochasticVanillaGradientDescent :: Manifold m
=> Double -- ^ Step size
-> Double -- ^ Gradient Rejection Bound
-> (c :#: m -> x -> forall s . RandST s (Differentials :#: Tangent c m)) -- ^ Gradient calculator
-> (c :#: m) -- ^ The initial point
-> RandST r (StochasticPursuit x c m) -- ^ The gradient ascent
boundedStochasticVanillaGradientDescent eps = boundedStochasticVanillaGradientAscent (-eps)
stochasticVanillaGradientDescent :: Manifold m
=> Double -- ^ Step size
-> (c :#: m -> x -> forall s . RandST s (Differentials :#: Tangent c m)) -- ^ Gradient calculator
-> (c :#: m) -- ^ The initial point
-> RandST r (StochasticPursuit x c m) -- ^ The gradient ascent
stochasticVanillaGradientDescent eps = stochasticVanillaGradientAscent (-eps)
--- Mean Squared Error --
meanSquaredError
:: ((c :#: m) -> [x] -> [Double]) -- ^ Error Function
-> (c :#: m) -- ^ Current Point
-> [x] -- ^ Sample points
-> Double -- ^ Mean squared error
meanSquaredError err p xs =
let rsdls = err p xs
in (*0.5) . mean $ (**2) <$> rsdls
--- Cauchy Sequences ---
cauchyLimit :: Manifold m => Int -> Double -> [c :#: m] -> c :#: m
-- | Attempts to calculate the limit of a sequence. This finds the iterate with a
-- sufficiently small 'Euclidean' distance from the previous iterate, or returns
-- the nth iterate.
cauchyLimit n eps ps = last $ cauchySequence n eps ps
cauchySequence :: Manifold m => Int -> Double -> [c :#: m] -> [c :#: m]
cauchySequence n eps ps =
let ps' = take n ps
pps' = takeWhile taker . zip ps' $ tail ps'
in head ps : map snd pps'
where taker (p1,p2) = let p = alterChart Cartesian $ p1 <-> p2 in eps < sqrt (p <.> p)
-- Least Squares --
designMatrix :: Manifold m => [c :#: m] -> Function (Dual c) Cartesian :#: Tensor Euclidean m
-- | A glorified fromRows operation.
designMatrix rws = matrixTranspose $ coordinateTransform rws
leastSquares :: Manifold m => [c :#: m] -> [Double] -> Dual c :#: m
leastSquares xs ys =
let mtx = designMatrix xs
mtxt = matrixTranspose mtx
prj = matrixInverse (mtxt <#> mtx) <#> mtxt
in prj >.> euclideanPoint ys
leastSquares0 :: Manifold m => (Function c Cartesian :#: Tensor Euclidean m) -> [Double] -> c :#: m
leastSquares0 mtx ys =
let mtxt = matrixTranspose mtx
prj = matrixInverse (mtxt <#> mtx) <#> mtxt
in prj >.> euclideanPoint ys
-- Newton --
newtonStep :: Manifold m
=> Double -- ^ Step size
-> (Differentials :#: Tangent c m) -- ^ Derivatives
-> (Function Partials Differentials :#: Tensor (Tangent c m) (Tangent c m)) -- ^ Hessian
-> (c :#: m) -- ^ Step
newtonStep eps f' f'' = gradientStep (-eps) $ matrixInverse f'' >.> f'
newtonSequence :: Manifold m
=> Double -- ^ Step Size
-> (c :#: m -> Differentials :#: Tangent c m) -- ^ Derivatives
-> (c :#: m -> Function Partials Differentials :#: Tensor (Tangent c m) (Tangent c m)) -- ^ Hessian
-> (c :#: m) -- ^ Initial point
-> [c :#: m] -- ^ Newton sequence
newtonSequence eps f' f'' = iterate iterator
where iterator p = newtonStep eps (f' p) (f'' p)
-- Gauss Newton --
gaussNewtonStep :: Manifold m => Double -> [Double] -> [Differentials :#: Tangent c m] -> c :#: m
gaussNewtonStep eps rs grds = gradientStep (-eps) $ leastSquares0 (designMatrix grds) rs
--- Graveyard ---
{-
gaussNewtonPursuit :: Manifold m
=> Double -- ^ Damping Factor
-> (c :#: m -> [x] -> [Double]) -- ^ Residual Function
-> (c :#: m -> [x] -> [Differentials :#: Tangent c m]) -- ^ Residual Differential
-> (c :#: m) -- ^ Initial guess
-> StochasticPursuit x c m -- ^ Pursuit
gaussNewtonPursuit dmp residual residuald = accumulateFunction accumulator
where accumulator xs cm =
let cm' = gaussNewtonStep dmp (residual cm xs) (residuald cm xs)
in (cm', cm')
-}