vstd/arithmetic/internals/
mul_internals.rs1#[allow(unused_imports)]
15use super::super::super::prelude::*;
16
17#[cfg(verus_keep_ghost)]
18use super::super::super::arithmetic::internals::general_internals::{
19 is_le, lemma_induction_helper,
20};
21use super::super::super::arithmetic::internals::mul_internals_nonlinear as MulINL;
22#[cfg(verus_keep_ghost)]
23use super::super::super::math::{add as add1, sub as sub1};
24
25verus! {
26
27#[verifier::opaque]
30pub open spec fn mul_pos(x: int, y: int) -> int
31 recommends
32 x >= 0,
33 decreases x,
34{
35 if x <= 0 {
36 0
37 } else {
38 y + mul_pos(x - 1, y)
39 }
40}
41
42pub open spec fn mul_recursive(x: int, y: int) -> int {
44 if x >= 0 {
45 mul_pos(x, y)
46 } else {
47 -1 * mul_pos(-1 * x, y)
48 }
49}
50
51pub proof fn lemma_mul_induction(f: spec_fn(int) -> bool)
68 requires
69 f(0),
70 forall|i: int| i >= 0 && #[trigger] f(i) ==> #[trigger] f(add1(i, 1)),
71 forall|i: int| i <= 0 && #[trigger] f(i) ==> #[trigger] f(sub1(i, 1)),
72 ensures
73 forall|i: int| #[trigger] f(i),
74{
75 assert forall|i: int| #[trigger] f(i) by { lemma_induction_helper(1, f, i) };
76}
77
78pub broadcast proof fn lemma_mul_commutes(x: int, y: int)
80 ensures
81 #[trigger] (x * y) == y * x,
82{
83}
84
85proof fn lemma_mul_successor()
88 ensures
89 forall|x: int, y: int| #[trigger] ((x + 1) * y) == x * y + y,
90 forall|x: int, y: int| #[trigger] ((x - 1) * y) == x * y - y,
91{
92 assert forall|x: int, y: int| #[trigger] ((x + 1) * y) == x * y + y by {
93 MulINL::lemma_mul_is_distributive_add(y, x, 1);
94 }
95 assert forall|x: int, y: int| #[trigger] ((x - 1) * y) == x * y - y by {
96 assert((x - 1) * y == y * (x - 1));
97 MulINL::lemma_mul_is_distributive_add(y, x, -1);
98 assert(y * (x - 1) == y * x + y * -1);
99 assert(-1 * y == -y);
100 assert(x * y + (-1 * y) == x * y - y);
101 }
102}
103
104#[verifier::spinoff_prover]
107pub broadcast proof fn lemma_mul_distributes_plus(x: int, y: int, z: int)
108 ensures
109 #[trigger] ((x + y) * z) == (x * z + y * z),
110{
111 lemma_mul_successor();
112 assert forall|x: int, y: int, z: int| #[trigger] ((x + y) * z) == (x * z + y * z) by {
113 let f1 = |i: int| ((x + i) * z) == (x * z + i * z);
114 assert(f1(0));
115 assert forall|i: int| i >= 0 && #[trigger] f1(i) implies #[trigger] f1(add1(i, 1)) by {
116 assert((x + (i + 1)) * z == ((x + i) + 1) * z == (x + i) * z + z);
117 };
118 assert forall|i: int| i <= 0 && #[trigger] f1(i) implies #[trigger] f1(sub1(i, 1)) by {
119 assert((x + (i - 1)) * z == ((x + i) - 1) * z == (x + i) * z - z);
120 };
121 lemma_mul_induction(f1);
122 assert(f1(y));
123 }
124}
125
126#[verifier::spinoff_prover]
127pub broadcast proof fn lemma_mul_distributes_minus(x: int, y: int, z: int)
128 ensures
129 #[trigger] ((x - y) * z) == (x * z - y * z),
130{
131 lemma_mul_successor();
132 assert forall|x: int, y: int, z: int| #[trigger] ((x - y) * z) == (x * z - y * z) by {
133 let f2 = |i: int| ((x - i) * z) == (x * z - i * z);
134 assert(f2(0));
135 assert forall|i: int| i >= 0 && #[trigger] f2(i) implies #[trigger] f2(add1(i, 1)) by {
136 assert((x - (i + 1)) * z == ((x - i) - 1) * z == (x - i) * z - z);
137 };
138 assert forall|i: int| i <= 0 && #[trigger] f2(i) implies #[trigger] f2(sub1(i, 1)) by {
139 assert((x - (i - 1)) * z == ((x - i) + 1) * z == (x - i) * z + z);
140 };
141 lemma_mul_induction(f2);
142 assert(f2(y));
143 }
144}
145
146pub open spec fn mul_auto() -> bool {
149 &&& forall|x: int, y: int| #[trigger] (x * y) == (y * x)
150 &&& forall|x: int, y: int, z: int| #[trigger] ((x + y) * z) == (x * z + y * z)
151 &&& forall|x: int, y: int, z: int| #[trigger] ((x - y) * z) == (x * z - y * z)
152}
153
154pub broadcast group group_mul_properties_internal {
155 lemma_mul_commutes,
156 lemma_mul_distributes_plus,
157 lemma_mul_distributes_minus,
158}
159
160proof fn lemma_mul_properties_internal_prove_mul_auto()
162 ensures
163 mul_auto(),
164{
165 broadcast use group_mul_properties_internal;
166
167 assert(mul_auto());
168}
169
170pub proof fn lemma_mul_induction_auto(x: int, f: spec_fn(int) -> bool)
185 requires
186 mul_auto() ==> {
187 &&& f(0)
188 &&& (forall|i| #[trigger] is_le(0, i) && f(i) ==> f(i + 1))
189 &&& (forall|i| #[trigger] is_le(i, 0) && f(i) ==> f(i - 1))
190 },
191 ensures
192 mul_auto(),
193 f(x),
194{
195 broadcast use group_mul_properties_internal;
196
197 assert(forall|i| is_le(0, i) && #[trigger] f(i) ==> f(i + 1));
198 assert(forall|i| is_le(i, 0) && #[trigger] f(i) ==> f(i - 1));
199 lemma_mul_induction(f);
200}
201
202pub proof fn lemma_mul_induction_auto_forall(f: spec_fn(int) -> bool)
217 requires
218 mul_auto() ==> {
219 &&& f(0)
220 &&& (forall|i| #[trigger] is_le(0, i) && f(i) ==> f(i + 1))
221 &&& (forall|i| #[trigger] is_le(i, 0) && f(i) ==> f(i - 1))
222 },
223 ensures
224 mul_auto(),
225 forall|i| #[trigger] f(i),
226{
227 assert(mul_auto()) by {
228 lemma_mul_induction_auto(0, f);
229 }
230 assert forall|i| #[trigger] f(i) by {
231 lemma_mul_induction_auto(i, f);
232 }
233}
234
235}