array-memoize 0.5.0 → 0.6.0
raw patch · 2 files changed
+117/−90 lines, 2 files
Files
- Data/Function/ArrayMemoize.hs +107/−82
- array-memoize.cabal +10/−8
Data/Function/ArrayMemoize.hs view
@@ -8,60 +8,67 @@ import Data.Array.ST (STArray, STUArray, runSTArray) import Control.Monad.ST -import Debug.Trace -{-+{-| Memoize a function over a finite (sub)domain, using an array (boxed), e.g., + @+ arrayMemo (0, 20) f+ @+ memoizes f between from 0 to 20. -}+{-# INLINE arrayMemo #-}+arrayMemo :: (Ix a, ArrayMemoizable b) => (a, a) -> (a -> b) -> (a -> b)+arrayMemo (l, u) f = + let cache = runSTArray (do cache <- newArray_ (l, u)+ mapM_ (\x -> writeArray cache x (f x)) (range (l, u))+ return cache)+ in \x -> cache ! x -Attempt at rewrite rules -{-# RULES "disc-rw1" continuize = cont';- "disc-rw2" discretize = disc';- "disc1a" forall delta x . disc' delta (cont' delta x) = x; - "disc2a" forall delta x . cont' delta (disc' delta x) = x; - "disc1b" forall delta . (disc' delta) . (cont' delta) = id;- #-}+{-| Memoize a fixed point of a function over a sub domain.+ Similar to 'fix', but over 'arrayMemo', passing a function a memoized + version of itself. -}+{-# INLINE arrayMemoFix #-}+arrayMemoFix :: (Ix a, ArrayMemoizable b) => (a, a) -> ((a -> b) -> (a -> b)) -> a -> b+arrayMemoFix (l, u) f = memo_f where memo_f = arrayMemo (l, u) (f memo_f) -{-# NOINLINE cont' #-}-cont' = continuize -{-# NOINLINE disc' #-}-disc' = discretize --}+{-| Memoize a mutual fixed point for two functions (over sub domains of these functions). -}+{-# INLINE arrayMemoFixMutual #-}+arrayMemoFixMutual :: (ArrayMemoizable b, ArrayMemoizable d, Ix a, Ix c) => (a, a) -> (c, c) -> ((a -> b) -> (c -> d) -> (a -> b)) -> ((a -> b) -> (c -> d) -> (c -> d)) -> (a -> b)+arrayMemoFixMutual (l, u) (l', u') f g =+ memo_f where memo_f = arrayMemo (l, u) (f memo_f memo_g) + memo_g = arrayMemo (l', u') (g memo_f memo_g) --- Memoize and quantize a function over a finite (sub)domain, using an array. -{-# INLINE quantizedMemo #-}-quantizedMemo :: (Show a, ArrayMemoizable b, Discretize a) => (a, a) -> a -> (a -> b) -> (a -> b)-quantizedMemo (l, u) delta f =- let disc = discretize delta- cache = runSTArray (do cache <- newArray_ (disc l, succ (disc u))- mapM_ (\x -> writeArray cache x (f (continuize delta x))) (enumFromTo (disc l) (succ (disc u)))- return cache)- in (\x -> cache ! disc x)+{-| Memoize a mutual fixed point for three functions (over sub domains of these functions). -} -{-# INLINE quantizedMemoFix #-} -quantizedMemoFix :: (ArrayMemoizable b, Discretize a, Show a) => (a, a) -> a -> ((a -> b) -> (a -> b)) -> (a -> b)-quantizedMemoFix (l, u) delta f = memo_f where memo_f = quantizedMemo (l, u) delta (f memo_f) +{-# INLINE arrayMemoFixMutual3 #-}+arrayMemoFixMutual3 :: (ArrayMemoizable b, ArrayMemoizable d, ArrayMemoizable f, Ix a, Ix c, Ix e) => (a, a) -> (c, c) -> (e, e) -> ((a -> b) -> (c -> d) -> (e -> f) -> (a -> b)) -> ((a -> b) -> (c -> d) -> (e -> f) -> (c -> d)) ->+ ((a -> b) -> (c -> d) -> (e -> f) -> (e -> f)) -> (a -> b)+arrayMemoFixMutual3 (l, u) (l', u') (l'', u'') f g h =+ memo_f where memo_f = arrayMemo (l, u) (f memo_f memo_g memo_h) + memo_g = arrayMemo (l', u') (g memo_f memo_g memo_h) + memo_h = arrayMemo (l'', u'') (h memo_f memo_g memo_h) -{--quantizedMemoFix :: (Show a, ArrayMemoizable b, Discretize a) => (a, a) -> a -> ((a -> b) -> (a -> b)) -> (a -> b)-quantizedMemoFix (l, u) delta f =- let disc = discretize delta- cache = runSTArray (do cache <- newArray_ (disc l, succ (disc u))- mapM_ (\x -> writeArray cache x (f' (continuize delta x))) (enumFromTo (disc l) (succ (disc u)))- return cache)- f' = f (\x ->(show x) `trace` cache ! disc x) -- - in f'-} +{-| Memoize a function over a finite (sub)domain, using an unboxed 'IO' array. + This requires the incoming function to return results in the 'IO' monad, but should + preferable be pure. -}+{-# INLINE uarrayMemoFixIO #-}+uarrayMemoFixIO :: (Ix a, UArrayMemoizable b) => (a, a) -> ((a -> IO b) -> (a -> IO b)) -> a -> IO b+uarrayMemoFixIO (l, u) f =+ \i -> do cache <- newUArray_ (l, u)+ let f' = f (\x -> readUArray cache x)+ mapM_ (\x -> (f' x) >>= (\val -> writeUArray cache x val)) (range (l, u)) + f' i -{-# INLINE quantizedMemoFixMutual #-}-quantizedMemoFixMutual :: (ArrayMemoizable b, ArrayMemoizable d, Discretize a, Discretize c, Show a, Show c) => (a, a) -> a -> (c, c) -> c -> ((a -> b) -> (c -> d) -> (a -> b)) -> ((a -> b) -> (c -> d) -> (c -> d)) -> (a -> b)-quantizedMemoFixMutual (l, u) delta (l', u') delta' f g =- memo_f where memo_f = quantizedMemo (l, u) delta (f memo_f memo_g) - memo_g = quantizedMemo (l', u') delta' (g memo_f memo_g) --- Memoize and discretize a function over a finite (sub)domain, using an array. -+{-| Memoize and discretize a function over a finite (sub)domain, using an array. e.g.+ @+ discretemMemo (0.0, 10.0) 2.0 f+ @+ returns a discretized version of f (with the discrete type defined by 'Discrete') + in the range 0.0 to 10.0 with step size 2.0 (i.e., the resulting discrete domain is + of size 5). -} {-# INLINE discreteMemo #-} discreteMemo :: (ArrayMemoizable b, Discretize a) => (a, a) -> a -> (a -> b) -> (Discrete a -> b) discreteMemo (l, u) delta f =@@ -72,6 +79,7 @@ in (\x -> cache ! x) +{-| Memoize and discretize a fixed point of a function over a subdomain with discretization step -} {-# INLINE discreteMemoFix #-} discreteMemoFix :: (ArrayMemoizable b, Discretize a) => (a, a) -> a -> ((a -> b) -> (a -> b)) ->(Discrete a -> b) discreteMemoFix (l, u) delta f =@@ -81,44 +89,51 @@ return cache) in (\x -> cache' ! x) --- Memoize a function over a finite (sub)domain, using an array. -{-# INLINE arrayMemo #-}-arrayMemo :: (Ix a, ArrayMemoizable b) => (a, a) -> (a -> b) -> (a -> b)-arrayMemo (l, u) f = - let cache = runSTArray (do cache <- newArray_ (l, u)- mapM_ (\x -> writeArray cache x (f x)) (range (l, u))- return cache)- in \x -> cache ! x+{-| Memoize and quantize a function over a finite (sub)domain, using a boxed array, e.g, + @+ quantizedMemo (0.0, 10.0) 2.0 f+ @+ memoizes f between 0.0 and 10.0 with step size 2.0 (i.e. the function is quantized into + 5 parts, memoized into an array of size 5).+-}+{-# INLINE quantizedMemo #-}+quantizedMemo :: (ArrayMemoizable b, Discretize a) => (a, a) -> a -> (a -> b) -> (a -> b)+quantizedMemo (l, u) delta f =+ let disc = discretize delta+ cache = runSTArray (do cache <- newArray_ (disc l, succ (disc u))+ mapM_ (\x -> writeArray cache x (f (continuize delta x))) (enumFromTo (disc l) (succ (disc u)))+ return cache)+ in (\x -> cache ! disc x) -{-# INLINE arrayMemoFix #-}-arrayMemoFix :: (Ix a, ArrayMemoizable b) => (a, a) -> ((a -> b) -> (a -> b)) -> a -> b-arrayMemoFix (l, u) f = memo_f where memo_f = arrayMemo (l, u) (f memo_f) -{-# INLINE arrayMemoFixMutual #-}-arrayMemoFixMutual :: (ArrayMemoizable b, ArrayMemoizable d, Ix a, Ix c) => (a, a) -> (c, c) -> ((a -> b) -> (c -> d) -> (a -> b)) -> ((a -> b) -> (c -> d) -> (c -> d)) -> (a -> b)-arrayMemoFixMutual (l, u) (l', u') f g =- memo_f where memo_f = arrayMemo (l, u) (f memo_f memo_g) - memo_g = arrayMemo (l', u') (g memo_f memo_g) +{-| Memoize and quantize a fixed point of a function. Similar to 'fix', but using 'quantizedMemo' +to pass the fixed function a quantized memoized version of itself,+ therefore memoizing any recursive calls. -}+{-# INLINE quantizedMemoFix #-} +quantizedMemoFix :: (ArrayMemoizable b, Discretize a) => (a, a) -> a -> ((a -> b) -> (a -> b)) -> (a -> b)+quantizedMemoFix (l, u) delta f = memo_f where memo_f = quantizedMemo (l, u) delta (f memo_f) --- Memoize an function over a finite (sub)domain, using an unboxed IO array--- requires incoming function must return IO - but be otherwise pure+{-| Memoize and quantize a mutually recursive fixed point of two functions. -}+{-# INLINE quantizedMemoFixMutual #-}+quantizedMemoFixMutual :: (ArrayMemoizable b, ArrayMemoizable d, Discretize a, Discretize c) => (a, a) -> a -> (c, c) -> c -> ((a -> b) -> (c -> d) -> (a -> b)) -> ((a -> b) -> (c -> d) -> (c -> d)) -> (a -> b)+quantizedMemoFixMutual (l, u) delta (l', u') delta' f g =+ memo_f where memo_f = quantizedMemo (l, u) delta (f memo_f memo_g) + memo_g = quantizedMemo (l', u') delta' (g memo_f memo_g) -{-# INLINE uarrayMemoFixIO #-}-uarrayMemoFixIO :: (Ix a, UArrayMemoizable b) => (a, a) -> ((a -> IO b) -> (a -> IO b)) -> a -> IO b-uarrayMemoFixIO (l, u) f =- \i -> do cache <- newUArray_ (l, u)- let f' = f (\x -> readUArray cache x)- mapM_ (\x -> (f' x) >>= (\val -> writeUArray cache x val)) (range (l, u)) - f' i -{-+{-| Memoize and quantize a mutually recursive fixed point of three functions. -}+{-# INLINE quantizedMemoFixMutual3 #-}+quantizedMemoFixMutual3 :: (ArrayMemoizable b, ArrayMemoizable d, ArrayMemoizable f, Discretize a, Discretize c, Discretize e) => (a, a) -> a -> (c, c) -> c -> (e, e) -> e -> ((a -> b) -> (c -> d) -> (e -> f) -> (a -> b)) -> ((a -> b) -> (c -> d) -> (e -> f) -> (c -> d)) -> ((a -> b) -> (c -> d) -> (e -> f) -> (e -> f)) -> (a -> b)+quantizedMemoFixMutual3 (l, u) delta (l', u') delta' (l'', u'') delta'' f g h =+ memo_f where memo_f = quantizedMemo (l, u) delta (f memo_f memo_g memo_h) + memo_g = quantizedMemo (l', u') delta' (g memo_f memo_g memo_h) + memo_h = quantizedMemo (l'', u'') delta'' (h memo_f memo_g memo_h) - The following defines the subset of types for which we can do array - memoization --}+{-| 'ArrayMemoizable' defines the subset of types for which we can do array + memoization -} class ArrayMemoizable a where newArray_ :: (Ix i) => (i, i) -> ST s (STArray s i a)@@ -132,41 +147,51 @@ newArray_ = MArray.newArray_ writeArray = MArray.writeArray +instance ArrayMemoizable Integer where+ newArray_ = MArray.newArray_+ writeArray = MArray.writeArray+ instance ArrayMemoizable Int where newArray_ = MArray.newArray_ writeArray = MArray.writeArray --- Unboxed versions using IO+instance ArrayMemoizable Bool where+ newArray_ = MArray.newArray_+ writeArray = MArray.writeArray +instance ArrayMemoizable Char where+ newArray_ = MArray.newArray_+ writeArray = MArray.writeArray++{-| 'UArrayMemoizable' defines the subset of types for which we can +do unboxed IOUArray memoization -}+ class IArray UArray a => UArrayMemoizable a where newUArray_ :: (Ix i) => (i, i) -> IO (IOUArray i a) writeUArray :: (Ix i) => IOUArray i a -> i -> a -> IO () readUArray :: (Ix i) => IOUArray i a -> i -> IO a- freeze :: (Ix i) => IOUArray i a -> IO (UArray i a) instance UArrayMemoizable Float where newUArray_ = MArray.newArray_ readUArray = MArray.readArray writeUArray = MArray.writeArray- freeze = MArray.freeze instance UArrayMemoizable Double where newUArray_ = MArray.newArray_ readUArray = MArray.readArray writeUArray = MArray.writeArray- freeze = MArray.freeze instance UArrayMemoizable Int where newUArray_ = MArray.newArray_ readUArray = MArray.readArray writeUArray = MArray.writeArray- freeze = MArray.freeze -{---Num and Enum classes for working with tuple domains+instance UArrayMemoizable Char where+ newUArray_ = MArray.newArray_+ readUArray = MArray.readArray+ writeUArray = MArray.writeArray --}+{- Num and Enum classes for working with tuple domains -} instance (Enum a, Enum b) => Enum (a, b) where toEnum = undefined@@ -192,7 +217,6 @@ signum (a, b) = (signum a, signum b) fromInteger i = (0, fromInteger i) - instance (Num a, Num b, Num c) => Num (a, b, c) where (a1, b1, c1) + (a2, b2, c2) = (a1 + a2, b1 + b2, c1 + c2) (a1, b1, c1) * (a2, b2, c2) = (a1 * a2, b1 * b2, c1 * c2)@@ -201,7 +225,7 @@ signum (a, b, c) = (signum a, signum b, signum c) fromInteger i = (0, 0, fromInteger i) -{- Discretization of float/double values and tuples -}+{-| Discretization of float/double values and tuples -} class (Ix (Discrete t), Enum (Discrete t)) => Discretize t where type Discrete t@@ -230,5 +254,6 @@ discretize (dx, dy, dz) (x, y, z) = (discretize dx x, discretize dy y, discretize dz z) continuize (dx, dy, dz) (x, y, z) = (continuize dx x, continuize dy y, continuize dz z) +{-| Discretized a function function. The second parameter is the discretisation step. -} discrete :: Discretize a => (a -> b) -> a -> (Discrete a -> b) discrete f delta = f . (continuize delta)
array-memoize.cabal view
@@ -1,10 +1,10 @@ name: array-memoize-version: 0.5.0-synopsis: Memoization combinators for finite subsets of function domains using arrays+version: 0.6.0+synopsis: Memoization combinators using arrays for finite sub-domains of functions description: Memoization combinators are great for providing high-performance Haskell programs, but they can be even faster if memoization is performed on a finite, discrete domain- as an array can then be used.+ since an array can then be used to store results. . This package provides various combinators for doing just this, including also combinators for quanitzing and discretizing Float/Double-valued functions.@@ -12,12 +12,14 @@ Example: . @- fibA :: Int -> Int- fibA 0 = 1- fibA 1 = 1- fibA n = fibB (n - 1) + fibB (n - 2)+ fib' :: (Int -> Int) -> Int -> Int+ fib' _ 0 = 1+ fib' _ 1 = 1+ fib' rec n = rec (n - 1) + rec (n - 2) - fibB = arrayMemo (0, 1000) fibA + -- Memoizes fib between 0 and 1000 (after that it is a run-time error)+ fib :: Int -> Int+ fib = arrayMemoFix (0, 1000) fib' @ license: BSD3