Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit ba1c3f3

Browse files
committed
feat(data/int/log): integer logarithms of linearly ordered fields (#13913)
Notably, this provides a way to find the position of the most significant digit of a decimal expansion
1 parent f8d5c64 commit ba1c3f3

File tree

3 files changed

+339
-1
lines changed

3 files changed

+339
-1
lines changed

src/algebra/order/floor.lean

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,13 @@ lemma le_floor (h : (n : α) ≤ a) : n ≤ ⌊a⌋₊ := (le_floor_iff $ n.cast
9696

9797
lemma floor_lt (ha : 0 ≤ a) : ⌊a⌋₊ < n ↔ a < n := lt_iff_lt_of_le_iff_le $ le_floor_iff ha
9898

99+
lemma floor_lt_one (ha : 0 ≤ a) : ⌊a⌋₊ < 1 ↔ a < 1 :=
100+
(floor_lt ha).trans $ by rw nat.cast_one
101+
99102
lemma lt_of_floor_lt (h : ⌊a⌋₊ < n) : a < n := lt_of_not_le $ λ h', (le_floor h').not_lt h
100103

104+
lemma lt_one_of_floor_lt_one (h : ⌊a⌋₊ < 1) : a < 1 := by exact_mod_cast lt_of_floor_lt h
105+
101106
lemma floor_le (ha : 0 ≤ a) : (⌊a⌋₊ : α) ≤ a := (le_floor_iff ha).1 le_rfl
102107

103108
lemma lt_succ_floor (a : α) : a < ⌊a⌋₊.succ := lt_of_floor_lt $ nat.lt_succ_self _
@@ -146,6 +151,9 @@ lemma lt_of_lt_floor (h : n < ⌊a⌋₊) : ↑n < a :=
146151

147152
lemma floor_le_of_le (h : a ≤ n) : ⌊a⌋₊ ≤ n := le_imp_le_iff_lt_imp_lt.2 lt_of_lt_floor h
148153

154+
lemma floor_le_one_of_le_one (h : a ≤ 1) : ⌊a⌋₊ ≤ 1 :=
155+
floor_le_of_le $ h.trans_eq $ nat.cast_one.symm
156+
149157
@[simp] lemma floor_eq_zero : ⌊a⌋₊ = 0 ↔ a < 1 :=
150158
by { rw [←lt_one_iff, ←@cast_one α], exact floor_lt' nat.one_ne_zero }
151159

@@ -186,6 +194,8 @@ eq_of_forall_ge_iff $ λ a, ceil_le.trans nat.cast_le
186194

187195
@[simp] lemma ceil_zero : ⌈(0 : α)⌉₊ = 0 := ceil_coe 0
188196

197+
@[simp] lemma ceil_one : ⌈(1 : α)⌉₊ = 1 := by rw [←nat.cast_one, ceil_coe]
198+
189199
@[simp] lemma ceil_eq_zero : ⌈a⌉₊ = 0 ↔ a ≤ 0 := le_zero_iff.symm.trans ceil_le
190200

191201
lemma lt_of_ceil_lt (h : ⌈a⌉₊ < n) : a < n := (le_ceil a).trans_lt (nat.cast_lt.2 h)
@@ -631,6 +641,8 @@ lemma ceil_pos : 0 < ⌈a⌉ ↔ 0 < a := lt_ceil
631641

632642
@[simp] lemma ceil_zero : ⌈(0 : α)⌉ = 0 := ceil_coe 0
633643

644+
@[simp] lemma ceil_one : ⌈(1 : α)⌉ = 1 := by rw [←int.cast_one, ceil_coe]
645+
634646
lemma ceil_nonneg (ha : 0 ≤ a) : 0 ≤ ⌈a⌉ :=
635647
by exact_mod_cast ha.trans (le_ceil a)
636648

src/analysis/special_functions/log/base.lean

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Authors: Bolton Bailey, Chris Hughes, Abhimanyu Pallavi Sudhir, Jean Lo, Calle S
55
-/
66
import analysis.special_functions.log.basic
77
import analysis.special_functions.pow
8+
import data.int.log
89

910
/-!
1011
# Real logarithm base `b`
@@ -14,7 +15,7 @@ define this as the division of the natural logarithms of the argument and the ba
1415
a globally defined function with `logb b 0 = 0`, `logb b (-x) = logb b x` `logb 0 x = 0` and
1516
`logb (-b) x = logb b x`.
1617
17-
We prove some basic properties of this function and it's relation to `rpow`.
18+
We prove some basic properties of this function and its relation to `rpow`.
1819
1920
## Tags
2021
@@ -291,6 +292,32 @@ end
291292

292293
end b_pos_and_b_lt_one
293294

295+
lemma floor_logb_nat_cast {b : ℕ} {r : ℝ} (hb : 1 < b) (hr : 0 ≤ r) : ⌊logb b r⌋ = int.log b r :=
296+
begin
297+
obtain rfl | hr := hr.eq_or_lt,
298+
{ rw [logb_zero, int.log_zero_right, int.floor_zero] },
299+
have hb1' : 1 < (b : ℝ) := nat.one_lt_cast.mpr hb,
300+
apply le_antisymm,
301+
{ rw [←int.zpow_le_iff_le_log hb hr, ←rpow_int_cast b],
302+
refine le_of_le_of_eq _ (rpow_logb (zero_lt_one.trans hb1') hb1'.ne' hr),
303+
exact rpow_le_rpow_of_exponent_le hb1'.le (int.floor_le _) },
304+
{ rw [int.le_floor, le_logb_iff_rpow_le hb1' hr, rpow_int_cast],
305+
exact int.zpow_log_le_self hb hr }
306+
end
307+
308+
lemma ceil_logb_nat_cast {b : ℕ} {r : ℝ} (hb : 1 < b) (hr : 0 ≤ r) : ⌈logb b r⌉ = int.clog b r :=
309+
begin
310+
obtain rfl | hr := hr.eq_or_lt,
311+
{ rw [logb_zero, int.clog_zero_right, int.ceil_zero] },
312+
have hb1' : 1 < (b : ℝ) := nat.one_lt_cast.mpr hb,
313+
apply le_antisymm,
314+
{ rw [int.ceil_le, logb_le_iff_le_rpow hb1' hr, rpow_int_cast],
315+
refine int.self_le_zpow_clog hb r },
316+
{ rw [←int.le_zpow_iff_clog_le hb hr, ←rpow_int_cast b],
317+
refine (rpow_logb (zero_lt_one.trans hb1') hb1'.ne' hr).symm.trans_le _,
318+
exact rpow_le_rpow_of_exponent_le hb1'.le (int.le_ceil _) },
319+
end
320+
294321
@[simp] lemma logb_eq_zero :
295322
logb b x = 0 ↔ b = 0 ∨ b = 1 ∨ b = -1 ∨ x = 0 ∨ x = 1 ∨ x = -1 :=
296323
begin

src/data/int/log.lean

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
/-
2+
Copyright (c) 2022 Eric Wieser. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Eric Wieser
5+
-/
6+
import data.nat.log
7+
import algebra.order.floor
8+
import algebra.field_power
9+
10+
/-!
11+
# Integer logarithms in a field with respect to a natural base
12+
13+
This file defines two `ℤ`-valued analogs of the logarithm of `r : R` with base `b : ℕ`:
14+
15+
* `int.log b r`: Lower logarithm, or floor **log**. Greatest `k` such that `↑b^k ≤ r`.
16+
* `int.clog b r`: Upper logarithm, or **c**eil **log**. Least `k` such that `r ≤ ↑b^k`.
17+
18+
Note that `int.log` gives the position of the left-most non-zero digit:
19+
```lean
20+
#eval (int.log 10 (0.09 : ℚ), int.log 10 (0.10 : ℚ), int.log 10 (0.11 : ℚ))
21+
-- (-2, -1, -1)
22+
#eval (int.log 10 (9 : ℚ), int.log 10 (10 : ℚ), int.log 10 (11 : ℚ))
23+
-- (0, 1, 1)
24+
```
25+
which means it can be used for computing digit expansions
26+
```lean
27+
import data.fin.vec_notation
28+
29+
def digits (b : ℕ) (q : ℚ) (n : ℕ) : ℕ :=
30+
⌊q*b^(↑n - int.log b q)⌋₊ % b
31+
32+
#eval digits 10 (1/7) ∘ (coe : fin 8 → ℕ)
33+
-- ![1, 4, 2, 8, 5, 7, 1, 4]
34+
```
35+
36+
## Main results
37+
38+
* For `int.log`:
39+
* `int.zpow_log_le_self`, `int.lt_zpow_succ_log_self`: the bounds formed by `int.log`,
40+
`(b : R) ^ log b r ≤ r < (b : R) ^ (log b r + 1)`.
41+
* `int.zpow_log_gi`: the galois coinsertion between `zpow` and `int.log`.
42+
* For `int.clog`:
43+
* `int.zpow_pred_clog_lt_self`, `int.self_le_zpow_clog`: the bounds formed by `int.clog`,
44+
`(b : R) ^ (clog b r - 1) < r ≤ (b : R) ^ clog b r`.
45+
* `int.clog_zpow_gi`: the galois insertion between `int.clog` and `zpow`.
46+
* `int.neg_log_inv_eq_clog`, `int.neg_clog_inv_eq_log`: the link between the two definitions.
47+
48+
-/
49+
variables {R : Type*} [linear_ordered_field R] [floor_ring R]
50+
51+
namespace int
52+
53+
/-- The greatest power of `b` such that `b ^ log b r ≤ r`. -/
54+
def log (b : ℕ) (r : R) : ℤ :=
55+
if 1 ≤ r then
56+
nat.log b ⌊r⌋₊
57+
else
58+
-nat.clog b ⌈r⁻¹⌉₊
59+
60+
lemma log_of_one_le_right (b : ℕ) {r : R} (hr : 1 ≤ r) : log b r = nat.log b ⌊r⌋₊ :=
61+
if_pos hr
62+
63+
lemma log_of_right_le_one (b : ℕ) {r : R} (hr : r ≤ 1) : log b r = -nat.clog b ⌈r⁻¹⌉₊ :=
64+
begin
65+
obtain rfl | hr := hr.eq_or_lt,
66+
{ rw [log, if_pos hr, inv_one, nat.ceil_one, nat.floor_one, nat.log_one_right, nat.clog_one_right,
67+
int.coe_nat_zero, neg_zero], },
68+
{ exact if_neg hr.not_le }
69+
end
70+
71+
@[simp, norm_cast] lemma log_nat_cast (b : ℕ) (n : ℕ) : log b (n : R) = nat.log b n :=
72+
begin
73+
cases n,
74+
{ simp [log_of_right_le_one _ _, nat.log_zero_right] },
75+
{ have : 1 ≤ (n.succ : R) := by simp,
76+
simp [log_of_one_le_right _ this, ←nat.cast_succ] }
77+
end
78+
79+
lemma log_of_left_le_one {b : ℕ} (hb : b ≤ 1) (r : R) : log b r = 0 :=
80+
begin
81+
cases le_total 1 r,
82+
{ rw [log_of_one_le_right _ h, nat.log_of_left_le_one hb, int.coe_nat_zero] },
83+
{ rw [log_of_right_le_one _ h, nat.clog_of_left_le_one hb, int.coe_nat_zero, neg_zero] },
84+
end
85+
86+
lemma log_of_right_le_zero (b : ℕ) {r : R} (hr : r ≤ 0) : log b r = 0 :=
87+
by rw [log_of_right_le_one _ (hr.trans zero_le_one),
88+
nat.clog_of_right_le_one ((nat.ceil_eq_zero.mpr $ inv_nonpos.2 hr).trans_le zero_le_one),
89+
int.coe_nat_zero, neg_zero]
90+
91+
lemma zpow_log_le_self {b : ℕ} {r : R} (hb : 1 < b) (hr : 0 < r) :
92+
(b : R) ^ log b r ≤ r :=
93+
begin
94+
cases le_total 1 r with hr1 hr1,
95+
{ rw log_of_one_le_right _ hr1,
96+
refine le_trans _ (nat.floor_le hr.le),
97+
rw [zpow_coe_nat, ←nat.cast_pow, nat.cast_le],
98+
exact nat.pow_log_le_self hb (nat.floor_pos.mpr hr1) },
99+
{ rw [log_of_right_le_one _ hr1, zpow_neg, zpow_coe_nat, ← nat.cast_pow],
100+
apply inv_le_of_inv_le hr,
101+
refine (nat.le_ceil _).trans (nat.cast_le.2 _),
102+
exact nat.le_pow_clog hb _ },
103+
end
104+
105+
lemma lt_zpow_succ_log_self {b : ℕ} (hb : 1 < b) (r : R) :
106+
r < (b : R) ^ (log b r + 1) :=
107+
begin
108+
cases le_or_lt r 0 with hr hr,
109+
{ rw [log_of_right_le_zero _ hr, zero_add, zpow_one],
110+
exact hr.trans_lt (zero_lt_one.trans_le $ by exact_mod_cast hb.le) },
111+
cases le_or_lt 1 r with hr1 hr1,
112+
{ rw log_of_one_le_right _ hr1,
113+
rw [int.coe_nat_add_one_out, zpow_coe_nat, ←nat.cast_pow],
114+
apply nat.lt_of_floor_lt,
115+
exact nat.lt_pow_succ_log_self hb _, },
116+
{ rw log_of_right_le_one _ hr1.le,
117+
have hcri : 1 < r⁻¹ := one_lt_inv hr hr1,
118+
have : 1 ≤ nat.clog b ⌈r⁻¹⌉₊ :=
119+
nat.succ_le_of_lt (nat.clog_pos hb $ nat.one_lt_cast.1 $ hcri.trans_le (nat.le_ceil _)),
120+
rw [neg_add_eq_sub, ←neg_sub, ←int.coe_nat_one, ← int.coe_nat_sub this,
121+
zpow_neg, zpow_coe_nat, lt_inv hr (pow_pos (nat.cast_pos.mpr $ zero_lt_one.trans hb) _),
122+
←nat.cast_pow],
123+
refine nat.lt_ceil.1 _,
124+
exact (nat.pow_pred_clog_lt_self hb $ nat.one_lt_cast.1 $ hcri.trans_le $ nat.le_ceil _), }
125+
end
126+
127+
@[simp] lemma log_zero_right (b : ℕ) : log b (0 : R) = 0 :=
128+
log_of_right_le_zero b le_rfl
129+
130+
@[simp] lemma log_one_right (b : ℕ) : log b (1 : R) = 0 :=
131+
by rw [log_of_one_le_right _ le_rfl, nat.floor_one, nat.log_one_right, int.coe_nat_zero]
132+
133+
lemma log_zpow {b : ℕ} (hb : 1 < b) (z : ℤ) : log b (b ^ z : R) = z :=
134+
begin
135+
obtain ⟨n, rfl | rfl⟩ := z.eq_coe_or_neg,
136+
{ rw [log_of_one_le_right _ (one_le_zpow_of_nonneg _ $ int.coe_nat_nonneg _),
137+
zpow_coe_nat, ←nat.cast_pow, nat.floor_coe, nat.log_pow hb],
138+
exact_mod_cast hb.le, },
139+
{ rw [log_of_right_le_one _ (zpow_le_one_of_nonpos _ $ neg_nonpos.mpr (int.coe_nat_nonneg _)),
140+
zpow_neg, inv_inv, zpow_coe_nat, ←nat.cast_pow, nat.ceil_coe, nat.clog_pow _ _ hb],
141+
exact_mod_cast hb.le, },
142+
end
143+
144+
@[mono] lemma log_mono_right {b : ℕ} {r₁ r₂ : R} (h₀ : 0 < r₁) (h : r₁ ≤ r₂) :
145+
log b r₁ ≤ log b r₂ :=
146+
begin
147+
cases le_or_lt b 1 with hb hb,
148+
{ rw [log_of_left_le_one hb, log_of_left_le_one hb], },
149+
cases le_total r₁ 1 with h₁ h₁; cases le_total r₂ 1 with h₂ h₂,
150+
{ rw [log_of_right_le_one _ h₁, log_of_right_le_one _ h₂, neg_le_neg_iff, int.coe_nat_le],
151+
exact nat.clog_mono_right _ (nat.ceil_mono $ inv_le_inv_of_le h₀ h), },
152+
{ rw [log_of_right_le_one _ h₁, log_of_one_le_right _ h₂],
153+
exact (neg_nonpos.mpr (int.coe_nat_nonneg _)).trans (int.coe_nat_nonneg _) },
154+
{ obtain rfl := le_antisymm h (h₂.trans h₁), refl, },
155+
{ rw [log_of_one_le_right _ h₁, log_of_one_le_right _ h₂, int.coe_nat_le],
156+
exact nat.log_mono_right (nat.floor_mono h), },
157+
end
158+
159+
variables (R)
160+
161+
/-- Over suitable subtypes, `zpow` and `int.log` form a galois coinsertion -/
162+
def zpow_log_gi {b : ℕ} (hb : 1 < b) :
163+
galois_coinsertion
164+
(λ z : ℤ, subtype.mk ((b : R) ^ z) $ zpow_pos_of_pos (by exact_mod_cast zero_lt_one.trans hb) z)
165+
(λ r : set.Ioi (0 : R), int.log b (r : R)) :=
166+
galois_coinsertion.monotone_intro
167+
(λ r₁ r₂, log_mono_right r₁.prop)
168+
(λ z₁ z₂ hz, subtype.coe_le_coe.mp $ (zpow_strict_mono $ by exact_mod_cast hb).monotone hz)
169+
(λ r, subtype.coe_le_coe.mp $ zpow_log_le_self hb r.prop)
170+
(λ _, log_zpow hb _)
171+
172+
variables {R}
173+
174+
/-- `zpow b` and `int.log b` (almost) form a Galois connection. -/
175+
lemma lt_zpow_iff_log_lt {b : ℕ} (hb : 1 < b) {x : ℤ} {r : R} (hr : 0 < r) :
176+
r < (b : R) ^ x ↔ log b r < x :=
177+
@galois_connection.lt_iff_lt _ _ _ _ _ _ (zpow_log_gi R hb).gc x ⟨r, hr⟩
178+
179+
/-- `zpow b` and `int.log b` (almost) form a Galois connection. -/
180+
lemma zpow_le_iff_le_log {b : ℕ} (hb : 1 < b) {x : ℤ} {r : R} (hr : 0 < r) :
181+
(b : R) ^ x ≤ r ↔ x ≤ log b r :=
182+
@galois_connection.le_iff_le _ _ _ _ _ _ (zpow_log_gi R hb).gc x ⟨r, hr⟩
183+
184+
/-- The least power of `b` such that `r ≤ b ^ log b r`. -/
185+
def clog (b : ℕ) (r : R) : ℤ :=
186+
if 1 ≤ r then
187+
nat.clog b ⌈r⌉₊
188+
else
189+
-nat.log b ⌊r⁻¹⌋₊
190+
191+
lemma clog_of_one_le_right (b : ℕ) {r : R} (hr : 1 ≤ r) : clog b r = nat.clog b ⌈r⌉₊ :=
192+
if_pos hr
193+
194+
lemma clog_of_right_le_one (b : ℕ) {r : R} (hr : r ≤ 1) : clog b r = -nat.log b ⌊r⁻¹⌋₊ :=
195+
begin
196+
obtain rfl | hr := hr.eq_or_lt,
197+
{ rw [clog, if_pos hr, inv_one, nat.ceil_one, nat.floor_one, nat.log_one_right,
198+
nat.clog_one_right, int.coe_nat_zero, neg_zero], },
199+
{ exact if_neg hr.not_le }
200+
end
201+
202+
lemma clog_of_right_le_zero (b : ℕ) {r : R} (hr : r ≤ 0) : clog b r = 0 :=
203+
begin
204+
rw [clog, if_neg (hr.trans_lt zero_lt_one).not_le, neg_eq_zero, int.coe_nat_eq_zero,
205+
nat.log_eq_zero_iff],
206+
cases le_or_lt b 1 with hb hb,
207+
{ exact or.inr hb },
208+
{ refine or.inl (lt_of_le_of_lt _ hb),
209+
exact nat.floor_le_one_of_le_one ((inv_nonpos.2 hr).trans zero_le_one) },
210+
end
211+
212+
@[simp] lemma clog_inv (b : ℕ) (r : R) : clog b r⁻¹ = -log b r :=
213+
begin
214+
cases lt_or_le 0 r with hrp hrp,
215+
{ obtain hr | hr := le_total 1 r,
216+
{ rw [clog_of_right_le_one _ (inv_le_one hr), log_of_one_le_right _ hr, inv_inv] },
217+
{ rw [clog_of_one_le_right _ (one_le_inv hrp hr), log_of_right_le_one _ hr, neg_neg] }, },
218+
{ rw [clog_of_right_le_zero _ (inv_nonpos.mpr hrp), log_of_right_le_zero _ hrp, neg_zero], },
219+
end
220+
221+
@[simp] lemma log_inv (b : ℕ) (r : R) : log b r⁻¹ = -clog b r :=
222+
by rw [←inv_inv r, clog_inv, neg_neg, inv_inv]
223+
224+
-- note this is useful for writing in reverse
225+
lemma neg_log_inv_eq_clog (b : ℕ) (r : R) : -log b r⁻¹ = clog b r :=
226+
by rw [log_inv, neg_neg]
227+
228+
lemma neg_clog_inv_eq_log (b : ℕ) (r : R) : -clog b r⁻¹ = log b r :=
229+
by rw [clog_inv, neg_neg]
230+
231+
@[simp, norm_cast] lemma clog_nat_cast (b : ℕ) (n : ℕ) : clog b (n : R) = nat.clog b n :=
232+
begin
233+
cases n,
234+
{ simp [clog_of_right_le_one _ _, nat.clog_zero_right] },
235+
{ have : 1 ≤ (n.succ : R) := by simp,
236+
simp [clog_of_one_le_right _ this, ←nat.cast_succ] }
237+
end
238+
239+
lemma clog_of_left_le_one {b : ℕ} (hb : b ≤ 1) (r : R) : clog b r = 0 :=
240+
by rw [←neg_log_inv_eq_clog, log_of_left_le_one hb, neg_zero]
241+
242+
lemma self_le_zpow_clog {b : ℕ} (hb : 1 < b) (r : R) : r ≤ (b : R) ^ clog b r :=
243+
begin
244+
cases le_or_lt r 0 with hr hr,
245+
{ rw [clog_of_right_le_zero _ hr, zpow_zero],
246+
exact hr.trans zero_le_one },
247+
rw [←neg_log_inv_eq_clog, zpow_neg, le_inv hr (zpow_pos_of_pos _ _)],
248+
{ exact zpow_log_le_self hb (inv_pos.mpr hr), },
249+
{ exact nat.cast_pos.mpr (zero_le_one.trans_lt hb), },
250+
end
251+
252+
lemma zpow_pred_clog_lt_self {b : ℕ} {r : R} (hb : 1 < b) (hr : 0 < r) :
253+
(b : R) ^ (clog b r - 1) < r :=
254+
begin
255+
rw [←neg_log_inv_eq_clog, ←neg_add', zpow_neg, inv_lt (zpow_pos_of_pos _ _) hr],
256+
{ exact lt_zpow_succ_log_self hb _, },
257+
{ exact nat.cast_pos.mpr (zero_le_one.trans_lt hb), },
258+
end
259+
260+
@[simp] lemma clog_zero_right (b : ℕ) : clog b (0 : R) = 0 :=
261+
clog_of_right_le_zero _ le_rfl
262+
263+
@[simp] lemma clog_one_right (b : ℕ) : clog b (1 : R) = 0 :=
264+
by rw [clog_of_one_le_right _ le_rfl, nat.ceil_one, nat.clog_one_right, int.coe_nat_zero]
265+
266+
lemma clog_zpow {b : ℕ} (hb : 1 < b) (z : ℤ) : clog b (b ^ z : R) = z :=
267+
by rw [←neg_log_inv_eq_clog, ←zpow_neg, log_zpow hb, neg_neg]
268+
269+
@[mono] lemma clog_mono_right {b : ℕ} {r₁ r₂ : R} (h₀ : 0 < r₁) (h : r₁ ≤ r₂) :
270+
clog b r₁ ≤ clog b r₂ :=
271+
begin
272+
rw [←neg_log_inv_eq_clog, ←neg_log_inv_eq_clog, neg_le_neg_iff],
273+
exact log_mono_right (inv_pos.mpr $ h₀.trans_le h) (inv_le_inv_of_le h₀ h),
274+
end
275+
276+
variables (R)
277+
/-- Over suitable subtypes, `int.clog` and `zpow` form a galois insertion -/
278+
def clog_zpow_gi {b : ℕ} (hb : 1 < b) :
279+
galois_insertion
280+
(λ r : set.Ioi (0 : R), int.clog b (r : R))
281+
(λ z : ℤ, ⟨(b : R) ^ z, zpow_pos_of_pos (by exact_mod_cast zero_lt_one.trans hb) z⟩) :=
282+
galois_insertion.monotone_intro
283+
(λ z₁ z₂ hz, subtype.coe_le_coe.mp $ (zpow_strict_mono $ by exact_mod_cast hb).monotone hz)
284+
(λ r₁ r₂, clog_mono_right r₁.prop)
285+
(λ r, subtype.coe_le_coe.mp $ self_le_zpow_clog hb _)
286+
(λ _, clog_zpow hb _)
287+
variables {R}
288+
289+
/-- `int.clog b` and `zpow b` (almost) form a Galois connection. -/
290+
lemma zpow_lt_iff_lt_clog {b : ℕ} (hb : 1 < b) {x : ℤ} {r : R} (hr : 0 < r) :
291+
(b : R) ^ x < r ↔ x < clog b r :=
292+
(@galois_connection.lt_iff_lt _ _ _ _ _ _ (clog_zpow_gi R hb).gc ⟨r, hr⟩ x).symm
293+
294+
/-- `int.clog b` and `zpow b` (almost) form a Galois connection. -/
295+
lemma le_zpow_iff_clog_le {b : ℕ} (hb : 1 < b) {x : ℤ} {r : R} (hr : 0 < r) :
296+
r ≤ (b : R) ^ x ↔ clog b r ≤ x :=
297+
(@galois_connection.le_iff_le _ _ _ _ _ _ (clog_zpow_gi R hb).gc ⟨r, hr⟩ x).symm
298+
299+
end int

0 commit comments

Comments
 (0)