-
Notifications
You must be signed in to change notification settings - Fork 75
Expand file tree
/
Copy pathBoyerMoore.hs
More file actions
92 lines (76 loc) · 2.39 KB
/
BoyerMoore.hs
File metadata and controls
92 lines (76 loc) · 2.39 KB
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE ScopedTypeVariables #-}
module BoyerMoore where
import Copilot.Language hiding (length)
import Copilot.Theorem
import Copilot.Theorem.Prover.SMT (induction, def, debug, z3)
import Copilot.Core.Type
import Prelude ()
import Control.Monad (forM_)
import Data.String (fromString)
import qualified Prelude as P
import qualified Data.List as L
length :: [a] -> Stream Word8
length l = constant (fromInteger $ L.genericLength l)
arbitraryCst :: forall a . (Typed a) => String -> Stream a
arbitraryCst s = c
where
t :: Stream Word8
t = [0] ++ (1 + t)
i :: Stream a
i = extern s Nothing
c = if t == 0 then i else [uninitialized (typeOf :: Type a)] ++ c
majorityVote :: forall a . (Typed a, Eq a) => [Stream a] -> Stream a
majorityVote [] = error "empty list"
majorityVote (x : xs) = aux x 1 xs
where
aux :: Stream a -> Stream Word8 -> [Stream a] -> Stream a
aux p _s [] = p
aux p s (l : ls) =
local (if s == 0 then l else p) $ \p' ->
local (if s == 0 || l == p then s + 1 else s - 1) $ \s' ->
aux p' s' ls
okWith ::
forall a . (Typed a, Eq a) =>
Stream a -> [Stream a] -> Stream a -> Stream Bool
okWith a l maj = (a /= maj) ==> ((2 * count a l) <= length l)
where
count :: Stream a -> [Stream a] -> Stream Word8
count _e [] = 0
count e (x : xs) = (if x == e then 1 else 0) + count e xs
spec = do
forM_ (zip [1..] ss) $ \(k :: Int, s) ->
observer ((P.++) "s" (show k)) s
observer "maj" maj
i1 <- prop "i1" (forAll $ s1 == 1 && s2 == 1 && s3 == 1 && s4 == 1)
theorem "r1" (forAll $ maj == 1) $ assume i1 >> induct
theorem "OK" (forAll $ okWith (arbitraryCst "n") ss maj) induct
where
s1 = externW8 "s1" (Just $ repeat 1)
s2 = externW8 "s2" (Just $ repeat 3)
s3 = externW8 "s3" (Just $ repeat 1)
s4 = externW8 "s4" (Just $ repeat 1)
s5 = externW8 "s5" (Just $ repeat 2)
s6 = externW8 "s6" (Just $ repeat 2)
s7 = externW8 "s7" (Just $ repeat 1)
ss = [s1, s2, s3, s4, s5, s6, s7]
maj = majorityVote ss
induct :: Proof Universal
induct = induction def { debug = False } z3
-- | Initial value for a given type.
--
-- Does not support structs or arrays.
uninitialized :: Type a -> a
uninitialized t =
case t of
Bool -> False
Int8 -> 0
Int16 -> 0
Int32 -> 0
Int64 -> 0
Word8 -> 0
Word16 -> 0
Word32 -> 0
Word64 -> 0
Float -> 0
Double -> 0