/-
Copyright (c) 2023 Anne Baanen. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Anne Baanen
-/

import ring_theory.dedekind_domain.dvr
import ring_theory.dedekind_domain.ideal

/-!
# Proving a Dedekind domain is a PID

This file contains some results that we can use to show all ideals in a Dedekind domain are
principal.

## Main results

 * `ideal.is_principal.of_finite_maximals_of_is_unit`: an invertible ideal in a commutative ring
   with finitely many maximal ideals, is a principal ideal.
 * `is_principal_ideal_ring.of_finite_primes`: if a Dedekind domain has finitely many prime ideals,
   it is a principal ideal domain.
-/

variables {R : Type*} [comm_ring R]

open ideal
open unique_factorization_monoid
open_locale big_operators
open_locale non_zero_divisors

open unique_factorization_monoid

/-- Let `P` be a prime ideal, `x ∈ P \ P²` and `x ∉ Q` for all prime ideals `Q ≠ P`.
Then `P` is generated by `x`. -/
lemma ideal.eq_span_singleton_of_mem_of_not_mem_sq_of_not_mem_prime_ne
  {P : ideal R} (hP : P.is_prime) [is_domain R] [is_dedekind_domain R]
  {x : R} (x_mem : x ∈ P) (hxP2 : x ∉ P^2)
  (hxQ : ∀ (Q : ideal R), is_prime Q → Q ≠ P → x ∉ Q) :
  P = ideal.span {x} :=
begin
  letI := classical.dec_eq (ideal R),
  have hx0 : x ≠ 0,
  { rintro rfl,
    exact hxP2 (zero_mem _) },
  by_cases hP0 : P = ⊥,
  { unfreezingI { subst hP0 },
    simpa using hxP2 },
  have hspan0 : span ({x} : set R) ≠ ⊥ := mt ideal.span_singleton_eq_bot.mp hx0,
  have span_le := (ideal.span_singleton_le_iff_mem _).mpr x_mem,
  refine associated_iff_eq.mp
    ((associated_iff_normalized_factors_eq_normalized_factors hP0 hspan0).mpr
      (le_antisymm ((dvd_iff_normalized_factors_le_normalized_factors hP0 hspan0).mp _) _)),
  { rwa [ideal.dvd_iff_le, ideal.span_singleton_le_iff_mem] },
  simp only [normalized_factors_irreducible ((ideal.prime_of_is_prime hP0 hP).irreducible),
      normalize_eq, multiset.le_iff_count, multiset.count_singleton],
  intros Q,
  split_ifs with hQ,
  { unfreezingI { subst hQ },
    refine (ideal.count_normalized_factors_eq _ _).le;
      simp only [ideal.span_singleton_le_iff_mem, pow_one];
      assumption },
  by_cases hQp : is_prime Q,
  { resetI,
    refine (ideal.count_normalized_factors_eq _ _).le;
      simp only [ideal.span_singleton_le_iff_mem, pow_one, pow_zero, one_eq_top, submodule.mem_top],
    exact hxQ _ hQp hQ },
  { exact (multiset.count_eq_zero.mpr (λ hQi, hQp (is_prime_of_prime (irreducible_iff_prime.mp
      (irreducible_of_normalized_factor _ hQi))))).le }
end

lemma fractional_ideal.is_principal_of_unit_of_comap_mul_span_singleton_eq_top
  {R A : Type*} [comm_ring R] [comm_ring A] [algebra R A] {S : submonoid R} [is_localization S A]
  (I : (fractional_ideal S A)ˣ) {v : A} (hv : v ∈ (↑I⁻¹ : fractional_ideal S A))
  (h : submodule.comap (algebra.linear_map R A) (I * submodule.span R {v}) = ⊤) :
  submodule.is_principal (I : submodule R A) :=
begin
  have hinv := I.mul_inv,
  set J := submodule.comap (algebra.linear_map R A) (I * submodule.span R {v}),
  have hJ : is_localization.coe_submodule A J = I * submodule.span R {v},
  { rw [subtype.ext_iff, fractional_ideal.coe_mul, fractional_ideal.coe_one] at hinv,
    apply submodule.map_comap_eq_self,
    rw [← submodule.one_eq_range, ← hinv],
    exact submodule.mul_le_mul_right ((submodule.span_singleton_le_iff_mem _ _).2 hv) },
  have : (1 : A) ∈ ↑I * submodule.span R {v},
  { rw [← hJ, h, is_localization.coe_submodule_top, submodule.mem_one],
    exact ⟨1, (algebra_map R _).map_one⟩ },
  obtain ⟨w, hw, hvw⟩ := submodule.mem_mul_span_singleton.1 this,
  refine ⟨⟨w, _⟩⟩,
  rw [← fractional_ideal.coe_span_singleton S, ← inv_inv I, eq_comm, coe_coe],
  refine congr_arg coe (units.eq_inv_of_mul_eq_one_left (le_antisymm _ _)),
  { apply_instance },
  { conv_rhs { rw [← hinv, mul_comm] },
    apply fractional_ideal.mul_le_mul_left (fractional_ideal.span_singleton_le_iff_mem.mpr hw) },
  { rw [fractional_ideal.one_le, ← hvw, mul_comm],
    exact fractional_ideal.mul_mem_mul hv (fractional_ideal.mem_span_singleton_self _ _) }
end

/--
An invertible fractional ideal of a commutative ring with finitely many maximal ideals is principal.

https://math.stackexchange.com/a/95857 -/
theorem fractional_ideal.is_principal.of_finite_maximals_of_inv
  {A : Type*} [comm_ring A] [algebra R A] {S : submonoid R} [is_localization S A]
  (hS : S ≤ R⁰) (hf : {I : ideal R | I.is_maximal}.finite)
  (I I' : fractional_ideal S A) (hinv : I * I' = 1) :
  submodule.is_principal (I : submodule R A) :=
begin
  have hinv' := hinv,
  rw [subtype.ext_iff, fractional_ideal.coe_mul] at hinv,
  let s := hf.to_finset,
  haveI := classical.dec_eq (ideal R),
  have coprime : ∀ (M ∈ s) (M' ∈ s.erase M), M ⊔ M' = ⊤,
  { simp_rw [finset.mem_erase, hf.mem_to_finset],
    rintro M hM M' ⟨hne, hM'⟩,
    exact ideal.is_maximal.coprime_of_ne hM hM' hne.symm },
  have nle : ∀ M ∈ s, ¬ (⨅ M' ∈ s.erase M, M') ≤ M := λ M hM, left_lt_sup.1
    ((hf.mem_to_finset.1 hM).ne_top.lt_top.trans_eq (ideal.sup_infi_eq_top $ coprime M hM).symm),
  have : ∀ M ∈ s, ∃ (a ∈ I) (b ∈ I'), a * b ∉ is_localization.coe_submodule A M,
  { intros M hM, by_contra' h,
    obtain ⟨x, hx, hxM⟩ := set_like.exists_of_lt ((is_localization.coe_submodule_strict_mono
      hS (hf.mem_to_finset.1 hM).ne_top.lt_top).trans_eq hinv.symm),
    refine hxM (submodule.map₂_le.2 _ hx), exact h },
  choose! a ha b hb hm using this,
  choose! u hu hum using λ M hM, set_like.not_le_iff_exists.1 (nle M hM),
  let v := ∑ M in s, u M • b M,
  have hv : v ∈ I' := submodule.sum_mem _ (λ M hM, submodule.smul_mem _ _ $ hb M hM),
  refine fractional_ideal.is_principal_of_unit_of_comap_mul_span_singleton_eq_top
    (units.mk_of_mul_eq_one I I' hinv') hv (of_not_not $ λ h, _),
  obtain ⟨M, hM, hJM⟩ := ideal.exists_le_maximal _ h,
  replace hM := hf.mem_to_finset.2 hM,
  have : ∀ (a ∈ I) (b ∈ I'), ∃ c, algebra_map R _ c = a * b,
  { intros a ha b hb, have hi := hinv.le,
    obtain ⟨c, -, hc⟩ := hi (submodule.mul_mem_mul ha hb),
    exact ⟨c, hc⟩ },
  have hmem: a M * v ∈ is_localization.coe_submodule A M,
  { obtain ⟨c, hc⟩ := this _ (ha M hM) v hv,
    refine is_localization.coe_submodule_mono _ hJM ⟨c, _, hc⟩,
    have := submodule.mul_mem_mul (ha M hM) (submodule.mem_span_singleton_self v),
    rwa ← hc at this },
  simp_rw [finset.mul_sum, mul_smul_comm] at hmem,
  rw [← s.add_sum_erase _ hM, submodule.add_mem_iff_left] at hmem,
  { refine hm M hM _,
    obtain ⟨c, (hc : algebra_map R A c = a M * b M)⟩ := this _ (ha M hM) _ (hb M hM),
    rw ← hc at hmem ⊢,
    rw [algebra.smul_def, ← _root_.map_mul] at hmem,
    obtain ⟨d, hdM, he⟩ := hmem,
    rw is_localization.injective _ hS he at hdM,
    exact submodule.mem_map_of_mem
      (((hf.mem_to_finset.1 hM).is_prime.mem_or_mem hdM).resolve_left $ hum M hM) },
  { refine submodule.sum_mem _ (λ M' hM', _),
    rw finset.mem_erase at hM',
    obtain ⟨c, hc⟩ := this _ (ha M hM) _ (hb M' hM'.2),
    rw [← hc, algebra.smul_def, ← _root_.map_mul],
    specialize hu M' hM'.2,
    simp_rw [ideal.mem_infi, finset.mem_erase] at hu,
    exact submodule.mem_map_of_mem (M.mul_mem_right _ $ hu M ⟨hM'.1.symm, hM⟩) },
end

/-- An invertible ideal in a commutative ring with finitely many maximal ideals is principal.

https://math.stackexchange.com/a/95857 -/
theorem ideal.is_principal.of_finite_maximals_of_is_unit
  (hf : {I : ideal R | I.is_maximal}.finite)
  {I : ideal R} (hI : is_unit (I : fractional_ideal R⁰ (fraction_ring R))) :
  I.is_principal :=
(is_localization.coe_submodule_is_principal _ le_rfl).mp
  (fractional_ideal.is_principal.of_finite_maximals_of_inv le_rfl hf I
    (↑(hI.unit⁻¹) : fractional_ideal R⁰ (fraction_ring R))
    hI.unit.mul_inv)

/-- A Dedekind domain is a PID if its set of primes is finite. -/
theorem is_principal_ideal_ring.of_finite_primes [is_domain R] [is_dedekind_domain R]
  (h : {I : ideal R | I.is_prime}.finite) :
  is_principal_ideal_ring R :=
⟨λ I, begin
  obtain rfl | hI := eq_or_ne I ⊥,
  { exact bot_is_principal },
  apply ideal.is_principal.of_finite_maximals_of_is_unit,
  { apply h.subset, exact @ideal.is_maximal.is_prime _ _ },
  { exact is_unit_of_mul_eq_one _ _ (fractional_ideal.coe_ideal_mul_inv I hI) },
end⟩

variables [is_domain R] [is_dedekind_domain R]
variables (S : Type*) [comm_ring S] [is_domain S]
variables [algebra R S] [module.free R S] [module.finite R S]
variables (p : ideal R) (hp0 : p ≠ ⊥) [is_prime p]
variables {Sₚ : Type*} [comm_ring Sₚ] [algebra S Sₚ]
variables [is_localization (algebra.algebra_map_submonoid S p.prime_compl) Sₚ]
variables [algebra R Sₚ] [is_scalar_tower R S Sₚ]
/- The first hypothesis below follows from properties of the localization but is needed for the
second, so we leave it to the user to provide (automatically). -/
variables [is_domain Sₚ] [is_dedekind_domain Sₚ]

include S hp0

/-- If `p` is a prime in the Dedekind domain `R`, `S` an extension of `R` and `Sₚ` the localization
of `S` at `p`, then all primes in `Sₚ` are factors of the image of `p` in `Sₚ`. -/
lemma is_localization.over_prime.mem_normalized_factors_of_is_prime [decidable_eq (ideal Sₚ)]
  {P : ideal Sₚ} (hP : is_prime P) (hP0 : P ≠ ⊥) :
  P ∈ normalized_factors (ideal.map (algebra_map R Sₚ) p) :=
begin
  have non_zero_div : algebra.algebra_map_submonoid S p.prime_compl ≤ S⁰ :=
    map_le_non_zero_divisors_of_injective _ (no_zero_smul_divisors.algebra_map_injective _ _)
      p.prime_compl_le_non_zero_divisors,
  letI : algebra (localization.at_prime p) Sₚ := localization_algebra p.prime_compl S,
  haveI : is_scalar_tower R (localization.at_prime p) Sₚ := is_scalar_tower.of_algebra_map_eq
    (λ x, by erw [is_localization.map_eq, is_scalar_tower.algebra_map_apply R S]),
  obtain ⟨pid, p', ⟨hp'0, hp'p⟩, hpu⟩ :=
    (discrete_valuation_ring.iff_pid_with_one_nonzero_prime (localization.at_prime p)).mp
      (is_localization.at_prime.discrete_valuation_ring_of_dedekind_domain R hp0 _),
  have : local_ring.maximal_ideal (localization.at_prime p) ≠ ⊥,
  { rw submodule.ne_bot_iff at ⊢ hp0,
    obtain ⟨x, x_mem, x_ne⟩ := hp0,
    exact ⟨algebra_map _ _ x,
      (is_localization.at_prime.to_map_mem_maximal_iff _ _ _).mpr x_mem,
      is_localization.to_map_ne_zero_of_mem_non_zero_divisors _ p.prime_compl_le_non_zero_divisors
        (mem_non_zero_divisors_of_ne_zero x_ne)⟩ },
  rw [← multiset.singleton_le, ← normalize_eq P,
      ← normalized_factors_irreducible (ideal.prime_of_is_prime hP0 hP).irreducible,
      ← dvd_iff_normalized_factors_le_normalized_factors hP0, dvd_iff_le,
      is_scalar_tower.algebra_map_eq R (localization.at_prime p) Sₚ, ← ideal.map_map,
      localization.at_prime.map_eq_maximal_ideal, ideal.map_le_iff_le_comap,
      hpu (local_ring.maximal_ideal _) ⟨this, _⟩, hpu (comap _ _) ⟨_, _⟩],
  { exact le_rfl },
  { have hRS : algebra.is_integral R S := is_integral_of_noetherian
      (is_noetherian_of_fg_of_noetherian' module.finite.out),
    exact mt (ideal.eq_bot_of_comap_eq_bot (is_integral_localization hRS)) hP0 },
  { exact ideal.comap_is_prime (algebra_map (localization.at_prime p) Sₚ) P },
  { exact (local_ring.maximal_ideal.is_maximal _).is_prime },
  { rw [ne.def, zero_eq_bot, ideal.map_eq_bot_iff_of_injective],
    { assumption },
    rw is_scalar_tower.algebra_map_eq R S Sₚ,
    exact (is_localization.injective Sₚ non_zero_div).comp
      (no_zero_smul_divisors.algebra_map_injective _ _) },
end

/-- Let `p` be a prime in the Dedekind domain `R` and `S` be an integral extension of `R`,
then the localization `Sₚ` of `S` at `p` is a PID. -/
theorem is_dedekind_domain.is_principal_ideal_ring_localization_over_prime :
  is_principal_ideal_ring Sₚ :=
begin
  letI := classical.dec_eq (ideal Sₚ),
  letI := classical.dec_pred (λ (P : ideal Sₚ), P.is_prime),
  refine is_principal_ideal_ring.of_finite_primes
    (set.finite.of_finset (finset.filter (λ P, P.is_prime)
      ({⊥} ∪ (normalized_factors (ideal.map (algebra_map R Sₚ) p)).to_finset))
      (λ P, _)),
  rw [finset.mem_filter, finset.mem_union, finset.mem_singleton, set.mem_set_of,
      multiset.mem_to_finset],
  exact and_iff_right_of_imp (λ hP, or_iff_not_imp_left.mpr
    (is_localization.over_prime.mem_normalized_factors_of_is_prime S p hp0 hP))
end


/-
Copyright (c) 2020 Paul van Wamelen. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul van Wamelen
-/
import number_theory.pythagorean_triples
import ring_theory.coprime

/-!
# Fermat's Last Theorem for the case n = 4
There are no non-zero integers `a`, `b` and `c` such that `a ^ 4 + b ^ 4 = c ^ 4`.
-/

noncomputable theory
open_locale classical

/-- Shorthand for three non-zero integers `a`, `b`, and `c` satisfying `a ^ 4 + b ^ 4 = c ^ 2`.
We will show that no integers satisfy this equation. Clearly Fermat's Last theorem for n = 4
follows. -/
def fermat_42 (a b c : ℤ) : Prop := a ≠ 0 ∧ b ≠ 0 ∧ a ^ 4 + b ^ 4 = c ^ 2

namespace fermat_42

lemma comm {a b c : ℤ} :
 (fermat_42 a b c) ↔ (fermat_42 b a c) :=
 by { delta fermat_42, rw add_comm, tauto }

lemma mul {a b c k : ℤ} (hk0 : k ≠ 0) :
  fermat_42 a b c ↔ fermat_42 (k * a) (k * b) (k ^ 2 * c) :=
begin
  delta fermat_42,
  split,
  { intro f42,
    split, { exact mul_ne_zero hk0 f42.1 },
    split, { exact mul_ne_zero hk0 f42.2.1 },
    { calc (k * a) ^ 4 + (k * b) ^ 4
          = k ^ 4 * (a ^ 4 + b ^ 4) : by ring
      ... = k ^ 4 * c ^ 2 : by rw f42.2.2
      ... = (k ^ 2 * c) ^ 2 : by ring }},
  { intro f42,
    split, { exact right_ne_zero_of_mul f42.1 },
    split, { exact right_ne_zero_of_mul f42.2.1 },
    apply (mul_right_inj' (pow_ne_zero 4 hk0)).mp,
    { calc k ^ 4 * (a ^ 4 + b ^ 4)
          = (k * a) ^ 4 + (k * b) ^ 4 : by ring
      ... = (k ^ 2 * c) ^ 2 : by rw f42.2.2
      ... = k ^ 4 * c ^ 2 : by ring }}
end

lemma ne_zero {a b c : ℤ} (h : fermat_42 a b c) : c ≠ 0 :=
begin
  apply ne_zero_pow (dec_trivial : 2 ≠ 0), apply ne_of_gt,
  rw [← h.2.2, (by ring : a ^ 4 + b ^ 4 = (a ^ 2) ^ 2 + (b ^ 2) ^ 2)],
  exact add_pos (sq_pos_of_ne_zero _ (pow_ne_zero 2 h.1))
      (sq_pos_of_ne_zero _ (pow_ne_zero 2 h.2.1))
end

/-- We say a solution to `a ^ 4 + b ^ 4 = c ^ 2` is minimal if there is no other solution with
a smaller `c` (in absolute value). -/
def minimal (a b c : ℤ) : Prop :=
  (fermat_42 a b c) ∧ ∀ (a1 b1 c1 : ℤ), (fermat_42 a1 b1 c1) → int.nat_abs c ≤ int.nat_abs c1

/-- if we have a solution to `a ^ 4 + b ^ 4 = c ^ 2` then there must be a minimal one. -/
lemma exists_minimal {a b c : ℤ} (h : fermat_42 a b c) :
  ∃ (a0 b0 c0), (minimal a0 b0 c0) :=
begin
  let S : set ℕ := { n | ∃ (s : ℤ × ℤ × ℤ), fermat_42 s.1 s.2.1 s.2.2 ∧ n = int.nat_abs s.2.2},
  have S_nonempty : S.nonempty,
  { use int.nat_abs c,
    rw set.mem_set_of_eq,
    use ⟨a, ⟨b, c⟩⟩, tauto },
  let m : ℕ := nat.find S_nonempty,
  have m_mem : m ∈ S := nat.find_spec S_nonempty,
  rcases m_mem with ⟨s0, hs0, hs1⟩,
  use [s0.1, s0.2.1, s0.2.2, hs0],
  intros a1 b1 c1 h1,
  rw ← hs1,
  apply nat.find_min',
  use ⟨a1, ⟨b1, c1⟩⟩, tauto
end

/-- a minimal solution to `a ^ 4 + b ^ 4 = c ^ 2` must have `a` and `b` coprime. -/
lemma coprime_of_minimal {a b c : ℤ} (h : minimal a b c) : is_coprime a b :=
begin
  apply int.gcd_eq_one_iff_coprime.mp,
  by_contradiction hab,
  obtain ⟨p, hp, hpa, hpb⟩ := nat.prime.not_coprime_iff_dvd.mp hab,
  obtain ⟨a1, rfl⟩ := (int.coe_nat_dvd_left.mpr hpa),
  obtain ⟨b1, rfl⟩ := (int.coe_nat_dvd_left.mpr hpb),
  have hpc : (p : ℤ) ^ 2 ∣ c,
  { apply (int.pow_dvd_pow_iff (dec_trivial : 0 < 2)).mp,
    rw ← h.1.2.2,
    apply dvd.intro (a1 ^ 4 + b1 ^ 4), ring },
  obtain ⟨c1, rfl⟩ := hpc,
  have hf : fermat_42 a1 b1 c1,
    exact (fermat_42.mul (int.coe_nat_ne_zero.mpr (nat.prime.ne_zero hp))).mpr h.1,
  apply nat.le_lt_antisymm (h.2 _ _ _ hf),
  rw [int.nat_abs_mul, lt_mul_iff_one_lt_left, int.nat_abs_pow, int.nat_abs_of_nat],
  { exact nat.one_lt_pow _ _ (show 0 < 2, from dec_trivial) (nat.prime.one_lt hp) },
  { exact (nat.pos_of_ne_zero (int.nat_abs_ne_zero_of_ne_zero (ne_zero hf))) },
end

/-- We can swap `a` and `b` in a minimal solution to `a ^ 4 + b ^ 4 = c ^ 2`. -/

/-- We can assume that a minimal solution to `a ^ 4 + b ^ 4 = c ^ 2` has positive `c`. -/
lemma neg_of_minimal {a b c : ℤ} :
 (minimal a b c) → (minimal a b (-c)) :=
begin
  rintros ⟨⟨ha, hb, heq⟩, h2⟩,
  split,
  { apply and.intro ha (and.intro hb _),
    rw heq, exact (neg_sq c).symm },
  rwa (int.nat_abs_neg c),
end

/-- We can assume that a minimal solution to `a ^ 4 + b ^ 4 = c ^ 2` has `a` odd. -/
lemma exists_odd_minimal {a b c : ℤ} (h : fermat_42 a b c) :
  ∃ (a0 b0 c0), (minimal a0 b0 c0) ∧ a0 % 2 = 1 :=
begin
  obtain ⟨a0, b0, c0, hf⟩ := exists_minimal h,
  cases int.mod_two_eq_zero_or_one a0 with hap hap,
  { cases int.mod_two_eq_zero_or_one b0 with hbp hbp,
    { exfalso,
      have h1 : 2 ∣ (int.gcd a0 b0 : ℤ),
      { exact int.dvd_gcd (int.dvd_of_mod_eq_zero hap) (int.dvd_of_mod_eq_zero hbp) },
        rw int.gcd_eq_one_iff_coprime.mpr (coprime_of_minimal hf) at h1, revert h1, norm_num },
      { exact ⟨b0, ⟨a0, ⟨c0, minimal_comm hf, hbp⟩⟩⟩ }},
  exact ⟨a0, ⟨b0, ⟨c0 , hf, hap⟩⟩⟩,
end

/-- We can assume that a minimal solution to `a ^ 4 + b ^ 4 = c ^ 2` has
`a` odd and `c` positive. -/
lemma exists_pos_odd_minimal {a b c : ℤ} (h : fermat_42 a b c) :
  ∃ (a0 b0 c0), (minimal a0 b0 c0) ∧ a0 % 2 = 1 ∧ 0 < c0  :=
begin
  obtain ⟨a0, b0, c0, hf, hc⟩ := exists_odd_minimal h,
  rcases lt_trichotomy 0 c0 with (h1 | rfl | h1),
  { use [a0, b0, c0], tauto },
  { exfalso, exact ne_zero hf.1 rfl},
  { use [a0, b0, -c0, neg_of_minimal hf, hc],
    exact neg_pos.mpr h1 },
end

end fermat_42

lemma int.coprime_of_sq_sum {r s : ℤ} (h2 : is_coprime s r) :
  is_coprime (r ^ 2 + s ^ 2) r :=
begin
  rw [sq, sq],
  exact (is_coprime.mul_left h2 h2).mul_add_left_left r
end

lemma int.coprime_of_sq_sum' {r s : ℤ} (h : is_coprime r s) :
  is_coprime (r ^ 2 + s ^ 2) (r * s) :=
begin
  apply is_coprime.mul_right (int.coprime_of_sq_sum (is_coprime_comm.mp h)),
  rw add_comm, apply int.coprime_of_sq_sum h
end

namespace fermat_42

-- If we have a solution to a ^ 4 + b ^ 4 = c ^ 2, we can construct a smaller one. This
-- implies there can't be a smallest solution.
lemma not_minimal {a b c : ℤ}
  (h : minimal a b c) (ha2 : a % 2 = 1) (hc : 0 < c) : false :=
begin
  -- Use the fact that a ^ 2, b ^ 2, c form a pythagorean triple to obtain m and n such that
  -- a ^ 2 = m ^ 2 - n ^ 2, b ^ 2 = 2 * m * n and c = m ^ 2 + n ^ 2
  -- first the formula:
  have ht : pythagorean_triple (a ^ 2) (b ^ 2) c,
  { calc ((a ^ 2) * (a ^ 2)) + ((b ^ 2) * (b ^ 2))
        = a ^ 4 + b ^ 4 : by ring
    ... = c ^ 2 : by rw h.1.2.2
    ... = c * c : by rw sq },
  -- coprime requirement:
  have h2 : int.gcd (a ^ 2) (b ^ 2) = 1 :=
    int.gcd_eq_one_iff_coprime.mpr (coprime_of_minimal h).pow,
  -- in order to reduce the possibilities we get from the classification of pythagorean triples
  -- it helps if we know the parity of a ^ 2 (and the sign of c):
  have ha22 : a ^ 2 % 2 = 1, { rw [sq, int.mul_mod, ha2], norm_num },
  obtain ⟨m, n, ht1, ht2, ht3, ht4, ht5, ht6⟩ :=
    pythagorean_triple.coprime_classification' ht h2 ha22 hc,
  -- Now a, n, m form a pythagorean triple and so we can obtain r and s such that
  -- a = r ^ 2 - s ^ 2, n = 2 * r * s and m = r ^ 2 + s ^ 2
  -- formula:
  have htt : pythagorean_triple a n m,
  { delta pythagorean_triple,
    rw [← sq, ← sq, ← sq], exact (add_eq_of_eq_sub ht1) },
  -- a and n are coprime, because a ^ 2 = m ^ 2 - n ^ 2 and m and n are coprime.
  have h3 : int.gcd a n = 1,
  { apply int.gcd_eq_one_iff_coprime.mpr,
    apply @is_coprime.of_mul_left_left _ _ _ a,
    rw [← sq, ht1, (by ring : m ^ 2 - n ^ 2 = m ^ 2 + (-n) * n)],
    exact (int.gcd_eq_one_iff_coprime.mp ht4).pow_left.add_mul_right_left (-n) },
  -- m is positive because b is non-zero and b ^ 2 = 2 * m * n and we already have 0 ≤ m.
  have hb20 : b ^ 2 ≠ 0 := mt pow_eq_zero h.1.2.1,
  have h4 : 0 < m,
  { apply lt_of_le_of_ne ht6,
    rintro rfl,
    revert hb20,
    rw ht2, simp },
  obtain ⟨r, s, htt1, htt2, htt3, htt4, htt5, htt6⟩ :=
    pythagorean_triple.coprime_classification' htt h3 ha2 h4,
  -- Now use the fact that (b / 2) ^ 2 = m * r * s, and m, r and s are pairwise coprime to obtain
  -- i, j and k such that m = i ^ 2, r = j ^ 2 and s = k ^ 2.
  -- m and r * s are coprime because m = r ^ 2 + s ^ 2 and r and s are coprime.
  have hcp : int.gcd m (r * s) = 1,
  { rw htt3,
    exact int.gcd_eq_one_iff_coprime.mpr (int.coprime_of_sq_sum'
      (int.gcd_eq_one_iff_coprime.mp htt4)) },
  -- b is even because b ^ 2 = 2 * m * n.
  have hb2 : 2 ∣ b,
  { apply @int.prime.dvd_pow' _ 2 _ (by norm_num : nat.prime 2),
    rw [ht2, mul_assoc], exact dvd_mul_right 2 (m * n) },
  cases hb2 with b' hb2',
  have hs : b' ^ 2 = m * (r * s),
  { apply (mul_right_inj' (by norm_num : (4 : ℤ) ≠ 0)).mp,
    calc 4 * b' ^ 2 = (2 * b') * (2 * b') : by ring
                    ... = 2 * m * (2 * r * s) : by rw [← hb2', ← sq, ht2, htt2]
                    ... = 4 * (m * (r * s)) : by ring },
  have hrsz : r * s ≠ 0, -- because b ^ 2 is not zero and (b / 2) ^ 2 = m * (r * s)
  { by_contradiction hrsz,
    revert hb20, rw [ht2, htt2, mul_assoc, @mul_assoc _ _ _ r s, (not_not.mp hrsz)],
    simp },
  have h2b0 : b' ≠ 0,
  { apply ne_zero_pow (dec_trivial : 2 ≠ 0),
    rw hs, apply mul_ne_zero, { exact ne_of_gt h4}, { exact hrsz } },
  obtain ⟨i, hi⟩ := int.sq_of_gcd_eq_one hcp hs.symm,
  -- use m is positive to exclude m = - i ^ 2
  have hi' : ¬ m = - i ^ 2,
  { by_contradiction h1,
    have hit : - i ^ 2 ≤ 0, apply neg_nonpos.mpr (sq_nonneg i),
    rw ← h1 at hit,
    apply absurd h4 (not_lt.mpr hit) },
  replace hi : m = i ^ 2, { apply or.resolve_right hi hi' },
  rw mul_comm at hs,
  rw [int.gcd_comm] at hcp,
  -- obtain d such that r * s = d ^ 2
  obtain ⟨d, hd⟩ := int.sq_of_gcd_eq_one hcp hs.symm,
  -- (b / 2) ^ 2 and m are positive so r * s is positive
  have hd' : ¬ r * s = - d ^ 2,
  { by_contradiction h1,
    rw h1 at hs,
    have h2 : b' ^ 2 ≤ 0,
    { rw [hs, (by ring : - d ^ 2 * m = - (d ^ 2 * m))], apply neg_nonpos.mpr,
      apply (zero_le_mul_right h4).mpr (sq_nonneg d) },
    have h2' : 0 ≤ b' ^ 2, { apply sq_nonneg b' },
    exact absurd (lt_of_le_of_ne h2' (ne.symm (pow_ne_zero _ h2b0))) (not_lt.mpr h2) },
  replace hd : r * s = d ^ 2, { apply or.resolve_right hd hd' },
  -- r = +/- j ^ 2
  obtain ⟨j, hj⟩ := int.sq_of_gcd_eq_one htt4 hd,
  have hj0 : j ≠ 0,
  { intro h0, rw [h0, zero_pow (dec_trivial : 0 < 2), neg_zero, or_self] at hj,
    apply left_ne_zero_of_mul hrsz hj },
  rw mul_comm at hd,
  rw [int.gcd_comm] at htt4,
  -- s = +/- k ^ 2
  obtain ⟨k, hk⟩ := int.sq_of_gcd_eq_one htt4 hd,
  have hk0 : k ≠ 0,
  { intro h0, rw [h0, zero_pow (dec_trivial : 0 < 2), neg_zero, or_self] at hk,
    apply right_ne_zero_of_mul hrsz hk },
  have hj2 : r ^ 2 = j ^ 4, { cases hj with hjp hjp; { rw hjp, ring } },
  have hk2 : s ^ 2 = k ^ 4, { cases hk with hkp hkp; { rw hkp, ring } },
  -- from m = r ^ 2 + s ^ 2 we now get a new solution to a ^ 4 + b ^ 4 = c ^ 2:
  have hh : i ^ 2 = j ^ 4 + k ^ 4, { rw [← hi, htt3, hj2, hk2] },
  have hn : n ≠ 0, { rw ht2 at hb20, apply right_ne_zero_of_mul hb20 },
  -- and it has a smaller c: from c = m ^ 2 + n ^ 2 we see that m is smaller than c, and i ^ 2 = m.
  have hic : int.nat_abs i < int.nat_abs c,
  { apply int.coe_nat_lt.mp, rw ← (int.eq_nat_abs_of_zero_le (le_of_lt hc)),
    apply gt_of_gt_of_ge _ (int.abs_le_self_sq i),
    rw [← hi, ht3],
    apply gt_of_gt_of_ge _ (int.le_self_sq m),
    exact lt_add_of_pos_right (m ^ 2) (sq_pos_of_ne_zero n hn) },
  have hic' : int.nat_abs c ≤ int.nat_abs i,
  { apply (h.2 j k i),
    exact ⟨hj0, hk0, hh.symm⟩ },
  apply absurd (not_le_of_lt hic) (not_not.mpr hic')
end

end fermat_42

lemma not_fermat_42 {a b c : ℤ} (ha : a ≠ 0) (hb : b ≠ 0) :
  a ^ 4 + b ^ 4 ≠ c ^ 2 :=
begin
  intro h,
  obtain ⟨a0, b0, c0, ⟨hf, h2, hp⟩⟩ :=
    fermat_42.exists_pos_odd_minimal (and.intro ha (and.intro hb h)),
  apply fermat_42.not_minimal hf h2 hp
end

theorem not_fermat_4 {a b c : ℤ} (ha : a ≠ 0) (hb : b ≠ 0) :
  a ^ 4 + b ^ 4 ≠ c ^ 4 :=
begin
  intro heq,
  apply @not_fermat_42 _ _ (c ^ 2) ha hb,
  rw heq, ring
end


/-
Copyright (c) 2021 Frédéric Dupuis. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Frédéric Dupuis
-/

import analysis.normed.group.hom
import analysis.normed_space.basic
import analysis.normed_space.linear_isometry
import algebra.star.self_adjoint
import algebra.star.unitary
import topology.algebra.star_subalgebra

/-!
# Normed star rings and algebras

A normed star group is a normed group with a compatible `star` which is isometric.

A C⋆-ring is a normed star group that is also a ring and that verifies the stronger
condition `‖x⋆ * x‖ = ‖x‖^2` for all `x`.  If a C⋆-ring is also a star algebra, then it is a
C⋆-algebra.

To get a C⋆-algebra `E` over field `𝕜`, use
`[normed_field 𝕜] [star_ring 𝕜] [normed_ring E] [star_ring E] [cstar_ring E]
 [normed_algebra 𝕜 E] [star_module 𝕜 E]`.

## TODO

- Show that `‖x⋆ * x‖ = ‖x‖^2` is equivalent to `‖x⋆ * x‖ = ‖x⋆‖ * ‖x‖`, which is used as the
  definition of C*-algebras in some sources (e.g. Wikipedia).

-/

open_locale topology

local postfix `⋆`:std.prec.max_plus := star

/-- A normed star group is a normed group with a compatible `star` which is isometric. -/
class normed_star_group (E : Type*) [seminormed_add_comm_group E] [star_add_monoid E] : Prop :=
(norm_star : ∀ x : E, ‖x⋆‖ = ‖x‖)

export normed_star_group (norm_star)
attribute [simp] norm_star

variables {𝕜 E α : Type*}

section normed_star_group
variables [seminormed_add_comm_group E] [star_add_monoid E] [normed_star_group E]

@[simp] lemma nnnorm_star (x : E) : ‖star x‖₊ = ‖x‖₊ := subtype.ext $ norm_star _

/-- The `star` map in a normed star group is a normed group homomorphism. -/
def star_normed_add_group_hom : normed_add_group_hom E E :=
{ bound' := ⟨1, λ v, le_trans (norm_star _).le (one_mul _).symm.le⟩,
  .. star_add_equiv }

/-- The `star` map in a normed star group is an isometry -/
lemma star_isometry : isometry (star : E → E) :=
show isometry star_add_equiv,
by exact add_monoid_hom_class.isometry_of_norm star_add_equiv
    (show ∀ x, ‖x⋆‖ = ‖x‖, from norm_star)

@[priority 100]
instance normed_star_group.to_has_continuous_star : has_continuous_star E :=
⟨star_isometry.continuous⟩

end normed_star_group

instance ring_hom_isometric.star_ring_end [normed_comm_ring E] [star_ring E]
  [normed_star_group E] : ring_hom_isometric (star_ring_end E) :=
⟨norm_star⟩

/-- A C*-ring is a normed star ring that satifies the stronger condition `‖x⋆ * x‖ = ‖x‖^2`
for every `x`. -/
class cstar_ring (E : Type*) [non_unital_normed_ring E] [star_ring E] : Prop :=
(norm_star_mul_self : ∀ {x : E}, ‖x⋆ * x‖ = ‖x‖ * ‖x‖)

instance : cstar_ring ℝ :=
{ norm_star_mul_self := λ x, by simp only [star, id.def, norm_mul] }

namespace cstar_ring
section non_unital

variables [non_unital_normed_ring E] [star_ring E] [cstar_ring E]

/-- In a C*-ring, star preserves the norm. -/
@[priority 100] -- see Note [lower instance priority]
instance to_normed_star_group : normed_star_group E :=
⟨begin
  intro x,
  by_cases htriv : x = 0,
  { simp only [htriv, star_zero] },
  { have hnt : 0 < ‖x‖ := norm_pos_iff.mpr htriv,
    have hnt_star : 0 < ‖x⋆‖ :=
      norm_pos_iff.mpr ((add_equiv.map_ne_zero_iff star_add_equiv).mpr htriv),
    have h₁ := calc
      ‖x‖ * ‖x‖ = ‖x⋆ * x‖        : norm_star_mul_self.symm
            ... ≤ ‖x⋆‖ * ‖x‖      : norm_mul_le _ _,
    have h₂ := calc
      ‖x⋆‖ * ‖x⋆‖ = ‖x * x⋆‖      : by rw [←norm_star_mul_self, star_star]
             ... ≤ ‖x‖ * ‖x⋆‖     : norm_mul_le _ _,
    exact le_antisymm (le_of_mul_le_mul_right h₂ hnt_star) (le_of_mul_le_mul_right h₁ hnt) },
end⟩

lemma norm_self_mul_star {x : E} : ‖x * x⋆‖ = ‖x‖ * ‖x‖ :=
by { nth_rewrite 0 [←star_star x], simp only [norm_star_mul_self, norm_star] }

lemma norm_star_mul_self' {x : E} : ‖x⋆ * x‖ = ‖x⋆‖ * ‖x‖ :=
by rw [norm_star_mul_self, norm_star]

lemma nnnorm_self_mul_star {x : E} : ‖x * star x‖₊ = ‖x‖₊ * ‖x‖₊ :=
subtype.ext norm_self_mul_star

lemma nnnorm_star_mul_self {x : E} : ‖x⋆ * x‖₊ = ‖x‖₊ * ‖x‖₊ :=
subtype.ext norm_star_mul_self

@[simp]
lemma star_mul_self_eq_zero_iff (x : E) : star x * x = 0 ↔ x = 0 :=
by { rw [←norm_eq_zero, norm_star_mul_self], exact mul_self_eq_zero.trans norm_eq_zero }

lemma star_mul_self_ne_zero_iff (x : E) : star x * x ≠ 0 ↔ x ≠ 0 :=
by simp only [ne.def, star_mul_self_eq_zero_iff]

@[simp]
lemma mul_star_self_eq_zero_iff (x : E) : x * star x = 0 ↔ x = 0 :=
by simpa only [star_eq_zero, star_star] using @star_mul_self_eq_zero_iff _ _ _ _ (star x)

lemma mul_star_self_ne_zero_iff (x : E) : x * star x ≠ 0 ↔ x ≠ 0 :=
by simp only [ne.def, mul_star_self_eq_zero_iff]

end non_unital

section prod_pi

variables {ι R₁ R₂ : Type*} {R : ι → Type*}
variables [non_unital_normed_ring R₁] [star_ring R₁] [cstar_ring R₁]
variables [non_unital_normed_ring R₂] [star_ring R₂] [cstar_ring R₂]
variables [Π i, non_unital_normed_ring (R i)] [Π i, star_ring (R i)]

/-- This instance exists to short circuit type class resolution because of problems with
inference involving Π-types. -/
instance _root_.pi.star_ring' : star_ring (Π i, R i) := infer_instance

variables [fintype ι] [Π i, cstar_ring (R i)]

instance _root_.prod.cstar_ring : cstar_ring (R₁ × R₂) :=
{ norm_star_mul_self := λ x,
  begin
    unfold norm,
    simp only [prod.fst_mul, prod.fst_star, prod.snd_mul, prod.snd_star, norm_star_mul_self, ←sq],
    refine le_antisymm _ _,
    { refine max_le _ _;
      rw [sq_le_sq, abs_of_nonneg (norm_nonneg _)],
      exact (le_max_left _ _).trans (le_abs_self _),
      exact (le_max_right _ _).trans (le_abs_self _) },
    { rw le_sup_iff,
      rcases le_total (‖x.fst‖) (‖x.snd‖) with (h | h);
      simp [h] }
  end }

instance _root_.pi.cstar_ring : cstar_ring (Π i, R i) :=
{ norm_star_mul_self := λ x,
  begin
    simp only [norm, pi.mul_apply, pi.star_apply, nnnorm_star_mul_self, ←sq],
    norm_cast,
    exact (finset.comp_sup_eq_sup_comp_of_is_total (λ x : nnreal, x ^ 2)
      (λ x y h, by simpa only [sq] using mul_le_mul' h h) (by simp)).symm,
  end }

instance _root_.pi.cstar_ring' : cstar_ring (ι → R₁) := pi.cstar_ring

end prod_pi

section unital
variables [normed_ring E] [star_ring E] [cstar_ring E]

@[simp] lemma norm_one [nontrivial E] : ‖(1 : E)‖ = 1 :=
begin
  have : 0 < ‖(1 : E)‖ := norm_pos_iff.mpr one_ne_zero,
  rw [←mul_left_inj' this.ne', ←norm_star_mul_self, mul_one, star_one, one_mul],
end

@[priority 100] -- see Note [lower instance priority]
instance [nontrivial E] : norm_one_class E := ⟨norm_one⟩

lemma norm_coe_unitary [nontrivial E] (U : unitary E) : ‖(U : E)‖ = 1 :=
begin
  rw [←sq_eq_sq (norm_nonneg _) zero_le_one, one_pow 2, sq, ←cstar_ring.norm_star_mul_self,
    unitary.coe_star_mul_self, cstar_ring.norm_one],
end

@[simp] lemma norm_of_mem_unitary [nontrivial E] {U : E} (hU : U ∈ unitary E) : ‖U‖ = 1 :=
norm_coe_unitary ⟨U, hU⟩

@[simp] lemma norm_coe_unitary_mul (U : unitary E) (A : E) : ‖(U : E) * A‖ = ‖A‖ :=
begin
  nontriviality E,
  refine le_antisymm _ _,
  { calc _  ≤ ‖(U : E)‖ * ‖A‖     : norm_mul_le _ _
        ... = ‖A‖                 : by rw [norm_coe_unitary, one_mul] },
  { calc _ = ‖(U : E)⋆ * U * A‖         : by rw [unitary.coe_star_mul_self U, one_mul]
       ... ≤ ‖(U : E)⋆‖ * ‖(U : E) * A‖ : by { rw [mul_assoc], exact norm_mul_le _ _ }
       ... = ‖(U : E) * A‖              : by rw [norm_star, norm_coe_unitary, one_mul] },
end

@[simp] lemma norm_unitary_smul (U : unitary E) (A : E) : ‖U • A‖ = ‖A‖ :=
norm_coe_unitary_mul U A

lemma norm_mem_unitary_mul {U : E} (A : E) (hU : U ∈ unitary E) : ‖U * A‖ = ‖A‖ :=
norm_coe_unitary_mul ⟨U, hU⟩ A

@[simp] lemma norm_mul_coe_unitary (A : E) (U : unitary E) : ‖A * U‖ = ‖A‖ :=
calc _ = ‖((U : E)⋆ * A⋆)⋆‖ : by simp only [star_star, star_mul]
  ...  = ‖(U : E)⋆ * A⋆‖    : by rw [norm_star]
  ...  = ‖A⋆‖               : norm_mem_unitary_mul (star A) (unitary.star_mem U.prop)
  ...  = ‖A‖                : norm_star _

lemma norm_mul_mem_unitary (A : E) {U : E} (hU : U ∈ unitary E) : ‖A * U‖ = ‖A‖ :=
norm_mul_coe_unitary A ⟨U, hU⟩

end unital
end cstar_ring

lemma is_self_adjoint.nnnorm_pow_two_pow [normed_ring E] [star_ring E]
  [cstar_ring E] {x : E} (hx : is_self_adjoint x) (n : ℕ) : ‖x ^ 2 ^ n‖₊ = ‖x‖₊ ^ (2 ^ n) :=
begin
  induction n with k hk,
  { simp only [pow_zero, pow_one] },
  { rw [pow_succ, pow_mul', sq],
    nth_rewrite 0 ←(self_adjoint.mem_iff.mp hx),
    rw [←star_pow, cstar_ring.nnnorm_star_mul_self, ←sq, hk, pow_mul'] },
end

lemma self_adjoint.nnnorm_pow_two_pow [normed_ring E] [star_ring E] [cstar_ring E]
  (x : self_adjoint E) (n : ℕ) : ‖x ^ 2 ^ n‖₊ = ‖x‖₊ ^ (2 ^ n) :=
x.prop.nnnorm_pow_two_pow _

section starₗᵢ

variables [comm_semiring 𝕜] [star_ring 𝕜]
variables [seminormed_add_comm_group E] [star_add_monoid E] [normed_star_group E]
variables [module 𝕜 E] [star_module 𝕜 E]

variables (𝕜)
/-- `star` bundled as a linear isometric equivalence -/
def starₗᵢ : E ≃ₗᵢ⋆[𝕜] E :=
{ map_smul' := star_smul,
  norm_map' := norm_star,
  .. star_add_equiv }

variables {𝕜}

@[simp] lemma coe_starₗᵢ : (starₗᵢ 𝕜 : E → E) = star := rfl

lemma starₗᵢ_apply {x : E} : starₗᵢ 𝕜 x = star x := rfl

end starₗᵢ

namespace star_subalgebra

instance to_normed_algebra {𝕜 A : Type*} [normed_field 𝕜] [star_ring 𝕜]
  [semi_normed_ring A] [star_ring A] [normed_algebra 𝕜 A] [star_module 𝕜 A]
  (S : star_subalgebra 𝕜 A) : normed_algebra 𝕜 S :=
@normed_algebra.induced _ 𝕜 S A _ (subring_class.to_ring S) S.algebra _ _ _ S.subtype

instance to_cstar_ring {R A} [comm_ring R] [star_ring R] [normed_ring A]
  [star_ring A] [cstar_ring A] [algebra R A] [star_module R A] (S : star_subalgebra R A) :
  cstar_ring S :=
{ norm_star_mul_self := λ x, @cstar_ring.norm_star_mul_self A _ _ _ x }

end star_subalgebra


/-
Copyright (c) 2018 Kenny Lau. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kenny Lau
-/
import data.nat.sqrt

/-!
# Square root of integers

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

This file defines the square root function on integers. `int.sqrt z` is the greatest integer `r`
such that `r * r ≤ z`. If `z ≤ 0`, then `int.sqrt z = 0`.
-/

namespace int

/-- `sqrt z` is the square root of an integer `z`. If `z` is positive, it returns the largest
integer `r` such that `r * r ≤ n`. If it is negative, it returns `0`. For example, `sqrt (-1) = 0`,
`sqrt 1 = 1`, `sqrt 2 = 1` -/
@[pp_nodot] def sqrt (z : ℤ) : ℤ :=
nat.sqrt $ int.to_nat z

theorem sqrt_eq (n : ℤ) : sqrt (n*n) = n.nat_abs :=
by rw [sqrt, ← nat_abs_mul_self, to_nat_coe_nat, nat.sqrt_eq]

theorem exists_mul_self (x : ℤ) :
  (∃ n, n * n = x) ↔ sqrt x * sqrt x = x :=
⟨λ ⟨n, hn⟩, by rw [← hn, sqrt_eq, ← int.coe_nat_mul, nat_abs_mul_self],
λ h, ⟨sqrt x, h⟩⟩

theorem sqrt_nonneg (n : ℤ) : 0 ≤ sqrt n := coe_nat_nonneg _

end int


/-
Copyright (c) 2020 Sébastien Gouëzel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sébastien Gouëzel, Yury Kudryashov

! This file was ported from Lean 3 source module data.real.conjugate_exponents
! leanprover-community/mathlib commit 2196ab363eb097c008d4497125e0dde23fb36db2
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Real.Ennreal

/-!
# Real conjugate exponents

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

`p.is_conjugate_exponent q` registers the fact that the real numbers `p` and `q` are `> 1` and
satisfy `1/p + 1/q = 1`. This property shows up often in analysis, especially when dealing with
`L^p` spaces.

We make several basic facts available through dot notation in this situation.

We also introduce `p.conjugate_exponent` for `p / (p-1)`. When `p > 1`, it is conjugate to `p`.
-/

noncomputable section

namespace Real

#print Real.IsConjugateExponent /-
/-- Two real exponents `p, q` are conjugate if they are `> 1` and satisfy the equality
`1/p + 1/q = 1`. This condition shows up in many theorems in analysis, notably related to `L^p`
norms. -/
structure IsConjugateExponent (p q : ℝ) : Prop where
  one_lt : 1 < p
  inv_add_inv_conj : 1 / p + 1 / q = 1
#align real.is_conjugate_exponent Real.IsConjugateExponent
-/

#print Real.conjugateExponent /-
/-- The conjugate exponent of `p` is `q = p/(p-1)`, so that `1/p + 1/q = 1`. -/
def conjugateExponent (p : ℝ) : ℝ :=
  p / (p - 1)
#align real.conjugate_exponent Real.conjugateExponent
-/

namespace IsConjugateExponent

variable {p q : ℝ} (h : p.IsConjugateExponent q)

include h

/- warning: real.is_conjugate_exponent.pos -> Real.IsConjugateExponent.pos is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (LT.lt.{0} Real Real.hasLt (OfNat.ofNat.{0} Real 0 (OfNat.mk.{0} Real 0 (Zero.zero.{0} Real Real.hasZero))) p)
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (LT.lt.{0} Real Real.instLTReal (OfNat.ofNat.{0} Real 0 (Zero.toOfNat0.{0} Real Real.instZeroReal)) p)
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.pos Real.IsConjugateExponent.posₓ'. -/
/- Register several non-vanishing results following from the fact that `p` has a conjugate exponent
`q`: many computations using these exponents require clearing out denominators, which can be done
with `field_simp` given a proof that these denominators are non-zero, so we record the most usual
ones. -/
theorem pos : 0 < p :=
  lt_trans zero_lt_one h.one_lt
#align real.is_conjugate_exponent.pos Real.IsConjugateExponent.pos

/- warning: real.is_conjugate_exponent.nonneg -> Real.IsConjugateExponent.nonneg is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (LE.le.{0} Real Real.hasLe (OfNat.ofNat.{0} Real 0 (OfNat.mk.{0} Real 0 (Zero.zero.{0} Real Real.hasZero))) p)
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (LE.le.{0} Real Real.instLEReal (OfNat.ofNat.{0} Real 0 (Zero.toOfNat0.{0} Real Real.instZeroReal)) p)
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.nonneg Real.IsConjugateExponent.nonnegₓ'. -/
theorem nonneg : 0 ≤ p :=
  le_of_lt h.Pos
#align real.is_conjugate_exponent.nonneg Real.IsConjugateExponent.nonneg

/- warning: real.is_conjugate_exponent.ne_zero -> Real.IsConjugateExponent.ne_zero is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Ne.{1} Real p (OfNat.ofNat.{0} Real 0 (OfNat.mk.{0} Real 0 (Zero.zero.{0} Real Real.hasZero))))
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Ne.{1} Real p (OfNat.ofNat.{0} Real 0 (Zero.toOfNat0.{0} Real Real.instZeroReal)))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.ne_zero Real.IsConjugateExponent.ne_zeroₓ'. -/
theorem ne_zero : p ≠ 0 :=
  ne_of_gt h.Pos
#align real.is_conjugate_exponent.ne_zero Real.IsConjugateExponent.ne_zero

/- warning: real.is_conjugate_exponent.sub_one_pos -> Real.IsConjugateExponent.sub_one_pos is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (LT.lt.{0} Real Real.hasLt (OfNat.ofNat.{0} Real 0 (OfNat.mk.{0} Real 0 (Zero.zero.{0} Real Real.hasZero))) (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.hasSub) p (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne)))))
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (LT.lt.{0} Real Real.instLTReal (OfNat.ofNat.{0} Real 0 (Zero.toOfNat0.{0} Real Real.instZeroReal)) (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.instSubReal) p (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal))))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.sub_one_pos Real.IsConjugateExponent.sub_one_posₓ'. -/
theorem sub_one_pos : 0 < p - 1 :=
  sub_pos.2 h.one_lt
#align real.is_conjugate_exponent.sub_one_pos Real.IsConjugateExponent.sub_one_pos

/- warning: real.is_conjugate_exponent.sub_one_ne_zero -> Real.IsConjugateExponent.sub_one_ne_zero is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Ne.{1} Real (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.hasSub) p (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne)))) (OfNat.ofNat.{0} Real 0 (OfNat.mk.{0} Real 0 (Zero.zero.{0} Real Real.hasZero))))
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Ne.{1} Real (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.instSubReal) p (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal))) (OfNat.ofNat.{0} Real 0 (Zero.toOfNat0.{0} Real Real.instZeroReal)))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.sub_one_ne_zero Real.IsConjugateExponent.sub_one_ne_zeroₓ'. -/
theorem sub_one_ne_zero : p - 1 ≠ 0 :=
  ne_of_gt h.sub_one_pos
#align real.is_conjugate_exponent.sub_one_ne_zero Real.IsConjugateExponent.sub_one_ne_zero

/- warning: real.is_conjugate_exponent.one_div_pos -> Real.IsConjugateExponent.one_div_pos is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (LT.lt.{0} Real Real.hasLt (OfNat.ofNat.{0} Real 0 (OfNat.mk.{0} Real 0 (Zero.zero.{0} Real Real.hasZero))) (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (DivInvMonoid.toHasDiv.{0} Real (DivisionRing.toDivInvMonoid.{0} Real Real.divisionRing))) (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne))) p))
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (LT.lt.{0} Real Real.instLTReal (OfNat.ofNat.{0} Real 0 (Zero.toOfNat0.{0} Real Real.instZeroReal)) (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (LinearOrderedField.toDiv.{0} Real Real.instLinearOrderedFieldReal)) (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal)) p))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.one_div_pos Real.IsConjugateExponent.one_div_posₓ'. -/
theorem one_div_pos : 0 < 1 / p :=
  one_div_pos.2 h.Pos
#align real.is_conjugate_exponent.one_div_pos Real.IsConjugateExponent.one_div_pos

/- warning: real.is_conjugate_exponent.one_div_nonneg -> Real.IsConjugateExponent.one_div_nonneg is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (LE.le.{0} Real Real.hasLe (OfNat.ofNat.{0} Real 0 (OfNat.mk.{0} Real 0 (Zero.zero.{0} Real Real.hasZero))) (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (DivInvMonoid.toHasDiv.{0} Real (DivisionRing.toDivInvMonoid.{0} Real Real.divisionRing))) (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne))) p))
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (LE.le.{0} Real Real.instLEReal (OfNat.ofNat.{0} Real 0 (Zero.toOfNat0.{0} Real Real.instZeroReal)) (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (LinearOrderedField.toDiv.{0} Real Real.instLinearOrderedFieldReal)) (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal)) p))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.one_div_nonneg Real.IsConjugateExponent.one_div_nonnegₓ'. -/
theorem one_div_nonneg : 0 ≤ 1 / p :=
  le_of_lt h.one_div_pos
#align real.is_conjugate_exponent.one_div_nonneg Real.IsConjugateExponent.one_div_nonneg

/- warning: real.is_conjugate_exponent.one_div_ne_zero -> Real.IsConjugateExponent.one_div_ne_zero is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Ne.{1} Real (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (DivInvMonoid.toHasDiv.{0} Real (DivisionRing.toDivInvMonoid.{0} Real Real.divisionRing))) (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne))) p) (OfNat.ofNat.{0} Real 0 (OfNat.mk.{0} Real 0 (Zero.zero.{0} Real Real.hasZero))))
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Ne.{1} Real (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (LinearOrderedField.toDiv.{0} Real Real.instLinearOrderedFieldReal)) (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal)) p) (OfNat.ofNat.{0} Real 0 (Zero.toOfNat0.{0} Real Real.instZeroReal)))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.one_div_ne_zero Real.IsConjugateExponent.one_div_ne_zeroₓ'. -/
theorem one_div_ne_zero : 1 / p ≠ 0 :=
  ne_of_gt h.one_div_pos
#align real.is_conjugate_exponent.one_div_ne_zero Real.IsConjugateExponent.one_div_ne_zero

/- warning: real.is_conjugate_exponent.conj_eq -> Real.IsConjugateExponent.conj_eq is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} Real q (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (DivInvMonoid.toHasDiv.{0} Real (DivisionRing.toDivInvMonoid.{0} Real Real.divisionRing))) p (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.hasSub) p (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne))))))
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} Real q (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (LinearOrderedField.toDiv.{0} Real Real.instLinearOrderedFieldReal)) p (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.instSubReal) p (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal)))))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.conj_eq Real.IsConjugateExponent.conj_eqₓ'. -/
theorem conj_eq : q = p / (p - 1) :=
  by
  have := h.inv_add_inv_conj
  rw [← eq_sub_iff_add_eq', one_div, inv_eq_iff_eq_inv] at this
  field_simp [this, h.ne_zero]
#align real.is_conjugate_exponent.conj_eq Real.IsConjugateExponent.conj_eq

#print Real.IsConjugateExponent.conjugate_eq /-
theorem conjugate_eq : conjugateExponent p = q :=
  h.conj_eq.symm
#align real.is_conjugate_exponent.conjugate_eq Real.IsConjugateExponent.conjugate_eq
-/

/- warning: real.is_conjugate_exponent.sub_one_mul_conj -> Real.IsConjugateExponent.sub_one_mul_conj is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} Real (HMul.hMul.{0, 0, 0} Real Real Real (instHMul.{0} Real Real.hasMul) (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.hasSub) p (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne)))) q) p)
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} Real (HMul.hMul.{0, 0, 0} Real Real Real (instHMul.{0} Real Real.instMulReal) (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.instSubReal) p (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal))) q) p)
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.sub_one_mul_conj Real.IsConjugateExponent.sub_one_mul_conjₓ'. -/
theorem sub_one_mul_conj : (p - 1) * q = p :=
  mul_comm q (p - 1) ▸ (eq_div_iff h.sub_one_ne_zero).1 h.conj_eq
#align real.is_conjugate_exponent.sub_one_mul_conj Real.IsConjugateExponent.sub_one_mul_conj

/- warning: real.is_conjugate_exponent.mul_eq_add -> Real.IsConjugateExponent.mul_eq_add is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} Real (HMul.hMul.{0, 0, 0} Real Real Real (instHMul.{0} Real Real.hasMul) p q) (HAdd.hAdd.{0, 0, 0} Real Real Real (instHAdd.{0} Real Real.hasAdd) p q))
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} Real (HMul.hMul.{0, 0, 0} Real Real Real (instHMul.{0} Real Real.instMulReal) p q) (HAdd.hAdd.{0, 0, 0} Real Real Real (instHAdd.{0} Real Real.instAddReal) p q))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.mul_eq_add Real.IsConjugateExponent.mul_eq_addₓ'. -/
theorem mul_eq_add : p * q = p + q := by
  simpa only [sub_mul, sub_eq_iff_eq_add, one_mul] using h.sub_one_mul_conj
#align real.is_conjugate_exponent.mul_eq_add Real.IsConjugateExponent.mul_eq_add

#print Real.IsConjugateExponent.symm /-
@[symm]
protected theorem symm : q.IsConjugateExponent p :=
  { one_lt := by
      rw [h.conj_eq]
      exact (one_lt_div h.sub_one_pos).mpr (sub_one_lt p)
    inv_add_inv_conj := by simpa [add_comm] using h.inv_add_inv_conj }
#align real.is_conjugate_exponent.symm Real.IsConjugateExponent.symm
-/

/- warning: real.is_conjugate_exponent.div_conj_eq_sub_one -> Real.IsConjugateExponent.div_conj_eq_sub_one is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} Real (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (DivInvMonoid.toHasDiv.{0} Real (DivisionRing.toDivInvMonoid.{0} Real Real.divisionRing))) p q) (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.hasSub) p (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne)))))
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} Real (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (LinearOrderedField.toDiv.{0} Real Real.instLinearOrderedFieldReal)) p q) (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.instSubReal) p (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal))))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.div_conj_eq_sub_one Real.IsConjugateExponent.div_conj_eq_sub_oneₓ'. -/
theorem div_conj_eq_sub_one : p / q = p - 1 :=
  by
  field_simp [h.symm.ne_zero]
  rw [h.sub_one_mul_conj]
#align real.is_conjugate_exponent.div_conj_eq_sub_one Real.IsConjugateExponent.div_conj_eq_sub_one

#print Real.IsConjugateExponent.one_lt_nNReal /-
theorem one_lt_nNReal : 1 < Real.toNNReal p :=
  by
  rw [← Real.toNNReal_one, Real.toNNReal_lt_toNNReal_iff h.pos]
  exact h.one_lt
#align real.is_conjugate_exponent.one_lt_nnreal Real.IsConjugateExponent.one_lt_nNReal
-/

/- warning: real.is_conjugate_exponent.inv_add_inv_conj_nnreal -> Real.IsConjugateExponent.inv_add_inv_conj_nNReal is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} NNReal (HAdd.hAdd.{0, 0, 0} NNReal NNReal NNReal (instHAdd.{0} NNReal (Distrib.toHasAdd.{0} NNReal (NonUnitalNonAssocSemiring.toDistrib.{0} NNReal (NonAssocSemiring.toNonUnitalNonAssocSemiring.{0} NNReal (Semiring.toNonAssocSemiring.{0} NNReal NNReal.semiring))))) (HDiv.hDiv.{0, 0, 0} NNReal NNReal NNReal (instHDiv.{0} NNReal NNReal.hasDiv) (OfNat.ofNat.{0} NNReal 1 (OfNat.mk.{0} NNReal 1 (One.one.{0} NNReal (AddMonoidWithOne.toOne.{0} NNReal (AddCommMonoidWithOne.toAddMonoidWithOne.{0} NNReal (NonAssocSemiring.toAddCommMonoidWithOne.{0} NNReal (Semiring.toNonAssocSemiring.{0} NNReal NNReal.semiring))))))) (Real.toNNReal p)) (HDiv.hDiv.{0, 0, 0} NNReal NNReal NNReal (instHDiv.{0} NNReal NNReal.hasDiv) (OfNat.ofNat.{0} NNReal 1 (OfNat.mk.{0} NNReal 1 (One.one.{0} NNReal (AddMonoidWithOne.toOne.{0} NNReal (AddCommMonoidWithOne.toAddMonoidWithOne.{0} NNReal (NonAssocSemiring.toAddCommMonoidWithOne.{0} NNReal (Semiring.toNonAssocSemiring.{0} NNReal NNReal.semiring))))))) (Real.toNNReal q))) (OfNat.ofNat.{0} NNReal 1 (OfNat.mk.{0} NNReal 1 (One.one.{0} NNReal (AddMonoidWithOne.toOne.{0} NNReal (AddCommMonoidWithOne.toAddMonoidWithOne.{0} NNReal (NonAssocSemiring.toAddCommMonoidWithOne.{0} NNReal (Semiring.toNonAssocSemiring.{0} NNReal NNReal.semiring))))))))
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} NNReal (HAdd.hAdd.{0, 0, 0} NNReal NNReal NNReal (instHAdd.{0} NNReal (Distrib.toAdd.{0} NNReal (NonUnitalNonAssocSemiring.toDistrib.{0} NNReal (NonAssocSemiring.toNonUnitalNonAssocSemiring.{0} NNReal (Semiring.toNonAssocSemiring.{0} NNReal instNNRealSemiring))))) (HDiv.hDiv.{0, 0, 0} NNReal NNReal NNReal (instHDiv.{0} NNReal (CanonicallyLinearOrderedSemifield.toDiv.{0} NNReal NNReal.instCanonicallyLinearOrderedSemifieldNNReal)) (OfNat.ofNat.{0} NNReal 1 (One.toOfNat1.{0} NNReal instNNRealOne)) (Real.toNNReal p)) (HDiv.hDiv.{0, 0, 0} NNReal NNReal NNReal (instHDiv.{0} NNReal (CanonicallyLinearOrderedSemifield.toDiv.{0} NNReal NNReal.instCanonicallyLinearOrderedSemifieldNNReal)) (OfNat.ofNat.{0} NNReal 1 (One.toOfNat1.{0} NNReal instNNRealOne)) (Real.toNNReal q))) (OfNat.ofNat.{0} NNReal 1 (One.toOfNat1.{0} NNReal instNNRealOne)))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.inv_add_inv_conj_nnreal Real.IsConjugateExponent.inv_add_inv_conj_nNRealₓ'. -/
theorem inv_add_inv_conj_nNReal : 1 / Real.toNNReal p + 1 / Real.toNNReal q = 1 := by
  rw [← Real.toNNReal_one, ← Real.toNNReal_div' h.nonneg, ← Real.toNNReal_div' h.symm.nonneg, ←
    Real.toNNReal_add h.one_div_nonneg h.symm.one_div_nonneg, h.inv_add_inv_conj]
#align real.is_conjugate_exponent.inv_add_inv_conj_nnreal Real.IsConjugateExponent.inv_add_inv_conj_nNReal

/- warning: real.is_conjugate_exponent.inv_add_inv_conj_ennreal -> Real.IsConjugateExponent.inv_add_inv_conj_ennreal is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} ENNReal (HAdd.hAdd.{0, 0, 0} ENNReal ENNReal ENNReal (instHAdd.{0} ENNReal (Distrib.toHasAdd.{0} ENNReal (NonUnitalNonAssocSemiring.toDistrib.{0} ENNReal (NonAssocSemiring.toNonUnitalNonAssocSemiring.{0} ENNReal (Semiring.toNonAssocSemiring.{0} ENNReal (OrderedSemiring.toSemiring.{0} ENNReal (OrderedCommSemiring.toOrderedSemiring.{0} ENNReal (CanonicallyOrderedCommSemiring.toOrderedCommSemiring.{0} ENNReal ENNReal.canonicallyOrderedCommSemiring)))))))) (HDiv.hDiv.{0, 0, 0} ENNReal ENNReal ENNReal (instHDiv.{0} ENNReal (DivInvMonoid.toHasDiv.{0} ENNReal ENNReal.divInvMonoid)) (OfNat.ofNat.{0} ENNReal 1 (OfNat.mk.{0} ENNReal 1 (One.one.{0} ENNReal (AddMonoidWithOne.toOne.{0} ENNReal (AddCommMonoidWithOne.toAddMonoidWithOne.{0} ENNReal ENNReal.addCommMonoidWithOne))))) (ENNReal.ofReal p)) (HDiv.hDiv.{0, 0, 0} ENNReal ENNReal ENNReal (instHDiv.{0} ENNReal (DivInvMonoid.toHasDiv.{0} ENNReal ENNReal.divInvMonoid)) (OfNat.ofNat.{0} ENNReal 1 (OfNat.mk.{0} ENNReal 1 (One.one.{0} ENNReal (AddMonoidWithOne.toOne.{0} ENNReal (AddCommMonoidWithOne.toAddMonoidWithOne.{0} ENNReal ENNReal.addCommMonoidWithOne))))) (ENNReal.ofReal q))) (OfNat.ofNat.{0} ENNReal 1 (OfNat.mk.{0} ENNReal 1 (One.one.{0} ENNReal (AddMonoidWithOne.toOne.{0} ENNReal (AddCommMonoidWithOne.toAddMonoidWithOne.{0} ENNReal ENNReal.addCommMonoidWithOne))))))
but is expected to have type
  forall {p : Real} {q : Real}, (Real.IsConjugateExponent p q) -> (Eq.{1} ENNReal (HAdd.hAdd.{0, 0, 0} ENNReal ENNReal ENNReal (instHAdd.{0} ENNReal (Distrib.toAdd.{0} ENNReal (NonUnitalNonAssocSemiring.toDistrib.{0} ENNReal (NonAssocSemiring.toNonUnitalNonAssocSemiring.{0} ENNReal (Semiring.toNonAssocSemiring.{0} ENNReal (OrderedSemiring.toSemiring.{0} ENNReal (OrderedCommSemiring.toOrderedSemiring.{0} ENNReal (CanonicallyOrderedCommSemiring.toOrderedCommSemiring.{0} ENNReal ENNReal.instCanonicallyOrderedCommSemiringENNReal)))))))) (HDiv.hDiv.{0, 0, 0} ENNReal ENNReal ENNReal (instHDiv.{0} ENNReal (DivInvMonoid.toDiv.{0} ENNReal ENNReal.instDivInvMonoidENNReal)) (OfNat.ofNat.{0} ENNReal 1 (One.toOfNat1.{0} ENNReal (CanonicallyOrderedCommSemiring.toOne.{0} ENNReal ENNReal.instCanonicallyOrderedCommSemiringENNReal))) (ENNReal.ofReal p)) (HDiv.hDiv.{0, 0, 0} ENNReal ENNReal ENNReal (instHDiv.{0} ENNReal (DivInvMonoid.toDiv.{0} ENNReal ENNReal.instDivInvMonoidENNReal)) (OfNat.ofNat.{0} ENNReal 1 (One.toOfNat1.{0} ENNReal (CanonicallyOrderedCommSemiring.toOne.{0} ENNReal ENNReal.instCanonicallyOrderedCommSemiringENNReal))) (ENNReal.ofReal q))) (OfNat.ofNat.{0} ENNReal 1 (One.toOfNat1.{0} ENNReal (CanonicallyOrderedCommSemiring.toOne.{0} ENNReal ENNReal.instCanonicallyOrderedCommSemiringENNReal))))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent.inv_add_inv_conj_ennreal Real.IsConjugateExponent.inv_add_inv_conj_ennrealₓ'. -/
theorem inv_add_inv_conj_ennreal : 1 / ENNReal.ofReal p + 1 / ENNReal.ofReal q = 1 := by
  rw [← ENNReal.ofReal_one, ← ENNReal.ofReal_div_of_pos h.pos, ←
    ENNReal.ofReal_div_of_pos h.symm.pos, ←
    ENNReal.ofReal_add h.one_div_nonneg h.symm.one_div_nonneg, h.inv_add_inv_conj]
#align real.is_conjugate_exponent.inv_add_inv_conj_ennreal Real.IsConjugateExponent.inv_add_inv_conj_ennreal

end IsConjugateExponent

/- warning: real.is_conjugate_exponent_iff -> Real.isConjugateExponent_iff is a dubious translation:
lean 3 declaration is
  forall {p : Real} {q : Real}, (LT.lt.{0} Real Real.hasLt (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne))) p) -> (Iff (Real.IsConjugateExponent p q) (Eq.{1} Real q (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (DivInvMonoid.toHasDiv.{0} Real (DivisionRing.toDivInvMonoid.{0} Real Real.divisionRing))) p (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.hasSub) p (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne)))))))
but is expected to have type
  forall {p : Real} {q : Real}, (LT.lt.{0} Real Real.instLTReal (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal)) p) -> (Iff (Real.IsConjugateExponent p q) (Eq.{1} Real q (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (LinearOrderedField.toDiv.{0} Real Real.instLinearOrderedFieldReal)) p (HSub.hSub.{0, 0, 0} Real Real Real (instHSub.{0} Real Real.instSubReal) p (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal))))))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent_iff Real.isConjugateExponent_iffₓ'. -/
theorem isConjugateExponent_iff {p q : ℝ} (h : 1 < p) : p.IsConjugateExponent q ↔ q = p / (p - 1) :=
  ⟨fun H => H.conj_eq, fun H => ⟨h, by field_simp [H, ne_of_gt (lt_trans zero_lt_one h)] ⟩⟩
#align real.is_conjugate_exponent_iff Real.isConjugateExponent_iff

/- warning: real.is_conjugate_exponent_conjugate_exponent -> Real.isConjugateExponent_conjugateExponent is a dubious translation:
lean 3 declaration is
  forall {p : Real}, (LT.lt.{0} Real Real.hasLt (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne))) p) -> (Real.IsConjugateExponent p (Real.conjugateExponent p))
but is expected to have type
  forall {p : Real}, (LT.lt.{0} Real Real.instLTReal (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal)) p) -> (Real.IsConjugateExponent p (Real.conjugateExponent p))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent_conjugate_exponent Real.isConjugateExponent_conjugateExponentₓ'. -/
theorem isConjugateExponent_conjugateExponent {p : ℝ} (h : 1 < p) :
    p.IsConjugateExponent (conjugateExponent p) :=
  (isConjugateExponent_iff h).2 rfl
#align real.is_conjugate_exponent_conjugate_exponent Real.isConjugateExponent_conjugateExponent

/- warning: real.is_conjugate_exponent_one_div -> Real.isConjugateExponent_one_div is a dubious translation:
lean 3 declaration is
  forall {a : Real} {b : Real}, (LT.lt.{0} Real Real.hasLt (OfNat.ofNat.{0} Real 0 (OfNat.mk.{0} Real 0 (Zero.zero.{0} Real Real.hasZero))) a) -> (LT.lt.{0} Real Real.hasLt (OfNat.ofNat.{0} Real 0 (OfNat.mk.{0} Real 0 (Zero.zero.{0} Real Real.hasZero))) b) -> (Eq.{1} Real (HAdd.hAdd.{0, 0, 0} Real Real Real (instHAdd.{0} Real Real.hasAdd) a b) (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne)))) -> (Real.IsConjugateExponent (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (DivInvMonoid.toHasDiv.{0} Real (DivisionRing.toDivInvMonoid.{0} Real Real.divisionRing))) (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne))) a) (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (DivInvMonoid.toHasDiv.{0} Real (DivisionRing.toDivInvMonoid.{0} Real Real.divisionRing))) (OfNat.ofNat.{0} Real 1 (OfNat.mk.{0} Real 1 (One.one.{0} Real Real.hasOne))) b))
but is expected to have type
  forall {a : Real} {b : Real}, (LT.lt.{0} Real Real.instLTReal (OfNat.ofNat.{0} Real 0 (Zero.toOfNat0.{0} Real Real.instZeroReal)) a) -> (LT.lt.{0} Real Real.instLTReal (OfNat.ofNat.{0} Real 0 (Zero.toOfNat0.{0} Real Real.instZeroReal)) b) -> (Eq.{1} Real (HAdd.hAdd.{0, 0, 0} Real Real Real (instHAdd.{0} Real Real.instAddReal) a b) (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal))) -> (Real.IsConjugateExponent (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (LinearOrderedField.toDiv.{0} Real Real.instLinearOrderedFieldReal)) (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal)) a) (HDiv.hDiv.{0, 0, 0} Real Real Real (instHDiv.{0} Real (LinearOrderedField.toDiv.{0} Real Real.instLinearOrderedFieldReal)) (OfNat.ofNat.{0} Real 1 (One.toOfNat1.{0} Real Real.instOneReal)) b))
Case conversion may be inaccurate. Consider using '#align real.is_conjugate_exponent_one_div Real.isConjugateExponent_one_divₓ'. -/
theorem isConjugateExponent_one_div {a b : ℝ} (ha : 0 < a) (hb : 0 < b) (hab : a + b = 1) :
    (1 / a).IsConjugateExponent (1 / b) :=
  ⟨by
    rw [lt_div_iff ha, one_mul]
    linarith, by
    simp_rw [one_div_one_div]
    exact hab⟩
#align real.is_conjugate_exponent_one_div Real.isConjugateExponent_one_div

end Real