pub struct Map<K, V> { /* private fields */ }
Expand description
Map<K, V>
is an abstract map type for specifications.
To use a “map” in compiled code, use an exec
type like HashMap (TODO)
that has a Map<K, V>
as its specification type.
An object map: Map<K, V>
has a domain, a set of keys given by map.dom()
,
and a mapping for keys in the domain to values, given by map[key]
.
Alternatively, a map can be thought of as a set of (K, V)
pairs where each key
appears in at most entry.
In general, a map might be infinite.
To work specifically with finite maps, see the self.finite()
predicate.
Maps can be constructed in a few different ways:
Map::empty()
constructs an empty map.Map::new
andMap::total
construct a map given functions that specify its domain and the mapping from keys to values (a map comprehension).- The
map!
macro, to construct small maps of a fixed size. - By manipulating an existing map with
Map::insert
orMap::remove
.
To prove that two maps are equal, it is usually easiest to use the extensionality operator =~=
.
Implementations§
source§impl<K, V> Map<K, V>
impl<K, V> Map<K, V>
sourcepub open spec fn total(fv: impl Fn(K) -> V) -> Map<K, V>
pub open spec fn total(fv: impl Fn(K) -> V) -> Map<K, V>
{ Set::full().mk_map(fv) }
Gives a Map<K, V>
whose domain contains every key, and maps each key
to the value given by fv
.
sourcepub open spec fn new(fk: impl Fn(K) -> bool, fv: impl Fn(K) -> V) -> Map<K, V>
pub open spec fn new(fk: impl Fn(K) -> bool, fv: impl Fn(K) -> V) -> Map<K, V>
{ Set::new(fk).mk_map(fv) }
Gives a Map<K, V>
whose domain is given by the boolean predicate on keys fk
,
and maps each key to the value given by fv
.
sourcepub spec fn index(self, key: K) -> V
pub spec fn index(self, key: K) -> V
self.dom().contains(key),
Gets the value that the given key key
maps to.
For keys not in the domain, the result is meaningless and arbitrary.
sourcepub open spec fn spec_index(self, key: K) -> V
pub open spec fn spec_index(self, key: K) -> V
self.dom().contains(key),
{ self.index(key) }
[]
operator, synonymous with index
sourcepub spec fn insert(self, key: K, value: V) -> Map<K, V>
pub spec fn insert(self, key: K, value: V) -> Map<K, V>
Inserts the given (key, value) pair into the map.
If the key is already present from the map, then its existing value is overwritten by the new value.
sourcepub spec fn remove(self, key: K) -> Map<K, V>
pub spec fn remove(self, key: K) -> Map<K, V>
Removes the given key and its associated value from the map.
If the key is already absent from the map, then the map is left unchanged.
sourcepub open spec fn len(self) -> nat
pub open spec fn len(self) -> nat
{ self.dom().len() }
Returns the number of key-value pairs in the map
sourcepub open spec fn ext_equal(self, m2: Map<K, V>) -> bool
👎Deprecated: use =~= or =~~= instead
pub open spec fn ext_equal(self, m2: Map<K, V>) -> bool
{ self =~= m2 }
DEPRECATED: use =~= or =~~= instead.
Returns true if the two maps are pointwise equal, i.e.,
they have the same domains and the corresponding values are equal
for each key. This is equivalent to the maps being actually equal
by axiom_map_ext_equal
.
To prove that two maps are equal via extensionality, it may be easier
to use the general-purpose =~=
or =~~=
or
to use the assert_maps_equal!
macro, rather than using .ext_equal
directly.
sourcepub proof fn tracked_empty() -> tracked out_v : Self
pub proof fn tracked_empty() -> tracked out_v : Self
out_v == Map::<K, V>::empty(),
sourcepub proof fn tracked_insert(tracked &mut self, key: K, tracked value: V)
pub proof fn tracked_insert(tracked &mut self, key: K, tracked value: V)
*self == Map::insert(*old(self), key, value),
sourcepub proof fn tracked_remove(tracked &mut self, key: K) -> tracked v : V
pub proof fn tracked_remove(tracked &mut self, key: K) -> tracked v : V
old(self).dom().contains(key),
ensures*self == Map::remove(*old(self), key),
v == old(self)[key],
todo fill in documentation
sourcepub proof fn tracked_borrow(tracked &self, key: K) -> tracked v : &V
pub proof fn tracked_borrow(tracked &self, key: K) -> tracked v : &V
self.dom().contains(key),
ensures*v === self.index(key),
sourcepub proof fn tracked_map_keys<J>(tracked old_map: Map<K, V>, key_map: Map<J, K>) -> tracked new_map : Map<J, V>
pub proof fn tracked_map_keys<J>(tracked old_map: Map<K, V>, key_map: Map<J, K>) -> tracked new_map : Map<J, V>
forall |j| key_map.dom().contains(j) ==> old_map.dom().contains(key_map.index(j)),
forall |j1, j2| {
!equal(j1, j2) && key_map.dom().contains(j1) && key_map.dom().contains(j2)
==> !equal(key_map.index(j1), key_map.index(j2))
},
ensuresforall |j| #[trigger] new_map.dom().contains(j) <==> key_map.dom().contains(j),
forall |j| {
key_map.dom().contains(j)
==> new_map.dom().contains(j)
&& #[trigger] new_map.index(j) == old_map.index(key_map.index(j))
},
sourcepub proof fn tracked_remove_keys(tracked &mut self, keys: Set<K>) -> tracked out_map : Map<K, V>
pub proof fn tracked_remove_keys(tracked &mut self, keys: Set<K>) -> tracked out_map : Map<K, V>
keys.subset_of(old(self).dom()),
ensuresself == old(self).remove_keys(keys),
out_map == old(self).restrict(keys),
sourcepub proof fn tracked_union_prefer_right(tracked &mut self, right: Self)
pub proof fn tracked_union_prefer_right(tracked &mut self, right: Self)
*self == old(self).union_prefer_right(right),
source§impl<K, V> Map<K, V>
impl<K, V> Map<K, V>
sourcepub proof fn tracked_map_keys_in_place(&mut self, key_map: Map<K, K>)
pub proof fn tracked_map_keys_in_place(&mut self, key_map: Map<K, K>)
forall |j| key_map.dom().contains(j) ==> old(self).dom().contains(key_map.index(j)),
forall |j1, j2| {
j1 != j2 && key_map.dom().contains(j1) && key_map.dom().contains(j2)
==> key_map.index(j1) != key_map.index(j2)
},
ensuresforall |j| #[trigger] self.dom().contains(j) == key_map.dom().contains(j),
forall |j| {
key_map.dom().contains(j)
==> self.dom().contains(j)
&& #[trigger] self.index(j) == old(self).index(key_map.index(j))
},
source§impl<K, V> Map<K, V>
impl<K, V> Map<K, V>
sourcepub open spec fn is_full(self) -> bool
pub open spec fn is_full(self) -> bool
{ self.dom().is_full() }
Is true
if called by a “full” map, i.e., a map containing every element of type A
.
sourcepub open spec fn is_empty(self) -> b : bool
pub open spec fn is_empty(self) -> b : bool
{ self.dom().is_empty() }
Is true
if called by an “empty” map, i.e., a map containing no elements and has length 0
sourcepub open spec fn contains_key(self, k: K) -> bool
pub open spec fn contains_key(self, k: K) -> bool
{ self.dom().contains(k) }
Returns true if the key k
is in the domain of self
.
sourcepub open spec fn contains_value(self, v: V) -> bool
pub open spec fn contains_value(self, v: V) -> bool
{ exists |i: K| #[trigger] self.dom().contains(i) && self[i] == v }
Returns true if the value v
is in the range of self
.
sourcepub open spec fn values(self) -> Set<V>
pub open spec fn values(self) -> Set<V>
{ Set::<V>::new(|v: V| self.contains_value(v)) }
Returns the set of values in the map.
§Example
assert(
map![1 => 10, 2 => 11].values() =~= set![10, 11]
);
sourcepub open spec fn contains_pair(self, k: K, v: V) -> bool
pub open spec fn contains_pair(self, k: K, v: V) -> bool
{ self.dom().contains(k) && self[k] == v }
Returns true if the key k
is in the domain of self
, and it maps to the value v
.
sourcepub open spec fn submap_of(self, m2: Self) -> bool
pub open spec fn submap_of(self, m2: Self) -> bool
{
forall |k: K| {
#[trigger] self.dom().contains(k)
==> #[trigger] m2.dom().contains(k) && self[k] == m2[k]
}
}
Returns true if m1
is contained in m2
, i.e., the domain of m1
is a subset
of the domain of m2
, and they agree on all values in m1
.
§Example
assert(
map![1 => 10, 2 => 11].le(map![1 => 10, 2 => 11, 3 => 12])
);
sourcepub open spec fn le(self, m2: Self) -> bool
👎Deprecated: use m1.submap_of(m2) or m1 <= m2 instead
pub open spec fn le(self, m2: Self) -> bool
{ self.submap_of(m2) }
Deprecated synonym for submap_of
sourcepub open spec fn union_prefer_right(self, m2: Self) -> Self
pub open spec fn union_prefer_right(self, m2: Self) -> Self
{
Self::new(
|k: K| self.dom().contains(k) || m2.dom().contains(k),
|k: K| if m2.dom().contains(k) { m2[k] } else { self[k] },
)
}
Gives the union of two maps, defined as:
- The domain is the union of the two input maps.
- For a given key in both input maps, it maps to the same value that it maps to in the right map (
m2
). - For any other key in either input map (but not both), it maps to the same value as it does in that map.
§Example
assert(
map![1 => 10, 2 => 11].union_prefer_right(map![1 => 20, 3 => 13])
=~= map![1 => 20, 2 => 11, 3 => 13]);
sourcepub open spec fn remove_keys(self, keys: Set<K>) -> Self
pub open spec fn remove_keys(self, keys: Set<K>) -> Self
{ Self::new(|k: K| self.dom().contains(k) && !keys.contains(k), |k: K| self[k]) }
Removes the given keys and their associated values from the map.
Ignores any key in keys
which is not in the domain of self
.
§Example
assert(
map![1 => 10, 2 => 11, 3 => 12].remove_keys(set!{2, 3, 4})
=~= map![1 => 10]);
sourcepub open spec fn restrict(self, keys: Set<K>) -> Self
pub open spec fn restrict(self, keys: Set<K>) -> Self
{ Self::new(|k: K| self.dom().contains(k) && keys.contains(k), |k: K| self[k]) }
Complement to remove_keys
. Restricts the map to (key, value) pairs
for keys that are in the given set; that is, it removes any keys
not in the set.
§Example
assert(
map![1 => 10, 2 => 11, 3 => 12].remove_keys(set!{2, 3, 4})
=~= map![2 => 11, 3 => 12]);
sourcepub open spec fn is_equal_on_key(self, m2: Self, key: K) -> bool
pub open spec fn is_equal_on_key(self, m2: Self, key: K) -> bool
{
||| (!self.dom().contains(key) && !m2.dom().contains(key))
||| (self.dom().contains(key) && m2.dom().contains(key) && self[key] == m2[key])
}
Returns true
if and only if the given key maps to the same value or does not exist in self and m2.
sourcepub open spec fn agrees(self, m2: Self) -> bool
pub open spec fn agrees(self, m2: Self) -> bool
{ forall |k| self.dom().contains(k) && m2.dom().contains(k) ==> self[k] == m2[k] }
Returns true
if the two given maps agree on all keys that their domains share
sourcepub open spec fn map_entries<W>(self, f: FnSpec<(K, V), W>) -> Map<K, W>
pub open spec fn map_entries<W>(self, f: FnSpec<(K, V), W>) -> Map<K, W>
{ Map::new(|k: K| self.contains_key(k), |k: K| f(k, self[k])) }
Map a function f
over all (k, v) pairs in self
.
sourcepub open spec fn map_values<W>(self, f: FnSpec<(V,), W>) -> Map<K, W>
pub open spec fn map_values<W>(self, f: FnSpec<(V,), W>) -> Map<K, W>
{ Map::new(|k: K| self.contains_key(k), |k: K| f(self[k])) }
Map a function f
over the values in self
.
sourcepub open spec fn is_injective(self) -> bool
pub open spec fn is_injective(self) -> bool
{
forall |x: K, y: K| {
x != y && self.dom().contains(x) && self.dom().contains(y)
==> #[trigger] self[x] != #[trigger] self[y]
}
}
Returns true
if and only if a map is injective
sourcepub open spec fn invert(self) -> Map<V, K>
pub open spec fn invert(self) -> Map<V, K>
{
Map::<
V,
K,
>::new(|v: V| self.contains_value(v), |v: V| choose |k: K| self.contains_pair(k, v))
}
Swaps map keys and values. Values are not required to be unique; no promises on which key is chosen on the intersection.
sourcepub proof fn lemma_remove_key_len(self, key: K)
pub proof fn lemma_remove_key_len(self, key: K)
self.dom().contains(key),
self.dom().finite(),
ensuresself.dom().len() == 1 + self.remove(key).dom().len(),
Removing a key from a map that previously contained that key decreases the map’s length by one
sourcepub proof fn lemma_remove_equivalency(self, key: K)
pub proof fn lemma_remove_equivalency(self, key: K)
self.remove(key).dom() == self.dom().remove(key),
The domain of a map after removing a key is equivalent to removing the key from the domain of the original map.
sourcepub proof fn lemma_remove_keys_len(self, keys: Set<K>)
pub proof fn lemma_remove_keys_len(self, keys: Set<K>)
forall |k: K| #[trigger] keys.contains(k) ==> self.contains_key(k),
keys.finite(),
self.dom().finite(),
ensuresself.remove_keys(keys).dom().len() == self.dom().len() - keys.len(),
Removing a set of n keys from a map that previously contained all n keys results in a domain of size n less than the original domain.
sourcepub proof fn lemma_invert_is_injective(self)
pub proof fn lemma_invert_is_injective(self)
self.invert().is_injective(),
The function invert
results in an injective map
source§impl Map<int, int>
impl Map<int, int>
sourcepub open spec fn is_monotonic(self) -> bool
pub open spec fn is_monotonic(self) -> bool
{
forall |x: int, y: int| {
self.dom().contains(x) && self.dom().contains(y) && x <= y
==> #[trigger] self[x] <= #[trigger] self[y]
}
}
Returns true
if a map is monotonic – that is, if the mapping between ordered sets
preserves the regular <=
ordering on integers.
sourcepub open spec fn is_monotonic_from(self, start: int) -> bool
pub open spec fn is_monotonic_from(self, start: int) -> bool
{
forall |x: int, y: int| {
self.dom().contains(x) && self.dom().contains(y) && start <= x <= y
==> #[trigger] self[x] <= #[trigger] self[y]
}
}
Returns true
if and only if a map is monotonic, only considering keys greater than
or equal to start