Hash maps #
THIS FILE IS SYNCHRONIZED WITH MATHLIB4. Any changes to this file require a corresponding PR to mathlib4.
Defines a hash map data structure, representing a finite key-value map
with a value type that may depend on the key type. The structure
requires a nat
-valued hash function to associate keys to buckets.
Main definitions #
hash_map
: constructed withmk_hash_map
.
Implementation details #
A hash map with key type α
and (dependent) value type β : α → Type*
consists of an array of buckets, which are lists containing
key/value pairs for that bucket. The hash function is taken modulo n
to assign keys to their respective bucket. Because of this, some care
should be put into the hash function to ensure it evenly distributes
keys.
The bucket array is an array
. These have special VM support for
in-place modification if there is only ever one reference to them. If
one takes special care to never keep references to old versions of a
hash map alive after updating it, then the hash map will be modified
in-place. In this documentation, when we say a hash map is modified
in-place, we are assuming the API is being used in this manner.
When inserting (hash_map.insert
), if the number of stored pairs (the
size) is going to exceed the number of buckets, then a new hash map
is first created with double the number of buckets and everything in
the old hash map is reinserted along with the new key/value pair.
Otherwise, the bucket array is modified in-place. The amortized
running time of inserting $$n$$ elements into a hash map is $$O(n)$$.
When removing (hash_map.erase
), the hash map is modified in-place.
The implementation does not reduce the number of buckets in the hash
map if the size gets too low.
Tags #
hash map
bucket_array α β
is the underlying data type for hash_map α β
,
an array of linked lists of key-value pairs.
Instances for bucket_array
Read the bucket corresponding to an element
Equations
- bucket_array.read hash_fn data a = let bidx : fin ↑n := hash_map.mk_idx n (hash_fn a) in array.read data bidx
Write the bucket corresponding to an element
Equations
- bucket_array.write hash_fn data a l = let bidx : fin ↑n := hash_map.mk_idx n (hash_fn a) in array.write data bidx l
Modify (read, apply f
, and write) the bucket corresponding to an element
Equations
- bucket_array.modify hash_fn data a f = let bidx : fin ↑n := hash_map.mk_idx n (hash_fn a) in array.write data bidx (f (array.read data bidx))
The list of all key-value pairs in the bucket list
Equations
- data.as_list = (array.to_list data).join
Fold a function f
over the key-value pairs in the bucket list
Insert the pair ⟨a, b⟩
into the correct location in the bucket array
(without checking for duplication)
Equations
- hash_map.reinsert_aux hash_fn data a b = bucket_array.modify hash_fn data a (λ (l : list (Σ (a : α), β a)), ⟨a, b⟩ :: l)
Search a bucket for a key a
and return the value
Equations
- hash_map.find_aux a (⟨a', b⟩ :: t) = dite (a' = a) (λ (h : a' = a), option.some (h.rec_on b)) (λ (h : ¬a' = a), hash_map.find_aux a t)
- hash_map.find_aux a list.nil = option.none
Returns tt
if the bucket l
contains the key a
Equations
- hash_map.contains_aux a l = (hash_map.find_aux a l).is_some
Modify a bucket to replace a value in the list. Leaves the list unchanged if the key is not found.
Equations
- hash_map.replace_aux a b (⟨a', b'⟩ :: t) = ite (a' = a) (⟨a, b⟩ :: t) (⟨a', b'⟩ :: hash_map.replace_aux a b t)
- hash_map.replace_aux a b list.nil = list.nil
Modify a bucket to remove a key, if it exists.
Equations
- hash_map.erase_aux a (⟨a', b'⟩ :: t) = ite (a' = a) t (⟨a', b'⟩ :: hash_map.erase_aux a t)
- hash_map.erase_aux a list.nil = list.nil
- len : bkts.as_list.length = sz
- idx : ∀ {i : fin ↑n} {a : Σ (a : α), β a}, a ∈ array.read bkts i → hash_map.mk_idx n (hash_fn a.fst) = i
- nodup : ∀ (i : fin ↑n), (list.map sigma.fst (array.read bkts i)).nodup
The predicate valid bkts sz
means that bkts
satisfies the hash_map
invariants: There are exactly sz
elements in it, every pair is in the
bucket determined by its key and the hash function, and no key appears
multiple times in the list.
- hash_fn : α → ℕ
- size : ℕ
- nbuckets : ℕ+
- buckets : bucket_array α β self.nbuckets
- is_valid : hash_map.valid self.hash_fn self.buckets self.size
A hash map data structure, representing a finite key-value map
with key type α
and value type β
(which may depend on α
).
Instances for hash_map
- hash_map.has_sizeof_inst
- hash_map.has_mem
- hash_map.has_to_string
- hash_map.has_to_format
- hash_map.inhabited
Construct an empty hash map with buffer size nbuckets
(default 8).
Return the value corresponding to a key, or none
if not found
Equations
- m.find a = hash_map.find_aux a (bucket_array.read m.hash_fn m.buckets a)
Insert a key-value pair into the map. (Modifies m
in-place when applicable)
Equations
- {hash_fn := hash_fn, size := size, nbuckets := n, buckets := buckets, is_valid := v}.insert a b = let bkt : list (Σ (a : α), β a) := bucket_array.read hash_fn buckets a in dite ↥(hash_map.contains_aux a bkt) (λ (hc : ↥(hash_map.contains_aux a bkt)), {hash_fn := hash_fn, size := size, nbuckets := n, buckets := bucket_array.modify hash_fn buckets a (hash_map.replace_aux a b), is_valid := _}) (λ (hc : ¬↥(hash_map.contains_aux a bkt)), let size' : ℕ := size + 1, buckets' : bucket_array α β n := bucket_array.modify hash_fn buckets a (λ (l : list (Σ (a : α), β a)), ⟨a, b⟩ :: l), valid' : hash_map.valid hash_fn (hash_map.reinsert_aux hash_fn buckets a b) (size + 1) := _ in ite (size' ≤ ↑n) {hash_fn := hash_fn, size := size', nbuckets := n, buckets := buckets', is_valid := valid'} (let n' : ℕ+ := ⟨↑n * 2, _⟩, buckets'' : bucket_array α β n' := buckets'.foldl (mk_array ↑n' list.nil) (hash_map.reinsert_aux hash_fn) in {hash_fn := hash_fn, size := size', nbuckets := n', buckets := buckets'', is_valid := _}))
Insert a list of key-value pairs into the map. (Modifies m
in-place when applicable)
Equations
- hash_map.insert_all l m = list.foldl (λ (m : hash_map α β) (_x : Σ (a : α), β a), hash_map.insert_all._match_1 m _x) m l
- hash_map.insert_all._match_1 m ⟨a, b⟩ = m.insert a b
Construct a hash map from a list of key-value pairs.
Equations
- hash_map.of_list l hash_fn = hash_map.insert_all l (mk_hash_map hash_fn (2 * l.length))
Remove a key from the map. (Modifies m
in-place when applicable)
Equations
- m.erase a = hash_map.erase._match_1 m a m
- hash_map.erase._match_1 m a {hash_fn := hash_fn, size := size, nbuckets := n, buckets := buckets, is_valid := v} = dite ↥(hash_map.contains_aux a (bucket_array.read hash_fn buckets a)) (λ (hc : ↥(hash_map.contains_aux a (bucket_array.read hash_fn buckets a))), {hash_fn := hash_fn, size := size - 1, nbuckets := n, buckets := bucket_array.modify hash_fn buckets a (hash_map.erase_aux a), is_valid := _}) (λ (hc : ¬↥(hash_map.contains_aux a (bucket_array.read hash_fn buckets a))), m)
Equations
- hash_map.has_to_string = {to_string := to_string (λ (a : α), _inst_3 a)}