{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveFunctor #-}
module Numeric.AffineForm.Subdivision
( Subdivisible(..)
, SubdivisionEnvironment(..)
, defaultEnvironment
, branchAndBound
) where
import Control.Monad.Reader
import Control.Monad.State
import Data.List
import Numeric.Interval as IA
class Subdivisible a where
subdivide :: a -> Int -> [a]
combine2 :: a -> a -> a
combine :: [a] -> a
combine2 l r = combine [l,r]
combine = foldl1 combine2
instance (Ord a, Fractional a) => Subdivisible (Interval a) where
subdivide i n = f . fromIntegral <$> [1..n]
where f x = (((x-1)*w/n')IA....(x*w/n')) + (IA.singleton $ inf i)
w = width i
n' = fromIntegral n
combine2 = hull
instance (Subdivisible a) => Subdivisible [a] where
subdivide l n = sequenceA $ flip subdivide n <$> l
combine2 l r = uncurry combine2 <$> zip l r
data SubdivisionEnvironment a b e = SubdivisionEnvironment
{ function :: a -> b
, errorFun :: b -> e
, maxError :: e
, maxDepth :: Int
, subdivs :: Int
}
defaultEnvironment :: (Fractional e) => (a -> b) -> (b -> e) -> SubdivisionEnvironment a b e
defaultEnvironment f g = SubdivisionEnvironment
{ function = f
, errorFun = g
, maxError = 0.1
, maxDepth = 3
, subdivs = 2
}
type Subdivider a b e = Reader (SubdivisionEnvironment a b e) (SubdivisionTree a)
data SubdivisionTree a
= Branch [SubdivisionTree a]
| Node a
deriving (Show, Functor)
deepen :: (Subdivisible a, Ord e) => SubdivisionTree a -> Int -> Subdivider a b e
deepen (Node x) depth =
do
env <- ask
let res = function env $ x
err = errorFun env $ res
n = subdivs env
if err <= maxError env
then return $ Node x
else deepen (Branch $ Node <$> subdivide x n) $ depth
deepen (Branch l) depth =
do
env <- ask
if depth >= maxDepth env
then return $ Branch l
else Branch <$> (sequence $ flip deepen (depth + 1) <$> l)
collapse :: (Subdivisible a) => SubdivisionTree a -> a
collapse (Node a) = a
collapse (Branch l) = combine $ collapse <$> l
evalTree :: (Subdivisible b) => Subdivider a b e -> SubdivisionEnvironment a b e -> b
evalTree div cfg = flip runReader cfg $
do
val <- div
env <- ask
return . collapse $ function env <$> val
branchAndBound :: (Subdivisible a, Subdivisible b, Ord e) => a -> SubdivisionEnvironment a b e -> b
branchAndBound x env = flip evalTree env $ deepen (Node x) 0
test :: Interval Double
test =
flip evalTree env $ deepen (Node $ [3 IA.... 4, 1 IA....4]) 0
where env = SubdivisionEnvironment
{ function = (\[x, y] -> x * y - x)
, errorFun = width
, maxError = 0.1
, maxDepth = 5
, subdivs = 2
}