forked from verus-lang/verus
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathimo_1988_6.rs
More file actions
132 lines (123 loc) · 3.61 KB
/
Copy pathimo_1988_6.rs
File metadata and controls
132 lines (123 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#![allow(unused_imports)]
use verus_builtin::*;
use verus_builtin_macros::*;
// IMO 1988, #6.
// Let a and b be positive integers such that (a^2 + b^2) / (ab + 1) is an integer.
// Prove that it is a perfect square.
//
// This is a classic example of "vieta jumping". It makes a decent exercise
// utilizing nonlinear arithmetic in Verus.
// Closely following the solution given here:
// https://en.wikipedia.org/wiki/Vieta_jumping#Geometric_interpretation
verus! {
proof fn vieta_jump(b: int, c: int, x: int)
by (nonlinear_arith)
requires
x * x - b * x + c == 0,
ensures
({
let y = b - x;
y * y - b * y + c == 0 && y * x == c
}),
{
}
proof fn sqrt2_contradiction(a: int)
requires
a * a == 2,
ensures
false,
{
assert(a * a == 2 ==> false) by (nonlinear_arith);
}
proof fn is_perfect_square_wlog(a: int, b: int, q: int) -> (sqrt: int)
requires
a >= 0,
b >= 0,
a * a + b * b == (a * b + 1) * q,
q > 2,
a < b,
ensures
sqrt * sqrt == q,
decreases a + b, 0int,
{
if a == 0 {
assert(a * a == 0);
assert(a * b == 0);
assert(b * b == q) by (nonlinear_arith)
requires
a == 0,
a * a + b * b == (a * b + 1) * q,
;
return b;
} else {
assert(b * b - (q * a) * b + (a * a - q) == 0) by {
assert((a * b + 1) * q == (a * b) * q + q) by (nonlinear_arith);
assert((a * b) * q == (q * a) * b) by (nonlinear_arith);
}
vieta_jump(q * a, a * a - q, b);
let b1 = q * a - b;
assert(b1 * b1 - (q * a) * b1 + (a * a - q) == 0);
assert(a * a + b1 * b1 == (a * b1 + 1) * q) by {
assert((a * b1 + 1) * q == (a * b1) * q + q) by (nonlinear_arith);
assert((a * b1) * q == (q * a) * b1) by (nonlinear_arith);
}
assert(b1 < b) by {
assert(a > 0);
assert(b1 * b == a * a - q);
assert(b1 <= a) by {
assert(a >= 0 && b >= 0 && b1 > a && b > a ==> b1 * b >= a * a)
by (nonlinear_arith);
}
}
assert(b1 >= 0) by {
assert(a * a + b1 * b1 == (a * b1 + 1) * q && a >= 1 && q > 2 ==> a * b1 + 1 > 0)
by (nonlinear_arith);
assert(a * b1 + 1 > 0 && a > 0 ==> b1 >= 0) by (nonlinear_arith);
}
return is_perfect_square(a, b1, q);
}
}
// Main result
proof fn is_perfect_square(a: int, b: int, q: int) -> (sqrt: int)
requires
a >= 0,
b >= 0,
a * a + b * b == (a * b + 1) * q,
ensures
sqrt * sqrt == q,
decreases a + b, 1int,
{
if q < 0 {
assert(a >= 0 && b >= 0 && a * a + b * b == (a * b + 1) * q ==> q >= 0)
by (nonlinear_arith);
assert(false);
return 0;
} else if q == 0 {
return 0;
} else if q == 1 {
return 1;
} else if q == 2 {
assert((a - b) * (a - b) == 2) by (nonlinear_arith)
requires
a * a + b * b == (a * b + 1) * 2,
;
sqrt2_contradiction(a - b);
return 0;
} else {
assert(q > 2);
if a == b {
assert(2 * a * a == a * a + a * a) by (nonlinear_arith);
assert(q > 2 ==> (a * a + 1) * q >= (a * a + 1) * 2) by (nonlinear_arith);
assert(false);
return 0;
} else if a < b {
return is_perfect_square_wlog(a, b, q);
} else {
assert(a > b);
return is_perfect_square_wlog(b, a, q);
}
}
}
fn main() {
}
} // verus!