/-
Copyright (c) 2019 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Chris Hughes
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.data.matrix.basic
import Mathlib.data.pequiv
import Mathlib.PostPort

universes u_3 u_4 v u_2 u_1

namespace Mathlib

/-
# partial equivalences for matrices

Using partial equivalences to represent matrices.
This file introduces the function `pequiv.to_matrix`, which returns a matrix containing ones and
zeros. For any partial equivalence `f`, `f.to_matrix i j = 1 ↔ f i = some j`.

The following important properties of this function are proved
`to_matrix_trans : (f.trans g).to_matrix = f.to_matrix ⬝ g.to_matrix`
`to_matrix_symm  : f.symm.to_matrix = f.to_matrixᵀ`
`to_matrix_refl : (pequiv.refl n).to_matrix = 1`
`to_matrix_bot : ⊥.to_matrix = 0`

This theory gives the matrix representation of projection linear maps, and their right inverses.
For example, the matrix `(single (0 : fin 1) (i : fin n)).to_matrix` corresponds to the the ith
projection map from R^n to R.

Any injective function `fin m → fin n` gives rise to a `pequiv`, whose matrix is the projection
map from R^m → R^n represented by the same function. The transpose of this matrix is the right
inverse of this map, sending anything not in the image to zero.

## notations

This file uses the notation ` ⬝ ` for `matrix.mul` and `ᵀ` for `matrix.transpose`.
-/

namespace pequiv

/-- `to_matrix` returns a matrix containing ones and zeros. `f.to_matrix i j` is `1` if
  `f i = some j` and `0` otherwise -/
def to_matrix {m : Type u_3} {n : Type u_4} [fintype m] [fintype n] {α : Type v} [DecidableEq n]
    [HasZero α] [HasOne α] (f : m ≃. n) : matrix m n α :=
  sorry

theorem mul_matrix_apply {l : Type u_2} {m : Type u_3} {n : Type u_4} [fintype l] [fintype m]
    [fintype n] {α : Type v} [DecidableEq m] [semiring α] (f : l ≃. m) (M : matrix m n α) (i : l)
    (j : n) :
    matrix.mul (to_matrix f) M i j = option.cases_on (coe_fn f i) 0 fun (fi : m) => M fi j :=
  sorry

theorem to_matrix_symm {m : Type u_3} {n : Type u_4} [fintype m] [fintype n] {α : Type v}
    [DecidableEq m] [DecidableEq n] [HasZero α] [HasOne α] (f : m ≃. n) :
    to_matrix (pequiv.symm f) = matrix.transpose (to_matrix f) :=
  sorry

@[simp] theorem to_matrix_refl {n : Type u_4} [fintype n] {α : Type v} [DecidableEq n] [HasZero α]
    [HasOne α] : to_matrix (pequiv.refl n) = 1 :=
  sorry

theorem matrix_mul_apply {l : Type u_2} {m : Type u_3} {n : Type u_4} [fintype l] [fintype m]
    [fintype n] {α : Type v} [semiring α] [DecidableEq n] (M : matrix l m α) (f : m ≃. n) (i : l)
    (j : n) :
    matrix.mul M (to_matrix f) i j =
        option.cases_on (coe_fn (pequiv.symm f) j) 0 fun (fj : m) => M i fj :=
  sorry

theorem to_pequiv_mul_matrix {m : Type u_3} {n : Type u_4} [fintype m] [fintype n] {α : Type v}
    [DecidableEq m] [semiring α] (f : m ≃ m) (M : matrix m n α) :
    matrix.mul (to_matrix (equiv.to_pequiv f)) M = fun (i : m) => M (coe_fn f i) :=
  sorry

theorem to_matrix_trans {l : Type u_2} {m : Type u_3} {n : Type u_4} [fintype l] [fintype m]
    [fintype n] {α : Type v} [DecidableEq m] [DecidableEq n] [semiring α] (f : l ≃. m)
    (g : m ≃. n) : to_matrix (pequiv.trans f g) = matrix.mul (to_matrix f) (to_matrix g) :=
  sorry

@[simp] theorem to_matrix_bot {m : Type u_3} {n : Type u_4} [fintype m] [fintype n] {α : Type v}
    [DecidableEq n] [HasZero α] [HasOne α] : to_matrix ⊥ = 0 :=
  rfl

theorem to_matrix_injective {m : Type u_3} {n : Type u_4} [fintype m] [fintype n] {α : Type v}
    [DecidableEq n] [monoid_with_zero α] [nontrivial α] : function.injective to_matrix :=
  sorry

theorem to_matrix_swap {n : Type u_4} [fintype n] {α : Type v} [DecidableEq n] [ring α] (i : n)
    (j : n) :
    to_matrix (equiv.to_pequiv (equiv.swap i j)) =
        1 - to_matrix (single i i) - to_matrix (single j j) + to_matrix (single i j) +
          to_matrix (single j i) :=
  sorry

@[simp] theorem single_mul_single {k : Type u_1} {m : Type u_3} {n : Type u_4} [fintype k]
    [fintype m] [fintype n] {α : Type v} [DecidableEq k] [DecidableEq m] [DecidableEq n]
    [semiring α] (a : m) (b : n) (c : k) :
    matrix.mul (to_matrix (single a b)) (to_matrix (single b c)) = to_matrix (single a c) :=
  sorry

theorem single_mul_single_of_ne {k : Type u_1} {m : Type u_3} {n : Type u_4} [fintype k] [fintype m]
    [fintype n] {α : Type v} [DecidableEq k] [DecidableEq m] [DecidableEq n] [semiring α] {b₁ : n}
    {b₂ : n} (hb : b₁ ≠ b₂) (a : m) (c : k) :
    matrix.mul (to_matrix (single a b₁)) (to_matrix (single b₂ c)) = 0 :=
  sorry

/-- Restatement of `single_mul_single`, which will simplify expressions in `simp` normal form,
  when associativity may otherwise need to be carefully applied. -/
@[simp] theorem single_mul_single_right {k : Type u_1} {l : Type u_2} {m : Type u_3} {n : Type u_4}
    [fintype k] [fintype l] [fintype m] [fintype n] {α : Type v} [DecidableEq k] [DecidableEq m]
    [DecidableEq n] [semiring α] (a : m) (b : n) (c : k) (M : matrix k l α) :
    matrix.mul (to_matrix (single a b)) (matrix.mul (to_matrix (single b c)) M) =
        matrix.mul (to_matrix (single a c)) M :=
  sorry

/-- We can also define permutation matrices by permuting the rows of the identity matrix. -/
theorem equiv_to_pequiv_to_matrix {n : Type u_4} [fintype n] {α : Type v} [DecidableEq n]
    [HasZero α] [HasOne α] (σ : n ≃ n) (i : n) (j : n) :
    to_matrix (equiv.to_pequiv σ) i j = HasOne.one (coe_fn σ i) j :=
  if_congr option.some_inj rfl rfl

end Mathlib


import tactic

-- these two statements tell Lean to use the law of excluded middle as necessary
noncomputable theory
open_locale classical

--BEGIN--

/--------------------------------------------------------------------------

``em``

  If ``P : Prop``, then ``em P : P ∨ ¬ P`` lets you use the law of the excluded middle on ``P``.

Delete the ``sorry,`` below and replace them with a legitimate proof.

--------------------------------------------------------------------------/

theorem not_not_self_imp_self (P : Prop) : ¬ ¬ P → P:=
begin
  sorry,
end

theorem contrapositive_converse (P Q : Prop) : (¬Q → ¬P) → (P → Q) :=
begin
  sorry,
end

example (P : Prop) : ¬ P → ¬ ¬ ¬ P :=
begin
  sorry,
end

theorem principle_of_explosion (P Q : Prop) : P → (¬ P → Q) :=
begin
  sorry,
end

--END--


/-
Copyright (c) 2021 Yury G. Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury G. Kudryashov

! This file was ported from Lean 3 source module topology.instances.irrational
! leanprover-community/mathlib commit f2ce6086713c78a7f880485f7917ea547a215982
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Real.Irrational
import Mathbin.Data.Rat.Encodable
import Mathbin.Topology.MetricSpace.Baire

/-!
# Topology of irrational numbers

In this file we prove the following theorems:

* `is_Gδ_irrational`, `dense_irrational`, `eventually_residual_irrational`: irrational numbers
  form a dense Gδ set;

* `irrational.eventually_forall_le_dist_cast_div`,
  `irrational.eventually_forall_le_dist_cast_div_of_denom_le`;
  `irrational.eventually_forall_le_dist_cast_rat_of_denom_le`: a sufficiently small neighborhood of
  an irrational number is disjoint with the set of rational numbers with bounded denominator.

We also provide `order_topology`, `no_min_order`, `no_max_order`, and `densely_ordered`
instances for `{x // irrational x}`.

## Tags

irrational, residual
-/

open Set Filter Metric

open Filter Topology

theorem isGδ_irrational : IsGδ { x | Irrational x } :=
  (countable_range _).isGδ_compl
#align is_Gδ_irrational isGδ_irrational

theorem dense_irrational : Dense { x : ℝ | Irrational x } :=
  by
  refine' real.is_topological_basis_Ioo_rat.dense_iff.2 _
  simp only [mem_Union, mem_singleton_iff]
  rintro _ ⟨a, b, hlt, rfl⟩ hne; rw [inter_comm]
  exact exists_irrational_btwn (Rat.cast_lt.2 hlt)
#align dense_irrational dense_irrational

theorem eventually_residual_irrational : ∀ᶠ x in residual ℝ, Irrational x :=
  eventually_residual.2 ⟨_, isGδ_irrational, dense_irrational, fun _ => id⟩
#align eventually_residual_irrational eventually_residual_irrational

namespace Irrational

variable {x : ℝ}

instance : OrderTopology { x // Irrational x } :=
  induced_orderTopology _ (fun x y => Iff.rfl) fun x y hlt =>
    let ⟨a, ha, hxa, hay⟩ := exists_irrational_btwn hlt
    ⟨⟨a, ha⟩, hxa, hay⟩

instance : NoMaxOrder { x // Irrational x } :=
  ⟨fun ⟨x, hx⟩ => ⟨⟨x + (1 : ℕ), hx.addNat 1⟩, by simp⟩⟩

instance : NoMinOrder { x // Irrational x } :=
  ⟨fun ⟨x, hx⟩ => ⟨⟨x - (1 : ℕ), hx.subNat 1⟩, by simp⟩⟩

instance : DenselyOrdered { x // Irrational x } :=
  ⟨fun x y hlt =>
    let ⟨z, hz, hxz, hzy⟩ := exists_irrational_btwn hlt
    ⟨⟨z, hz⟩, hxz, hzy⟩⟩

theorem eventually_forall_le_dist_cast_div (hx : Irrational x) (n : ℕ) :
    ∀ᶠ ε : ℝ in 𝓝 0, ∀ m : ℤ, ε ≤ dist x (m / n) :=
  by
  have A : IsClosed (range (fun m => n⁻¹ * m : ℤ → ℝ)) :=
    ((isClosedMap_smul₀ (n⁻¹ : ℝ)).comp int.closed_embedding_coe_real.is_closed_map).closed_range
  have B : x ∉ range (fun m => n⁻¹ * m : ℤ → ℝ) :=
    by
    rintro ⟨m, rfl⟩
    simpa using hx
  rcases Metric.mem_nhds_iff.1 (A.is_open_compl.mem_nhds B) with ⟨ε, ε0, hε⟩
  refine' (ge_mem_nhds ε0).mono fun δ hδ m => not_lt.1 fun hlt => _
  rw [dist_comm] at hlt
  refine' hε (ball_subset_ball hδ hlt) ⟨m, _⟩
  simp [div_eq_inv_mul]
#align irrational.eventually_forall_le_dist_cast_div Irrational.eventually_forall_le_dist_cast_div

theorem eventually_forall_le_dist_cast_div_of_denom_le (hx : Irrational x) (n : ℕ) :
    ∀ᶠ ε : ℝ in 𝓝 0, ∀ k ≤ n, ∀ (m : ℤ), ε ≤ dist x (m / k) :=
  (finite_le_nat n).eventually_all.2 fun k hk => hx.eventually_forall_le_dist_cast_div k
#align irrational.eventually_forall_le_dist_cast_div_of_denom_le Irrational.eventually_forall_le_dist_cast_div_of_denom_le

theorem eventually_forall_le_dist_cast_rat_of_den_le (hx : Irrational x) (n : ℕ) :
    ∀ᶠ ε : ℝ in 𝓝 0, ∀ r : ℚ, r.den ≤ n → ε ≤ dist x r :=
  (hx.eventually_forall_le_dist_cast_div_of_denom_le n).mono fun ε H r hr => by
    simpa only [Rat.cast_def] using H r.denom hr r.num
#align irrational.eventually_forall_le_dist_cast_rat_of_denom_le Irrational.eventually_forall_le_dist_cast_rat_of_den_le

end Irrational


/-
Copyright (c) 2014 Robert Lewis. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Robert Lewis, Leonardo de Moura, Mario Carneiro, Floris van Doorn
-/
import algebra.parity
import algebra.char_zero.lemmas
import algebra.group_with_zero.power
import algebra.order.field.basic

/-!
# Lemmas about powers in ordered fields.

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.
-/

variables {α : Type*}
open function

section linear_ordered_semifield
variables [linear_ordered_semifield α] {a b c d e : α} {m n : ℤ}

/-! ### Integer powers -/

lemma zpow_le_of_le (ha : 1 ≤ a) (h : m ≤ n) : a ^ m ≤ a ^ n :=
begin
  have ha₀ : 0 < a, from one_pos.trans_le ha,
  lift n - m to ℕ using sub_nonneg.2 h with k hk,
  calc a ^ m = a ^ m * 1 : (mul_one _).symm
  ... ≤ a ^ m * a ^ k : mul_le_mul_of_nonneg_left (one_le_pow_of_one_le ha _) (zpow_nonneg ha₀.le _)
  ... = a ^ n : by rw [← zpow_coe_nat, ← zpow_add₀ ha₀.ne', hk, add_sub_cancel'_right]
end

lemma zpow_le_one_of_nonpos (ha : 1 ≤ a) (hn : n ≤ 0) : a ^ n ≤ 1 :=
(zpow_le_of_le ha hn).trans_eq $ zpow_zero _

lemma one_le_zpow_of_nonneg (ha : 1 ≤ a) (hn : 0 ≤ n) : 1 ≤ a ^ n :=
(zpow_zero _).symm.trans_le $ zpow_le_of_le ha hn

protected lemma nat.zpow_pos_of_pos {a : ℕ} (h : 0 < a) (n : ℤ) : 0 < (a : α)^n :=
by { apply zpow_pos_of_pos, exact_mod_cast h }

lemma nat.zpow_ne_zero_of_pos {a : ℕ} (h : 0 < a) (n : ℤ) : (a : α)^n ≠ 0 :=
(nat.zpow_pos_of_pos h n).ne'

lemma one_lt_zpow (ha : 1 < a) : ∀ n : ℤ, 0 < n → 1 < a ^ n
| (n : ℕ) h := (zpow_coe_nat _ _).symm.subst (one_lt_pow ha $ int.coe_nat_ne_zero.mp h.ne')
| -[1+ n] h := ((int.neg_succ_not_pos _).mp h).elim

lemma zpow_strict_mono (hx : 1 < a) : strict_mono ((^) a : ℤ → α) :=
strict_mono_int_of_lt_succ $ λ n,
have xpos : 0 < a, from zero_lt_one.trans hx,
calc a ^ n < a ^ n * a : lt_mul_of_one_lt_right (zpow_pos_of_pos xpos _) hx
... = a ^ (n + 1) : (zpow_add_one₀ xpos.ne' _).symm

lemma zpow_strict_anti (h₀ : 0 < a) (h₁ : a < 1) : strict_anti ((^) a : ℤ → α) :=
strict_anti_int_of_succ_lt $ λ n,
calc a ^ (n + 1) = a ^ n * a : zpow_add_one₀ h₀.ne' _
... < a ^ n * 1 : (mul_lt_mul_left $ zpow_pos_of_pos h₀ _).2 h₁
... = a ^ n : mul_one _

@[simp] lemma zpow_lt_iff_lt (hx : 1 < a) : a ^ m < a ^ n ↔ m < n := (zpow_strict_mono hx).lt_iff_lt
@[simp] lemma zpow_le_iff_le (hx : 1 < a) : a ^ m ≤ a ^ n ↔ m ≤ n := (zpow_strict_mono hx).le_iff_le

@[simp] lemma div_pow_le (ha : 0 ≤ a) (hb : 1 ≤ b) (k : ℕ) : a/b^k ≤ a :=
div_le_self ha $ one_le_pow_of_one_le hb _

lemma zpow_injective (h₀ : 0 < a) (h₁ : a ≠ 1) : injective ((^) a : ℤ → α) :=
begin
  rcases h₁.lt_or_lt with H|H,
  { exact (zpow_strict_anti h₀ H).injective },
  { exact (zpow_strict_mono H).injective }
end

@[simp] lemma zpow_inj (h₀ : 0 < a) (h₁ : a ≠ 1) : a ^ m = a ^ n ↔ m = n :=
(zpow_injective h₀ h₁).eq_iff

lemma zpow_le_max_of_min_le {x : α} (hx : 1 ≤ x) {a b c : ℤ} (h : min a b ≤ c) :
  x ^ -c ≤ max (x ^ -a) (x ^ -b) :=
begin
  have : antitone (λ n : ℤ, x ^ -n) := λ m n h, zpow_le_of_le hx (neg_le_neg h),
  exact (this h).trans_eq this.map_min,
end

lemma zpow_le_max_iff_min_le {x : α} (hx : 1 < x) {a b c : ℤ} :
  x ^ -c ≤ max (x ^ -a) (x ^ -b) ↔ min a b ≤ c :=
by simp_rw [le_max_iff, min_le_iff, zpow_le_iff_le hx, neg_le_neg_iff]

end linear_ordered_semifield

section linear_ordered_field
variables [linear_ordered_field α] {a b c d : α} {n : ℤ}

/-! ### Lemmas about powers to numerals. -/

lemma zpow_bit0_nonneg (a : α) (n : ℤ) : 0 ≤ a ^ bit0 n :=
(mul_self_nonneg _).trans_eq $ (zpow_bit0 _ _).symm

lemma zpow_two_nonneg (a : α) : 0 ≤ a ^ (2 : ℤ) := zpow_bit0_nonneg _ _
lemma zpow_neg_two_nonneg (a : α) : 0 ≤ a ^ (-2 : ℤ) := zpow_bit0_nonneg _ (-1)

lemma zpow_bit0_pos (h : a ≠ 0) (n : ℤ) : 0 < a ^ bit0 n :=
(zpow_bit0_nonneg a n).lt_of_ne (zpow_ne_zero _ h).symm

lemma zpow_two_pos_of_ne_zero (h : a ≠ 0) : 0 < a ^ (2 : ℤ) := zpow_bit0_pos h _

@[simp] lemma zpow_bit0_pos_iff (hn : n ≠ 0) : 0 < a ^ bit0 n ↔ a ≠ 0 :=
⟨by { rintro h rfl, refine (zero_zpow _ _).not_gt h, rwa bit0_ne_zero }, λ h, zpow_bit0_pos h _⟩

@[simp] lemma zpow_bit1_neg_iff : a ^ bit1 n < 0 ↔ a < 0 :=
⟨λ h, not_le.1 $ λ h', not_le.2 h $ zpow_nonneg h' _,
 λ h, by rw [bit1, zpow_add_one₀ h.ne]; exact mul_neg_of_pos_of_neg (zpow_bit0_pos h.ne _) h⟩

@[simp] lemma zpow_bit1_nonneg_iff : 0 ≤ a ^ bit1 n ↔ 0 ≤ a :=
le_iff_le_iff_lt_iff_lt.2 zpow_bit1_neg_iff

@[simp] lemma zpow_bit1_nonpos_iff : a ^ bit1 n ≤ 0 ↔ a ≤ 0 :=
by rw [le_iff_lt_or_eq, le_iff_lt_or_eq, zpow_bit1_neg_iff, zpow_eq_zero_iff (int.bit1_ne_zero n)]

@[simp] lemma zpow_bit1_pos_iff : 0 < a ^ bit1 n ↔ 0 < a :=
lt_iff_lt_of_le_iff_le zpow_bit1_nonpos_iff

protected lemma even.zpow_nonneg (hn : even n) (a : α) : 0 ≤ a ^ n :=
by obtain ⟨k, rfl⟩ := hn; exact zpow_bit0_nonneg _ _

lemma even.zpow_pos_iff (hn : even n) (h : n ≠ 0) : 0 < a ^ n ↔ a ≠ 0 :=
by obtain ⟨k, rfl⟩ := hn; exact zpow_bit0_pos_iff (by rintro rfl; simpa using h)

lemma odd.zpow_neg_iff (hn : odd n) : a ^ n < 0 ↔ a < 0 :=
by cases hn with k hk; simpa only [hk, two_mul] using zpow_bit1_neg_iff

protected lemma odd.zpow_nonneg_iff (hn : odd n) : 0 ≤ a ^ n ↔ 0 ≤ a :=
by cases hn with k hk; simpa only [hk, two_mul] using zpow_bit1_nonneg_iff

lemma odd.zpow_nonpos_iff (hn : odd n) : a ^ n ≤ 0 ↔ a ≤ 0 :=
by cases hn with k hk; simpa only [hk, two_mul] using zpow_bit1_nonpos_iff

lemma odd.zpow_pos_iff (hn : odd n) : 0 < a ^ n ↔ 0 < a :=
by cases hn with k hk; simpa only [hk, two_mul] using zpow_bit1_pos_iff

alias even.zpow_pos_iff ↔ _ even.zpow_pos
alias odd.zpow_neg_iff ↔ _ odd.zpow_neg
alias odd.zpow_nonpos_iff ↔ _ odd.zpow_nonpos

lemma even.zpow_abs {p : ℤ} (hp : even p) (a : α) : |a| ^ p = a ^ p :=
by cases abs_choice a with h h; simp only [h, hp.neg_zpow _]

@[simp] lemma zpow_bit0_abs (a : α) (p : ℤ) : |a| ^ bit0 p = a ^ bit0 p := (even_bit0 _).zpow_abs _

/-! ### Miscellaneous lemmmas -/

/-- Bernoulli's inequality reformulated to estimate `(n : α)`. -/
lemma nat.cast_le_pow_sub_div_sub (H : 1 < a)  (n : ℕ) : (n : α) ≤ (a ^ n - 1) / (a - 1) :=
(le_div_iff (sub_pos.2 H)).2 $ le_sub_left_of_add_le $
  one_add_mul_sub_le_pow ((neg_le_self zero_le_one).trans H.le) _

/-- For any `a > 1` and a natural `n` we have `n ≤ a ^ n / (a - 1)`. See also
`nat.cast_le_pow_sub_div_sub` for a stronger inequality with `a ^ n - 1` in the numerator. -/
theorem nat.cast_le_pow_div_sub (H : 1 < a) (n : ℕ) : (n : α) ≤ a ^ n / (a - 1) :=
(n.cast_le_pow_sub_div_sub H).trans $ div_le_div_of_le (sub_nonneg.2 H.le)
  (sub_le_self _ zero_le_one)

end linear_ordered_field


/-
Copyright (c) 2018 Chris Hughes. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Chris Hughes, Patrick Stevens
-/
import data.nat.choose.basic
import tactic.linarith
import algebra.big_operators.ring
import algebra.big_operators.intervals
import algebra.big_operators.order
import algebra.big_operators.nat_antidiagonal

/-!
# Sums of binomial coefficients

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

This file includes variants of the binomial theorem and other results on sums of binomial
coefficients. Theorems whose proofs depend on such sums may also go in this file for import
reasons.

-/
open nat
open finset

open_locale big_operators

variables {R : Type*}

namespace commute

variables [semiring R] {x y : R} (h : commute x y) (n : ℕ)

include h

/-- A version of the **binomial theorem** for commuting elements in noncommutative semirings. -/
theorem add_pow :
  (x + y) ^ n = ∑ m in range (n + 1), x ^ m * y ^ (n - m) * choose n m :=
begin
  let t : ℕ → ℕ → R := λ n m, x ^ m * (y ^ (n - m)) * (choose n m),
  change (x + y) ^ n = ∑ m in range (n + 1), t n m,
  have h_first : ∀ n, t n 0 = y ^ n :=
    λ n, by { dsimp [t], rw [choose_zero_right, pow_zero, nat.cast_one, mul_one, one_mul] },
  have h_last : ∀ n, t n n.succ = 0 :=
    λ n, by { dsimp [t], rw [choose_succ_self, nat.cast_zero, mul_zero] },
  have h_middle : ∀ (n i : ℕ), (i ∈ range n.succ) →
   ((t n.succ) ∘ nat.succ) i = x * (t n i) + y * (t n i.succ) :=
  begin
    intros n i h_mem,
    have h_le : i ≤ n := nat.le_of_lt_succ (mem_range.mp h_mem),
    dsimp [t],
    rw [choose_succ_succ, nat.cast_add, mul_add],
    congr' 1,
    { rw [pow_succ x, succ_sub_succ, mul_assoc, mul_assoc, mul_assoc] },
    { rw [← mul_assoc y, ← mul_assoc y, (h.symm.pow_right i.succ).eq],
      by_cases h_eq : i = n,
      { rw [h_eq, choose_succ_self, nat.cast_zero, mul_zero, mul_zero] },
      { rw [succ_sub (lt_of_le_of_ne h_le h_eq)],
        rw [pow_succ y, mul_assoc, mul_assoc, mul_assoc, mul_assoc] } }
  end,
  induction n with n ih,
  { rw [pow_zero, sum_range_succ, range_zero, sum_empty, zero_add],
    dsimp [t], rw [pow_zero, pow_zero, choose_self, nat.cast_one, mul_one, mul_one] },
  { rw [sum_range_succ', h_first],
    rw [sum_congr rfl (h_middle n), sum_add_distrib, add_assoc],
    rw [pow_succ (x + y), ih, add_mul, mul_sum, mul_sum],
    congr' 1,
    rw [sum_range_succ', sum_range_succ, h_first, h_last,
       mul_zero, add_zero, pow_succ] }
end

/-- A version of `commute.add_pow` that avoids ℕ-subtraction by summing over the antidiagonal and
also with the binomial coefficient applied via scalar action of ℕ. -/
lemma add_pow' :
  (x + y) ^ n = ∑ m in nat.antidiagonal n, choose n m.fst • (x ^ m.fst * y ^ m.snd) :=
by simp_rw [finset.nat.sum_antidiagonal_eq_sum_range_succ (λ m p, choose n m • (x^m * y^p)),
  _root_.nsmul_eq_mul, cast_comm, h.add_pow]

end commute

/-- The **binomial theorem** -/
theorem add_pow [comm_semiring R] (x y : R) (n : ℕ) :
  (x + y) ^ n = ∑ m in range (n + 1), x ^ m * y ^ (n - m) * choose n m :=
(commute.all x y).add_pow n

namespace nat

/-- The sum of entries in a row of Pascal's triangle -/
theorem sum_range_choose (n : ℕ) :
  ∑ m in range (n + 1), choose n m = 2 ^ n :=
by simpa using (add_pow 1 1 n).symm

lemma sum_range_choose_halfway (m : nat) :
  ∑ i in range (m + 1), choose (2 * m + 1) i = 4 ^ m :=
have ∑ i in range (m + 1), choose (2 * m + 1) (2 * m + 1 - i) =
  ∑ i in range (m + 1), choose (2 * m + 1) i,
from sum_congr rfl $ λ i hi, choose_symm $ by linarith [mem_range.1 hi],
mul_right_injective₀ two_ne_zero $
calc 2 * (∑ i in range (m + 1), choose (2 * m + 1) i) =
  (∑ i in range (m + 1), choose (2 * m + 1) i) +
    ∑ i in range (m + 1), choose (2 * m + 1) (2 * m + 1 - i) :
  by rw [two_mul, this]
... = (∑ i in range (m + 1), choose (2 * m + 1) i) +
  ∑ i in Ico (m + 1) (2 * m + 2), choose (2 * m + 1) i : begin
    rw [range_eq_Ico, sum_Ico_reflect],
    { congr,
      have A : m + 1 ≤ 2 * m + 1, by linarith,
      rw [add_comm, add_tsub_assoc_of_le A, ← add_comm],
      congr,
      rw tsub_eq_iff_eq_add_of_le A,
      ring, },
   { linarith }
  end
... = ∑ i in range (2 * m + 2), choose (2 * m + 1) i : sum_range_add_sum_Ico _ (by linarith)
... = 2^(2 * m + 1) : sum_range_choose (2 * m + 1)
... = 2 * 4^m : by { rw [pow_succ, pow_mul], refl }

lemma choose_middle_le_pow (n : ℕ) : choose (2 * n + 1) n ≤ 4 ^ n :=
begin
  have t : choose (2 * n + 1) n ≤ ∑ i in range (n + 1), choose (2 * n + 1) i :=
    single_le_sum (λ x _, by linarith) (self_mem_range_succ n),
  simpa [sum_range_choose_halfway n] using t
end

lemma four_pow_le_two_mul_add_one_mul_central_binom (n : ℕ) :
  4 ^ n ≤ (2 * n + 1) * choose (2 * n) n :=
calc 4 ^ n = (1 + 1) ^ (2 * n) : by norm_num [pow_mul]
...        = ∑ m in range (2 * n + 1), choose (2 * n) m : by simp [add_pow]
...        ≤ ∑ m in range (2 * n + 1), choose (2 * n) (2 * n / 2) :
  sum_le_sum (λ i hi, choose_le_middle i (2 * n))
...        = (2 * n + 1) * choose (2 * n) n : by simp

end nat

theorem int.alternating_sum_range_choose {n : ℕ} :
  ∑ m in range (n + 1), ((-1) ^ m * ↑(choose n m) : ℤ) = if n = 0 then 1 else 0 :=
begin
  cases n, { simp },
  have h := add_pow (-1 : ℤ) 1 n.succ,
  simp only [one_pow, mul_one, add_left_neg] at h,
  rw [← h, zero_pow (nat.succ_pos n), if_neg (nat.succ_ne_zero n)],
end

theorem int.alternating_sum_range_choose_of_ne {n : ℕ} (h0 : n ≠ 0) :
  ∑ m in range (n + 1), ((-1) ^ m * ↑(choose n m) : ℤ) = 0 :=
by rw [int.alternating_sum_range_choose, if_neg h0]

namespace finset

theorem sum_powerset_apply_card {α β : Type*} [add_comm_monoid α] (f : ℕ → α) {x : finset β} :
  ∑ m in x.powerset, f m.card = ∑ m in range (x.card + 1), (x.card.choose m) • f m :=
begin
  transitivity ∑ m in range (x.card + 1), ∑ j in x.powerset.filter (λ z, z.card = m), f j.card,
  { refine (sum_fiberwise_of_maps_to _ _).symm,
    intros y hy,
    rw [mem_range, nat.lt_succ_iff],
    rw mem_powerset at hy,
    exact card_le_of_subset hy },
  { refine sum_congr rfl (λ y hy, _),
    rw [← card_powerset_len, ← sum_const],
    refine sum_congr powerset_len_eq_filter.symm (λ z hz, _),
    rw (mem_powerset_len.1 hz).2 }
end

theorem sum_powerset_neg_one_pow_card {α : Type*} [decidable_eq α] {x : finset α} :
  ∑ m in x.powerset, (-1 : ℤ) ^ m.card = if x = ∅ then 1 else 0 :=
begin
  rw sum_powerset_apply_card,
  simp only [nsmul_eq_mul', ← card_eq_zero, int.alternating_sum_range_choose]
end

theorem sum_powerset_neg_one_pow_card_of_nonempty {α : Type*} {x : finset α}
  (h0 : x.nonempty) :
  ∑ m in x.powerset, (-1 : ℤ) ^ m.card = 0 :=
begin
  classical,
  rw [sum_powerset_neg_one_pow_card, if_neg],
  rw [← ne.def, ← nonempty_iff_ne_empty],
  apply h0,
end

end finset


/-
Copyright (c) 2015 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Robert Y. Lewis
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.algebra.group_power.basic
import Mathlib.algebra.opposites
import Mathlib.data.list.basic
import Mathlib.data.int.cast
import Mathlib.data.equiv.basic
import Mathlib.data.equiv.mul_add
import Mathlib.deprecated.group
import Mathlib.PostPort

universes y u w x z u₁ u_1

namespace Mathlib

/-!
# Lemmas about power operations on monoids and groups

This file contains lemmas about `monoid.pow`, `group.pow`, `nsmul`, `gsmul`
which require additional imports besides those available in `.basic`.
-/

/-!
### (Additive) monoid
-/

@[simp] theorem nsmul_one {A : Type y} [add_monoid A] [HasOne A] (n : ℕ) : n •ℕ 1 = ↑n :=
  add_monoid_hom.eq_nat_cast
    (add_monoid_hom.mk (fun (n : ℕ) => n •ℕ 1) (zero_nsmul 1) fun (_x _x_1 : ℕ) => add_nsmul 1 _x _x_1) (one_nsmul 1)

@[simp] theorem list.prod_repeat {M : Type u} [monoid M] (a : M) (n : ℕ) : list.prod (list.repeat a n) = a ^ n := sorry

@[simp] theorem list.sum_repeat {A : Type y} [add_monoid A] (a : A) (n : ℕ) : list.sum (list.repeat a n) = n •ℕ a :=
  list.prod_repeat

@[simp] theorem units.coe_pow {M : Type u} [monoid M] (u : units M) (n : ℕ) : ↑(u ^ n) = ↑u ^ n :=
  monoid_hom.map_pow (units.coe_hom M) u n

theorem is_unit_of_pow_eq_one {M : Type u} [monoid M] (x : M) (n : ℕ) (hx : x ^ n = 1) (hn : 0 < n) : is_unit x := sorry

theorem nat.nsmul_eq_mul (m : ℕ) (n : ℕ) : m •ℕ n = m * n := sorry

theorem gsmul_one {A : Type y} [add_group A] [HasOne A] (n : ℤ) : n •ℤ 1 = ↑n := sorry

theorem gpow_add_one {G : Type w} [group G] (a : G) (n : ℤ) : a ^ (n + 1) = a ^ n * a := sorry

theorem add_one_gsmul {A : Type y} [add_group A] (a : A) (i : ℤ) : (i + 1) •ℤ a = i •ℤ a + a :=
  gpow_add_one

theorem gpow_sub_one {G : Type w} [group G] (a : G) (n : ℤ) : a ^ (n - 1) = a ^ n * (a⁻¹) := sorry

theorem gpow_add {G : Type w} [group G] (a : G) (m : ℤ) (n : ℤ) : a ^ (m + n) = a ^ m * a ^ n := sorry

theorem mul_self_gpow {G : Type w} [group G] (b : G) (m : ℤ) : b * b ^ m = b ^ (m + 1) := sorry

theorem mul_gpow_self {G : Type w} [group G] (b : G) (m : ℤ) : b ^ m * b = b ^ (m + 1) := sorry

theorem add_gsmul {A : Type y} [add_group A] (a : A) (i : ℤ) (j : ℤ) : (i + j) •ℤ a = i •ℤ a + j •ℤ a :=
  gpow_add

theorem gpow_sub {G : Type w} [group G] (a : G) (m : ℤ) (n : ℤ) : a ^ (m - n) = a ^ m * (a ^ n⁻¹) := sorry

theorem sub_gsmul {A : Type y} [add_group A] (m : ℤ) (n : ℤ) (a : A) : (m - n) •ℤ a = m •ℤ a - n •ℤ a := sorry

theorem gpow_one_add {G : Type w} [group G] (a : G) (i : ℤ) : a ^ (1 + i) = a * a ^ i :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a ^ (1 + i) = a * a ^ i)) (gpow_add a 1 i)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a ^ 1 * a ^ i = a * a ^ i)) (gpow_one a))) (Eq.refl (a * a ^ i)))

theorem one_add_gsmul {A : Type y} [add_group A] (a : A) (i : ℤ) : (1 + i) •ℤ a = a + i •ℤ a :=
  gpow_one_add

theorem gpow_mul_comm {G : Type w} [group G] (a : G) (i : ℤ) (j : ℤ) : a ^ i * a ^ j = a ^ j * a ^ i :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a ^ i * a ^ j = a ^ j * a ^ i)) (Eq.symm (gpow_add a i j))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a ^ (i + j) = a ^ j * a ^ i)) (Eq.symm (gpow_add a j i))))
      (eq.mpr (id (Eq._oldrec (Eq.refl (a ^ (i + j) = a ^ (j + i))) (add_comm i j))) (Eq.refl (a ^ (j + i)))))

theorem gsmul_add_comm {A : Type y} [add_group A] (a : A) (i : ℤ) (j : ℤ) : i •ℤ a + j •ℤ a = j •ℤ a + i •ℤ a :=
  gpow_mul_comm

theorem gpow_mul {G : Type w} [group G] (a : G) (m : ℤ) (n : ℤ) : a ^ (m * n) = (a ^ m) ^ n := sorry

theorem gsmul_mul' {A : Type y} [add_group A] (a : A) (m : ℤ) (n : ℤ) : m * n •ℤ a = n •ℤ (m •ℤ a) :=
  gpow_mul

theorem gpow_mul' {G : Type w} [group G] (a : G) (m : ℤ) (n : ℤ) : a ^ (m * n) = (a ^ n) ^ m :=
  eq.mpr (id (Eq._oldrec (Eq.refl (a ^ (m * n) = (a ^ n) ^ m)) (mul_comm m n)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a ^ (n * m) = (a ^ n) ^ m)) (gpow_mul a n m))) (Eq.refl ((a ^ n) ^ m)))

theorem gsmul_mul {A : Type y} [add_group A] (a : A) (m : ℤ) (n : ℤ) : m * n •ℤ a = m •ℤ (n •ℤ a) :=
  eq.mpr (id (Eq._oldrec (Eq.refl (m * n •ℤ a = m •ℤ (n •ℤ a))) (mul_comm m n)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (n * m •ℤ a = m •ℤ (n •ℤ a))) (gsmul_mul' a n m))) (Eq.refl (m •ℤ (n •ℤ a))))

theorem gpow_bit0 {G : Type w} [group G] (a : G) (n : ℤ) : a ^ bit0 n = a ^ n * a ^ n :=
  gpow_add a n n

theorem bit0_gsmul {A : Type y} [add_group A] (a : A) (n : ℤ) : bit0 n •ℤ a = n •ℤ a + n •ℤ a :=
  gpow_add a n n

theorem gpow_bit1 {G : Type w} [group G] (a : G) (n : ℤ) : a ^ bit1 n = a ^ n * a ^ n * a := sorry

theorem bit1_gsmul {A : Type y} [add_group A] (a : A) (n : ℤ) : bit1 n •ℤ a = n •ℤ a + n •ℤ a + a :=
  gpow_bit1

@[simp] theorem monoid_hom.map_gpow {G : Type w} {H : Type x} [group G] [group H] (f : G →* H) (a : G) (n : ℤ) : coe_fn f (a ^ n) = coe_fn f a ^ n :=
  int.cases_on n (fun (n : ℕ) => monoid_hom.map_pow f a n)
    fun (n : ℕ) =>
      Eq.trans (monoid_hom.map_inv f (a ^ Nat.succ n)) (congr_arg has_inv.inv (monoid_hom.map_pow f a (Nat.succ n)))

@[simp] theorem add_monoid_hom.map_gsmul {A : Type y} {B : Type z} [add_group A] [add_group B] (f : A →+ B) (a : A) (n : ℤ) : coe_fn f (n •ℤ a) = n •ℤ coe_fn f a :=
  monoid_hom.map_gpow (coe_fn add_monoid_hom.to_multiplicative f) a n

@[simp] theorem units.coe_gpow {G : Type w} [group G] (u : units G) (n : ℤ) : ↑(u ^ n) = ↑u ^ n :=
  monoid_hom.map_gpow (units.coe_hom G) u n

/-! Lemmas about `gsmul` under ordering,  placed here (rather than in `algebra.group_power.basic`
with their friends) because they require facts from `data.int.basic`-/

theorem gsmul_pos {A : Type y} [ordered_add_comm_group A] {a : A} (ha : 0 < a) {k : ℤ} (hk : 0 < k) : 0 < k •ℤ a := sorry

theorem gsmul_le_gsmul {A : Type y} [ordered_add_comm_group A] {a : A} {n : ℤ} {m : ℤ} (ha : 0 ≤ a) (h : n ≤ m) : n •ℤ a ≤ m •ℤ a := sorry

theorem gsmul_lt_gsmul {A : Type y} [ordered_add_comm_group A] {a : A} {n : ℤ} {m : ℤ} (ha : 0 < a) (h : n < m) : n •ℤ a < m •ℤ a := sorry

theorem gsmul_le_gsmul_iff {A : Type y} [linear_ordered_add_comm_group A] {a : A} {n : ℤ} {m : ℤ} (ha : 0 < a) : n •ℤ a ≤ m •ℤ a ↔ n ≤ m := sorry

theorem gsmul_lt_gsmul_iff {A : Type y} [linear_ordered_add_comm_group A] {a : A} {n : ℤ} {m : ℤ} (ha : 0 < a) : n •ℤ a < m •ℤ a ↔ n < m := sorry

theorem nsmul_le_nsmul_iff {A : Type y} [linear_ordered_add_comm_group A] {a : A} {n : ℕ} {m : ℕ} (ha : 0 < a) : n •ℕ a ≤ m •ℕ a ↔ n ≤ m := sorry

theorem nsmul_lt_nsmul_iff {A : Type y} [linear_ordered_add_comm_group A] {a : A} {n : ℕ} {m : ℕ} (ha : 0 < a) : n •ℕ a < m •ℕ a ↔ n < m := sorry

@[simp] theorem with_bot.coe_nsmul {A : Type y} [add_monoid A] (a : A) (n : ℕ) : ↑(n •ℕ a) = n •ℕ ↑a :=
  add_monoid_hom.map_nsmul (add_monoid_hom.mk coe with_bot.coe_zero with_bot.coe_add) a n

theorem nsmul_eq_mul' {R : Type u₁} [semiring R] (a : R) (n : ℕ) : n •ℕ a = a * ↑n := sorry

@[simp] theorem nsmul_eq_mul {R : Type u₁} [semiring R] (n : ℕ) (a : R) : n •ℕ a = ↑n * a :=
  eq.mpr (id (Eq._oldrec (Eq.refl (n •ℕ a = ↑n * a)) (nsmul_eq_mul' a n)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a * ↑n = ↑n * a)) (commute.eq (nat.cast_commute n a)))) (Eq.refl (a * ↑n)))

theorem mul_nsmul_left {R : Type u₁} [semiring R] (a : R) (b : R) (n : ℕ) : n •ℕ (a * b) = a * (n •ℕ b) :=
  eq.mpr (id (Eq._oldrec (Eq.refl (n •ℕ (a * b) = a * (n •ℕ b))) (nsmul_eq_mul' (a * b) n)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a * b * ↑n = a * (n •ℕ b))) (nsmul_eq_mul' b n)))
      (eq.mpr (id (Eq._oldrec (Eq.refl (a * b * ↑n = a * (b * ↑n))) (mul_assoc a b ↑n))) (Eq.refl (a * (b * ↑n)))))

theorem mul_nsmul_assoc {R : Type u₁} [semiring R] (a : R) (b : R) (n : ℕ) : n •ℕ (a * b) = n •ℕ a * b :=
  eq.mpr (id (Eq._oldrec (Eq.refl (n •ℕ (a * b) = n •ℕ a * b)) (nsmul_eq_mul n (a * b))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (↑n * (a * b) = n •ℕ a * b)) (nsmul_eq_mul n a)))
      (eq.mpr (id (Eq._oldrec (Eq.refl (↑n * (a * b) = ↑n * a * b)) (mul_assoc (↑n) a b))) (Eq.refl (↑n * (a * b)))))

@[simp] theorem nat.cast_pow {R : Type u₁} [semiring R] (n : ℕ) (m : ℕ) : ↑(n ^ m) = ↑n ^ m := sorry

@[simp] theorem int.coe_nat_pow (n : ℕ) (m : ℕ) : ↑(n ^ m) = ↑n ^ m := sorry

theorem int.nat_abs_pow (n : ℤ) (k : ℕ) : int.nat_abs (n ^ k) = int.nat_abs n ^ k := sorry

-- The next four lemmas allow us to replace multiplication by a numeral with a `gsmul` expression.

-- They are used by the `noncomm_ring` tactic, to normalise expressions before passing to `abel`.

theorem bit0_mul {R : Type u₁} [ring R] {n : R} {r : R} : bit0 n * r = bit0 1 •ℤ (n * r) := sorry

theorem mul_bit0 {R : Type u₁} [ring R] {n : R} {r : R} : r * bit0 n = bit0 1 •ℤ (r * n) := sorry

theorem bit1_mul {R : Type u₁} [ring R] {n : R} {r : R} : bit1 n * r = bit0 1 •ℤ (n * r) + r := sorry

theorem mul_bit1 {R : Type u₁} [ring R] {n : R} {r : R} : r * bit1 n = bit0 1 •ℤ (r * n) + r := sorry

@[simp] theorem gsmul_eq_mul {R : Type u₁} [ring R] (a : R) (n : ℤ) : n •ℤ a = ↑n * a := sorry

theorem gsmul_eq_mul' {R : Type u₁} [ring R] (a : R) (n : ℤ) : n •ℤ a = a * ↑n :=
  eq.mpr (id (Eq._oldrec (Eq.refl (n •ℤ a = a * ↑n)) (gsmul_eq_mul a n)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (↑n * a = a * ↑n)) (commute.eq (int.cast_commute n a)))) (Eq.refl (a * ↑n)))

theorem mul_gsmul_left {R : Type u₁} [ring R] (a : R) (b : R) (n : ℤ) : n •ℤ (a * b) = a * (n •ℤ b) :=
  eq.mpr (id (Eq._oldrec (Eq.refl (n •ℤ (a * b) = a * (n •ℤ b))) (gsmul_eq_mul' (a * b) n)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (a * b * ↑n = a * (n •ℤ b))) (gsmul_eq_mul' b n)))
      (eq.mpr (id (Eq._oldrec (Eq.refl (a * b * ↑n = a * (b * ↑n))) (mul_assoc a b ↑n))) (Eq.refl (a * (b * ↑n)))))

theorem mul_gsmul_assoc {R : Type u₁} [ring R] (a : R) (b : R) (n : ℤ) : n •ℤ (a * b) = n •ℤ a * b :=
  eq.mpr (id (Eq._oldrec (Eq.refl (n •ℤ (a * b) = n •ℤ a * b)) (gsmul_eq_mul (a * b) n)))
    (eq.mpr (id (Eq._oldrec (Eq.refl (↑n * (a * b) = n •ℤ a * b)) (gsmul_eq_mul a n)))
      (eq.mpr (id (Eq._oldrec (Eq.refl (↑n * (a * b) = ↑n * a * b)) (mul_assoc (↑n) a b))) (Eq.refl (↑n * (a * b)))))

@[simp] theorem gsmul_int_int (a : ℤ) (b : ℤ) : a •ℤ b = a * b := sorry

theorem gsmul_int_one (n : ℤ) : n •ℤ 1 = n := sorry

@[simp] theorem int.cast_pow {R : Type u₁} [ring R] (n : ℤ) (m : ℕ) : ↑(n ^ m) = ↑n ^ m := sorry

theorem neg_one_pow_eq_pow_mod_two {R : Type u₁} [ring R] {n : ℕ} : (-1) ^ n = (-1) ^ (n % bit0 1) := sorry

/-- Bernoulli's inequality. This version works for semirings but requires
additional hypotheses `0 ≤ a * a` and `0 ≤ (1 + a) * (1 + a)`. -/
theorem one_add_mul_le_pow' {R : Type u₁} [ordered_semiring R] {a : R} (Hsqr : 0 ≤ a * a) (Hsqr' : 0 ≤ (1 + a) * (1 + a)) (H : 0 ≤ bit0 1 + a) (n : ℕ) : 1 + ↑n * a ≤ (1 + a) ^ n := sorry

theorem pow_lt_pow_of_lt_one {R : Type u₁} [ordered_semiring R] {a : R} (h : 0 < a) (ha : a < 1) {i : ℕ} {j : ℕ} (hij : i < j) : a ^ j < a ^ i := sorry

theorem pow_lt_pow_iff_of_lt_one {R : Type u₁} [ordered_semiring R] {a : R} {n : ℕ} {m : ℕ} (hpos : 0 < a) (h : a < 1) : a ^ m < a ^ n ↔ n < m :=
  strict_mono.lt_iff_lt fun (m n : order_dual ℕ) => pow_lt_pow_of_lt_one hpos h

theorem pow_le_pow_of_le_one {R : Type u₁} [ordered_semiring R] {a : R} (h : 0 ≤ a) (ha : a ≤ 1) {i : ℕ} {j : ℕ} (hij : i ≤ j) : a ^ j ≤ a ^ i := sorry

theorem pow_le_one {R : Type u₁} [ordered_semiring R] {x : R} (n : ℕ) (h0 : 0 ≤ x) (h1 : x ≤ 1) : x ^ n ≤ 1 := sorry

theorem sign_cases_of_C_mul_pow_nonneg {R : Type u₁} [linear_ordered_semiring R] {C : R} {r : R} (h : ∀ (n : ℕ), 0 ≤ C * r ^ n) : C = 0 ∨ 0 < C ∧ 0 ≤ r := sorry

@[simp] theorem abs_pow {R : Type u₁} [linear_ordered_ring R] (a : R) (n : ℕ) : abs (a ^ n) = abs a ^ n :=
  monoid_hom.map_pow (monoid_with_zero_hom.to_monoid_hom abs_hom) a n

@[simp] theorem pow_bit1_neg_iff {R : Type u₁} [linear_ordered_ring R] {a : R} {n : ℕ} : a ^ bit1 n < 0 ↔ a < 0 :=
  { mp := fun (h : a ^ bit1 n < 0) => iff.mp not_le fun (h' : 0 ≤ a) => iff.mpr not_le h (pow_nonneg h' (bit1 n)),
    mpr := fun (h : a < 0) => mul_neg_of_neg_of_pos h (pow_bit0_pos (has_lt.lt.ne h) n) }

@[simp] theorem pow_bit1_nonneg_iff {R : Type u₁} [linear_ordered_ring R] {a : R} {n : ℕ} : 0 ≤ a ^ bit1 n ↔ 0 ≤ a :=
  iff.mpr le_iff_le_iff_lt_iff_lt pow_bit1_neg_iff

@[simp] theorem pow_bit1_nonpos_iff {R : Type u₁} [linear_ordered_ring R] {a : R} {n : ℕ} : a ^ bit1 n ≤ 0 ↔ a ≤ 0 := sorry

@[simp] theorem pow_bit1_pos_iff {R : Type u₁} [linear_ordered_ring R] {a : R} {n : ℕ} : 0 < a ^ bit1 n ↔ 0 < a :=
  lt_iff_lt_of_le_iff_le pow_bit1_nonpos_iff

theorem strict_mono_pow_bit1 {R : Type u₁} [linear_ordered_ring R] (n : ℕ) : strict_mono fun (a : R) => a ^ bit1 n := sorry

/-- Bernoulli's inequality for `n : ℕ`, `-2 ≤ a`. -/
theorem one_add_mul_le_pow {R : Type u₁} [linear_ordered_ring R] {a : R} (H : -bit0 1 ≤ a) (n : ℕ) : 1 + ↑n * a ≤ (1 + a) ^ n :=
  one_add_mul_le_pow' (mul_self_nonneg a) (mul_self_nonneg (1 + a)) (iff.mp neg_le_iff_add_nonneg' H) n

/-- Bernoulli's inequality reformulated to estimate `a^n`. -/
theorem one_add_mul_sub_le_pow {R : Type u₁} [linear_ordered_ring R] {a : R} (H : -1 ≤ a) (n : ℕ) : 1 + ↑n * (a - 1) ≤ a ^ n := sorry

/-- Bernoulli's inequality reformulated to estimate `(n : K)`. -/
theorem nat.cast_le_pow_sub_div_sub {K : Type u_1} [linear_ordered_field K] {a : K} (H : 1 < a) (n : ℕ) : ↑n ≤ (a ^ n - 1) / (a - 1) :=
  iff.mpr (le_div_iff (iff.mpr sub_pos H))
    (le_sub_left_of_add_le (one_add_mul_sub_le_pow (has_le.le.trans (neg_le_self zero_le_one) (has_lt.lt.le H)) n))

/-- For any `a > 1` and a natural `n` we have `n ≤ a ^ n / (a - 1)`. See also
`nat.cast_le_pow_sub_div_sub` for a stronger inequality with `a ^ n - 1` in the numerator. -/
theorem nat.cast_le_pow_div_sub {K : Type u_1} [linear_ordered_field K] {a : K} (H : 1 < a) (n : ℕ) : ↑n ≤ a ^ n / (a - 1) :=
  has_le.le.trans (nat.cast_le_pow_sub_div_sub H n)
    (div_le_div_of_le (iff.mpr sub_nonneg (has_lt.lt.le H)) (sub_le_self (a ^ n) zero_le_one))

namespace int

theorem units_pow_two (u : units ℤ) : u ^ bit0 1 = 1 :=
  Eq.symm (pow_two u) ▸ units_mul_self u

theorem units_pow_eq_pow_mod_two (u : units ℤ) (n : ℕ) : u ^ n = u ^ (n % bit0 1) := sorry

@[simp] theorem nat_abs_pow_two (x : ℤ) : ↑(nat_abs x) ^ bit0 1 = x ^ bit0 1 :=
  eq.mpr (id (Eq._oldrec (Eq.refl (↑(nat_abs x) ^ bit0 1 = x ^ bit0 1)) (pow_two ↑(nat_abs x))))
    (eq.mpr (id (Eq._oldrec (Eq.refl (↑(nat_abs x) * ↑(nat_abs x) = x ^ bit0 1)) (nat_abs_mul_self' x)))
      (eq.mpr (id (Eq._oldrec (Eq.refl (x * x = x ^ bit0 1)) (pow_two x))) (Eq.refl (x * x))))

theorem abs_le_self_pow_two (a : ℤ) : ↑(nat_abs a) ≤ a ^ bit0 1 := sorry

theorem le_self_pow_two (b : ℤ) : b ≤ b ^ bit0 1 :=
  le_trans le_nat_abs (abs_le_self_pow_two b)

end int

/-- Monoid homomorphisms from `multiplicative ℕ` are defined by the image
of `multiplicative.of_add 1`. -/
def powers_hom (M : Type u) [monoid M] : M ≃ (multiplicative ℕ →* M) :=
  equiv.mk
    (fun (x : M) => monoid_hom.mk (fun (n : multiplicative ℕ) => x ^ coe_fn multiplicative.to_add n) (pow_zero x) sorry)
    (fun (f : multiplicative ℕ →* M) => coe_fn f (coe_fn multiplicative.of_add 1)) pow_one sorry

/-- Monoid homomorphisms from `multiplicative ℤ` are defined by the image
of `multiplicative.of_add 1`. -/
def gpowers_hom (G : Type w) [group G] : G ≃ (multiplicative ℤ →* G) :=
  equiv.mk
    (fun (x : G) => monoid_hom.mk (fun (n : multiplicative ℤ) => x ^ coe_fn multiplicative.to_add n) (gpow_zero x) sorry)
    (fun (f : multiplicative ℤ →* G) => coe_fn f (coe_fn multiplicative.of_add 1)) gpow_one sorry

/-- Additive homomorphisms from `ℕ` are defined by the image of `1`. -/
def multiples_hom (A : Type y) [add_monoid A] : A ≃ (ℕ →+ A) :=
  equiv.mk (fun (x : A) => add_monoid_hom.mk (fun (n : ℕ) => n •ℕ x) (zero_nsmul x) sorry)
    (fun (f : ℕ →+ A) => coe_fn f 1) one_nsmul sorry

/-- Additive homomorphisms from `ℤ` are defined by the image of `1`. -/
def gmultiples_hom (A : Type y) [add_group A] : A ≃ (ℤ →+ A) :=
  equiv.mk (fun (x : A) => add_monoid_hom.mk (fun (n : ℤ) => n •ℤ x) (zero_gsmul x) sorry)
    (fun (f : ℤ →+ A) => coe_fn f 1) one_gsmul sorry

@[simp] theorem powers_hom_apply {M : Type u} [monoid M] (x : M) (n : multiplicative ℕ) : coe_fn (coe_fn (powers_hom M) x) n = x ^ coe_fn multiplicative.to_add n :=
  rfl

@[simp] theorem powers_hom_symm_apply {M : Type u} [monoid M] (f : multiplicative ℕ →* M) : coe_fn (equiv.symm (powers_hom M)) f = coe_fn f (coe_fn multiplicative.of_add 1) :=
  rfl

@[simp] theorem gpowers_hom_apply {G : Type w} [group G] (x : G) (n : multiplicative ℤ) : coe_fn (coe_fn (gpowers_hom G) x) n = x ^ coe_fn multiplicative.to_add n :=
  rfl

@[simp] theorem gpowers_hom_symm_apply {G : Type w} [group G] (f : multiplicative ℤ →* G) : coe_fn (equiv.symm (gpowers_hom G)) f = coe_fn f (coe_fn multiplicative.of_add 1) :=
  rfl

@[simp] theorem multiples_hom_apply {A : Type y} [add_monoid A] (x : A) (n : ℕ) : coe_fn (coe_fn (multiples_hom A) x) n = n •ℕ x :=
  rfl

@[simp] theorem multiples_hom_symm_apply {A : Type y} [add_monoid A] (f : ℕ →+ A) : coe_fn (equiv.symm (multiples_hom A)) f = coe_fn f 1 :=
  rfl

@[simp] theorem gmultiples_hom_apply {A : Type y} [add_group A] (x : A) (n : ℤ) : coe_fn (coe_fn (gmultiples_hom A) x) n = n •ℤ x :=
  rfl

@[simp] theorem gmultiples_hom_symm_apply {A : Type y} [add_group A] (f : ℤ →+ A) : coe_fn (equiv.symm (gmultiples_hom A)) f = coe_fn f 1 :=
  rfl

theorem monoid_hom.apply_mnat {M : Type u} [monoid M] (f : multiplicative ℕ →* M) (n : multiplicative ℕ) : coe_fn f n = coe_fn f (coe_fn multiplicative.of_add 1) ^ coe_fn multiplicative.to_add n := sorry

theorem monoid_hom.ext_mnat {M : Type u} [monoid M] {f : multiplicative ℕ →* M} {g : multiplicative ℕ →* M} (h : coe_fn f (coe_fn multiplicative.of_add 1) = coe_fn g (coe_fn multiplicative.of_add 1)) : f = g := sorry

theorem monoid_hom.apply_mint {M : Type u} [group M] (f : multiplicative ℤ →* M) (n : multiplicative ℤ) : coe_fn f n = coe_fn f (coe_fn multiplicative.of_add 1) ^ coe_fn multiplicative.to_add n := sorry

theorem monoid_hom.ext_mint {M : Type u} [group M] {f : multiplicative ℤ →* M} {g : multiplicative ℤ →* M} (h : coe_fn f (coe_fn multiplicative.of_add 1) = coe_fn g (coe_fn multiplicative.of_add 1)) : f = g := sorry

theorem add_monoid_hom.apply_nat {M : Type u} [add_monoid M] (f : ℕ →+ M) (n : ℕ) : coe_fn f n = n •ℕ coe_fn f 1 := sorry

/-! `add_monoid_hom.ext_nat` is defined in `data.nat.cast` -/

theorem add_monoid_hom.apply_int {M : Type u} [add_group M] (f : ℤ →+ M) (n : ℤ) : coe_fn f n = n •ℤ coe_fn f 1 := sorry

/-! `add_monoid_hom.ext_int` is defined in `data.int.cast` -/

/-- If `M` is commutative, `powers_hom` is a multiplicative equivalence. -/
def powers_mul_hom (M : Type u) [comm_monoid M] : M ≃* (multiplicative ℕ →* M) :=
  mul_equiv.mk (equiv.to_fun (powers_hom M)) (equiv.inv_fun (powers_hom M)) sorry sorry sorry

/-- If `M` is commutative, `gpowers_hom` is a multiplicative equivalence. -/
def gpowers_mul_hom (G : Type w) [comm_group G] : G ≃* (multiplicative ℤ →* G) :=
  mul_equiv.mk (equiv.to_fun (gpowers_hom G)) (equiv.inv_fun (gpowers_hom G)) sorry sorry sorry

/-- If `M` is commutative, `multiples_hom` is an additive equivalence. -/
def multiples_add_hom (A : Type y) [add_comm_monoid A] : A ≃+ (ℕ →+ A) :=
  add_equiv.mk (equiv.to_fun (multiples_hom A)) (equiv.inv_fun (multiples_hom A)) sorry sorry sorry

/-- If `M` is commutative, `gmultiples_hom` is an additive equivalence. -/
def gmultiples_add_hom (A : Type y) [add_comm_group A] : A ≃+ (ℤ →+ A) :=
  add_equiv.mk (equiv.to_fun (gmultiples_hom A)) (equiv.inv_fun (gmultiples_hom A)) sorry sorry sorry

@[simp] theorem powers_mul_hom_apply {M : Type u} [comm_monoid M] (x : M) (n : multiplicative ℕ) : coe_fn (coe_fn (powers_mul_hom M) x) n = x ^ coe_fn multiplicative.to_add n :=
  rfl

@[simp] theorem powers_mul_hom_symm_apply {M : Type u} [comm_monoid M] (f : multiplicative ℕ →* M) : coe_fn (mul_equiv.symm (powers_mul_hom M)) f = coe_fn f (coe_fn multiplicative.of_add 1) :=
  rfl

@[simp] theorem gpowers_mul_hom_apply {G : Type w} [comm_group G] (x : G) (n : multiplicative ℤ) : coe_fn (coe_fn (gpowers_mul_hom G) x) n = x ^ coe_fn multiplicative.to_add n :=
  rfl

@[simp] theorem gpowers_mul_hom_symm_apply {G : Type w} [comm_group G] (f : multiplicative ℤ →* G) : coe_fn (mul_equiv.symm (gpowers_mul_hom G)) f = coe_fn f (coe_fn multiplicative.of_add 1) :=
  rfl

@[simp] theorem multiples_add_hom_apply {A : Type y} [add_comm_monoid A] (x : A) (n : ℕ) : coe_fn (coe_fn (multiples_add_hom A) x) n = n •ℕ x :=
  rfl

@[simp] theorem multiples_add_hom_symm_apply {A : Type y} [add_comm_monoid A] (f : ℕ →+ A) : coe_fn (add_equiv.symm (multiples_add_hom A)) f = coe_fn f 1 :=
  rfl

@[simp] theorem gmultiples_add_hom_apply {A : Type y} [add_comm_group A] (x : A) (n : ℤ) : coe_fn (coe_fn (gmultiples_add_hom A) x) n = n •ℤ x :=
  rfl

@[simp] theorem gmultiples_add_hom_symm_apply {A : Type y} [add_comm_group A] (f : ℤ →+ A) : coe_fn (add_equiv.symm (gmultiples_add_hom A)) f = coe_fn f 1 :=
  rfl

/-!
### Commutativity (again)

Facts about `semiconj_by` and `commute` that require `gpow` or `gsmul`, or the fact that integer
multiplication equals semiring multiplication.
-/

namespace semiconj_by

@[simp] theorem cast_nat_mul_right {R : Type u₁} [semiring R] {a : R} {x : R} {y : R} (h : semiconj_by a x y) (n : ℕ) : semiconj_by a (↑n * x) (↑n * y) :=
  mul_right (nat.commute_cast a n) h

@[simp] theorem cast_nat_mul_left {R : Type u₁} [semiring R] {a : R} {x : R} {y : R} (h : semiconj_by a x y) (n : ℕ) : semiconj_by (↑n * a) x y :=
  mul_left (nat.cast_commute n y) h

@[simp] theorem cast_nat_mul_cast_nat_mul {R : Type u₁} [semiring R] {a : R} {x : R} {y : R} (h : semiconj_by a x y) (m : ℕ) (n : ℕ) : semiconj_by (↑m * a) (↑n * x) (↑n * y) :=
  cast_nat_mul_right (cast_nat_mul_left h m) n

@[simp] theorem units_gpow_right {M : Type u} [monoid M] {a : M} {x : units M} {y : units M} (h : semiconj_by a ↑x ↑y) (m : ℤ) : semiconj_by a ↑(x ^ m) ↑(y ^ m) := sorry

@[simp] theorem cast_int_mul_right {R : Type u₁} [ring R] {a : R} {x : R} {y : R} (h : semiconj_by a x y) (m : ℤ) : semiconj_by a (↑m * x) (↑m * y) :=
  mul_right (int.commute_cast a m) h

@[simp] theorem cast_int_mul_left {R : Type u₁} [ring R] {a : R} {x : R} {y : R} (h : semiconj_by a x y) (m : ℤ) : semiconj_by (↑m * a) x y :=
  mul_left (int.cast_commute m y) h

@[simp] theorem cast_int_mul_cast_int_mul {R : Type u₁} [ring R] {a : R} {x : R} {y : R} (h : semiconj_by a x y) (m : ℤ) (n : ℤ) : semiconj_by (↑m * a) (↑n * x) (↑n * y) :=
  cast_int_mul_right (cast_int_mul_left h m) n

end semiconj_by

namespace commute

@[simp] theorem cast_nat_mul_right {R : Type u₁} [semiring R] {a : R} {b : R} (h : commute a b) (n : ℕ) : commute a (↑n * b) :=
  semiconj_by.cast_nat_mul_right h n

@[simp] theorem cast_nat_mul_left {R : Type u₁} [semiring R] {a : R} {b : R} (h : commute a b) (n : ℕ) : commute (↑n * a) b :=
  semiconj_by.cast_nat_mul_left h n

@[simp] theorem cast_nat_mul_cast_nat_mul {R : Type u₁} [semiring R] {a : R} {b : R} (h : commute a b) (m : ℕ) (n : ℕ) : commute (↑m * a) (↑n * b) :=
  semiconj_by.cast_nat_mul_cast_nat_mul h m n

@[simp] theorem self_cast_nat_mul {R : Type u₁} [semiring R] {a : R} (n : ℕ) : commute a (↑n * a) :=
  cast_nat_mul_right (commute.refl a) n

@[simp] theorem cast_nat_mul_self {R : Type u₁} [semiring R] {a : R} (n : ℕ) : commute (↑n * a) a :=
  cast_nat_mul_left (commute.refl a) n

@[simp] theorem self_cast_nat_mul_cast_nat_mul {R : Type u₁} [semiring R] {a : R} (m : ℕ) (n : ℕ) : commute (↑m * a) (↑n * a) :=
  cast_nat_mul_cast_nat_mul (commute.refl a) m n

@[simp] theorem units_gpow_right {M : Type u} [monoid M] {a : M} {u : units M} (h : commute a ↑u) (m : ℤ) : commute a ↑(u ^ m) :=
  semiconj_by.units_gpow_right h m

@[simp] theorem units_gpow_left {M : Type u} [monoid M] {u : units M} {a : M} (h : commute (↑u) a) (m : ℤ) : commute (↑(u ^ m)) a :=
  commute.symm (units_gpow_right (commute.symm h) m)

@[simp] theorem cast_int_mul_right {R : Type u₁} [ring R] {a : R} {b : R} (h : commute a b) (m : ℤ) : commute a (↑m * b) :=
  semiconj_by.cast_int_mul_right h m

@[simp] theorem cast_int_mul_left {R : Type u₁} [ring R] {a : R} {b : R} (h : commute a b) (m : ℤ) : commute (↑m * a) b :=
  semiconj_by.cast_int_mul_left h m

theorem cast_int_mul_cast_int_mul {R : Type u₁} [ring R] {a : R} {b : R} (h : commute a b) (m : ℤ) (n : ℤ) : commute (↑m * a) (↑n * b) :=
  semiconj_by.cast_int_mul_cast_int_mul h m n

@[simp] theorem self_cast_int_mul {R : Type u₁} [ring R] (a : R) (n : ℤ) : commute a (↑n * a) :=
  cast_int_mul_right (commute.refl a) n

@[simp] theorem cast_int_mul_self {R : Type u₁} [ring R] (a : R) (n : ℤ) : commute (↑n * a) a :=
  cast_int_mul_left (commute.refl a) n

theorem self_cast_int_mul_cast_int_mul {R : Type u₁} [ring R] (a : R) (m : ℤ) (n : ℤ) : commute (↑m * a) (↑n * a) :=
  cast_int_mul_cast_int_mul (commute.refl a) m n

end commute

@[simp] theorem nat.to_add_pow (a : multiplicative ℕ) (b : ℕ) : coe_fn multiplicative.to_add (a ^ b) = coe_fn multiplicative.to_add a * b := sorry

@[simp] theorem nat.of_add_mul (a : ℕ) (b : ℕ) : coe_fn multiplicative.of_add (a * b) = coe_fn multiplicative.of_add a ^ b :=
  Eq.symm (nat.to_add_pow a b)

@[simp] theorem int.to_add_pow (a : multiplicative ℤ) (b : ℕ) : coe_fn multiplicative.to_add (a ^ b) = coe_fn multiplicative.to_add a * ↑b := sorry

@[simp] theorem int.to_add_gpow (a : multiplicative ℤ) (b : ℤ) : coe_fn multiplicative.to_add (a ^ b) = coe_fn multiplicative.to_add a * b := sorry

@[simp] theorem int.of_add_mul (a : ℤ) (b : ℤ) : coe_fn multiplicative.of_add (a * b) = coe_fn multiplicative.of_add a ^ b :=
  Eq.symm (int.to_add_gpow a b)

namespace units

theorem conj_pow {M : Type u} [monoid M] (u : units M) (x : M) (n : ℕ) : (↑u * x * ↑(u⁻¹)) ^ n = ↑u * x ^ n * ↑(u⁻¹) :=
  Eq.symm (iff.mpr divp_eq_iff_mul_eq (Eq.symm (semiconj_by.eq (semiconj_by.pow_right (mk_semiconj_by u x) n))))

theorem conj_pow' {M : Type u} [monoid M] (u : units M) (x : M) (n : ℕ) : (↑(u⁻¹) * x * ↑u) ^ n = ↑(u⁻¹) * x ^ n * ↑u :=
  conj_pow (u⁻¹) x n

/-- Moving to the opposite monoid commutes with taking powers. -/
@[simp] theorem op_pow {M : Type u} [monoid M] (x : M) (n : ℕ) : opposite.op (x ^ n) = opposite.op x ^ n := sorry

@[simp] theorem unop_pow {M : Type u} [monoid M] (x : Mᵒᵖ) (n : ℕ) : opposite.unop (x ^ n) = opposite.unop x ^ n := sorry


import linear_algebra.projective_space.basic
import tactic.field_simp

variables (K V W : Type*) [field K] [add_comm_group V] [module K V]
  [add_comm_group W] [module K W]

namespace projectivization

def affine_embedding : V → ℙ K (K × V) :=
λ v, mk _ (1,v) (by simp)

lemma affine_embedding_injective : function.injective (affine_embedding K V) :=
begin
  intros a b h,
  erw mk_eq_mk_iff at h,
  obtain ⟨u,h⟩ := h,
  simp only [prod.smul_mk, prod.mk.inj_iff] at h,
  have : u = 1,
  { ext, convert h.1, rw [units.smul_def], simp },
  have h2 := h.2,
  rw this at h2,
  simpa using h2.symm
end

lemma ne_of_leading_one_of_leading_zero (v w : V) (h : w ≠ 0) :
  (mk K (1,v) (by simp) : ℙ K (K × V)) ≠ mk K (0,w) (by simpa) :=
begin
  intro c,
  rw mk_eq_mk_iff at c,
  obtain ⟨u,hu⟩ := c,
  simpa using hu,
end

def affine_embedding_of_nonzero (u : K) (hu : u ≠ 0) : V → ℙ K (K × V) :=
λ v, mk _ (u,v) (by simpa)

lemma affine_embedding_of_nonzero_injective (u : K) (hu : u ≠ 0) :
  function.injective (affine_embedding_of_nonzero K V u hu) :=
begin
  intros a b h,
  erw mk_eq_mk_iff at h,
  obtain ⟨t,ht⟩ := h,
  simp only [prod.smul_mk, prod.mk.inj_iff] at ht,
  cases ht with h1 h2,
  have : t = 1,
  { change (t : K) * u = u at h1, apply_fun (λ e, e * u⁻¹) at h1,
    field_simp at h1, exact h1 },
  rw this at h2,
  simpa using h2.symm,
end

lemma ne_of_leading_nonzero_of_leading_zero (v w : V) (h : w ≠ 0)
  (a : K) (ha : a ≠ 0) :
  (mk K (a,v) (by simpa) : ℙ K (K × V)) ≠ mk K (0,w) (by simpa) :=
begin
  intro c,
  rw mk_eq_mk_iff at c,
  obtain ⟨t,ht⟩ := c,
  simp only [prod.smul_mk, smul_zero, prod.mk.inj_iff] at ht,
  exact ha (ht.1.symm)
end

end projectivization


/-
Copyright (c) 2022 Julian Kuelshammer. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author : Julian Kuelshammer
-/

import easy_mode.sheet10

notation `myrat` := quotient t

attribute [instance] t

namespace «myrat»

lemma equiv_def (r s : int_plane_non_zero) :
r ≈ s ↔ r.1 * s.2 = s.1 * r.2 :=
begin
  sorry
end

def neg : myrat → myrat := _
begin
  sorry
end

instance : has_neg myrat :=
{ neg := neg }

def add : myrat → myrat → myrat := _

instance : has_add myrat :=
{ add := add }

def mul : myrat → myrat → myrat := _

instance : has_mul myrat :=
{ mul := mul }

/- Let's try to prove that `myrat` together with these operations forms a commutative ring. -/
instance comm_ring : comm_ring myrat :=
_
/- But we know that even better, the non-zero rational numbers have an inverse, i.e. the rational numbers
  form a field. Let's try to prove that. -/

instance : has_inv myrat :=
_

instance : field myrat :=
_

end «myrat»


/-
Copyright (c) 2021 Yury G. Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury G. Kudryashov
-/
import geometry.manifold.diffeomorph
import geometry.manifold.instances.real
import geometry.manifold.partition_of_unity

/-!
# Whitney embedding theorem

In this file we prove a version of the Whitney embedding theorem: for any compact real manifold `M`,
for sufficiently large `n` there exists a smooth embedding `M → ℝ^n`.

## TODO

* Prove the weak Whitney embedding theorem: any `σ`-compact smooth `m`-dimensional manifold can be
  embedded into `ℝ^(2m+1)`. This requires a version of Sard's theorem: for a locally Lipschitz
  continuous map `f : ℝ^m → ℝ^n`, `m < n`, the range has Hausdorff dimension at most `m`, hence it
  has measure zero.

## Tags

partition of unity, smooth bump function, whitney theorem
-/

universes uι uE uH uM
variables {ι : Type uι}
{E : Type uE} [normed_add_comm_group E] [normed_space ℝ E] [finite_dimensional ℝ E]
{H : Type uH} [topological_space H] {I : model_with_corners ℝ E H}
{M : Type uM} [topological_space M] [charted_space H M] [smooth_manifold_with_corners I M]

open function filter finite_dimensional set
open_locale topology manifold classical filter big_operators

noncomputable theory

namespace smooth_bump_covering

/-!
### Whitney embedding theorem

In this section we prove a version of the Whitney embedding theorem: for any compact real manifold
`M`, for sufficiently large `n` there exists a smooth embedding `M → ℝ^n`.
-/

variables [t2_space M] [hi : fintype ι] {s : set M} (f : smooth_bump_covering ι I M s)
include hi

/-- Smooth embedding of `M` into `(E × ℝ) ^ ι`. -/
def embedding_pi_tangent : C^∞⟮I, M; 𝓘(ℝ, ι → (E × ℝ)), ι → (E × ℝ)⟯ :=
{ to_fun := λ x i, (f i x • ext_chart_at I (f.c i) x, f i x),
  cont_mdiff_to_fun := cont_mdiff_pi_space.2 $ λ i,
    ((f i).smooth_smul cont_mdiff_on_ext_chart_at).prod_mk_space ((f i).smooth) }

local attribute [simp] lemma embedding_pi_tangent_coe :
  ⇑f.embedding_pi_tangent = λ x i, (f i x • ext_chart_at I (f.c i) x, f i x) :=
rfl

lemma embedding_pi_tangent_inj_on : inj_on f.embedding_pi_tangent s :=
begin
  intros x hx y hy h,
  simp only [embedding_pi_tangent_coe, funext_iff] at h,
  obtain ⟨h₁, h₂⟩ := prod.mk.inj_iff.1 (h (f.ind x hx)),
  rw [f.apply_ind x hx] at h₂,
  rw [← h₂, f.apply_ind x hx, one_smul, one_smul] at h₁,
  have := f.mem_ext_chart_at_source_of_eq_one h₂.symm,
  exact (ext_chart_at I (f.c _)).inj_on (f.mem_ext_chart_at_ind_source x hx) this h₁
end

lemma embedding_pi_tangent_injective (f : smooth_bump_covering ι I M) :
  injective f.embedding_pi_tangent :=
injective_iff_inj_on_univ.2 f.embedding_pi_tangent_inj_on

lemma comp_embedding_pi_tangent_mfderiv (x : M) (hx : x ∈ s) :
  ((continuous_linear_map.fst ℝ E ℝ).comp
    (@continuous_linear_map.proj ℝ _ ι (λ _, E × ℝ) _ _
      (λ _, infer_instance) (f.ind x hx))).comp
      (mfderiv I 𝓘(ℝ, ι → (E × ℝ)) f.embedding_pi_tangent x) =
  mfderiv I I (chart_at H (f.c (f.ind x hx))) x :=
begin
  set L := ((continuous_linear_map.fst ℝ E ℝ).comp
    (@continuous_linear_map.proj ℝ _ ι (λ _, E × ℝ) _ _ (λ _, infer_instance) (f.ind x hx))),
  have := L.has_mfderiv_at.comp x f.embedding_pi_tangent.mdifferentiable_at.has_mfderiv_at,
  convert has_mfderiv_at_unique this _,
  refine (has_mfderiv_at_ext_chart_at I (f.mem_chart_at_ind_source x hx)).congr_of_eventually_eq _,
  refine (f.eventually_eq_one x hx).mono (λ y hy, _),
  simp only [embedding_pi_tangent_coe, continuous_linear_map.coe_comp', (∘),
    continuous_linear_map.coe_fst', continuous_linear_map.proj_apply],
  rw [hy, pi.one_apply, one_smul]
end

lemma embedding_pi_tangent_ker_mfderiv (x : M) (hx : x ∈ s) :
  linear_map.ker (mfderiv I 𝓘(ℝ, ι → (E × ℝ)) f.embedding_pi_tangent x) = ⊥ :=
begin
  apply bot_unique,
  rw [← (mdifferentiable_chart I (f.c (f.ind x hx))).ker_mfderiv_eq_bot
    (f.mem_chart_at_ind_source x hx), ← comp_embedding_pi_tangent_mfderiv],
  exact linear_map.ker_le_ker_comp _ _
end

lemma embedding_pi_tangent_injective_mfderiv (x : M) (hx : x ∈ s) :
  injective (mfderiv I 𝓘(ℝ, ι → (E × ℝ)) f.embedding_pi_tangent x) :=
linear_map.ker_eq_bot.1 (f.embedding_pi_tangent_ker_mfderiv x hx)

omit hi

/-- Baby version of the **Whitney weak embedding theorem**: if `M` admits a finite covering by
supports of bump functions, then for some `n` it can be immersed into the `n`-dimensional
Euclidean space. -/
lemma exists_immersion_euclidean [finite ι] (f : smooth_bump_covering ι I M) :
  ∃ (n : ℕ) (e : M → euclidean_space ℝ (fin n)), smooth I (𝓡 n) e ∧
    injective e ∧ ∀ x : M, injective (mfderiv I (𝓡 n) e x) :=
begin
  casesI nonempty_fintype ι,
  set F := euclidean_space ℝ (fin $ finrank ℝ (ι → (E × ℝ))),
  letI : is_noetherian ℝ (E × ℝ) := is_noetherian.iff_fg.2 infer_instance,
  letI : finite_dimensional ℝ (ι → E × ℝ) := is_noetherian.iff_fg.1 infer_instance,
  set eEF : (ι → (E × ℝ)) ≃L[ℝ] F :=
    continuous_linear_equiv.of_finrank_eq finrank_euclidean_space_fin.symm,
  refine ⟨_, eEF ∘ f.embedding_pi_tangent,
    eEF.to_diffeomorph.smooth.comp f.embedding_pi_tangent.smooth,
    eEF.injective.comp f.embedding_pi_tangent_injective, λ x, _⟩,
  rw [mfderiv_comp _ eEF.differentiable_at.mdifferentiable_at
    f.embedding_pi_tangent.mdifferentiable_at, eEF.mfderiv_eq],
  exact eEF.injective.comp (f.embedding_pi_tangent_injective_mfderiv _ trivial)
end

end smooth_bump_covering

/-- Baby version of the Whitney weak embedding theorem: if `M` admits a finite covering by
supports of bump functions, then for some `n` it can be embedded into the `n`-dimensional
Euclidean space. -/
lemma exists_embedding_euclidean_of_compact [t2_space M] [compact_space M] :
  ∃ (n : ℕ) (e : M → euclidean_space ℝ (fin n)), smooth I (𝓡 n) e ∧
    closed_embedding e ∧ ∀ x : M, injective (mfderiv I (𝓡 n) e x) :=
begin
  rcases smooth_bump_covering.exists_is_subordinate I is_closed_univ (λ (x : M) _, univ_mem)
    with ⟨ι, f, -⟩,
  haveI := f.fintype,
  rcases f.exists_immersion_euclidean with ⟨n, e, hsmooth, hinj, hinj_mfderiv⟩,
  exact ⟨n, e, hsmooth, hsmooth.continuous.closed_embedding hinj, hinj_mfderiv⟩
end


import basic_definitions.group_representation
import linear_algebra.direct_sum_module
universes u v w u₁
variables (R : Type u) [ring R]
          (G : Type v)[group G]
          (ι : Type w) [decidable_eq ι]
          (M : ι → Type w)
          [Π i, add_comm_group (M i)]
          [Π i, module R (M i)]
          (ρ  : Π i, group_representation G R (M i))

variables (i : ι ) (g : G) (x y : M i)
#check ρ i g (x+y)
example : ρ i g (x+y) = ρ i g (x) +ρ i g (y) := begin
    rw (ρ i g).map_add,
end
#check direct_sum ι M
#check direct_sum.lof R ι  M i
#check   direct_sum.to_module  R ι ( direct_sum ι  M ) (λ i,  (direct_sum.lof R ι  M i) ⊚ ( ρ i g))
#check to_module_lof
open direct_sum
#check to_module_lof R i x

def direct_sum_representation : group_representation G R (direct_sum ι M) :=
{ to_fun    := λ g, direct_sum.to_module  R ι ( direct_sum ι  M ) (λ i,  (direct_sum.lof R ι  M i) ⊚ ( ρ i g)),
  map_one'  :=
    begin
    ext,let t :=
    @to_module_lof R _  ι _ M _ _ (direct_sum ι M) _ _ (λ i,  (direct_sum.lof R ι  M i) ⊚ ( ρ i 1)) i (x i),
    let h := lof_apply R i (x i),

    end,
  map_mul'  := _ }


/-
Copyright (c) 2021 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin

! This file was ported from Lean 3 source module ring_theory.henselian
! leanprover-community/mathlib commit d1accf4f9cddb3666c6e8e4da0ac2d19c4ed73f0
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Polynomial.Taylor
import Mathbin.RingTheory.Ideal.LocalRing
import Mathbin.LinearAlgebra.AdicCompletion

/-!
# Henselian rings

In this file we set up the basic theory of Henselian (local) rings.
A ring `R` is *Henselian* at an ideal `I` if the following conditions hold:
* `I` is contained in the Jacobson radical of `R`
* for every polynomial `f` over `R`, with a *simple* root `a₀` over the quotient ring `R/I`,
  there exists a lift `a : R` of `a₀` that is a root of `f`.

(Here, saying that a root `b` of a polynomial `g` is *simple* means that `g.derivative.eval b` is a
unit. Warning: if `R/I` is not a field then it is not enough to assume that `g` has a factorization
into monic linear factors in which `X - b` shows up only once; for example `1` is not a simple root
of `X^2-1` over `ℤ/4ℤ`.)

A local ring `R` is *Henselian* if it is Henselian at its maximal ideal.
In this case the first condition is automatic, and in the second condition we may ask for
`f.derivative.eval a ≠ 0`, since the quotient ring `R/I` is a field in this case.

## Main declarations

* `henselian_ring`: a typeclass on commutative rings,
  asserting that the ring is Henselian at the ideal `I`.
* `henselian_local_ring`: a typeclass on commutative rings,
   asserting that the ring is local Henselian.
* `field.henselian`: fields are Henselian local rings
* `henselian.tfae`: equivalent ways of expressing the Henselian property for local rings
* `is_adic_complete.henselian`:
  a ring `R` with ideal `I` that is `I`-adically complete is Henselian at `I`

## References

https://stacks.math.columbia.edu/tag/04GE

## Todo

After a good API for etale ring homomorphisms has been developed,
we can give more equivalent characterization os Henselian rings.

In particular, this can give a proof that factorizations into coprime polynomials can be lifted
from the residue field to the Henselian ring.

The following gist contains some code sketches in that direction.
https://gist.github.com/jcommelin/47d94e4af092641017a97f7f02bf9598

-/

noncomputable section

universe u v

open BigOperators Polynomial

open LocalRing Polynomial Function

theorem isLocalRingHom_of_le_jacobson_bot {R : Type _} [CommRing R] (I : Ideal R)
    (h : I ≤ Ideal.jacobson ⊥) : IsLocalRingHom (Ideal.Quotient.mk I) :=
  by
  constructor
  intro a h
  have : IsUnit (Ideal.Quotient.mk (Ideal.jacobson ⊥) a) :=
    by
    rw [isUnit_iff_exists_inv] at *
    obtain ⟨b, hb⟩ := h
    obtain ⟨b, rfl⟩ := Ideal.Quotient.mk_surjective b
    use Ideal.Quotient.mk _ b
    rw [← (Ideal.Quotient.mk _).map_one, ← (Ideal.Quotient.mk _).map_mul, Ideal.Quotient.eq] at hb⊢
    exact h hb
  obtain ⟨⟨x, y, h1, h2⟩, rfl : x = _⟩ := this
  obtain ⟨y, rfl⟩ := Ideal.Quotient.mk_surjective y
  rw [← (Ideal.Quotient.mk _).map_mul, ← (Ideal.Quotient.mk _).map_one, Ideal.Quotient.eq,
    Ideal.mem_jacobson_bot] at h1 h2
  specialize h1 1
  simp at h1
  exact h1.1
#align is_local_ring_hom_of_le_jacobson_bot isLocalRingHom_of_le_jacobson_bot

/-- A ring `R` is *Henselian* at an ideal `I` if the following condition holds:
for every polynomial `f` over `R`, with a *simple* root `a₀` over the quotient ring `R/I`,
there exists a lift `a : R` of `a₀` that is a root of `f`.

(Here, saying that a root `b` of a polynomial `g` is *simple* means that `g.derivative.eval b` is a
unit. Warning: if `R/I` is not a field then it is not enough to assume that `g` has a factorization
into monic linear factors in which `X - b` shows up only once; for example `1` is not a simple root
of `X^2-1` over `ℤ/4ℤ`.) -/
class HenselianRing (R : Type _) [CommRing R] (I : Ideal R) : Prop where
  jac : I ≤ Ideal.jacobson ⊥
  is_henselian :
    ∀ (f : R[X]) (hf : f.Monic) (a₀ : R) (h₁ : f.eval a₀ ∈ I)
      (h₂ : IsUnit (Ideal.Quotient.mk I (f.derivative.eval a₀))), ∃ a : R, f.IsRoot a ∧ a - a₀ ∈ I
#align henselian_ring HenselianRing

/-- A local ring `R` is *Henselian* if the following condition holds:
for every polynomial `f` over `R`, with a *simple* root `a₀` over the residue field,
there exists a lift `a : R` of `a₀` that is a root of `f`.
(Recall that a root `b` of a polynomial `g` is *simple* if it is not a double root, so if
`g.derivative.eval b ≠ 0`.)

In other words, `R` is local Henselian if it is Henselian at the ideal `I`,
in the sense of `henselian_ring`. -/
class HenselianLocalRing (R : Type _) [CommRing R] extends LocalRing R : Prop where
  is_henselian :
    ∀ (f : R[X]) (hf : f.Monic) (a₀ : R) (h₁ : f.eval a₀ ∈ maximalIdeal R)
      (h₂ : IsUnit (f.derivative.eval a₀)), ∃ a : R, f.IsRoot a ∧ a - a₀ ∈ maximalIdeal R
#align henselian_local_ring HenselianLocalRing

-- see Note [lower instance priority]
instance (priority := 100) Field.henselian (K : Type _) [Field K] : HenselianLocalRing K
    where is_henselian f hf a₀ h₁ h₂ :=
    by
    refine' ⟨a₀, _, _⟩ <;> rwa [(maximal_ideal K).eq_bot_of_prime, Ideal.mem_bot] at *
    rw [sub_self]
#align field.henselian Field.henselian

theorem HenselianLocalRing.tFAE (R : Type u) [CommRing R] [LocalRing R] :
    TFAE
      [HenselianLocalRing R,
        ∀ (f : R[X]) (hf : f.Monic) (a₀ : ResidueField R) (h₁ : aeval a₀ f = 0)
          (h₂ : aeval a₀ f.derivative ≠ 0), ∃ a : R, f.IsRoot a ∧ residue R a = a₀,
        ∀ {K : Type u} [Field K],
          ∀ (φ : R →+* K) (hφ : surjective φ) (f : R[X]) (hf : f.Monic) (a₀ : K)
            (h₁ : f.eval₂ φ a₀ = 0) (h₂ : f.derivative.eval₂ φ a₀ ≠ 0),
            ∃ a : R, f.IsRoot a ∧ φ a = a₀] :=
  by
  tfae_have _3_2 : 3 → 2;
  · intro H
    exact H (residue R) Ideal.Quotient.mk_surjective
  tfae_have _2_1 : 2 → 1
  · intro H
    constructor
    intro f hf a₀ h₁ h₂
    specialize H f hf (residue R a₀)
    have aux := flip mem_nonunits_iff.mp h₂
    simp only [aeval_def, residue_field.algebra_map_eq, eval₂_at_apply, ←
      Ideal.Quotient.eq_zero_iff_mem, ← LocalRing.mem_maximalIdeal] at H h₁ aux
    obtain ⟨a, ha₁, ha₂⟩ := H h₁ aux
    refine' ⟨a, ha₁, _⟩
    rw [← Ideal.Quotient.eq_zero_iff_mem]
    rwa [← sub_eq_zero, ← RingHom.map_sub] at ha₂
  tfae_have _1_3 : 1 → 3
  · intro hR K _K φ hφ f hf a₀ h₁ h₂
    obtain ⟨a₀, rfl⟩ := hφ a₀
    have H := HenselianLocalRing.is_henselian f hf a₀
    simp only [← ker_eq_maximal_ideal φ hφ, eval₂_at_apply, φ.mem_ker] at H h₁ h₂
    obtain ⟨a, ha₁, ha₂⟩ := H h₁ _
    · refine' ⟨a, ha₁, _⟩
      rwa [φ.map_sub, sub_eq_zero] at ha₂
    · contrapose! h₂
      rwa [← mem_nonunits_iff, ← LocalRing.mem_maximalIdeal, ← LocalRing.ker_eq_maximalIdeal φ hφ,
        φ.mem_ker] at h₂
  tfae_finish
#align henselian_local_ring.tfae HenselianLocalRing.tFAE

instance (R : Type _) [CommRing R] [hR : HenselianLocalRing R] : HenselianRing R (maximalIdeal R)
    where
  jac := by
    rw [Ideal.jacobson, le_infₛ_iff]
    rintro I ⟨-, hI⟩
    exact (eq_maximal_ideal hI).ge
  is_henselian := by
    intro f hf a₀ h₁ h₂
    refine' HenselianLocalRing.is_henselian f hf a₀ h₁ _
    contrapose! h₂
    rw [← mem_nonunits_iff, ← LocalRing.mem_maximalIdeal, ← Ideal.Quotient.eq_zero_iff_mem] at h₂
    rw [h₂]
    exact not_isUnit_zero

-- see Note [lower instance priority]
/-- A ring `R` that is `I`-adically complete is Henselian at `I`. -/
instance (priority := 100) IsAdicComplete.henselianRing (R : Type _) [CommRing R] (I : Ideal R)
    [IsAdicComplete I R] : HenselianRing R I
    where
  jac := IsAdicComplete.le_jacobson_bot _
  is_henselian := by
    intro f hf a₀ h₁ h₂
    classical
      let f' := f.derivative
      -- we define a sequence `c n` by starting at `a₀` and then continually
      -- applying the function sending `b` to `b - f(b)/f'(b)` (Newton's method).
      -- Note that `f'.eval b` is a unit, because `b` has the same residue as `a₀` modulo `I`.
      let c : ℕ → R := fun n => Nat.recOn n a₀ fun _ b => b - f.eval b * Ring.inverse (f'.eval b)
      have hc : ∀ n, c (n + 1) = c n - f.eval (c n) * Ring.inverse (f'.eval (c n)) :=
        by
        intro n
        dsimp only [c, Nat.rec_add_one]
        rfl
      -- we now spend some time determining properties of the sequence `c : ℕ → R`
      -- `hc_mod`: for every `n`, we have `c n ≡ a₀ [SMOD I]`
      -- `hf'c`  : for every `n`, `f'.eval (c n)` is a unit
      -- `hfcI`  : for every `n`, `f.eval (c n)` is contained in `I ^ (n+1)`
      have hc_mod : ∀ n, c n ≡ a₀ [SMOD I] := by
        intro n
        induction' n with n ih
        · rfl
        rw [Nat.succ_eq_add_one, hc, sub_eq_add_neg, ← add_zero a₀]
        refine' ih.add _
        rw [SModEq.zero, Ideal.neg_mem_iff]
        refine' I.mul_mem_right _ _
        rw [← SModEq.zero] at h₁⊢
        exact (ih.eval f).trans h₁
      have hf'c : ∀ n, IsUnit (f'.eval (c n)) := by
        intro n
        haveI := isLocalRingHom_of_le_jacobson_bot I (IsAdicComplete.le_jacobson_bot I)
        apply isUnit_of_map_unit (Ideal.Quotient.mk I)
        convert h₂ using 1
        exact smodeq.def.mp ((hc_mod n).eval _)
      have hfcI : ∀ n, f.eval (c n) ∈ I ^ (n + 1) :=
        by
        intro n
        induction' n with n ih
        · simpa only [pow_one]
        simp only [Nat.succ_eq_add_one]
        rw [← taylor_eval_sub (c n), hc]
        simp only [sub_eq_add_neg, add_neg_cancel_comm]
        rw [eval_eq_sum, sum_over_range' _ _ _ (lt_add_of_pos_right _ zero_lt_two), ←
          Finset.sum_range_add_sum_Ico _ (Nat.le_add_left _ _)]
        swap
        · intro i
          rw [MulZeroClass.zero_mul]
        refine' Ideal.add_mem _ _ _
        · simp only [Finset.sum_range_succ, taylor_coeff_one, mul_one, pow_one, taylor_coeff_zero,
            mul_neg, Finset.sum_singleton, Finset.range_one, pow_zero]
          rw [mul_left_comm, Ring.mul_inverse_cancel _ (hf'c n), mul_one, add_neg_self]
          exact Ideal.zero_mem _
        · refine' Submodule.sum_mem _ _
          simp only [Finset.mem_Ico]
          rintro i ⟨h2i, hi⟩
          have aux : n + 2 ≤ i * (n + 1) := by trans 2 * (n + 1) <;> nlinarith only [h2i]
          refine' Ideal.mul_mem_left _ _ (Ideal.pow_le_pow aux _)
          rw [pow_mul']
          refine' Ideal.pow_mem_pow ((Ideal.neg_mem_iff _).2 <| Ideal.mul_mem_right _ _ ih) _
      -- we are now in the position to show that `c : ℕ → R` is a Cauchy sequence
      have aux : ∀ m n, m ≤ n → c m ≡ c n [SMOD (I ^ m • ⊤ : Ideal R)] :=
        by
        intro m n hmn
        rw [← Ideal.one_eq_top, Ideal.smul_eq_mul, mul_one]
        obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_le hmn
        clear hmn
        induction' k with k ih
        · rw [add_zero]
        rw [Nat.succ_eq_add_one, ← add_assoc, hc, ← add_zero (c m), sub_eq_add_neg]
        refine' ih.add _
        symm
        rw [SModEq.zero, Ideal.neg_mem_iff]
        refine' Ideal.mul_mem_right _ _ (Ideal.pow_le_pow _ (hfcI _))
        rw [add_assoc]
        exact le_self_add
      -- hence the sequence converges to some limit point `a`, which is the `a` we are looking for
      obtain ⟨a, ha⟩ := IsPrecomplete.prec' c aux
      refine' ⟨a, _, _⟩
      · show f.is_root a
        suffices ∀ n, f.eval a ≡ 0 [SMOD (I ^ n • ⊤ : Ideal R)] by exact IsHausdorff.haus' _ this
        intro n
        specialize ha n
        rw [← Ideal.one_eq_top, Ideal.smul_eq_mul, mul_one] at ha⊢
        refine' (ha.symm.eval f).trans _
        rw [SModEq.zero]
        exact Ideal.pow_le_pow le_self_add (hfcI _)
      · show a - a₀ ∈ I
        specialize ha 1
        rw [hc, pow_one, ← Ideal.one_eq_top, Ideal.smul_eq_mul, mul_one, sub_eq_add_neg] at ha
        rw [← SModEq.sub_mem, ← add_zero a₀]
        refine' ha.symm.trans (smodeq.rfl.add _)
        rw [SModEq.zero, Ideal.neg_mem_iff]
        exact Ideal.mul_mem_right _ _ h₁
#align is_adic_complete.henselian_ring IsAdicComplete.henselianRing