-
Notifications
You must be signed in to change notification settings - Fork 0
/
Set.hs
254 lines (215 loc) · 9.73 KB
/
Set.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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
module Set.Set where
import qualified Data.Set as Set
{-@ class measure setElts :: forall s a. s a -> Set.Set a @-}
{-@ class Set s a where
empty :: {v:s a | Set_emp (setElts v)}
insert :: e:a -> v:s a -> {vv: s a | (setElts vv) == Set_cup (Set_sng e) (setElts v)}
member :: e:a -> v:s a -> Bool
@-}
class Set s a where
empty :: s a
insert :: a -> s a -> s a
member :: a -> s a -> Bool
{------------------------------------------------------------------------------
- BEGIN UnbalancedSet Implementation
- I couldn't get this to work in a seperate file so, it's here for now.
-----------------------------------------------------------------------------}
{-@ data UnbalancedSet a =
E |
T {
val :: a,
left :: UnbalancedSet {vv:a | vv < val},
right :: UnbalancedSet {vv:a | vv > val}
}
@-}
data UnbalancedSet a =
E |
T {
val :: a,
left :: UnbalancedSet a,
right :: UnbalancedSet a
}
{-@ instance measure setElts :: forall a. UnbalancedSet a -> Set.Set a
setElts E = (Set_empty 0)
setElts (T v l r) = Set_cup (Set_sng v) (Set_cup (setElts l) (setElts r))
@-}
{-@ insert_aux :: Ord a =>
x:a ->
v:UnbalancedSet a ->
{vv: UnbalancedSet a |
((setElts vv) == Set_cup (Set_sng x) (setElts v))}
@-}
insert_aux :: Ord a => a -> UnbalancedSet a -> UnbalancedSet a
insert_aux x E = T x E E
insert_aux x s@(T y l r)
| x < y = T y (insert_aux x l) r
| x > y = T y l (insert_aux x r)
| otherwise = s
instance Ord a => Set UnbalancedSet a where
empty = E
insert x s = insert_aux x s
member _ E = False
member x (T y l r)
| x < y = member x l
| x > y = member x r
| otherwise = True
{------------------------------------------------------------------------------
- BEGIN Red-Black Implementation
- Same story as above.
-----------------------------------------------------------------------------}
data Color = Red | Black deriving Eq
{-@ data RedBlackSet a =
Empty |
Tree {
color :: Color,
rbval :: a,
rbleft :: { v:RedBlackSet {vv:a | vv < rbval} | RedInvariant color v},
rbright :: { v:RedBlackSet {vv:a | vv > rbval} | RedInvariant color v &&
BlackInvariant v rbleft}
}
@-}
{-@ predicate RedInvariant C S = (C == Red) ==> (getColor S /= Red) @-}
{-@ predicate BlackInvariant S0 S1 = (numBlack S0) == (numBlack S1) @-}
data RedBlackSet a =
Empty |
Tree {
color :: Color,
rbval :: a,
rbleft :: RedBlackSet a,
rbright :: RedBlackSet a
}
{- Assuming that the number of black nodes along are paths to a leaf node are
- equal, return this value. This function actually counts the number of black
- nodes when recursing leftwards down the tree but, red black tree must have
- this value be the same for all paths to a leaf node -}
{-@ measure numBlack @-}
{-@ numBlack :: RedBlackSet a -> Nat @-}
numBlack :: RedBlackSet a -> Int
numBlack Empty = 0
numBlack (Tree c _ l r) = (if c == Black then 1 else 0) + (numBlack l)
{- By definition, the empty nodes in a Red Black Tree are black. The color of
- all other nodes is defined by the color field -}
{-@ measure getColor @-}
{-@ getColor :: RedBlackSet a -> Color @-}
getColor Empty = Black
getColor (Tree c _ _ _) = c
{-@ instance measure setElts :: forall a. RedBlackSet a -> Set.Set a
setElts Empty = (Set_empty 0)
setElts (Tree _ v l r) = Set_cup (Set_sng v) (Set_cup (setElts l) (setElts r))
@-}
{- Sometimes, I need to represent a weaker variant of a RedBlackSet. This data
- type checks most of the same invariants but, it does not require that the
- red invariant holds for the root of the tree. It does require that the black
- invariant holds.
-
- It also a requires a weak version of the red invariant: At least one out of
- the root node and its children must be black. This property was chosen
- because it holds for trees before and after rebalancing during insertion. -}
{-@ data WeakRedInvariant a = WeakRedInvariant {
weakColor :: Color,
weakVal :: a,
weakLeft :: RedBlackSet {vv:a | vv < weakVal},
weakRight :: {v:RedBlackSet {vv:a | vv > weakVal} |
(weakColor /= Red ||
(getColor weakLeft) /= Red ||
(getColor v) /= Red) &&
(numBlack v) == (numBlack weakLeft)}
}
@-}
data WeakRedInvariant a = WeakRedInvariant {
weakColor :: Color,
weakVal :: a,
weakLeft :: RedBlackSet a,
weakRight :: RedBlackSet a
}
{- I want to be able to say that a WeakRedInvariant actualy has the original
- strong version of the invariant. -}
{-@ predicate HasStrongRedInvariant Nri = (weakColor Nri) == Red ==>
(getColor (weakLeft Nri) /= Red &&
getColor (weakRight Nri) /= Red)
@-}
{-@ instance measure setElts :: forall a. WeakRedInvariant a -> Set.Set a
setElts (WeakRedInvariant _ v l r) = Set_cup (Set_sng v) (Set_cup (setElts l) (setElts r))
@-}
{-@ measure weakNumBlack @-}
{-@ weakNumBlack :: WeakRedInvariant a -> Nat @-}
weakNumBlack :: WeakRedInvariant a -> Int
weakNumBlack (WeakRedInvariant c _ l r) = (if c == Black then 1 else 0) + (numBlack l)
{- balanceLeft is called after the recursivly inserting an element into the left
- subtree. The recursive insert might have left the tree in a state where the
- red invariant no longer holds. This Fixes the invariant in the left subtree
- and returns a new tree constructed using the element, right subtree and fixed
- left subtree. This new tree might also fail to maintain the red invariant. but,
- this will be fixed by later calls to balance or by insert after rb_insert_aux
- completes. -}
{-@ balanceLeft :: forall a. Ord a =>
c:Color ->
t:a ->
l:{v:WeakRedInvariant {vv:a | vv < t} | c == Red ==> HasStrongRedInvariant v} ->
r:{v:RedBlackSet {vv:a | vv > t} | RedInvariant c v &&
(numBlack v) == (weakNumBlack l)} ->
{v:WeakRedInvariant a | (c /= Red ==> HasStrongRedInvariant v) &&
(weakNumBlack v) == ( if c == Black then 1 else 0) + weakNumBlack l &&
(setElts v) == (Set_cup (Set_sng t) (Set_cup (setElts l) (setElts r)))}
@-}
balanceLeft :: Ord a => Color -> a -> WeakRedInvariant a -> RedBlackSet a -> WeakRedInvariant a
balanceLeft Black z (WeakRedInvariant Red y (Tree Red x a b) c) d =
WeakRedInvariant Red y (Tree Black x a b) (Tree Black z c d)
balanceLeft Black z (WeakRedInvariant Red x a (Tree Red y b c)) d =
WeakRedInvariant Red y (Tree Black x a b) (Tree Black z c d)
balanceLeft c x (WeakRedInvariant c' x' a' b' ) b =
WeakRedInvariant c x (Tree c' x' a' b') b
{- balanceRight has the same logic as balanceLeft but, it is called after inserting
- into the right subtree. -}
{-@ balanceRight :: forall a. Ord a =>
c:Color ->
t:a ->
l:{v:RedBlackSet {vv:a | vv < t} | RedInvariant c v} ->
r:{v:WeakRedInvariant {vv:a | vv > t} | (c == Red ==> HasStrongRedInvariant v) &&
(weakNumBlack v) == (numBlack l)} ->
{v:WeakRedInvariant a | (c /= Red ==> HasStrongRedInvariant v) &&
(weakNumBlack v) == (if c == Black then 1 else 0) + numBlack l &&
(setElts v) == (Set_cup (Set_sng t) (Set_cup (setElts l) (setElts r)))}
@-}
balanceRight :: Ord a => Color -> a -> RedBlackSet a -> WeakRedInvariant a -> WeakRedInvariant a
balanceRight Black x a (WeakRedInvariant Red z (Tree Red y b c) d ) =
WeakRedInvariant Red y (Tree Black x a b) (Tree Black z c d)
balanceRight Black x a (WeakRedInvariant Red y b (Tree Red z c d) ) =
WeakRedInvariant Red y (Tree Black x a b) (Tree Black z c d)
balanceRight c x a (WeakRedInvariant c' x' a' b' ) =
WeakRedInvariant c x a (Tree c' x' a' b')
{- This is where recursive insertion happens. No special refinements are placed
- on the inputs to this function, but the return type is interesting. The return
- value is not always a complete red back tree. It only has the full red invariant
- if the original color of the tree was black (I'm not sure I fully understand
- why this is the case). The other refinements on the return value check that
- the black node property has not changed during insertion and that the expected
- change has occurred in the set of elements. The first is required when constructing
- a new tree from the old subtree and a new subtree where an element has been inserted.
- The second is used to ensure this data structure behaves like a set. -}
{-@ rb_insert_aux :: forall a. Ord a =>
x:a ->
s:RedBlackSet a ->
{v:WeakRedInvariant a | ((getColor s) /= Red ==> HasStrongRedInvariant v) &&
(weakNumBlack v) == (numBlack s) &&
(setElts v) == (Set_cup (Set_sng x) (setElts s))}
@-}
rb_insert_aux :: Ord a => a -> RedBlackSet a -> WeakRedInvariant a
rb_insert_aux x Empty = WeakRedInvariant Red x Empty Empty
rb_insert_aux x (Tree c y a b)
| x < y = balanceLeft c y (rb_insert_aux x a) b
| x > y = balanceRight c y a (rb_insert_aux x b)
| otherwise = (WeakRedInvariant c y a b)
instance Ord a => Set RedBlackSet a where
empty = Empty
{- The result of rb_insert_aux might not have the red invaraint. This is easy
- to fix by forceing the root node to be black -}
insert x s = forceRedInvarient (rb_insert_aux x s)
where forceRedInvarient (WeakRedInvariant _ e a b) = Tree Black e a b
member _ Empty = False
member e (Tree _ x l r)
| e < x = member e l
| e > x = member e r
| otherwise = True