X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=src%2FODE%2FIVP.hs;h=5bffe08cfff387210c3bdd7cc3f5483dba81c13e;hb=e1bf90ef57aaa37620e001d04cabec0ea2e8ddbf;hp=233e5f872a97f29e4e46dd3a34bc582484ac46ce;hpb=d6f147bb46c47cc5f885b72536f5adbe6039af77;p=numerical-analysis.git diff --git a/src/ODE/IVP.hs b/src/ODE/IVP.hs index 233e5f8..5bffe08 100644 --- a/src/ODE/IVP.hs +++ b/src/ODE/IVP.hs @@ -1,4 +1,5 @@ {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE RebindableSyntax #-} -- | Numerical solution of the initial value problem, -- @@ -8,11 +9,18 @@ -- for x in [x0, xN]. -- -module ODE.IVP +module ODE.IVP ( + eulers_method, + eulers_method1, + eulers_methodH ) where -import Misc (partition) - +import Misc ( partition ) +import NumericPrelude hiding ( abs ) +import qualified Algebra.Field as Field ( C ) +import qualified Algebra.ToInteger as ToInteger ( C ) +import qualified Algebra.ToRational as ToRational ( C ) +import qualified Algebra.RealField as RealField ( C ) -- | A single iteration of Euler's method over the interval -- [$x0$, $x0$+$h$]. @@ -26,7 +34,7 @@ import Misc (partition) -- >>> eulers_method1 x0 y0 f h -- 2.0 -- -eulers_method1 :: (RealFrac a, RealFrac b) +eulers_method1 :: forall a b. (Field.C a, ToRational.C a, Field.C b) => a -- ^ x0, the initial point -> b -- ^ y0, the initial value at x0 -> (a -> b -> b) -- ^ The function f(x,y) @@ -35,7 +43,7 @@ eulers_method1 :: (RealFrac a, RealFrac b) eulers_method1 x0 y0 f h = y0 + h'*y' where - h' = fromRational $ toRational h + h' = fromRational'$ toRational h :: b y' = (f x0 y0) @@ -48,6 +56,7 @@ eulers_method1 x0 y0 f h = -- -- Examples: -- +-- >>> import Algebra.Absolute (abs) -- >>> let x0 = 0.0 -- >>> let xN = 1.0 -- >>> let y0 = 1.0 @@ -59,7 +68,11 @@ eulers_method1 x0 y0 f h = -- >>> head ys == y0 -- True -- -eulers_method :: forall a b c. (RealFrac a, RealFrac b, Integral c) +eulers_method :: forall a b c. (Field.C a, + ToRational.C a, + Field.C b, + ToInteger.C c, + Enum c) => a -- ^ x0, the initial point -> b -- ^ y0, the initial value at x0 -> a -- ^ xN, the terminal point @@ -72,14 +85,15 @@ eulers_method x0 y0 xN f n = xs = partition n x0 xN -- The 'go' function actually does all the work. It takes a list - -- of intervals [(x0,x1), (x1, x2)...] and peels off the first + -- of intervals [(v0,v1), (v1, v2)...] and peels off the first -- one. It then runs the single-step Euler's method on that -- interval, and afterwards recurses down the rest of the list. + -- go :: [(a,a)] -> b -> (a -> b -> b) -> [b] go [] _ _ = [] - go ((x0,x1):rest) y0 f = y1 : (go rest y1 f) + go ((v0,v1):rest) w0 g = w1 : (go rest w1 g) where - y1 = eulers_method1 x0 y0 f (x1 - x0) + w1 = eulers_method1 v0 w0 g (v1 - v0) -- | Perform as many iterations of Euler's method over the interval @@ -101,7 +115,7 @@ eulers_method x0 y0 xN f n = -- >>> ys == ys' -- True -- -eulers_methodH :: (RealFrac a, RealFrac b) +eulers_methodH :: (RealField.C a, ToRational.C a, Field.C b) => a -- ^ x0, the initial point -> b -- ^ y0, the initial value at x0 -> a -- ^ xN, the terminal point @@ -111,4 +125,5 @@ eulers_methodH :: (RealFrac a, RealFrac b) eulers_methodH x0 y0 xN f h = eulers_method x0 y0 xN f n where + n :: Integer n = floor $ (xN - x0) / h