module UInt
import Nat
import UIntDefs
import UIntToFrom
import UIntAdd
import UIntMult
import UIntMonus
import UIntLess
lemma expt_dub_inc: all n:UInt, p:UInt. n ^ dub_inc(p) = sqr(n * (n^p))
proof
arbitrary n:UInt, p:UInt
expand operator^ | expt.
end
lemma expt_inc_dub: all n:UInt, p:UInt. n ^ inc_dub(p) = n * sqr(n^p)
proof
arbitrary n:UInt, p:UInt
expand operator^ | expt.
end
theorem toNat_expt: all p:UInt, n:UInt.
toNat(n^p) = toNat(n) ^ toNat(p)
proof
induction UInt
case bzero {
arbitrary n:UInt
evaluate
}
case dub_inc(p') assume IH {
arbitrary n:UInt
replace expt_dub_inc
expand toNat
replace pow_add_r
expand sqr
replace toNat_mult | toNat_mult | toNat_mult | IH
define x = toNat(n)
define p = toNat(p')
replace symmetric pow_mul_r[p, x, ℕ2] | pow_mul_l
replace mult_commute[x ^ p, x].
}
case inc_dub(x') assume IH {
arbitrary n:UInt
replace expt_inc_dub
expand toNat
replace nat_suc_one_add | pow_add_r | toNat_mult
expand sqr
replace toNat_mult | IH | symmetric pow_mul_r[toNat(x'), toNat(n), ℕ2]
replace pow_mul_l.
}
end
theorem fromNat_expt: all x:Nat, y:Nat.
fromNat(x^y) = fromNat(x)^fromNat(y)
proof
arbitrary x:Nat, y:Nat
suffices toNat(fromNat(x^y)) = toNat(fromNat(x)^fromNat(y))
by uint_toNat_injective
replace toNat_expt | uint_toNat_fromNat.
end
theorem lit_expt_fromNat: all x:Nat, y:Nat.
fromNat(lit(x)) ^ fromNat(lit(y)) = fromNat(lit(x) ^ lit(y))
proof
arbitrary x:Nat, y:Nat
symmetric fromNat_expt
end
auto lit_expt_fromNat
theorem uint_expt_zero: all n:UInt.
n ^ 0 = 1
proof
arbitrary n:UInt
suffices toNat(n^0) = toNat(1) by uint_toNat_injective
equations
toNat(n^0) = toNat(n)^toNat(0) by toNat_expt
... = ℕ1 by replace uint_toNat_fromNat.
... = # toNat(1) # by replace uint_toNat_fromNat.
end
auto uint_expt_zero
theorem uint_expt_suc: all n:UInt, m:Nat. n ^ fromNat(lit(suc(m))) = n * n ^ fromNat(lit(m))
proof
arbitrary n:UInt, m:Nat
suffices toNat(n ^ fromNat(lit(suc(m)))) = toNat(n * n ^ fromNat(lit(m))) by uint_toNat_injective
replace toNat_mult | toNat_expt | uint_toNat_fromNat.
end
auto uint_expt_suc
theorem uint_expt_one: all n:UInt.
n ^ 1 = n
proof
arbitrary n:UInt
suffices toNat(n^1) = toNat(n) by uint_toNat_injective
.
end
theorem uint_expt_two: all n:UInt.
n ^ 2 = n * n
proof
arbitrary n:UInt
suffices toNat(n^2) = toNat(n * n) by uint_toNat_injective
.
end
theorem uint_one_expt: all n:UInt.
1 ^ n = 1
proof
arbitrary n:UInt
suffices toNat(1^n) = toNat(1) by uint_toNat_injective
equations
toNat(1^n) = toNat(1)^toNat(n) by toNat_expt
... = ℕ1^toNat(n) by { replace uint_toNat_fromNat. }
... = ℕ1 by .
... = #toNat(1)# by { replace uint_toNat_fromNat. }
end
theorem uint_pow_add_r : all m:UInt, n:UInt, o:UInt.
m^(n + o) = m^n * m^o
proof
arbitrary m:UInt, n:UInt, o:UInt
suffices toNat(m^(n + o)) = toNat(m^n * m^o) by uint_toNat_injective
equations
toNat(m^(n + o))
= toNat(m) ^ toNat(n + o) by toNat_expt
... = toNat(m) ^ (toNat(n) + toNat(o)) by replace toNat_add.
... = toNat(m) ^ toNat(n) * toNat(m) ^ toNat(o) by replace pow_add_r.
... = #toNat(m^n) * toNat(m^o)# by replace toNat_expt.
... = #toNat(m^n * m^o)# by replace toNat_mult.
end
theorem uint_pow_mul_l : all m:UInt, n:UInt, o:UInt.
(m * n)^o = m^o * n^o
proof
arbitrary m:UInt, n:UInt, o:UInt
suffices toNat((m * n)^o) = toNat(m^o * n^o) by uint_toNat_injective
equations
toNat((m * n)^o)
= toNat(m*n)^toNat(o) by replace toNat_expt.
... = (toNat(m)*toNat(n))^toNat(o) by replace toNat_mult.
... = toNat(m)^toNat(o) * toNat(n)^toNat(o) by replace pow_mul_l.
... = #toNat(m^o) * toNat(n^o)# by replace toNat_expt.
... = #toNat(m^o * n^o)# by replace toNat_mult.
end
theorem uint_pow_mul_r : all m : UInt, n : UInt, o : UInt.
(m ^ n) ^ o = m ^ (n * o)
proof
arbitrary m:UInt, n:UInt, o:UInt
suffices toNat((m ^ n) ^ o) = toNat(m ^ (n * o)) by uint_toNat_injective
equations
toNat((m ^ n) ^ o)
= (toNat(m) ^ toNat(n)) ^ toNat(o) by replace toNat_expt | toNat_expt.
... = toNat(m) ^ (toNat(n) * toNat(o)) by pow_mul_r
... = #toNat(m ^ (n * o))# by replace toNat_expt | toNat_mult.
end
theorem lit_pow_mul_r: all m:Nat, n:Nat, o:UInt.
fromNat(lit(m)) ^ (fromNat(lit(n)) * o) = (fromNat(lit(m)) ^ fromNat(lit(n))) ^ o
proof
arbitrary m:Nat, n:Nat, o:UInt
symmetric uint_pow_mul_r[fromNat(lit(m)), fromNat(lit(n)), o]
end
auto lit_pow_mul_r
lemma pow_cnt_dubs_le_inc: all n:UInt. 2 ^ cnt_dubs(n) ≤ inc(n)
proof
induction UInt
case bzero {
evaluate
}
case dub_inc(n') assume IH {
expand cnt_dubs | inc
replace inc_add_one | uint_pow_add_r | inc_dub_add_mult2 | uint_dist_mult_add
show 2 * 2 ^ cnt_dubs(n') ≤ 3 + 2 * n'
have IH': 2 ^ cnt_dubs(n') ≤ 1 + n' by replace inc_add_one in IH
have A: 2 * 2 ^ cnt_dubs(n') ≤ 2 * (1 + n') by apply uint_mult_mono_le[2] to IH'
have B: 2 * (1 + n') ≤ 3 + 2 * n' by {
replace uint_dist_mult_add
apply uint_add_mono_less_equal[2,2*n',3,2*n'] to .
}
apply uint_less_equal_trans to A, B
}
case inc_dub(n') assume IH {
expand cnt_dubs | inc
replace inc_add_one | uint_pow_add_r | dub_inc_mult2_add | uint_dist_mult_add
show 2 * 2 ^ cnt_dubs(n') ≤ 2 + 2 * n'
have IH': 2 ^ cnt_dubs(n') ≤ 1 + n' by replace inc_add_one in IH
have A: 2 * 2 ^ cnt_dubs(n') ≤ 2 * (1 + n') by apply uint_mult_mono_le[2] to IH'
have B: 2 * (1 + n') ≤ 2 + 2 * n' by replace uint_dist_mult_add.
apply uint_less_equal_trans to A, B
}
end
lemma cnt_le_cnt_dub: all x:UInt.
cnt_dubs(x) ≤ cnt_dubs(dub(x))
proof
induction UInt
case bzero {
expand dub.
}
case dub_inc(x') assume IH {
expand dub | cnt_dubs | cnt_dubs
replace inc_add_one | inc_add_one | uint_add_commute
uint_less_equal_add
}
case inc_dub(x') assume IH {
expand dub | cnt_dubs
replace inc_add_one
IH
}
end
lemma cnt_dub_le_cnt: all x:UInt.
cnt_dubs(dub(x)) ≤ 1 + cnt_dubs(x)
proof
induction UInt
case bzero {
expand dub | cnt_dubs
evaluate
}
case dub_inc(x') assume IH {
expand dub | cnt_dubs | cnt_dubs
replace inc_add_one | inc_add_one.
}
case inc_dub(x') assume IH {
expand dub | cnt_dubs
replace inc_add_one
apply uint_add_both_sides_of_less_equal[1] to IH
}
end
theorem log_pow: all n:UInt. log(2^n) = n
proof
define P = fun n:UInt { log(2^n) = n }
have base: P(0) by {
expand P
evaluate
}
have step: all m:UInt. if P(m) then P(1 + m) by {
arbitrary m:UInt
expand P
assume IH: log(2^m) = m
have pow_pos: 0 < 2^m by {
have toNat0: toNat((0:UInt)) = zero by evaluate
have toNat2: toNat((2:UInt)) = suc(suc(zero)) by evaluate
apply less_toNat[0, 2^m] to {
replace toNat_expt | toNat0 | toNat2
have two_pos: zero < suc(suc(zero)) by evaluate
apply pow_pos_nonneg[toNat(m), suc(suc(zero))] to two_pos
}
}
obtain b where eq_pow: 2^m = 1 + b from apply uint_positive_add_one[2^m] to pow_pos
have b_eq: pred(2^m) = b by {
replace eq_pow
replace symmetric inc_add_one[b]
uint_pred_inc
}
have cnt_b: cnt_dubs(b) = m by {
replace symmetric b_eq
expand log in IH
}
have step_eq: 2^(1+m) = dub_inc(b) by {
have h1: 2^(1+m) = 2 * 2^m by uint_pow_add_r[2, 1, m]
have h2: 2 * 2^m = 2 * (1 + b) by replace eq_pow.
have h3: 2 * (1 + b) = dub_inc(b) by symmetric dub_inc_mult2_add[b]
transitive h1 (transitive h2 h3)
}
expand log
replace step_eq
expand pred | cnt_dubs
replace cnt_b | inc_add_one.
}
expand P in apply uint_induction[P] to base, step
end
theorem uint_expt_log_less_equal: all n:UInt. if 0 < n then 2^log(n) ≤ n
proof
arbitrary n:UInt
assume pos
obtain n' where n_n': n = 1 + n' from apply uint_positive_add_one[n] to pos
replace n_n'
expand log
replace uint_pred_monus
conclude 2 ^ cnt_dubs(n') ≤ 1 + n'
by replace inc_add_one in pow_cnt_dubs_le_inc[n']
end
lemma inc_dub_less_dub : all n : UInt, m : UInt. if n < m then 1 + 2 * n < 2 * m
proof
arbitrary n : UInt, m : UInt
assume prem
have prem1 : 1 + n <= m by replace uint_less_is_less_equal[n][m] in prem
have prem2 : 2 * (1 + n) <= 2 * m by apply uint_mult_mono_le[2] to prem1
have prem3 : 1 + (1 + 2 * n) <= 2 * m by replace uint_dist_mult_add in prem2
define g = 1 + 2 * n
conclude g < 2 * m by replace symmetric uint_less_is_less_equal[g][2 * m] in prem3
end
lemma less_equal_pow_cnt_dubs: all n:UInt. 1 + n < 2 ^ (1 + cnt_dubs(n))
proof
induction UInt
case bzero {
evaluate
}
case dub_inc(n') assume IH {
expand cnt_dubs
replace inc_add_one | uint_pow_add_r | dub_inc_mult2_add | uint_dist_mult_add
show 3 + 2 * n' < 4 * 2 ^ cnt_dubs(n')
have IH1: 1 + n' < 2 * 2 ^ cnt_dubs(n') by replace uint_pow_add_r in IH
have IH2: 1 + 2*(1 + n') < 4 * 2 ^ cnt_dubs(n')
by apply inc_dub_less_dub[1+n', 2*2^cnt_dubs(n')] to ., IH1
conclude 3 + 2*n' < 4 * 2 ^ cnt_dubs(n')
by replace uint_dist_mult_add in IH2
}
case inc_dub(n') assume IH {
expand cnt_dubs
replace inc_add_one | uint_pow_add_r | inc_dub_add_mult2
show 2 + 2 * n' < 4 * 2 ^ cnt_dubs(n')
have IH1 : 2 * (1 + n') < 2 * 2 ^ (1 + cnt_dubs(n')) by
apply uint_pos_mult_both_sides_of_less[2, 1+n', 2^(1+ cnt_dubs(n'))] to ., IH
conclude 2 + 2 * n' < 4 * 2 ^ cnt_dubs(n') by
replace uint_dist_mult_add[2, 1, n'] | uint_pow_add_r in IH1
}
end
theorem less_pow_log: all n:UInt. if 0 < n then n < 2^(1 + log(n))
proof
arbitrary n:UInt
assume npos
expand log
replace uint_pred_monus
obtain n' where n_n': n = 1 + n' from apply uint_positive_add_one[n] to npos
replace n_n'
less_equal_pow_cnt_dubs
end
lemma cnt_dubs_mono: all y:UInt, x:UInt. if x ≤ y then cnt_dubs(x) ≤ cnt_dubs(y)
proof
induction UInt
case bzero {
arbitrary x:UInt
assume xle
have x_z: x = bzero by apply uint_less_equal_bzero to xle
replace x_z.
}
case dub_inc(y') assume IH {
arbitrary x:UInt
assume xle: x ≤ dub_inc(y')
switch x {
case bzero {
expand cnt_dubs
uint_bzero_le
}
case dub_inc(x') assume xeq {
have step: x' ≤ y' by {
have h: dub_inc(x') ≤ dub_inc(y') by replace xeq in xle
have or_eq: dub_inc(x') < dub_inc(y') or dub_inc(x') = dub_inc(y') by expand operator≤ in h
cases or_eq
case lt {
have hh: x' < y' by expand operator< in lt
apply uint_less_implies_less_equal to hh
}
case eq {
have hh: x' = y' by injective dub_inc eq
replace hh.
}
}
have ihres: cnt_dubs(x') ≤ cnt_dubs(y') by apply IH[x'] to step
expand cnt_dubs
replace inc_add_one
apply uint_add_both_sides_of_less_equal[1] to ihres
}
case inc_dub(x') assume xeq {
have step: x' ≤ y' by {
have h: inc_dub(x') ≤ dub_inc(y') by replace xeq in xle
have or_eq: inc_dub(x') < dub_inc(y') or inc_dub(x') = dub_inc(y') by expand operator≤ in h
cases or_eq
case lt {
have hh: x' < y' or x' = y' by expand operator< in lt
cases hh
case llt { apply uint_less_implies_less_equal to llt }
case leq { replace leq. }
}
case eq {
conclude false by evaluate in eq
}
}
have ihres: cnt_dubs(x') ≤ cnt_dubs(y') by apply IH[x'] to step
expand cnt_dubs
replace inc_add_one
apply uint_add_both_sides_of_less_equal[1] to ihres
}
}
}
case inc_dub(y') assume IH {
arbitrary x:UInt
assume xle: x ≤ inc_dub(y')
switch x {
case bzero {
expand cnt_dubs
uint_bzero_le
}
case dub_inc(x') assume xeq {
have step: x' ≤ y' by {
have h: dub_inc(x') ≤ inc_dub(y') by replace xeq in xle
have or_eq: dub_inc(x') < inc_dub(y') or dub_inc(x') = inc_dub(y') by expand operator≤ in h
cases or_eq
case lt {
have hh: x' < y' by expand operator< in lt
apply uint_less_implies_less_equal to hh
}
case eq {
conclude false by evaluate in eq
}
}
have ihres: cnt_dubs(x') ≤ cnt_dubs(y') by apply IH[x'] to step
expand cnt_dubs
replace inc_add_one
apply uint_add_both_sides_of_less_equal[1] to ihres
}
case inc_dub(x') assume xeq {
have step: x' ≤ y' by {
have h: inc_dub(x') ≤ inc_dub(y') by replace xeq in xle
have or_eq: inc_dub(x') < inc_dub(y') or inc_dub(x') = inc_dub(y') by expand operator≤ in h
cases or_eq
case lt {
have hh: x' < y' by expand operator< in lt
apply uint_less_implies_less_equal to hh
}
case eq {
have hh: x' = y' by injective inc_dub eq
replace hh.
}
}
have ihres: cnt_dubs(x') ≤ cnt_dubs(y') by apply IH[x'] to step
expand cnt_dubs
replace inc_add_one
apply uint_add_both_sides_of_less_equal[1] to ihres
}
}
}
end
lemma nat_pred_mono: all a:Nat. all b:Nat. if a ≤ b then pred(a) ≤ pred(b)
proof
induction Nat
case zero {
arbitrary b:Nat
assume _
expand pred.
}
case suc(a') assume IH {
arbitrary b:Nat
assume hle
switch b {
case zero assume bz {
conclude pred(suc(a')) ≤ pred(zero) by expand operator≤ in replace bz in hle
}
case suc(b') assume bs {
expand pred
expand operator≤ in replace bs in hle
}
}
}
end
theorem uint_log_mono: all x:UInt, y:UInt. (if x ≤ y then log(x) ≤ log(y))
proof
arbitrary x:UInt, y:UInt
assume xle
expand log
have predle: pred(x) ≤ pred(y) by {
apply less_equal_toNat[pred(x), pred(y)] to {
replace toNat_pred
have nle: toNat(x) ≤ toNat(y) by apply toNat_less_equal to xle
apply nat_pred_mono[toNat(x), toNat(y)] to nle
}
}
apply cnt_dubs_mono[pred(y), pred(x)] to predle
end
theorem uint_log_greater_one: all n:UInt. if 2 ≤ n then 1 ≤ log(n)
proof
arbitrary n:UInt
assume two_n
have log2_1: log(2) = 1 by evaluate
have one_log2: 1 ≤ log(2) by replace log2_1.
have log2_logn: log(2) ≤ log(n) by apply uint_log_mono to two_n
conclude 1 ≤ log(n)
by apply uint_less_equal_trans to one_log2, log2_logn
end
lemma cnt_dub_less_n: all n:UInt. cnt_dubs(n) ≤ 1 + n
proof
induction UInt
case bzero {
expand cnt_dubs
uint_bzero_le
}
case dub_inc(n') assume IH {
expand cnt_dubs
replace dub_inc_mult2_add | inc_add_one | uint_dist_mult_add
have less: 1 + n' ≤ 2 + 2 * n' by {
have A: 1 + n' ≤ (1 + n') + (1 + n') by uint_less_equal_add
have B: (1 + n') + (1 + n') ≤ 2 + 2*n'
by replace uint_add_commute[n', 1] | symmetric uint_two_mult[n'].
apply uint_less_equal_trans to A, B
}
apply uint_less_equal_trans to IH, less
}
case inc_dub(n') assume IH {
expand cnt_dubs
replace inc_dub_add_mult2 | inc_add_one
have A: 1 + cnt_dubs(n') ≤ 2 + n'
by apply uint_add_both_sides_of_less_equal[1] to IH
have B: 2 + n' ≤ 2 + 2*n' by {
have n_2n: n' ≤ 2*n' by {
replace uint_two_mult
uint_less_equal_add
}
apply uint_add_mono_less_equal[2, n', 2, 2*n'] to ., n_2n
}
apply uint_less_equal_trans to A, B
}
end
theorem uint_logn_le_n: all n:UInt. log(n) ≤ n
proof
arbitrary n:UInt
expand log
have X: cnt_dubs(pred(n)) ≤ 1 + pred(n) by cnt_dub_less_n[pred(n)]
have Y: cnt_dubs(n ∸ 1) ≤ 1 + (n ∸ 1) by replace uint_pred_monus in X
cases uint_zero_or_add_one[n]
case nz {
replace nz
evaluate
}
case ns {
obtain n' where n_n1: n = 1 + n' from ns
replace n_n1 | uint_pred_monus
replace n_n1 in Y
}
end
postulate uint_log_add_le_log_mult: all m:UInt, n:UInt.
if 0 < m and 0 < n
then log(m) + log(n) ≤ log(m * n)
lemma uint_one_le_pow2: all k:UInt. 1 ≤ 2^k
proof
arbitrary k:UInt
have pow_pos: 0 < 2^k by {
have toNat0: toNat((0:UInt)) = zero by evaluate
have toNat2: toNat((2:UInt)) = suc(suc(zero)) by evaluate
apply less_toNat[0, 2^k] to {
replace toNat_expt | toNat0 | toNat2
have two_pos: zero < suc(suc(zero)) by evaluate
apply pow_pos_nonneg[toNat(k), suc(suc(zero))] to two_pos
}
}
apply uint_pos_implies_one_le to pow_pos
end
lemma uint_pow2_mono: all a:UInt, b:UInt. if a ≤ b then 2^a ≤ 2^b
proof
arbitrary a:UInt, b:UInt
assume aleb: a ≤ b
have step: a + (b ∸ a) = b by apply uint_monus_add_identity[b, a] to aleb
have pow_eq: 2^b = 2^a * 2^(b ∸ a) by {
replace symmetric step
uint_pow_add_r[2, a, b ∸ a]
}
have one_le: 1 ≤ 2^(b ∸ a) by uint_one_le_pow2[b ∸ a]
have mult_le: 2^a * 1 ≤ 2^a * 2^(b ∸ a) by apply uint_mult_mono_le[2^a] to one_le
conclude 2^a ≤ 2^b by {
replace pow_eq
mult_le
}
end
lemma uint_pow2_lt_implies_lt: all a:UInt, b:UInt. if 2^a < 2^b then a < b
proof
arbitrary a:UInt, b:UInt
assume powlt: 2^a < 2^b
have tri: a < b or a = b or b < a by uint_trichotomy[a, b]
cases tri
case alb: a < b {
alb
}
case aeb: a = b {
have absurd: 2^a < 2^a by replace symmetric aeb in powlt
conclude false by apply uint_less_irreflexive to absurd
}
case bla: b < a {
have ble: b ≤ a by apply uint_less_implies_less_equal to bla
have powle: 2^b ≤ 2^a by apply uint_pow2_mono[b, a] to ble
have disj: 2^b < 2^a or 2^b = 2^a by expand operator≤ in powle
have powlt2: 2^a < 2^a by {
cases disj
case lt: 2^b < 2^a {
apply uint_less_trans to powlt, lt
}
case eq: 2^b = 2^a {
conclude 2^a < 2^a by replace eq in powlt
}
}
conclude false by apply uint_less_irreflexive to powlt2
}
end
theorem uint_log_mult_le_log_add: all m:UInt, n:UInt. log(m * n) ≤ 1 + log(m) + log(n)
proof
arbitrary m:UInt, n:UInt
cases uint_zero_or_positive[m]
case m_zero: m = 0 {
replace m_zero
have logz: log((0:UInt)) = 0 by evaluate
replace logz
uint_zero_le[1 + log(n)]
}
case m_pos: 0 < m {
cases uint_zero_or_positive[n]
case n_zero: n = 0 {
replace n_zero
have logz: log((0:UInt)) = 0 by evaluate
replace logz
uint_zero_le[1 + log(m) + 0]
}
case n_pos: 0 < n {
have mn_pos: 0 < m * n
by apply uint_pos_mult_both_sides_of_less[m, 0, n] to m_pos, n_pos
have m_lt: m < 2^(1 + log(m)) by apply less_pow_log to m_pos
have n_lt: n < 2^(1 + log(n)) by apply less_pow_log to n_pos
have step1: m * n < 2^(1 + log(m)) * n by {
have h: n * m < n * 2^(1 + log(m)) by apply uint_pos_mult_both_sides_of_less[n, m, 2^(1 + log(m))] to n_pos, m_lt
replace uint_mult_commute[n, m] | uint_mult_commute[n, 2^(1 + log(m))] in h
}
have pow_pos_m: 0 < 2^(1 + log(m)) by {
have one_le: 1 ≤ 2^(1 + log(m)) by uint_one_le_pow2[1 + log(m)]
have one_pos: 0 < 1 by evaluate
have or_eq: 1 < 2^(1 + log(m)) or 1 = 2^(1 + log(m)) by expand operator≤ in one_le
cases or_eq
case lt { apply uint_less_trans to one_pos, lt }
case eq { replace symmetric eq one_pos }
}
have step2: 2^(1 + log(m)) * n < 2^(1 + log(m)) * 2^(1 + log(n))
by apply uint_pos_mult_both_sides_of_less[2^(1 + log(m)), n, 2^(1 + log(n))] to pow_pos_m, n_lt
have step3: m * n < 2^(1 + log(m)) * 2^(1 + log(n)) by apply uint_less_trans to step1, step2
have pow_combine: 2^(1 + log(m)) * 2^(1 + log(n)) = 2^((1 + log(m)) + (1 + log(n))) by symmetric uint_pow_add_r[2, 1 + log(m), 1 + log(n)]
have step4: m * n < 2^((1 + log(m)) + (1 + log(n))) by replace pow_combine in step3
have step5: 2^log(m * n) ≤ m * n by apply uint_expt_log_less_equal to mn_pos
have or_eq: 2^log(m * n) < m * n or 2^log(m * n) = m * n by expand operator≤ in step5
have step6: 2^log(m * n) < 2^((1 + log(m)) + (1 + log(n))) by {
cases or_eq
case lt { apply uint_less_trans to lt, step4 }
case eq { replace eq step4 }
}
have step7: log(m * n) < (1 + log(m)) + (1 + log(n)) by apply uint_pow2_lt_implies_lt to step6
have step8: log(m * n) ≤ log(m) + 1 + log(n) by replace uint_less_is_less_equal in step7
replace uint_add_commute[log(m), 1] in step8
}
}
end
theorem uint_log_pos: all n:UInt. (if 1 < n then 0 < log(n))
proof
arbitrary n:UInt
assume one_n: 1 < n
have two_n: 2 ≤ n by replace uint_less_is_less_equal[1, n] in one_n
have one_logn: 1 ≤ log(n) by apply uint_log_greater_one to two_n
replace uint_less_is_less_equal[0, log(n)]
one_logn
end