-
Notifications
You must be signed in to change notification settings - Fork 1
/
Template.hs
74 lines (64 loc) · 2.48 KB
/
Template.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
{-# LANGUAGE TemplateHaskell #-}
module Template where
import Language.Haskell.TH
unrollLookupTree :: SplitTree -> ExpQ
unrollLookupTree t = do
x <- newName "x"
body <- loop (varE x) Nothing Nothing t
return $ LamE [VarP x] body
loop :: ExpQ -> Maybe (Double,Double) -> Maybe (Double,Double) -> SplitTree -> ExpQ
loop x lb ub Leaf =
case (lb,ub) of
(Nothing, Nothing) -> error "can't interpolate on empty tree"
(Just (l,lv), Nothing) -> ld lv
(Nothing, Just (u,uv)) -> ld uv
(Just (l,lv), Just (u,uv)) ->
[| $(ld lv) + ($x - $(ld l)) * ($(ld uv) - $(ld lv))/($(ld u) - $(ld l)) |]
loop x lb ub (Node (n,nv) left right) =
[| case compare $x $(ld n) of
EQ -> $(ld nv)
LT -> $(loop x lb (Just (n,nv)) left)
GT -> $(loop x (Just (n,nv)) ub right)
|]
-- Lift a Double to an ExpQ
ld :: Double -> ExpQ
ld = litE . rationalL . realToFrac
unrollLinearLookup [] = error "linearLookup: empty table"
unrollLinearLookup table = do
x <- newName "x"
body <- linearLoop (varE x) Nothing table
return $ LamE [VarP x] body
linearLoop :: ExpQ -> Maybe (Double,Double) -> [(Double,Double)] -> ExpQ
linearLoop x Nothing [] = error "absolutely cannot happen"
linearLoop x (Just (a,av)) [] = ld av
linearLoop x previous ((b,bv):rest) =
let val = case previous of
Just (a,av) -> [| $(ld av) + ($x - $(ld a)) * ($(ld bv) - $(ld av))/($(ld b) - $(ld a)) |]
Nothing -> ld bv
in [| case compare $x $(ld b) of
GT -> $(linearLoop x (Just (b,bv)) rest)
_ -> $val
|]
data SplitTree = Leaf
| Node (Double, Double) SplitTree SplitTree
deriving (Show)
makeTree :: [(Double,Double)] -> SplitTree
makeTree [] = Leaf
makeTree [p] = Node p Leaf Leaf
makeTree ps = let n = length ps
m = n `div` 2
(left, (middle:right)) = splitAt m ps
in Node middle (makeTree left) (makeTree right)
treeLookup :: SplitTree -> Double -> Double
treeLookup t x = loop Nothing Nothing t
where loop lb ub Leaf =
case (lb,ub) of
(Nothing, Nothing) -> error "can't interpolate on empty tree"
(Just (l,lv), Nothing) -> lv
(Nothing, Just (u,uv)) -> uv
(Just (l,lv), Just (u,uv)) -> lv + (x-l)*(uv-lv)/(u-l)
loop lb ub (Node (n,nv) left right) =
case compare x n of
EQ -> nv
LT -> loop lb (Just (n,nv)) left
GT -> loop (Just (n,nv)) ub right