vstd/arithmetic/
logarithm.rs1#[allow(unused_imports)]
15use super::super::prelude::*;
16
17verus! {
18
19use super::super::calc_macro::*;
20#[cfg(verus_keep_ghost)]
21use super::div_mod::{
22 lemma_div_pos_is_pos,
23 lemma_div_decreases,
24 lemma_div_is_ordered,
25 lemma_div_multiples_vanish,
26};
27#[cfg(verus_keep_ghost)]
28use super::super::math::{div as div1};
29#[cfg(verus_keep_ghost)]
30use super::super::arithmetic::mul::{lemma_mul_increases, lemma_mul_is_commutative};
31#[cfg(verus_keep_ghost)]
32use super::super::arithmetic::power::{pow, lemma_pow_positive};
33
34#[verifier::opaque]
38pub open spec fn log(base: int, pow: int) -> int
39 recommends
40 base > 1,
41 pow >= 0,
42 decreases pow,
43{
44 if pow < base || pow / base >= pow || pow / base < 0 {
49 0
50 } else {
51 1 + log(base, pow / base)
52 }
53}
54
55pub proof fn lemma_log0(base: int, pow: int)
57 requires
58 base > 1,
59 0 <= pow < base,
60 ensures
61 log(base, pow) == 0,
62{
63 reveal(log);
64}
65
66pub broadcast proof fn lemma_log_s(base: int, pow: int)
70 requires
71 base > 1,
72 pow >= base,
73 ensures
74 #![trigger log(base, div1(pow, base))]
75 pow / base >= 0,
76 log(base, pow) == 1 + log(base, pow / base),
77{
78 broadcast use {lemma_div_pos_is_pos, lemma_div_decreases};
79
80 reveal(log);
81}
82
83pub proof fn lemma_log_nonnegative(base: int, pow: int)
86 requires
87 base > 1,
88 0 <= pow,
89 ensures
90 log(base, pow) >= 0,
91 decreases pow,
92{
93 reveal(log);
94 if !(pow < base || pow / base >= pow || pow / base < 0) {
95 lemma_log_nonnegative(base, pow / base);
96 }
97}
98
99pub proof fn lemma_log_is_ordered(base: int, pow1: int, pow2: int)
103 requires
104 base > 1,
105 0 <= pow1 <= pow2,
106 ensures
107 log(base, pow1) <= log(base, pow2),
108 decreases pow1,
109{
110 reveal(log);
111 if pow2 < base {
112 assert(log(base, pow1) == 0 == log(base, pow2));
113 } else if pow1 < base {
114 assert(log(base, pow1) == 0);
115 lemma_log_nonnegative(base, pow2);
116 } else {
117 broadcast use {lemma_div_pos_is_pos, lemma_div_is_ordered, lemma_div_decreases};
118
119 lemma_log_is_ordered(base, pow1 / base, pow2 / base);
120 }
121}
122
123pub proof fn lemma_log_pow(base: int, n: nat)
125 requires
126 base > 1,
127 ensures
128 log(base, pow(base, n)) == n,
129 decreases n,
130{
131 if n == 0 {
132 reveal(pow);
133 reveal(log);
134 } else {
135 let n_minus_1: nat = (n - 1) as nat;
136 lemma_pow_positive(base, n);
137 calc! {
138 (==)
139 log(base, pow(base, n)); (==) {
140 reveal(pow);
141 }
142 log(base, base * pow(base, n_minus_1)); (==) {
143 lemma_pow_positive(base, n_minus_1);
144 lemma_mul_increases(pow(base, n_minus_1), base);
145 lemma_mul_is_commutative(pow(base, n_minus_1), base);
146 lemma_log_s(base, base * pow(base, n_minus_1));
147 }
148 1 + log(base, (base * pow(base, n_minus_1)) / base); (==) {
149 lemma_div_multiples_vanish(pow(base, n_minus_1), base);
150 }
151 1 + log(base, pow(base, n_minus_1)); (==) {
152 lemma_log_pow(base, n_minus_1);
153 }
154 1 + (n - 1);
155 }
156 }
157}
158
159}