diff options
Diffstat (limited to 'packages/gsl/src/Numeric/GSL/Interpolation.hs')
-rw-r--r-- | packages/gsl/src/Numeric/GSL/Interpolation.hs | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/packages/gsl/src/Numeric/GSL/Interpolation.hs b/packages/gsl/src/Numeric/GSL/Interpolation.hs new file mode 100644 index 0000000..4d72ee2 --- /dev/null +++ b/packages/gsl/src/Numeric/GSL/Interpolation.hs | |||
@@ -0,0 +1,282 @@ | |||
1 | {- | | ||
2 | Module : Numeric.GSL.Interpolation | ||
3 | Copyright : (c) Matthew Peddie 2015 | ||
4 | License : GPL | ||
5 | Maintainer : Alberto Ruiz | ||
6 | Stability : provisional | ||
7 | |||
8 | Interpolation routines. | ||
9 | |||
10 | <https://www.gnu.org/software/gsl/manual/html_node/Interpolation.html#Interpolation> | ||
11 | |||
12 | The GSL routines @gsl_spline_eval@ and friends are used, but in spite | ||
13 | of the names, they are not restricted to spline interpolation. The | ||
14 | functions in this module will work for any 'InterpolationMethod'. | ||
15 | |||
16 | -} | ||
17 | |||
18 | |||
19 | module Numeric.GSL.Interpolation ( | ||
20 | -- * Interpolation methods | ||
21 | InterpolationMethod(..) | ||
22 | -- * Evaluation of interpolated functions | ||
23 | , evaluate | ||
24 | , evaluateV | ||
25 | -- * Evaluation of derivatives of interpolated functions | ||
26 | , evaluateDerivative | ||
27 | , evaluateDerivative2 | ||
28 | , evaluateDerivativeV | ||
29 | , evaluateDerivative2V | ||
30 | -- * Evaluation of integrals of interpolated functions | ||
31 | , evaluateIntegral | ||
32 | , evaluateIntegralV | ||
33 | ) where | ||
34 | |||
35 | import Data.Packed.Vector(Vector, fromList, dim) | ||
36 | import Data.Packed.Foreign(appVector) | ||
37 | import Foreign.C.Types | ||
38 | import Foreign.Marshal.Alloc(alloca) | ||
39 | import Foreign.Ptr(Ptr) | ||
40 | import Foreign.Storable(peek) | ||
41 | import Numeric.GSL.Internal | ||
42 | import System.IO.Unsafe(unsafePerformIO) | ||
43 | |||
44 | data InterpolationMethod = Linear | ||
45 | | Polynomial | ||
46 | | CSpline | ||
47 | | CSplinePeriodic | ||
48 | | Akima | ||
49 | | AkimaPeriodic | ||
50 | deriving (Eq, Show, Read) | ||
51 | |||
52 | methodToInt :: Integral a => InterpolationMethod -> a | ||
53 | methodToInt Linear = 0 | ||
54 | methodToInt Polynomial = 1 | ||
55 | methodToInt CSpline = 2 | ||
56 | methodToInt CSplinePeriodic = 3 | ||
57 | methodToInt Akima = 4 | ||
58 | methodToInt AkimaPeriodic = 5 | ||
59 | |||
60 | applyCFun hsname cname fun mth xs ys x | ||
61 | | dim xs /= dim ys = error $ | ||
62 | "Error: Vectors of unequal sizes " ++ | ||
63 | show (dim xs) ++ " and " ++ show (dim ys) ++ | ||
64 | " supplied to " ++ hsname | ||
65 | | otherwise = unsafePerformIO $ | ||
66 | flip appVector xs $ \xs' -> | ||
67 | flip appVector ys $ \ys' -> | ||
68 | alloca $ \y' -> do | ||
69 | fun xs' ys' | ||
70 | (fromIntegral $ dim xs) x | ||
71 | (methodToInt mth) y' // check cname | ||
72 | peek y' | ||
73 | |||
74 | foreign import ccall safe "spline_eval" c_spline_eval | ||
75 | :: Ptr Double -> Ptr Double -> CUInt -> Double -> CInt -> Ptr Double -> IO CInt | ||
76 | |||
77 | -------------------------------------------------------------------- | ||
78 | {- | Evaluate a function by interpolating within the given dataset. For | ||
79 | example: | ||
80 | |||
81 | >>> let xs = vector [1..10] | ||
82 | >>> let ys = vector $ map (**2) [1..10] | ||
83 | >>> evaluateV CSpline xs ys 2.2 | ||
84 | 4.818867924528303 | ||
85 | |||
86 | To successfully @evaluateV xs ys x@, the vectors of corresponding | ||
87 | domain-range values @xs@ and @ys@ must have identical lengths, and | ||
88 | @xs@ must be monotonically increasing. The evaluation point @x@ must | ||
89 | lie between the smallest and largest values in @xs@. | ||
90 | |||
91 | -} | ||
92 | evaluateV :: InterpolationMethod -- ^ What method to use to interpolate | ||
93 | -> Vector Double -- ^ Data points sampling the domain of the function | ||
94 | -> Vector Double -- ^ Data points sampling the range of the function | ||
95 | -> Double -- ^ Point at which to evaluate the function | ||
96 | -> Double -- ^ Interpolated result | ||
97 | evaluateV = applyCFun "evaluateV" "spline_eval" c_spline_eval | ||
98 | |||
99 | {- | Evaluate a function by interpolating within the given dataset. For | ||
100 | example: | ||
101 | |||
102 | >>> let xs = [1..10] | ||
103 | >>> let ys map (**2) [1..10] | ||
104 | >>> evaluate Akima (zip xs ys) 2.2 | ||
105 | 4.840000000000001 | ||
106 | |||
107 | To successfully @evaluate points x@, the domain (@x@) values in | ||
108 | @points@ must be monotonically increasing. The evaluation point @x@ | ||
109 | must lie between the smallest and largest values in the sampled | ||
110 | domain. | ||
111 | |||
112 | -} | ||
113 | evaluate :: InterpolationMethod -- ^ What method to use to interpolate | ||
114 | -> [(Double, Double)] -- ^ (domain, range) values sampling the function | ||
115 | -> Double -- ^ Point at which to evaluate the function | ||
116 | -> Double -- ^ Interpolated result | ||
117 | evaluate mth pts = | ||
118 | applyCFun "evaluate" "spline_eval" c_spline_eval_deriv | ||
119 | mth (fromList xs) (fromList ys) | ||
120 | where | ||
121 | (xs, ys) = unzip pts | ||
122 | |||
123 | foreign import ccall safe "spline_eval_deriv" c_spline_eval_deriv | ||
124 | :: Ptr Double -> Ptr Double -> CUInt -> Double -> CInt -> Ptr Double -> IO CInt | ||
125 | |||
126 | {- | Evaluate the derivative of a function by interpolating within the | ||
127 | given dataset. For example: | ||
128 | |||
129 | >>> let xs = vector [1..10] | ||
130 | >>> let ys = vector $ map (**2) [1..10] | ||
131 | >>> evaluateDerivativeV CSpline xs ys 2.2 | ||
132 | 4.338867924528302 | ||
133 | |||
134 | To successfully @evaluateDerivativeV xs ys x@, the vectors of | ||
135 | corresponding domain-range values @xs@ and @ys@ must have identical | ||
136 | lengths, and @xs@ must be monotonically increasing. The interpolation | ||
137 | point @x@ must lie between the smallest and largest values in @xs@. | ||
138 | |||
139 | -} | ||
140 | evaluateDerivativeV :: InterpolationMethod -- ^ What method to use to interpolate | ||
141 | -> Vector Double -- ^ Data points @xs@ sampling the domain of the function | ||
142 | -> Vector Double -- ^ Data points @ys@ sampling the range of the function | ||
143 | -> Double -- ^ Point @x@ at which to evaluate the derivative | ||
144 | -> Double -- ^ Interpolated result | ||
145 | evaluateDerivativeV = | ||
146 | applyCFun "evaluateDerivativeV" "spline_eval_deriv" c_spline_eval_deriv | ||
147 | |||
148 | {- | Evaluate the derivative of a function by interpolating within the | ||
149 | given dataset. For example: | ||
150 | |||
151 | >>> let xs = [1..10] | ||
152 | >>> let ys map (**2) [1..10] | ||
153 | >>> evaluateDerivative Akima (zip xs ys) 2.2 | ||
154 | 4.4 | ||
155 | |||
156 | To successfully @evaluateDerivative points x@, the domain (@x@) values | ||
157 | in @points@ must be monotonically increasing. The evaluation point | ||
158 | @x@ must lie between the smallest and largest values in the sampled | ||
159 | domain. | ||
160 | |||
161 | -} | ||
162 | evaluateDerivative :: InterpolationMethod -- ^ What method to use to interpolate | ||
163 | -> [(Double, Double)] -- ^ (domain, range) points sampling the function | ||
164 | -> Double -- ^ Point @x@ at which to evaluate the derivative | ||
165 | -> Double -- ^ Interpolated result | ||
166 | evaluateDerivative mth pts = | ||
167 | applyCFun "evaluateDerivative" "spline_eval_deriv" c_spline_eval_deriv | ||
168 | mth (fromList xs) (fromList ys) | ||
169 | where | ||
170 | (xs, ys) = unzip pts | ||
171 | |||
172 | foreign import ccall safe "spline_eval_deriv2" c_spline_eval_deriv2 | ||
173 | :: Ptr Double -> Ptr Double -> CUInt -> Double -> CInt -> Ptr Double -> IO CInt | ||
174 | |||
175 | {- | Evaluate the second derivative of a function by interpolating within the | ||
176 | given dataset. For example: | ||
177 | |||
178 | >>> let xs = vector [1..10] | ||
179 | >>> let ys = vector $ map (**2) [1..10] | ||
180 | >>> evaluateDerivative2V CSpline xs ys 2.2 | ||
181 | 2.4 | ||
182 | |||
183 | To successfully @evaluateDerivative2V xs ys x@, the vectors @xs@ and | ||
184 | @ys@ must have identical lengths, and @xs@ must be monotonically | ||
185 | increasing. The evaluation point @x@ must lie between the smallest | ||
186 | and largest values in @xs@. | ||
187 | |||
188 | -} | ||
189 | evaluateDerivative2V :: InterpolationMethod -- ^ What method to use to interpolate | ||
190 | -> Vector Double -- ^ Data points @xs@ sampling the domain of the function | ||
191 | -> Vector Double -- ^ Data points @ys@ sampling the range of the function | ||
192 | -> Double -- ^ Point @x@ at which to evaluate the second derivative | ||
193 | -> Double -- ^ Interpolated result | ||
194 | evaluateDerivative2V = | ||
195 | applyCFun "evaluateDerivative2V" "spline_eval_deriv2" c_spline_eval_deriv2 | ||
196 | |||
197 | {- | Evaluate the second derivative of a function by interpolating | ||
198 | within the given dataset. For example: | ||
199 | |||
200 | >>> let xs = [1..10] | ||
201 | >>> let ys map (**2) [1..10] | ||
202 | >>> evaluateDerivative2 Akima (zip xs ys) 2.2 | ||
203 | 2.0 | ||
204 | |||
205 | To successfully @evaluateDerivative2 points x@, the domain (@x@) | ||
206 | values in @points@ must be monotonically increasing. The evaluation | ||
207 | point @x@ must lie between the smallest and largest values in the | ||
208 | sampled domain. | ||
209 | |||
210 | -} | ||
211 | evaluateDerivative2 :: InterpolationMethod -- ^ What method to use to interpolate | ||
212 | -> [(Double, Double)] -- ^ (domain, range) points sampling the function | ||
213 | -> Double -- ^ Point @x@ at which to evaluate the second derivative | ||
214 | -> Double -- ^ Interpolated result | ||
215 | evaluateDerivative2 mth pts = | ||
216 | applyCFun "evaluateDerivative2" "spline_eval_deriv2" c_spline_eval_deriv2 | ||
217 | mth (fromList xs) (fromList ys) | ||
218 | where | ||
219 | (xs, ys) = unzip pts | ||
220 | |||
221 | foreign import ccall safe "spline_eval_integ" c_spline_eval_integ | ||
222 | :: Ptr Double -> Ptr Double -> CUInt -> Double -> Double -> CInt -> Ptr Double -> IO CInt | ||
223 | |||
224 | applyCIntFun hsname cname fun mth xs ys a b | ||
225 | | dim xs /= dim ys = error $ | ||
226 | "Error: Vectors of unequal sizes " ++ | ||
227 | show (dim xs) ++ " and " ++ show (dim ys) ++ | ||
228 | " supplied to " ++ hsname | ||
229 | | otherwise = unsafePerformIO $ | ||
230 | flip appVector xs $ \xs' -> | ||
231 | flip appVector ys $ \ys' -> | ||
232 | alloca $ \y' -> do | ||
233 | fun xs' ys' | ||
234 | (fromIntegral $ dim xs) a b | ||
235 | (methodToInt mth) y' // check cname | ||
236 | peek y' | ||
237 | |||
238 | {- | Evaluate the definite integral of a function by interpolating | ||
239 | within the given dataset. For example: | ||
240 | |||
241 | >>> let xs = vector [1..10] | ||
242 | >>> let ys = vector $ map (**2) [1..10] | ||
243 | >>> evaluateIntegralV CSpline xs ys 2.2 5.5 | ||
244 | 51.89853207547169 | ||
245 | |||
246 | To successfully @evaluateIntegralV xs ys a b@, the vectors @xs@ and | ||
247 | @ys@ must have identical lengths, and @xs@ must be monotonically | ||
248 | increasing. The integration bounds @a@ and @b@ must lie between the | ||
249 | smallest and largest values in @xs@. | ||
250 | |||
251 | -} | ||
252 | evaluateIntegralV :: InterpolationMethod -- ^ What method to use to interpolate | ||
253 | -> Vector Double -- ^ Data points @xs@ sampling the domain of the function | ||
254 | -> Vector Double -- ^ Data points @ys@ sampling the range of the function | ||
255 | -> Double -- ^ Lower integration bound @a@ | ||
256 | -> Double -- ^ Upper integration bound @b@ | ||
257 | -> Double -- ^ Resulting area | ||
258 | evaluateIntegralV = | ||
259 | applyCIntFun "evaluateIntegralV" "spline_eval_integ" c_spline_eval_integ | ||
260 | |||
261 | {- | Evaluate the definite integral of a function by interpolating | ||
262 | within the given dataset. For example: | ||
263 | |||
264 | >>> let xs = [1..10] | ||
265 | >>> let ys = map (**2) [1..10] | ||
266 | >>> evaluateIntegralV CSpline (zip xs ys) (2.2, 5.5) | ||
267 | 51.909 | ||
268 | |||
269 | To successfully @evaluateIntegral points (a, b)@, the domain (@x@) | ||
270 | values of @points@ must be monotonically increasing. The integration | ||
271 | bounds @a@ and @b@ must lie between the smallest and largest values in | ||
272 | the sampled domain.. | ||
273 | -} | ||
274 | evaluateIntegral :: InterpolationMethod -- ^ What method to use to interpolate | ||
275 | -> [(Double, Double)] -- ^ (domain, range) points sampling the function | ||
276 | -> (Double, Double) -- ^ Integration bounds (@a@, @b@) | ||
277 | -> Double -- ^ Resulting area | ||
278 | evaluateIntegral mth pts (a, b) = | ||
279 | applyCIntFun "evaluateIntegral" "spline_eval_integ" c_spline_eval_integ | ||
280 | mth (fromList xs) (fromList ys) a b | ||
281 | where | ||
282 | (xs, ys) = unzip pts | ||