l-bfgs-b 0.1 → 0.1.0.1
raw patch · 6 files changed
+46/−93 lines, 6 files
Files
- examples/Example1.hs +0/−42
- examples/Example2.hs +0/−26
- examples/build.sh +0/−6
- l-bfgs-b.cabal +18/−4
- src/Numeric/LBFGSB.hs +27/−14
- src/Numeric/LBFGSB/Result.hs +1/−1
− examples/Example1.hs
@@ -1,42 +0,0 @@-module Main where--import Numeric.LBFGSB-import Numeric.LBFGSB.Result-import qualified Data.Vector.Storable as V---- Example optimization problem taken from driver1.f in the tarball--- for version 3.0 of L-BFGS-B itself.--n :: Int-n = 25--f :: V.Vector Double -> Double-f x = 4* (V.foldl (\s i -> s + (x V.! i - (x V.! (i-1))^2)^2) (0.25* (x V.! 0 - 1)^2) (V.enumFromN 1 (n-1)))--g :: V.Vector Double -> V.Vector Double-g x = V.generate n (\i -> 8*(t (i-1)) - 1.6e1*(x V.! i)*(t i))- where- t i- | i == -1 = 0.25*(x V.! 0 - 1)- | i == n-1 = 0- | otherwise = x V.! (i+1) - (x V.! i)^2--bounds :: [(Maybe Double, Maybe Double)]-bounds = map (\i -> if odd i then (Just 1e0, Just 1e2) else (Just (-1e2), Just 1e2)) [1..n]--start :: V.Vector Double-start = V.replicate n 3.0--main :: IO ()-main = putStrLn "Testing with function and parameters from driver1.f from L-BFGS-B 3.0 distribution archive." >>- let- res = minimize 5 1e7 1e-5 Nothing bounds start f g- in- putStrLn "Full results:" >>- print res >>- putStrLn "Solution point:" >>- print (solution res) >>- putStrLn "Steps needed:" >>- print (length (backtrace res)) >>- putStrLn "Function value at solution:" >>- print (f (solution res))
− examples/Example2.hs
@@ -1,26 +0,0 @@-module Main where--import Numeric.LBFGSB-import Numeric.LBFGSB.Convenience-import Numeric.LBFGSB.Result-import qualified Data.Vector.Storable as V---- 2D Rosenbrock function with approximate derivatives.--rosenbrock :: V.Vector Double -> Double-rosenbrock x = (1 - x0)^2 + 100*(x1-x0^2)^2- where- x0 = x V.! 0- x1 = x V.! 1--main :: IO ()-main = putStrLn "Testing with Rosenbrock function, both unbounded and bounded with minimum outside bounds." >>- let- resUnbounded = minimize 5 1e0 1e-12 (Just 100) [] (V.fromList [100, 100]) rosenbrock (approximateGradient 1e-6 rosenbrock)- resBounded = minimize 5 1e0 1e-12 (Just 100) [(Nothing, Nothing), (Nothing, Just 0.1)] (V.fromList [0, 0]) rosenbrock (approximateGradient 1e-6 rosenbrock)- in- putStrLn "Unbounded:" >>- print resUnbounded >>- putStrLn "-------------------" >>- putStrLn "Bounded to (-infty, 0.1) in the second direction only:" >>- print resBounded
− examples/build.sh
@@ -1,6 +0,0 @@-#!/bin/bash--ghc -threaded -i../src -O2 -fforce-recomp -o example1 --make Example1.hs -llbfgsb -ghc -threaded -i../src -O2 -fforce-recomp -o example2 --make Example2.hs -llbfgsb--
l-bfgs-b.cabal view
@@ -1,12 +1,12 @@ Name: l-bfgs-b-Version: 0.1+Version: 0.1.0.1 Synopsis: Bindings to L-BFGS-B, Fortran code for limited-memory quasi-Newton bound-constrained optimization Homepage: http://nonempty.org/software/haskell-l-bfgs-b License: BSD3 License-file: LICENSE Author: Gard Spreemann Maintainer: Gard Spreemann <gspreemann@gmail.com>-Copyright: 2013 Gard Spreemann+Copyright: 2013-2014 Gard Spreemann Category: Math Build-type: Simple Cabal-version: >=1.4@@ -26,18 +26,32 @@ output as specified in the L-BFGS-B code. However, there are two places in said code where the flag is ignored and output still occurs. If it bothers you that code exposed as pure prints things, see <http://nonempty.org/software/haskell-l-bfgs-b> for information on a simple patch for L-BFGS-B. The SciPy project- has described the same behavior at <http://projects.scipy.org/scipy/ticket/1742>.+ has described the same behavior in <https://github.com/scipy/scipy/issues/2261>. .+ The code assumes that your Haskell compiler's Doubles are IEEE-754 doubles.+ . Example on usage can be found in the included @examples@ directiory. . The current version has only been lightly tested, and should not be trusted for serious work. Feedback is appreciated. .+ Changes in version 0.1.0.1:+ .+ * Check some function arguments for sanity and cause a runtime error otherwise.+ .+ * Add note above on double representation.+ .+ * Added TODO below.+ . Changes in version 0.1: . * There has only been cursory testing, so do not trust these bindings yet. . * Initial release.- . + .+ TODO:+ .+ * Be more generic with regards to vector types?+ . . \[1] R. H. Byrd, P. Lu and J. Nocedal. A Limited Memory Algorithm for Bound Constrained Optimization, (1995), SIAM Journal on Scientific and Statistical Computing , 16, 5, pp. 1190-1208.
src/Numeric/LBFGSB.hs view
@@ -28,9 +28,9 @@ -- | Minimization using L-BFGS-B. If you only require the solution--- point, and not the full 'R.Result', see 'minimize''. If the--- arguments do not satisfy the given requirements, behavior is--- undefined and the program may even crash.+-- point, and not the full 'R.Result', see 'minimize''. Take care to+-- satisfy the requirements on the arguments. Failure to do so may result+-- in a runtime error, or, when noted, undefined behavior/crash. minimize :: Int -- ^ @m@: The maximum number of variable metric corrections used -- to define the limited memory matrix. /Suggestion:/ @5@. -> Double -- ^ @factr@: Iteration stops when the relative change in function value@@ -49,12 +49,20 @@ -- as constraint. -> V.Vector Double -- ^ @x0@: Starting point. The point /must/ be within the bounds. -> (V.Vector Double -> Double) -- ^ @f@: Function to minimize. /Must/ take 'V.Vector's of precisely the same- -- length as @x0@.+ -- length as @x0@, or else behavior is undefined (the program may crash)! -> (V.Vector Double -> V.Vector Double) -- ^ @g@: Gradient of @f@. /Must/ take and return 'V.Vector's of precisely the same- -- length as @x0@. "Numeric.LBFGSB.Convenience" provides a simple- -- approximation of the gradient if you do not have the real one.+ -- length as @x0@, or else behavior is undefined (the program may crash)!+ -- "Numeric.LBFGSB.Convenience" provides a simple approximation of the gradient if+ -- you do not have the real one. -> R.Result-minimize m factr tol steps bounds x0 f g = unsafeDupablePerformIO (runDriver m factr tol steps bounds x0 f g)+minimize m factr pgtol steps bounds x0 f g + | not (factr >= 0) = error "factr must be >=0."+ | not (pgtol >= 0) = error "pgtol must be >=0."+ | not (maybe True (>0) steps) = error "steps must be >0."+ | not (inBounds bounds' x0) = error "x0 must be within bounds."+ | otherwise = unsafeDupablePerformIO (runDriver m factr pgtol steps bounds' x0 f g)+ where+ bounds' = take (V.length x0) (bounds ++ repeat (Nothing, Nothing)) -- | If L-BFGS-B converges within the specified number of steps, the -- solution point is returned as @'Just' solution@. Otherwise@@ -69,12 +77,20 @@ -> (V.Vector Double -> Double) -> (V.Vector Double -> V.Vector Double) -> Maybe (V.Vector Double)-minimize' m factr tol steps bounds x0 f g +minimize' m factr pgtol steps bounds x0 f g | R.stopReason result == R.Converged = Just $ R.solution result | otherwise = Nothing where- result = minimize m factr tol steps bounds x0 f g+ result = minimize m factr pgtol steps bounds x0 f g +inBounds :: [(Maybe Double, Maybe Double)] -> V.Vector Double -> Bool+inBounds bounds v = all ib (zip bounds (V.toList v))+ where+ ib ((Nothing, Nothing), _) = True+ ib ((Nothing, Just u), x) = x <= u+ ib ((Just l , Nothing), x) = x >= l+ ib ((Just l , Just u), x) = x >= l && x <= u+ data DriverContext = DriverContext { pn :: Ptr CInt , pm :: Ptr CInt , px :: Ptr Double@@ -134,7 +150,7 @@ runDriver m factr tol steps bounds x0 f g = let n = V.length x0- (ls, us, bds) = unzipBounds (take n (bounds ++ repeat (Nothing, Nothing)))+ (ls, us, bds) = unzipBounds bounds in with (fromIntegral n) $ \pn -> with (fromIntegral m) $ \pm ->@@ -201,9 +217,7 @@ makeCall :: DriverContext -> IO () makeCall context@(DriverContext pn pm px pl pu pnbd pf pg pfactr ppgtol pwa piwa ptask piprint pcsave plsave pisave pdsave)- = fortran_setulb pn pm px pl pu pnbd pf pg pfactr ppgtol pwa piwa ptask piprint pcsave plsave pisave pdsave --(fromIntegral taskLength) (fromIntegral csaveLength)--+ = fortran_setulb pn pm px pl pu pnbd pf pg pfactr ppgtol pwa piwa ptask piprint pcsave plsave pisave pdsave foreign import ccall "setulb_" fortran_setulb -- # Comments below are from the L-BFGS-B Fortran source code:@@ -325,6 +339,5 @@ -- the starting point of the line search; -- dsave(16) = the square of the 2-norm of the line search -- direction vector.--- -> CInt -> CInt -- FORTRAN string lengths piled at the end. Fixme, is this right? -> IO ()
src/Numeric/LBFGSB/Result.hs view
@@ -9,7 +9,7 @@ solution :: V.Vector Double -- ^ Solution point /if the minimization completed successfully/. See 'stopReason'. , backtrace :: [V.Vector Double] -- ^ The steps taken to reach the solution, in reverse order. Does not include the starting point. , stopReason :: StopReason -- ^ The reason L-BFGS-B terminated. Only if this is- -- 'Converted' should you consider the solution correct!+ -- 'Converged' should you consider the solution correct! } deriving (Show)