-
Notifications
You must be signed in to change notification settings - Fork 1
/
021-rescale_to_unit.dfy
93 lines (86 loc) · 2.57 KB
/
021-rescale_to_unit.dfy
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
function affine(x: real, shift: real, scale: real) : real
requires scale > 0.0
{
(x + shift) / scale
}
lemma affine_zero(x: real, shift: real, scale: real)
requires x == -shift
requires scale > 0.0
ensures affine(x, shift, scale) == 0.0 {}
lemma affine_unit(x: real, shift: real, scale: real)
requires x == scale - shift
requires scale > 0.0
ensures affine(x, shift, scale) == 1.0 {}
function affine_seq(s: seq<real>, r: seq<real>, shift: real, scale: real) : bool
requires scale > 0.0
requires |r| == |s|
{
forall i :: 0 <= i < |s| ==> r[i] == affine(s[i], shift, scale)
}
lemma div_unit(x: real, scale: real)
requires 0.0 <= x <= scale
requires scale > 0.0
ensures x / scale <= 1.0 {}
method rescale_to_unit(s: seq<real>) returns (r : seq<real>)
// pre-conditions-start
requires |s| >= 2
requires exists i, j : int :: (0 <= i < j < |s|) && s[i] != s[j]
// pre-conditions-end
// post-conditions-start
ensures |r| == |s|
ensures forall i : int :: 0 <= i < |s| ==> 0.0 <= r[i] <= 1.0
ensures exists i : int :: 0 <= i < |s| && r[i] == 0.0
ensures exists i : int :: 0 <= i < |s| && r[i] == 1.0
ensures exists shift, scale :: scale > 0.0 && affine_seq(s, r, shift, scale)
// post-conditions-end
{
// impl-start
var mni : int := if s[0] < s[1] then 0 else 1;
var mxi : int := if s[0] < s[1] then 1 else 0;
for i := 2 to |s|
// invariants-start
invariant 0 <= mni < |s|
invariant 0 <= mxi < |s|
invariant forall j : int :: (0 <= j < i) ==> s[mni] <= s[j] <= s[mxi]
invariant s[mni] <= s[mxi]
// invariants-end
{
if (s[i] < s[mni]) {
mni := i;
}
if (s[i] > s[mxi]) {
mxi := i;
}
}
var shift := -s[mni];
var scale := s[mxi] - s[mni];
assert scale > 0.0; // assert-line
r := [];
for j := 0 to |s|
// invariants-start
invariant |r| == j
invariant forall k : int :: 0 <= k < j ==> 0.0 <= r[k] <= 1.0
invariant affine_seq(s[..j], r, shift, scale)
// invariants-end
{
var rj : real := affine(s[j], shift, scale);
// assert-start
assert rj <= 1.0 by {
div_unit(s[j] + shift, scale);
}
// assert-end
r := r + [rj];
}
assert s[..|s|] == s; // assert-line
// assert-start
assert r[mni] == 0.0 by {
affine_zero(s[mni], shift, scale);
}
// assert-end
// assert-start
assert r[mxi] == 1.0 by {
affine_unit(s[mxi], shift, scale);
}
// assert-end
// impl-end
}