1 {-# LANGUAGE RebindableSyntax #-}
3 module Integration.Simpson
6 import Misc (partition)
8 import NumericPrelude hiding (abs)
9 import Algebra.Absolute (abs)
10 import qualified Algebra.Field as Field
11 import qualified Algebra.RealField as RealField
12 import qualified Algebra.RealRing as RealRing
13 import qualified Algebra.ToInteger as ToInteger
14 import qualified Algebra.ToRational as ToRational
16 -- | Use the Simpson's rule to numerically integrate @f@ over the
17 -- interval [@a@, @b@].
22 -- >>> simpson_1 f (-1) 1
26 -- >>> simpson_1 f (-1) 1
30 -- >>> let area = simpson_1 f (-1) 1
31 -- >>> abs (area - (2/3)) < 1/10^12
35 -- >>> simpson_1 f (-1) 1
39 -- >>> simpson_1 f 0 1
42 simpson_1 :: (RealField.C a, ToRational.C a, RealField.C b)
43 => (a -> b) -- ^ The function @f@
44 -> a -- ^ The \"left\" endpoint, @a@
45 -> a -- ^ The \"right\" endpoint, @b@
48 coefficient * ((f a) + 4*(f midpoint) + (f b))
50 coefficient = (fromRational' $ toRational (b - a)) / 6
51 midpoint = (a + b) / 2
54 -- | Use the composite Simpson's rule to numerically integrate @f@
55 -- over @n@ subintervals of [@a@, @b@].
60 -- >>> let area = simpson 10 f (-1) 1
61 -- >>> abs (area - (2/5)) < 0.0001
64 -- Note that the convergence here is much faster than the Trapezoid
67 -- >>> let area = simpson 10 sin 0 pi
68 -- >>> abs (area - 2) < 0.00001
71 simpson :: (RealField.C a,
76 => c -- ^ The number of subintervals to use, @n@
77 -> (a -> b) -- ^ The function @f@
78 -> a -- ^ The \"left\" endpoint, @a@
79 -> a -- ^ The \"right\" endpoint, @b@
82 sum $ map simpson_pairs pieces
84 pieces = partition n a b
85 -- Convert the simpson_1 function into one that takes pairs
86 -- (a,b) instead of individual arguments 'a' and 'b'.
87 simpson_pairs = uncurry (simpson_1 f)