import data.real.basic
import data.nat.choose.sum -- binomial theorem
import data.real.ereal
import data.pnat.basic

-- namespace problem_sheet_two
section Q2

/-!

# Q2

-/

/-
2.  Fix nonempty sets S_n ⊆ R, n= 1,2,3,....
Prove that sup{sup S1,sup S2,sup S3,...} = sup(⋃_{n=1}^{infty} S_n),
in the sense that if either exists then so does the other, and they are equal.
-/

/-
Let's first answer a better question with fewer restrictions,
using extended reals.
Then Sup {Sup (S_i) : i ∈ I} = Sup (⋃_{i ∈ I} S_i) is *always* true
-/

example (I : Type) (S : I → set (ereal)) :
  Sup (set.range (λ i, Sup (S i))) = Sup (⋃ i, S i) :=
begin
  apply le_antisymm,
  { rw Sup_le_iff,
    rintro - ⟨i, rfl⟩,
    dsimp only,
    refine Sup_le_Sup _,
    exact set.subset_Union S i },
  { rw Sup_le_iff,
    rintros x ⟨-, ⟨i, rfl⟩, (hix : x ∈ S i)⟩,
    apply le_trans (le_Sup hix),
    apply le_Sup _,
    use i }
end

lemma exists_lub (S : set ℝ) :
  S.nonempty ∧ (upper_bounds S).nonempty → (∃ B, is_lub S B) :=
begin
  rintros ⟨h1, h2⟩,
  cases real.exists_sup S h1 h2 with B hB,
  use B,
  split,
  { apply (hB B).1,
    refl },
  { intros x hx,
    rw hB,
    exact hx }
end

-- "All the S_i have a sup and the set {sup S1, sup S2, ...} has a sup, if and
-- only if the union of the S_i has a sup"
theorem Q2a (S : ℕ+ → set ℝ)
  (hS : ∀ i : ℕ+, (S i).nonempty) :
  (∀ n : ℕ+, ∃ B, is_lub (S n) B) ∧ (∃ B, is_lub (set.range (λ i, Sup (S i))) B) ↔
  ∃ B, is_lub (⋃ i, S i) B :=
begin
  split,
  { rintro ⟨h1, B, hB1, hB2⟩,
    apply exists_lub,
    cases hS 37 with x hx,
    use [x, S 37, 37, hx],
    use B,
    rintros y ⟨-, ⟨i, rfl⟩, (hiY : y ∈ S i)⟩,
    specialize hB1 ⟨i, rfl⟩,
    refine le_trans _ hB1,
    apply real.le_Sup _ _ hiY,
    rcases h1 i with ⟨C, hC1, hC2⟩,
    use C,
    exact hC1 },
  { rintro ⟨B, hB1, hB2⟩,
    split,
    { intro n,
      apply exists_lub,
      use hS n,
      use B,
      apply upper_bounds_mono_set _ hB1,
      exact set.subset_Union S n },
    { apply exists_lub,
      split,
      { apply set.range_nonempty },
      { use B,
        rintro - ⟨i, rfl⟩,
        dsimp only,
        rw real.Sup_le _ (hS i),
        { intros z hz,
          apply hB1,
          use [S i, i, hz] },
        { use B,
          intros z hz,
          apply hB1,
          use [S i, i, hz] } } } }
end

-- assuming both sides make sense, prove the sups are equal
theorem Q2b (S : ℕ+ → set ℝ)
  (hS : ∀ i : ℕ+, (S i).nonempty)
  (hLHS: ∀ n : ℕ+, ∃ B, is_lub (S n) B) (hLHS' : ∃ B, is_lub (set.range (λ i, Sup (S i))) B)
  (hRHS : ∃ B, is_lub (⋃ i, S i) B) :
  Sup (set.range (λ i, Sup (S i))) = Sup (⋃ i, S i) :=
begin
  -- suffices to prove LHS ≤ RHS and RHS ≤ LHS
  apply le_antisymm,
  { -- to prove Sup ≤ something, suffices to prove all elements are ≤ it
    rw real.Sup_le,
    rintro - ⟨j, rfl⟩,
    dsimp only,
    -- so it suffices to prove Sup (S j) ≤ Sup (⋃_i S i)
    rw real.Sup_le,
    -- so it even suffices to prove every element of S j is ≤ the Sup
    intros x hx,
    -- but this is clear because the elements are in the set
    apply real.le_Sup, swap,
    use [S j, j, hx],
    -- now just check that all sets were nonempty and had least upper bounds,
    -- this follows from our assumptions.
    { rcases hRHS with ⟨B, hB1, hB2⟩,
      use B,
      exact hB1 },
    { exact hS j},
    { rcases hLHS j with ⟨B, hB1, hB2⟩,
      use B,
      exact hB1 },
    { apply set.range_nonempty },
    { rcases hLHS' with ⟨B, hB1, hB2⟩,
      use B,
      exact hB1 } },
  { -- to prove Sup ≤ somthing, suffices to prove all elements are ≤ it
    rw real.Sup_le,
    -- so assume z is in one of the S i's, call it S j
    rintro z ⟨-, ⟨j, rfl⟩, (hzj : z ∈ S j)⟩,
    -- then z ≤ Sup (S j)
    apply le_trans (real.le_Sup _ _ hzj),
    -- so it's certainly ≤ Sup of a set containing Sup (S j)
    apply real.le_Sup,
    -- now tidy up
    { rcases hLHS' with ⟨B, hB1, hB2⟩,
      use B,
      exact hB1 },
    { use j },
    { rcases hLHS j with ⟨B, hB1, hB2⟩,
      use B,
      exact hB1 },
    { cases hS 37 with x hx,
      use [x, S 37, 37, hx],
    },
    { rcases hRHS with ⟨B, hB1, hB2⟩,
      use B,
      exact hB1 } }
end

end Q2

/-!

# Q3

Take bounded, nonempty `S, T ⊆ ℝ`.
Define `S + T := { s + t : s ∈ S, t ∈ T}`.
Prove `sup(S+T)  =  sup(S)+ sup(T)`

-/

theorem is_lub_def {S : set ℝ} {a : ℝ} :
  is_lub S a ↔ a ∈ upper_bounds S ∧ ∀ x, x ∈ upper_bounds S → a ≤ x :=
begin
  refl
end

-- #check mem_upper_bounds -- a ∈ upper_bounds S ↔ ∀ x, x ∈ S → x ≤ a

--example (P Q : Prop) : P → Q ↔ ¬ Q → ¬ P :=
--by library_search

theorem useful_lemma {S : set ℝ} {a : ℝ} (haS : is_lub S a) (t : ℝ)
  (ht : t < a) : ∃ s, s ∈ S ∧ t < s :=
begin
  rw is_lub_def at haS,
  cases haS with haS1 haS2,
  specialize haS2 t,
  replace haS2 := mt haS2,
  push_neg at haS2,
  specialize haS2 ht,
  rw mem_upper_bounds at haS2,
  push_neg at haS2,
  exact haS2,
end

theorem problem_sheet_two.Q3 (S T : set ℝ) (a b : ℝ) :
  is_lub S a → is_lub T b → is_lub (S + T) (a + b) :=
begin
  intros hSa hTb,
  rw is_lub_def,
  split,
  { rw mem_upper_bounds,
    intro x,
    intro hx,
    rcases hx with ⟨s, t, hsS, htT, rfl⟩,
    rw is_lub_def at hSa hTb,
    rcases hSa with ⟨ha1, ha2⟩,
    rcases hTb with ⟨hb1, hb2⟩,
    rw mem_upper_bounds at ha1 hb1,
    specialize ha1 s hsS,
    specialize hb1 t htT,
    linarith,
  },
  { intro x,
    intro hx,
    rw mem_upper_bounds at hx,
    by_contra,
    push_neg at h,
    set ε := a + b - x with hε,
    have hε2 : 0 < ε,
      linarith,
    set a' := a - ε/2 with ha',
    set b' := b - ε/2 with hb',
    rcases useful_lemma hSa a' (by linarith) with ⟨s', hs', hs'2⟩,
    rcases useful_lemma hTb b' (by linarith) with ⟨t', ht', ht'2⟩,
    specialize hx (s' + t') ⟨s', t', hs', ht', rfl⟩,
    linarith,
  }
end

/-!

# Q4

Fix `a ∈ (0,∞)` and `n : ℕ`. We will prove
`∃ x : ℝ, x^n = a`.

-/

section Q4

noncomputable theory

section one

-- this first section, a and n are going to be variables
variables {a : ℝ} (ha : 0 < a) {n : ℕ} (hn : 0 < n)

include ha hn

/- Note: We do things in a slightly different order to the question
on the sheet, because the way it's set up on the sheet, `x` is
defined to be `Sup(S_a)` very early on, which technically forces
us to prove that `1/x` is `Sup(S_{1/a})` -- this is unnecessary
with the approach below. I broke this question into five "parts".
-/

/-
2) For `ε ∈ (0,1)` and arbitrary `x ≥ 0` show `(x+ε)ⁿ ≤ x^n + ε[(x + 1)ⁿ − xⁿ].`
(Hint: multiply out.)
-/

theorem part2 {x : ℝ} (x_nonneg : 0 ≤ x) (ε : ℝ) (hε0 : 0 < ε) (hε1 : ε < 1) :
  (x + ε)^n ≤ x^n + ε * ((x + 1)^n - x^n) :=
begin
  rw [ add_pow, add_pow ],
  simp_rw [one_pow, mul_one],
  rw [finset.sum_range_succ, nat.sub_self, pow_zero, mul_one],
  rw [nat.choose_self, nat.cast_one, mul_one],
  apply add_le_add_left,
  rw [finset.sum_range_succ, nat.choose_self, nat.cast_one, mul_one],
  rw [add_sub_cancel', finset.mul_sum],
  apply finset.sum_le_sum,
  intros i hi,
  rw [finset.mem_range, nat.lt_iff_add_one_le, le_iff_exists_add] at hi,
  -- rcases hi with ⟨c, rfl⟩, -- rcases bug?
  cases hi with c hc,
  have hni : n - i = c + 1,
    omega,
  rw [hni, mul_comm (x ^ i), mul_assoc, pow_succ, mul_comm ε, mul_assoc],
  apply mul_le_of_le_one_left,
  { apply mul_nonneg (le_of_lt hε0),
    apply mul_nonneg (pow_nonneg x_nonneg i),
    norm_cast, simp },
  { apply pow_le_one; linarith }
end

/-
3) Hence show that if `x ≥ 0` and `xⁿ < a` then
`∃ ε ∈ (0,1)` such that `(x+ε)ⁿ < a.` (*)
-/

theorem part3 {x : ℝ} (x_nonneg : 0 ≤ x) (h : x ^ n < a) :
  ∃ ε : ℝ, 0 < ε ∧ ε < 1 ∧ (x+ε)^n < a :=
begin
  set ε := min (1 / 2) ((a - x ^ n) / ((x + 1) ^ n - x ^ n) / 2) with hε,
  use ε,
  have hx1 : 0 < (x + 1) ^ n - x ^ n,
    rw sub_pos,
    apply pow_lt_pow_of_lt_left (lt_add_one _) x_nonneg hn,
  have hε0 : 0 < ε,
    rw [hε, lt_min_iff],
    split, { linarith },
    refine div_pos _ (by linarith),
    refine div_pos (by linarith) hx1,
  use hε0,
  have hε1 : ε < 1,
    suffices : ε ≤ 1/2, linarith,
    rw hε,
    exact min_le_left _ _,
  use hε1,
  apply lt_of_le_of_lt (part2 ha hn x_nonneg ε hε0 hε1),
  rw ← lt_sub_iff_add_lt',
  rw ← lt_div_iff hx1,
  apply lt_of_le_of_lt (min_le_right _ _),
  apply div_two_lt_of_pos,
  exact div_pos (by linarith) hx1,
end

/-
4) If `x > 0` is arbitrary and `xⁿ > a`, deduce from (∗) (i.e. part 3) that
`∃ ε ∈ (0,1)` such that `(1/x+ε)ⁿ < 1/a`. (∗∗)

Note that here it makes life much easier to have x a variable and not
the fixed Sup(S_a); with the approach on the sheet one would have to
technical prove that 1/x is Sup(S_{1/a}), which is not necessary
with this approach.
-/

theorem part4 {x : ℝ} (hx : 0 < x) (h : a < x^n) :
  ∃ ε : ℝ, 0 < ε ∧ ε < 1 ∧ (1/x + ε)^n < 1/a :=
begin
  have h1x_pos : 0 < 1/x,
    rwa one_div_pos,
  have h1xa : (1/x)^n < 1/a,
    rw [div_pow, one_pow],
    apply div_lt_div_of_lt_left ha h zero_lt_one,
  exact part3 (one_div_pos.2 ha) hn (le_of_lt h1x_pos) h1xa,
end

end one

section two

-- in this section, a and n are going to be fixed parameters

parameters {a : ℝ} (ha : 0 < a) {n : ℕ} (hn : 0 < n)

include ha hn
/-
1) Set `Sₐ := {s ∈ [0,∞) : s^n < a}` and show `Sₐ` is nonempty and
bounded above, so we may define `x := sup Sₐ`
-/

def S := {s : ℝ | 0 ≤ s ∧ s ^ n < a}

theorem part1 : (∃ s : ℝ, s ∈ S) ∧ (∃ B : ℝ, ∀ s ∈ S, s ≤ B ) :=
begin
  split,
  { use 0,
    split, { refl },
    convert ha,
    simp [hn] },
  { use a + 1,
    rintro s ⟨hs1, hs2⟩,
    by_contra hsa,
    push_neg at hsa,
    have hs3 : 1 ≤ s,
      linarith,
    have hs4 : s ≤ s ^ n,
      cases n, cases hn,
      suffices : 1 ≤ s ^ n,
        convert mul_le_mul (le_refl s) this (by linarith) hs1,
        { simp },
      exact one_le_pow_of_one_le hs3 _,
    linarith, }
end

def x := Sup S

theorem is_lub_x : is_lub S x :=
begin
  cases part1 with nonempty bdd,
  cases nonempty with x hx,
  cases bdd with y hy,
  exact real.is_lub_Sup hx hy,
end

lemma x_nonneg : 0 ≤ x :=
begin
  rcases is_lub_x with ⟨h, -⟩,
  apply h,
  split, refl,
  convert ha,
  simp [hn],
end

lemma easy (h : a < x^n) : x ≠ 0 :=
begin
  intro hx,
  rw hx at h,
  suffices : a < 0,
    linarith,
  convert h,
  symmetry, -- todo add simp lemma to mathlib
  simp [hn],
end

/-
5) Deduce contradictions from (∗) and (∗∗) to show that `xⁿ = a`.
-/

-- lemma le_of_pow_le_pow (n : ℕ) (hn : 0 < n) (x y : ℝ) (h : x^n ≤ y^n) : x ≤ y :=
-- begin
--   by_contra hxy,
--   push_neg at hxy,
--   sorry,
-- --  have h2 : pow_lt_pow
-- end

theorem part5 : x^n = a :=
begin
  rcases lt_trichotomy (x^n) a with (hlt | heq | hgt),
  { exfalso,
    obtain ⟨ε, hε0, -, hε⟩ := part3 ha hn (x_nonneg) hlt,
    have ZZZ := is_lub_x.1 ⟨_, hε⟩, linarith,
    linarith [x_nonneg] },
  { assumption },
  { exfalso,
    have hxpow : 0 < x,
      rw lt_iff_le_and_ne,
      exact ⟨x_nonneg, (easy hgt).symm⟩,
    obtain ⟨ε, hε0, -, hε⟩ := part4 ha hn hxpow hgt,
    have huseful : 0 < 1 / x + ε,
      refine add_pos _ hε0,
      exact one_div_pos.mpr hxpow,
    have ha' : a < (1 / (1 / x + ε)) ^ n,
    { rw [div_pow, one_pow],
      rwa lt_one_div _ ha at hε,
      apply pow_pos,
      assumption },
    have hproblem : (1 / (1 / x + ε)) ∈ upper_bounds S,
    { rintro t ⟨ht0, hta⟩,
      apply le_of_lt,
      apply lt_of_pow_lt_pow n,
      { apply le_of_lt,
        rwa one_div_pos },
      { linarith } },
    have ZZZ := is_lub_x.2 hproblem,
      rw le_one_div at ZZZ,
      { linarith },
      { assumption },
      { assumption } }
end

end two

end Q4

section Q6

/-!

# Q6

"Do (a) from first principles and then do parts (b)-(g) from (a)"

-/

-- We introduce the usual mathematical notation for absolute value
local notation `|` x `|` := abs x

/-
Useful for this one: `unfold`, `split_ifs` if you want to prove
from first principles, or guessing the name of the library function
if you want to use the library.
-/
theorem Q6a (x y : ℝ) : | x + y | ≤ | x | + | y | :=
begin
  unfold abs max,
  split_ifs;
  linarith
end

-- all the rest you're supposed to do using Q6a somehow:
-- `simp` and `linarith` are useful.

theorem Q6b (x y : ℝ) : |x + y| ≥ |x| - |y| :=
begin
  have h := Q6a (x + y) (-y),
  simp at h,
  linarith,
end

theorem Q6c (x y : ℝ) : |x + y| ≥ |y| - |x| :=
begin
  have h := Q6a (x + y) (-x),
  simp at h,
  linarith,
end

theorem Q6d (x y : ℝ) : |x - y| ≥ | |x| - |y| | :=
begin
  show _ ≤ _,
  rw abs_le,
  split,
  { -- |y|<=|x|+|y-x|
    have h := Q6a x (y-x),
    simp at h,
    rw abs_sub,
    linarith },
  { have h := Q6a (x-y) y,
    simp at h,
    linarith }
end

theorem Q6e (x y : ℝ) : |x| ≤ |y| + |x - y| :=
begin
  have h := Q6a y (x-y),
  convert h,
  ring,
end

theorem Q6f (x y : ℝ) : |x| ≥ |y| - |x - y| :=
begin
  have h := Q6a x (y-x),
  simp at h,
  rw abs_sub at h,
  linarith,
end

theorem Q6g (x y z : ℝ) : |x - y| ≤ |x - z| + |y - z| :=
begin
  have h := Q6a (x-z) (z-y),
  rw abs_sub z y at h,
  convert h,
  ring,
end

end Q6


import data.nat.basic
import data.nat.gcd.basic
import data.nat.pow

import algebra.associated
import algebra.group_power.basic

/-
Iranian Mathematical Olympiad 1998, Problem 6

Let x,a,b be positive integers such that x^(a+b) = a^b * b. Prove
that a = x and b = x^x.
-/

theorem iran1998_q6
  (x a b : ℕ)
  (hx : 0 < x)
  (ha : 0 < a)
  (hb : 0 < b)
  (h : x^(a+b) = a^b * b)
 : a = x ∧ b = x^x :=
begin
  cases x,
  { exact false.elim (nat.lt_asymm hx hx) },
  cases x,
  { rw [one_pow] at h,
    have hab : 1 ≤ a ^ b := nat.one_le_pow b a ha,
    have habb : a ^ b ≤ a ^ b * b := nat.le_mul_of_pos_right hb,
    rw [←h] at habb,
    have hab' : a ^ b = 1 := le_antisymm habb hab,
    rw [hab', one_mul, eq_comm] at h,
    rw[one_pow],
    rw [h, pow_one] at hab',
    exact ⟨hab', h⟩ },
  let x' := x.succ.succ,
  have : ∀ p : ℕ, prime p → p ∣ x → p ∣ b,
  { intros p hpp hpx,
    sorry },
  sorry
end


import group_theory.quotient_group bundled_subgroup

namespace quotient_group

variables {G : Type*} [group G] {N : subgroup G} (h : is_normal_subgroup N)

open function

def quotient' {G : Type*} [group G] {N : subgroup G} (h : is_normal_subgroup N) := quotient N.carrier

instance quotient'_is_group {G : Type*} [group G] {N : subgroup G} (h : is_normal_subgroup N) :
group (quotient' h) := by unfold quotient'; letI : normal_subgroup (N.carrier) := h; apply_instance

def mk' {G : Type*} [group G] {N : subgroup G} (h : is_normal_subgroup N) : G →* quotient' h :=
by letI : normal_subgroup (N.carrier) := h; exact group_hom.mk (quotient_group.mk)

theorem mk'.surjective : surjective (mk' h) := begin
  intro q,
  use quotient.out' q,
  apply quotient.out_eq'
end

end quotient_group


/-
Copyright (c) 2020 Damiano Testa. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Damiano Testa

! This file was ported from Lean 3 source module data.polynomial.denoms_clearable
! leanprover-community/mathlib commit 97eab48559068f3d6313da387714ef25768fb730
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Polynomial.EraseLead
import Mathbin.Data.Polynomial.Eval

/-!
# Denominators of evaluation of polynomials at ratios

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

Let `i : R → K` be a homomorphism of semirings.  Assume that `K` is commutative.  If `a` and
`b` are elements of `R` such that `i b ∈ K` is invertible, then for any polynomial
`f ∈ R[X]` the "mathematical" expression `b ^ f.nat_degree * f (a / b) ∈ K` is in
the image of the homomorphism `i`.
-/

open Polynomial Finset

open Polynomial

section DenomsClearable

variable {R K : Type _} [Semiring R] [CommSemiring K] {i : R →+* K}

variable {a b : R} {bi : K}

#print DenomsClearable /-
-- TODO: use hypothesis (ub : is_unit (i b)) to work with localizations.
/-- `denoms_clearable` formalizes the property that `b ^ N * f (a / b)`
does not have denominators, if the inequality `f.nat_degree ≤ N` holds.

The definition asserts the existence of an element `D` of `R` and an
element `bi = 1 / i b` of `K` such that clearing the denominators of
the fraction equals `i D`.
-/
def DenomsClearable (a b : R) (N : ℕ) (f : R[X]) (i : R →+* K) : Prop :=
  ∃ (D : R)(bi : K), bi * i b = 1 ∧ i D = i b ^ N * eval (i a * bi) (f.map i)
#align denoms_clearable DenomsClearable
-/

/- warning: denoms_clearable_zero -> denomsClearable_zero is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {K : Type.{u2}} [_inst_1 : Semiring.{u1} R] [_inst_2 : CommSemiring.{u2} K] {i : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))} {b : R} {bi : K} (N : Nat) (a : R), (Eq.{succ u2} K (HMul.hMul.{u2, u2, u2} K K K (instHMul.{u2} K (Distrib.toHasMul.{u2} K (NonUnitalNonAssocSemiring.toDistrib.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)))))) bi (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) (fun (_x : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) => R -> K) (RingHom.hasCoeToFun.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) i b)) (OfNat.ofNat.{u2} K 1 (OfNat.mk.{u2} K 1 (One.one.{u2} K (AddMonoidWithOne.toOne.{u2} K (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} K (NonAssocSemiring.toAddCommMonoidWithOne.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))))))))) -> (DenomsClearable.{u1, u2} R K _inst_1 _inst_2 a b N (OfNat.ofNat.{u1} (Polynomial.{u1} R _inst_1) 0 (OfNat.mk.{u1} (Polynomial.{u1} R _inst_1) 0 (Zero.zero.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.zero.{u1} R _inst_1)))) i)
but is expected to have type
  forall {R : Type.{u1}} {K : Type.{u2}} [_inst_1 : Semiring.{u1} R] [_inst_2 : CommSemiring.{u2} K] {i : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))} {b : R} {bi : K} (N : Nat) (a : R), (Eq.{succ u2} K (HMul.hMul.{u2, u2, u2} K ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => K) b) K (instHMul.{u2} K (NonUnitalNonAssocSemiring.toMul.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))))) bi (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => K) _x) (MulHomClass.toFunLike.{max u1 u2, u1, u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R K (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)))) (NonUnitalRingHomClass.toMulHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1)) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) (RingHomClass.toNonUnitalRingHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)) (RingHom.instRingHomClassRingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)))))) i b)) (OfNat.ofNat.{u2} K 1 (One.toOfNat1.{u2} K (Semiring.toOne.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))))) -> (DenomsClearable.{u1, u2} R K _inst_1 _inst_2 a b N (OfNat.ofNat.{u1} (Polynomial.{u1} R _inst_1) 0 (Zero.toOfNat0.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.zero.{u1} R _inst_1))) i)
Case conversion may be inaccurate. Consider using '#align denoms_clearable_zero denomsClearable_zeroₓ'. -/
theorem denomsClearable_zero (N : ℕ) (a : R) (bu : bi * i b = 1) : DenomsClearable a b N 0 i :=
  ⟨0, bi, bu, by
    simp only [eval_zero, RingHom.map_zero, MulZeroClass.mul_zero, Polynomial.map_zero]⟩
#align denoms_clearable_zero denomsClearable_zero

/- warning: denoms_clearable_C_mul_X_pow -> denomsClearable_C_mul_X_pow is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {K : Type.{u2}} [_inst_1 : Semiring.{u1} R] [_inst_2 : CommSemiring.{u2} K] {i : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))} {b : R} {bi : K} {N : Nat} (a : R), (Eq.{succ u2} K (HMul.hMul.{u2, u2, u2} K K K (instHMul.{u2} K (Distrib.toHasMul.{u2} K (NonUnitalNonAssocSemiring.toDistrib.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)))))) bi (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) (fun (_x : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) => R -> K) (RingHom.hasCoeToFun.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) i b)) (OfNat.ofNat.{u2} K 1 (OfNat.mk.{u2} K 1 (One.one.{u2} K (AddMonoidWithOne.toOne.{u2} K (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} K (NonAssocSemiring.toAddCommMonoidWithOne.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))))))))) -> (forall {n : Nat} (r : R), (LE.le.{0} Nat Nat.hasLe n N) -> (DenomsClearable.{u1, u2} R K _inst_1 _inst_2 a b N (HMul.hMul.{u1, u1, u1} (Polynomial.{u1} R _inst_1) (Polynomial.{u1} R _inst_1) (Polynomial.{u1} R _inst_1) (instHMul.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.mul'.{u1} R _inst_1)) (coeFn.{succ u1, succ u1} (RingHom.{u1, u1} R (Polynomial.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1))) (fun (_x : RingHom.{u1, u1} R (Polynomial.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1))) => R -> (Polynomial.{u1} R _inst_1)) (RingHom.hasCoeToFun.{u1, u1} R (Polynomial.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1))) (Polynomial.C.{u1} R _inst_1) r) (HPow.hPow.{u1, 0, u1} (Polynomial.{u1} R _inst_1) Nat (Polynomial.{u1} R _inst_1) (instHPow.{u1, 0} (Polynomial.{u1} R _inst_1) Nat (Monoid.Pow.{u1} (Polynomial.{u1} R _inst_1) (MonoidWithZero.toMonoid.{u1} (Polynomial.{u1} R _inst_1) (Semiring.toMonoidWithZero.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1))))) (Polynomial.X.{u1} R _inst_1) n)) i))
but is expected to have type
  forall {R : Type.{u1}} {K : Type.{u2}} [_inst_1 : Semiring.{u1} R] [_inst_2 : CommSemiring.{u2} K] {i : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))} {b : R} {bi : K} {N : Nat} (a : R), (Eq.{succ u2} K (HMul.hMul.{u2, u2, u2} K ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => K) b) K (instHMul.{u2} K (NonUnitalNonAssocSemiring.toMul.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))))) bi (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => K) _x) (MulHomClass.toFunLike.{max u1 u2, u1, u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R K (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)))) (NonUnitalRingHomClass.toMulHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1)) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) (RingHomClass.toNonUnitalRingHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)) (RingHom.instRingHomClassRingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)))))) i b)) (OfNat.ofNat.{u2} K 1 (One.toOfNat1.{u2} K (Semiring.toOne.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))))) -> (forall {n : Nat} (r : R), (LE.le.{0} Nat instLENat n N) -> (DenomsClearable.{u1, u2} R K _inst_1 _inst_2 a b N (HMul.hMul.{u1, u1, u1} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => Polynomial.{u1} R _inst_1) r) (Polynomial.{u1} R _inst_1) (Polynomial.{u1} R _inst_1) (instHMul.{u1} ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => Polynomial.{u1} R _inst_1) r) (Polynomial.mul'.{u1} R _inst_1)) (FunLike.coe.{succ u1, succ u1, succ u1} (RingHom.{u1, u1} R (Polynomial.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => Polynomial.{u1} R _inst_1) _x) (MulHomClass.toFunLike.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1))) R (Polynomial.{u1} R _inst_1) (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u1} (Polynomial.{u1} R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1)))) (NonUnitalRingHomClass.toMulHomClass.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1))) R (Polynomial.{u1} R _inst_1) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1)) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1))) (RingHomClass.toNonUnitalRingHomClass.{u1, u1, u1} (RingHom.{u1, u1} R (Polynomial.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1))) R (Polynomial.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1)) (RingHom.instRingHomClassRingHom.{u1, u1} R (Polynomial.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1)))))) (Polynomial.C.{u1} R _inst_1) r) (HPow.hPow.{u1, 0, u1} (Polynomial.{u1} R _inst_1) Nat (Polynomial.{u1} R _inst_1) (instHPow.{u1, 0} (Polynomial.{u1} R _inst_1) Nat (Monoid.Pow.{u1} (Polynomial.{u1} R _inst_1) (MonoidWithZero.toMonoid.{u1} (Polynomial.{u1} R _inst_1) (Semiring.toMonoidWithZero.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.semiring.{u1} R _inst_1))))) (Polynomial.X.{u1} R _inst_1) n)) i))
Case conversion may be inaccurate. Consider using '#align denoms_clearable_C_mul_X_pow denomsClearable_C_mul_X_powₓ'. -/
/- ./././Mathport/Syntax/Translate/Tactic/Lean3.lean:132:4: warning: unsupported: rw with cfg: { occs := occurrences.pos[occurrences.pos] «expr[ ,]»([2]) } -/
theorem denomsClearable_C_mul_X_pow {N : ℕ} (a : R) (bu : bi * i b = 1) {n : ℕ} (r : R)
    (nN : n ≤ N) : DenomsClearable a b N (C r * X ^ n) i :=
  by
  refine' ⟨r * a ^ n * b ^ (N - n), bi, bu, _⟩
  rw [C_mul_X_pow_eq_monomial, map_monomial, ← C_mul_X_pow_eq_monomial, eval_mul, eval_pow, eval_C]
  rw [RingHom.map_mul, RingHom.map_mul, RingHom.map_pow, RingHom.map_pow, eval_X, mul_comm]
  rw [← tsub_add_cancel_of_le nN]
  rw [pow_add, mul_assoc, mul_comm (i b ^ n), mul_pow, mul_assoc, mul_assoc (i a ^ n), ← mul_pow]
  rw [bu, one_pow, mul_one]
#align denoms_clearable_C_mul_X_pow denomsClearable_C_mul_X_pow

/- warning: denoms_clearable.add -> DenomsClearable.add is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {K : Type.{u2}} [_inst_1 : Semiring.{u1} R] [_inst_2 : CommSemiring.{u2} K] {i : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))} {a : R} {b : R} {N : Nat} {f : Polynomial.{u1} R _inst_1} {g : Polynomial.{u1} R _inst_1}, (DenomsClearable.{u1, u2} R K _inst_1 _inst_2 a b N f i) -> (DenomsClearable.{u1, u2} R K _inst_1 _inst_2 a b N g i) -> (DenomsClearable.{u1, u2} R K _inst_1 _inst_2 a b N (HAdd.hAdd.{u1, u1, u1} (Polynomial.{u1} R _inst_1) (Polynomial.{u1} R _inst_1) (Polynomial.{u1} R _inst_1) (instHAdd.{u1} (Polynomial.{u1} R _inst_1) (Polynomial.add'.{u1} R _inst_1)) f g) i)
but is expected to have type
  forall {R : Type.{u2}} {K : Type.{u1}} [_inst_1 : Semiring.{u2} R] [_inst_2 : CommSemiring.{u1} K] {i : RingHom.{u2, u1} R K (Semiring.toNonAssocSemiring.{u2} R _inst_1) (Semiring.toNonAssocSemiring.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2))} {a : R} {b : R} {N : Nat} {f : Polynomial.{u2} R _inst_1} {g : Polynomial.{u2} R _inst_1}, (DenomsClearable.{u2, u1} R K _inst_1 _inst_2 a b N f i) -> (DenomsClearable.{u2, u1} R K _inst_1 _inst_2 a b N g i) -> (DenomsClearable.{u2, u1} R K _inst_1 _inst_2 a b N (HAdd.hAdd.{u2, u2, u2} (Polynomial.{u2} R _inst_1) (Polynomial.{u2} R _inst_1) (Polynomial.{u2} R _inst_1) (instHAdd.{u2} (Polynomial.{u2} R _inst_1) (Polynomial.add'.{u2} R _inst_1)) f g) i)
Case conversion may be inaccurate. Consider using '#align denoms_clearable.add DenomsClearable.addₓ'. -/
theorem DenomsClearable.add {N : ℕ} {f g : R[X]} :
    DenomsClearable a b N f i → DenomsClearable a b N g i → DenomsClearable a b N (f + g) i :=
  fun ⟨Df, bf, bfu, Hf⟩ ⟨Dg, bg, bgu, Hg⟩ =>
  ⟨Df + Dg, bf, bfu,
    by
    rw [RingHom.map_add, Polynomial.map_add, eval_add, mul_add, Hf, Hg]
    congr
    refine' @inv_unique K _ (i b) bg bf _ _ <;> rwa [mul_comm]⟩
#align denoms_clearable.add DenomsClearable.add

/- warning: denoms_clearable_of_nat_degree_le -> denomsClearable_of_natDegree_le is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {K : Type.{u2}} [_inst_1 : Semiring.{u1} R] [_inst_2 : CommSemiring.{u2} K] {i : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))} {b : R} {bi : K} (N : Nat) (a : R), (Eq.{succ u2} K (HMul.hMul.{u2, u2, u2} K K K (instHMul.{u2} K (Distrib.toHasMul.{u2} K (NonUnitalNonAssocSemiring.toDistrib.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)))))) bi (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) (fun (_x : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) => R -> K) (RingHom.hasCoeToFun.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) i b)) (OfNat.ofNat.{u2} K 1 (OfNat.mk.{u2} K 1 (One.one.{u2} K (AddMonoidWithOne.toOne.{u2} K (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} K (NonAssocSemiring.toAddCommMonoidWithOne.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))))))))) -> (forall (f : Polynomial.{u1} R _inst_1), (LE.le.{0} Nat Nat.hasLe (Polynomial.natDegree.{u1} R _inst_1 f) N) -> (DenomsClearable.{u1, u2} R K _inst_1 _inst_2 a b N f i))
but is expected to have type
  forall {R : Type.{u1}} {K : Type.{u2}} [_inst_1 : Semiring.{u1} R] [_inst_2 : CommSemiring.{u2} K] {i : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))} {b : R} {bi : K} (N : Nat) (a : R), (Eq.{succ u2} K (HMul.hMul.{u2, u2, u2} K ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => K) b) K (instHMul.{u2} K (NonUnitalNonAssocSemiring.toMul.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))))) bi (FunLike.coe.{max (succ u1) (succ u2), succ u1, succ u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => K) _x) (MulHomClass.toFunLike.{max u1 u2, u1, u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R K (NonUnitalNonAssocSemiring.toMul.{u1} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)))) (NonUnitalRingHomClass.toMulHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} R (Semiring.toNonAssocSemiring.{u1} R _inst_1)) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) (RingHomClass.toNonUnitalRingHomClass.{max u1 u2, u1, u2} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)) (RingHom.instRingHomClassRingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)))))) i b)) (OfNat.ofNat.{u2} K 1 (One.toOfNat1.{u2} K (Semiring.toOne.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))))) -> (forall (f : Polynomial.{u1} R _inst_1), (LE.le.{0} Nat instLENat (Polynomial.natDegree.{u1} R _inst_1 f) N) -> (DenomsClearable.{u1, u2} R K _inst_1 _inst_2 a b N f i))
Case conversion may be inaccurate. Consider using '#align denoms_clearable_of_nat_degree_le denomsClearable_of_natDegree_leₓ'. -/
theorem denomsClearable_of_natDegree_le (N : ℕ) (a : R) (bu : bi * i b = 1) :
    ∀ f : R[X], f.natDegree ≤ N → DenomsClearable a b N f i :=
  induction_with_natDegree_le _ N (denomsClearable_zero N a bu)
    (fun N_1 r r0 => denomsClearable_C_mul_X_pow a bu r) fun f g fg gN df dg => df.add dg
#align denoms_clearable_of_nat_degree_le denomsClearable_of_natDegree_le

/- warning: denoms_clearable_nat_degree -> denomsClearable_natDegree is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {K : Type.{u2}} [_inst_1 : Semiring.{u1} R] [_inst_2 : CommSemiring.{u2} K] {b : R} {bi : K} (i : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) (f : Polynomial.{u1} R _inst_1) (a : R), (Eq.{succ u2} K (HMul.hMul.{u2, u2, u2} K K K (instHMul.{u2} K (Distrib.toHasMul.{u2} K (NonUnitalNonAssocSemiring.toDistrib.{u2} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2)))))) bi (coeFn.{max (succ u1) (succ u2), max (succ u1) (succ u2)} (RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) (fun (_x : RingHom.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) => R -> K) (RingHom.hasCoeToFun.{u1, u2} R K (Semiring.toNonAssocSemiring.{u1} R _inst_1) (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))) i b)) (OfNat.ofNat.{u2} K 1 (OfNat.mk.{u2} K 1 (One.one.{u2} K (AddMonoidWithOne.toOne.{u2} K (AddCommMonoidWithOne.toAddMonoidWithOne.{u2} K (NonAssocSemiring.toAddCommMonoidWithOne.{u2} K (Semiring.toNonAssocSemiring.{u2} K (CommSemiring.toSemiring.{u2} K _inst_2))))))))) -> (DenomsClearable.{u1, u2} R K _inst_1 _inst_2 a b (Polynomial.natDegree.{u1} R _inst_1 f) f i)
but is expected to have type
  forall {R : Type.{u2}} {K : Type.{u1}} [_inst_1 : Semiring.{u2} R] [_inst_2 : CommSemiring.{u1} K] {b : R} {bi : K} (i : RingHom.{u2, u1} R K (Semiring.toNonAssocSemiring.{u2} R _inst_1) (Semiring.toNonAssocSemiring.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2))) (f : Polynomial.{u2} R _inst_1) (a : R), (Eq.{succ u1} K (HMul.hMul.{u1, u1, u1} K ((fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => K) b) K (instHMul.{u1} K (NonUnitalNonAssocSemiring.toMul.{u1} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} K (Semiring.toNonAssocSemiring.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2))))) bi (FunLike.coe.{max (succ u2) (succ u1), succ u2, succ u1} (RingHom.{u2, u1} R K (Semiring.toNonAssocSemiring.{u2} R _inst_1) (Semiring.toNonAssocSemiring.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2))) R (fun (_x : R) => (fun (x._@.Mathlib.Algebra.Hom.Group._hyg.2391 : R) => K) _x) (MulHomClass.toFunLike.{max u2 u1, u2, u1} (RingHom.{u2, u1} R K (Semiring.toNonAssocSemiring.{u2} R _inst_1) (Semiring.toNonAssocSemiring.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2))) R K (NonUnitalNonAssocSemiring.toMul.{u2} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (Semiring.toNonAssocSemiring.{u2} R _inst_1))) (NonUnitalNonAssocSemiring.toMul.{u1} K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} K (Semiring.toNonAssocSemiring.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2)))) (NonUnitalRingHomClass.toMulHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} R K (Semiring.toNonAssocSemiring.{u2} R _inst_1) (Semiring.toNonAssocSemiring.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2))) R K (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (Semiring.toNonAssocSemiring.{u2} R _inst_1)) (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u1} K (Semiring.toNonAssocSemiring.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2))) (RingHomClass.toNonUnitalRingHomClass.{max u2 u1, u2, u1} (RingHom.{u2, u1} R K (Semiring.toNonAssocSemiring.{u2} R _inst_1) (Semiring.toNonAssocSemiring.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2))) R K (Semiring.toNonAssocSemiring.{u2} R _inst_1) (Semiring.toNonAssocSemiring.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2)) (RingHom.instRingHomClassRingHom.{u2, u1} R K (Semiring.toNonAssocSemiring.{u2} R _inst_1) (Semiring.toNonAssocSemiring.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2)))))) i b)) (OfNat.ofNat.{u1} K 1 (One.toOfNat1.{u1} K (Semiring.toOne.{u1} K (CommSemiring.toSemiring.{u1} K _inst_2))))) -> (DenomsClearable.{u2, u1} R K _inst_1 _inst_2 a b (Polynomial.natDegree.{u2} R _inst_1 f) f i)
Case conversion may be inaccurate. Consider using '#align denoms_clearable_nat_degree denomsClearable_natDegreeₓ'. -/
/-- If `i : R → K` is a ring homomorphism, `f` is a polynomial with coefficients in `R`,
`a, b` are elements of `R`, with `i b` invertible, then there is a `D ∈ R` such that
`b ^ f.nat_degree * f (a / b)` equals `i D`. -/
theorem denomsClearable_natDegree (i : R →+* K) (f : R[X]) (a : R) (bu : bi * i b = 1) :
    DenomsClearable a b f.natDegree f i :=
  denomsClearable_of_natDegree_le f.natDegree a bu f le_rfl
#align denoms_clearable_nat_degree denomsClearable_natDegree

end DenomsClearable

open RingHom

/- warning: one_le_pow_mul_abs_eval_div -> one_le_pow_mul_abs_eval_div is a dubious translation:
lean 3 declaration is
  forall {K : Type.{u1}} [_inst_1 : LinearOrderedField.{u1} K] {f : Polynomial.{0} Int Int.semiring} {a : Int} {b : Int}, (LT.lt.{0} Int Int.hasLt (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero))) b) -> (Ne.{succ u1} K (Polynomial.eval.{u1} K (Ring.toSemiring.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) (HDiv.hDiv.{u1, u1, u1} K K K (instHDiv.{u1} K (DivInvMonoid.toHasDiv.{u1} K (DivisionRing.toDivInvMonoid.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Int K (HasLiftT.mk.{1, succ u1} Int K (CoeTCₓ.coe.{1, succ u1} Int K (Int.castCoe.{u1} K (AddGroupWithOne.toHasIntCast.{u1} K (AddCommGroupWithOne.toAddGroupWithOne.{u1} K (Ring.toAddCommGroupWithOne.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))))))) a) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Int K (HasLiftT.mk.{1, succ u1} Int K (CoeTCₓ.coe.{1, succ u1} Int K (Int.castCoe.{u1} K (AddGroupWithOne.toHasIntCast.{u1} K (AddCommGroupWithOne.toAddGroupWithOne.{u1} K (Ring.toAddCommGroupWithOne.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))))))) b)) (Polynomial.map.{0, u1} Int K Int.semiring (Ring.toSemiring.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) (algebraMap.{0, u1} Int K Int.commSemiring (Ring.toSemiring.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) (algebraInt.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))) f)) (OfNat.ofNat.{u1} K 0 (OfNat.mk.{u1} K 0 (Zero.zero.{u1} K (MulZeroClass.toHasZero.{u1} K (NonUnitalNonAssocSemiring.toMulZeroClass.{u1} K (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u1} K (NonAssocRing.toNonUnitalNonAssocRing.{u1} K (Ring.toNonAssocRing.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))))))))))) -> (LE.le.{u1} K (Preorder.toLE.{u1} K (PartialOrder.toPreorder.{u1} K (OrderedAddCommGroup.toPartialOrder.{u1} K (StrictOrderedRing.toOrderedAddCommGroup.{u1} K (LinearOrderedRing.toStrictOrderedRing.{u1} K (LinearOrderedCommRing.toLinearOrderedRing.{u1} K (LinearOrderedField.toLinearOrderedCommRing.{u1} K _inst_1))))))) (OfNat.ofNat.{u1} K 1 (OfNat.mk.{u1} K 1 (One.one.{u1} K (AddMonoidWithOne.toOne.{u1} K (AddGroupWithOne.toAddMonoidWithOne.{u1} K (AddCommGroupWithOne.toAddGroupWithOne.{u1} K (Ring.toAddCommGroupWithOne.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))))))))) (HMul.hMul.{u1, u1, u1} K K K (instHMul.{u1} K (Distrib.toHasMul.{u1} K (Ring.toDistrib.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))))) (HPow.hPow.{u1, 0, u1} K Nat K (instHPow.{u1, 0} K Nat (Monoid.Pow.{u1} K (Ring.toMonoid.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Int K (HasLiftT.mk.{1, succ u1} Int K (CoeTCₓ.coe.{1, succ u1} Int K (Int.castCoe.{u1} K (AddGroupWithOne.toHasIntCast.{u1} K (AddCommGroupWithOne.toAddGroupWithOne.{u1} K (Ring.toAddCommGroupWithOne.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))))))) b) (Polynomial.natDegree.{0} Int Int.semiring f)) (Abs.abs.{u1} K (Neg.toHasAbs.{u1} K (SubNegMonoid.toHasNeg.{u1} K (AddGroup.toSubNegMonoid.{u1} K (AddGroupWithOne.toAddGroup.{u1} K (AddCommGroupWithOne.toAddGroupWithOne.{u1} K (Ring.toAddCommGroupWithOne.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))))))) (SemilatticeSup.toHasSup.{u1} K (Lattice.toSemilatticeSup.{u1} K (LinearOrder.toLattice.{u1} K (LinearOrderedRing.toLinearOrder.{u1} K (LinearOrderedCommRing.toLinearOrderedRing.{u1} K (LinearOrderedField.toLinearOrderedCommRing.{u1} K _inst_1))))))) (Polynomial.eval.{u1} K (Ring.toSemiring.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) (HDiv.hDiv.{u1, u1, u1} K K K (instHDiv.{u1} K (DivInvMonoid.toHasDiv.{u1} K (DivisionRing.toDivInvMonoid.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Int K (HasLiftT.mk.{1, succ u1} Int K (CoeTCₓ.coe.{1, succ u1} Int K (Int.castCoe.{u1} K (AddGroupWithOne.toHasIntCast.{u1} K (AddCommGroupWithOne.toAddGroupWithOne.{u1} K (Ring.toAddCommGroupWithOne.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))))))) a) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Int K (HasLiftT.mk.{1, succ u1} Int K (CoeTCₓ.coe.{1, succ u1} Int K (Int.castCoe.{u1} K (AddGroupWithOne.toHasIntCast.{u1} K (AddCommGroupWithOne.toAddGroupWithOne.{u1} K (Ring.toAddCommGroupWithOne.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))))))) b)) (Polynomial.map.{0, u1} Int K Int.semiring (Ring.toSemiring.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) (algebraMap.{0, u1} Int K Int.commSemiring (Ring.toSemiring.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) (algebraInt.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))) f)))))
but is expected to have type
  forall {K : Type.{u1}} [_inst_1 : LinearOrderedField.{u1} K] {f : Polynomial.{0} Int Int.instSemiringInt} {a : Int} {b : Int}, (LT.lt.{0} Int Int.instLTInt (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)) b) -> (Ne.{succ u1} K (Polynomial.eval.{u1} K (DivisionSemiring.toSemiring.{u1} K (Semifield.toDivisionSemiring.{u1} K (LinearOrderedSemifield.toSemifield.{u1} K (LinearOrderedField.toLinearOrderedSemifield.{u1} K _inst_1)))) (HDiv.hDiv.{u1, u1, u1} K K K (instHDiv.{u1} K (LinearOrderedField.toDiv.{u1} K _inst_1)) (Int.cast.{u1} K (Ring.toIntCast.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) a) (Int.cast.{u1} K (Ring.toIntCast.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) b)) (Polynomial.map.{0, u1} Int K (CommSemiring.toSemiring.{0} Int Int.instCommSemiringInt) (DivisionSemiring.toSemiring.{u1} K (Semifield.toDivisionSemiring.{u1} K (LinearOrderedSemifield.toSemifield.{u1} K (LinearOrderedField.toLinearOrderedSemifield.{u1} K _inst_1)))) (algebraMap.{0, u1} Int K Int.instCommSemiringInt (DivisionSemiring.toSemiring.{u1} K (Semifield.toDivisionSemiring.{u1} K (LinearOrderedSemifield.toSemifield.{u1} K (LinearOrderedField.toLinearOrderedSemifield.{u1} K _inst_1)))) (algebraInt.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))) f)) (OfNat.ofNat.{u1} K 0 (Zero.toOfNat0.{u1} K (CommMonoidWithZero.toZero.{u1} K (CommGroupWithZero.toCommMonoidWithZero.{u1} K (Semifield.toCommGroupWithZero.{u1} K (LinearOrderedSemifield.toSemifield.{u1} K (LinearOrderedField.toLinearOrderedSemifield.{u1} K _inst_1)))))))) -> (LE.le.{u1} K (Preorder.toLE.{u1} K (PartialOrder.toPreorder.{u1} K (StrictOrderedRing.toPartialOrder.{u1} K (LinearOrderedRing.toStrictOrderedRing.{u1} K (LinearOrderedCommRing.toLinearOrderedRing.{u1} K (LinearOrderedField.toLinearOrderedCommRing.{u1} K _inst_1)))))) (OfNat.ofNat.{u1} K 1 (One.toOfNat1.{u1} K (NonAssocRing.toOne.{u1} K (Ring.toNonAssocRing.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))))) (HMul.hMul.{u1, u1, u1} K K K (instHMul.{u1} K (NonUnitalNonAssocRing.toMul.{u1} K (NonAssocRing.toNonUnitalNonAssocRing.{u1} K (Ring.toNonAssocRing.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))))) (HPow.hPow.{u1, 0, u1} K Nat K (instHPow.{u1, 0} K Nat (Monoid.Pow.{u1} K (MonoidWithZero.toMonoid.{u1} K (Semiring.toMonoidWithZero.{u1} K (DivisionSemiring.toSemiring.{u1} K (Semifield.toDivisionSemiring.{u1} K (LinearOrderedSemifield.toSemifield.{u1} K (LinearOrderedField.toLinearOrderedSemifield.{u1} K _inst_1)))))))) (Int.cast.{u1} K (Ring.toIntCast.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) b) (Polynomial.natDegree.{0} Int Int.instSemiringInt f)) (Abs.abs.{u1} K (Neg.toHasAbs.{u1} K (Ring.toNeg.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) (SemilatticeSup.toSup.{u1} K (Lattice.toSemilatticeSup.{u1} K (DistribLattice.toLattice.{u1} K (instDistribLattice.{u1} K (LinearOrderedRing.toLinearOrder.{u1} K (LinearOrderedCommRing.toLinearOrderedRing.{u1} K (LinearOrderedField.toLinearOrderedCommRing.{u1} K _inst_1)))))))) (Polynomial.eval.{u1} K (DivisionSemiring.toSemiring.{u1} K (Semifield.toDivisionSemiring.{u1} K (LinearOrderedSemifield.toSemifield.{u1} K (LinearOrderedField.toLinearOrderedSemifield.{u1} K _inst_1)))) (HDiv.hDiv.{u1, u1, u1} K K K (instHDiv.{u1} K (LinearOrderedField.toDiv.{u1} K _inst_1)) (Int.cast.{u1} K (Ring.toIntCast.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) a) (Int.cast.{u1} K (Ring.toIntCast.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1)))) b)) (Polynomial.map.{0, u1} Int K (CommSemiring.toSemiring.{0} Int Int.instCommSemiringInt) (DivisionSemiring.toSemiring.{u1} K (Semifield.toDivisionSemiring.{u1} K (LinearOrderedSemifield.toSemifield.{u1} K (LinearOrderedField.toLinearOrderedSemifield.{u1} K _inst_1)))) (algebraMap.{0, u1} Int K Int.instCommSemiringInt (DivisionSemiring.toSemiring.{u1} K (Semifield.toDivisionSemiring.{u1} K (LinearOrderedSemifield.toSemifield.{u1} K (LinearOrderedField.toLinearOrderedSemifield.{u1} K _inst_1)))) (algebraInt.{u1} K (DivisionRing.toRing.{u1} K (Field.toDivisionRing.{u1} K (LinearOrderedField.toField.{u1} K _inst_1))))) f)))))
Case conversion may be inaccurate. Consider using '#align one_le_pow_mul_abs_eval_div one_le_pow_mul_abs_eval_divₓ'. -/
/-- Evaluating a polynomial with integer coefficients at a rational number and clearing
denominators, yields a number greater than or equal to one.  The target can be any
`linear_ordered_field K`.
The assumption on `K` could be weakened to `linear_ordered_comm_ring` assuming that the
image of the denominator is invertible in `K`. -/
theorem one_le_pow_mul_abs_eval_div {K : Type _} [LinearOrderedField K] {f : ℤ[X]} {a b : ℤ}
    (b0 : 0 < b) (fab : eval ((a : K) / b) (f.map (algebraMap ℤ K)) ≠ 0) :
    (1 : K) ≤ b ^ f.natDegree * |eval ((a : K) / b) (f.map (algebraMap ℤ K))| :=
  by
  obtain ⟨ev, bi, bu, hF⟩ :=
    @denomsClearable_natDegree _ _ _ _ b _ (algebraMap ℤ K) f a
      (by
        rw [eq_intCast, one_div_mul_cancel]
        rw [Int.cast_ne_zero]
        exact b0.ne.symm)
  obtain Fa := congr_arg abs hF
  rw [eq_one_div_of_mul_eq_one_left bu, eq_intCast, eq_intCast, abs_mul] at Fa
  rw [abs_of_pos (pow_pos (int.cast_pos.mpr b0) _ : 0 < (b : K) ^ _), one_div, eq_intCast] at Fa
  rw [div_eq_mul_inv, ← Fa, ← Int.cast_abs, ← Int.cast_one, Int.cast_le]
  refine' Int.le_of_lt_add_one ((lt_add_iff_pos_left 1).mpr (abs_pos.mpr fun F0 => fab _))
  rw [eq_one_div_of_mul_eq_one_left bu, F0, one_div, eq_intCast, Int.cast_zero, zero_eq_mul] at hF
  cases' hF with hF hF
  · exact (not_le.mpr b0 (le_of_eq (int.cast_eq_zero.mp (pow_eq_zero hF)))).elim
  · rwa [div_eq_mul_inv]
#align one_le_pow_mul_abs_eval_div one_le_pow_mul_abs_eval_div


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

/-!
# 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
open matrix

universes u v

variables {k l m n : Type*}
variables [fintype k] [fintype l] [fintype m] [fintype n]
variables {α : Type v}

open_locale matrix

/-- `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 [decidable_eq n] [has_zero α] [has_one α] (f : m ≃. n) : matrix m n α
| i j := if j ∈ f i then 1 else 0

lemma mul_matrix_apply [decidable_eq m] [semiring α] (f : l ≃. m) (M : matrix m n α) (i j) :
  (f.to_matrix ⬝ M) i j = option.cases_on (f i) 0 (λ fi, M fi j) :=
begin
  dsimp [to_matrix, matrix.mul_apply],
  cases h : f i with fi,
  { simp [h] },
  { rw finset.sum_eq_single fi;
    simp [h, eq_comm] {contextual := tt} }
end

lemma to_matrix_symm [decidable_eq m] [decidable_eq n] [has_zero α] [has_one α] (f : m ≃. n) :
  (f.symm.to_matrix : matrix n m α) = f.to_matrixᵀ :=
by ext; simp only [transpose, mem_iff_mem f, to_matrix]; congr

@[simp] lemma to_matrix_refl [decidable_eq n] [has_zero α] [has_one α] :
  ((pequiv.refl n).to_matrix : matrix n n α) = 1 :=
by ext; simp [to_matrix, one_apply]; congr

lemma matrix_mul_apply [semiring α] [decidable_eq n] (M : matrix l m α) (f : m ≃. n) (i j) :
  (M ⬝ f.to_matrix) i j = option.cases_on (f.symm j) 0 (λ fj, M i fj) :=
begin
  dsimp [to_matrix, matrix.mul_apply],
  cases h : f.symm j with fj,
  { simp [h, ← f.eq_some_iff] },
  { rw finset.sum_eq_single fj,
    { simp [h, ← f.eq_some_iff], },
    { intros b H n, simp [h, ← f.eq_some_iff, n.symm], },
    { simp, } }
end

lemma to_pequiv_mul_matrix [decidable_eq m] [semiring α] (f : m ≃ m) (M : matrix m n α) :
  (f.to_pequiv.to_matrix ⬝ M) = λ i, M (f i) :=
by { ext i j, rw [mul_matrix_apply, equiv.to_pequiv_apply] }

lemma to_matrix_trans [decidable_eq m] [decidable_eq n] [semiring α] (f : l ≃. m) (g : m ≃. n) :
  ((f.trans g).to_matrix : matrix l n α) = f.to_matrix ⬝ g.to_matrix :=
begin
  ext i j,
  rw [mul_matrix_apply],
  dsimp [to_matrix, pequiv.trans],
  cases f i; simp
end

@[simp] lemma to_matrix_bot [decidable_eq n] [has_zero α] [has_one α] :
  ((⊥ : pequiv m n).to_matrix : matrix m n α) = 0 := rfl

lemma to_matrix_injective [decidable_eq n] [monoid_with_zero α] [nontrivial α] :
  function.injective (@to_matrix m n _ _ α _ _ _) :=
begin
  classical,
  assume f g,
  refine not_imp_not.1 _,
  simp only [matrix.ext_iff.symm, to_matrix, pequiv.ext_iff,
    not_forall, exists_imp_distrib],
  assume i hi,
  use i,
  cases hf : f i with fi,
  { cases hg : g i with gi,
    { cc },
    { use gi,
      simp, } },
  { use fi,
    simp [hf.symm, ne.symm hi] }
end

lemma to_matrix_swap [decidable_eq n] [ring α] (i j : n) :
  (equiv.swap i j).to_pequiv.to_matrix =
  (1 : matrix n n α) - (single i i).to_matrix - (single j j).to_matrix + (single i j).to_matrix +
    (single j i).to_matrix :=
begin
  ext,
  dsimp [to_matrix, single, equiv.swap_apply_def, equiv.to_pequiv, one_apply],
  split_ifs; simp * at *
end

@[simp] lemma single_mul_single [decidable_eq k] [decidable_eq m] [decidable_eq n] [semiring α]
  (a : m) (b : n) (c : k) :
  ((single a b).to_matrix : matrix _ _ α) ⬝ (single b c).to_matrix = (single a c).to_matrix :=
by rw [← to_matrix_trans, single_trans_single]

lemma single_mul_single_of_ne [decidable_eq k] [decidable_eq m] [decidable_eq n] [semiring α]
  {b₁ b₂ : n} (hb : b₁ ≠ b₂) (a : m) (c : k) :
  ((single a b₁).to_matrix : matrix _ _ α) ⬝ (single b₂ c).to_matrix = 0 :=
by rw [← to_matrix_trans, single_trans_single_of_ne hb, to_matrix_bot]

/-- Restatement of `single_mul_single`, which will simplify expressions in `simp` normal form,
  when associativity may otherwise need to be carefully applied. -/
@[simp] lemma single_mul_single_right [decidable_eq k] [decidable_eq m] [decidable_eq n]
  [semiring α] (a : m) (b : n) (c : k) (M : matrix k l α) :
  (single a b).to_matrix ⬝ ((single b c).to_matrix ⬝ M) = (single a c).to_matrix ⬝ M :=
by rw [← matrix.mul_assoc, single_mul_single]

/-- We can also define permutation matrices by permuting the rows of the identity matrix. -/

end pequiv


/-
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 algebra.group_power.basic
import algebra.invertible
import algebra.opposites
import data.list.basic
import data.int.cast
import data.equiv.basic
import data.equiv.mul_add
import deprecated.group

/-!
# 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`.
-/

universes u v w x y z u₁ u₂

variables {M : Type u} {N : Type v} {G : Type w} {H : Type x} {A : Type y} {B : Type z}
  {R : Type u₁} {S : Type u₂}

/-!
### (Additive) monoid
-/
section monoid
variables [monoid M] [monoid N] [add_monoid A] [add_monoid B]

@[simp] theorem nsmul_one [has_one A] : ∀ n : ℕ, n • (1 : A) = n :=
add_monoid_hom.eq_nat_cast
  ⟨λ n, n • (1 : A), zero_nsmul _, λ _ _, add_nsmul _ _ _⟩
  (one_nsmul _)

@[simp, priority 500]
theorem list.prod_repeat (a : M) (n : ℕ) : (list.repeat a n).prod = a ^ n :=
begin
  induction n with n ih,
  { rw pow_zero, refl },
  { rw [list.repeat_succ, list.prod_cons, ih, pow_succ] }
end

@[simp, priority 500]
theorem list.sum_repeat : ∀ (a : A) (n : ℕ), (list.repeat a n).sum = n • a :=
@list.prod_repeat (multiplicative A) _

@[simp, norm_cast] lemma units.coe_pow (u : units M) (n : ℕ) : ((u ^ n : units M) : M) = u ^ n :=
(units.coe_hom M).map_pow u n

instance invertible_pow (m : M) [invertible m] (n : ℕ) : invertible (m ^ n) :=
{ inv_of := ⅟ m ^ n,
  inv_of_mul_self := by rw [← (commute_inv_of m).symm.mul_pow, inv_of_mul_self, one_pow],
  mul_inv_of_self := by rw [← (commute_inv_of m).mul_pow, mul_inv_of_self, one_pow] }

lemma inv_of_pow (m : M) [invertible m] (n : ℕ) [invertible (m ^ n)] :
  ⅟(m ^ n) = ⅟m ^ n :=
@invertible_unique M _ (m ^ n) (m ^ n) rfl ‹_› (invertible_pow m n)

lemma is_unit.pow {m : M} (n : ℕ) : is_unit m → is_unit (m ^ n) :=
λ ⟨u, hu⟩, ⟨u ^ n, by simp *⟩

/-- If `x ^ n.succ = 1` then `x` has an inverse, `x^n`. -/
def invertible_of_pow_succ_eq_one (x : M) (n : ℕ) (hx : x ^ n.succ = 1) :
  invertible x :=
⟨x ^ n, (pow_succ' x n).symm.trans hx, (pow_succ x n).symm.trans hx⟩

/-- If `x ^ n = 1` then `x` has an inverse, `x^(n - 1)`. -/
def invertible_of_pow_eq_one (x : M) (n : ℕ) (hx : x ^ n = 1) (hn : 0 < n) :
  invertible x :=
begin
  apply invertible_of_pow_succ_eq_one x (n - 1),
  convert hx,
  exact nat.sub_add_cancel (nat.succ_le_of_lt hn),
end

lemma is_unit_of_pow_eq_one (x : M) (n : ℕ) (hx : x ^ n = 1) (hn : 0 < n) :
  is_unit x :=
begin
  haveI := invertible_of_pow_eq_one x n hx hn,
  exact is_unit_of_invertible x
end

end monoid

theorem nat.nsmul_eq_mul (m n : ℕ) : m • n = m * n :=
by induction m with m ih; [rw [zero_nsmul, zero_mul],
  rw [succ_nsmul', ih, nat.succ_mul]]

section group
variables [group G] [group H] [add_group A] [add_group B]

open int

local attribute [ematch] le_of_lt
open nat

theorem gsmul_one [has_one A] (n : ℤ) : n • (1 : A) = n :=
by cases n; simp

lemma gpow_add_one (a : G) : ∀ n : ℤ, a ^ (n + 1) = a ^ n * a
| (of_nat n) := by simp [← int.coe_nat_succ, pow_succ']
| -[1+0]     := by simp [int.neg_succ_of_nat_eq]
| -[1+(n+1)] := by rw [int.neg_succ_of_nat_eq, gpow_neg, neg_add, neg_add_cancel_right, gpow_neg,
  ← int.coe_nat_succ, gpow_coe_nat, gpow_coe_nat, pow_succ _ (n + 1), mul_inv_rev,
  inv_mul_cancel_right]

theorem add_one_gsmul : ∀ (a : A) (i : ℤ), (i + 1) • a = i • a + a :=
@gpow_add_one (multiplicative A) _

lemma gpow_sub_one (a : G) (n : ℤ) : a ^ (n - 1) = a ^ n * a⁻¹ :=
calc a ^ (n - 1) = a ^ (n - 1) * a * a⁻¹ : (mul_inv_cancel_right _ _).symm
             ... = a^n * a⁻¹             : by rw [← gpow_add_one, sub_add_cancel]

lemma gpow_add (a : G) (m n : ℤ) : a ^ (m + n) = a ^ m * a ^ n :=
begin
  induction n using int.induction_on with n ihn n ihn,
  case hz : { simp },
  { simp only [← add_assoc, gpow_add_one, ihn, mul_assoc] },
  { rw [gpow_sub_one, ← mul_assoc, ← ihn, ← gpow_sub_one, add_sub_assoc] }
end

lemma mul_self_gpow (b : G) (m : ℤ) : b*b^m = b^(m+1) :=
by { conv_lhs {congr, rw ← gpow_one b }, rw [← gpow_add, add_comm] }

lemma mul_gpow_self (b : G) (m : ℤ) : b^m*b = b^(m+1) :=
by { conv_lhs {congr, skip, rw ← gpow_one b }, rw [← gpow_add, add_comm] }

theorem add_gsmul : ∀ (a : A) (i j : ℤ), (i + j) • a = i • a + j • a :=
@gpow_add (multiplicative A) _

lemma gpow_sub (a : G) (m n : ℤ) : a ^ (m - n) = a ^ m * (a ^ n)⁻¹ :=
by rw [sub_eq_add_neg, gpow_add, gpow_neg]

lemma sub_gsmul (m n : ℤ) (a : A) : (m - n) • a = m • a - n • a :=
by simpa only [sub_eq_add_neg] using @gpow_sub (multiplicative A) _ _ _ _

theorem gpow_one_add (a : G) (i : ℤ) : a ^ (1 + i) = a * a ^ i :=
by rw [gpow_add, gpow_one]

theorem one_add_gsmul : ∀ (a : A) (i : ℤ), (1 + i) • a = a + i • a :=
@gpow_one_add (multiplicative A) _

theorem gpow_mul_comm (a : G) (i j : ℤ) : a ^ i * a ^ j = a ^ j * a ^ i :=
by rw [← gpow_add, ← gpow_add, add_comm]

theorem gsmul_add_comm : ∀ (a : A) (i j : ℤ), i • a + j • a = j • a + i • a :=
@gpow_mul_comm (multiplicative A) _

theorem gpow_mul (a : G) (m n : ℤ) : a ^ (m * n) = (a ^ m) ^ n :=
int.induction_on n (by simp) (λ n ihn, by simp [mul_add, gpow_add, ihn])
  (λ n ihn, by simp only [mul_sub, gpow_sub, ihn, mul_one, gpow_one])

theorem gsmul_mul' : ∀ (a : A) (m n : ℤ), (m * n) • a = n • (m • a) :=
@gpow_mul (multiplicative A) _

theorem gpow_mul' (a : G) (m n : ℤ) : a ^ (m * n) = (a ^ n) ^ m :=
by rw [mul_comm, gpow_mul]

theorem mul_gsmul (a : A) (m n : ℤ) : (m * n) • a = m • (n • a) :=
by rw [mul_comm, gsmul_mul']

theorem gpow_bit0 (a : G) (n : ℤ) : a ^ bit0 n = a ^ n * a ^ n := gpow_add _ _ _

theorem bit0_gsmul (a : A) (n : ℤ) : bit0 n • a = n • a + n • a :=
@gpow_bit0 (multiplicative A) _ _ _

theorem gpow_bit1 (a : G) (n : ℤ) : a ^ bit1 n = a ^ n * a ^ n * a :=
by rw [bit1, gpow_add, gpow_bit0, gpow_one]

theorem bit1_gsmul : ∀ (a : A) (n : ℤ), bit1 n • a = n • a + n • a + a :=
@gpow_bit1 (multiplicative A) _

@[simp] theorem monoid_hom.map_gpow (f : G →* H) (a : G) (n : ℤ) : f (a ^ n) = f a ^ n :=
by cases n; simp

@[simp] theorem add_monoid_hom.map_gsmul (f : A →+ B) (a : A) (n : ℤ) : f (n • a) = n • f a :=
f.to_multiplicative.map_gpow a n

@[simp, norm_cast] lemma units.coe_gpow (u : units G) (n : ℤ) : ((u ^ n : units G) : G) = u ^ n :=
(units.coe_hom G).map_gpow u n

end group

section ordered_add_comm_group

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

lemma gsmul_pos {a : A} (ha : 0 < a) {k : ℤ} (hk : (0:ℤ) < k) : 0 < k • a :=
begin
  lift k to ℕ using int.le_of_lt hk,
  rw gsmul_coe_nat,
  apply nsmul_pos ha,
  exact coe_nat_pos.mp hk,
end

theorem gsmul_le_gsmul {a : A} {n m : ℤ} (ha : 0 ≤ a) (h : n ≤ m) : n • a ≤ m • a :=
calc n • a = n • a + 0 : (add_zero _).symm
  ... ≤ n • a + (m - n) • a : add_le_add_left (gsmul_nonneg ha (sub_nonneg.mpr h)) _
  ... = m • a : by { rw [← add_gsmul], simp }

theorem gsmul_lt_gsmul {a : A} {n m : ℤ} (ha : 0 < a) (h : n < m) : n • a < m • a :=
calc n • a = n • a + 0 : (add_zero _).symm
  ... < n • a + (m - n) • a : add_lt_add_left (gsmul_pos ha (sub_pos.mpr h)) _
  ... = m • a : by { rw [← add_gsmul], simp }

lemma abs_nsmul {α : Type*} [linear_ordered_add_comm_group α] (n : ℕ) (a : α) :
  abs (n • a) = n • abs a :=
begin
  cases le_total a 0 with hneg hpos,
  { rw [abs_of_nonpos hneg, ← abs_neg, ← neg_nsmul, abs_of_nonneg],
    exact nsmul_nonneg (neg_nonneg.mpr hneg) n },
  { rw [abs_of_nonneg hpos, abs_of_nonneg],
    exact nsmul_nonneg hpos n }
end

lemma abs_gsmul {α : Type*} [linear_ordered_add_comm_group α] (n : ℤ) (a : α) :
  abs (n • a) = (abs n) • abs a :=
begin
  by_cases n0 : 0 ≤ n,
  { lift n to ℕ using n0,
    simp only [abs_nsmul, coe_nat_abs, gsmul_coe_nat] },
  { lift (- n) to ℕ using int.le_of_lt (neg_pos.mpr (not_le.mp n0)) with m h,
    rw [← abs_neg (n • a), ← neg_gsmul, ← abs_neg n, ← h, gsmul_coe_nat, coe_nat_abs,
      gsmul_coe_nat],
    exact abs_nsmul m _ },
end

lemma abs_add_eq_add_abs_le {α : Type*} [linear_ordered_add_comm_group α] {a b : α} (hle : a ≤ b) :
  abs (a + b) = abs a + abs b ↔ (0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0) :=
begin
  by_cases a0 : 0 ≤ a; by_cases b0 : 0 ≤ b,
  { simp [a0, b0, abs_of_nonneg, add_nonneg a0 b0] },
  { exact (lt_irrefl (0 : α) (a0.trans_lt (hle.trans_lt (not_le.mp b0)))).elim },
  any_goals { simp [(not_le.mp a0).le, (not_le.mp b0).le, abs_of_nonpos, add_nonpos, add_comm] },
  obtain F := (not_le.mp a0),
  have : (abs (a + b) = -a + b ↔ b ≤ 0) ↔ (abs (a + b) =
    abs a + abs b ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0),
  { simp [a0, b0, abs_of_neg, abs_of_nonneg, F, F.le] },
  refine this.mp ⟨λ h, _, λ h, by simp only [le_antisymm h b0, abs_of_neg F, add_zero]⟩,
  by_cases ba : a + b ≤ 0,
  { refine le_of_eq (eq_zero_of_neg_eq _),
    rwa [abs_of_nonpos ba, neg_add_rev, add_comm, add_right_inj] at h },
  { refine (lt_irrefl (0 : α) _).elim,
    rw [abs_of_pos (not_le.mp ba), add_left_inj] at h,
    rwa eq_zero_of_neg_eq h.symm at F }
end

lemma abs_add_eq_add_abs_iff {α : Type*} [linear_ordered_add_comm_group α] (a b : α) :
  abs (a + b) = abs a + abs b ↔ (0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0) :=
begin
  by_cases ab : a ≤ b,
  { exact abs_add_eq_add_abs_le ab },
  { rw [add_comm a, add_comm (abs _), abs_add_eq_add_abs_le ((not_le.mp ab).le), and.comm,
    @and.comm (b ≤ 0 ) _] }
end

end ordered_add_comm_group

section linear_ordered_add_comm_group
variable [linear_ordered_add_comm_group A]

theorem gsmul_le_gsmul_iff {a : A} {n m : ℤ} (ha : 0 < a) : n • a ≤ m • a ↔ n ≤ m :=
begin
  refine ⟨λ h, _, gsmul_le_gsmul $ le_of_lt ha⟩,
  by_contra H,
  exact lt_irrefl _ (lt_of_lt_of_le (gsmul_lt_gsmul ha (not_le.mp H)) h)
end

theorem gsmul_lt_gsmul_iff {a : A} {n m : ℤ} (ha : 0 < a) : n • a < m • a ↔ n < m :=
begin
  refine ⟨λ h, _, gsmul_lt_gsmul ha⟩,
  by_contra H,
  exact lt_irrefl _ (lt_of_le_of_lt (gsmul_le_gsmul (le_of_lt ha) $ not_lt.mp H) h)
end

theorem nsmul_le_nsmul_iff {a : A} {n m : ℕ} (ha : 0 < a) : n • a ≤ m • a ↔ n ≤ m :=
begin
  refine ⟨λ h, _, nsmul_le_nsmul $ le_of_lt ha⟩,
  by_contra H,
  exact lt_irrefl _ (lt_of_lt_of_le (nsmul_lt_nsmul ha (not_le.mp H)) h)
end

theorem nsmul_lt_nsmul_iff {a : A} {n m : ℕ} (ha : 0 < a) : n • a < m • a ↔ n < m :=
begin
  refine ⟨λ h, _, nsmul_lt_nsmul ha⟩,
  by_contra H,
  exact lt_irrefl _ (lt_of_le_of_lt (nsmul_le_nsmul (le_of_lt ha) $ not_lt.mp H) h)
end

end linear_ordered_add_comm_group

@[simp] lemma with_bot.coe_nsmul [add_monoid A] (a : A) (n : ℕ) :
  ((n • a : A) : with_bot A) = n • a :=
add_monoid_hom.map_nsmul ⟨(coe : A → with_bot A), with_bot.coe_zero, with_bot.coe_add⟩ a n

theorem nsmul_eq_mul' [semiring R] (a : R) (n : ℕ) : n • a = a * n :=
by induction n with n ih; [rw [zero_nsmul, nat.cast_zero, mul_zero],
  rw [succ_nsmul', ih, nat.cast_succ, mul_add, mul_one]]

@[simp] theorem nsmul_eq_mul [semiring R] (n : ℕ) (a : R) : n • a = n * a :=
by rw [nsmul_eq_mul', (n.cast_commute a).eq]

theorem mul_nsmul_left [semiring R] (a b : R) (n : ℕ) : n • (a * b) = a * (n • b) :=
by rw [nsmul_eq_mul', nsmul_eq_mul', mul_assoc]

theorem mul_nsmul_assoc [semiring R] (a b : R) (n : ℕ) : n • (a * b) = n • a * b :=
by rw [nsmul_eq_mul, nsmul_eq_mul, mul_assoc]

@[simp, norm_cast] theorem nat.cast_pow [semiring R] (n m : ℕ) : (↑(n ^ m) : R) = ↑n ^ m :=
begin
  induction m with m ih,
  { rw [pow_zero, pow_zero], exact nat.cast_one },
  { rw [pow_succ', pow_succ', nat.cast_mul, ih] }
end

@[simp, norm_cast] theorem int.coe_nat_pow (n m : ℕ) : ((n ^ m : ℕ) : ℤ) = n ^ m :=
by induction m with m ih; [exact int.coe_nat_one, rw [pow_succ', pow_succ', int.coe_nat_mul, ih]]

theorem int.nat_abs_pow (n : ℤ) (k : ℕ) : int.nat_abs (n ^ k) = (int.nat_abs n) ^ k :=
by induction k with k ih; [refl, rw [pow_succ', int.nat_abs_mul, pow_succ', ih]]

-- 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`.

lemma bit0_mul [ring R] {n r : R} : bit0 n * r = (2 : ℤ) • (n * r) :=
by { dsimp [bit0], rw [add_mul, add_gsmul, one_gsmul], }

lemma mul_bit0 [ring R] {n r : R} : r * bit0 n = (2 : ℤ) • (r * n) :=
by { dsimp [bit0], rw [mul_add, add_gsmul, one_gsmul], }

lemma bit1_mul [ring R] {n r : R} : bit1 n * r = (2 : ℤ) • (n * r) + r :=
by { dsimp [bit1], rw [add_mul, bit0_mul, one_mul], }

lemma mul_bit1 [ring R] {n r : R} : r * bit1 n = (2 : ℤ) • (r * n) + r :=
by { dsimp [bit1], rw [mul_add, mul_bit0, mul_one], }

@[simp] theorem gsmul_eq_mul [ring R] (a : R) : ∀ (n : ℤ), n • a = n * a
| (n : ℕ) := by { rw [gsmul_coe_nat, nsmul_eq_mul], refl }
| -[1+ n] := by simp [nat.cast_succ, neg_add_rev, int.cast_neg_succ_of_nat, add_mul]

theorem gsmul_eq_mul' [ring R] (a : R) (n : ℤ) : n • a = a * n :=
by rw [gsmul_eq_mul, (n.cast_commute a).eq]

theorem mul_gsmul_left [ring R] (a b : R) (n : ℤ) : n • (a * b) = a * (n • b) :=
by rw [gsmul_eq_mul', gsmul_eq_mul', mul_assoc]

theorem mul_gsmul_assoc [ring R] (a b : R) (n : ℤ) : n • (a * b) = n • a * b :=
by rw [gsmul_eq_mul, gsmul_eq_mul, mul_assoc]

lemma gsmul_int_int (a b : ℤ) : a • b = a * b := by simp

lemma gsmul_int_one (n : ℤ) : n • 1 = n := by simp

@[simp, norm_cast] theorem int.cast_pow [ring R] (n : ℤ) (m : ℕ) : (↑(n ^ m) : R) = ↑n ^ m :=
begin
  induction m with m ih,
  { rw [pow_zero, pow_zero, int.cast_one] },
  { rw [pow_succ, pow_succ, int.cast_mul, ih] }
end

lemma neg_one_pow_eq_pow_mod_two [ring R] {n : ℕ} : (-1 : R) ^ n = (-1) ^ (n % 2) :=
by rw [← nat.mod_add_div n 2, pow_add, pow_mul]; simp [sq]

section ordered_semiring
variable [ordered_semiring R]

/-- 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' {a : R} (Hsq : 0 ≤ a * a) (Hsq' : 0 ≤ (1 + a) * (1 + a))
  (H : 0 ≤ 2 + a) :
  ∀ (n : ℕ), 1 + (n : R) * a ≤ (1 + a) ^ n
| 0     := by simp
| 1     := by simp
| (n+2) :=
have 0 ≤ (n : R) * (a * a * (2 + a)) + a * a,
  from add_nonneg (mul_nonneg n.cast_nonneg (mul_nonneg Hsq H)) Hsq,
calc 1 + (↑(n + 2) : R) * a ≤ 1 + ↑(n + 2) * a + (n * (a * a * (2 + a)) + a * a) :
  (le_add_iff_nonneg_right _).2 this
... = (1 + a) * (1 + a) * (1 + n * a) :
  by { simp [add_mul, mul_add, bit0, mul_assoc, (n.cast_commute (_ : R)).left_comm],
       ac_refl }
... ≤ (1 + a) * (1 + a) * (1 + a)^n :
  mul_le_mul_of_nonneg_left (one_add_mul_le_pow' n) Hsq'
... = (1 + a)^(n + 2) : by simp only [pow_succ, mul_assoc]

private lemma pow_lt_pow_of_lt_one_aux {a : R} (h : 0 < a) (ha : a < 1) (i : ℕ) :
  ∀ k : ℕ, a ^ (i + k + 1) < a ^ i
| 0 :=
  begin
    rw [←one_mul (a^i), add_zero, pow_succ],
    exact mul_lt_mul ha (le_refl _) (pow_pos h _) zero_le_one
  end
| (k+1) :=
  begin
    rw [←one_mul (a^i), pow_succ],
    apply mul_lt_mul ha _ _ zero_le_one,
    { apply le_of_lt, apply pow_lt_pow_of_lt_one_aux },
    { show 0 < a ^ (i + (k + 1) + 0), apply pow_pos h }
  end

private lemma pow_le_pow_of_le_one_aux {a : R}  (h : 0 ≤ a) (ha : a ≤ 1) (i : ℕ) :
  ∀ k : ℕ, a ^ (i + k) ≤ a ^ i
| 0 := by simp
| (k+1) := by { rw [←add_assoc, ←one_mul (a^i), pow_succ],
                exact mul_le_mul ha (pow_le_pow_of_le_one_aux _) (pow_nonneg h _) zero_le_one }

lemma pow_lt_pow_of_lt_one  {a : R} (h : 0 < a) (ha : a < 1)
  {i j : ℕ} (hij : i < j) : a ^ j < a ^ i :=
let ⟨k, hk⟩ := nat.exists_eq_add_of_lt hij in
by rw hk; exact pow_lt_pow_of_lt_one_aux h ha _ _

lemma pow_lt_pow_iff_of_lt_one {a : R} {n m : ℕ} (hpos : 0 < a) (h : a < 1) :
  a ^ m < a ^ n ↔ n < m :=
begin
  have : strict_mono (λ (n : order_dual ℕ), a ^ (id n : ℕ)) := λ m n, pow_lt_pow_of_lt_one hpos h,
  exact this.lt_iff_lt
end

lemma pow_le_pow_of_le_one  {a : R} (h : 0 ≤ a) (ha : a ≤ 1)
  {i j : ℕ} (hij : i ≤ j) : a ^ j ≤ a ^ i :=
let ⟨k, hk⟩ := nat.exists_eq_add_of_le hij in
by rw hk; exact pow_le_pow_of_le_one_aux h ha _ _

lemma pow_le_one {x : R} : ∀ (n : ℕ) (h0 : 0 ≤ x) (h1 : x ≤ 1), x ^ n ≤ 1
| 0     h0 h1 := by rw [pow_zero]
| (n+1) h0 h1 := by { rw [pow_succ], exact mul_le_one h1 (pow_nonneg h0 _) (pow_le_one n h0 h1) }

end ordered_semiring

section linear_ordered_semiring

variables [linear_ordered_semiring R]

lemma sign_cases_of_C_mul_pow_nonneg {C r : R} (h : ∀ n : ℕ, 0 ≤ C * r ^ n) :
  C = 0 ∨ (0 < C ∧ 0 ≤ r) :=
begin
  have : 0 ≤ C, by simpa only [pow_zero, mul_one] using h 0,
  refine this.eq_or_lt.elim (λ h, or.inl h.symm) (λ hC, or.inr ⟨hC, _⟩),
  refine nonneg_of_mul_nonneg_left _ hC,
  simpa only [pow_one] using h 1
end

end linear_ordered_semiring

section linear_ordered_ring

variables [linear_ordered_ring R] {a : R} {n : ℕ}

@[simp] lemma abs_pow (a : R) (n : ℕ) : abs (a ^ n) = abs a ^ n :=
(pow_abs a n).symm

@[simp] theorem pow_bit1_neg_iff : a ^ bit1 n < 0 ↔ a < 0 :=
⟨λ h, not_le.1 $ λ h', not_le.2 h $ pow_nonneg h' _,
  λ h, by { rw [bit1, pow_succ], exact mul_neg_of_neg_of_pos h (pow_bit0_pos h.ne _)}⟩

@[simp] theorem pow_bit1_nonneg_iff : 0 ≤ a ^ bit1 n ↔ 0 ≤ a :=
le_iff_le_iff_lt_iff_lt.2 pow_bit1_neg_iff

@[simp] theorem pow_bit1_nonpos_iff : a ^ bit1 n ≤ 0 ↔ a ≤ 0 :=
by simp only [le_iff_lt_or_eq, pow_bit1_neg_iff, pow_eq_zero_iff (bit1_pos (zero_le n))]

@[simp] theorem pow_bit1_pos_iff : 0 < a ^ bit1 n ↔ 0 < a :=
lt_iff_lt_of_le_iff_le pow_bit1_nonpos_iff

theorem pow_even_nonneg (a : R) (hn : even n) : 0 ≤ a ^ n :=
by cases hn with k hk; simpa only [hk, two_mul] using pow_bit0_nonneg a k

theorem pow_even_pos (ha : a ≠ 0) (hn : even n) : 0 < a ^ n :=
by cases hn with k hk; simpa only [hk, two_mul] using pow_bit0_pos ha k

theorem pow_odd_nonneg (ha : 0 ≤ a) (hn : odd n) : 0 ≤ a ^ n :=
by cases hn with k hk; simpa only [hk, two_mul] using pow_bit1_nonneg_iff.mpr ha

theorem pow_odd_pos (ha : 0 < a) (hn : odd n) : 0 < a ^ n :=
by cases hn with k hk; simpa only [hk, two_mul] using pow_bit1_pos_iff.mpr ha

theorem pow_odd_nonpos (ha : a ≤ 0) (hn : odd n) : a ^ n ≤ 0:=
by cases hn with k hk; simpa only [hk, two_mul] using pow_bit1_nonpos_iff.mpr ha

theorem pow_odd_neg (ha : a < 0) (hn : odd n) : a ^ n < 0:=
by cases hn with k hk; simpa only [hk, two_mul] using pow_bit1_neg_iff.mpr ha

lemma pow_even_abs (a : R) {p : ℕ} (hp : even p) :
  abs a ^ p = a ^ p :=
begin
  rw [←abs_pow, abs_eq_self],
  exact pow_even_nonneg _ hp
end

@[simp] lemma pow_bit0_abs (a : R) (p : ℕ) :
  abs a ^ bit0 p = a ^ bit0 p :=
pow_even_abs _ (even_bit0 _)

lemma strict_mono_pow_bit1 (n : ℕ) : strict_mono (λ a : R, a ^ bit1 n) :=
begin
  intros a b hab,
  cases le_total a 0 with ha ha,
  { cases le_or_lt b 0 with hb hb,
    { rw [← neg_lt_neg_iff, ← neg_pow_bit1, ← neg_pow_bit1],
      exact pow_lt_pow_of_lt_left (neg_lt_neg hab) (neg_nonneg.2 hb) (bit1_pos (zero_le n)) },
    { exact (pow_bit1_nonpos_iff.2 ha).trans_lt (pow_bit1_pos_iff.2 hb) } },
  { exact pow_lt_pow_of_lt_left hab ha (bit1_pos (zero_le n)) }
end

/-- Bernoulli's inequality for `n : ℕ`, `-2 ≤ a`. -/
theorem one_add_mul_le_pow (H : -2 ≤ a) (n : ℕ) : 1 + (n : R) * a ≤ (1 + a) ^ n :=
one_add_mul_le_pow' (mul_self_nonneg _) (mul_self_nonneg _) (neg_le_iff_add_nonneg'.1 H) _

/-- Bernoulli's inequality reformulated to estimate `a^n`. -/
theorem one_add_mul_sub_le_pow (H : -1 ≤ a) (n : ℕ) : 1 + (n : R) * (a - 1) ≤ a ^ n :=
have -2 ≤ a - 1, by rwa [bit0, neg_add, ← sub_eq_add_neg, sub_le_sub_iff_right],
by simpa only [add_sub_cancel'_right] using one_add_mul_le_pow this n

end linear_ordered_ring

/-- Bernoulli's inequality reformulated to estimate `(n : K)`. -/
theorem nat.cast_le_pow_sub_div_sub {K : Type*} [linear_ordered_field K] {a : K} (H : 1 < a)
  (n : ℕ) :
  (n : K) ≤ (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 K _).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 {K : Type*} [linear_ordered_field K] {a : K} (H : 1 < a) (n : ℕ) :
  (n : K) ≤ 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)

namespace int

lemma units_sq (u : units ℤ) : u ^ 2 = 1 :=
(sq u).symm ▸ units_mul_self u

alias int.units_sq ← int.units_pow_two

lemma units_pow_eq_pow_mod_two (u : units ℤ) (n : ℕ) : u ^ n = u ^ (n % 2) :=
by conv {to_lhs, rw ← nat.mod_add_div n 2}; rw [pow_add, pow_mul, units_sq, one_pow, mul_one]

@[simp] lemma nat_abs_sq (x : ℤ) : (x.nat_abs ^ 2 : ℤ) = x ^ 2 :=
by rw [sq, int.nat_abs_mul_self', sq]

alias int.nat_abs_sq ← int.nat_abs_pow_two

lemma abs_le_self_sq (a : ℤ) : (int.nat_abs a : ℤ) ≤ a ^ 2 :=
by { rw [← int.nat_abs_sq a, sq], norm_cast, apply nat.le_mul_self }

alias int.abs_le_self_sq ← int.abs_le_self_pow_two

lemma le_self_sq (b : ℤ) : b ≤ b ^ 2 := le_trans (le_nat_abs) (abs_le_self_sq _)

alias int.le_self_sq ← int.le_self_pow_two

end int

variables (M G A)

/-- Monoid homomorphisms from `multiplicative ℕ` are defined by the image
of `multiplicative.of_add 1`. -/
def powers_hom [monoid M] : M ≃ (multiplicative ℕ →* M) :=
{ to_fun := λ x, ⟨λ n, x ^ n.to_add, by { convert pow_zero x, exact to_add_one },
    λ m n, pow_add x m n⟩,
  inv_fun := λ f, f (multiplicative.of_add 1),
  left_inv := pow_one,
  right_inv := λ f, monoid_hom.ext $ λ n, by { simp [← f.map_pow, ← of_add_nsmul] } }

/-- Monoid homomorphisms from `multiplicative ℤ` are defined by the image
of `multiplicative.of_add 1`. -/
def gpowers_hom [group G] : G ≃ (multiplicative ℤ →* G) :=
{ to_fun := λ x, ⟨λ n, x ^ n.to_add, gpow_zero x, λ m n, gpow_add x m n⟩,
  inv_fun := λ f, f (multiplicative.of_add 1),
  left_inv := gpow_one,
  right_inv := λ f, monoid_hom.ext $ λ n, by { simp [← f.map_gpow, ← of_add_gsmul ] } }

/-- Additive homomorphisms from `ℕ` are defined by the image of `1`. -/
def multiples_hom [add_monoid A] : A ≃ (ℕ →+ A) :=
{ to_fun := λ x, ⟨λ n, n • x, zero_nsmul x, λ m n, add_nsmul _ _ _⟩,
  inv_fun := λ f, f 1,
  left_inv := one_nsmul,
  right_inv := λ f, add_monoid_hom.ext_nat $ one_nsmul (f 1) }

/-- Additive homomorphisms from `ℤ` are defined by the image of `1`. -/
def gmultiples_hom [add_group A] : A ≃ (ℤ →+ A) :=
{ to_fun := λ x, ⟨λ n, n • x, zero_gsmul x, λ m n, add_gsmul _ _ _⟩,
  inv_fun := λ f, f 1,
  left_inv := one_gsmul,
  right_inv := λ f, add_monoid_hom.ext_int $ one_gsmul (f 1) }

variables {M G A}

@[simp] lemma powers_hom_apply [monoid M] (x : M) (n : multiplicative ℕ) :
  powers_hom M x n = x ^ n.to_add := rfl

@[simp] lemma powers_hom_symm_apply [monoid M] (f : multiplicative ℕ →* M) :
  (powers_hom M).symm f = f (multiplicative.of_add 1) := rfl

@[simp] lemma gpowers_hom_apply [group G] (x : G) (n : multiplicative ℤ) :
  gpowers_hom G x n = x ^ n.to_add := rfl

@[simp] lemma gpowers_hom_symm_apply [group G] (f : multiplicative ℤ →* G) :
  (gpowers_hom G).symm f = f (multiplicative.of_add 1) := rfl

@[simp] lemma multiples_hom_apply [add_monoid A] (x : A) (n : ℕ) :
  multiples_hom A x n = n • x := rfl

@[simp] lemma multiples_hom_symm_apply [add_monoid A] (f : ℕ →+ A) :
  (multiples_hom A).symm f = f 1 := rfl

@[simp] lemma gmultiples_hom_apply [add_group A] (x : A) (n : ℤ) :
  gmultiples_hom A x n = n • x := rfl

@[simp] lemma gmultiples_hom_symm_apply [add_group A] (f : ℤ →+ A) :
  (gmultiples_hom A).symm f = f 1 := rfl

lemma monoid_hom.apply_mnat [monoid M] (f : multiplicative ℕ →* M) (n : multiplicative ℕ) :
  f n = (f (multiplicative.of_add 1)) ^ n.to_add :=
by rw [← powers_hom_symm_apply, ← powers_hom_apply, equiv.apply_symm_apply]

@[ext] lemma monoid_hom.ext_mnat [monoid M] ⦃f g : multiplicative ℕ →* M⦄
  (h : f (multiplicative.of_add 1) = g (multiplicative.of_add 1)) : f = g :=
monoid_hom.ext $ λ n, by rw [f.apply_mnat, g.apply_mnat, h]

lemma monoid_hom.apply_mint [group M] (f : multiplicative ℤ →* M) (n : multiplicative ℤ) :
  f n = (f (multiplicative.of_add 1)) ^ n.to_add :=
by rw [← gpowers_hom_symm_apply, ← gpowers_hom_apply, equiv.apply_symm_apply]

/-! `monoid_hom.ext_mint` is defined in `data.int.cast` -/

lemma add_monoid_hom.apply_nat [add_monoid M] (f : ℕ →+ M) (n : ℕ) :
  f n = n • (f 1) :=
by rw [← multiples_hom_symm_apply, ← multiples_hom_apply, equiv.apply_symm_apply]

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

lemma add_monoid_hom.apply_int [add_group M] (f : ℤ →+ M) (n : ℤ) :
  f n = n • (f 1) :=
by rw [← gmultiples_hom_symm_apply, ← gmultiples_hom_apply, equiv.apply_symm_apply]

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

variables (M G A)

/-- If `M` is commutative, `powers_hom` is a multiplicative equivalence. -/
def powers_mul_hom [comm_monoid M] : M ≃* (multiplicative ℕ →* M) :=
{ map_mul' := λ a b, monoid_hom.ext $ by simp [mul_pow],
  ..powers_hom M}

/-- If `M` is commutative, `gpowers_hom` is a multiplicative equivalence. -/
def gpowers_mul_hom [comm_group G] : G ≃* (multiplicative ℤ →* G) :=
{ map_mul' := λ a b, monoid_hom.ext $ by simp [mul_gpow],
  ..gpowers_hom G}

/-- If `M` is commutative, `multiples_hom` is an additive equivalence. -/
def multiples_add_hom [add_comm_monoid A] : A ≃+ (ℕ →+ A) :=
{ map_add' := λ a b, add_monoid_hom.ext $ by simp [nsmul_add],
  ..multiples_hom A}

/-- If `M` is commutative, `gmultiples_hom` is an additive equivalence. -/
def gmultiples_add_hom [add_comm_group A] : A ≃+ (ℤ →+ A) :=
{ map_add' := λ a b, add_monoid_hom.ext $ by simp [gsmul_add],
  ..gmultiples_hom A}

variables {M G A}

@[simp] lemma powers_mul_hom_apply [comm_monoid M] (x : M) (n : multiplicative ℕ) :
  powers_mul_hom M x n = x ^ n.to_add := rfl

@[simp] lemma powers_mul_hom_symm_apply [comm_monoid M] (f : multiplicative ℕ →* M) :
  (powers_mul_hom M).symm f = f (multiplicative.of_add 1) := rfl

@[simp] lemma gpowers_mul_hom_apply [comm_group G] (x : G) (n : multiplicative ℤ) :
  gpowers_mul_hom G x n = x ^ n.to_add := rfl

@[simp] lemma gpowers_mul_hom_symm_apply [comm_group G] (f : multiplicative ℤ →* G) :
  (gpowers_mul_hom G).symm f = f (multiplicative.of_add 1) := rfl

@[simp] lemma multiples_add_hom_apply [add_comm_monoid A] (x : A) (n : ℕ) :
  multiples_add_hom A x n = n • x := rfl

@[simp] lemma multiples_add_hom_symm_apply [add_comm_monoid A] (f : ℕ →+ A) :
  (multiples_add_hom A).symm f = f 1 := rfl

@[simp] lemma gmultiples_add_hom_apply [add_comm_group A] (x : A) (n : ℤ) :
  gmultiples_add_hom A x n = n • x := rfl

@[simp] lemma gmultiples_add_hom_symm_apply [add_comm_group A] (f : ℤ →+ A) :
  (gmultiples_add_hom A).symm f = 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

section

variables [semiring R] {a x y : R}

@[simp] lemma cast_nat_mul_right (h : semiconj_by a x y) (n : ℕ) :
  semiconj_by a ((n : R) * x) (n * y) :=
semiconj_by.mul_right (nat.commute_cast _ _) h

@[simp] lemma cast_nat_mul_left (h : semiconj_by a x y) (n : ℕ) : semiconj_by ((n : R) * a) x y :=
semiconj_by.mul_left (nat.cast_commute _ _) h

@[simp] lemma cast_nat_mul_cast_nat_mul (h : semiconj_by a x y) (m n : ℕ) :
  semiconj_by ((m : R) * a) (n * x) (n * y) :=
(h.cast_nat_mul_left m).cast_nat_mul_right n

end

variables [monoid M] [group G] [ring R]

@[simp] lemma units_gpow_right {a : M} {x y : units M} (h : semiconj_by a x y) :
  ∀ m : ℤ, semiconj_by a (↑(x^m)) (↑(y^m))
| (n : ℕ) := by simp only [gpow_coe_nat, units.coe_pow, h, pow_right]
| -[1+n] := by simp only [gpow_neg_succ_of_nat, units.coe_pow, units_inv_right, h, pow_right]

variables {a b x y x' y' : R}

@[simp] lemma cast_int_mul_right (h : semiconj_by a x y) (m : ℤ) :
  semiconj_by a ((m : ℤ) * x) (m * y) :=
semiconj_by.mul_right (int.commute_cast _ _) h

@[simp] lemma cast_int_mul_left (h : semiconj_by a x y) (m : ℤ) : semiconj_by ((m : R) * a) x y :=
semiconj_by.mul_left (int.cast_commute _ _) h

@[simp] lemma cast_int_mul_cast_int_mul (h : semiconj_by a x y) (m n : ℤ) :
  semiconj_by ((m : R) * a) (n * x) (n * y) :=
(h.cast_int_mul_left m).cast_int_mul_right n

end semiconj_by

namespace commute

section

variables [semiring R] {a b : R}

@[simp] theorem cast_nat_mul_right (h : commute a b) (n : ℕ) : commute a ((n : R) * b) :=
h.cast_nat_mul_right n

@[simp] theorem cast_nat_mul_left (h : commute a b) (n : ℕ) : commute ((n : R) * a) b :=
h.cast_nat_mul_left n

@[simp] theorem cast_nat_mul_cast_nat_mul (h : commute a b) (m n : ℕ) :
  commute ((m : R) * a) (n * b) :=
h.cast_nat_mul_cast_nat_mul m n

@[simp] theorem self_cast_nat_mul (n : ℕ) : commute a (n * a) :=
(commute.refl a).cast_nat_mul_right n

@[simp] theorem cast_nat_mul_self (n : ℕ) : commute ((n : R) * a) a :=
(commute.refl a).cast_nat_mul_left n

@[simp] theorem self_cast_nat_mul_cast_nat_mul (m n : ℕ) : commute ((m : R) * a) (n * a) :=
(commute.refl a).cast_nat_mul_cast_nat_mul m n

end

variables [monoid M] [group G] [ring R]

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

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

variables {a b : R}

@[simp] lemma cast_int_mul_right (h : commute a b) (m : ℤ) : commute a (m * b) :=
h.cast_int_mul_right m

@[simp] lemma cast_int_mul_left (h : commute a b) (m : ℤ) : commute ((m : R) * a) b :=
h.cast_int_mul_left m

lemma cast_int_mul_cast_int_mul (h : commute a b) (m n : ℤ) : commute ((m : R) * a) (n * b) :=
h.cast_int_mul_cast_int_mul m n

variables (a) (m n : ℤ)

@[simp] theorem self_cast_int_mul : commute a (n * a) := (commute.refl a).cast_int_mul_right n

@[simp] theorem cast_int_mul_self : commute ((n : R) * a) a := (commute.refl a).cast_int_mul_left n

theorem self_cast_int_mul_cast_int_mul : commute ((m : R) * a) (n * a) :=
(commute.refl a).cast_int_mul_cast_int_mul m n

end commute

section multiplicative

open multiplicative

@[simp] lemma nat.to_add_pow (a : multiplicative ℕ) (b : ℕ) : to_add (a ^ b) = to_add a * b :=
begin
  induction b with b ih,
  { erw [pow_zero, to_add_one, mul_zero] },
  { simp [*, pow_succ, add_comm, nat.mul_succ] }
end

@[simp] lemma nat.of_add_mul (a b : ℕ) : of_add (a * b) = of_add a ^ b :=
(nat.to_add_pow _ _).symm

@[simp] lemma int.to_add_pow (a : multiplicative ℤ) (b : ℕ) : to_add (a ^ b) = to_add a * b :=
by induction b; simp [*, mul_add, pow_succ, add_comm]

@[simp] lemma int.to_add_gpow (a : multiplicative ℤ) (b : ℤ) : to_add (a ^ b) = to_add a * b :=
int.induction_on b (by simp)
  (by simp [gpow_add, mul_add] {contextual := tt})
  (by simp [gpow_add, mul_add, sub_eq_add_neg, -int.add_neg_one] {contextual := tt})

@[simp] lemma int.of_add_mul (a b : ℤ) : of_add (a * b) = of_add a ^ b :=
(int.to_add_gpow _ _).symm

end multiplicative

namespace units

variables [monoid M]

lemma conj_pow (u : units M) (x : M) (n : ℕ) : (↑u * x * ↑(u⁻¹))^n = u * x^n * ↑(u⁻¹) :=
(divp_eq_iff_mul_eq.2 ((u.mk_semiconj_by x).pow_right n).eq.symm).symm

lemma conj_pow' (u : units M) (x : M) (n : ℕ) : (↑(u⁻¹) * x * u)^n = ↑(u⁻¹) * x^n * u:=
(u⁻¹).conj_pow x n

open opposite

/-- Moving to the opposite monoid commutes with taking powers. -/
@[simp] lemma op_pow (x : M) (n : ℕ) : op (x ^ n) = (op x) ^ n :=
begin
  induction n with n h,
  { simp },
  { rw [pow_succ', op_mul, h, pow_succ] }
end

@[simp] lemma unop_pow (x : Mᵒᵖ) (n : ℕ) : unop (x ^ n) = (unop x) ^ n :=
begin
  induction n with n h,
  { simp },
  { rw [pow_succ', unop_mul, h, pow_succ] }
end

end units