diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,234 @@
+liblbfgs (MIT license):
+
+Copyright (c) 1990 Jorge Nocedal
+Copyright (c) 2007-2010 Naoaki Okazaki
+
+Haskell module (Apache License version 2.0):
+
+Copyright (c) 2010 Daniël de Kok
+
+---
+
+The MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+---
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/Numeric/LBFGS.hs b/Numeric/LBFGS.hs
new file mode 100644
--- /dev/null
+++ b/Numeric/LBFGS.hs
@@ -0,0 +1,259 @@
+-- |
+-- Module      : Numeric.LBFGS
+-- Copyright   : (c) 2010 Daniël de Kok
+-- License     : Apache 2
+--
+--
+-- Maintainer  : Daniël de Kok <me@danieldk.eu>
+-- Stability   : experimental
+--
+-- Binding for the liblbfgs library, much implements the Limited-memory
+-- Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) method for solving
+-- unconstrained minimization problems. The original C library is
+-- available from:
+--
+-- <http://www.chokkan.org/software/liblbfgs/>
+
+module Numeric.LBFGS (LineSearchAlgorithm(..), EvaluateFun,
+                      ProgressFun, LBFGSResult, lbfgs) where
+
+import Data.Array.Storable (StorableArray,
+                            unsafeForeignPtrToStorableArray)
+import Foreign.C.Types (CDouble, CInt)
+import Foreign.ForeignPtr (newForeignPtr_)
+import Foreign.Marshal.Alloc (malloc, free)
+import Foreign.Ptr (Ptr, freeHaskellFunPtr, nullPtr, plusPtr)
+import Foreign.Storable (Storable(..), peek, poke, sizeOf)
+
+import qualified Numeric.LBFGS.Raw as R
+import Numeric.LBFGS.Raw (CEvaluateFun, CProgressFun, CLBFGSParameter(..),
+                          defaultCParam, CLBFGSResult(..),
+                          c_lbfgs_malloc, c_lbfgs_free,
+                          c_lbfgs_evaluate_t_wrap, c_lbfgs_progress_t_wrap,
+                          c_lbfgs
+                         )
+
+-- |
+-- Various line search algorithms. Wolfe backtracking algorithms require
+-- a coefficient.
+data LineSearchAlgorithm = DefaultLineSearch
+                         | MoreThuente
+                         | BacktrackingArmijo
+                         | Backtracking
+                         | BacktrackingWolfe       {coeff :: Double }
+                         | BacktrackingStrongWolfe {coeff :: Double }
+
+mergeLineSearchAlgorithm :: CLBFGSParameter -> LineSearchAlgorithm ->
+                            CLBFGSParameter
+mergeLineSearchAlgorithm p DefaultLineSearch =
+    p {R.linesearch = R.defaultLineSearch}
+mergeLineSearchAlgorithm p MoreThuente =
+    p { R.linesearch = R.moreThuente }
+mergeLineSearchAlgorithm p BacktrackingArmijo =
+    p { R.linesearch = R.backtrackingArmijo }
+mergeLineSearchAlgorithm p Backtracking =
+    p { R.linesearch = R.backtracking }
+mergeLineSearchAlgorithm p (BacktrackingWolfe c) =
+    p { R.linesearch = R.backtrackingWolfe,
+        R.wolfe      = realToFrac c }
+mergeLineSearchAlgorithm p (BacktrackingStrongWolfe c) =
+    p { R.linesearch = R.backtrackingStrongWolfe,
+        R.wolfe      = realToFrac c }
+
+withParam :: LineSearchAlgorithm -> CLBFGSParameter
+withParam lineSearch =
+    mergeLineSearchAlgorithm defaultCParam lineSearch
+
+
+data LBFGSResult
+    = Success
+    | Stop
+    | AlreadyMinimized
+    | UnknownError
+    | LogicError
+    | OutOfMemory
+    | Canceled
+    | InvalidN
+    | InvalidNSSE
+    | InvalidXSSE
+    | InvalidEpsilon
+    | InvalidTestPeriod
+    | InvalidDelta
+    | InvalidLineSearch
+    | InvalidMinStep
+    | InvalidMaxStep
+    | InvalidFtol
+    | InvalidWolfe
+    | InvalidGtol
+    | InvalidXtol
+    | InvalidMaxLineSearch
+    | InvalidOrthantwise
+    | InvalidOrthantwiseStart
+    | InvalidOrthantwiseEnd
+    | OutOfInterval
+    | IncorrectTMinMax
+    | RoundingError
+    | MinimumStep
+    | MaximumStep
+    | MaximumLineSearch
+    | MaximumIteration
+    | WidthTooSmall
+    | InvalidParameters
+    | IncreaseGradient
+    deriving (Eq, Show)
+
+deriveResult :: CLBFGSResult -> LBFGSResult
+deriveResult r
+    | r == R.lbfgsSuccess = Success
+    | r == R.lbfgsStop = Stop
+    | r == R.lbfgsAlreadyMinimized = AlreadyMinimized
+    | r == R.lbfgserrUnknownerror = UnknownError
+    | r == R.lbfgserrLogicerror = LogicError
+    | r == R.lbfgserrOutofmemory = OutOfMemory
+    | r == R.lbfgserrCanceled = Canceled
+    | r == R.lbfgserrInvalidN = InvalidN
+    | r == R.lbfgserrInvalidNSse = InvalidNSSE
+    | r == R.lbfgserrInvalidXSse = InvalidXSSE
+    | r == R.lbfgserrInvalidEpsilon = InvalidEpsilon
+    | r == R.lbfgserrInvalidTestperiod = InvalidTestPeriod
+    | r == R.lbfgserrInvalidDelta = InvalidDelta
+    | r == R.lbfgserrInvalidLinesearch = InvalidLineSearch
+    | r == R.lbfgserrInvalidMinstep = InvalidMinStep
+    | r == R.lbfgserrInvalidMaxstep = InvalidMaxStep
+    | r == R.lbfgserrInvalidFtol = InvalidFtol
+    | r == R.lbfgserrInvalidWolfe = InvalidWolfe
+    | r == R.lbfgserrInvalidGtol = InvalidGtol
+    | r == R.lbfgserrInvalidXtol = InvalidXtol
+    | r == R.lbfgserrInvalidMaxlinesearch = InvalidMaxLineSearch
+    | r == R.lbfgserrInvalidOrthantwise = InvalidOrthantwise
+    | r == R.lbfgserrInvalidOrthantwiseStart = InvalidOrthantwiseStart
+    | r == R.lbfgserrInvalidOrthantwiseEnd = InvalidOrthantwiseEnd
+    | r == R.lbfgserrOutofinterval = OutOfInterval
+    | r == R.lbfgserrIncorrectTminmax = IncorrectTMinMax
+    | r == R.lbfgserrRoundingError = RoundingError
+    | r == R.lbfgserrMinimumstep = MinimumStep
+    | r == R.lbfgserrMaximumstep = MaximumStep
+    | r == R.lbfgserrMaximumlinesearch = MaximumLineSearch
+    | r == R.lbfgserrMaximumiteration = MaximumIteration
+    | r == R.lbfgserrWidthtoosmall = WidthTooSmall
+    | r == R.lbfgserrInvalidparameters = InvalidParameters
+    | r == R.lbfgserrIncreasegradient = IncreaseGradient
+
+cDoublePlusPtr :: Ptr CDouble -> Int -> Ptr CDouble
+cDoublePlusPtr ptr n = plusPtr ptr (n * sizeOf (undefined :: CDouble))
+
+listToVector :: [Double] -> IO (CInt, Ptr CDouble)
+listToVector l = do
+  v <- c_lbfgs_malloc n
+  copyList l v
+  return (n, v)
+    where n = fromIntegral . length $ l
+
+copyList :: [Double] -> Ptr CDouble -> IO ()
+copyList [] _ = return ()
+copyList l p = do
+  poke p $ realToFrac $ head l
+  copyList (tail l) (cDoublePlusPtr p 1)
+
+
+freeVector :: Ptr CDouble -> IO ()
+freeVector = c_lbfgs_free
+
+vectorToList :: CInt -> Ptr CDouble -> IO ([Double])
+vectorToList cn p = vectorToList_ p (cDoublePlusPtr p n) []
+    where n = fromIntegral cn
+
+vectorToList_ :: Ptr CDouble -> Ptr CDouble -> [Double] -> IO ([Double])
+vectorToList_ pStart pCur l
+    | pCur >= pStart = do
+  cval <- peek pCur
+  let val = realToFrac cval
+  vectorToList_ pStart (cDoublePlusPtr pCur (-1)) (val:l)
+    | otherwise = return l
+
+
+-- |
+-- Type signature for the objective function and gradient evaluations.
+type EvaluateFun a =
+    a                            -- ^ Instance data
+    -> StorableArray Int CDouble -- ^ Current variables (should not be
+                                 --   modified by the function)
+    -> StorableArray Int CDouble -- ^ Gradients
+    -> CInt                      -- ^ Number of variables
+    -> CDouble                   -- ^ Step of the line search algorithm
+    -> IO (CDouble)              -- ^ Value of the objective function
+
+wrapEvaluateFun :: (Storable a) => EvaluateFun a -> Ptr a -> Ptr CDouble ->
+                   Ptr CDouble -> CInt -> CDouble -> IO (CDouble)
+wrapEvaluateFun fun inst x g n step = do
+  let nInt = fromIntegral n
+  instV <- peek inst
+  xFp <- newForeignPtr_ x
+  xArr <- unsafeForeignPtrToStorableArray xFp (0, nInt - 1)
+  gFp <- newForeignPtr_ g
+  gArr <- unsafeForeignPtrToStorableArray gFp (0, nInt - 1)
+  fun instV xArr gArr n step
+
+-- |
+-- Type signature for a function reporting on the progress of the
+-- optimization.
+type ProgressFun a =
+    a                            -- ^ Instance data
+    -> StorableArray Int CDouble -- ^ Variables (should not be modified
+                                 --   by the function)
+    -> StorableArray Int CDouble -- ^ Gradients (should not be modified
+                                 --   by the function)
+    -> CDouble                   -- ^ Value of the objective function
+    -> CDouble                   -- ^ Euclidean norm of the variables
+    -> CDouble                   -- ^ Eucledian norm of the gradients
+    -> CDouble                   -- ^ Step of the line search algorithm
+    -> CInt                      -- ^ Number of variables
+    -> CInt                      -- ^ Iteration count
+    -> CInt                      -- ^ Number of evaluations for this iteration
+    -> IO (CInt)                 -- ^ Return zero to continue the evaluation,
+                                 --   non-zero otherwise
+
+wrapProgressFun :: (Storable a) => ProgressFun a -> Ptr a -> Ptr CDouble ->
+                   Ptr CDouble-> CDouble -> CDouble -> CDouble -> CDouble ->
+                   CInt -> CInt -> CInt -> IO (CInt)
+wrapProgressFun fun inst x g fx xn gn step n k ls = do
+  let nInt = fromIntegral n
+  instV <- peek inst
+  xFp <- newForeignPtr_ x
+  xArr <- unsafeForeignPtrToStorableArray xFp (0, nInt - 1)
+  gFp <- newForeignPtr_ g
+  gArr <- unsafeForeignPtrToStorableArray gFp (0, nInt - 1)
+  fun instV xArr gArr fx xn gn step n k ls
+
+-- |
+-- Start a L-BFGS optimization. The initial variables should be
+-- provided as a list of doubles.
+lbfgs :: (Storable a) =>
+         LineSearchAlgorithm       -- ^ The line search algorithm
+      -> EvaluateFun a             -- ^ Objective function
+      -> ProgressFun a             -- ^ Progress report function
+      -> a                         -- ^ Instance data
+      -> [Double]                  -- ^ Initial variable values
+      -> IO(LBFGSResult, [Double]) -- ^ Result and variable values
+lbfgs ls evalFun progressFun inst p = lbfgs_ ls (wrapEvaluateFun evalFun)
+                                 (wrapProgressFun progressFun) inst p
+
+lbfgs_ :: (Storable a) => LineSearchAlgorithm -> CEvaluateFun a ->
+          CProgressFun a -> a -> [Double] -> IO(LBFGSResult, [Double])
+lbfgs_ ls evalFun progressFun inst p = do
+  (n, pVec) <- listToVector p
+  let param = withParam ls
+  instP <- malloc
+  poke instP inst
+  paramP <- malloc
+  poke paramP param
+  evalW <- c_lbfgs_evaluate_t_wrap evalFun
+  progressW <- c_lbfgs_progress_t_wrap progressFun
+  r <- c_lbfgs n pVec nullPtr evalW progressW instP paramP
+  freeHaskellFunPtr progressW
+  freeHaskellFunPtr evalW
+  free paramP
+  free instP
+  freeVector pVec
+  rl <- vectorToList n pVec
+  return (deriveResult $ CLBFGSResult r, rl)
diff --git a/Numeric/LBFGS/Raw.hsc b/Numeric/LBFGS/Raw.hsc
new file mode 100644
--- /dev/null
+++ b/Numeric/LBFGS/Raw.hsc
@@ -0,0 +1,186 @@
+{-# LANGUAGE ForeignFunctionInterface, GeneralizedNewtypeDeriving #-}
+
+#include "lbfgs.h"
+#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)
+
+module Numeric.LBFGS.Raw (CLineSearchAlgorithm, CLBFGSParameter(..),
+                          CEvaluateFun, CProgressFun,
+                          defaultCParam, c_lbfgs, c_lbfgs_malloc,
+                          c_lbfgs_free, c_lbfgs_evaluate_t_wrap,
+                          c_lbfgs_progress_t_wrap,
+
+                          defaultLineSearch, moreThuente, backtrackingArmijo,
+                          backtracking, backtrackingWolfe,
+                          backtrackingStrongWolfe,
+
+                          CLBFGSResult(..),
+                          lbfgsSuccess,
+                          lbfgsConvergence,
+                          lbfgsStop,
+                          lbfgsAlreadyMinimized,
+                          lbfgserrUnknownerror,
+                          lbfgserrLogicerror,
+                          lbfgserrOutofmemory,
+                          lbfgserrCanceled,
+                          lbfgserrInvalidN,
+                          lbfgserrInvalidNSse,
+                          lbfgserrInvalidXSse,
+                          lbfgserrInvalidEpsilon,
+                          lbfgserrInvalidTestperiod,
+                          lbfgserrInvalidDelta,
+                          lbfgserrInvalidLinesearch,
+                          lbfgserrInvalidMinstep,
+                          lbfgserrInvalidMaxstep,
+                          lbfgserrInvalidFtol,
+                          lbfgserrInvalidWolfe,
+                          lbfgserrInvalidGtol,
+                          lbfgserrInvalidXtol,
+                          lbfgserrInvalidMaxlinesearch,
+                          lbfgserrInvalidOrthantwise,
+                          lbfgserrInvalidOrthantwiseStart,
+                          lbfgserrInvalidOrthantwiseEnd,
+                          lbfgserrOutofinterval,
+                          lbfgserrIncorrectTminmax,
+                          lbfgserrRoundingError,
+                          lbfgserrMinimumstep,
+                          lbfgserrMaximumstep,
+                          lbfgserrMaximumlinesearch,
+                          lbfgserrMaximumiteration,
+                          lbfgserrWidthtoosmall,
+                          lbfgserrInvalidparameters,
+                          lbfgserrIncreasegradient
+
+) where
+
+import Foreign.Storable (Storable(..))
+import Foreign.C.Types (CDouble, CInt)
+import Foreign.Ptr (FunPtr, Ptr)
+
+newtype CLineSearchAlgorithm =
+    CLineSearchAlgorithm { unCLineSearchAlgorithm :: CInt }
+    deriving (Storable, Show)
+
+#{enum CLineSearchAlgorithm, CLineSearchAlgorithm,
+  defaultLineSearch = LBFGS_LINESEARCH_DEFAULT,
+  moreThuente = LBFGS_LINESEARCH_MORETHUENTE,
+  backtrackingArmijo = LBFGS_LINESEARCH_BACKTRACKING_ARMIJO,
+  backtracking = LBFGS_LINESEARCH_BACKTRACKING,
+  backtrackingWolfe = LBFGS_LINESEARCH_BACKTRACKING_WOLFE,
+  backtrackingStrongWolfe = LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE
+}
+
+newtype CLBFGSResult =
+    CLBFGSResult { unCLBFGSResult :: CInt }
+    deriving (Eq, Show)
+
+#{enum CLBFGSResult, CLBFGSResult,
+  LBFGS_SUCCESS, LBFGS_CONVERGENCE, LBFGS_STOP,
+  LBFGS_ALREADY_MINIMIZED, LBFGSERR_UNKNOWNERROR, LBFGSERR_LOGICERROR,
+  LBFGSERR_OUTOFMEMORY, LBFGSERR_CANCELED, LBFGSERR_INVALID_N,
+  LBFGSERR_INVALID_N_SSE, LBFGSERR_INVALID_X_SSE,
+  LBFGSERR_INVALID_EPSILON, LBFGSERR_INVALID_TESTPERIOD,
+  LBFGSERR_INVALID_DELTA, LBFGSERR_INVALID_LINESEARCH,
+  LBFGSERR_INVALID_MINSTEP, LBFGSERR_INVALID_MAXSTEP,
+  LBFGSERR_INVALID_FTOL, LBFGSERR_INVALID_WOLFE,
+  LBFGSERR_INVALID_GTOL, LBFGSERR_INVALID_XTOL,
+  LBFGSERR_INVALID_MAXLINESEARCH, LBFGSERR_INVALID_ORTHANTWISE,
+  LBFGSERR_INVALID_ORTHANTWISE_START,
+  LBFGSERR_INVALID_ORTHANTWISE_END, LBFGSERR_OUTOFINTERVAL,
+  LBFGSERR_INCORRECT_TMINMAX, LBFGSERR_ROUNDING_ERROR,
+  LBFGSERR_MINIMUMSTEP, LBFGSERR_MAXIMUMSTEP,
+  LBFGSERR_MAXIMUMLINESEARCH, LBFGSERR_MAXIMUMITERATION,
+  LBFGSERR_WIDTHTOOSMALL, LBFGSERR_INVALIDPARAMETERS,
+  LBFGSERR_INCREASEGRADIENT }
+
+data CLBFGSParameter = CLBFGSParameter {
+      m :: CInt,
+      epsilon :: CDouble,
+      past :: CInt,
+      delta :: CDouble,
+      max_iterations :: CInt,
+      linesearch :: CLineSearchAlgorithm,
+      max_linesearch :: CInt,
+      min_step :: CDouble,
+      max_step :: CDouble,
+      ftol :: CDouble,
+      wolfe :: CDouble,
+      gtol :: CDouble,
+      xtol :: CDouble,
+      orthantwise_c :: CDouble,
+      orthantwise_start :: CDouble,
+      orthantwise_end :: CDouble
+} deriving Show
+
+defaultCParam :: CLBFGSParameter
+defaultCParam = CLBFGSParameter 6 1e-5 0 1e-5 0 defaultLineSearch 40 1e-20
+                1e20 1e-4 0.9 0.9 1.0e-16 0.0 0.0 (-1.0)
+
+instance Storable CLBFGSParameter where
+    sizeOf _ = #{size lbfgs_parameter_t}
+    alignment _ = #{alignment lbfgs_parameter_t}
+    peek ptr = do
+      m                 <- (#peek lbfgs_parameter_t, m) ptr
+      epsilon           <- (#peek lbfgs_parameter_t, epsilon) ptr
+      past              <- (#peek lbfgs_parameter_t, past) ptr
+      delta             <- (#peek lbfgs_parameter_t, delta) ptr
+      max_iterations    <- (#peek lbfgs_parameter_t, max_iterations) ptr
+      linesearch        <- (#peek lbfgs_parameter_t, linesearch) ptr
+      max_linesearch    <- (#peek lbfgs_parameter_t, max_linesearch) ptr
+      min_step          <- (#peek lbfgs_parameter_t, min_step) ptr
+      max_step          <- (#peek lbfgs_parameter_t, max_step) ptr
+      ftol              <- (#peek lbfgs_parameter_t, ftol) ptr
+      wolfe             <- (#peek lbfgs_parameter_t, wolfe) ptr
+      gtol              <- (#peek lbfgs_parameter_t, gtol) ptr
+      xtol              <- (#peek lbfgs_parameter_t, xtol) ptr
+      orthantwise_c     <- (#peek lbfgs_parameter_t, orthantwise_c) ptr
+      orthantwise_start <- (#peek lbfgs_parameter_t, orthantwise_start) ptr
+      orthantwise_end   <- (#peek lbfgs_parameter_t, orthantwise_end) ptr
+      return $ CLBFGSParameter m epsilon past delta max_iterations
+             linesearch max_linesearch min_step max_step
+             ftol wolfe gtol xtol orthantwise_c
+             orthantwise_start orthantwise_end
+    poke ptr (CLBFGSParameter m epsilon past delta max_iterations
+                              linesearch max_linesearch min_step max_step
+                              ftol wolfe gtol xtol orthantwise_c
+                              orthantwise_start orthantwise_end
+             ) = do
+      (#poke lbfgs_parameter_t, m) ptr m
+      (#poke lbfgs_parameter_t, epsilon) ptr epsilon
+      (#poke lbfgs_parameter_t, past) ptr past
+      (#poke lbfgs_parameter_t, delta) ptr delta
+      (#poke lbfgs_parameter_t, max_iterations) ptr max_iterations
+      (#poke lbfgs_parameter_t, linesearch) ptr linesearch
+      (#poke lbfgs_parameter_t, max_linesearch) ptr max_linesearch
+      (#poke lbfgs_parameter_t, min_step) ptr min_step
+      (#poke lbfgs_parameter_t, max_step) ptr max_step
+      (#poke lbfgs_parameter_t, ftol) ptr ftol
+      (#poke lbfgs_parameter_t, wolfe) ptr wolfe
+      (#poke lbfgs_parameter_t, gtol) ptr gtol
+      (#poke lbfgs_parameter_t, xtol) ptr xtol
+      (#poke lbfgs_parameter_t, orthantwise_c) ptr orthantwise_c
+      (#poke lbfgs_parameter_t, orthantwise_start) ptr orthantwise_start
+      (#poke lbfgs_parameter_t, orthantwise_end) ptr orthantwise_end
+
+type CEvaluateFun a = (Ptr a -> Ptr CDouble -> Ptr CDouble -> CInt ->
+                      CDouble -> IO (CDouble))
+
+type CProgressFun a = (Ptr a -> Ptr CDouble -> Ptr CDouble -> CDouble ->
+                      CDouble -> CDouble -> CDouble -> CInt -> CInt ->
+                      CInt -> IO (CInt))
+
+foreign import ccall "wrapper"
+        c_lbfgs_evaluate_t_wrap :: CEvaluateFun a -> IO (FunPtr (CEvaluateFun a))
+
+foreign import ccall "wrapper"
+        c_lbfgs_progress_t_wrap :: CProgressFun a -> IO (FunPtr (CProgressFun a))
+
+foreign import ccall safe "lbfgs.h lbfgs" c_lbfgs ::
+    CInt -> Ptr CDouble -> Ptr CDouble -> FunPtr (CEvaluateFun a) ->
+    FunPtr (CProgressFun a) -> Ptr a -> Ptr (CLBFGSParameter) -> IO (CInt)
+
+foreign import ccall unsafe "lbfgs.h lbfgs_malloc" c_lbfgs_malloc ::
+    CInt -> IO (Ptr CDouble)
+
+foreign import ccall unsafe "lbfgs.h lbfgs_free" c_lbfgs_free ::
+    Ptr CDouble -> IO ()
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/cbits/lbfgs.c b/cbits/lbfgs.c
new file mode 100644
--- /dev/null
+++ b/cbits/lbfgs.c
@@ -0,0 +1,1371 @@
+/*
+ *      Limited memory BFGS (L-BFGS).
+ *
+ * Copyright (c) 1990, Jorge Nocedal
+ * Copyright (c) 2007-2010 Naoaki Okazaki
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* $Id: lbfgs.c 65 2010-01-29 12:19:16Z naoaki $ */
+
+/*
+This library is a C port of the FORTRAN implementation of Limited-memory
+Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) method written by Jorge Nocedal.
+The original FORTRAN source code is available at:
+http://www.ece.northwestern.edu/~nocedal/lbfgs.html
+
+The L-BFGS algorithm is described in:
+    - Jorge Nocedal.
+      Updating Quasi-Newton Matrices with Limited Storage.
+      <i>Mathematics of Computation</i>, Vol. 35, No. 151, pp. 773--782, 1980.
+    - Dong C. Liu and Jorge Nocedal.
+      On the limited memory BFGS method for large scale optimization.
+      <i>Mathematical Programming</i> B, Vol. 45, No. 3, pp. 503-528, 1989.
+
+The line search algorithms used in this implementation are described in:
+    - John E. Dennis and Robert B. Schnabel.
+      <i>Numerical Methods for Unconstrained Optimization and Nonlinear
+      Equations</i>, Englewood Cliffs, 1983.
+    - Jorge J. More and David J. Thuente.
+      Line search algorithm with guaranteed sufficient decrease.
+      <i>ACM Transactions on Mathematical Software (TOMS)</i>, Vol. 20, No. 3,
+      pp. 286-307, 1994.
+
+This library also implements Orthant-Wise Limited-memory Quasi-Newton (OWL-QN)
+method presented in:
+    - Galen Andrew and Jianfeng Gao.
+      Scalable training of L1-regularized log-linear models.
+      In <i>Proceedings of the 24th International Conference on Machine
+      Learning (ICML 2007)</i>, pp. 33-40, 2007.
+
+I would like to thank the original author, Jorge Nocedal, who has been
+distributing the effieicnt and explanatory implementation in an open source
+licence.
+*/
+
+#ifdef  HAVE_CONFIG_H
+#include <config.h>
+#endif/*HAVE_CONFIG_H*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <lbfgs.h>
+
+#ifdef  _MSC_VER
+#define inline  __inline
+typedef unsigned int uint32_t;
+#endif/*_MSC_VER*/
+
+#if     defined(USE_SSE) && defined(__SSE2__) && LBFGS_FLOAT == 64
+/* Use SSE2 optimization for 64bit double precision. */
+#include "arithmetic_sse_double.h"
+
+#elif   defined(USE_SSE) && defined(__SSE__) && LBFGS_FLOAT == 32
+/* Use SSE optimization for 32bit float precision. */
+#include "arithmetic_sse_float.h"
+
+#else
+/* No CPU specific optimization. */
+#include "arithmetic_ansi.h"
+
+#endif
+
+#define min2(a, b)      ((a) <= (b) ? (a) : (b))
+#define max2(a, b)      ((a) >= (b) ? (a) : (b))
+#define max3(a, b, c)   max2(max2((a), (b)), (c));
+
+struct tag_callback_data {
+    int n;
+    void *instance;
+    lbfgs_evaluate_t proc_evaluate;
+    lbfgs_progress_t proc_progress;
+};
+typedef struct tag_callback_data callback_data_t;
+
+struct tag_iteration_data {
+    lbfgsfloatval_t alpha;
+    lbfgsfloatval_t *s;     /* [n] */
+    lbfgsfloatval_t *y;     /* [n] */
+    lbfgsfloatval_t ys;     /* vecdot(y, s) */
+};
+typedef struct tag_iteration_data iteration_data_t;
+
+static const lbfgs_parameter_t _defparam = {
+    6, 1e-5, 0, 1e-5,
+    0, LBFGS_LINESEARCH_DEFAULT, 40,
+    1e-20, 1e20, 1e-4, 0.9, 0.9, 1.0e-16,
+    0.0, 0, -1,
+};
+
+/* Forward function declarations. */
+
+typedef int (*line_search_proc)(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wa,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    );
+    
+static int line_search_backtracking(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wa,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    );
+
+static int line_search_backtracking_owlqn(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wp,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    );
+
+static int line_search_morethuente(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wa,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    );
+
+static int update_trial_interval(
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *fx,
+    lbfgsfloatval_t *dx,
+    lbfgsfloatval_t *y,
+    lbfgsfloatval_t *fy,
+    lbfgsfloatval_t *dy,
+    lbfgsfloatval_t *t,
+    lbfgsfloatval_t *ft,
+    lbfgsfloatval_t *dt,
+    const lbfgsfloatval_t tmin,
+    const lbfgsfloatval_t tmax,
+    int *brackt
+    );
+
+static lbfgsfloatval_t owlqn_x1norm(
+    const lbfgsfloatval_t* x,
+    const int start,
+    const int n
+    );
+
+static void owlqn_pseudo_gradient(
+    lbfgsfloatval_t* pg,
+    const lbfgsfloatval_t* x,
+    const lbfgsfloatval_t* g,
+    const int n,
+    const lbfgsfloatval_t c,
+    const int start,
+    const int end
+    );
+
+static void owlqn_project(
+    lbfgsfloatval_t* d,
+    const lbfgsfloatval_t* sign,
+    const int start,
+    const int end
+    );
+
+
+#if     defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__))
+static int round_out_variables(int n)
+{
+    n += 7;
+    n /= 8;
+    n *= 8;
+    return n;
+}
+#endif/*defined(USE_SSE)*/
+
+lbfgsfloatval_t* lbfgs_malloc(int n)
+{
+#if     defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__))
+    n = round_out_variables(n);
+#endif/*defined(USE_SSE)*/
+    return (lbfgsfloatval_t*)vecalloc(sizeof(lbfgsfloatval_t) * n);
+}
+
+void lbfgs_free(lbfgsfloatval_t *x)
+{
+    vecfree(x);
+}
+
+void lbfgs_parameter_init(lbfgs_parameter_t *param)
+{
+    memcpy(param, &_defparam, sizeof(*param));
+}
+
+int lbfgs(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *ptr_fx,
+    lbfgs_evaluate_t proc_evaluate,
+    lbfgs_progress_t proc_progress,
+    void *instance,
+    lbfgs_parameter_t *_param
+    )
+{
+    int ret;
+    int i, j, k, ls, end, bound;
+    lbfgsfloatval_t step;
+
+    /* Constant parameters and their default values. */
+    lbfgs_parameter_t param = (_param != NULL) ? (*_param) : _defparam;
+    const int m = param.m;
+
+    lbfgsfloatval_t *xp = NULL;
+    lbfgsfloatval_t *g = NULL, *gp = NULL, *pg = NULL;
+    lbfgsfloatval_t *d = NULL, *w = NULL, *pf = NULL;
+    iteration_data_t *lm = NULL, *it = NULL;
+    lbfgsfloatval_t ys, yy;
+    lbfgsfloatval_t xnorm, gnorm, beta;
+    lbfgsfloatval_t fx = 0.;
+    lbfgsfloatval_t rate = 0.;
+    line_search_proc linesearch = line_search_morethuente;
+
+    /* Construct a callback data. */
+    callback_data_t cd;
+    cd.n = n;
+    cd.instance = instance;
+    cd.proc_evaluate = proc_evaluate;
+    cd.proc_progress = proc_progress;
+
+#if     defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__))
+    /* Round out the number of variables. */
+    n = round_out_variables(n);
+#endif/*defined(USE_SSE)*/
+
+    /* Check the input parameters for errors. */
+    if (n <= 0) {
+        return LBFGSERR_INVALID_N;
+    }
+#if     defined(USE_SSE) && (defined(__SSE__) || defined(__SSE2__))
+    if (n % 8 != 0) {
+        return LBFGSERR_INVALID_N_SSE;
+    }
+    if (((unsigned short)x & 0x000F) != 0) {
+        return LBFGSERR_INVALID_X_SSE;
+    }
+#endif/*defined(USE_SSE)*/
+    if (param.epsilon < 0.) {
+        return LBFGSERR_INVALID_EPSILON;
+    }
+    if (param.past < 0) {
+        return LBFGSERR_INVALID_TESTPERIOD;
+    }
+    if (param.delta < 0.) {
+        return LBFGSERR_INVALID_DELTA;
+    }
+    if (param.min_step < 0.) {
+        return LBFGSERR_INVALID_MINSTEP;
+    }
+    if (param.max_step < param.min_step) {
+        return LBFGSERR_INVALID_MAXSTEP;
+    }
+    if (param.ftol < 0.) {
+        return LBFGSERR_INVALID_FTOL;
+    }
+    if (param.linesearch == LBFGS_LINESEARCH_BACKTRACKING_WOLFE ||
+        param.linesearch == LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE) {
+        if (param.wolfe <= param.ftol || 1. <= param.wolfe) {
+            return LBFGSERR_INVALID_WOLFE;
+        }
+    }
+    if (param.gtol < 0.) {
+        return LBFGSERR_INVALID_GTOL;
+    }
+    if (param.xtol < 0.) {
+        return LBFGSERR_INVALID_XTOL;
+    }
+    if (param.max_linesearch <= 0) {
+        return LBFGSERR_INVALID_MAXLINESEARCH;
+    }
+    if (param.orthantwise_c < 0.) {
+        return LBFGSERR_INVALID_ORTHANTWISE;
+    }
+    if (param.orthantwise_start < 0 || n < param.orthantwise_start) {
+        return LBFGSERR_INVALID_ORTHANTWISE_START;
+    }
+    if (param.orthantwise_end < 0) {
+        param.orthantwise_end = n;
+    }
+    if (n < param.orthantwise_end) {
+        return LBFGSERR_INVALID_ORTHANTWISE_END;
+    }
+    if (param.orthantwise_c != 0.) {
+        switch (param.linesearch) {
+        case LBFGS_LINESEARCH_BACKTRACKING:
+            linesearch = line_search_backtracking_owlqn;
+            break;
+        default:
+            /* Only the backtracking method is available. */
+            return LBFGSERR_INVALID_LINESEARCH;
+        }
+    } else {
+        switch (param.linesearch) {
+        case LBFGS_LINESEARCH_MORETHUENTE:
+            linesearch = line_search_morethuente;
+            break;
+        case LBFGS_LINESEARCH_BACKTRACKING_ARMIJO:
+        case LBFGS_LINESEARCH_BACKTRACKING_WOLFE:
+        case LBFGS_LINESEARCH_BACKTRACKING_STRONG_WOLFE:
+            linesearch = line_search_backtracking;
+            break;
+        default:
+            return LBFGSERR_INVALID_LINESEARCH;
+        }
+    }
+
+    /* Allocate working space. */
+    xp = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t));
+    g = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t));
+    gp = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t));
+    d = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t));
+    w = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t));
+    if (xp == NULL || g == NULL || gp == NULL || d == NULL || w == NULL) {
+        ret = LBFGSERR_OUTOFMEMORY;
+        goto lbfgs_exit;
+    }
+
+    if (param.orthantwise_c != 0.) {
+        /* Allocate working space for OW-LQN. */
+        pg = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t));
+        if (pg == NULL) {
+            ret = LBFGSERR_OUTOFMEMORY;
+            goto lbfgs_exit;
+        }
+    }
+
+    /* Allocate limited memory storage. */
+    lm = (iteration_data_t*)vecalloc(m * sizeof(iteration_data_t));
+    if (lm == NULL) {
+        ret = LBFGSERR_OUTOFMEMORY;
+        goto lbfgs_exit;
+    }
+
+    /* Initialize the limited memory. */
+    for (i = 0;i < m;++i) {
+        it = &lm[i];
+        it->alpha = 0;
+        it->ys = 0;
+        it->s = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t));
+        it->y = (lbfgsfloatval_t*)vecalloc(n * sizeof(lbfgsfloatval_t));
+        if (it->s == NULL || it->y == NULL) {
+            ret = LBFGSERR_OUTOFMEMORY;
+            goto lbfgs_exit;
+        }
+    }
+
+    /* Allocate an array for storing previous values of the objective function. */
+    if (0 < param.past) {
+        pf = (lbfgsfloatval_t*)vecalloc(param.past * sizeof(lbfgsfloatval_t));
+    }
+
+    /* Evaluate the function value and its gradient. */
+    fx = cd.proc_evaluate(cd.instance, x, g, cd.n, 0);
+    if (0. != param.orthantwise_c) {
+        /* Compute the L1 norm of the variable and add it to the object value. */
+        xnorm = owlqn_x1norm(x, param.orthantwise_start, param.orthantwise_end);
+        fx += xnorm * param.orthantwise_c;
+        owlqn_pseudo_gradient(
+            pg, x, g, n,
+            param.orthantwise_c, param.orthantwise_start, param.orthantwise_end
+            );
+    }
+
+    /* Store the initial value of the objective function. */
+    if (pf != NULL) {
+        pf[0] = fx;
+    }
+
+    /*
+        Compute the direction;
+        we assume the initial hessian matrix H_0 as the identity matrix.
+     */
+    if (param.orthantwise_c == 0.) {
+        vecncpy(d, g, n);
+    } else {
+        vecncpy(d, pg, n);
+    }
+
+    /*
+       Make sure that the initial variables are not a minimizer.
+     */
+    vec2norm(&xnorm, x, n);
+    if (param.orthantwise_c == 0.) {
+        vec2norm(&gnorm, g, n);
+    } else {
+        vec2norm(&gnorm, pg, n);
+    }
+    if (xnorm < 1.0) xnorm = 1.0;
+    if (gnorm / xnorm <= param.epsilon) {
+        ret = LBFGS_ALREADY_MINIMIZED;
+        goto lbfgs_exit;
+    }
+
+    /* Compute the initial step:
+        step = 1.0 / sqrt(vecdot(d, d, n))
+     */
+    vec2norminv(&step, d, n);
+
+    k = 1;
+    end = 0;
+    for (;;) {
+        /* Store the current position and gradient vectors. */
+        veccpy(xp, x, n);
+        veccpy(gp, g, n);
+
+        /* Search for an optimal step. */
+        if (param.orthantwise_c == 0.) {
+            ls = linesearch(n, x, &fx, g, d, &step, xp, gp, w, &cd, &param);
+        } else {
+            ls = linesearch(n, x, &fx, g, d, &step, xp, pg, w, &cd, &param);
+            owlqn_pseudo_gradient(
+                pg, x, g, n,
+                param.orthantwise_c, param.orthantwise_start, param.orthantwise_end
+                );
+        }
+        if (ls < 0) {
+            /* Revert to the previous point. */
+            veccpy(x, xp, n);
+            veccpy(g, gp, n);
+            ret = ls;
+            goto lbfgs_exit;
+        }
+
+        /* Compute x and g norms. */
+        vec2norm(&xnorm, x, n);
+        if (param.orthantwise_c == 0.) {
+            vec2norm(&gnorm, g, n);
+        } else {
+            vec2norm(&gnorm, pg, n);
+        }
+
+        /* Report the progress. */
+        if (cd.proc_progress) {
+            if (ret = cd.proc_progress(cd.instance, x, g, fx, xnorm, gnorm, step, cd.n, k, ls)) {
+                goto lbfgs_exit;
+            }
+        }
+
+        /*
+            Convergence test.
+            The criterion is given by the following formula:
+                |g(x)| / \max(1, |x|) < \epsilon
+         */
+        if (xnorm < 1.0) xnorm = 1.0;
+        if (gnorm / xnorm <= param.epsilon) {
+            /* Convergence. */
+            ret = LBFGS_SUCCESS;
+            break;
+        }
+
+        /*
+            Test for stopping criterion.
+            The criterion is given by the following formula:
+                (f(past_x) - f(x)) / f(x) < \delta
+         */
+        if (pf != NULL) {
+            /* We don't test the stopping criterion while k < past. */
+            if (param.past <= k) {
+                /* Compute the relative improvement from the past. */
+                rate = (pf[k % param.past] - fx) / fx;
+
+                /* The stopping criterion. */
+                if (rate < param.delta) {
+                    ret = LBFGS_STOP;
+                    break;
+                }
+            }
+
+            /* Store the current value of the objective function. */
+            pf[k % param.past] = fx;
+        }
+
+        if (param.max_iterations != 0 && param.max_iterations < k+1) {
+            /* Maximum number of iterations. */
+            ret = LBFGSERR_MAXIMUMITERATION;
+            break;
+        }
+
+        /*
+            Update vectors s and y:
+                s_{k+1} = x_{k+1} - x_{k} = \step * d_{k}.
+                y_{k+1} = g_{k+1} - g_{k}.
+         */
+        it = &lm[end];
+        vecdiff(it->s, x, xp, n);
+        vecdiff(it->y, g, gp, n);
+
+        /*
+            Compute scalars ys and yy:
+                ys = y^t \cdot s = 1 / \rho.
+                yy = y^t \cdot y.
+            Notice that yy is used for scaling the hessian matrix H_0 (Cholesky factor).
+         */
+        vecdot(&ys, it->y, it->s, n);
+        vecdot(&yy, it->y, it->y, n);
+        it->ys = ys;
+
+        /*
+            Recursive formula to compute dir = -(H \cdot g).
+                This is described in page 779 of:
+                Jorge Nocedal.
+                Updating Quasi-Newton Matrices with Limited Storage.
+                Mathematics of Computation, Vol. 35, No. 151,
+                pp. 773--782, 1980.
+         */
+        bound = (m <= k) ? m : k;
+        ++k;
+        end = (end + 1) % m;
+
+        /* Compute the steepest direction. */
+        if (param.orthantwise_c == 0.) {
+            /* Compute the negative of gradients. */
+            vecncpy(d, g, n);
+        } else {
+            vecncpy(d, pg, n);
+        }
+
+        j = end;
+        for (i = 0;i < bound;++i) {
+            j = (j + m - 1) % m;    /* if (--j == -1) j = m-1; */
+            it = &lm[j];
+            /* \alpha_{j} = \rho_{j} s^{t}_{j} \cdot q_{k+1}. */
+            vecdot(&it->alpha, it->s, d, n);
+            it->alpha /= it->ys;
+            /* q_{i} = q_{i+1} - \alpha_{i} y_{i}. */
+            vecadd(d, it->y, -it->alpha, n);
+        }
+
+        vecscale(d, ys / yy, n);
+
+        for (i = 0;i < bound;++i) {
+            it = &lm[j];
+            /* \beta_{j} = \rho_{j} y^t_{j} \cdot \gamma_{i}. */
+            vecdot(&beta, it->y, d, n);
+            beta /= it->ys;
+            /* \gamma_{i+1} = \gamma_{i} + (\alpha_{j} - \beta_{j}) s_{j}. */
+            vecadd(d, it->s, it->alpha - beta, n);
+            j = (j + 1) % m;        /* if (++j == m) j = 0; */
+        }
+
+        /*
+            Constrain the search direction for orthant-wise updates.
+         */
+        if (param.orthantwise_c != 0.) {
+            for (i = param.orthantwise_start;i < param.orthantwise_end;++i) {
+                if (d[i] * pg[i] >= 0) {
+                    d[i] = 0;
+                }
+            }
+        }
+
+        /*
+            Now the search direction d is ready. We try step = 1 first.
+         */
+        step = 1.0;
+    }
+
+lbfgs_exit:
+    /* Return the final value of the objective function. */
+    if (ptr_fx != NULL) {
+        *ptr_fx = fx;
+    }
+
+    vecfree(pf);
+
+    /* Free memory blocks used by this function. */
+    if (lm != NULL) {
+        for (i = 0;i < m;++i) {
+            vecfree(lm[i].s);
+            vecfree(lm[i].y);
+        }
+        vecfree(lm);
+    }
+    vecfree(pg);
+    vecfree(w);
+    vecfree(d);
+    vecfree(gp);
+    vecfree(g);
+    vecfree(xp);
+
+    return ret;
+}
+
+
+
+static int line_search_backtracking(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wp,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    )
+{
+    int ret = 0, count = 0;
+    lbfgsfloatval_t width, dg, norm = 0.;
+    lbfgsfloatval_t finit, dginit = 0., dgtest;
+    const lbfgsfloatval_t dec = 0.5, inc = 2.1;
+
+    /* Check the input parameters for errors. */
+    if (*stp <= 0.) {
+        return LBFGSERR_INVALIDPARAMETERS;
+    }
+
+    /* Compute the initial gradient in the search direction. */
+    vecdot(&dginit, g, s, n);
+
+    /* Make sure that s points to a descent direction. */
+    if (0 < dginit) {
+        return LBFGSERR_INCREASEGRADIENT;
+    }
+
+    /* The initial value of the objective function. */
+    finit = *f;
+    dgtest = param->ftol * dginit;
+
+    for (;;) {
+        veccpy(x, xp, n);
+        vecadd(x, s, *stp, n);
+
+        /* Evaluate the function and gradient values. */
+        *f = cd->proc_evaluate(cd->instance, x, g, cd->n, *stp);
+
+        ++count;
+
+        if (*f > finit + *stp * dgtest) {
+            width = dec;
+        } else {
+            /* The sufficient decrease condition (Armijo condition). */
+            if (param->linesearch == LBFGS_LINESEARCH_BACKTRACKING_ARMIJO) {
+                /* Exit with the Armijo condition. */
+                return count;
+	        }
+
+	        /* Check the Wolfe condition. */
+	        vecdot(&dg, g, s, n);
+	        if (dg < param->wolfe * dginit) {
+    		    width = inc;
+	        } else {
+		        if(param->linesearch == LBFGS_LINESEARCH_BACKTRACKING_WOLFE) {
+		            /* Exit with the regular Wolfe condition. */
+		            return count;
+		        }
+
+		        /* Check the strong Wolfe condition. */
+		        if(dg > -param->wolfe * dginit) {
+		            width = dec;
+		        } else {
+		            /* Exit with the strong Wolfe condition. */
+		            return count;
+		        }
+            }
+        }
+
+        if (*stp < param->min_step) {
+            /* The step is the minimum value. */
+            return LBFGSERR_MINIMUMSTEP;
+        }
+        if (*stp > param->max_step) {
+            /* The step is the maximum value. */
+            return LBFGSERR_MAXIMUMSTEP;
+        }
+        if (param->max_linesearch <= count) {
+            /* Maximum number of iteration. */
+            return LBFGSERR_MAXIMUMLINESEARCH;
+        }
+
+        (*stp) *= width;
+    }
+}
+
+
+
+static int line_search_backtracking_owlqn(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wp,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    )
+{
+    int i, ret = 0, count = 0;
+    lbfgsfloatval_t width = 0.5, norm = 0.;
+    lbfgsfloatval_t finit = *f, dgtest;
+
+    /* Check the input parameters for errors. */
+    if (*stp <= 0.) {
+        return LBFGSERR_INVALIDPARAMETERS;
+    }
+
+    /* Choose the orthant for the new point. */
+    for (i = 0;i < n;++i) {
+        wp[i] = (xp[i] == 0.) ? -gp[i] : xp[i];
+    }
+
+    for (;;) {
+        /* Update the current point. */
+        veccpy(x, xp, n);
+        vecadd(x, s, *stp, n);
+
+        /* The current point is projected onto the orthant. */
+        owlqn_project(x, wp, param->orthantwise_start, param->orthantwise_end);
+
+        /* Evaluate the function and gradient values. */
+        *f = cd->proc_evaluate(cd->instance, x, g, cd->n, *stp);
+
+        /* Compute the L1 norm of the variables and add it to the object value. */
+        norm = owlqn_x1norm(x, param->orthantwise_start, param->orthantwise_end);
+        *f += norm * param->orthantwise_c;
+
+        ++count;
+
+        dgtest = 0.;
+        for (i = 0;i < n;++i) {
+            dgtest += (x[i] - xp[i]) * gp[i];
+        }
+
+        if (*f <= finit + param->ftol * dgtest) {
+            /* The sufficient decrease condition. */
+            return count;
+        }
+
+        if (*stp < param->min_step) {
+            /* The step is the minimum value. */
+            return LBFGSERR_MINIMUMSTEP;
+        }
+        if (*stp > param->max_step) {
+            /* The step is the maximum value. */
+            return LBFGSERR_MAXIMUMSTEP;
+        }
+        if (param->max_linesearch <= count) {
+            /* Maximum number of iteration. */
+            return LBFGSERR_MAXIMUMLINESEARCH;
+        }
+
+        (*stp) *= width;
+    }
+}
+
+
+
+static int line_search_morethuente(
+    int n,
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *f,
+    lbfgsfloatval_t *g,
+    lbfgsfloatval_t *s,
+    lbfgsfloatval_t *stp,
+    const lbfgsfloatval_t* xp,
+    const lbfgsfloatval_t* gp,
+    lbfgsfloatval_t *wa,
+    callback_data_t *cd,
+    const lbfgs_parameter_t *param
+    )
+{
+    int count = 0;
+    int brackt, stage1, uinfo = 0;
+    lbfgsfloatval_t dg;
+    lbfgsfloatval_t stx, fx, dgx;
+    lbfgsfloatval_t sty, fy, dgy;
+    lbfgsfloatval_t fxm, dgxm, fym, dgym, fm, dgm;
+    lbfgsfloatval_t finit, ftest1, dginit, dgtest;
+    lbfgsfloatval_t width, prev_width;
+    lbfgsfloatval_t stmin, stmax;
+
+    /* Check the input parameters for errors. */
+    if (*stp <= 0.) {
+        return LBFGSERR_INVALIDPARAMETERS;
+    }
+
+    /* Compute the initial gradient in the search direction. */
+    vecdot(&dginit, g, s, n);
+
+    /* Make sure that s points to a descent direction. */
+    if (0 < dginit) {
+        return LBFGSERR_INCREASEGRADIENT;
+    }
+
+    /* Initialize local variables. */
+    brackt = 0;
+    stage1 = 1;
+    finit = *f;
+    dgtest = param->ftol * dginit;
+    width = param->max_step - param->min_step;
+    prev_width = 2.0 * width;
+
+    /*
+        The variables stx, fx, dgx contain the values of the step,
+        function, and directional derivative at the best step.
+        The variables sty, fy, dgy contain the value of the step,
+        function, and derivative at the other endpoint of
+        the interval of uncertainty.
+        The variables stp, f, dg contain the values of the step,
+        function, and derivative at the current step.
+    */
+    stx = sty = 0.;
+    fx = fy = finit;
+    dgx = dgy = dginit;
+
+    for (;;) {
+        /*
+            Set the minimum and maximum steps to correspond to the
+            present interval of uncertainty.
+         */
+        if (brackt) {
+            stmin = min2(stx, sty);
+            stmax = max2(stx, sty);
+        } else {
+            stmin = stx;
+            stmax = *stp + 4.0 * (*stp - stx);
+        }
+
+        /* Clip the step in the range of [stpmin, stpmax]. */
+        if (*stp < param->min_step) *stp = param->min_step;
+        if (param->max_step < *stp) *stp = param->max_step;
+
+        /*
+            If an unusual termination is to occur then let
+            stp be the lowest point obtained so far.
+         */
+        if ((brackt && ((*stp <= stmin || stmax <= *stp) || param->max_linesearch <= count + 1 || uinfo != 0)) || (brackt && (stmax - stmin <= param->xtol * stmax))) {
+            *stp = stx;
+        }
+
+        /*
+            Compute the current value of x:
+                x <- x + (*stp) * s.
+         */
+        veccpy(x, xp, n);
+        vecadd(x, s, *stp, n);
+
+        /* Evaluate the function and gradient values. */
+        *f = cd->proc_evaluate(cd->instance, x, g, cd->n, *stp);
+        vecdot(&dg, g, s, n);
+
+        ftest1 = finit + *stp * dgtest;
+        ++count;
+
+        /* Test for errors and convergence. */
+        if (brackt && ((*stp <= stmin || stmax <= *stp) || uinfo != 0)) {
+            /* Rounding errors prevent further progress. */
+            return LBFGSERR_ROUNDING_ERROR;
+        }
+        if (*stp == param->max_step && *f <= ftest1 && dg <= dgtest) {
+            /* The step is the maximum value. */
+            return LBFGSERR_MAXIMUMSTEP;
+        }
+        if (*stp == param->min_step && (ftest1 < *f || dgtest <= dg)) {
+            /* The step is the minimum value. */
+            return LBFGSERR_MINIMUMSTEP;
+        }
+        if (brackt && (stmax - stmin) <= param->xtol * stmax) {
+            /* Relative width of the interval of uncertainty is at most xtol. */
+            return LBFGSERR_WIDTHTOOSMALL;
+        }
+        if (param->max_linesearch <= count) {
+            /* Maximum number of iteration. */
+            return LBFGSERR_MAXIMUMLINESEARCH;
+        }
+        if (*f <= ftest1 && fabs(dg) <= param->gtol * (-dginit)) {
+            /* The sufficient decrease condition and the directional derivative condition hold. */
+            return count;
+        }
+
+        /*
+            In the first stage we seek a step for which the modified
+            function has a nonpositive value and nonnegative derivative.
+         */
+        if (stage1 && *f <= ftest1 && min2(param->ftol, param->gtol) * dginit <= dg) {
+            stage1 = 0;
+        }
+
+        /*
+            A modified function is used to predict the step only if
+            we have not obtained a step for which the modified
+            function has a nonpositive function value and nonnegative
+            derivative, and if a lower function value has been
+            obtained but the decrease is not sufficient.
+         */
+        if (stage1 && ftest1 < *f && *f <= fx) {
+            /* Define the modified function and derivative values. */
+            fm = *f - *stp * dgtest;
+            fxm = fx - stx * dgtest;
+            fym = fy - sty * dgtest;
+            dgm = dg - dgtest;
+            dgxm = dgx - dgtest;
+            dgym = dgy - dgtest;
+
+            /*
+                Call update_trial_interval() to update the interval of
+                uncertainty and to compute the new step.
+             */
+            uinfo = update_trial_interval(
+                &stx, &fxm, &dgxm,
+                &sty, &fym, &dgym,
+                stp, &fm, &dgm,
+                stmin, stmax, &brackt
+                );
+
+            /* Reset the function and gradient values for f. */
+            fx = fxm + stx * dgtest;
+            fy = fym + sty * dgtest;
+            dgx = dgxm + dgtest;
+            dgy = dgym + dgtest;
+        } else {
+            /*
+                Call update_trial_interval() to update the interval of
+                uncertainty and to compute the new step.
+             */
+            uinfo = update_trial_interval(
+                &stx, &fx, &dgx,
+                &sty, &fy, &dgy,
+                stp, f, &dg,
+                stmin, stmax, &brackt
+                );
+        }
+
+        /*
+            Force a sufficient decrease in the interval of uncertainty.
+         */
+        if (brackt) {
+            if (0.66 * prev_width <= fabs(sty - stx)) {
+                *stp = stx + 0.5 * (sty - stx);
+            }
+            prev_width = width;
+            width = fabs(sty - stx);
+        }
+    }
+
+    return LBFGSERR_LOGICERROR;
+}
+
+
+
+/**
+ * Define the local variables for computing minimizers.
+ */
+#define USES_MINIMIZER \
+    lbfgsfloatval_t a, d, gamma, theta, p, q, r, s;
+
+/**
+ * Find a minimizer of an interpolated cubic function.
+ *  @param  cm      The minimizer of the interpolated cubic.
+ *  @param  u       The value of one point, u.
+ *  @param  fu      The value of f(u).
+ *  @param  du      The value of f'(u).
+ *  @param  v       The value of another point, v.
+ *  @param  fv      The value of f(v).
+ *  @param  du      The value of f'(v).
+ */
+#define CUBIC_MINIMIZER(cm, u, fu, du, v, fv, dv) \
+    d = (v) - (u); \
+    theta = ((fu) - (fv)) * 3 / d + (du) + (dv); \
+    p = fabs(theta); \
+    q = fabs(du); \
+    r = fabs(dv); \
+    s = max3(p, q, r); \
+    /* gamma = s*sqrt((theta/s)**2 - (du/s) * (dv/s)) */ \
+    a = theta / s; \
+    gamma = s * sqrt(a * a - ((du) / s) * ((dv) / s)); \
+    if ((v) < (u)) gamma = -gamma; \
+    p = gamma - (du) + theta; \
+    q = gamma - (du) + gamma + (dv); \
+    r = p / q; \
+    (cm) = (u) + r * d;
+
+/**
+ * Find a minimizer of an interpolated cubic function.
+ *  @param  cm      The minimizer of the interpolated cubic.
+ *  @param  u       The value of one point, u.
+ *  @param  fu      The value of f(u).
+ *  @param  du      The value of f'(u).
+ *  @param  v       The value of another point, v.
+ *  @param  fv      The value of f(v).
+ *  @param  du      The value of f'(v).
+ *  @param  xmin    The maximum value.
+ *  @param  xmin    The minimum value.
+ */
+#define CUBIC_MINIMIZER2(cm, u, fu, du, v, fv, dv, xmin, xmax) \
+    d = (v) - (u); \
+    theta = ((fu) - (fv)) * 3 / d + (du) + (dv); \
+    p = fabs(theta); \
+    q = fabs(du); \
+    r = fabs(dv); \
+    s = max3(p, q, r); \
+    /* gamma = s*sqrt((theta/s)**2 - (du/s) * (dv/s)) */ \
+    a = theta / s; \
+    gamma = s * sqrt(max2(0, a * a - ((du) / s) * ((dv) / s))); \
+    if ((u) < (v)) gamma = -gamma; \
+    p = gamma - (dv) + theta; \
+    q = gamma - (dv) + gamma + (du); \
+    r = p / q; \
+    if (r < 0. && gamma != 0.) { \
+        (cm) = (v) - r * d; \
+    } else if (a < 0) { \
+        (cm) = (xmax); \
+    } else { \
+        (cm) = (xmin); \
+    }
+
+/**
+ * Find a minimizer of an interpolated quadratic function.
+ *  @param  qm      The minimizer of the interpolated quadratic.
+ *  @param  u       The value of one point, u.
+ *  @param  fu      The value of f(u).
+ *  @param  du      The value of f'(u).
+ *  @param  v       The value of another point, v.
+ *  @param  fv      The value of f(v).
+ */
+#define QUARD_MINIMIZER(qm, u, fu, du, v, fv) \
+    a = (v) - (u); \
+    (qm) = (u) + (du) / (((fu) - (fv)) / a + (du)) / 2 * a;
+
+/**
+ * Find a minimizer of an interpolated quadratic function.
+ *  @param  qm      The minimizer of the interpolated quadratic.
+ *  @param  u       The value of one point, u.
+ *  @param  du      The value of f'(u).
+ *  @param  v       The value of another point, v.
+ *  @param  dv      The value of f'(v).
+ */
+#define QUARD_MINIMIZER2(qm, u, du, v, dv) \
+    a = (u) - (v); \
+    (qm) = (v) + (dv) / ((dv) - (du)) * a;
+
+/**
+ * Update a safeguarded trial value and interval for line search.
+ *
+ *  The parameter x represents the step with the least function value.
+ *  The parameter t represents the current step. This function assumes
+ *  that the derivative at the point of x in the direction of the step.
+ *  If the bracket is set to true, the minimizer has been bracketed in
+ *  an interval of uncertainty with endpoints between x and y.
+ *
+ *  @param  x       The pointer to the value of one endpoint.
+ *  @param  fx      The pointer to the value of f(x).
+ *  @param  dx      The pointer to the value of f'(x).
+ *  @param  y       The pointer to the value of another endpoint.
+ *  @param  fy      The pointer to the value of f(y).
+ *  @param  dy      The pointer to the value of f'(y).
+ *  @param  t       The pointer to the value of the trial value, t.
+ *  @param  ft      The pointer to the value of f(t).
+ *  @param  dt      The pointer to the value of f'(t).
+ *  @param  tmin    The minimum value for the trial value, t.
+ *  @param  tmax    The maximum value for the trial value, t.
+ *  @param  brackt  The pointer to the predicate if the trial value is
+ *                  bracketed.
+ *  @retval int     Status value. Zero indicates a normal termination.
+ *  
+ *  @see
+ *      Jorge J. More and David J. Thuente. Line search algorithm with
+ *      guaranteed sufficient decrease. ACM Transactions on Mathematical
+ *      Software (TOMS), Vol 20, No 3, pp. 286-307, 1994.
+ */
+static int update_trial_interval(
+    lbfgsfloatval_t *x,
+    lbfgsfloatval_t *fx,
+    lbfgsfloatval_t *dx,
+    lbfgsfloatval_t *y,
+    lbfgsfloatval_t *fy,
+    lbfgsfloatval_t *dy,
+    lbfgsfloatval_t *t,
+    lbfgsfloatval_t *ft,
+    lbfgsfloatval_t *dt,
+    const lbfgsfloatval_t tmin,
+    const lbfgsfloatval_t tmax,
+    int *brackt
+    )
+{
+    int bound;
+    int dsign = fsigndiff(dt, dx);
+    lbfgsfloatval_t mc; /* minimizer of an interpolated cubic. */
+    lbfgsfloatval_t mq; /* minimizer of an interpolated quadratic. */
+    lbfgsfloatval_t newt;   /* new trial value. */
+    USES_MINIMIZER;     /* for CUBIC_MINIMIZER and QUARD_MINIMIZER. */
+
+    /* Check the input parameters for errors. */
+    if (*brackt) {
+        if (*t <= min2(*x, *y) || max2(*x, *y) <= *t) {
+            /* The trival value t is out of the interval. */
+            return LBFGSERR_OUTOFINTERVAL;
+        }
+        if (0. <= *dx * (*t - *x)) {
+            /* The function must decrease from x. */
+            return LBFGSERR_INCREASEGRADIENT;
+        }
+        if (tmax < tmin) {
+            /* Incorrect tmin and tmax specified. */
+            return LBFGSERR_INCORRECT_TMINMAX;
+        }
+    }
+
+    /*
+        Trial value selection.
+     */
+    if (*fx < *ft) {
+        /*
+            Case 1: a higher function value.
+            The minimum is brackt. If the cubic minimizer is closer
+            to x than the quadratic one, the cubic one is taken, else
+            the average of the minimizers is taken.
+         */
+        *brackt = 1;
+        bound = 1;
+        CUBIC_MINIMIZER(mc, *x, *fx, *dx, *t, *ft, *dt);
+        QUARD_MINIMIZER(mq, *x, *fx, *dx, *t, *ft);
+        if (fabs(mc - *x) < fabs(mq - *x)) {
+            newt = mc;
+        } else {
+            newt = mc + 0.5 * (mq - mc);
+        }
+    } else if (dsign) {
+        /*
+            Case 2: a lower function value and derivatives of
+            opposite sign. The minimum is brackt. If the cubic
+            minimizer is closer to x than the quadratic (secant) one,
+            the cubic one is taken, else the quadratic one is taken.
+         */
+        *brackt = 1;
+        bound = 0;
+        CUBIC_MINIMIZER(mc, *x, *fx, *dx, *t, *ft, *dt);
+        QUARD_MINIMIZER2(mq, *x, *dx, *t, *dt);
+        if (fabs(mc - *t) > fabs(mq - *t)) {
+            newt = mc;
+        } else {
+            newt = mq;
+        }
+    } else if (fabs(*dt) < fabs(*dx)) {
+        /*
+            Case 3: a lower function value, derivatives of the
+            same sign, and the magnitude of the derivative decreases.
+            The cubic minimizer is only used if the cubic tends to
+            infinity in the direction of the minimizer or if the minimum
+            of the cubic is beyond t. Otherwise the cubic minimizer is
+            defined to be either tmin or tmax. The quadratic (secant)
+            minimizer is also computed and if the minimum is brackt
+            then the the minimizer closest to x is taken, else the one
+            farthest away is taken.
+         */
+        bound = 1;
+        CUBIC_MINIMIZER2(mc, *x, *fx, *dx, *t, *ft, *dt, tmin, tmax);
+        QUARD_MINIMIZER2(mq, *x, *dx, *t, *dt);
+        if (*brackt) {
+            if (fabs(*t - mc) < fabs(*t - mq)) {
+                newt = mc;
+            } else {
+                newt = mq;
+            }
+        } else {
+            if (fabs(*t - mc) > fabs(*t - mq)) {
+                newt = mc;
+            } else {
+                newt = mq;
+            }
+        }
+    } else {
+        /*
+            Case 4: a lower function value, derivatives of the
+            same sign, and the magnitude of the derivative does
+            not decrease. If the minimum is not brackt, the step
+            is either tmin or tmax, else the cubic minimizer is taken.
+         */
+        bound = 0;
+        if (*brackt) {
+            CUBIC_MINIMIZER(newt, *t, *ft, *dt, *y, *fy, *dy);
+        } else if (*x < *t) {
+            newt = tmax;
+        } else {
+            newt = tmin;
+        }
+    }
+
+    /*
+        Update the interval of uncertainty. This update does not
+        depend on the new step or the case analysis above.
+
+        - Case a: if f(x) < f(t),
+            x <- x, y <- t.
+        - Case b: if f(t) <= f(x) && f'(t)*f'(x) > 0,
+            x <- t, y <- y.
+        - Case c: if f(t) <= f(x) && f'(t)*f'(x) < 0, 
+            x <- t, y <- x.
+     */
+    if (*fx < *ft) {
+        /* Case a */
+        *y = *t;
+        *fy = *ft;
+        *dy = *dt;
+    } else {
+        /* Case c */
+        if (dsign) {
+            *y = *x;
+            *fy = *fx;
+            *dy = *dx;
+        }
+        /* Cases b and c */
+        *x = *t;
+        *fx = *ft;
+        *dx = *dt;
+    }
+
+    /* Clip the new trial value in [tmin, tmax]. */
+    if (tmax < newt) newt = tmax;
+    if (newt < tmin) newt = tmin;
+
+    /*
+        Redefine the new trial value if it is close to the upper bound
+        of the interval.
+     */
+    if (*brackt && bound) {
+        mq = *x + 0.66 * (*y - *x);
+        if (*x < *y) {
+            if (mq < newt) newt = mq;
+        } else {
+            if (newt < mq) newt = mq;
+        }
+    }
+
+    /* Return the new trial value. */
+    *t = newt;
+    return 0;
+}
+
+
+
+
+
+static lbfgsfloatval_t owlqn_x1norm(
+    const lbfgsfloatval_t* x,
+    const int start,
+    const int n
+    )
+{
+    int i;
+    lbfgsfloatval_t norm = 0.;
+
+    for (i = start;i < n;++i) {
+        norm += fabs(x[i]);
+    }
+
+    return norm;
+}
+
+static void owlqn_pseudo_gradient(
+    lbfgsfloatval_t* pg,
+    const lbfgsfloatval_t* x,
+    const lbfgsfloatval_t* g,
+    const int n,
+    const lbfgsfloatval_t c,
+    const int start,
+    const int end
+    )
+{
+    int i;
+
+    /* Compute the negative of gradients. */
+    for (i = 0;i < start;++i) {
+        pg[i] = g[i];
+    }
+
+    /* Compute the psuedo-gradients. */
+    for (i = start;i < end;++i) {
+        if (x[i] < 0.) {
+            /* Differentiable. */
+            pg[i] = g[i] - c;
+        } else if (0. < x[i]) {
+            /* Differentiable. */
+            pg[i] = g[i] + c;
+        } else {
+            if (g[i] < -c) {
+                /* Take the right partial derivative. */
+                pg[i] = g[i] + c;
+            } else if (c < g[i]) {
+                /* Take the left partial derivative. */
+                pg[i] = g[i] - c;
+            } else {
+                pg[i] = 0.;
+            }
+        }
+    }
+
+    for (i = end;i < n;++i) {
+        pg[i] = g[i];
+    }
+}
+
+static void owlqn_project(
+    lbfgsfloatval_t* d,
+    const lbfgsfloatval_t* sign,
+    const int start,
+    const int end
+    )
+{
+    int i;
+
+    for (i = start;i < end;++i) {
+        if (d[i] * sign[i] <= 0) {
+            d[i] = 0;
+        }
+    }
+}
diff --git a/lbfgs.cabal b/lbfgs.cabal
new file mode 100644
--- /dev/null
+++ b/lbfgs.cabal
@@ -0,0 +1,19 @@
+Name:		lbfgs
+Version:	0.0.1
+License:        OtherLicense
+License-File:   LICENSE
+Copyright:	Daniël de Kok
+Maintainer:	Daniël de Kok <me@danieldk.eu>
+Author:		Daniël de Kok <me@danieldk.eu>
+Category:       Numeric
+Synopsis:       L-BFGS optimization
+Description:    Limited memory BFGS solver for non-linear optimization
+                problems.
+Build-Type:	Simple
+Cabal-Version:	>= 1.4
+
+Library
+  Build-Depends:	base >= 4 && < 5, array >= 0.3.0.0
+  Exposed-modules:	Numeric.LBFGS.Raw, Numeric.LBFGS
+  Include-Dirs:		cbits
+  C-Sources:		cbits/lbfgs.c
