summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Numeric/GSL/Fitting.hs72
-rw-r--r--lib/Numeric/GSL/gsl-aux.c1
-rw-r--r--lib/Numeric/LinearAlgebra/Tests.hs12
3 files changed, 59 insertions, 26 deletions
diff --git a/lib/Numeric/GSL/Fitting.hs b/lib/Numeric/GSL/Fitting.hs
index 6e91b2d..b1f3a32 100644
--- a/lib/Numeric/GSL/Fitting.hs
+++ b/lib/Numeric/GSL/Fitting.hs
@@ -14,17 +14,17 @@ Nonlinear Least-Squares Fitting
14The example program in the GSL manual (see examples/fitting.hs): 14The example program in the GSL manual (see examples/fitting.hs):
15 15
16@dat = [ 16@dat = [
17 ([0.0],[6.0133918608118675],0.1), 17 ([0.0],([6.0133918608118675],0.1)),
18 ([1.0],[5.5153769909966535],0.1), 18 ([1.0],([5.5153769909966535],0.1)),
19 ([2.0],[5.261094606015287],0.1), 19 ([2.0],([5.261094606015287],0.1)),
20 ... 20 ...
21 ([39.0],[1.0619821710802808],0.1)] 21 ([39.0],([1.0619821710802808],0.1))]
22 22
23expModel [a,lambda,b] [t] = [a * exp (-lambda * t) + b] 23expModel [a,lambda,b] [t] = [a * exp (-lambda * t) + b]
24 24
25expModelDer [a,lambda,b] [t] = [[exp (-lambda * t), -t * a * exp(-lambda*t) , 1]] 25expModelDer [a,lambda,b] [t] = [[exp (-lambda * t), -t * a * exp(-lambda*t) , 1]]
26 26
27(sol,path) = fitModel 1E-4 1E-4 20 (resM expModel, resD expModelDer) dat [1,0,0] 27(sol,path) = fitModelScaled 1E-4 1E-4 20 (expModel, expModelDer) dat [1,0,0]
28 28
29\> path 29\> path
30(6><5) 30(6><5)
@@ -46,7 +46,7 @@ module Numeric.GSL.Fitting (
46 -- * Levenberg-Marquardt 46 -- * Levenberg-Marquardt
47 nlFitting, FittingMethod(..), 47 nlFitting, FittingMethod(..),
48 -- * Utilities 48 -- * Utilities
49 fitModel, resM, resD 49 fitModelScaled, fitModel
50) where 50) where
51 51
52import Data.Packed.Internal 52import Data.Packed.Internal
@@ -57,7 +57,8 @@ import Numeric.GSL.Internal
57 57
58------------------------------------------------------------------------- 58-------------------------------------------------------------------------
59 59
60data FittingMethod = LevenbergMarquardt -- ^ Interface to gsl_multifit_fdfsolver_lmsder. This is a robust and efficient version of the Levenberg-Marquardt algorithm as implemented in the scaled lmder routine in minpack. Minpack was written by Jorge J. More, Burton S. Garbow and Kenneth E. Hillstrom. 60data FittingMethod = LevenbergMarquardtScaled -- ^ Interface to gsl_multifit_fdfsolver_lmsder. This is a robust and efficient version of the Levenberg-Marquardt algorithm as implemented in the scaled lmder routine in minpack. Minpack was written by Jorge J. More, Burton S. Garbow and Kenneth E. Hillstrom.
61 | LevenbergMarquardt -- ^ This is an unscaled version of the lmder algorithm. The elements of the diagonal scaling matrix D are set to 1. This algorithm may be useful in circumstances where the scaled version of lmder converges too slowly, or the function is already scaled appropriately.
61 deriving (Enum,Eq,Show,Bounded) 62 deriving (Enum,Eq,Show,Bounded)
62 63
63 64
@@ -104,32 +105,52 @@ checkdim2 n p m
104 105
105------------------------------------------------------------ 106------------------------------------------------------------
106 107
107err model dat vsol = zip sol errs where 108err (model,deriv) dat vsol = zip sol errs where
108 sol = toList vsol 109 sol = toList vsol
109 c = max 1 (chi/sqrt (fromIntegral dof)) 110 c = max 1 (chi/sqrt (fromIntegral dof))
110 dof = length dat - (rows cov) 111 dof = length dat - (rows cov)
111 chi = pnorm PNorm2 (fromList $ cost (fst model) dat sol) 112 chi = pnorm PNorm2 (fromList $ cost (resMs model) dat sol)
112 js = fromLists $ jacobian (snd model) dat sol 113 js = fromLists $ jacobian (resDs deriv) dat sol
113 cov = inv $ trans js <> js 114 cov = inv $ trans js <> js
114 errs = toList $ scalar c * sqrt (takeDiag cov) 115 errs = toList $ scalar c * sqrt (takeDiag cov)
115 116
116 117
117 118
119-- | Higher level interface to 'nlFitting' 'LevenbergMarquardtScaled'. The optimization function and
120-- Jacobian are automatically built from a model f vs x = y and its derivatives, and a list of
121-- instances (x, (y,sigma)) to be fitted.
122
123fitModelScaled
124 :: Double -- ^ absolute tolerance
125 -> Double -- ^ relative tolerance
126 -> Int -- ^ maximum number of iterations allowed
127 -> ([Double] -> x -> [Double], [Double] -> x -> [[Double]]) -- ^ (model, derivatives)
128 -> [(x, ([Double], Double))] -- ^ instances
129 -> [Double] -- ^ starting point
130 -> ([(Double, Double)], Matrix Double) -- ^ (solution, error) and optimization path
131fitModelScaled epsabs epsrel maxit (model,deriv) dt xin = (err (model,deriv) dt sol, path) where
132 (sol,path) = nlFitting LevenbergMarquardtScaled epsabs epsrel maxit
133 (fromList . cost (resMs model) dt . toList)
134 (fromLists . jacobian (resDs deriv) dt . toList)
135 (fromList xin)
136
137
138
118-- | Higher level interface to 'nlFitting' 'LevenbergMarquardt'. The optimization function and 139-- | Higher level interface to 'nlFitting' 'LevenbergMarquardt'. The optimization function and
119-- Jacobian are automatically built from a model f vs x = 0 and its derivatives, and a list of 140-- Jacobian are automatically built from a model f vs x = y and its derivatives, and a list of
120-- instances x to be fitted. 141-- instances (x,y) to be fitted.
121 142
122fitModel :: Double -- ^ absolute tolerance 143fitModel :: Double -- ^ absolute tolerance
123 -> Double -- ^ relative tolerance 144 -> Double -- ^ relative tolerance
124 -> Int -- ^ maximum number of iterations allowed 145 -> Int -- ^ maximum number of iterations allowed
125 -> ([Double] -> x -> [Double], [Double] -> x -> [[Double]]) -- ^ (model, derivatives) 146 -> ([Double] -> x -> [Double], [Double] -> x -> [[Double]]) -- ^ (model, derivatives)
126 -> [x] -- ^ instances 147 -> [(x, [Double])] -- ^ instances
127 -> [Double] -- ^ starting point 148 -> [Double] -- ^ starting point
128 -> ([(Double, Double)], Matrix Double) -- ^ (solution, error) and optimization path 149 -> ([Double], Matrix Double) -- ^ solution and optimization path
129fitModel epsabs epsrel maxit model dt xin = (err model dt sol, path) where 150fitModel epsabs epsrel maxit (model,deriv) dt xin = (toList sol, path) where
130 (sol,path) = nlFitting LevenbergMarquardt epsabs epsrel maxit 151 (sol,path) = nlFitting LevenbergMarquardt epsabs epsrel maxit
131 (fromList . cost (fst model) dt . toList) 152 (fromList . cost (resM model) dt . toList)
132 (fromLists . jacobian (snd model) dt . toList) 153 (fromLists . jacobian (resD deriv) dt . toList)
133 (fromList xin) 154 (fromList xin)
134 155
135cost model ds vs = concatMap (model vs) ds 156cost model ds vs = concatMap (model vs) ds
@@ -137,11 +158,18 @@ cost model ds vs = concatMap (model vs) ds
137jacobian modelDer ds vs = concatMap (modelDer vs) ds 158jacobian modelDer ds vs = concatMap (modelDer vs) ds
138 159
139-- | Model-to-residual for association pairs with sigma, to be used with 'fitModel'. 160-- | Model-to-residual for association pairs with sigma, to be used with 'fitModel'.
140resM :: ([Double] -> x -> [Double]) -> [Double] -> (x, [Double], Double) -> [Double] 161resMs :: ([Double] -> x -> [Double]) -> [Double] -> (x, ([Double], Double)) -> [Double]
141resM m v = \(x,ys,s) -> zipWith (g s) (m v x) ys where g s a b = (a-b)/s 162resMs m v = \(x,(ys,s)) -> zipWith (g s) (m v x) ys where g s a b = (a-b)/s
142 163
143-- | Associated derivative for 'resM'. 164-- | Associated derivative for 'resMs'.
144resD :: ([Double] -> x -> [[Double]]) -> [Double] -> (x, [Double], Double) -> [[Double]] 165resDs :: ([Double] -> x -> [[Double]]) -> [Double] -> (x, ([Double], Double)) -> [[Double]]
145resD m v = \(x,_,s) -> map (map (/s)) (m v x) 166resDs m v = \(x,(_,s)) -> map (map (/s)) (m v x)
146 167
168-- | Model-to-residual for association pairs, to be used with 'fitModel'. It is equivalent
169-- to 'resMs' with all sigmas = 1.
170resM :: ([Double] -> x -> [Double]) -> [Double] -> (x, [Double]) -> [Double]
171resM m v = \(x,ys) -> zipWith g (m v x) ys where g a b = a-b
147 172
173-- | Associated derivative for 'resM'.
174resD :: ([Double] -> x -> [[Double]]) -> [Double] -> (x, [Double]) -> [[Double]]
175resD m v = \(x,_) -> m v x
diff --git a/lib/Numeric/GSL/gsl-aux.c b/lib/Numeric/GSL/gsl-aux.c
index f258fb1..f5a95f4 100644
--- a/lib/Numeric/GSL/gsl-aux.c
+++ b/lib/Numeric/GSL/gsl-aux.c
@@ -812,6 +812,7 @@ int nlfit(int method, int f(int, double*, int, double*),
812 812
813 switch(method) { 813 switch(method) {
814 case 0 : { T = gsl_multifit_fdfsolver_lmsder; break; } 814 case 0 : { T = gsl_multifit_fdfsolver_lmsder; break; }
815 case 1 : { T = gsl_multifit_fdfsolver_lmder; break; }
815 default: ERROR(BAD_CODE); 816 default: ERROR(BAD_CODE);
816 } 817 }
817 818
diff --git a/lib/Numeric/LinearAlgebra/Tests.hs b/lib/Numeric/LinearAlgebra/Tests.hs
index c9408a6..60c60e6 100644
--- a/lib/Numeric/LinearAlgebra/Tests.hs
+++ b/lib/Numeric/LinearAlgebra/Tests.hs
@@ -143,19 +143,23 @@ odeTest = utest "ode" (last (toLists sol) ~~ [-1.7588880332411019, 8.36434890871
143 143
144--------------------------------------------------------------------- 144---------------------------------------------------------------------
145 145
146fittingTest = utest "levmar" ok 146fittingTest = utest "levmar" (ok1 && ok2)
147 where 147 where
148 xs = map return [0 .. 39] 148 xs = map return [0 .. 39]
149 sigma = 0.1 149 sigma = 0.1
150 ys = map return $ toList $ fromList (map (head . expModel [5,0.1,1]) xs) 150 ys = map return $ toList $ fromList (map (head . expModel [5,0.1,1]) xs)
151 + scalar sigma * (randomVector 0 Gaussian 40) 151 + scalar sigma * (randomVector 0 Gaussian 40)
152 dat = zipWith3 (,,) xs ys (repeat sigma) 152 dats = zip xs (zip ys (repeat sigma))
153 dat = zip xs ys
153 154
154 expModel [a,lambda,b] [t] = [a * exp (-lambda * t) + b] 155 expModel [a,lambda,b] [t] = [a * exp (-lambda * t) + b]
155 expModelDer [a,lambda,_b] [t] = [[exp (-lambda * t), -t * a * exp(-lambda*t) , 1]] 156 expModelDer [a,lambda,_b] [t] = [[exp (-lambda * t), -t * a * exp(-lambda*t) , 1]]
156 157
157 sol = fst $ fitModel 1E-4 1E-4 20 (resM expModel, resD expModelDer) dat [1,0,0] 158 sols = fst $ fitModelScaled 1E-4 1E-4 20 (expModel, expModelDer) dats [1,0,0]
158 ok = and (zipWith f sol [5,0.1,1]) where f (x,d) r = abs (x-r)<2*d 159 sol = fst $ fitModel 1E-4 1E-4 20 (expModel, expModelDer) dat [1,0,0]
160
161 ok1 = and (zipWith f sols [5,0.1,1]) where f (x,d) r = abs (x-r)<2*d
162 ok2 = pnorm PNorm2 (fromList (map fst sols) - fromList sol) < 1E-5
159 163
160--------------------------------------------------------------------- 164---------------------------------------------------------------------
161 165