packages feed

lagrangian 0.4.0.1 → 0.5.0.0

raw patch · 4 files changed

+30/−26 lines, 4 filesdep ~addep ~test-frameworkdep ~test-framework-hunitPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: ad, test-framework, test-framework-hunit, test-framework-quickcheck2

API changes (from Hackage documentation)

+ Numeric.AD.Lagrangian: FU :: (forall s r. (Mode s, Mode r) => [AD2 s r a] -> AD2 s r a) -> FU a
+ Numeric.AD.Lagrangian: newtype FU a
+ Numeric.AD.Lagrangian: unFU :: FU a -> forall s r. (Mode s, Mode r) => [AD2 s r a] -> AD2 s r a
- Numeric.AD.Lagrangian: (<=>) :: ([a] -> a) -> a -> Constraint a
+ Numeric.AD.Lagrangian: (<=>) :: (forall s r. (Mode s, Mode r) => [AD2 s r a] -> AD2 s r a) -> a -> Constraint a
- Numeric.AD.Lagrangian: feasible :: (forall s r. (Mode s, Mode r) => [AD2 s r Double] -> AD2 s r Double) -> (forall s r. (Mode s, Mode r) => [Constraint (AD2 s r Double)]) -> [Double] -> Bool
+ Numeric.AD.Lagrangian: feasible :: (forall s r. (Mode s, Mode r) => [AD2 s r Double] -> AD2 s r Double) -> [Constraint Double] -> [Double] -> Bool
- Numeric.AD.Lagrangian: maximize :: Double -> (forall s r. (Mode s, Mode r) => [AD2 s r Double] -> AD2 s r Double) -> (forall s r. (Mode s, Mode r) => [Constraint (AD2 s r Double)]) -> Int -> Either (Result, Statistics) (Vector Double, Vector Double)
+ Numeric.AD.Lagrangian: maximize :: Double -> (forall s r. (Mode s, Mode r) => [AD2 s r Double] -> AD2 s r Double) -> [Constraint Double] -> Int -> Either (Result, Statistics) (Vector Double, Vector Double)
- Numeric.AD.Lagrangian: minimize :: Double -> (forall s r. (Mode s, Mode r) => [AD2 s r Double] -> AD2 s r Double) -> (forall s r. (Mode s, Mode r) => [Constraint (AD2 s r Double)]) -> Int -> Either (Result, Statistics) (Vector Double, Vector Double)
+ Numeric.AD.Lagrangian: minimize :: Double -> (forall s r. (Mode s, Mode r) => [AD2 s r Double] -> AD2 s r Double) -> [Constraint Double] -> Int -> Either (Result, Statistics) (Vector Double, Vector Double)
- Numeric.AD.Lagrangian: type AD2 s r a = AD s (AD r Double)
+ Numeric.AD.Lagrangian: type AD2 s r a = AD s (AD r a)
- Numeric.AD.Lagrangian: type Constraint a = ([a] -> a, a)
+ Numeric.AD.Lagrangian: type Constraint a = (FU a, a)

Files

lagrangian.cabal view
@@ -10,7 +10,7 @@ -- PVP summary:      +-+------- breaking API changes --                   | | +----- non-breaking API additions --                   | | | +--- code changes with no API change-version:             0.4.0.1+version:             0.5.0.0  -- A short (one-line) description of the package. synopsis:            Solve Lagrange multiplier problems@@ -94,11 +94,11 @@   build-depends: base ==4.6.*,                  nonlinear-optimization ==0.3.*,                   vector ==0.10.*, -                 ad ==3.3.*,+                 ad ==3.4.*,                  hmatrix == 0.14.*, -                 test-framework ==0.6.*, -                 test-framework-hunit ==0.2.*, -                 test-framework-quickcheck2 ==0.2.*,+                 test-framework ==0.8.*, +                 test-framework-hunit ==0.3.*, +                 test-framework-quickcheck2 ==0.3.*,                  HUnit == 1.2.*  
src/Numeric/AD/Lagrangian.hs view
@@ -11,6 +11,7 @@ module Numeric.AD.Lagrangian (     -- *** Helper types     AD2,+    FU(..),     (<=>),     Constraint,     -- ** Solver@@ -18,4 +19,5 @@     minimize,     -- *** Experimental features     feasible) where-import Numeric.AD.Lagrangian.Internal (AD2, (<=>), maximize, minimize, feasible, Constraint)+import Numeric.AD.Lagrangian.Internal (AD2, FU(..), +    (<=>), maximize, minimize, feasible, Constraint)
src/Numeric/AD/Lagrangian/Internal.hs view
@@ -13,24 +13,25 @@ import Numeric.AD.Internal.Tower  infixr 1 <=>--- | This is just a little bit of sugar for (,) to make constraints look like ---  equals-(<=>) :: ([a] -> a) -> a -> Constraint a-g <=> c = (g,c)--- | The type for the contraints.---   Given a constraint @g(x, y, ...) = c@, we would represent it as @(g, c)@.---   or with sugar @g@ '<=>' @c@-type Constraint a = ([a] -> a, a)+-- | Build a 'Constraint' from a function and a constant+(<=>) :: (forall s r. (Mode s, Mode r) => [AD2 s r a] -> AD2 s r a) -> a -> Constraint a+g <=> c = (FU g,c) -type AD2 s r a = AD s (AD r Double)+-- | A constraint of the form @g(x, y, ...) = c@. See '<=>' for constructing a 'Constraint'.+type Constraint a = (FU a, a) +type AD2 s r a = AD s (AD r a)++-- | A newtype wrapper for working with the rank 2 types constraint functions. +newtype FU a = FU {unFU :: forall s r. (Mode s, Mode r) => [AD2 s r a] -> AD2 s r a}+ -- | This is the lagrangian multiplier solver. It is assumed that the  --   objective function and all of the constraints take in the  --   same amount of arguments. minimize :: Double       -> (forall s r. (Mode s, Mode r) => [AD2 s r Double] -> AD2 s r Double)          -- ^ The function to minimize-      -> (forall s r. (Mode s, Mode r) => [Constraint (AD2 s r Double)] ) +      -> [Constraint Double]       -- ^ The constraints as pairs @g \<=\> c@ which represent equations        --   of the form @g(x, y, ...) = c@       -> Int @@ -44,8 +45,7 @@     obj argsAndLams =          squaredGrad (lagrangian toMin constraints argCount) argsAndLams     -    -- The mode does matter but I need to add annotation for the type checker-    constraintCount = length (constraints :: [Constraint (AD Tower (AD Tower Double))])+    constraintCount = length constraints           -- perhaps this should be exposed     guess = U.replicate (argCount + constraintCount) (1.0 :: Double) @@ -66,7 +66,7 @@ maximize :: Double       -> (forall s r. (Mode s, Mode r) => [AD2 s r Double] -> AD2 s r Double)          -- ^ The function to maximize-      -> (forall s r. (Mode s, Mode r) => [Constraint (AD2 s r Double)] ) +      -> [Constraint Double]        -- ^ The constraints as pairs @g \<=\> c@ which represent equations        --   of the form @g(x, y, ...) = c@       -> Int @@ -78,18 +78,18 @@ maximize tolerance toMax constraints argCount =      minimize tolerance (negate1 . toMax) constraints argCount -lagrangian :: Num a -           => ([a] -> a)+lagrangian :: (Num a, Mode s, Mode r)+           => (forall s r. (Mode s, Mode r) => [AD2 s r a] -> AD2 s r a)             -> [Constraint a]            -> Int-           -> [a]  -           -> a+           -> [AD2 s r a]  +           -> AD2 s r a lagrangian f constraints argCount argsAndLams = result where     args = take argCount argsAndLams     lams = drop argCount argsAndLams          -- g(x, y, ...) = c <=> g(x, y, ...) - c = 0-    appliedConstraints = fmap (\(f, c) -> f args - c) constraints+    appliedConstraints = fmap (\(FU f, c) -> f args - (auto . auto) c) constraints          -- L(x, y, ..., lam0, ...) = f(x, y, ...) + lam0 * (g0 - c0) ...      result = f args + (sum . zipWith (*) lams $ appliedConstraints)@@ -104,7 +104,7 @@ --   exactly how to implement that. This just checks the feasiblility at a point. --   If this ever returns false, 'solve' can fail. feasible :: (forall s r. (Mode s, Mode r) => [AD2 s r Double] -> AD2 s r Double)-         -> (forall s r. (Mode s, Mode r) => [Constraint (AD2 s r Double)] )+         -> [Constraint Double]          -> [Double]          -> Bool feasible toMin constraints points = result where
tests/Main.hs view
@@ -23,8 +23,10 @@ --class Approximate a where --    x =~= y :: a -> a -> Bool ++ entropyTest = (S.sum . S.map abs $ S.zipWith (-) actual expected) < 0.02 @?= True  where-    Right actual = fst <$> maximize 0.00001 f [(\xs -> sum xs, 1)] 3+    Right actual = fst <$> maximize 0.00001 f [sum <=> 1] 3     expected  = S.fromList [0.33, 0.33, 0.33]     f :: Floating a => [a] -> a     f = negate . sum . map (\x -> x * log x)