1use vstd::prelude::*;
3use vstd::relations::*;
4use vstd::set_lib::*;
5
6verus! {
7
8pub open spec fn bijective_on<A, B>(f: spec_fn(A) -> B, domain: Set<A>, codomain: Set<B>) -> bool {
11 domain.injective_on(f) && domain.map(f) =~= codomain
12}
13
14pub open spec fn left_inverse_on<A, B>(
17 f: spec_fn(A) -> B,
18 g: spec_fn(B) -> A,
19 domain: Set<A>,
20 codomain: Set<B>,
21) -> bool {
22 domain.all(|x: A| codomain.contains(f(x)) && g(f(x)) == x)
23}
24
25pub open spec fn right_inverse_on<A, B>(
28 f: spec_fn(A) -> B,
29 g: spec_fn(B) -> A,
30 domain: Set<A>,
31 codomain: Set<B>,
32) -> bool {
33 codomain.all(|y: B| domain.contains(g(y)) && f(g(y)) == y)
34}
35
36pub open spec fn inverse_on<A, B>(
38 f: spec_fn(A) -> B,
39 g: spec_fn(B) -> A,
40 domain: Set<A>,
41 codomain: Set<B>,
42) -> bool {
43 left_inverse_on(f, g, domain, codomain) && right_inverse_on(f, g, domain, codomain)
44}
45
46pub open spec fn construct_left_inverse<A, B>(f: spec_fn(A) -> B, domain: Set<A>) -> spec_fn(B) -> A
49 recommends
50 domain.injective_on(f),
51{
52 |b: B| choose|a: A| domain.contains(a) && f(a) == b
53}
54
55pub open spec fn construct_inverse<A, B>(
58 f: spec_fn(A) -> B,
59 domain: Set<A>,
60 codomain: Set<B>,
61) -> spec_fn(B) -> A
62 recommends
63 bijective_on(f, domain, codomain),
64{
65 |b: B| choose|a: A| domain.contains(a) && f(a) == b
66}
67
68pub proof fn lemma_construct_left_inverse_sound<A, B>(f: spec_fn(A) -> B, domain: Set<A>)
72 requires
73 domain.injective_on(f),
74 ensures
75 left_inverse_on(f, construct_left_inverse(f, domain), domain, domain.map(f)),
76{
77}
78
79pub proof fn lemma_construct_inverse_sound<A, B>(
83 f: spec_fn(A) -> B,
84 domain: Set<A>,
85 codomain: Set<B>,
86)
87 requires
88 bijective_on(f, domain, codomain),
89 ensures
90 inverse_on(f, construct_inverse(f, domain, codomain), domain, codomain),
91{
92}
93
94pub proof fn lemma_injective_implies_injective_on<T, U>(f: spec_fn(T) -> U, dom: Set<T>)
96 requires
97 injective(f),
98 ensures
99 dom.injective_on(f),
100{
101}
102
103pub proof fn lemma_two_sided_inverse_implies_bijective<A, B>(
105 f: spec_fn(A) -> B,
106 g: spec_fn(B) -> A,
107 domain: Set<A>,
108 codomain: Set<B>,
109)
110 requires
111 inverse_on(f, g, domain, codomain),
112 ensures
113 bijective_on(f, domain, codomain),
114{
115}
116
117pub proof fn lemma_left_inverse_of_bijection_is_bijective<A, B>(
120 f: spec_fn(A) -> B,
121 g: spec_fn(B) -> A,
122 domain: Set<A>,
123 codomain: Set<B>,
124)
125 requires
126 bijective_on(f, domain, codomain),
127 left_inverse_on(f, g, domain, codomain),
128 ensures
129 bijective_on(g, codomain, domain),
130{
131}
132
133pub proof fn lemma_right_inverse_of_bijection_is_bijective<A, B>(
136 f: spec_fn(A) -> B,
137 g: spec_fn(B) -> A,
138 domain: Set<A>,
139 codomain: Set<B>,
140)
141 requires
142 bijective_on(f, domain, codomain),
143 right_inverse_on(f, g, domain, codomain),
144 ensures
145 bijective_on(g, codomain, domain),
146{
147 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 dom.injective_on(f),
179 s <= dom,
180 ensures
181 s.len() == s.map(f).len(),
182 decreases s.len(),
183{
184 if s.is_empty() {
185 assert(s.map(f) == Set::empty());
186 } else {
187 let x = s.choose();
188 lemma_injective_map_cardinality(f, dom, s.remove(x));
189 assert(s.map(f) == s.remove(x).map(f).insert(f(x)));
190 }
191}
192
193pub proof fn lemma_bijective_cardinality<A, B>(f: spec_fn(A) -> B, domain: Set<A>, codomain: Set<B>)
194 requires
195 bijective_on(f, domain, codomain),
196 ensures
197 domain.len() == codomain.len(),
198{
199 lemma_injective_map_cardinality(f, domain, domain);
200}
201
202pub proof fn lemma_bijective_subset_still_bijective<A, B>(
203 f: spec_fn(A) -> B,
204 domain: Set<A>,
205 codomain: Set<B>,
206 s: Set<A>,
207)
208 requires
209 bijective_on(f, domain, codomain),
210 s <= domain,
211 ensures
212 bijective_on(f, s, s.map(f)),
213{
214}
215
216}