#![allow(unused_imports)]
use super::pervasive::*;
use super::prelude::*;
use super::set::*;
verus! {
#[verifier::ext_equal]
#[verifier::reject_recursive_types(K)]
#[verifier::accept_recursive_types(V)]
pub tracked struct Map<K, V> {
mapping: spec_fn(K) -> Option<V>,
}
impl<K, V> Map<K, V> {
pub closed spec fn empty() -> Map<K, V> {
Map { mapping: |k| None }
}
pub open spec fn total(fv: spec_fn(K) -> V) -> Map<K, V> {
Set::full().mk_map(fv)
}
pub open spec fn new(fk: spec_fn(K) -> bool, fv: spec_fn(K) -> V) -> Map<K, V> {
Set::new(fk).mk_map(fv)
}
pub closed spec fn dom(self) -> Set<K> {
Set::new(|k| (self.mapping)(k) is Some)
}
pub closed spec fn index(self, key: K) -> V
recommends
self.dom().contains(key),
{
(self.mapping)(key)->Some_0
}
#[verifier::inline]
pub open spec fn spec_index(self, key: K) -> V
recommends
self.dom().contains(key),
{
self.index(key)
}
pub closed spec fn insert(self, key: K, value: V) -> Map<K, V> {
Map {
mapping: |k|
if k == key {
Some(value)
} else {
(self.mapping)(k)
},
}
}
pub closed spec fn remove(self, key: K) -> Map<K, V> {
Map {
mapping: |k|
if k == key {
None
} else {
(self.mapping)(k)
},
}
}
pub open spec fn len(self) -> nat {
self.dom().len()
}
pub axiom fn tracked_empty() -> (tracked out_v: Self)
ensures
out_v == Map::<K, V>::empty(),
;
pub axiom fn tracked_insert(tracked &mut self, key: K, tracked value: V)
ensures
*self == Map::insert(*old(self), key, value),
;
pub axiom fn tracked_remove(tracked &mut self, key: K) -> (tracked v: V)
requires
old(self).dom().contains(key),
ensures
*self == Map::remove(*old(self), key),
v == old(self)[key],
;
pub axiom fn tracked_borrow(tracked &self, key: K) -> (tracked v: &V)
requires
self.dom().contains(key),
ensures
*v === self.index(key),
;
pub axiom fn tracked_map_keys<J>(
tracked old_map: Map<K, V>,
key_map: Map<J, K>,
) -> (tracked new_map: Map<J, V>)
requires
forall|j|
#![auto]
key_map.dom().contains(j) ==> old_map.dom().contains(key_map.index(j)),
forall|j1, j2|
#![auto]
!equal(j1, j2) && key_map.dom().contains(j1) && key_map.dom().contains(j2)
==> !equal(key_map.index(j1), key_map.index(j2)),
ensures
forall|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)),
;
pub axiom fn tracked_remove_keys(tracked &mut self, keys: Set<K>) -> (tracked out_map: Map<
K,
V,
>)
requires
keys.subset_of(old(self).dom()),
ensures
self == old(self).remove_keys(keys),
out_map == old(self).restrict(keys),
;
pub axiom fn tracked_union_prefer_right(tracked &mut self, right: Self)
ensures
*self == old(self).union_prefer_right(right),
;
}
pub broadcast axiom fn axiom_map_index_decreases_finite<K, V>(m: Map<K, V>, key: K)
requires
m.dom().finite(),
m.dom().contains(key),
ensures
#[trigger] (decreases_to!(m => m[key])),
;
pub broadcast axiom fn axiom_map_index_decreases_infinite<K, V>(m: Map<K, V>, key: K)
requires
m.dom().contains(key),
ensures
#[trigger] is_smaller_than_recursive_function_field(m[key], m),
;
pub broadcast proof fn axiom_map_empty<K, V>()
ensures
#[trigger] Map::<K, V>::empty().dom() == Set::<K>::empty(),
{
broadcast use super::set::group_set_axioms;
assert(Set::new(|k: K| (|k| None::<V>)(k) is Some) == Set::<K>::empty());
}
pub broadcast proof fn axiom_map_insert_domain<K, V>(m: Map<K, V>, key: K, value: V)
ensures
#[trigger] m.insert(key, value).dom() == m.dom().insert(key),
{
broadcast use super::set::group_set_axioms;
assert(m.insert(key, value).dom() =~= m.dom().insert(key));
}
pub broadcast proof fn axiom_map_insert_same<K, V>(m: Map<K, V>, key: K, value: V)
ensures
#[trigger] m.insert(key, value)[key] == value,
{
}
pub broadcast proof fn axiom_map_insert_different<K, V>(m: Map<K, V>, key1: K, key2: K, value: V)
requires
key1 != key2,
ensures
#[trigger] m.insert(key2, value)[key1] == m[key1],
{
}
pub broadcast proof fn axiom_map_remove_domain<K, V>(m: Map<K, V>, key: K)
ensures
#[trigger] m.remove(key).dom() == m.dom().remove(key),
{
broadcast use super::set::group_set_axioms;
assert(m.remove(key).dom() =~= m.dom().remove(key));
}
pub broadcast proof fn axiom_map_remove_different<K, V>(m: Map<K, V>, key1: K, key2: K)
requires
key1 != key2,
ensures
#[trigger] m.remove(key2)[key1] == m[key1],
{
}
pub broadcast proof fn axiom_map_ext_equal<K, V>(m1: Map<K, V>, m2: Map<K, V>)
ensures
#[trigger] (m1 =~= m2) <==> {
&&& m1.dom() =~= m2.dom()
&&& forall|k: K| #![auto] m1.dom().contains(k) ==> m1[k] == m2[k]
},
{
broadcast use super::set::group_set_axioms;
if m1 =~= m2 {
assert(m1.dom() =~= m2.dom());
assert(forall|k: K| #![auto] m1.dom().contains(k) ==> m1[k] == m2[k]);
}
if ({
&&& m1.dom() =~= m2.dom()
&&& forall|k: K| #![auto] m1.dom().contains(k) ==> m1[k] == m2[k]
}) {
if m1.mapping != m2.mapping {
assert(exists|k| #[trigger] (m1.mapping)(k) != (m2.mapping)(k));
let k = choose|k| #[trigger] (m1.mapping)(k) != (m2.mapping)(k);
if m1.dom().contains(k) {
assert(m1[k] == m2[k]);
}
assert(false);
}
assert(m1 =~= m2);
}
}
pub broadcast proof fn axiom_map_ext_equal_deep<K, V>(m1: Map<K, V>, m2: Map<K, V>)
ensures
#[trigger] (m1 =~~= m2) <==> {
&&& m1.dom() =~~= m2.dom()
&&& forall|k: K| #![auto] m1.dom().contains(k) ==> m1[k] =~~= m2[k]
},
{
axiom_map_ext_equal(m1, m2);
}
pub broadcast group group_map_axioms {
axiom_map_index_decreases_finite,
axiom_map_index_decreases_infinite,
axiom_map_empty,
axiom_map_insert_domain,
axiom_map_insert_same,
axiom_map_insert_different,
axiom_map_remove_domain,
axiom_map_remove_different,
axiom_map_ext_equal,
axiom_map_ext_equal_deep,
}
#[doc(hidden)]
#[macro_export]
macro_rules! map_internal {
[$($key:expr => $value:expr),* $(,)?] => {
$crate::vstd::map::Map::empty()
$(.insert($key, $value))*
}
}
#[macro_export]
macro_rules! map {
[$($tail:tt)*] => {
$crate::vstd::prelude::verus_proof_macro_exprs!($crate::vstd::map::map_internal!($($tail)*))
};
}
#[doc(hidden)]
#[verifier::inline]
pub open spec fn check_argument_is_map<K, V>(m: Map<K, V>) -> Map<K, V> {
m
}
#[doc(hidden)]
pub use map_internal;
pub use map;
#[macro_export]
macro_rules! assert_maps_equal {
[$($tail:tt)*] => {
$crate::vstd::prelude::verus_proof_macro_exprs!($crate::vstd::map::assert_maps_equal_internal!($($tail)*))
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! assert_maps_equal_internal {
(::verus_builtin::spec_eq($m1:expr, $m2:expr)) => {
assert_maps_equal_internal!($m1, $m2)
};
(::verus_builtin::spec_eq($m1:expr, $m2:expr), $k:ident $( : $t:ty )? => $bblock:block) => {
assert_maps_equal_internal!($m1, $m2, $k $( : $t )? => $bblock)
};
($m1:expr, $m2:expr $(,)?) => {
assert_maps_equal_internal!($m1, $m2, key => { })
};
($m1:expr, $m2:expr, $k:ident $( : $t:ty )? => $bblock:block) => {
#[verifier::spec] let m1 = $crate::vstd::map::check_argument_is_map($m1);
#[verifier::spec] let m2 = $crate::vstd::map::check_argument_is_map($m2);
$crate::vstd::prelude::assert_by($crate::vstd::prelude::equal(m1, m2), {
$crate::vstd::prelude::assert_forall_by(|$k $( : $t )?| {
$crate::vstd::prelude::ensures([
$crate::vstd::prelude::imply(#[verifier::trigger] m1.dom().contains($k), m2.dom().contains($k))
&& $crate::vstd::prelude::imply(m2.dom().contains($k), m1.dom().contains($k))
&& $crate::vstd::prelude::imply(m1.dom().contains($k) && m2.dom().contains($k),
$crate::vstd::prelude::equal(m1.index($k), m2.index($k)))
]);
{ $bblock }
});
$crate::vstd::prelude::assert_($crate::vstd::prelude::ext_equal(m1, m2));
});
}
}
#[doc(hidden)]
pub use assert_maps_equal_internal;
pub use assert_maps_equal;
impl<K, V> Map<K, V> {
pub proof fn tracked_map_keys_in_place(
#[verifier::proof]
&mut self,
key_map: Map<K, K>,
)
requires
forall|j|
#![auto]
key_map.dom().contains(j) ==> old(self).dom().contains(key_map.index(j)),
forall|j1, j2|
#![auto]
j1 != j2 && key_map.dom().contains(j1) && key_map.dom().contains(j2)
==> key_map.index(j1) != key_map.index(j2),
ensures
forall|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)),
{
#[verifier::proof]
let mut tmp = Self::tracked_empty();
super::modes::tracked_swap(&mut tmp, self);
#[verifier::proof]
let mut tmp = Self::tracked_map_keys(tmp, key_map);
super::modes::tracked_swap(&mut tmp, self);
}
}
}