1use vstd::prelude::*;
3use vstd::relations::*;
4
5verus! {
6
7pub open spec fn bijective_on<A, B>(f: spec_fn(A) -> B, domain: Set<A>, codomain: Set<B>) -> bool {
10 injective_on(f, domain) && domain.map(f) =~= codomain
11}
12
13pub open spec fn left_inverse_on<A, B>(
16 f: spec_fn(A) -> B,
17 g: spec_fn(B) -> A,
18 domain: Set<A>,
19 codomain: Set<B>,
20) -> bool {
21 domain.all(|x: A| codomain.contains(f(x)) && g(f(x)) == x)
22}
23
24pub open spec fn right_inverse_on<A, B>(
27 f: spec_fn(A) -> B,
28 g: spec_fn(B) -> A,
29 domain: Set<A>,
30 codomain: Set<B>,
31) -> bool {
32 codomain.all(|y: B| domain.contains(g(y)) && f(g(y)) == y)
33}
34
35pub open spec fn inverse_on<A, B>(
37 f: spec_fn(A) -> B,
38 g: spec_fn(B) -> A,
39 domain: Set<A>,
40 codomain: Set<B>,
41) -> bool {
42 left_inverse_on(f, g, domain, codomain) && right_inverse_on(f, g, domain, codomain)
43}
44
45pub open spec fn construct_left_inverse<A, B>(f: spec_fn(A) -> B, domain: Set<A>) -> spec_fn(B) -> A
48 recommends
49 injective_on(f, domain),
50{
51 |b: B| choose|a: A| domain.contains(a) && f(a) == b
52}
53
54pub open spec fn construct_inverse<A, B>(
57 f: spec_fn(A) -> B,
58 domain: Set<A>,
59 codomain: Set<B>,
60) -> spec_fn(B) -> A
61 recommends
62 bijective_on(f, domain, codomain),
63{
64 |b: B| choose|a: A| domain.contains(a) && f(a) == b
65}
66
67pub proof fn lemma_construct_left_inverse_sound<A, B>(f: spec_fn(A) -> B, domain: Set<A>)
71 requires
72 injective_on(f, domain),
73 ensures
74 left_inverse_on(f, construct_left_inverse(f, domain), domain, domain.map(f)),
75{
76}
77
78pub proof fn lemma_construct_inverse_sound<A, B>(
82 f: spec_fn(A) -> B,
83 domain: Set<A>,
84 codomain: Set<B>,
85)
86 requires
87 bijective_on(f, domain, codomain),
88 ensures
89 inverse_on(f, construct_inverse(f, domain, codomain), domain, codomain),
90{
91}
92
93pub proof fn lemma_injective_implies_injective_on<T, U>(f: spec_fn(T) -> U, dom: Set<T>)
95 requires
96 injective(f),
97 ensures
98 injective_on(f, dom),
99{
100}
101
102pub proof fn lemma_two_sided_inverse_implies_bijective<A, B>(
104 f: spec_fn(A) -> B,
105 g: spec_fn(B) -> A,
106 domain: Set<A>,
107 codomain: Set<B>,
108)
109 requires
110 inverse_on(f, g, domain, codomain),
111 ensures
112 bijective_on(f, domain, codomain),
113{
114}
115
116pub proof fn lemma_left_inverse_of_bijection_is_bijective<A, B>(
119 f: spec_fn(A) -> B,
120 g: spec_fn(B) -> A,
121 domain: Set<A>,
122 codomain: Set<B>,
123)
124 requires
125 bijective_on(f, domain, codomain),
126 left_inverse_on(f, g, domain, codomain),
127 ensures
128 bijective_on(g, codomain, domain),
129{
130}
131
132pub proof fn lemma_right_inverse_of_bijection_is_bijective<A, B>(
135 f: spec_fn(A) -> B,
136 g: spec_fn(B) -> A,
137 domain: Set<A>,
138 codomain: Set<B>,
139)
140 requires
141 bijective_on(f, domain, codomain),
142 right_inverse_on(f, g, domain, codomain),
143 ensures
144 bijective_on(g, codomain, domain),
145{
146 assert forall|x| #[trigger] codomain.map(g).contains(x) == domain.contains(x) by {
148 if domain.contains(x) {
149 assert(codomain.contains(f(x)));
150 }
151 }
152}
153
154pub proof fn lemma_inverse_of_bijection_is_bijective<A, B>(
157 f: spec_fn(A) -> B,
158 g: spec_fn(B) -> A,
159 domain: Set<A>,
160 codomain: Set<B>,
161)
162 requires
163 bijective_on(f, domain, codomain),
164 left_inverse_on(f, g, domain, codomain) || right_inverse_on(f, g, domain, codomain),
165 ensures
166 bijective_on(g, codomain, domain),
167{
168 if left_inverse_on(f, g, domain, codomain) {
169 lemma_left_inverse_of_bijection_is_bijective(f, g, domain, codomain);
170 } else {
171 lemma_right_inverse_of_bijection_is_bijective(f, g, domain, codomain);
172 }
173}
174
175pub proof fn lemma_injective_map_cardinality<T, U>(f: spec_fn(T) -> U, dom: Set<T>, s: Set<T>)
177 requires
178 injective_on(f, dom),
179 s.finite(),
180 s <= dom,
181 ensures
182 s.len() == s.map(f).len(),
183 s.map(f).finite(),
184 decreases s.len(),
185{
186 if s.is_empty() {
187 assert(s.map(f) =~= Set::empty());
188 } else {
189 let x = s.choose();
190 lemma_injective_map_cardinality(f, dom, s.remove(x));
191 assert(s.map(f) =~= s.remove(x).map(f).insert(f(x)));
192 }
193}
194
195pub proof fn lemma_bijective_cardinality<A, B>(f: spec_fn(A) -> B, domain: Set<A>, codomain: Set<B>)
196 requires
197 bijective_on(f, domain, codomain),
198 domain.finite(),
199 ensures
200 codomain.finite(),
201 domain.len() == codomain.len(),
202{
203 lemma_injective_map_cardinality(f, domain, domain);
204}
205
206pub proof fn lemma_bijective_subset_still_bijective<A, B>(
207 f: spec_fn(A) -> B,
208 domain: Set<A>,
209 codomain: Set<B>,
210 s: Set<A>,
211)
212 requires
213 bijective_on(f, domain, codomain),
214 s <= domain,
215 ensures
216 bijective_on(f, s, s.map(f)),
217{
218}
219
220}