Skip to main content

vstd/
imap_lib.rs

1#[macro_use]
2use super::imap::{IMap, assert_imaps_equal, assert_imaps_equal_internal};
3#[cfg(verus_keep_ghost)]
4use super::iset::*;
5#[cfg(verus_keep_ghost)]
6use super::iset_lib::*;
7#[allow(unused_imports)]
8use super::pervasive::*;
9#[allow(unused_imports)]
10use super::prelude::*;
11#[allow(unused_imports)]
12use super::relations::*;
13
14verus! {
15
16broadcast use {super::imap::group_imap_lemmas, super::iset::group_iset_lemmas};
17
18impl<K, V> IMap<K, V> {
19    /// Is `true` if called by a "full" map, i.e., a map containing every element of type `A`.
20    #[verifier::inline]
21    pub open spec fn is_full(self) -> bool {
22        self.dom().is_full()
23    }
24
25    /// Is `true` if called by an "empty" map, i.e., a map containing no elements and has length 0
26    #[verifier::inline]
27    pub open spec fn is_empty(self) -> (b: bool) {
28        self.dom().is_empty()
29    }
30
31    /// Returns true if the key `k` is in the domain of `self`.
32    #[verifier::inline]
33    pub open spec fn contains_key(self, k: K) -> bool {
34        self.dom().contains(k)
35    }
36
37    /// Returns true if the value `v` is in the range of `self`.
38    pub open spec fn contains_value(self, v: V) -> bool {
39        exists|i: K| #[trigger] self.dom().contains(i) && self[i] == v
40    }
41
42    /// Returns `Some(v)` if the key `k` is in the domain of `self` and maps to `v`,
43    /// and `None` if the key `k` is not in the domain of `self`.
44    pub open spec fn index_opt(self, k: K) -> Option<V> {
45        if self.contains_key(k) {
46            Some(self[k])
47        } else {
48            None
49        }
50    }
51
52    ///
53    /// Returns the set of values in the map.
54    ///
55    /// ## Example
56    ///
57    /// ```rust
58    /// let m: IMap<int, int> = imap![1 => 10, 2 => 11];
59    /// assert(m.values() == iset![10int, 11int]) by {
60    ///     assert(m.contains_key(1));
61    ///     assert(m.contains_key(2));
62    ///     assert(m.values() =~= iset![10int, 11int]);
63    /// }
64    /// ```
65    pub open spec fn values(self) -> ISet<V> {
66        ISet::<V>::new(|v: V| self.contains_value(v))
67    }
68
69    ///
70    /// Returns the set of key-value pairs representing the map
71    ///
72    /// ## Example
73    ///
74    /// ```rust
75    /// let m: IMap<int, int> = imap![1 => 10, 2 => 11];
76    /// assert(m.kv_pairs() == iset![(1int, 10int), (2int, 11int)] by {
77    ///     assert(m.contains_pair(1int, 10int));
78    ///     assert(m.contains_pair(2int, 11int));
79    ///     assert(m.kv_pairs() =~= iset![(1int, 10int), (2int, 11int)]);
80    /// }
81    /// ```
82    pub open spec fn kv_pairs(self) -> ISet<(K, V)> {
83        ISet::<(K, V)>::new(|kv: (K, V)| self.dom().contains(kv.0) && self[kv.0] == kv.1)
84    }
85
86    /// Returns true if the key `k` is in the domain of `self`, and it maps to the value `v`.
87    pub open spec fn contains_pair(self, k: K, v: V) -> bool {
88        // We use the implication below to make sure that the solver tries to prove
89        // `self.dom().contains(k)` first. That fact is sometimes necessary to trigger
90        // a quantifier helpful in proving `self[k] == v`.
91        &&& self.dom().contains(k)
92        &&& self.dom().contains(k) ==> self[k] == v
93    }
94
95    /// Returns true if `m1` is _contained in_ `m2`, i.e., the domain of `m1` is a subset
96    /// of the domain of `m2`, and they agree on all values in `m1`.
97    ///
98    /// ## Example
99    ///
100    /// ```rust
101    /// assert(
102    ///    imap![1 => 10, 2 => 11].le(imap![1 => 10, 2 => 11, 3 => 12])
103    /// );
104    /// ```
105    pub open spec fn submap_of(self, m2: Self) -> bool {
106        forall|k: K| #[trigger]
107            self.dom().contains(k) ==> #[trigger] m2.dom().contains(k) && self[k] == m2[k]
108    }
109
110    #[verifier::inline]
111    pub open spec fn spec_le(self, m2: Self) -> bool {
112        self.submap_of(m2)
113    }
114
115    /// Gives the union of two maps, defined as:
116    ///  * The domain is the union of the two input maps.
117    ///  * For a given key in _both_ input maps, it maps to the same value that it maps to in the _right_ map (`m2`).
118    ///  * For any other key in either input map (but not both), it maps to the same value
119    ///    as it does in that map.
120    ///
121    /// ## Example
122    ///
123    /// ```rust
124    /// assert(
125    ///    map![1 => 10, 2 => 11].union_prefer_right(map![1 => 20, 3 => 13])
126    ///    =~= map![1 => 20, 2 => 11, 3 => 13]);
127    /// ```
128    pub open spec fn union_prefer_right(self, m2: Self) -> Self {
129        Self::new(
130            |k: K| self.dom().contains(k) || m2.dom().contains(k),
131            |k: K|
132                if m2.dom().contains(k) {
133                    m2[k]
134                } else {
135                    self[k]
136                },
137        )
138    }
139
140    /// Removes the given keys and their associated values from the map.
141    ///
142    /// Ignores any key in `keys` which is not in the domain of `self`.
143    ///
144    /// ## Example
145    ///
146    /// ```rust
147    /// assert(
148    ///    imap![1 => 10, 2 => 11, 3 => 12].remove_keys(iset!{2, 3, 4})
149    ///    =~= imap![1 => 10]);
150    /// ```
151    pub open spec fn remove_keys(self, keys: ISet<K>) -> Self {
152        Self::new(|k: K| self.dom().contains(k) && !keys.contains(k), |k: K| self[k])
153    }
154
155    /// Complement to `remove_keys`. Restricts the map to (key, value) pairs
156    /// for keys that are _in_ the given set; that is, it removes any keys
157    /// _not_ in the set.
158    ///
159    /// ## Example
160    ///
161    /// ```rust
162    /// assert(
163    ///    map![1 => 10, 2 => 11, 3 => 12].remove_keys(set!{2, 3, 4})
164    ///    =~= map![2 => 11, 3 => 12]);
165    /// ```
166    pub open spec fn restrict(self, keys: ISet<K>) -> Self {
167        Self::new(|k: K| self.dom().contains(k) && keys.contains(k), |k: K| self[k])
168    }
169
170    /// Returns `true` if and only if the given key maps to the same value or does not exist in self and m2.
171    pub open spec fn is_equal_on_key(self, m2: Self, key: K) -> bool {
172        ||| (!self.dom().contains(key) && !m2.dom().contains(key))
173        ||| (self.dom().contains(key) && m2.dom().contains(key) && self[key] == m2[key])
174    }
175
176    /// Returns `true` if the two given maps agree on all keys that their domains share
177    pub open spec fn agrees(self, m2: Self) -> bool {
178        forall|k| #![auto] self.dom().contains(k) && m2.dom().contains(k) ==> self[k] == m2[k]
179    }
180
181    /// Map a function `f` over all (k, v) pairs in `self`.
182    pub open spec fn map_entries<W>(self, f: spec_fn(K, V) -> W) -> IMap<K, W> {
183        IMap::new(|k: K| self.contains_key(k), |k: K| f(k, self[k]))
184    }
185
186    /// Map a function `f` over the values in `self`.
187    pub open spec fn map_values<W>(self, f: spec_fn(V) -> W) -> IMap<K, W> {
188        IMap::new(|k: K| self.contains_key(k), |k: K| f(self[k]))
189    }
190
191    /// Returns `true` if and only if a map is injective
192    pub open spec fn is_injective(self) -> bool {
193        forall|x: K, y: K|
194            x != y && self.dom().contains(x) && self.dom().contains(y) ==> #[trigger] self[x]
195                != #[trigger] self[y]
196    }
197
198    /// Swaps map keys and values. Values are not required to be unique; no
199    /// promises on which key is chosen on the intersection.
200    pub open spec fn invert(self) -> IMap<V, K> {
201        IMap::<V, K>::new(
202            |v: V| self.contains_value(v),
203            |v: V| choose|k: K| self.contains_pair(k, v),
204        )
205    }
206
207    // Proven lemmas
208    /// Removing a key from a map that previously contained that key decreases
209    /// the map's length by one
210    pub proof fn lemma_remove_key_len(self, key: K)
211        requires
212            self.dom().contains(key),
213            self.dom().finite(),
214        ensures
215            self.dom().len() == 1 + self.remove(key).dom().len(),
216    {
217    }
218
219    /// The domain of a map after removing a key is equivalent to removing the key from
220    /// the domain of the original map.
221    pub proof fn lemma_remove_equivalency(self, key: K)
222        ensures
223            self.remove(key).dom() == self.dom().remove(key),
224    {
225    }
226
227    /// Removing a set of n keys from a map that previously contained all n keys
228    /// results in a domain of size n less than the original domain.
229    pub proof fn lemma_remove_keys_len(self, keys: ISet<K>)
230        requires
231            forall|k: K| #[trigger] keys.contains(k) ==> self.contains_key(k),
232            keys.finite(),
233            self.dom().finite(),
234        ensures
235            self.remove_keys(keys).dom().len() == self.dom().len() - keys.len(),
236        decreases keys.len(),
237    {
238        broadcast use group_iset_properties;
239
240        if keys.len() > 0 {
241            let key = keys.choose();
242            let val = self[key];
243            self.remove(key).lemma_remove_keys_len(keys.remove(key));
244            assert(self.remove(key).remove_keys(keys.remove(key)) =~= self.remove_keys(keys));
245        } else {
246            assert(self.remove_keys(keys) =~= self);
247        }
248    }
249
250    /// The function `invert` results in an injective map
251    pub proof fn lemma_invert_is_injective(self)
252        ensures
253            self.invert().is_injective(),
254    {
255        assert forall|x: V, y: V|
256            x != y && self.invert().dom().contains(x) && self.invert().dom().contains(
257                y,
258            ) implies #[trigger] self.invert()[x] != #[trigger] self.invert()[y] by {
259            let i = choose|i: K| #[trigger] self.dom().contains(i) && self[i] == x;
260            assert(self.contains_pair(i, x));
261            let j = choose|j: K| self.contains_pair(j, x) && self.invert()[x] == j;
262            let k = choose|k: K| #[trigger] self.dom().contains(k) && self[k] == y;
263            assert(self.contains_pair(k, y));
264            let l = choose|l: K| self.contains_pair(l, y) && self.invert()[y] == l && l != j;
265        }
266    }
267
268    /// Keeps only those key-value pairs whose key satisfies `p`.
269    ///
270    /// ## Example
271    /// ```rust
272    /// proof fn example() {
273    ///     let m = imap![1 => 10, 2 => 20];
274    ///     let even = |k: int| k % 2 == 0;
275    ///     assert(m.filter_keys(even) =~= imap![2 => 20]);
276    /// }
277    /// ```
278    pub open spec fn filter_keys(self, p: spec_fn(K) -> bool) -> Self {
279        self.restrict(self.dom().filter(p))
280    }
281
282    /// Returns the value associated with key `k` in the map if it exists,
283    /// otherwise returns None.
284    ///
285    /// ## Example
286    /// ```rust
287    /// proof fn get_test() {
288    ///     let m: IMap<int, bool> = imap![
289    ///         1 => true,
290    ///         2 => false
291    ///     ];
292    ///
293    ///     assert(m.get(1) == Some(true));
294    ///     assert(m.get(3) == None);
295    /// }
296    /// ```
297    pub open spec fn get(self, k: K) -> Option<V> {
298        if self.dom().contains(k) {
299            Some(self[k])
300        } else {
301            None
302        }
303    }
304
305    /// A map contains a value satisfying predicate `p` iff some key maps to a value satisfying `p`.
306    ///
307    /// ## Example
308    /// ```rust
309    /// proof fn get_dom_value_any_test() {
310    ///     let m = imap![1 => 10, 2 => 20, 3 => 30];
311    ///     let p = |v: int| v > 25;
312    ///     assert(m[3] == 30);
313    ///     assert(m.dom().any(|k| p(m[k])));
314    /// }
315    /// ```
316    pub proof fn get_dom_value_any(self, p: spec_fn(V) -> bool)
317        ensures
318            self.dom().any(|k: K| p(self[k])) <==> self.values().any(p),
319    {
320        broadcast use group_imap_properties;
321
322        if self.dom().any(|k: K| p(self[k])) {
323            let k = choose|k: K| self.dom().contains(k) && #[trigger] p(self[k]);
324            assert(self.values().contains(self[k]));
325            assert(self.values().any(p));
326        }
327    }
328
329    /// Two maps are equal if and only if they are submaps of each other.
330    ///
331    /// ## Example
332    /// ```rust
333    /// proof fn submap_eq_test() {
334    ///     let m1 = imap![1 => 10, 2 => 20];
335    ///     let m2 = imap![1 => 10, 2 => 20];
336    ///     let m3 = imap![1 => 10, 2 => 30];
337    ///
338    ///     assert(m1.submap_of(m2) && m2.submap_of(m1));
339    ///     assert(m1 == m2);
340    /// }
341    /// ```
342    pub proof fn lemma_submap_eq_iff(self, m: Self)
343        ensures
344            (self == m) <==> (self.submap_of(m) && m.submap_of(self)),
345    {
346        broadcast use group_imap_properties;
347
348        if self.submap_of(m) && m.submap_of(self) {
349            assert(self.dom() == m.dom());
350            assert(self == m);
351        }
352    }
353
354    /// When removing a set of keys from a map after inserting (k,v),
355    /// the result depends on whether k is in the set:
356    /// if k is in the set, the insertion is discarded;
357    /// if not, the insertion happens after removal.
358    ///
359    /// ## Example
360    /// ```rust
361    /// proof fn map_remove_keys_insert_test() {
362    ///     let m = imap![1 => 10, 2 => 20, 3 => 30];
363    ///     let to_remove = set![2, 4];
364    ///
365    ///     // 5 not in m: insert happens after remove
366    ///     assert(m.insert(5, 15).remove_keys(to_remove) == m.remove_keys(to_remove).insert(5, 15));
367    ///
368    ///     // 2 in m: insert is eliminated by remove
369    ///     assert(m.insert(2, 25).remove_keys(to_remove) == m.remove_keys(to_remove));
370    /// }
371    /// ```
372    pub broadcast proof fn lemma_imap_remove_keys_insert(self, r: ISet<K>, k: K, v: V)
373        ensures
374            #[trigger] self.insert(k, v).remove_keys(r) == if r.contains(k) {
375                self.remove_keys(r)
376            } else {
377                self.remove_keys(r).insert(k, v)
378            },
379    {
380        broadcast use group_imap_properties;
381
382        let lhs = self.insert(k, v).remove_keys(r);
383        let rhs = if r.contains(k) {
384            self.remove_keys(r)
385        } else {
386            self.remove_keys(r).insert(k, v)
387        };
388        assert(lhs == rhs);
389    }
390
391    /// Filtering keys after inserting `(k, v)` leaves the result unchanged when `p(k)` is false,
392    /// and otherwise adds `(k, v)` to the already-filtered map.
393    ///
394    /// ## Example
395    /// ```rust
396    /// proof fn example() {
397    ///     let m = imap![1 => 10];
398    ///     let even = |k: int| k % 2 == 0;
399    ///
400    ///     assert(m.insert(3, 30).filter_keys(even) =~= m.filter_keys(even));
401    ///     assert(m.insert(2, 20).filter_keys(even)
402    ///            =~= m.filter_keys(even).insert(2, 20));
403    /// }
404    /// ```
405    pub broadcast proof fn lemma_filter_keys_insert(self, p: spec_fn(K) -> bool, k: K, v: V)
406        ensures
407            #[trigger] self.insert(k, v).filter_keys(p) == (if p(k) {
408                self.filter_keys(p).insert(k, v)
409            } else {
410                self.filter_keys(p)
411            }),
412    {
413        broadcast use group_imap_properties;
414
415        let lhs = self.insert(k, v).filter_keys(p);
416        let rhs = if p(k) {
417            self.filter_keys(p).insert(k, v)
418        } else {
419            self.filter_keys(p)
420        };
421        assert(lhs == rhs);
422    }
423
424    /// Inserting a value in a map means it contains the value that was inserted.
425    ///
426    /// ## Example
427    /// ```rust
428    /// proof fn example() {
429    ///     let a = imap![1int => 2int];
430    ///     assert(a.contains_value(2));
431    /// }
432    /// ```
433    pub broadcast proof fn lemma_insert_contains_value(self, k: K, v: V)
434        ensures
435            #[trigger] self.insert(k, v).contains_value(v),
436    {
437        assert(self.insert(k, v).contains_key(k));
438    }
439
440    /// Inserting a value in a map where that key is already present ensures
441    /// The contains value sees (only) the updated value;
442    ///
443    /// ## Example
444    /// ```rust
445    /// proof fn example() {
446    ///     let a = imap![1int => 2int].insert(1int, 3int);
447    ///     assert(!a.contains_value(2));
448    ///     assert(a.contains_value(3));
449    /// }
450    /// ```
451    pub broadcast proof fn lemma_insert_invariant_contains(self, old_v: V, k: K, v: V)
452        requires
453            self.contains_key(k) ==> self[k] != old_v,
454            old_v != v,
455        ensures
456            #[trigger] self.insert(k, v).contains_value(old_v) == self.contains_value(old_v),
457    {
458        if self.contains_value(old_v) {
459            let old_k = choose|key: K| #[trigger] self.dom().contains(key) && self[key] == old_v;
460            assert(self.insert(k, v).contains_key(old_k));
461        }
462    }
463
464    pub proof fn lemma_injective_values_len(self)
465        requires
466            self.dom().finite(),
467            self.is_injective(),
468        ensures
469            self.values().finite(),
470            self.values().len() == self.dom().len(),
471    {
472        let f = |k: K|
473            if self.contains_key(k) {
474                self[k]
475            } else {
476                ISet::<V>::full().difference(self.values()).choose()
477            };
478        assert(forall|a1: K, a2: K|
479            self.dom().contains(a1) && self.dom().contains(a2) && #[trigger] f(a1) == #[trigger] f(
480                a2,
481            ) ==> a1 == a2);
482        assert(self.dom().map(f) == self.values());
483        super::iset_lib::lemma_map_size(self.dom(), self.values(), f);
484    }
485
486    pub proof fn lemma_values_len(self)
487        requires
488            self.dom().finite(),
489        ensures
490            self.values().finite(),
491            self.values().len() <= self.dom().len(),
492    {
493        let f = |k: K|
494            if self.contains_key(k) {
495                self[k]
496            } else {
497                ISet::<V>::full().difference(self.values()).choose()
498            };
499        assert(self.dom().map(f) == self.values());
500        super::iset_lib::lemma_map_size_bound(self.dom(), self.values(), f);
501    }
502}
503
504impl<K, V> IMap<Seq<K>, V> {
505    /// Returns a sub-map of all entries whose key begins with `prefix`,
506    /// re-indexed so that the stored keys have that prefix removed.
507    ///
508    /// ## Example
509    /// ```rust
510    /// proof fn example() {
511    ///     let m = imap![seq![1, 2] => 10, seq![1, 2, 3] => 20, seq![2] => 30];
512    ///     let sub = m.prefixed_entries(seq![1, 2]);
513    ///
514    ///     assert(sub.contains_key(seq![]));          // original key [1,2]
515    ///     assert(sub[seq![]] == 10);
516    ///
517    ///     assert(sub.contains_key(seq![3]));         // original key [1,2,3]
518    ///     assert(sub[seq![3]] == 20);
519    ///
520    ///     assert(!sub.contains_key(seq![2]));        // original key [2] was not prefixed
521    /// }
522    /// ```
523    pub open spec fn prefixed_entries(self, prefix: Seq<K>) -> Self {
524        IMap::new(|k: Seq<K>| self.contains_key(prefix + k), |k: Seq<K>| self[prefix + k])
525    }
526
527    /// For every key `k` kept by `prefixed_entries(prefix)`,
528    /// the associated value is the one stored at `prefix + k` in the original map.
529    ///
530    /// ## Example
531    /// ```rust
532    /// proof fn example() {
533    ///     let m = imap![seq![1, 2] => 10, seq![1, 2, 3] => 20];
534    ///     let p = seq![1, 2];
535    ///
536    ///     // key inside the sub-map
537    ///     assert(m.prefixed_entries(p)[seq![]] == m[p + seq![]]);      // 10
538    ///     assert(m.prefixed_entries(p)[seq![3]] == m[p + seq![3]]);    // 20
539    /// }
540    /// ```
541    pub broadcast proof fn lemma_prefixed_entries_get(self, prefix: Seq<K>, k: Seq<K>)
542        requires
543            self.prefixed_entries(prefix).contains_key(k),
544        ensures
545            self.prefixed_entries(prefix)[k] == #[trigger] self[prefix + k],
546    {
547        broadcast use group_imap_properties;
548
549    }
550
551    /// A key `k` is in `prefixed_entries(prefix)` exactly when the original map
552    /// contains the key `prefix + k`.
553    ///
554    /// ## Example
555    /// ```rust
556    /// proof fn example() {
557    ///     let m = imap![seq![1, 2] => 10, seq![1, 2, 3] => 20];
558    ///     let p = seq![1, 2];
559    ///
560    ///     assert(m.prefixed_entries(p).contains_key(seq![])
561    ///            <==> m.contains_key(p + seq![]));
562    ///
563    ///     assert(m.prefixed_entries(p).contains_key(seq![3])
564    ///            <==> m.contains_key(p + seq![3]));
565    ///
566    ///     assert(!m.prefixed_entries(p).contains_key(seq![2]));
567    /// }
568    /// ```
569    pub broadcast proof fn lemma_prefixed_entries_contains(self, prefix: Seq<K>, k: Seq<K>)
570        ensures
571            #[trigger] self.prefixed_entries(prefix).contains_key(k) <==> self.contains_key(
572                prefix + k,
573            ),
574    {
575        broadcast use group_imap_properties;
576
577        let lhs = self.prefixed_entries(prefix);
578        let rhs = self;
579    }
580
581    /// Inserting `(prefix + k, v)` before taking `prefixed_entries(prefix)`
582    /// has the same effect as inserting `(k, v)` into the prefixed map.
583    ///
584    /// ## Example
585    /// ```rust
586    /// proof fn example() {
587    ///     let m = imap![seq![1, 2] => 10];
588    ///     let p = seq![1, 2];
589    ///
590    ///     let left  = m.insert(p + seq![3], 20).prefixed_entries(p);
591    ///     let right = m.prefixed_entries(p).insert(seq![3], 20);
592    ///
593    ///     assert(left == right);
594    /// }
595    /// ```
596    pub broadcast proof fn lemma_prefixed_entries_insert(self, prefix: Seq<K>, k: Seq<K>, v: V)
597        ensures
598            #[trigger] self.insert(prefix + k, v).prefixed_entries(prefix) == self.prefixed_entries(
599                prefix,
600            ).insert(k, v),
601    {
602        broadcast use group_imap_properties;
603        broadcast use super::seq::group_seq_axioms;
604        broadcast use super::seq_lib::group_seq_properties, super::seq_lib::lemma_seq_skip_of_skip;
605        broadcast use Map::lemma_prefixed_entries_contains, Map::lemma_prefixed_entries_get;
606
607        let lhs = self.insert(prefix + k, v).prefixed_entries(prefix);
608        let rhs = self.prefixed_entries(prefix).insert(k, v);
609        assert(lhs =~= rhs) by {
610            assert(forall|key| key != k ==> prefix.is_prefix_of(#[trigger] (prefix + key)));
611        }
612    }
613
614    /// Taking the entries that share `prefix` commutes with `union_prefer_right`:
615    /// union the two maps first and then strip the prefix, or strip the prefix from
616    /// each map and then union them—the resulting maps are identical.
617    ///
618    /// ## Example
619    /// ```rust
620    /// proof fn example() {
621    ///     let a = imap![seq![1, 2] => 10, seq![2, 3] => 20];
622    ///     let b = imap![seq![1, 2] => 99, seq![2, 4] => 40];
623    ///     let p = seq![2];
624    ///
625    ///     assert(
626    ///         a.union_prefer_right(b).prefixed_entries(p)
627    ///         == a.prefixed_entries(p).union_prefer_right(b.prefixed_entries(p))
628    ///     );
629    /// }
630    /// ```
631    pub broadcast proof fn lemma_prefixed_entries_union(self, m: Self, prefix: Seq<K>)
632        ensures
633            #[trigger] self.union_prefer_right(m).prefixed_entries(prefix) == self.prefixed_entries(
634                prefix,
635            ).union_prefer_right(m.prefixed_entries(prefix)),
636    {
637        broadcast use group_imap_properties;
638        broadcast use
639            IMap::lemma_prefixed_entries_contains,
640            IMap::lemma_prefixed_entries_get,
641            IMap::lemma_prefixed_entries_insert,
642        ;
643
644        let lhs = self.union_prefer_right(m).prefixed_entries(prefix);
645        let rhs = self.prefixed_entries(prefix).union_prefer_right(m.prefixed_entries(prefix));
646        assert(lhs == rhs);
647    }
648}
649
650impl IMap<int, int> {
651    /// Returns `true` if a map is monotonic -- that is, if the mapping between ordered sets
652    /// preserves the regular `<=` ordering on integers.
653    pub open spec fn is_monotonic(self) -> bool {
654        forall|x: int, y: int|
655            self.dom().contains(x) && self.dom().contains(y) && x <= y ==> #[trigger] self[x]
656                <= #[trigger] self[y]
657    }
658
659    /// Returns `true` if and only if a map is monotonic, only considering keys greater than
660    /// or equal to start
661    pub open spec fn is_monotonic_from(self, start: int) -> bool {
662        forall|x: int, y: int|
663            self.dom().contains(x) && self.dom().contains(y) && start <= x <= y
664                ==> #[trigger] self[x] <= #[trigger] self[y]
665    }
666}
667
668// Proven lemmas
669pub broadcast proof fn lemma_union_insert_left<K, V>(m1: IMap<K, V>, m2: IMap<K, V>, k: K, v: V)
670    requires
671        !m2.contains_key(k),
672    ensures
673        #[trigger] m1.insert(k, v).union_prefer_right(m2) == m1.union_prefer_right(m2).insert(k, v),
674{
675    assert(m1.insert(k, v).union_prefer_right(m2) =~= m1.union_prefer_right(m2).insert(k, v));
676}
677
678pub broadcast proof fn lemma_union_insert_right<K, V>(m1: IMap<K, V>, m2: IMap<K, V>, k: K, v: V)
679    ensures
680        #[trigger] m1.union_prefer_right(m2.insert(k, v)) == m1.union_prefer_right(m2).insert(k, v),
681{
682    assert(m1.union_prefer_right(m2.insert(k, v)) =~= m1.union_prefer_right(m2).insert(k, v));
683}
684
685pub broadcast proof fn lemma_union_remove_left<K, V>(m1: IMap<K, V>, m2: IMap<K, V>, k: K)
686    requires
687        m1.contains_key(k),
688        !m2.contains_key(k),
689    ensures
690        #[trigger] m1.union_prefer_right(m2).remove(k) == m1.remove(k).union_prefer_right(m2),
691{
692    assert(m1.remove(k).union_prefer_right(m2) =~= m1.union_prefer_right(m2).remove(k));
693}
694
695pub broadcast proof fn lemma_union_remove_right<K, V>(m1: IMap<K, V>, m2: IMap<K, V>, k: K)
696    requires
697        !m1.contains_key(k),
698        m2.contains_key(k),
699    ensures
700        #[trigger] m1.union_prefer_right(m2).remove(k) == m1.union_prefer_right(m2.remove(k)),
701{
702    assert(m1.union_prefer_right(m2.remove(k)) =~= m1.union_prefer_right(m2).remove(k));
703}
704
705pub broadcast proof fn lemma_union_dom<K, V>(m1: IMap<K, V>, m2: IMap<K, V>)
706    ensures
707        #[trigger] m1.union_prefer_right(m2).dom() == m1.dom().union(m2.dom()),
708{
709    assert(m1.dom().union(m2.dom()) =~= m1.union_prefer_right(m2).dom());
710}
711
712/// The size of the union of two disjoint maps is equal to the sum of the sizes of the individual maps
713pub broadcast proof fn lemma_disjoint_union_size<K, V>(m1: IMap<K, V>, m2: IMap<K, V>)
714    requires
715        m1.dom().disjoint(m2.dom()),
716        m1.dom().finite(),
717        m2.dom().finite(),
718    ensures
719        #[trigger] m1.union_prefer_right(m2).dom().len() == m1.dom().len() + m2.dom().len(),
720{
721    let u = m1.union_prefer_right(m2);
722    assert(u.dom() =~= m1.dom() + m2.dom());  //proves u.dom() is finite
723    assert(u.remove_keys(m1.dom()).dom() =~= m2.dom());
724    assert(u.remove_keys(m1.dom()).dom().len() == u.dom().len() - m1.dom().len()) by {
725        u.lemma_remove_keys_len(m1.dom());
726    }
727}
728
729pub broadcast group group_imap_union {
730    lemma_union_dom,
731    lemma_union_remove_left,
732    lemma_union_remove_right,
733    lemma_union_insert_left,
734    lemma_union_insert_right,
735    lemma_disjoint_union_size,
736}
737
738/// submap_of (<=) is transitive.
739pub broadcast proof fn lemma_submap_of_trans<K, V>(m1: IMap<K, V>, m2: IMap<K, V>, m3: IMap<K, V>)
740    requires
741        #[trigger] m1.submap_of(m2),
742        #[trigger] m2.submap_of(m3),
743    ensures
744        m1.submap_of(m3),
745{
746    assert forall|k| m1.dom().contains(k) implies #[trigger] m3.dom().contains(k) && m1[k]
747        == m3[k] by {
748        assert(m2.dom().contains(k));
749    }
750}
751
752// This verified lemma used to be an axiom in the Dafny prelude
753/// The domain of a map constructed with `IMap::new(fk, fv)` is equivalent to the set constructed with `ISet::new(fk)`.
754pub broadcast proof fn lemma_imap_new_domain<K, V>(fk: spec_fn(K) -> bool, fv: spec_fn(K) -> V)
755    ensures
756        #[trigger] IMap::<K, V>::new(fk, fv).dom() == ISet::<K>::new(|k: K| fk(k)),
757{
758    assert(ISet::new(fk) =~= ISet::<K>::new(|k: K| fk(k)));
759}
760
761// This verified lemma used to be an axiom in the Dafny prelude
762/// The set of values of a map constructed with `IMap::new(fk, fv)` is equivalent to
763/// the set constructed with `ISet::new(|v: V| (exists |k: K| fk(k) && fv(k) == v)`. In other words,
764/// the set of all values fv(k) where fk(k) is true.
765pub broadcast proof fn lemma_imap_new_values<K, V>(fk: spec_fn(K) -> bool, fv: spec_fn(K) -> V)
766    ensures
767        #[trigger] IMap::<K, V>::new(fk, fv).values() == ISet::<V>::new(
768            |v: V| (exists|k: K| #[trigger] fk(k) && #[trigger] fv(k) == v),
769        ),
770{
771    let keys = ISet::<K>::new(fk);
772    let values = IMap::<K, V>::new(fk, fv).values();
773    let map = IMap::<K, V>::new(fk, fv);
774    assert(map.dom() =~= keys);
775    assert(forall|k: K| #[trigger] fk(k) ==> keys.contains(k));
776    assert(values =~= ISet::<V>::new(
777        |v: V| (exists|k: K| #[trigger] fk(k) && #[trigger] fv(k) == v),
778    ));
779}
780
781pub broadcast group group_imap_properties {
782    lemma_imap_new_domain,
783    lemma_imap_new_values,
784}
785
786pub broadcast group group_imap_extra {
787    IMap::lemma_imap_remove_keys_insert,
788    IMap::lemma_filter_keys_insert,
789    IMap::lemma_insert_contains_value,
790    IMap::lemma_insert_invariant_contains,
791    IMap::lemma_prefixed_entries_get,
792    IMap::lemma_prefixed_entries_contains,
793    IMap::lemma_prefixed_entries_insert,
794    IMap::lemma_prefixed_entries_union,
795}
796
797pub proof fn lemma_values_finite<K, V>(m: IMap<K, V>)
798    requires
799        m.dom().finite(),
800    ensures
801        m.values().finite(),
802    decreases m.len(),
803{
804    if m.len() > 0 {
805        let k = m.dom().choose();
806        let v = m[k];
807        let m1 = m.remove(k);
808        assert(m.contains_key(k));
809        assert(m.contains_value(v));
810        let mv = m.values();
811        let m1v = m1.values();
812        assert_isets_equal!(mv == m1v.insert(v), v0 => {
813            if m.contains_value(v0) {
814                if v0 != v {
815                    let k0 = choose|k0| #![auto] m.contains_key(k0) && m[k0] == v0;
816                    assert(k0 != k);
817                    assert(m1.contains_key(k0));
818                    assert(mv.contains(v0) ==> m1v.insert(v).contains(v0));
819                    assert(mv.contains(v0) <== m1v.insert(v).contains(v0));
820                }
821            }
822        });
823        assert(m1.len() < m.len());
824        lemma_values_finite(m1);
825        lemma_iset_insert_finite(m1.values(), v);
826    } else {
827        assert(m.values() =~= ISet::<V>::empty());
828    }
829}
830
831} // verus!