module Optimization.Constrained.Penalty
(
Opt
, FU(..)
, optimize
, constrainEQ
, constrainLT
, constrainGT
, minimize
, maximize
, lagrangian
) where
import Numeric.AD
import qualified Data.Vector as V
newtype FU f a = FU { runFU :: forall s. Mode s => f (AD s a) -> AD s a }
type V = V.Vector
data Opt f a = Opt (FU f a) (V (FU f a)) (V (FU f a))
optimize :: (forall s. Mode s => f (AD s a) -> AD s a) -> Opt f a
optimize f = Opt (FU f) V.empty V.empty
augment :: a -> V a -> V a
augment a xs = V.cons a xs
constrainEQ :: (forall s. Mode s => f (AD s a) -> AD s a)
-> Opt f a -> Opt f a
constrainEQ g (Opt f gs hs) = Opt f (augment (FU g) gs) hs
constrainLT :: (forall s. Mode s => f (AD s a) -> AD s a)
-> Opt f a -> Opt f a
constrainLT h (Opt f gs hs) = Opt f gs (augment (FU h) hs)
constrainGT :: (Num a) => (forall s. Mode s => f (AD s a) -> AD s a)
-> Opt f a -> Opt f a
constrainGT h (Opt f gs hs) = Opt f gs (augment (FU $ negate . h) hs)
minimize :: (Functor f, RealFrac a, Ord a, g ~ V)
=> (FU f a -> f a -> [f a])
-> Opt f a
-> a
-> f a
-> g a
-> [f a]
minimize minX opt alpha = go
where go x0 l0 = let l1 = fmap (*alpha) l0
x1 = head $ drop 100 $ minX (FU $ \x -> augLagrangian opt x (fmap realToFrac l1)) x0
in x1 : go x1 l1
maximize :: (Functor f, RealFrac a, Ord a, g ~ V)
=> (FU f a -> f a -> [f a])
-> Opt f a
-> a
-> f a
-> g a
-> [f a]
maximize minX (Opt (FU f) gs hs) alpha =
minimize minX (Opt (FU $ negate . f) gs hs) alpha
lagrangian :: (Num a) => Opt f a
-> (forall s. Mode s => f (AD s a) -> V (AD s a) -> AD s a)
lagrangian (Opt (FU f) gs hs) x l =
f x V.sum (V.zipWith (\lamb (FU g)->lamb * g x) l gs)
augLagrangian :: (Num a, Ord a) => Opt f a
-> (forall s. Mode s => f (AD s a) -> V (AD s a) -> AD s a)
augLagrangian (Opt (FU f) gs hs) x l =
f x + V.sum (V.zipWith (*) l $ V.concat [gs', hs'])
where gs' = V.map (\(FU g) -> (g x)^2) gs
hs' = V.map (\(FU h) -> (max 0 $ h x)^2) hs