2 (** Hash tables using linear probing
4 Authors: Jean-Christophe Filliâtre (CNRS)
5 Martin Clochard (École Normale Supérieure)
8 module HashedTypeWithDummy
13 type keym (** the logic model of a key *)
14 function keym key: keym
16 val predicate eq (x y: key)
17 ensures { result <-> keym x = keym y }
18 let predicate neq (x y: key)
19 ensures { result <-> keym x <> keym y }
22 val function hash key : int
23 axiom hash_nonneg: forall k: key. 0 <= hash k
24 axiom hash_eq: forall x y: key. eq x y -> hash x = hash y
26 val constant dummy: key
27 constant dummym: keym = keym dummy
33 clone HashedTypeWithDummy with axiom .
36 use int.ComputerDivision
44 let function bucket (k: key) (n: int) : int
46 ensures { 0 <= result < n }
49 (** `j` lies between `l` and `r`, cyclically *)
50 predicate between (l j r: int) =
51 l <= j < r || r < l <= j || j < r < l
53 (** number of dummy values in array `a` between `l` and `u` *)
57 function numof (a: array key) (l u: int) : int =
58 NumOf.numof (fun i -> eq a[i] dummy) l u
60 let rec lemma numof_eq (a1 a2: array key) (l u: int) : unit
61 requires { 0 <= l <= u <= length a1 = length a2 }
62 requires { forall i: int. l <= i < u -> eq a2[i] a1[i] }
63 ensures { numof a2 l u = numof a1 l u }
65 = if l < u then numof_eq a1 a2 (l+1) u
67 let rec lemma dummy_const (a: array key) (n: int)
68 requires { 0 <= n } requires { forall i: int. 0 <= i < n -> a[i] = dummy }
69 variant { n } ensures { numof a 0 n = n }
70 = if n > 0 then dummy_const a (n-1)
73 function numofd (a: array key) (l u: int) : int = NumOfDummy.numof a l u
75 let ghost numof_update (a1 a2: array key) (l i u: int)
76 requires { 0 <= l <= i < u <= Array.length a1 = Array.length a2 }
77 requires { forall j: int. l <= j < u -> j<>i -> a1[j] = a2[j] }
78 requires { eq a1[i] dummy && neq a2[i] dummy }
79 ensures { numofd a1 l u = 1 + numofd a2 l u }
81 assert { numofd a1 l u
82 = numofd a1 l i + numofd a1 i u
83 = numofd a1 l i + numofd a1 i (i+1) + numofd a1 (i+1) u };
84 assert { numofd a2 l u
85 = numofd a2 l i + numofd a2 i u
86 = numofd a2 l i + numofd a2 i (i+1) + numofd a2 (i+1) u }
88 predicate valid (data: array key) (view: map keym bool) (loc : map keym int) =
89 (* dummy not in the model *)
90 not (Map.get view dummym)
92 (* any value in the array is in the model *)
93 (forall i: int. 0 <= i < Array.length data ->
94 let x = data[i] in neq x dummy ->
95 Map.get view (keym x) /\ Map.get loc (keym x) = i)
97 (* any value in the model is in the array *)
98 (let n = Array.length data in
99 forall x: key. Map.get view (keym x) ->
100 let i = Map.get loc (keym x) in
101 0 <= i < n && eq data[i] x &&
102 forall j: int. 0 <= j < n ->
103 between (bucket x n) j i ->
104 neq data[j] x /\ neq data[j] dummy)
105 (* TODO ^^^^^^^^^^^^^^^^^^ is actually provable *)
107 type t = { mutable size: int; (* total number of elements *)
108 mutable data: array key; (* buckets *)
109 ghost mutable view: map keym bool; (* pure model *)
110 ghost mutable loc : map keym int; (* index where it is stored *)
112 (* at least one empty slot *)
113 invariant { 0 <= size < length data }
114 invariant { let n = Array.length data in
115 size + numofd data 0 n = n }
116 invariant { valid data view loc }
118 let create (n: int) : t
120 ensures { forall x: key. not (Map.get result.view (keym x)) }
122 { size = 0; data = Array.make n dummy;
123 view = Const.const false; loc = Const.const 0; }
125 let clear (h: t) : unit
126 writes { h.size, h.data.elts, h.view }
127 ensures { h.size = 0 }
128 ensures { forall x: key. not (Map.get h.view (keym x)) }
131 Array.fill h.data 0 (Array.length h.data) dummy;
132 h.view <- Const.const false
134 let function next (n i: int) : int =
135 let i = i+1 in if i = n then 0 else i
137 let find (a: array key) (x: key) : int
138 requires { neq x dummy }
139 requires { let n = Array.length a in 0 < n /\ numofd a 0 n > 0 }
140 ensures { 0 <= result < Array.length a }
141 ensures { eq a[result] dummy || eq a[result] x }
142 ensures { forall j: int. 0 <= j < Array.length a ->
143 between (bucket x (Array.length a)) j result ->
144 neq a[j] x /\ neq a[j] dummy }
146 let n = Array.length a in
147 let b = bucket x n in
148 let rec find (i: int) : int
149 requires { 0 <= i < n }
150 requires { numofd a 0 n > 0 }
151 requires { forall j: int. 0 <= j < n -> between b j i ->
152 neq a[j] x /\ neq a[j] dummy }
153 requires { if i >= b then numofd a b i = 0
154 else numofd a b n = numofd a 0 i = 0 }
155 variant { if i >= b then n - i + b else b - i }
156 ensures { 0 <= result < n }
157 ensures { eq a[result] dummy || eq a[result] x }
158 ensures { forall j: int. 0 <= j < n -> between b j result ->
159 neq a[j] x /\ neq a[j] dummy }
161 if eq a[i] dummy || eq a[i] x then i else find (next n i)
165 let mem (h: t) (x: key) : bool
166 requires { neq x dummy }
167 ensures { result <-> Map.get h.view (keym x) }
169 neq h.data[find h.data x] dummy
171 let resize (h: t) : unit
172 writes { h.data, h.loc }
173 ensures { Array.length h.data = 2 * old (Array.length h.data) }
175 let n = Array.length h.data in
177 let a = Array.make n2 dummy in
178 let ghost l = ref (Const.const 0) in
179 for i = 0 to n - 1 do
180 invariant { numofd a 0 n2 = numofd h.data 0 i + n2 - i }
181 invariant { forall j: int. 0 <= j < n2 -> neq a[j] dummy ->
182 Map.get h.view (keym a[j]) /\ Map.get !l (keym a[j]) = j }
183 invariant { forall x: key. Map.get h.view (keym x) ->
184 let j = Map.get h.loc (keym x) in
186 let j2 = Map.get !l (keym x) in
187 0 <= j2 < n2 /\ eq a[j2] x /\
188 forall k: int. 0 <= k < n2 ->
189 between (bucket x n2) k j2 -> neq a[k] x /\ neq a[k] dummy
191 forall j2: int. 0 <= j2 < n2 -> neq a[j2] x }
193 if neq x dummy then begin
196 assert { eq a[j] dummy };
198 assert { numofd a 0 (j+1) = numofd (a at L) 0 (j+1) - 1 };
199 l := Map.set !l (keym x) j
205 let add (h: t) (x: key) : unit
206 requires { neq x dummy }
208 ensures { h.view = Map.set (old h.view) (keym x) True }
211 ensures { h.size + 1 < Array.length h.data }
212 if 2 * (h.size + 1) >= Array.length h.data then resize h
214 let i = find h.data x in
215 if eq h.data[i] dummy then begin
217 h.size <- h.size + 1;
219 assert { numofd h.data 0 (i+1) =
220 numofd (h.data at L) 0 (i+1) - 1 }
222 ghost (h.view <- Map.set h.view (keym x) True);
223 ghost (h.loc <- Map.set h.loc (keym x) i)
226 ensures { result.view = h.view }
228 { size = h.size; data = Array.copy h.data;
229 view = h.view; loc = h.loc; }
231 let rec ghost find_dummy (a: array key) (s: int) (i: int) : int
232 requires { 0 <= s < Array.length a }
233 requires { 0 <= i < Array.length a }
235 requires { if i >= s then numofd a i (Array.length a) + numofd a 0 s >= 1
236 else numofd a i s >= 1}
237 requires { forall k: int. 0 <= k < Array.length a ->
238 between s k i -> k<>s -> neq a[k] dummy }
239 variant { if i >= s then Array.length a - i + s else s - i}
240 ensures { 0 <= result < Array.length a }
241 ensures { result <> s }
242 ensures { eq a[result] dummy }
243 ensures { forall k: int. 0 <= k < Array.length a ->
244 between s k result -> k<>s -> neq a[k] dummy }
246 let n = Array.length a in
247 if eq a[i] dummy then i else find_dummy a s (next n i)
249 (* j is the hole just created by remove (see below) and this function
250 restores the data structure invariant for elements
251 to the right of j if needed, starting at index i *)
252 let rec delete (a: array key)
253 (ghost loc: ref (map keym int)) (ghost view: map keym bool)
254 (ghost f0: int) (j i: int) : unit
255 requires { 0 <= f0 < Array.length a }
256 requires { 0 <= j < Array.length a }
257 requires { 0 <= i < Array.length a }
259 requires { eq a[j] dummy }
260 requires { eq a[f0] dummy }
261 requires { between j i f0 }
262 requires { forall k: int. 0 <= k < Array.length a ->
263 between i k f0 -> k<>i -> neq a[k] dummy }
264 requires { not (Map.get view dummym) }
265 requires { forall k: int. 0 <= k < Array.length a ->
266 let x = a[k] in neq x dummy ->
267 Map.get view (keym x) /\ Map.get !loc (keym x) = k }
268 (* any value in the model is in the array *)
269 requires { let n = Array.length a in
270 forall x: key. Map.get view (keym x) ->
271 let k = Map.get !loc (keym x) in
272 0 <= k < n && eq a[k] x &&
273 forall l: int. 0 <= l < n -> between (bucket x n) l k ->
276 l = j /\ between j i k) }
277 variant { if i >= f0 then Array.length a - i + f0 else f0 - i }
278 ensures { numofd a 0 (Array.length a) =
279 numofd (old a) 0 (Array.length a) }
280 ensures { valid a view !loc }
282 let n = Array.length a in
285 if neq xi dummy then begin
286 let r = bucket xi n in
287 if j < r && r <= i || i < j && j < r || r <= i && i < j then
288 (* the hash index r lies cyclically between j and i *)
289 delete a loc view f0 j i
291 let ghost a1 = Array.copy a in
292 ghost NumOfDummy.numof_eq a a1 0 n;
293 (* the hole j lies cyclically between hash index r and i *)
295 ghost numof_update a1 a 0 j n;
296 let ghost a2 = Array.copy a in
297 ghost NumOfDummy.numof_eq a a2 0 n;
298 ghost loc := Map.set !loc (keym xi) j;
300 ghost numof_update a a2 0 i n;
301 delete a loc view f0 i i
305 let remove (h: t) (x: key) : unit
306 requires { neq x dummy }
307 ensures { h.view = Map.set (old h.view) (keym x) False }
309 let n = Array.length h.data in
310 let j = find h.data x in
311 if neq h.data[j] dummy then begin
314 assert { numofd h.data 0 (j+1) =
315 numofd (h.data at L) 0 (j+1) + 1 };
316 ghost (h.view <- Map.set h.view (keym x) False);
318 let f0 = find_dummy h.data j (next n j) in
319 delete h.data l h.view f0 j j;
321 h.size <- h.size - 1;