l3lab/ntp-mathlib huggingface dataset:
theorem inverse_compare : pkg.compare pkg' ∘ pkg'.compare pkg = id := by
  have uc := pkg.uniformContinuous_compare pkg'
  have uc' := pkg'.uniformContinuous_compare pkg
  apply pkg'.funext (uc.comp uc').continuous continuous_id
  intro a
  rw [comp_apply, pkg'.compare_coe pkg, pkg.compare_coe pkg']
  

Proof state:
α : Type u_1
inst✝¹ : UniformSpace α
pkg : AbstractCompletion α
β : Type u_2
inst✝ : UniformSpace β
pkg' : AbstractCompletion α
uc : UniformContinuous (compare pkg pkg')
uc' : UniformContinuous (compare pkg' pkg)
a : α
⊢ coe pkg' a = id (coe pkg' a)

Next tactic:
rfl
theorem uniformContinuous_extension₂ : UniformContinuous₂ (pkg.extend₂ pkg' f) := by
  

Proof state:
α : Type u_1
inst✝³ : UniformSpace α
pkg : AbstractCompletion α
β : Type u_2
inst✝² : UniformSpace β
pkg' : AbstractCompletion β
γ : Type u_3
inst✝¹ : UniformSpace γ
f : α → β → γ
inst✝ : CompleteSpace γ
⊢ UniformContinuous₂ (AbstractCompletion.extend₂ pkg pkg' f)

Next tactic:
rw [uniformContinuous₂_def, AbstractCompletion.extend₂, uncurry_curry]
theorem uniformContinuous_extension₂ : UniformContinuous₂ (pkg.extend₂ pkg' f) := by
  rw [uniformContinuous₂_def, AbstractCompletion.extend₂, uncurry_curry]
  

Proof state:
α : Type u_1
inst✝³ : UniformSpace α
pkg : AbstractCompletion α
β : Type u_2
inst✝² : UniformSpace β
pkg' : AbstractCompletion β
γ : Type u_3
inst✝¹ : UniformSpace γ
f : α → β → γ
inst✝ : CompleteSpace γ
⊢ UniformContinuous (AbstractCompletion.extend (AbstractCompletion.prod pkg pkg') (uncurry f))

Next tactic:
apply uniformContinuous_extend
lemma toNat_ofNat_of_lt {m} (h : m < 2^w) : (BitVec.ofNat w m).toNat = m := by
  

Proof state:
w v m : ℕ
h : m < 2 ^ w
⊢ BitVec.toNat m#w = m

Next tactic:
simp only [toNat_ofNat, mod_eq_of_lt h]
theorem toNat_extractLsb' {i j} {x : BitVec w} :
    (extractLsb' i j x).toNat = x.toNat / 2 ^ i % (2 ^ j) := by
  

Proof state:
w v i j : ℕ
x : BitVec w
⊢ BitVec.toNat (extractLsb' i j x) = BitVec.toNat x / 2 ^ i % 2 ^ j

Next tactic:
simp only [extractLsb', toNat_ofNat, shiftRight_eq_div_pow]
theorem addLsb_eq_twice_add_one {x b} : addLsb x b = 2 * x + cond b 1 0 := by
  

Proof state:
w v x : ℕ
b : Bool
⊢ addLsb x b = 2 * x + bif b then 1 else 0

Next tactic:
simp [addLsb, two_mul]
theorem addLsb_eq_twice_add_one {x b} : addLsb x b = 2 * x + cond b 1 0 := by
  simp [addLsb, two_mul]; 

Proof state:
w v x : ℕ
b : Bool
⊢ bit b x = x + x + bif b then 1 else 0

Next tactic:
cases b
theorem addLsb_eq_twice_add_one {x b} : addLsb x b = 2 * x + cond b 1 0 := by
  simp [addLsb, two_mul]; cases b <;> 

Proof state:
case false
w v x : ℕ
⊢ bit false x = x + x + bif false then 1 else 0

Next tactic:
rfl
theorem addLsb_eq_twice_add_one {x b} : addLsb x b = 2 * x + cond b 1 0 := by
  simp [addLsb, two_mul]; cases b <;> 

Proof state:
case true
w v x : ℕ
⊢ bit true x = x + x + bif true then 1 else 0

Next tactic:
rfl
theorem toNat_lt {n : ℕ} (v : BitVec n) : v.toNat < 2 ^ n := by
  

Proof state:
w v✝ n : ℕ
v : BitVec n
⊢ BitVec.toNat v < 2 ^ n

Next tactic:
exact v.toFin.2
theorem addLsb_div_two {x b} : addLsb x b / 2 = x := by
  

Proof state:
w v x : ℕ
b : Bool
⊢ addLsb x b / 2 = x

Next tactic:
rw [addLsb, ← Nat.div2_val, Nat.div2_bit]
theorem decide_addLsb_mod_two {x b} : decide (addLsb x b % 2 = 1) = b := by
  

Proof state:
w v x : ℕ
b : Bool
⊢ decide (addLsb x b % 2 = 1) = b

Next tactic:
simp [addLsb]
lemma ofNat_toNat' (x : BitVec w) : (x.toNat)#w = x := by
  

Proof state:
w v : ℕ
x : BitVec w
⊢ (BitVec.toNat x)#w = x

Next tactic:
rw [ofNat_toNat, truncate_eq]
lemma ofNat_toNat_of_eq (x : BitVec w) (h : w = v):
    BitVec.ofNat v x.toNat = x.cast h := by
  

Proof state:
w v : ℕ
x : BitVec w
h : w = v
⊢ (BitVec.toNat x)#v = cast h x

Next tactic:
cases h
lemma ofNat_toNat_of_eq (x : BitVec w) (h : w = v):
    BitVec.ofNat v x.toNat = x.cast h := by
  cases h; 

Proof state:
case refl
w : ℕ
x : BitVec w
⊢ (BitVec.toNat x)#w = cast (_ : w = w) x

Next tactic:
rw [ofNat_toNat', cast_eq]
theorem toFin_val {n : ℕ} (v : BitVec n) : (toFin v : ℕ) = v.toNat := by
  

Proof state:
w v✝ n : ℕ
v : BitVec n
⊢ ↑v.toFin = BitVec.toNat v

Next tactic:
rfl
theorem toFin_le_toFin_of_le {n} {v₀ v₁ : BitVec n} (h : v₀ ≤ v₁) : v₀.toFin ≤ v₁.toFin :=
  show (v₀.toFin : ℕ) ≤ v₁.toFin by
    

Proof state:
w v n : ℕ
v₀ v₁ : BitVec n
h : v₀ ≤ v₁
⊢ ↑v₀.toFin ≤ ↑v₁.toFin

Next tactic:
rw [toFin_val, toFin_val]
theorem toFin_le_toFin_of_le {n} {v₀ v₁ : BitVec n} (h : v₀ ≤ v₁) : v₀.toFin ≤ v₁.toFin :=
  show (v₀.toFin : ℕ) ≤ v₁.toFin by
    rw [toFin_val, toFin_val]
    

Proof state:
w v n : ℕ
v₀ v₁ : BitVec n
h : v₀ ≤ v₁
⊢ BitVec.toNat v₀ ≤ BitVec.toNat v₁

Next tactic:
exact h
theorem ofFin_le_ofFin_of_le {n : ℕ} {i j : Fin (2 ^ n)} (h : i ≤ j) : ofFin i ≤ ofFin j := by
  

Proof state:
w v n : ℕ
i j : Fin (2 ^ n)
h : i ≤ j
⊢ { toFin := i } ≤ { toFin := j }

Next tactic:
exact h
theorem toFin_ofFin {n} (i : Fin <| 2 ^ n) : (ofFin i).toFin = i :=
  Fin.eq_of_veq (by 

Proof state:
w v n : ℕ
i : Fin (2 ^ n)
⊢ ↑{ toFin := i }.toFin = ↑i

Next tactic:
simp [toFin_val, ofFin, toNat_ofNat, Nat.mod_eq_of_lt, i.is_lt]
theorem ofFin_toFin {n} (v : BitVec n) : ofFin (toFin v) = v := by
  

Proof state:
w v✝ n : ℕ
v : BitVec n
⊢ { toFin := v.toFin } = v

Next tactic:
rfl
@[simp] lemma ofFin_neg : ofFin (-x) = -(ofFin x) := by
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
⊢ { toFin := -x } = -{ toFin := x }

Next tactic:
rw [neg_eq_zero_sub]
@[simp] lemma ofFin_neg : ofFin (-x) = -(ofFin x) := by
  rw [neg_eq_zero_sub]; 

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
⊢ { toFin := 0 - x } = -{ toFin := x }

Next tactic:
rfl
@[simp] lemma ofFin_and : ofFin (x &&& y) = ofFin x &&& ofFin y := by
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
⊢ { toFin := x &&& y } = { toFin := x } &&& { toFin := y }

Next tactic:
simp only [HAnd.hAnd, AndOp.and, Fin.land, BitVec.and, toNat_ofFin, ofFin.injEq, Fin.mk.injEq]
@[simp] lemma ofFin_and : ofFin (x &&& y) = ofFin x &&& ofFin y := by
  simp only [HAnd.hAnd, AndOp.and, Fin.land, BitVec.and, toNat_ofFin, ofFin.injEq, Fin.mk.injEq]
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
⊢ land ↑x ↑y % 2 ^ w = land ↑x ↑y

Next tactic:
exact mod_eq_of_lt (Nat.and_lt_two_pow _ y.prop)
@[simp] lemma ofFin_or  : ofFin (x ||| y) = ofFin x ||| ofFin y := by
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
⊢ { toFin := x ||| y } = { toFin := x } ||| { toFin := y }

Next tactic:
simp only [HOr.hOr, OrOp.or, Fin.lor, BitVec.or, toNat_ofFin, ofFin.injEq, Fin.mk.injEq]
@[simp] lemma ofFin_or  : ofFin (x ||| y) = ofFin x ||| ofFin y := by
  simp only [HOr.hOr, OrOp.or, Fin.lor, BitVec.or, toNat_ofFin, ofFin.injEq, Fin.mk.injEq]
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
⊢ lor ↑x ↑y % 2 ^ w = lor ↑x ↑y

Next tactic:
exact mod_eq_of_lt (Nat.or_lt_two_pow x.prop y.prop)
@[simp] lemma ofFin_xor : ofFin (x ^^^ y) = ofFin x ^^^ ofFin y := by
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
⊢ { toFin := x ^^^ y } = { toFin := x } ^^^ { toFin := y }

Next tactic:
simp only [HXor.hXor, Xor.xor, Fin.xor, BitVec.xor, toNat_ofFin, ofFin.injEq, Fin.mk.injEq]
@[simp] lemma ofFin_xor : ofFin (x ^^^ y) = ofFin x ^^^ ofFin y := by
  simp only [HXor.hXor, Xor.xor, Fin.xor, BitVec.xor, toNat_ofFin, ofFin.injEq, Fin.mk.injEq]
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
⊢ Nat.xor ↑x ↑y % 2 ^ w = Nat.xor ↑x ↑y

Next tactic:
exact mod_eq_of_lt (Nat.xor_lt_two_pow x.prop y.prop)
lemma ofFin_one  : ofFin (1 : Fin (2^w)) = 1 := by
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
⊢ { toFin := 1 } = 1

Next tactic:
simp only [OfNat.ofNat, BitVec.ofNat, and_pow_two_is_mod]
lemma ofFin_one  : ofFin (1 : Fin (2^w)) = 1 := by
  simp only [OfNat.ofNat, BitVec.ofNat, and_pow_two_is_mod]
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
⊢ { toFin := Fin.ofNat' 1 (_ : 0 < 2 ^ w) } = { toFin := { val := 1 % 2 ^ w, isLt := (_ : 1 % 2 ^ w < 2 ^ w) } }

Next tactic:
rfl
@[simp] lemma ofFin_natCast (n : ℕ) : ofFin (n : Fin (2^w)) = n := by
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
n : ℕ
⊢ { toFin := ↑n } = ↑n

Next tactic:
simp only [Nat.cast, NatCast.natCast, OfNat.ofNat, BitVec.ofNat, and_pow_two_is_mod]
@[simp] lemma ofFin_natCast (n : ℕ) : ofFin (n : Fin (2^w)) = n := by
  simp only [Nat.cast, NatCast.natCast, OfNat.ofNat, BitVec.ofNat, and_pow_two_is_mod]
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
n : ℕ
⊢ { toFin := Fin.ofNat'' n } = { toFin := { val := n % 2 ^ w, isLt := (_ : n % 2 ^ w < 2 ^ w) } }

Next tactic:
rfl
@[simp] lemma ofFin_ofNat (n : ℕ) :
    ofFin (no_index (OfNat.ofNat n : Fin (2^w))) = OfNat.ofNat n := by
  

Proof state:
w v : ℕ
x y : Fin (2 ^ w)
n : ℕ
⊢ { toFin := OfNat.ofNat n } = OfNat.ofNat n

Next tactic:
simp only [OfNat.ofNat, Fin.ofNat', BitVec.ofNat, and_pow_two_is_mod]
@[simp] lemma toFin_neg : toFin (-x) = -(toFin x) := by
  

Proof state:
w v : ℕ
x y : BitVec w
⊢ (-x).toFin = -x.toFin

Next tactic:
rw [neg_eq_zero_sub]
@[simp] lemma toFin_neg : toFin (-x) = -(toFin x) := by
  rw [neg_eq_zero_sub]; 

Proof state:
w v : ℕ
x y : BitVec w
⊢ (-x).toFin = 0 - x.toFin

Next tactic:
rfl
@[simp] lemma toFin_and : toFin (x &&& y) = toFin x &&& toFin y := by
  

Proof state:
w v : ℕ
x y : BitVec w
⊢ (x &&& y).toFin = x.toFin &&& y.toFin

Next tactic:
apply toFin_inj.mpr
@[simp] lemma toFin_and : toFin (x &&& y) = toFin x &&& toFin y := by
  apply toFin_inj.mpr; 

Proof state:
w v : ℕ
x y : BitVec w
⊢ x &&& y = { toFin := x.toFin &&& y.toFin }

Next tactic:
simp only [ofFin_and]
@[simp] lemma toFin_or  : toFin (x ||| y) = toFin x ||| toFin y := by
  

Proof state:
w v : ℕ
x y : BitVec w
⊢ (x ||| y).toFin = x.toFin ||| y.toFin

Next tactic:
apply toFin_inj.mpr
@[simp] lemma toFin_or  : toFin (x ||| y) = toFin x ||| toFin y := by
  apply toFin_inj.mpr; 

Proof state:
w v : ℕ
x y : BitVec w
⊢ x ||| y = { toFin := x.toFin ||| y.toFin }

Next tactic:
simp only [ofFin_or]
@[simp] lemma toFin_xor : toFin (x ^^^ y) = toFin x ^^^ toFin y := by
  

Proof state:
w v : ℕ
x y : BitVec w
⊢ (x ^^^ y).toFin = x.toFin ^^^ y.toFin

Next tactic:
apply toFin_inj.mpr
@[simp] lemma toFin_xor : toFin (x ^^^ y) = toFin x ^^^ toFin y := by
  apply toFin_inj.mpr; 

Proof state:
w v : ℕ
x y : BitVec w
⊢ x ^^^ y = { toFin := x.toFin ^^^ y.toFin }

Next tactic:
simp only [ofFin_xor]
lemma toFin_one  : toFin (1 : BitVec w) = 1 := by
  

Proof state:
w v : ℕ
x y : BitVec w
⊢ 1.toFin = 1

Next tactic:
apply toFin_inj.mpr
lemma toFin_one  : toFin (1 : BitVec w) = 1 := by
  apply toFin_inj.mpr; 

Proof state:
w v : ℕ
x y : BitVec w
⊢ 1 = { toFin := 1 }

Next tactic:
simp only [ofNat_eq_ofNat, ofFin_ofNat]
@[simp] lemma toFin_natCast (n : ℕ) : toFin (n : BitVec w) = n := by
  

Proof state:
w v : ℕ
x y : BitVec w
n : ℕ
⊢ (↑n).toFin = ↑n

Next tactic:
apply toFin_inj.mpr
@[simp] lemma toFin_natCast (n : ℕ) : toFin (n : BitVec w) = n := by
  apply toFin_inj.mpr; 

Proof state:
w v : ℕ
x y : BitVec w
n : ℕ
⊢ ↑n = { toFin := NatCast.natCast n }

Next tactic:
simp only [ofFin_natCast]
lemma toFin_ofNat (n : ℕ) :
    toFin (no_index (OfNat.ofNat n : BitVec w)) = OfNat.ofNat n := by
  

Proof state:
w v : ℕ
x y : BitVec w
n : ℕ
⊢ (OfNat.ofNat n).toFin = OfNat.ofNat n

Next tactic:
simp only [OfNat.ofNat, BitVec.ofNat, and_pow_two_is_mod, Fin.ofNat']
@[norm_cast, simp]
theorem Nat.dist_cast_rat (x y : ℕ) : dist (x : ℚ) y = dist x y := by
  

Proof state:
x y : ℕ
⊢ dist ↑x ↑y = dist x y

Next tactic:
rw [← Nat.dist_cast_real, ← Rat.dist_cast]
@[norm_cast, simp]
theorem Nat.dist_cast_rat (x y : ℕ) : dist (x : ℚ) y = dist x y := by
  rw [← Nat.dist_cast_real, ← Rat.dist_cast]; 

Proof state:
x y : ℕ
⊢ dist ↑↑x ↑↑y = dist ↑x ↑y

Next tactic:
congr
theorem Nat.uniformEmbedding_coe_rat : UniformEmbedding ((↑) : ℕ → ℚ) :=
  uniformEmbedding_bot_of_pairwise_le_dist zero_lt_one <| by 

Proof state:
⊢ Pairwise fun x y => 1 ≤ dist ↑x ↑y

Next tactic:
simpa using Nat.pairwise_one_le_dist
theorem Nat.closedEmbedding_coe_rat : ClosedEmbedding ((↑) : ℕ → ℚ) :=
  closedEmbedding_of_pairwise_le_dist zero_lt_one <| by 

Proof state:
⊢ Pairwise fun x y => 1 ≤ dist ↑x ↑y

Next tactic:
simpa using Nat.pairwise_one_le_dist
@[norm_cast, simp]
theorem Int.dist_cast_rat (x y : ℤ) : dist (x : ℚ) y = dist x y := by
  

Proof state:
x y : ℤ
⊢ dist ↑x ↑y = dist x y

Next tactic:
rw [← Int.dist_cast_real, ← Rat.dist_cast]
@[norm_cast, simp]
theorem Int.dist_cast_rat (x y : ℤ) : dist (x : ℚ) y = dist x y := by
  rw [← Int.dist_cast_real, ← Rat.dist_cast]; 

Proof state:
x y : ℤ
⊢ dist ↑↑x ↑↑y = dist ↑x ↑y

Next tactic:
congr
theorem Int.uniformEmbedding_coe_rat : UniformEmbedding ((↑) : ℤ → ℚ) :=
  uniformEmbedding_bot_of_pairwise_le_dist zero_lt_one <| by 

Proof state:
⊢ Pairwise fun x y => 1 ≤ dist ↑x ↑y

Next tactic:
simpa using Int.pairwise_one_le_dist
theorem Int.closedEmbedding_coe_rat : ClosedEmbedding ((↑) : ℤ → ℚ) :=
  closedEmbedding_of_pairwise_le_dist zero_lt_one <| by 

Proof state:
⊢ Pairwise fun x y => 1 ≤ dist ↑x ↑y

Next tactic:
simpa using Int.pairwise_one_le_dist
theorem uniformContinuous_add : UniformContinuous fun p : ℚ × ℚ => p.1 + p.2 :=
  Rat.uniformEmbedding_coe_real.toUniformInducing.uniformContinuous_iff.2 <| by
    

Proof state:
⊢ UniformContinuous (Rat.cast ∘ fun p => p.1 + p.2)

Next tactic:
simp only [(· ∘ ·), Rat.cast_add]
theorem uniformContinuous_add : UniformContinuous fun p : ℚ × ℚ => p.1 + p.2 :=
  Rat.uniformEmbedding_coe_real.toUniformInducing.uniformContinuous_iff.2 <| by
    simp only [(· ∘ ·), Rat.cast_add]
    

Proof state:
⊢ UniformContinuous fun x => ↑x.1 + ↑x.2

Next tactic:
exact Real.uniformContinuous_add.comp
      (Rat.uniformContinuous_coe_real.prod_map Rat.uniformContinuous_coe_real)
theorem uniformContinuous_neg : UniformContinuous (@Neg.neg ℚ _) :=
  Metric.uniformContinuous_iff.2 fun ε ε0 =>
    ⟨_, ε0, fun h => by 

Proof state:
ε : ℝ
ε0 : ε > 0
a✝ b✝ : ℚ
h : dist a✝ b✝ < ε
⊢ dist (-a✝) (-b✝) < ε

Next tactic:
rw [dist_comm] at h
theorem uniformContinuous_neg : UniformContinuous (@Neg.neg ℚ _) :=
  Metric.uniformContinuous_iff.2 fun ε ε0 =>
    ⟨_, ε0, fun h => by rw [dist_comm] at h; 

Proof state:
ε : ℝ
ε0 : ε > 0
a✝ b✝ : ℚ
h : dist b✝ a✝ < ε
⊢ dist (-a✝) (-b✝) < ε

Next tactic:
simpa only [dist_eq, cast_neg, neg_sub_neg] using h
theorem uniformContinuous_abs : UniformContinuous (abs : ℚ → ℚ) :=
  Metric.uniformContinuous_iff.2 fun ε ε0 =>
    ⟨ε, ε0, fun h =>
      lt_of_le_of_lt (by 

Proof state:
ε : ℝ
ε0 : ε > 0
a✝ b✝ : ℚ
h : dist a✝ b✝ < ε
⊢ dist |a✝| |b✝| ≤ dist a✝ b✝

Next tactic:
simpa [Rat.dist_eq] using abs_abs_sub_abs_le_abs_sub _ _
nonrec theorem totallyBounded_Icc (a b : ℚ) : TotallyBounded (Icc a b) := by
  

Proof state:
a b : ℚ
⊢ TotallyBounded (Icc a b)

Next tactic:
simpa only [preimage_cast_Icc] using
    totallyBounded_preimage Rat.uniformEmbedding_coe_real (totallyBounded_Icc (a : ℝ) b)
/-- The divisors of a product of natural numbers are the pointwise product of the divisors of the
factors. -/
lemma Nat.divisors_mul (m n : ℕ) : divisors (m * n) = divisors m * divisors n := by
  

Proof state:
m n : ℕ
⊢ divisors (m * n) = divisors m * divisors n

Next tactic:
ext k
/-- The divisors of a product of natural numbers are the pointwise product of the divisors of the
factors. -/
lemma Nat.divisors_mul (m n : ℕ) : divisors (m * n) = divisors m * divisors n := by
  ext k
  

Proof state:
case a
m n k : ℕ
⊢ k ∈ divisors (m * n) ↔ k ∈ divisors m * divisors n

Next tactic:
simp_rw [mem_mul, mem_divisors, dvd_mul, mul_ne_zero_iff, ← exists_and_right]
/-- The divisors of a product of natural numbers are the pointwise product of the divisors of the
factors. -/
lemma Nat.divisors_mul (m n : ℕ) : divisors (m * n) = divisors m * divisors n := by
  ext k
  simp_rw [mem_mul, mem_divisors, dvd_mul, mul_ne_zero_iff, ← exists_and_right]
  

Proof state:
case a
m n k : ℕ
⊢ (∃ x x_1, (x ∣ m ∧ x_1 ∣ n ∧ x * x_1 = k) ∧ m ≠ 0 ∧ n ≠ 0) ↔ ∃ y z, (y ∣ m ∧ m ≠ 0) ∧ (z ∣ n ∧ n ≠ 0) ∧ y * z = k

Next tactic:
simp only [and_assoc, and_comm, and_left_comm]
lemma Nat.Prime.divisors_sq {p : ℕ} (hp : p.Prime) : (p ^ 2).divisors = {p ^ 2, p, 1} := by
  

Proof state:
p : ℕ
hp : Prime p
⊢ Nat.divisors (p ^ 2) = {p ^ 2, p, 1}

Next tactic:
simp [divisors_prime_pow hp, range_succ]
@[simp]
theorem dist_eq_zero_iff_eq_or_not_reachable {u v : V} :
    G.dist u v = 0 ↔ u = v ∨ ¬G.Reachable u v := by 

Proof state:
V : Type u_1
G : SimpleGraph V
u v : V
⊢ dist G u v = 0 ↔ u = v ∨ ¬Reachable G u v

Next tactic:
simp [dist, Nat.sInf_eq_zero, Reachable]
theorem dist_self {v : V} : dist G v v = 0 := by 

Proof state:
V : Type u_1
G : SimpleGraph V
v : V
⊢ dist G v v = 0

Next tactic:
simp
protected theorem Reachable.dist_eq_zero_iff {u v : V} (hr : G.Reachable u v) :
    G.dist u v = 0 ↔ u = v := by 

Proof state:
V : Type u_1
G : SimpleGraph V
u v : V
hr : Reachable G u v
⊢ dist G u v = 0 ↔ u = v

Next tactic:
simp [hr]
protected theorem Reachable.pos_dist_of_ne {u v : V} (h : G.Reachable u v) (hne : u ≠ v) :
    0 < G.dist u v :=
  Nat.pos_of_ne_zero (by 

Proof state:
V : Type u_1
G : SimpleGraph V
u v : V
h : Reachable G u v
hne : u ≠ v
⊢ dist G u v ≠ 0

Next tactic:
simp [h, hne]
protected theorem Connected.dist_eq_zero_iff (hconn : G.Connected) {u v : V} :
    G.dist u v = 0 ↔ u = v := by 

Proof state:
V : Type u_1
G : SimpleGraph V
hconn : Connected G
u v : V
⊢ dist G u v = 0 ↔ u = v

Next tactic:
simp [hconn u v]
protected theorem Connected.pos_dist_of_ne {u v : V} (hconn : G.Connected) (hne : u ≠ v) :
    0 < G.dist u v :=
  Nat.pos_of_ne_zero (by 

Proof state:
V : Type u_1
G : SimpleGraph V
u v : V
hconn : Connected G
hne : u ≠ v
⊢ dist G u v ≠ 0

Next tactic:
intro h
protected theorem Connected.pos_dist_of_ne {u v : V} (hconn : G.Connected) (hne : u ≠ v) :
    0 < G.dist u v :=
  Nat.pos_of_ne_zero (by intro h; 

Proof state:
V : Type u_1
G : SimpleGraph V
u v : V
hconn : Connected G
hne : u ≠ v
h : dist G u v = 0
⊢ False

Next tactic:
exact False.elim (hne (hconn.dist_eq_zero_iff.mp h))
theorem dist_eq_zero_of_not_reachable {u v : V} (h : ¬G.Reachable u v) : G.dist u v = 0 := by
  

Proof state:
V : Type u_1
G : SimpleGraph V
u v : V
h : ¬Reachable G u v
⊢ dist G u v = 0

Next tactic:
simp [h]
theorem nonempty_of_pos_dist {u v : V} (h : 0 < G.dist u v) :
    (Set.univ : Set (G.Walk u v)).Nonempty := by
  

Proof state:
V : Type u_1
G : SimpleGraph V
u v : V
h : 0 < dist G u v
⊢ Set.Nonempty Set.univ

Next tactic:
simpa [Set.range_nonempty_iff_nonempty, Set.nonempty_iff_univ_nonempty] using
    Nat.nonempty_of_pos_sInf h
protected theorem Connected.dist_triangle (hconn : G.Connected) {u v w : V} :
    G.dist u w ≤ G.dist u v + G.dist v w := by
  

Proof state:
V : Type u_1
G : SimpleGraph V
hconn : Connected G
u v w : V
⊢ dist G u w ≤ dist G u v + dist G v w

Next tactic:
obtain ⟨p, hp⟩ := hconn.exists_walk_of_dist u v
protected theorem Connected.dist_triangle (hconn : G.Connected) {u v w : V} :
    G.dist u w ≤ G.dist u v + G.dist v w := by
  obtain ⟨p, hp⟩ := hconn.exists_walk_of_dist u v
  

Proof state:
case intro
V : Type u_1
G : SimpleGraph V
hconn : Connected G
u v w : V
p : Walk G u v
hp : Walk.length p = dist G u v
⊢ dist G u w ≤ dist G u v + dist G v w

Next tactic:
obtain ⟨q, hq⟩ := hconn.exists_walk_of_dist v w
protected theorem Connected.dist_triangle (hconn : G.Connected) {u v w : V} :
    G.dist u w ≤ G.dist u v + G.dist v w := by
  obtain ⟨p, hp⟩ := hconn.exists_walk_of_dist u v
  obtain ⟨q, hq⟩ := hconn.exists_walk_of_dist v w
  

Proof state:
case intro.intro
V : Type u_1
G : SimpleGraph V
hconn : Connected G
u v w : V
p : Walk G u v
hp : Walk.length p = dist G u v
q : Walk G v w
hq : Walk.length q = dist G v w
⊢ dist G u w ≤ dist G u v + dist G v w

Next tactic:
rw [← hp, ← hq, ← Walk.length_append]
protected theorem Connected.dist_triangle (hconn : G.Connected) {u v w : V} :
    G.dist u w ≤ G.dist u v + G.dist v w := by
  obtain ⟨p, hp⟩ := hconn.exists_walk_of_dist u v
  obtain ⟨q, hq⟩ := hconn.exists_walk_of_dist v w
  rw [← hp, ← hq, ← Walk.length_append]
  

Proof state:
case intro.intro
V : Type u_1
G : SimpleGraph V
hconn : Connected G
u v w : V
p : Walk G u v
hp : Walk.length p = dist G u v
q : Walk G v w
hq : Walk.length q = dist G v w
⊢ dist G u w ≤ Walk.length (Walk.append p q)

Next tactic:
apply dist_le
private theorem dist_comm_aux {u v : V} (h : G.Reachable u v) : G.dist u v ≤ G.dist v u := by
  

Proof state:
V : Type u_1
G : SimpleGraph V
u v : V
h : Reachable G u v
⊢ dist G u v ≤ dist G v u

Next tactic:
obtain ⟨p, hp⟩ := h.symm.exists_walk_of_dist
private theorem dist_comm_aux {u v : V} (h : G.Reachable u v) : G.dist u v ≤ G.dist v u := by
  obtain ⟨p, hp⟩ := h.symm.exists_walk_of_dist
  

Proof state:
case intro
V : Type u_1
G : SimpleGraph V
u v : V
h : Reachable G u v
p : Walk G v u
hp : Walk.length p = dist G v u
⊢ dist G u v ≤ dist G v u

Next tactic:
rw [← hp, ← Walk.length_reverse]
private theorem dist_comm_aux {u v : V} (h : G.Reachable u v) : G.dist u v ≤ G.dist v u := by
  obtain ⟨p, hp⟩ := h.symm.exists_walk_of_dist
  rw [← hp, ← Walk.length_reverse]
  

Proof state:
case intro
V : Type u_1
G : SimpleGraph V
u v : V
h : Reachable G u v
p : Walk G v u
hp : Walk.length p = dist G v u
⊢ dist G u v ≤ Walk.length (Walk.reverse p)

Next tactic:
apply dist_le
theorem dist_comm {u v : V} : G.dist u v = G.dist v u := by
  

Proof state:
V : Type u_1
G : SimpleGraph V
u v : V
⊢ dist G u v = dist G v u

Next tactic:
by_cases h : G.Reachable u v
theorem dist_comm {u v : V} : G.dist u v = G.dist v u := by
  by_cases h : G.Reachable u v
  · 

Proof state:
case pos
V : Type u_1
G : SimpleGraph V
u v : V
h : Reachable G u v
⊢ dist G u v = dist G v u

Next tactic:
apply le_antisymm (dist_comm_aux h) (dist_comm_aux h.symm)
theorem dist_comm {u v : V} : G.dist u v = G.dist v u := by
  by_cases h : G.Reachable u v
  · apply le_antisymm (dist_comm_aux h) (dist_comm_aux h.symm)
  · 

Proof state:
case neg
V : Type u_1
G : SimpleGraph V
u v : V
h : ¬Reachable G u v
⊢ dist G u v = dist G v u

Next tactic:
have h' : ¬G.Reachable v u := fun h' => absurd h'.symm h
theorem dist_comm {u v : V} : G.dist u v = G.dist v u := by
  by_cases h : G.Reachable u v
  · apply le_antisymm (dist_comm_aux h) (dist_comm_aux h.symm)
  · have h' : ¬G.Reachable v u := fun h' => absurd h'.symm h
    

Proof state:
case neg
V : Type u_1
G : SimpleGraph V
u v : V
h : ¬Reachable G u v
h' : ¬Reachable G v u
⊢ dist G u v = dist G v u

Next tactic:
simp [h, h', dist_eq_zero_of_not_reachable]
@[simp]
theorem units_natAbs (u : ℤˣ) : natAbs u = 1 :=
  Units.ext_iff.1 <|
    Nat.units_eq_one
      ⟨natAbs u, natAbs ↑u⁻¹, by 

Proof state:
u : ℤˣ
⊢ natAbs ↑u * natAbs ↑u⁻¹ = 1

Next tactic:
rw [← natAbs_mul, Units.mul_inv]
@[simp]
theorem units_natAbs (u : ℤˣ) : natAbs u = 1 :=
  Units.ext_iff.1 <|
    Nat.units_eq_one
      ⟨natAbs u, natAbs ↑u⁻¹, by rw [← natAbs_mul, Units.mul_inv]; 

Proof state:
u : ℤˣ
⊢ natAbs 1 = 1

Next tactic:
rfl
@[simp]
theorem units_natAbs (u : ℤˣ) : natAbs u = 1 :=
  Units.ext_iff.1 <|
    Nat.units_eq_one
      ⟨natAbs u, natAbs ↑u⁻¹, by rw [← natAbs_mul, Units.mul_inv]; rfl, by
        

Proof state:
u : ℤˣ
⊢ natAbs ↑u⁻¹ * natAbs ↑u = 1

Next tactic:
rw [← natAbs_mul, Units.inv_mul]
@[simp]
theorem units_natAbs (u : ℤˣ) : natAbs u = 1 :=
  Units.ext_iff.1 <|
    Nat.units_eq_one
      ⟨natAbs u, natAbs ↑u⁻¹, by rw [← natAbs_mul, Units.mul_inv]; rfl, by
        rw [← natAbs_mul, Units.inv_mul]; 

Proof state:
u : ℤˣ
⊢ natAbs 1 = 1

Next tactic:
rfl
theorem units_eq_one_or (u : ℤˣ) : u = 1 ∨ u = -1 := by
  

Proof state:
u : ℤˣ
⊢ u = 1 ∨ u = -1

Next tactic:
simpa only [Units.ext_iff, units_natAbs] using natAbs_eq u
@[simp]
theorem units_ne_neg_self (u : ℤˣ) : u ≠ -u := by
  

Proof state:
u : ℤˣ
⊢ u ≠ -u

Next tactic:
rcases units_eq_one_or u with rfl | rfl
@[simp]
theorem units_ne_neg_self (u : ℤˣ) : u ≠ -u := by
  rcases units_eq_one_or u with rfl | rfl <;> 

Proof state:
case inl
⊢ 1 ≠ -1

Next tactic:
decide
@[simp]
theorem units_ne_neg_self (u : ℤˣ) : u ≠ -u := by
  rcases units_eq_one_or u with rfl | rfl <;> 

Proof state:
case inr
⊢ -1 ≠ - -1

Next tactic:
decide
theorem units_ne_iff_eq_neg {u u' : ℤˣ} : u ≠ u' ↔ u = -u' := by
  

Proof state:
u u' : ℤˣ
⊢ u ≠ u' ↔ u = -u'

Next tactic:
rcases units_eq_one_or u with rfl | rfl
theorem units_ne_iff_eq_neg {u u' : ℤˣ} : u ≠ u' ↔ u = -u' := by
  rcases units_eq_one_or u with rfl | rfl <;>
  

Proof state:
case inl
u' : ℤˣ
⊢ 1 ≠ u' ↔ 1 = -u'

Next tactic:
rcases units_eq_one_or u' with rfl | rfl