]> gitweb.michael.orlitzky.com - numerical-analysis.git/commitdiff
Split Roots into Roots.Simple and Roots.Fast.
authorMichael Orlitzky <michael@orlitzky.com>
Tue, 11 Sep 2012 12:40:18 +0000 (08:40 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Tue, 11 Sep 2012 12:40:18 +0000 (08:40 -0400)
Allow the makefile to find sources in subdirectories.
Update module exports in the cabal file.

makefile
numerical-analysis.cabal
src/Roots/Fast.hs [new file with mode: 0644]
src/Roots/Simple.hs [moved from src/Roots.hs with 61% similarity]
test/Doctests.hs

index 8b9c250c4dcb7f623801e1f1543c2f697fab3d98..0ffe8d38935eadc61681a673500d0b98e1419508 100644 (file)
--- a/makefile
+++ b/makefile
@@ -1,23 +1,27 @@
-BIN           = dist/build/numerical-analysis/numerical-analysis
+# There's only one '$' in the awk script, but we have to double-money
+# it for make.
+PN   = $(shell grep 'name:' *.cabal | awk '{ print $$2 }')
+BIN           = dist/build/$(PN)/$(PN)
 DOCTESTS_BIN  = dist/build/doctests/doctests
+SRCS = $(shell find src/ -name '*.hs')
 
 .PHONY : test publish_doc doc dist hlint
 
-$(BIN): src/*.hs
+$(BIN): $(SRCS)
        runghc Setup.hs clean
        runghc Setup.hs configure --user --flags=${FLAGS}
        runghc Setup.hs build
 
-$(DOCTESTS_BIN): src/*.hs test/Doctests.hs
+$(DOCTESTS_BIN): $(SRCS) test/Doctests.hs
        runghc Setup.hs configure --user --flags=${FLAGS} --enable-tests
        runghc Setup.hs build
 
 
-profile: src/*.hs
+profile: $(SRCS)
        runghc Setup.hs configure --user --enable-executable-profiling
        runghc Setup.hs build
 
-hpc: src/*.hs
+hpc: $(SRCS)
        FLAGS="hpc" make
 
 clean:
@@ -34,8 +38,8 @@ dist:
        runghc Setup.hs configure
        runghc Setup.hs sdist
 
-# Neither 'haddock' nor 'hscolour' seem to work properly.
-doc: src/*.hs
+
+doc: $(SRCS)
        runghc Setup.hs configure --user --flags=${FLAGS}
        runghc Setup.hs hscolour --executables
        runghc Setup.hs haddock --internal    \
index 708644fbcd0ee4169a3daeabebc5470f8b8cb574..7bd0fb409795c36257f88e0393ecb439b0e298de 100644 (file)
@@ -16,7 +16,7 @@ description:
 data-files: makefile
 
 library
-  exposed-modules: Roots
+  exposed-modules: Roots.Simple, Roots.Fast
 
   build-depends:
     base                        == 4.5.*,
diff --git a/src/Roots/Fast.hs b/src/Roots/Fast.hs
new file mode 100644 (file)
index 0000000..8e49750
--- /dev/null
@@ -0,0 +1,82 @@
+-- | The Roots.Fast module contains faster implementations of the
+--   'Roots.Simple' algorithms. Generally, we will pass precomputed
+--   values to the next iteration of a function rather than passing
+--   the function and the points at which to (re)evaluate it.
+
+module Roots.Fast
+where
+
+has_root :: (Fractional a, Ord a, Ord b, Num b)
+         => (a -> b) -- ^ The function @f@
+         -> a       -- ^ The \"left\" endpoint, @a@
+         -> a       -- ^ The \"right\" endpoint, @b@
+         -> Maybe a -- ^ The size of the smallest subinterval
+                   --   we'll examine, @epsilon@
+         -> Maybe b -- ^ Precoumpted f(a)
+         -> Maybe b -- ^ Precoumpted f(b)
+         -> Bool
+has_root f a b epsilon f_of_a f_of_b =
+  if not ((signum (f_of_a')) * (signum (f_of_b')) == 1) then
+    -- We don't care about epsilon here, there's definitely a root!
+    True
+  else
+    if (b - a) <= epsilon' then
+      -- Give up, return false.
+      False
+    else
+      -- If either [a,c] or [c,b] have roots, we do too.
+      (has_root f a c (Just epsilon') (Just f_of_a') Nothing) ||
+        (has_root f c b (Just epsilon') Nothing (Just f_of_b'))
+  where
+    -- If the size of the smallest subinterval is not specified,
+    -- assume we just want to check once on all of [a,b].
+    epsilon' = case epsilon of
+                 Nothing -> (b-a)
+                 Just eps -> eps
+
+    -- Compute f(a) and f(b) only if needed.
+    f_of_a'  = case f_of_a of
+                 Nothing -> f a
+                 Just v -> v
+
+    f_of_b'  = case f_of_b of
+                 Nothing -> f b
+                 Just v -> v
+
+    c = (a + b)/2
+
+
+
+bisect :: (Fractional a, Ord a, Num b, Ord b)
+       => (a -> b) -- ^ The function @f@ whose root we seek
+       -> a       -- ^ The \"left\" endpoint of the interval, @a@
+       -> a       -- ^ The \"right\" endpoint of the interval, @b@
+       -> a       -- ^ The tolerance, @epsilon@
+       -> Maybe b -- ^ Precomputed f(a)
+       -> Maybe b -- ^ Precomputed f(b)
+       -> Maybe a
+bisect f a b epsilon f_of_a f_of_b
+  -- We pass @epsilon@ to the 'has_root' function because if we want a
+  -- result within epsilon of the true root, we need to know that
+  -- there *is* a root within an interval of length epsilon.
+  | not (has_root f a b (Just epsilon) (Just f_of_a') (Just f_of_b')) = Nothing
+  | f_of_a' == 0 = Just a
+  | f_of_b' == 0 = Just b
+  | (b - c) < epsilon = Just c
+  | otherwise =
+      -- Use a 'prime' just for consistency.
+      let f_of_c' = f c in
+        if (has_root f a c (Just epsilon) (Just f_of_a') (Just f_of_c'))
+        then bisect f a c epsilon (Just f_of_a') (Just f_of_c')
+        else bisect f c b epsilon (Just f_of_c') (Just f_of_b')
+  where
+    -- Compute f(a) and f(b) only if needed.
+    f_of_a'  = case f_of_a of
+                 Nothing -> f a
+                 Just v -> v
+
+    f_of_b'  = case f_of_b of
+                 Nothing -> f b
+                 Just v -> v
+
+    c = (a + b) / 2
similarity index 61%
rename from src/Roots.hs
rename to src/Roots/Simple.hs
index a8c3c76bdb470e82e291aa2a916fbf632521ef5f..64124a876bfc24d3ff55b15eca29cc9d76dfe613 100644 (file)
@@ -1,14 +1,16 @@
--- | The Roots module contains root-finding algorithms. That is,
---   procedures to (numerically) find solutions to the equation,
+-- | The Roots.Simple module contains root-finding algorithms. That
+--   is, procedures to (numerically) find solutions to the equation,
 --
 --   > f(x) = 0
 --
 --   where f is assumed to be continuous on the interval of interest.
 --
 
-module Roots
+module Roots.Simple
 where
 
+import qualified Roots.Fast as F
+
 
 -- | Does the (continuous) function @f@ have a root on the interval
 --   [a,b]? If f(a) <] 0 and f(b) ]> 0, we know that there's a root in
@@ -37,23 +39,8 @@ has_root :: (Fractional a, Ord a, Ord b, Num b)
                    --   we'll examine, @epsilon@
          -> Bool
 has_root f a b epsilon =
-  if not ((signum (f a)) * (signum (f b)) == 1) then
-    -- We don't care about epsilon here, there's definitely a root!
-    True
-  else
-    if (b - a) <= epsilon' then
-      -- Give up, return false.
-      False
-    else
-      -- If either [a,c] or [c,b] have roots, we do too.
-      (has_root f a c (Just epsilon')) || (has_root f c b (Just epsilon'))
-  where
-    -- If the size of the smallest subinterval is not specified,
-    -- assume we just want to check once on all of [a,b].
-    epsilon' = case epsilon of
-                 Nothing -> (b-a)
-                 Just eps -> eps
-    c = (a + b)/2
+  F.has_root f a b epsilon Nothing Nothing
+
 
 
 
@@ -82,16 +69,5 @@ bisect :: (Fractional a, Ord a, Num b, Ord b)
        -> a       -- ^ The \"right\" endpoint of the interval, @b@
        -> a       -- ^ The tolerance, @epsilon@
        -> Maybe a
-bisect f a b epsilon
-  -- We pass @epsilon@ to the 'has_root' function because if we want a
-  -- result within epsilon of the true root, we need to know that
-  -- there *is* a root within an interval of length epsilon.
-  | not (has_root f a b (Just epsilon)) = Nothing
-  | f a == 0 = Just a
-  | f b == 0 = Just b
-  | (b - c) < epsilon = Just c
-  | otherwise =
-      if (has_root f a c (Just epsilon)) then bisect f a c epsilon
-      else bisect f c b epsilon
-  where
-    c = (a + b) / 2
+bisect f a b epsilon =
+  F.bisect f a b epsilon Nothing Nothing
index f9bacc5b238a57740d046f53b3fa34c0528e175e..3ce1b4a04c736bc5bfaa9346430a3145e5d59d7c 100644 (file)
@@ -4,4 +4,6 @@ where
 import Test.DocTest
 
 main :: IO ()
-main = doctest ["--optghc=-isrc", "src/Root.hs"]
+main = doctest ["--optghc=-isrc",
+                "src/Roots/Simple.hs",
+                "src/Roots/Fast.hs"]