1 {-# LANGUAGE ScopedTypeVariables #-}
3 -- | Numerical solution of the initial value problem,
14 import Misc (partition)
17 -- | A single iteration of Euler's method over the interval
26 -- >>> eulers_method1 x0 y0 f h
29 eulers_method1 :: (RealFrac a, RealFrac b)
30 => a -- ^ x0, the initial point
31 -> b -- ^ y0, the initial value at x0
32 -> (a -> b -> b) -- ^ The function f(x,y)
33 -> a -- ^ The step size h.
35 eulers_method1 x0 y0 f h =
38 h' = fromRational $ toRational h
42 -- | Perform $n$ iterations of Euler's method over the interval [$x0$,
43 -- $xN$]. The step size `h` will be calculated automatically. A list
44 -- of y-values will be returned.
46 -- The explicit 'forall' in the type signature allows us to refer
47 -- back to the type variables 'a' and 'b' in the 'where' clause.
55 -- >>> let ys = eulers_method x0 xN y0 f 10000
56 -- >>> let yN = head $ reverse ys
57 -- >>> abs ((exp 1) - yN) < 1/10^3
60 eulers_method :: forall a b c. (RealFrac a, RealFrac b, Integral c)
61 => a -- ^ x0, the initial point
62 -> b -- ^ y0, the initial value at x0
63 -> a -- ^ xN, the terminal point
64 -> (a -> b -> b) -- ^ The function f(x,y)
65 -> c -- ^ n, the number of intervals to use.
67 eulers_method x0 y0 xN f n =
70 xs = partition n x0 xN
72 -- The 'go' function actually does all the work. It takes a list
73 -- of intervals [(x0,x1), (x1, x2)...] and peels off the first
74 -- one. It then runs the single-step Euler's method on that
75 -- interval, and afterwards recurses down the rest of the list.
76 go :: [(a,a)] -> b -> (a -> b -> b) -> [b]
78 go ((x0,x1):rest) y0 f = y1 : (go rest y1 f)
80 y1 = eulers_method1 x0 y0 f (x1 - x0)