/-
Copyright (c) 2019 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Mario Carneiro

! This file was ported from Lean 3 source module data.rat.defs
! leanprover-community/mathlib commit c3291da49cfa65f0d43b094750541c0731edc932
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Data.Rat.Init
import Mathbin.Data.Int.Cast.Defs
import Mathbin.Data.Int.Dvd.Basic
import Mathbin.Algebra.Ring.Regular
import Mathbin.Data.Nat.Gcd.Basic
import Mathbin.Data.Pnat.Defs

/-!
# Basics for the Rational Numbers

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

## Summary

We define the integral domain structure on `ℚ` and prove basic lemmas about it.
The definition of the field structure on `ℚ` will be done in `data.rat.basic` once the
`field` class has been defined.

## Main Definitions

- `rat.mk n d` constructs a rational number `q = n / d` from `n d : ℤ`.

## Notations

- `/.` is infix notation for `rat.mk`.

-/

namespace Rat

#print Rat.ofInt /-
/-- Embed an integer as a rational number. You should use the coercion `coe : ℤ → ℚ` instead. -/
def ofInt (n : ℤ) : ℚ :=
  ⟨n, 1, Nat.one_pos, Nat.coprime_one_right _⟩
#align rat.of_int Rat.ofInt
-/

instance : IntCast ℚ :=
  ⟨ofInt⟩

#print Rat.ofInt_eq_cast /-
@[simp]
theorem ofInt_eq_cast (n : ℤ) : ofInt n = n :=
  rfl
#align rat.of_int_eq_cast Rat.ofInt_eq_cast
-/

#print Rat.coe_int_num /-
@[simp, norm_cast]
theorem coe_int_num (n : ℤ) : (n : ℚ).num = n :=
  rfl
#align rat.coe_int_num Rat.coe_int_num
-/

#print Rat.coe_int_den /-
@[simp, norm_cast]
theorem coe_int_den (n : ℤ) : (n : ℚ).den = 1 :=
  rfl
#align rat.coe_int_denom Rat.coe_int_den
-/

instance : Zero ℚ :=
  ⟨(0 : ℤ)⟩

instance : One ℚ :=
  ⟨(1 : ℤ)⟩

instance : Inhabited ℚ :=
  ⟨0⟩

/- warning: rat.mk_pnat clashes with [anonymous] -> [anonymous]
warning: rat.mk_pnat -> [anonymous] is a dubious translation:
lean 3 declaration is
  Int -> PNat -> Rat
but is expected to have type
  forall {n : Type.{u}} {ᾰ : Type.{v}}, (Nat -> n -> ᾰ) -> Nat -> (List.{u} n) -> (List.{v} ᾰ)
Case conversion may be inaccurate. Consider using '#align rat.mk_pnat [anonymous]ₓ'. -/
/-- Form the quotient `n / d` where `n:ℤ` and `d:ℕ+` (not necessarily coprime) -/
def [anonymous] (n : ℤ) : ℕ+ → ℚ
  | ⟨d, dpos⟩ =>
    let n' := n.natAbs
    let g := n'.gcd d
    ⟨n / g, d / g, by
      apply (Nat.le_div_iff_mul_le (Nat.gcd_pos_of_pos_right _ dpos)).2
      rw [one_mul]; exact Nat.le_of_dvd dpos (Nat.gcd_dvd_right _ _),
      by
      have : Int.natAbs (n / ↑g) = n' / g :=
        by
        cases' Int.natAbs_eq n with e e <;> rw [e]
        · rfl
        rw [Int.neg_ediv_of_dvd, Int.natAbs_neg]
        · rfl
        exact Int.coe_nat_dvd.2 (Nat.gcd_dvd_left _ _)
      rw [this]
      exact Nat.coprime_div_gcd_div_gcd (Nat.gcd_pos_of_pos_right _ dpos)⟩
#align rat.mk_pnat [anonymous]

#print mkRat /-
/-- Form the quotient `n / d` where `n:ℤ` and `d:ℕ`. In the case `d = 0`, we
  define `n / 0 = 0` by convention. -/
def mkRat (n : ℤ) (d : ℕ) : ℚ :=
  if d0 : d = 0 then 0 else [anonymous] n ⟨d, Nat.pos_of_ne_zero d0⟩
#align rat.mk_nat mkRat
-/

/-- Form the quotient `n / d` where `n d : ℤ`. -/
def mk : ℤ → ℤ → ℚ
  | n, (d : ℕ) => mkRat n d
  | n, -[d+1] => [anonymous] (-n) d.succPNat
#align rat.mk Rat.mk

-- mathport name: rat.mk
scoped infixl:70 " /. " => Rat.mk

/- warning: rat.mk_pnat_eq clashes with [anonymous] -> [anonymous]
warning: rat.mk_pnat_eq -> [anonymous] is a dubious translation:
lean 3 declaration is
  forall (n : Int) (d : Nat) (h : LT.lt.{0} Nat Nat.hasLt (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) d), Eq.{1} Rat ([anonymous] n (Subtype.mk.{1} Nat (fun (n : Nat) => LT.lt.{0} Nat Nat.hasLt (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) n) d h)) (Rat.mk n ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) d))
but is expected to have type
  forall {n : Type.{u}} {d : Type.{v}}, (Nat -> n -> d) -> Nat -> (List.{u} n) -> (List.{v} d)
Case conversion may be inaccurate. Consider using '#align rat.mk_pnat_eq [anonymous]ₓ'. -/
theorem [anonymous] (n d h) : [anonymous] n ⟨d, h⟩ = n /. d := by
  change n /. d with dite _ _ _ <;> simp [ne_of_gt h]
#align rat.mk_pnat_eq [anonymous]

/- warning: rat.mk_nat_eq -> Rat.mkRat_eq is a dubious translation:
lean 3 declaration is
  forall (n : Int) (d : Nat), Eq.{1} Rat (mkRat n d) (Rat.mk n ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) d))
but is expected to have type
  forall (n : Int) (d : Nat), Eq.{1} Rat (mkRat n d) (Rat.divInt n (Nat.cast.{0} Int instNatCastInt d))
Case conversion may be inaccurate. Consider using '#align rat.mk_nat_eq Rat.mkRat_eqₓ'. -/
theorem mkRat_eq (n d) : mkRat n d = n /. d :=
  rfl
#align rat.mk_nat_eq Rat.mkRat_eq

/- warning: rat.mk_zero -> Rat.divInt_zero is a dubious translation:
lean 3 declaration is
  forall (n : Int), Eq.{1} Rat (Rat.mk n (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) (OfNat.ofNat.{0} Rat 0 (OfNat.mk.{0} Rat 0 (Zero.zero.{0} Rat Rat.hasZero)))
but is expected to have type
  forall (n : Int), Eq.{1} Rat (Rat.divInt n (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) (OfNat.ofNat.{0} Rat 0 (Rat.instOfNatRat 0))
Case conversion may be inaccurate. Consider using '#align rat.mk_zero Rat.divInt_zeroₓ'. -/
@[simp]
theorem divInt_zero (n) : n /. 0 = 0 :=
  rfl
#align rat.mk_zero Rat.divInt_zero

/- warning: rat.zero_mk_pnat clashes with [anonymous] -> [anonymous]
warning: rat.zero_mk_pnat -> [anonymous] is a dubious translation:
lean 3 declaration is
  forall (n : PNat), Eq.{1} Rat ([anonymous] (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero))) n) (OfNat.ofNat.{0} Rat 0 (OfNat.mk.{0} Rat 0 (Zero.zero.{0} Rat Rat.hasZero)))
but is expected to have type
  forall {n : Type.{u}} {β : Type.{v}}, (Nat -> n -> β) -> Nat -> (List.{u} n) -> (List.{v} β)
Case conversion may be inaccurate. Consider using '#align rat.zero_mk_pnat [anonymous]ₓ'. -/
@[simp]
theorem [anonymous] (n) : [anonymous] 0 n = 0 :=
  by
  cases' n with n npos
  simp only [mk_pnat, Int.natAbs_zero, Nat.div_self npos, Nat.gcd_zero_left, Int.zero_div]
  rfl
#align rat.zero_mk_pnat [anonymous]

#print Rat.zero_mkRat /-
@[simp]
theorem zero_mkRat (n) : mkRat 0 n = 0 := by by_cases n = 0 <;> simp [*, mk_nat]
#align rat.zero_mk_nat Rat.zero_mkRat
-/

/- warning: rat.zero_mk -> Rat.zero_divInt is a dubious translation:
lean 3 declaration is
  forall (n : Int), Eq.{1} Rat (Rat.mk (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero))) n) (OfNat.ofNat.{0} Rat 0 (OfNat.mk.{0} Rat 0 (Zero.zero.{0} Rat Rat.hasZero)))
but is expected to have type
  forall (n : Int), Eq.{1} Rat (Rat.divInt (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)) n) (OfNat.ofNat.{0} Rat 0 (Rat.instOfNatRat 0))
Case conversion may be inaccurate. Consider using '#align rat.zero_mk Rat.zero_divIntₓ'. -/
@[simp]
theorem zero_divInt (n) : 0 /. n = 0 := by cases n <;> simp [mk]
#align rat.zero_mk Rat.zero_divInt

private theorem gcd_abs_dvd_left {a b} : (Nat.gcd (Int.natAbs a) b : ℤ) ∣ a :=
  Int.dvd_natAbs.1 <| Int.coe_nat_dvd.2 <| Nat.gcd_dvd_left (Int.natAbs a) b
#align rat.gcd_abs_dvd_left rat.gcd_abs_dvd_left

/- warning: rat.mk_eq_zero -> Rat.divInt_eq_zero is a dubious translation:
lean 3 declaration is
  forall {a : Int} {b : Int}, (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Iff (Eq.{1} Rat (Rat.mk a b) (OfNat.ofNat.{0} Rat 0 (OfNat.mk.{0} Rat 0 (Zero.zero.{0} Rat Rat.hasZero)))) (Eq.{1} Int a (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))))
but is expected to have type
  forall {a : Int} {b : Int}, (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Iff (Eq.{1} Rat (Rat.divInt a b) (OfNat.ofNat.{0} Rat 0 (Rat.instOfNatRat 0))) (Eq.{1} Int a (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))))
Case conversion may be inaccurate. Consider using '#align rat.mk_eq_zero Rat.divInt_eq_zeroₓ'. -/
@[simp]
theorem divInt_eq_zero {a b : ℤ} (b0 : b ≠ 0) : a /. b = 0 ↔ a = 0 :=
  by
  refine'
    ⟨fun h => _, by
      rintro rfl
      simp⟩
  have : ∀ {a b}, mk_pnat a b = 0 → a = 0 :=
    by
    rintro a ⟨b, h⟩ e
    injection e with e
    apply Int.eq_mul_of_ediv_eq_right gcd_abs_dvd_left e
  cases' b with b <;> simp only [mk, mk_nat, Int.ofNat_eq_coe, dite_eq_left_iff] at h
  · simp only [mt (congr_arg Int.ofNat) b0, not_false_iff, forall_true_left] at h
    exact this h
  · apply neg_injective
    simp [this h]
#align rat.mk_eq_zero Rat.divInt_eq_zero

/- warning: rat.mk_ne_zero -> Rat.divInt_ne_zero is a dubious translation:
lean 3 declaration is
  forall {a : Int} {b : Int}, (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Iff (Ne.{1} Rat (Rat.mk a b) (OfNat.ofNat.{0} Rat 0 (OfNat.mk.{0} Rat 0 (Zero.zero.{0} Rat Rat.hasZero)))) (Ne.{1} Int a (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))))
but is expected to have type
  forall {a : Int} {b : Int}, (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Iff (Ne.{1} Rat (Rat.divInt a b) (OfNat.ofNat.{0} Rat 0 (Rat.instOfNatRat 0))) (Ne.{1} Int a (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))))
Case conversion may be inaccurate. Consider using '#align rat.mk_ne_zero Rat.divInt_ne_zeroₓ'. -/
theorem divInt_ne_zero {a b : ℤ} (b0 : b ≠ 0) : a /. b ≠ 0 ↔ a ≠ 0 :=
  (divInt_eq_zero b0).Not
#align rat.mk_ne_zero Rat.divInt_ne_zero

/- warning: rat.mk_eq -> Rat.divInt_eq_iff is a dubious translation:
lean 3 declaration is
  forall {a : Int} {b : Int} {c : Int} {d : Int}, (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Iff (Eq.{1} Rat (Rat.mk a b) (Rat.mk c d)) (Eq.{1} Int (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) a d) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) c b)))
but is expected to have type
  forall {a : Int} {b : Int} {c : Int} {d : Int}, (Ne.{1} Int a (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Iff (Eq.{1} Rat (Rat.divInt c a) (Rat.divInt d b)) (Eq.{1} Int (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) c b) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) d a)))
Case conversion may be inaccurate. Consider using '#align rat.mk_eq Rat.divInt_eq_iffₓ'. -/
theorem divInt_eq_iff :
    ∀ {a b c d : ℤ} (hb : b ≠ 0) (hd : d ≠ 0), a /. b = c /. d ↔ a * d = c * b :=
  by
  suffices ∀ a b c d hb hd, [anonymous] a ⟨b, hb⟩ = [anonymous] c ⟨d, hd⟩ ↔ a * d = c * b
    by
    intros ; cases' b with b b <;> simp [mk, mk_nat, Nat.succPNat]
    simp [mt (congr_arg Int.ofNat) hb]
    all_goals
      cases' d with d d <;> simp [mk, mk_nat, Nat.succPNat]
      simp [mt (congr_arg Int.ofNat) hd]
      all_goals rw [this]; try rfl
    · change a * ↑d.succ = -c * ↑b ↔ a * -d.succ = c * b
      constructor <;> intro h <;> apply neg_injective <;>
        simpa [left_distrib, neg_add_eq_iff_eq_add, eq_neg_iff_add_eq_zero,
          neg_eq_iff_add_eq_zero] using h
    · change -a * ↑d = c * b.succ ↔ a * d = c * -b.succ
      constructor <;> intro h <;> apply neg_injective <;> simpa [left_distrib, eq_comm] using h
    · change -a * d.succ = -c * b.succ ↔ a * -d.succ = c * -b.succ
      simp [left_distrib, sub_eq_add_neg]
      cc
  intros ; simp [mk_pnat]; constructor <;> intro h
  · cases' h with ha hb
    have ha := by
      have dv := @gcd_abs_dvd_left
      have := Int.eq_mul_of_ediv_eq_right dv ha
      rw [← Int.mul_ediv_assoc _ dv] at this
      exact Int.eq_mul_of_ediv_eq_left (dv.mul_left _) this.symm
    have hb := by
      have dv := fun {a b} => Nat.gcd_dvd_right (Int.natAbs a) b
      have := Nat.eq_mul_of_div_eq_right dv hb
      rw [← Nat.mul_div_assoc _ dv] at this
      exact Nat.eq_mul_of_div_eq_left (dv.mul_left _) this.symm
    have m0 : (a.nat_abs.gcd b * c.nat_abs.gcd d : ℤ) ≠ 0 :=
      by
      refine' Int.coe_nat_ne_zero.2 (ne_of_gt _)
      apply mul_pos <;> apply Nat.gcd_pos_of_pos_right <;> assumption
    apply mul_right_cancel₀ m0
    simpa [mul_comm, mul_left_comm] using congr (congr_arg (· * ·) ha.symm) (congr_arg coe hb)
  · suffices ∀ a c, a * d = c * b → a / a.gcd b = c / c.gcd d ∧ b / a.gcd b = d / c.gcd d
      by
      cases' this a.nat_abs c.nat_abs (by simpa [Int.natAbs_mul] using congr_arg Int.natAbs h) with
        h₁ h₂
      have hs := congr_arg Int.sign h
      simp [Int.sign_eq_one_of_pos (Int.ofNat_lt.2 hb),
        Int.sign_eq_one_of_pos (Int.ofNat_lt.2 hd)] at hs
      conv in a => rw [← Int.sign_mul_natAbs a]
      conv in c => rw [← Int.sign_mul_natAbs c]
      rw [Int.mul_ediv_assoc, Int.mul_ediv_assoc]
      exact ⟨congr (congr_arg (· * ·) hs) (congr_arg coe h₁), h₂⟩
      all_goals exact Int.coe_nat_dvd.2 (Nat.gcd_dvd_left _ _)
    intro a c h
    suffices bd : b / a.gcd b = d / c.gcd d
    · refine' ⟨mul_left_cancel₀ hb.ne' _, bd⟩
      rw [← Nat.mul_div_assoc _ (Nat.gcd_dvd_left _ _), mul_comm,
        Nat.mul_div_assoc _ (Nat.gcd_dvd_right _ _), bd, ←
        Nat.mul_div_assoc _ (Nat.gcd_dvd_right _ _), h, mul_comm,
        Nat.mul_div_assoc _ (Nat.gcd_dvd_left _ _)]
    suffices ∀ {a c : ℕ}, ∀ b > 0, ∀ d > 0, a * d = c * b → b / a.gcd b ≤ d / c.gcd d by
      exact le_antisymm (this _ hb _ hd h) (this _ hd _ hb h.symm)
    intro a c b hb d hd h
    have gb0 := Nat.gcd_pos_of_pos_right a hb
    have gd0 := Nat.gcd_pos_of_pos_right c hd
    apply Nat.le_of_dvd
    apply (Nat.le_div_iff_mul_le gd0).2
    simp
    apply Nat.le_of_dvd hd (Nat.gcd_dvd_right _ _)
    apply (Nat.coprime_div_gcd_div_gcd gb0).symm.dvd_of_dvd_mul_left
    refine' ⟨c / c.gcd d, _⟩
    rw [← Nat.mul_div_assoc _ (Nat.gcd_dvd_left _ _), ← Nat.mul_div_assoc _ (Nat.gcd_dvd_right _ _)]
    apply congr_arg (· / c.gcd d)
    rw [mul_comm, ← Nat.mul_div_assoc _ (Nat.gcd_dvd_left _ _), mul_comm, h,
      Nat.mul_div_assoc _ (Nat.gcd_dvd_right _ _), mul_comm]
#align rat.mk_eq Rat.divInt_eq_iff

/- warning: rat.div_mk_div_cancel_left -> Rat.divInt_mul_right is a dubious translation:
lean 3 declaration is
  forall {a : Int} {b : Int} {c : Int}, (Ne.{1} Int c (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Eq.{1} Rat (Rat.mk (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) a c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) b c)) (Rat.mk a b))
but is expected to have type
  forall {a : Int} {b : Int} {c : Int}, (Ne.{1} Int c (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Eq.{1} Rat (Rat.divInt (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) a c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) b c)) (Rat.divInt a b))
Case conversion may be inaccurate. Consider using '#align rat.div_mk_div_cancel_left Rat.divInt_mul_rightₓ'. -/
@[simp]
theorem divInt_mul_right {a b c : ℤ} (c0 : c ≠ 0) : a * c /. (b * c) = a /. b :=
  by
  by_cases b0 : b = 0;
  · subst b0
    simp
  apply (mk_eq (mul_ne_zero b0 c0) b0).2; simp [mul_comm, mul_assoc]
#align rat.div_mk_div_cancel_left Rat.divInt_mul_right

/- warning: rat.num_denom -> Rat.num_den is a dubious translation:
lean 3 declaration is
  forall {a : Rat}, Eq.{1} Rat (Rat.mk (Rat.num a) ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) (Rat.den a))) a
but is expected to have type
  forall {a : Rat}, Eq.{1} Rat (Rat.divInt (Rat.num a) (Nat.cast.{0} Int instNatCastInt (Rat.den a))) a
Case conversion may be inaccurate. Consider using '#align rat.num_denom Rat.num_denₓ'. -/
@[simp]
theorem num_den : ∀ {a : ℚ}, a.num /. a.den = a
  | ⟨n, d, h, (c : _ = 1)⟩ => show mkRat n d = _ by simp [mk_nat, ne_of_gt h, mk_pnat, c]
#align rat.num_denom Rat.num_den

/- warning: rat.num_denom' -> Rat.num_den' is a dubious translation:
lean 3 declaration is
  forall {n : Int} {d : Nat} {h : LT.lt.{0} Nat Nat.hasLt (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) d} {c : Nat.coprime (Int.natAbs n) d}, Eq.{1} Rat (Rat.mk' n d h c) (Rat.mk n ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) d))
but is expected to have type
  forall {n : Int} {d : Nat} {h : Ne.{1} Nat d (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))} {c : Nat.coprime (Int.natAbs n) d}, Eq.{1} Rat (Rat.mk' n d h c) (Rat.divInt n (Nat.cast.{0} Int instNatCastInt d))
Case conversion may be inaccurate. Consider using '#align rat.num_denom' Rat.num_den'ₓ'. -/
theorem num_den' {n d h c} : (⟨n, d, h, c⟩ : ℚ) = n /. d :=
  num_den.symm
#align rat.num_denom' Rat.num_den'

/- warning: rat.coe_int_eq_mk -> Rat.coe_int_eq_divInt is a dubious translation:
lean 3 declaration is
  forall (z : Int), Eq.{1} Rat ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Int Rat (HasLiftT.mk.{1, 1} Int Rat (CoeTCₓ.coe.{1, 1} Int Rat (Int.castCoe.{0} Rat Rat.hasIntCast))) z) (Rat.mk z (OfNat.ofNat.{0} Int 1 (OfNat.mk.{0} Int 1 (One.one.{0} Int Int.hasOne))))
but is expected to have type
  forall (z : Int), Eq.{1} Rat (Int.cast.{0} Rat Rat.instIntCastRat z) (Rat.divInt z (OfNat.ofNat.{0} Int 1 (instOfNatInt 1)))
Case conversion may be inaccurate. Consider using '#align rat.coe_int_eq_mk Rat.coe_int_eq_divIntₓ'. -/
theorem coe_int_eq_divInt (z : ℤ) : (z : ℚ) = z /. 1 :=
  num_den'
#align rat.coe_int_eq_mk Rat.coe_int_eq_divInt

/- warning: rat.num_denom_cases_on -> Rat.numDenCasesOn is a dubious translation:
lean 3 declaration is
  forall {C : Rat -> Sort.{u1}} (a : Rat), (forall (n : Int) (d : Nat), (LT.lt.{0} Nat Nat.hasLt (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) d) -> (Nat.coprime (Int.natAbs n) d) -> (C (Rat.mk n ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) d)))) -> (C a)
but is expected to have type
  forall {C : Rat -> Sort.{u1}} (a : Rat), (forall (n : [mdata borrowed:1 Int]) (d : Nat), (LT.lt.{0} Nat instLTNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)) d) -> (Nat.coprime (Int.natAbs n) d) -> (C (Rat.divInt n (Nat.cast.{0} Int instNatCastInt d)))) -> (C a)
Case conversion may be inaccurate. Consider using '#align rat.num_denom_cases_on Rat.numDenCasesOnₓ'. -/
/-- Define a (dependent) function or prove `∀ r : ℚ, p r` by dealing with rational
numbers of the form `n /. d` with `0 < d` and coprime `n`, `d`. -/
@[elab_as_elim]
def numDenCasesOn.{u} {C : ℚ → Sort u} :
    ∀ (a : ℚ) (H : ∀ n d, 0 < d → (Int.natAbs n).coprime d → C (n /. d)), C a
  | ⟨n, d, h, c⟩, H => by rw [num_denom'] <;> exact H n d h c
#align rat.num_denom_cases_on Rat.numDenCasesOn

/- warning: rat.num_denom_cases_on' -> Rat.numDenCasesOn' is a dubious translation:
lean 3 declaration is
  forall {C : Rat -> Sort.{u1}} (a : Rat), (forall (n : Int) (d : Nat), (Ne.{1} Nat d (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero)))) -> (C (Rat.mk n ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) d)))) -> (C a)
but is expected to have type
  forall {C : Rat -> Sort.{u1}} (a : Rat), (forall (n : Int) (d : Nat), (Ne.{1} Nat d (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))) -> (C (Rat.divInt n (Nat.cast.{0} Int instNatCastInt d)))) -> (C a)
Case conversion may be inaccurate. Consider using '#align rat.num_denom_cases_on' Rat.numDenCasesOn'ₓ'. -/
/-- Define a (dependent) function or prove `∀ r : ℚ, p r` by dealing with rational
numbers of the form `n /. d` with `d ≠ 0`. -/
@[elab_as_elim]
def numDenCasesOn'.{u} {C : ℚ → Sort u} (a : ℚ) (H : ∀ (n : ℤ) (d : ℕ), d ≠ 0 → C (n /. d)) : C a :=
  numDenCasesOn a fun n d h c => H n d h.ne'
#align rat.num_denom_cases_on' Rat.numDenCasesOn'

#print Rat.add /-
/-- Addition of rational numbers. Use `(+)` instead. -/
protected def add : ℚ → ℚ → ℚ
  | ⟨n₁, d₁, h₁, c₁⟩, ⟨n₂, d₂, h₂, c₂⟩ => [anonymous] (n₁ * d₂ + n₂ * d₁) ⟨d₁ * d₂, mul_pos h₁ h₂⟩
#align rat.add Rat.add
-/

instance : Add ℚ :=
  ⟨Rat.add⟩

/- warning: rat.lift_binop_eq -> Rat.lift_binop_eq is a dubious translation:
lean 3 declaration is
  forall (f : Rat -> Rat -> Rat) (f₁ : Int -> Int -> Int -> Int -> Int) (f₂ : Int -> Int -> Int -> Int -> Int), (forall {n₁ : Int} {d₁ : Nat} {h₁ : LT.lt.{0} Nat Nat.hasLt (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) d₁} {c₁ : Nat.coprime (Int.natAbs n₁) d₁} {n₂ : Int} {d₂ : Nat} {h₂ : LT.lt.{0} Nat Nat.hasLt (OfNat.ofNat.{0} Nat 0 (OfNat.mk.{0} Nat 0 (Zero.zero.{0} Nat Nat.hasZero))) d₂} {c₂ : Nat.coprime (Int.natAbs n₂) d₂}, Eq.{1} Rat (f (Rat.mk' n₁ d₁ h₁ c₁) (Rat.mk' n₂ d₂ h₂ c₂)) (Rat.mk (f₁ n₁ ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) d₁) n₂ ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) d₂)) (f₂ n₁ ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) d₁) n₂ ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) d₂)))) -> (forall {n₁ : Int} {d₁ : Int} {n₂ : Int} {d₂ : Int}, (Ne.{1} Int d₁ (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Ne.{1} Int d₂ (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Ne.{1} Int (f₂ n₁ d₁ n₂ d₂) (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero))))) -> (forall (a : Int) (b : Int) (c : Int) (d : Int), (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (forall {n₁ : Int} {d₁ : Int} {n₂ : Int} {d₂ : Int}, (Eq.{1} Int (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) a d₁) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) n₁ b)) -> (Eq.{1} Int (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) c d₂) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) n₂ d)) -> (Eq.{1} Int (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) (f₁ n₁ d₁ n₂ d₂) (f₂ a b c d)) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) (f₁ a b c d) (f₂ n₁ d₁ n₂ d₂)))) -> (Eq.{1} Rat (f (Rat.mk a b) (Rat.mk c d)) (Rat.mk (f₁ a b c d) (f₂ a b c d))))
but is expected to have type
  forall (f : Rat -> Rat -> Rat) (f₁ : Int -> Int -> Int -> Int -> Int) (f₂ : Int -> Int -> Int -> Int -> Int), (forall {n₁ : Int} {d₁ : Nat} {h₁ : Ne.{1} Nat d₁ (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))} {c₁ : Nat.coprime (Int.natAbs n₁) d₁} {n₂ : Int} {d₂ : Nat} {h₂ : Ne.{1} Nat d₂ (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))} {c₂ : Nat.coprime (Int.natAbs n₂) d₂}, Eq.{1} Rat (f (Rat.mk' n₁ d₁ h₁ c₁) (Rat.mk' n₂ d₂ h₂ c₂)) (Rat.divInt (f₁ n₁ (Nat.cast.{0} Int instNatCastInt d₁) n₂ (Nat.cast.{0} Int instNatCastInt d₂)) (f₂ n₁ (Nat.cast.{0} Int instNatCastInt d₁) n₂ (Nat.cast.{0} Int instNatCastInt d₂)))) -> (forall {n₁ : Int} {d₁ : Int} {n₂ : Int} {d₂ : Int}, (Ne.{1} Int d₁ (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Ne.{1} Int d₂ (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Ne.{1} Int (f₂ n₁ d₁ n₂ d₂) (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)))) -> (forall (a : Int) (b : Int) (c : Int) (d : Int), (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (forall {n₁ : Int} {d₁ : Int} {n₂ : Int} {d₂ : Int}, (Eq.{1} Int (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) a d₁) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) n₁ b)) -> (Eq.{1} Int (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) c d₂) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) n₂ d)) -> (Eq.{1} Int (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) (f₁ n₁ d₁ n₂ d₂) (f₂ a b c d)) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) (f₁ a b c d) (f₂ n₁ d₁ n₂ d₂)))) -> (Eq.{1} Rat (f (Rat.divInt a b) (Rat.divInt c d)) (Rat.divInt (f₁ a b c d) (f₂ a b c d))))
Case conversion may be inaccurate. Consider using '#align rat.lift_binop_eq Rat.lift_binop_eqₓ'. -/
theorem lift_binop_eq (f : ℚ → ℚ → ℚ) (f₁ : ℤ → ℤ → ℤ → ℤ → ℤ) (f₂ : ℤ → ℤ → ℤ → ℤ → ℤ)
    (fv :
      ∀ {n₁ d₁ h₁ c₁ n₂ d₂ h₂ c₂},
        f ⟨n₁, d₁, h₁, c₁⟩ ⟨n₂, d₂, h₂, c₂⟩ = f₁ n₁ d₁ n₂ d₂ /. f₂ n₁ d₁ n₂ d₂)
    (f0 : ∀ {n₁ d₁ n₂ d₂} (d₁0 : d₁ ≠ 0) (d₂0 : d₂ ≠ 0), f₂ n₁ d₁ n₂ d₂ ≠ 0) (a b c d : ℤ)
    (b0 : b ≠ 0) (d0 : d ≠ 0)
    (H :
      ∀ {n₁ d₁ n₂ d₂} (h₁ : a * d₁ = n₁ * b) (h₂ : c * d₂ = n₂ * d),
        f₁ n₁ d₁ n₂ d₂ * f₂ a b c d = f₁ a b c d * f₂ n₁ d₁ n₂ d₂) :
    f (a /. b) (c /. d) = f₁ a b c d /. f₂ a b c d :=
  by
  generalize ha : a /. b = x; cases' x with n₁ d₁ h₁ c₁; rw [num_denom'] at ha
  generalize hc : c /. d = x; cases' x with n₂ d₂ h₂ c₂; rw [num_denom'] at hc
  rw [fv]
  have d₁0 := ne_of_gt (Int.ofNat_lt.2 h₁)
  have d₂0 := ne_of_gt (Int.ofNat_lt.2 h₂)
  exact (mk_eq (f0 d₁0 d₂0) (f0 b0 d0)).2 (H ((mk_eq b0 d₁0).1 ha) ((mk_eq d0 d₂0).1 hc))
#align rat.lift_binop_eq Rat.lift_binop_eq

/- warning: rat.add_def -> Rat.add_def'' is a dubious translation:
lean 3 declaration is
  forall {a : Int} {b : Int} {c : Int} {d : Int}, (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Eq.{1} Rat (HAdd.hAdd.{0, 0, 0} Rat Rat Rat (instHAdd.{0} Rat Rat.hasAdd) (Rat.mk a b) (Rat.mk c d)) (Rat.mk (HAdd.hAdd.{0, 0, 0} Int Int Int (instHAdd.{0} Int Int.hasAdd) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) a d) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) c b)) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) b d)))
but is expected to have type
  forall {a : Int} {b : Int} {c : Int} {d : Int}, (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Eq.{1} Rat (HAdd.hAdd.{0, 0, 0} Rat Rat Rat (instHAdd.{0} Rat Rat.instAddRat) (Rat.divInt a b) (Rat.divInt c d)) (Rat.divInt (HAdd.hAdd.{0, 0, 0} Int Int Int (instHAdd.{0} Int Int.instAddInt) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) a d) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) c b)) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) b d)))
Case conversion may be inaccurate. Consider using '#align rat.add_def Rat.add_def''ₓ'. -/
@[simp]
theorem add_def'' {a b c d : ℤ} (b0 : b ≠ 0) (d0 : d ≠ 0) :
    a /. b + c /. d = (a * d + c * b) /. (b * d) :=
  by
  apply lift_binop_eq Rat.add <;> intros <;> try assumption
  · apply mk_pnat_eq
  · apply mul_ne_zero d₁0 d₂0
  calc
    (n₁ * d₂ + n₂ * d₁) * (b * d) = n₁ * b * d₂ * d + n₂ * d * (d₁ * b) := by
      simp [mul_add, mul_comm, mul_left_comm]
    _ = a * d₁ * d₂ * d + c * d₂ * (d₁ * b) := by rw [h₁, h₂]
    _ = (a * d + c * b) * (d₁ * d₂) := by simp [mul_add, mul_comm, mul_left_comm]

#align rat.add_def Rat.add_def''

#print Rat.neg /-
/-- Negation of rational numbers. Use `-r` instead. -/
protected def neg (r : ℚ) : ℚ :=
  ⟨-r.num, r.den, r.Pos, by simp [r.cop]⟩
#align rat.neg Rat.neg
-/

instance : Neg ℚ :=
  ⟨Rat.neg⟩

/- warning: rat.neg_def -> Rat.neg_def is a dubious translation:
lean 3 declaration is
  forall {a : Int} {b : Int}, Eq.{1} Rat (Neg.neg.{0} Rat Rat.hasNeg (Rat.mk a b)) (Rat.mk (Neg.neg.{0} Int Int.hasNeg a) b)
but is expected to have type
  forall {a : Int} {b : Int}, Eq.{1} Rat (Neg.neg.{0} Rat Rat.instNegRat (Rat.divInt a b)) (Rat.divInt (Neg.neg.{0} Int Int.instNegInt a) b)
Case conversion may be inaccurate. Consider using '#align rat.neg_def Rat.neg_defₓ'. -/
@[simp]
theorem neg_def {a b : ℤ} : -(a /. b) = -a /. b :=
  by
  by_cases b0 : b = 0;
  · subst b0
    simp
    rfl
  generalize ha : a /. b = x; cases' x with n₁ d₁ h₁ c₁; rw [num_denom'] at ha
  show Rat.mk' _ _ _ _ = _; rw [num_denom']
  have d0 := ne_of_gt (Int.ofNat_lt.2 h₁)
  apply (mk_eq d0 b0).2; have h₁ := (mk_eq b0 d0).1 ha
  simp only [neg_mul, congr_arg Neg.neg h₁]
#align rat.neg_def Rat.neg_def

/- warning: rat.mk_neg_denom -> Rat.divInt_neg_den is a dubious translation:
lean 3 declaration is
  forall (n : Int) (d : Int), Eq.{1} Rat (Rat.mk n (Neg.neg.{0} Int Int.hasNeg d)) (Rat.mk (Neg.neg.{0} Int Int.hasNeg n) d)
but is expected to have type
  forall (n : Int) (d : Int), Eq.{1} Rat (Rat.divInt n (Neg.neg.{0} Int Int.instNegInt d)) (Rat.divInt (Neg.neg.{0} Int Int.instNegInt n) d)
Case conversion may be inaccurate. Consider using '#align rat.mk_neg_denom Rat.divInt_neg_denₓ'. -/
@[simp]
theorem divInt_neg_den (n d : ℤ) : n /. -d = -n /. d := by
  by_cases hd : d = 0 <;> simp [Rat.divInt_eq_iff, hd]
#align rat.mk_neg_denom Rat.divInt_neg_den

#print Rat.mul /-
/-- Multiplication of rational numbers. Use `(*)` instead. -/
protected def mul : ℚ → ℚ → ℚ
  | ⟨n₁, d₁, h₁, c₁⟩, ⟨n₂, d₂, h₂, c₂⟩ => [anonymous] (n₁ * n₂) ⟨d₁ * d₂, mul_pos h₁ h₂⟩
#align rat.mul Rat.mul
-/

instance : Mul ℚ :=
  ⟨Rat.mul⟩

/- warning: rat.mul_def -> Rat.mul_def' is a dubious translation:
lean 3 declaration is
  forall {a : Int} {b : Int} {c : Int} {d : Int}, (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Eq.{1} Rat (HMul.hMul.{0, 0, 0} Rat Rat Rat (instHMul.{0} Rat Rat.hasMul) (Rat.mk a b) (Rat.mk c d)) (Rat.mk (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) a c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) b d)))
but is expected to have type
  forall {a : Int} {b : Int} {c : Int} {d : Int}, (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Eq.{1} Rat (HMul.hMul.{0, 0, 0} Rat Rat Rat (instHMul.{0} Rat Rat.instMulRat) (Rat.divInt a b) (Rat.divInt c d)) (Rat.divInt (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) a c) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) b d)))
Case conversion may be inaccurate. Consider using '#align rat.mul_def Rat.mul_def'ₓ'. -/
@[simp]
theorem mul_def' {a b c d : ℤ} (b0 : b ≠ 0) (d0 : d ≠ 0) : a /. b * (c /. d) = a * c /. (b * d) :=
  by
  apply lift_binop_eq Rat.mul <;> intros <;> try assumption
  · apply mk_pnat_eq
  · apply mul_ne_zero d₁0 d₂0
  cc
#align rat.mul_def Rat.mul_def'

#print Rat.inv /-
/-- Inverse rational number. Use `r⁻¹` instead. -/
protected def inv : ℚ → ℚ
  | ⟨(n + 1 : ℕ), d, h, c⟩ => ⟨d, n + 1, n.succ_pos, c.symm⟩
  | ⟨0, d, h, c⟩ => 0
  | ⟨-[n+1], d, h, c⟩ => ⟨-d, n + 1, n.succ_pos, Nat.coprime.symm <| by simp <;> exact c⟩
#align rat.inv Rat.inv
-/

instance : Inv ℚ :=
  ⟨Rat.inv⟩

instance : Div ℚ :=
  ⟨fun a b => a * b⁻¹⟩

/- warning: rat.inv_def -> Rat.inv_def' is a dubious translation:
lean 3 declaration is
  forall {a : Int} {b : Int}, Eq.{1} Rat (Inv.inv.{0} Rat Rat.hasInv (Rat.mk a b)) (Rat.mk b a)
but is expected to have type
  forall {a : Int} {b : Int}, Eq.{1} Rat (Inv.inv.{0} Rat Rat.instInvRat (Rat.divInt a b)) (Rat.divInt b a)
Case conversion may be inaccurate. Consider using '#align rat.inv_def Rat.inv_def'ₓ'. -/
@[simp]
theorem inv_def' {a b : ℤ} : (a /. b)⁻¹ = b /. a :=
  by
  by_cases a0 : a = 0
  · subst a0
    simp
    rfl
  by_cases b0 : b = 0
  · subst b0
    simp
    rfl
  generalize ha : a /. b = x
  cases' x with n d h c
  rw [num_denom'] at ha
  refine' Eq.trans (_ : Rat.inv ⟨n, d, h, c⟩ = d /. n) _
  · cases' n with n <;> [cases' n with n, skip]
    · rfl
    · change Int.ofNat n.succ with (n + 1 : ℕ)
      unfold Rat.inv
      rw [num_denom']
    · unfold Rat.inv
      rw [num_denom']
      rfl
  have n0 : n ≠ 0 := by
    rintro rfl
    rw [Rat.zero_divInt, mk_eq_zero b0] at ha
    exact a0 ha
  have d0 := ne_of_gt (Int.ofNat_lt.2 h)
  have ha := (mk_eq b0 d0).1 ha
  apply (mk_eq n0 a0).2
  cc
#align rat.inv_def Rat.inv_def'

variable (a b c : ℚ)

#print Rat.add_zero /-
protected theorem add_zero : a + 0 = a :=
  numDenCasesOn' a fun n d h => by rw [← zero_mk d] <;> simp [h, -zero_mk]
#align rat.add_zero Rat.add_zero
-/

#print Rat.zero_add /-
protected theorem zero_add : 0 + a = a :=
  numDenCasesOn' a fun n d h => by rw [← zero_mk d] <;> simp [h, -zero_mk]
#align rat.zero_add Rat.zero_add
-/

#print Rat.add_comm /-
protected theorem add_comm : a + b = b + a :=
  numDenCasesOn' a fun n₁ d₁ h₁ => numDenCasesOn' b fun n₂ d₂ h₂ => by simp [h₁, h₂] <;> cc
#align rat.add_comm Rat.add_comm
-/

#print Rat.add_assoc /-
protected theorem add_assoc : a + b + c = a + (b + c) :=
  numDenCasesOn' a fun n₁ d₁ h₁ =>
    numDenCasesOn' b fun n₂ d₂ h₂ =>
      numDenCasesOn' c fun n₃ d₃ h₃ => by
        simp [h₁, h₂, h₃, mul_ne_zero, mul_add, mul_comm, mul_left_comm, add_left_comm, add_assoc]
#align rat.add_assoc Rat.add_assoc
-/

#print Rat.add_left_neg /-
protected theorem add_left_neg : -a + a = 0 :=
  numDenCasesOn' a fun n d h => by simp [h]
#align rat.add_left_neg Rat.add_left_neg
-/

/- warning: rat.mk_zero_one -> Rat.divInt_zero_one is a dubious translation:
lean 3 declaration is
  Eq.{1} Rat (Rat.mk (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero))) (OfNat.ofNat.{0} Int 1 (OfNat.mk.{0} Int 1 (One.one.{0} Int Int.hasOne)))) (OfNat.ofNat.{0} Rat 0 (OfNat.mk.{0} Rat 0 (Zero.zero.{0} Rat Rat.hasZero)))
but is expected to have type
  Eq.{1} Rat (Rat.divInt (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)) (OfNat.ofNat.{0} Int 1 (instOfNatInt 1))) (OfNat.ofNat.{0} Rat 0 (Rat.instOfNatRat 0))
Case conversion may be inaccurate. Consider using '#align rat.mk_zero_one Rat.divInt_zero_oneₓ'. -/
@[simp]
theorem divInt_zero_one : 0 /. 1 = 0 :=
  show [anonymous] _ _ = _ by
    rw [mk_pnat]
    simp
    rfl
#align rat.mk_zero_one Rat.divInt_zero_one

/- warning: rat.mk_one_one -> Rat.divInt_one_one is a dubious translation:
lean 3 declaration is
  Eq.{1} Rat (Rat.mk (OfNat.ofNat.{0} Int 1 (OfNat.mk.{0} Int 1 (One.one.{0} Int Int.hasOne))) (OfNat.ofNat.{0} Int 1 (OfNat.mk.{0} Int 1 (One.one.{0} Int Int.hasOne)))) (OfNat.ofNat.{0} Rat 1 (OfNat.mk.{0} Rat 1 (One.one.{0} Rat Rat.hasOne)))
but is expected to have type
  Eq.{1} Rat (Rat.divInt (OfNat.ofNat.{0} Int 1 (instOfNatInt 1)) (OfNat.ofNat.{0} Int 1 (instOfNatInt 1))) (OfNat.ofNat.{0} Rat 1 (Rat.instOfNatRat 1))
Case conversion may be inaccurate. Consider using '#align rat.mk_one_one Rat.divInt_one_oneₓ'. -/
@[simp]
theorem divInt_one_one : 1 /. 1 = 1 :=
  show [anonymous] _ _ = _ by
    rw [mk_pnat]
    simp
    rfl
#align rat.mk_one_one Rat.divInt_one_one

/- warning: rat.mk_neg_one_one -> Rat.divInt_neg_one_one is a dubious translation:
lean 3 declaration is
  Eq.{1} Rat (Rat.mk (Neg.neg.{0} Int Int.hasNeg (OfNat.ofNat.{0} Int 1 (OfNat.mk.{0} Int 1 (One.one.{0} Int Int.hasOne)))) (OfNat.ofNat.{0} Int 1 (OfNat.mk.{0} Int 1 (One.one.{0} Int Int.hasOne)))) (Neg.neg.{0} Rat Rat.hasNeg (OfNat.ofNat.{0} Rat 1 (OfNat.mk.{0} Rat 1 (One.one.{0} Rat Rat.hasOne))))
but is expected to have type
  Eq.{1} Rat (Rat.divInt (Neg.neg.{0} Int Int.instNegInt (OfNat.ofNat.{0} Int 1 (instOfNatInt 1))) (OfNat.ofNat.{0} Int 1 (instOfNatInt 1))) (Neg.neg.{0} Rat Rat.instNegRat (OfNat.ofNat.{0} Rat 1 (Rat.instOfNatRat 1)))
Case conversion may be inaccurate. Consider using '#align rat.mk_neg_one_one Rat.divInt_neg_one_oneₓ'. -/
@[simp]
theorem divInt_neg_one_one : -1 /. 1 = -1 :=
  show [anonymous] _ _ = _ by
    rw [mk_pnat]
    simp
    rfl
#align rat.mk_neg_one_one Rat.divInt_neg_one_one

#print Rat.mul_one /-
protected theorem mul_one : a * 1 = a :=
  numDenCasesOn' a fun n d h => by
    rw [← mk_one_one]
    simp [h, -mk_one_one]
#align rat.mul_one Rat.mul_one
-/

#print Rat.one_mul /-
protected theorem one_mul : 1 * a = a :=
  numDenCasesOn' a fun n d h => by
    rw [← mk_one_one]
    simp [h, -mk_one_one]
#align rat.one_mul Rat.one_mul
-/

#print Rat.mul_comm /-
protected theorem mul_comm : a * b = b * a :=
  numDenCasesOn' a fun n₁ d₁ h₁ => numDenCasesOn' b fun n₂ d₂ h₂ => by simp [h₁, h₂, mul_comm]
#align rat.mul_comm Rat.mul_comm
-/

#print Rat.mul_assoc /-
protected theorem mul_assoc : a * b * c = a * (b * c) :=
  numDenCasesOn' a fun n₁ d₁ h₁ =>
    numDenCasesOn' b fun n₂ d₂ h₂ =>
      numDenCasesOn' c fun n₃ d₃ h₃ => by simp [h₁, h₂, h₃, mul_ne_zero, mul_comm, mul_left_comm]
#align rat.mul_assoc Rat.mul_assoc
-/

#print Rat.add_mul /-
protected theorem add_mul : (a + b) * c = a * c + b * c :=
  numDenCasesOn' a fun n₁ d₁ h₁ =>
    numDenCasesOn' b fun n₂ d₂ h₂ =>
      numDenCasesOn' c fun n₃ d₃ h₃ => by
        simp [h₁, h₂, h₃, mul_ne_zero] <;>
            refine' (div_mk_div_cancel_left (Int.coe_nat_ne_zero.2 h₃)).symm.trans _ <;>
          simp [mul_add, mul_comm, mul_assoc, mul_left_comm]
#align rat.add_mul Rat.add_mul
-/

#print Rat.mul_add /-
protected theorem mul_add : a * (b + c) = a * b + a * c := by
  rw [Rat.mul_comm, Rat.add_mul, Rat.mul_comm, Rat.mul_comm c a]
#align rat.mul_add Rat.mul_add
-/

#print Rat.zero_ne_one /-
protected theorem zero_ne_one : 0 ≠ (1 : ℚ) :=
  by
  rw [ne_comm, ← mk_one_one, mk_ne_zero one_ne_zero]
  exact one_ne_zero
#align rat.zero_ne_one Rat.zero_ne_one
-/

#print Rat.mul_inv_cancel /-
protected theorem mul_inv_cancel : a ≠ 0 → a * a⁻¹ = 1 :=
  numDenCasesOn' a fun n d h a0 =>
    by
    have n0 : n ≠ 0 :=
      mt
        (by
          rintro rfl
          simp)
        a0
    simpa [h, n0, mul_comm] using @div_mk_div_cancel_left 1 1 _ n0
#align rat.mul_inv_cancel Rat.mul_inv_cancel
-/

#print Rat.inv_mul_cancel /-
protected theorem inv_mul_cancel (h : a ≠ 0) : a⁻¹ * a = 1 :=
  Eq.trans (Rat.mul_comm _ _) (Rat.mul_inv_cancel _ h)
#align rat.inv_mul_cancel Rat.inv_mul_cancel
-/

/- ./././Mathport/Syntax/Translate/Tactic/Builtin.lean:69:18: unsupported non-interactive tactic tactic.mk_dec_eq_instance -/
instance : DecidableEq ℚ := by
  run_tac
    tactic.mk_dec_eq_instance

/-! At this point in the import hierarchy we have not defined the `field` typeclass.
Instead we'll instantiate `comm_ring` and `comm_group_with_zero` at this point.
The `rat.field` instance and any field-specific lemmas can be found in `data.rat.basic`.
-/

instance : CommRing ℚ where
  zero := 0
  add := (· + ·)
  neg := Neg.neg
  one := 1
  mul := (· * ·)
  zero_add := Rat.zero_add
  add_zero := Rat.add_zero
  add_comm := Rat.add_comm
  add_assoc := Rat.add_assoc
  add_left_neg := Rat.add_left_neg
  mul_one := Rat.mul_one
  one_mul := Rat.one_mul
  mul_comm := Rat.mul_comm
  mul_assoc := Rat.mul_assoc
  left_distrib := Rat.mul_add
  right_distrib := Rat.add_mul
  intCast := coe
  /- Important: We do not set `nat_cast := λ n, ((n : ℤ) : ℚ)` (even though it's defeq) as that
    makes `int.cast_coe_nat` and `coe_coe` loop in `simp`. -/
  natCast n := ofInt n
  natCast_zero := rfl
  natCast_succ n := by
    simp only [of_int_eq_cast, coe_int_eq_mk, add_def one_ne_zero one_ne_zero, ← mk_one_one,
      Nat.cast_add, Nat.cast_one, mul_one]

instance : CommGroupWithZero ℚ :=
  { Rat.commRing with
    zero := 0
    one := 1
    mul := (· * ·)
    inv := Inv.inv
    div := (· / ·)
    exists_pair_ne := ⟨0, 1, Rat.zero_ne_one⟩
    inv_zero := rfl
    mul_inv_cancel := Rat.mul_inv_cancel
    mul_zero := MulZeroClass.mul_zero
    zero_mul := MulZeroClass.zero_mul }

instance : IsDomain ℚ :=
  NoZeroDivisors.to_isDomain _

-- Extra instances to short-circuit type class resolution
-- TODO(Mario): this instance slows down data.real.basic
instance : Nontrivial ℚ := by infer_instance

--instance : ring ℚ             := by apply_instance
instance : CommSemiring ℚ := by infer_instance

instance : Semiring ℚ := by infer_instance

instance : AddCommGroup ℚ := by infer_instance

instance : AddGroup ℚ := by infer_instance

instance : AddCommMonoid ℚ := by infer_instance

instance : AddMonoid ℚ := by infer_instance

instance : AddLeftCancelSemigroup ℚ := by infer_instance

instance : AddRightCancelSemigroup ℚ := by infer_instance

instance : AddCommSemigroup ℚ := by infer_instance

instance : AddSemigroup ℚ := by infer_instance

instance : CommMonoid ℚ := by infer_instance

instance : Monoid ℚ := by infer_instance

instance : CommSemigroup ℚ := by infer_instance

instance : Semigroup ℚ := by infer_instance

#print Rat.den_nz /-
theorem den_nz (q : ℚ) : q.den ≠ 0 :=
  ne_of_gt q.Pos
#align rat.denom_ne_zero Rat.den_nz
-/

#print Rat.eq_iff_mul_eq_mul /-
theorem eq_iff_mul_eq_mul {p q : ℚ} : p = q ↔ p.num * q.den = q.num * p.den :=
  by
  conv =>
    lhs
    rw [← @num_denom p, ← @num_denom q]
  apply Rat.divInt_eq_iff <;>
    · rw [← Nat.cast_zero, Ne, Int.ofNat_inj]
      apply denom_ne_zero
#align rat.eq_iff_mul_eq_mul Rat.eq_iff_mul_eq_mul
-/

/- warning: rat.sub_def -> Rat.sub_def'' is a dubious translation:
lean 3 declaration is
  forall {a : Int} {b : Int} {c : Int} {d : Int}, (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Eq.{1} Rat (HSub.hSub.{0, 0, 0} Rat Rat Rat (instHSub.{0} Rat (SubNegMonoid.toHasSub.{0} Rat (AddGroup.toSubNegMonoid.{0} Rat Rat.addGroup))) (Rat.mk a b) (Rat.mk c d)) (Rat.mk (HSub.hSub.{0, 0, 0} Int Int Int (instHSub.{0} Int Int.hasSub) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) a d) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) c b)) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) b d)))
but is expected to have type
  forall {a : Int} {b : Int} {c : Int} {d : Int}, (Ne.{1} Int b (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Eq.{1} Rat (HSub.hSub.{0, 0, 0} Rat Rat Rat (instHSub.{0} Rat Rat.instSubRat) (Rat.divInt a b) (Rat.divInt c d)) (Rat.divInt (HSub.hSub.{0, 0, 0} Int Int Int (instHSub.{0} Int Int.instSubInt) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) a d) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) c b)) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) b d)))
Case conversion may be inaccurate. Consider using '#align rat.sub_def Rat.sub_def''ₓ'. -/
theorem sub_def'' {a b c d : ℤ} (b0 : b ≠ 0) (d0 : d ≠ 0) :
    a /. b - c /. d = (a * d - c * b) /. (b * d) := by simp [b0, d0, sub_eq_add_neg]
#align rat.sub_def Rat.sub_def''

#print Rat.den_neg_eq_den /-
@[simp]
theorem den_neg_eq_den (q : ℚ) : (-q).den = q.den :=
  rfl
#align rat.denom_neg_eq_denom Rat.den_neg_eq_den
-/

#print Rat.num_neg_eq_neg_num /-
@[simp]
theorem num_neg_eq_neg_num (q : ℚ) : (-q).num = -q.num :=
  rfl
#align rat.num_neg_eq_neg_num Rat.num_neg_eq_neg_num
-/

#print Rat.num_zero /-
@[simp]
theorem num_zero : Rat.num 0 = 0 :=
  rfl
#align rat.num_zero Rat.num_zero
-/

#print Rat.den_zero /-
@[simp]
theorem den_zero : Rat.den 0 = 1 :=
  rfl
#align rat.denom_zero Rat.den_zero
-/

#print Rat.zero_of_num_zero /-
theorem zero_of_num_zero {q : ℚ} (hq : q.num = 0) : q = 0 :=
  by
  have : q = q.num /. q.den := num_den.symm
  simpa [hq]
#align rat.zero_of_num_zero Rat.zero_of_num_zero
-/

#print Rat.zero_iff_num_zero /-
theorem zero_iff_num_zero {q : ℚ} : q = 0 ↔ q.num = 0 :=
  ⟨fun _ => by simp [*], zero_of_num_zero⟩
#align rat.zero_iff_num_zero Rat.zero_iff_num_zero
-/

#print Rat.num_ne_zero_of_ne_zero /-
theorem num_ne_zero_of_ne_zero {q : ℚ} (h : q ≠ 0) : q.num ≠ 0 := fun this : q.num = 0 =>
  h <| zero_of_num_zero this
#align rat.num_ne_zero_of_ne_zero Rat.num_ne_zero_of_ne_zero
-/

#print Rat.num_one /-
@[simp]
theorem num_one : (1 : ℚ).num = 1 :=
  rfl
#align rat.num_one Rat.num_one
-/

#print Rat.den_one /-
@[simp]
theorem den_one : (1 : ℚ).den = 1 :=
  rfl
#align rat.denom_one Rat.den_one
-/

/- warning: rat.mk_num_ne_zero_of_ne_zero -> Rat.mk_num_ne_zero_of_ne_zero is a dubious translation:
lean 3 declaration is
  forall {q : Rat} {n : Int} {d : Int}, (Ne.{1} Rat q (OfNat.ofNat.{0} Rat 0 (OfNat.mk.{0} Rat 0 (Zero.zero.{0} Rat Rat.hasZero)))) -> (Eq.{1} Rat q (Rat.mk n d)) -> (Ne.{1} Int n (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero))))
but is expected to have type
  forall {q : Rat} {n : Int} {d : Int}, (Ne.{1} Rat q (OfNat.ofNat.{0} Rat 0 (Rat.instOfNatRat 0))) -> (Eq.{1} Rat q (Rat.divInt n d)) -> (Ne.{1} Int n (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)))
Case conversion may be inaccurate. Consider using '#align rat.mk_num_ne_zero_of_ne_zero Rat.mk_num_ne_zero_of_ne_zeroₓ'. -/
theorem mk_num_ne_zero_of_ne_zero {q : ℚ} {n d : ℤ} (hq : q ≠ 0) (hqnd : q = n /. d) : n ≠ 0 :=
  fun this : n = 0 => hq <| by simpa [this] using hqnd
#align rat.mk_num_ne_zero_of_ne_zero Rat.mk_num_ne_zero_of_ne_zero

/- warning: rat.mk_denom_ne_zero_of_ne_zero -> Rat.mk_denom_ne_zero_of_ne_zero is a dubious translation:
lean 3 declaration is
  forall {q : Rat} {n : Int} {d : Int}, (Ne.{1} Rat q (OfNat.ofNat.{0} Rat 0 (OfNat.mk.{0} Rat 0 (Zero.zero.{0} Rat Rat.hasZero)))) -> (Eq.{1} Rat q (Rat.mk n d)) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero))))
but is expected to have type
  forall {q : Rat} {n : Int} {d : Int}, (Ne.{1} Rat q (OfNat.ofNat.{0} Rat 0 (Rat.instOfNatRat 0))) -> (Eq.{1} Rat q (Rat.divInt n d)) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (instOfNatInt 0)))
Case conversion may be inaccurate. Consider using '#align rat.mk_denom_ne_zero_of_ne_zero Rat.mk_denom_ne_zero_of_ne_zeroₓ'. -/
theorem mk_denom_ne_zero_of_ne_zero {q : ℚ} {n d : ℤ} (hq : q ≠ 0) (hqnd : q = n /. d) : d ≠ 0 :=
  fun this : d = 0 => hq <| by simpa [this] using hqnd
#align rat.mk_denom_ne_zero_of_ne_zero Rat.mk_denom_ne_zero_of_ne_zero

/- warning: rat.mk_ne_zero_of_ne_zero -> Rat.divInt_ne_zero_of_ne_zero is a dubious translation:
lean 3 declaration is
  forall {n : Int} {d : Int}, (Ne.{1} Int n (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (Ne.{1} Rat (Rat.mk n d) (OfNat.ofNat.{0} Rat 0 (OfNat.mk.{0} Rat 0 (Zero.zero.{0} Rat Rat.hasZero))))
but is expected to have type
  forall {n : Int} {d : Int}, (Ne.{1} Int n (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Ne.{1} Int d (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (Ne.{1} Rat (Rat.divInt n d) (OfNat.ofNat.{0} Rat 0 (Rat.instOfNatRat 0)))
Case conversion may be inaccurate. Consider using '#align rat.mk_ne_zero_of_ne_zero Rat.divInt_ne_zero_of_ne_zeroₓ'. -/
theorem divInt_ne_zero_of_ne_zero {n d : ℤ} (h : n ≠ 0) (hd : d ≠ 0) : n /. d ≠ 0 :=
  (divInt_ne_zero hd).mpr h
#align rat.mk_ne_zero_of_ne_zero Rat.divInt_ne_zero_of_ne_zero

/- warning: rat.mul_num_denom -> Rat.mul_num_den is a dubious translation:
lean 3 declaration is
  forall (q : Rat) (r : Rat), Eq.{1} Rat (HMul.hMul.{0, 0, 0} Rat Rat Rat (instHMul.{0} Rat Rat.hasMul) q r) (Rat.mk (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) (Rat.num q) (Rat.num r)) ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat Nat.hasMul) (Rat.den q) (Rat.den r))))
but is expected to have type
  forall (q : Rat) (r : Rat), Eq.{1} Rat (HMul.hMul.{0, 0, 0} Rat Rat Rat (instHMul.{0} Rat Rat.instMulRat) q r) (Rat.divInt (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) (Rat.num q) (Rat.num r)) (Nat.cast.{0} Int instNatCastInt (HMul.hMul.{0, 0, 0} Nat Nat Nat (instHMul.{0} Nat instMulNat) (Rat.den q) (Rat.den r))))
Case conversion may be inaccurate. Consider using '#align rat.mul_num_denom Rat.mul_num_denₓ'. -/
theorem mul_num_den (q r : ℚ) : q * r = q.num * r.num /. ↑(q.den * r.den) :=
  by
  have hq' : (↑q.den : ℤ) ≠ 0 := by have := denom_ne_zero q <;> simpa
  have hr' : (↑r.den : ℤ) ≠ 0 := by have := denom_ne_zero r <;> simpa
  suffices q.num /. ↑q.den * (r.num /. ↑r.den) = q.num * r.num /. ↑(q.den * r.den) by
    simpa using this
  simp [mul_def hq' hr', -num_denom]
#align rat.mul_num_denom Rat.mul_num_den

/- warning: rat.div_num_denom -> Rat.div_num_den is a dubious translation:
lean 3 declaration is
  forall (q : Rat) (r : Rat), Eq.{1} Rat (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.hasDiv) q r) (Rat.mk (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) (Rat.num q) ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) (Rat.den r))) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.hasMul) ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) (Rat.den q)) (Rat.num r)))
but is expected to have type
  forall (q : Rat) (r : Rat), Eq.{1} Rat (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.instDivRat) q r) (Rat.divInt (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) (Rat.num q) (Nat.cast.{0} Int instNatCastInt (Rat.den r))) (HMul.hMul.{0, 0, 0} Int Int Int (instHMul.{0} Int Int.instMulInt) (Nat.cast.{0} Int instNatCastInt (Rat.den q)) (Rat.num r)))
Case conversion may be inaccurate. Consider using '#align rat.div_num_denom Rat.div_num_denₓ'. -/
theorem div_num_den (q r : ℚ) : q / r = q.num * r.den /. (q.den * r.num) :=
  if hr : r.num = 0 then by
    have hr' : r = 0 := zero_of_num_zero hr
    simp [*]
  else
    calc
      q / r = q * r⁻¹ := div_eq_mul_inv q r
      _ = q.num /. q.den * (r.num /. r.den)⁻¹ := by simp
      _ = q.num /. q.den * (r.den /. r.num) := by rw [inv_def]
      _ = q.num * r.den /. (q.den * r.num) := mul_def' (by simpa using denom_ne_zero q) hr

#align rat.div_num_denom Rat.div_num_den

section Casts

/- warning: rat.add_mk -> Rat.add_divInt is a dubious translation:
lean 3 declaration is
  forall (a : Int) (b : Int) (c : Int), Eq.{1} Rat (Rat.mk (HAdd.hAdd.{0, 0, 0} Int Int Int (instHAdd.{0} Int Int.hasAdd) a b) c) (HAdd.hAdd.{0, 0, 0} Rat Rat Rat (instHAdd.{0} Rat Rat.hasAdd) (Rat.mk a c) (Rat.mk b c))
but is expected to have type
  forall (a : Int) (b : Int) (c : Int), Eq.{1} Rat (Rat.divInt (HAdd.hAdd.{0, 0, 0} Int Int Int (instHAdd.{0} Int Int.instAddInt) a b) c) (HAdd.hAdd.{0, 0, 0} Rat Rat Rat (instHAdd.{0} Rat Rat.instAddRat) (Rat.divInt a c) (Rat.divInt b c))
Case conversion may be inaccurate. Consider using '#align rat.add_mk Rat.add_divIntₓ'. -/
protected theorem add_divInt (a b c : ℤ) : (a + b) /. c = a /. c + b /. c :=
  if h : c = 0 then by simp [h]
  else by
    rw [add_def h h, mk_eq h (mul_ne_zero h h)]
    simp [add_mul, mul_assoc]
#align rat.add_mk Rat.add_divInt

/- warning: rat.mk_eq_div -> Rat.divInt_eq_div is a dubious translation:
lean 3 declaration is
  forall (n : Int) (d : Int), Eq.{1} Rat (Rat.mk n d) (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.hasDiv) ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Int Rat (HasLiftT.mk.{1, 1} Int Rat (CoeTCₓ.coe.{1, 1} Int Rat (Int.castCoe.{0} Rat Rat.hasIntCast))) n) ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Int Rat (HasLiftT.mk.{1, 1} Int Rat (CoeTCₓ.coe.{1, 1} Int Rat (Int.castCoe.{0} Rat Rat.hasIntCast))) d))
but is expected to have type
  forall (n : Int) (d : Int), Eq.{1} Rat (Rat.divInt n d) (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.instDivRat) (Int.cast.{0} Rat Rat.instIntCastRat n) (Int.cast.{0} Rat Rat.instIntCastRat d))
Case conversion may be inaccurate. Consider using '#align rat.mk_eq_div Rat.divInt_eq_divₓ'. -/
theorem divInt_eq_div (n d : ℤ) : n /. d = (n : ℚ) / d :=
  by
  by_cases d0 : d = 0; · simp [d0, div_zero]
  simp [division_def, coe_int_eq_mk, mul_def one_ne_zero d0]
#align rat.mk_eq_div Rat.divInt_eq_div

/- warning: rat.mk_mul_mk_cancel -> Rat.divInt_mul_divInt_cancel is a dubious translation:
lean 3 declaration is
  forall {x : Int}, (Ne.{1} Int x (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (forall (n : Int) (d : Int), Eq.{1} Rat (HMul.hMul.{0, 0, 0} Rat Rat Rat (instHMul.{0} Rat Rat.hasMul) (Rat.mk n x) (Rat.mk x d)) (Rat.mk n d))
but is expected to have type
  forall {x : Int}, (Ne.{1} Int x (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (forall (n : Int) (d : Int), Eq.{1} Rat (HMul.hMul.{0, 0, 0} Rat Rat Rat (instHMul.{0} Rat Rat.instMulRat) (Rat.divInt n x) (Rat.divInt x d)) (Rat.divInt n d))
Case conversion may be inaccurate. Consider using '#align rat.mk_mul_mk_cancel Rat.divInt_mul_divInt_cancelₓ'. -/
theorem divInt_mul_divInt_cancel {x : ℤ} (hx : x ≠ 0) (n d : ℤ) : n /. x * (x /. d) = n /. d :=
  by
  by_cases hd : d = 0
  · rw [hd]
    simp
  rw [mul_def hx hd, mul_comm x, div_mk_div_cancel_left hx]
#align rat.mk_mul_mk_cancel Rat.divInt_mul_divInt_cancel

/- warning: rat.mk_div_mk_cancel_left -> Rat.divInt_div_divInt_cancel_left is a dubious translation:
lean 3 declaration is
  forall {x : Int}, (Ne.{1} Int x (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (forall (n : Int) (d : Int), Eq.{1} Rat (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.hasDiv) (Rat.mk n x) (Rat.mk d x)) (Rat.mk n d))
but is expected to have type
  forall {x : Int}, (Ne.{1} Int x (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (forall (n : Int) (d : Int), Eq.{1} Rat (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.instDivRat) (Rat.divInt n x) (Rat.divInt d x)) (Rat.divInt n d))
Case conversion may be inaccurate. Consider using '#align rat.mk_div_mk_cancel_left Rat.divInt_div_divInt_cancel_leftₓ'. -/
theorem divInt_div_divInt_cancel_left {x : ℤ} (hx : x ≠ 0) (n d : ℤ) : n /. x / (d /. x) = n /. d :=
  by rw [div_eq_mul_inv, inv_def, mk_mul_mk_cancel hx]
#align rat.mk_div_mk_cancel_left Rat.divInt_div_divInt_cancel_left

/- warning: rat.mk_div_mk_cancel_right -> Rat.divInt_div_divInt_cancel_right is a dubious translation:
lean 3 declaration is
  forall {x : Int}, (Ne.{1} Int x (OfNat.ofNat.{0} Int 0 (OfNat.mk.{0} Int 0 (Zero.zero.{0} Int Int.hasZero)))) -> (forall (n : Int) (d : Int), Eq.{1} Rat (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.hasDiv) (Rat.mk x n) (Rat.mk x d)) (Rat.mk d n))
but is expected to have type
  forall {x : Int}, (Ne.{1} Int x (OfNat.ofNat.{0} Int 0 (instOfNatInt 0))) -> (forall (n : Int) (d : Int), Eq.{1} Rat (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.instDivRat) (Rat.divInt x n) (Rat.divInt x d)) (Rat.divInt d n))
Case conversion may be inaccurate. Consider using '#align rat.mk_div_mk_cancel_right Rat.divInt_div_divInt_cancel_rightₓ'. -/
theorem divInt_div_divInt_cancel_right {x : ℤ} (hx : x ≠ 0) (n d : ℤ) :
    x /. n / (x /. d) = d /. n := by rw [div_eq_mul_inv, inv_def, mul_comm, mk_mul_mk_cancel hx]
#align rat.mk_div_mk_cancel_right Rat.divInt_div_divInt_cancel_right

/- warning: rat.coe_int_div_eq_mk -> Rat.coe_int_div_eq_divInt is a dubious translation:
lean 3 declaration is
  forall {n : Int} {d : Int}, Eq.{1} Rat (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.hasDiv) ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Int Rat (HasLiftT.mk.{1, 1} Int Rat (CoeTCₓ.coe.{1, 1} Int Rat (Int.castCoe.{0} Rat Rat.hasIntCast))) n) ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Int Rat (HasLiftT.mk.{1, 1} Int Rat (CoeTCₓ.coe.{1, 1} Int Rat (Int.castCoe.{0} Rat Rat.hasIntCast))) d)) (Rat.mk n d)
but is expected to have type
  forall {n : Int} {d : Int}, Eq.{1} Rat (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.instDivRat) (Int.cast.{0} Rat Rat.instIntCastRat n) (Int.cast.{0} Rat Rat.instIntCastRat d)) (Rat.divInt n d)
Case conversion may be inaccurate. Consider using '#align rat.coe_int_div_eq_mk Rat.coe_int_div_eq_divIntₓ'. -/
theorem coe_int_div_eq_divInt {n d : ℤ} : (n : ℚ) / ↑d = n /. d :=
  by
  repeat' rw [coe_int_eq_mk]
  exact mk_div_mk_cancel_left one_ne_zero n d
#align rat.coe_int_div_eq_mk Rat.coe_int_div_eq_divInt

/- warning: rat.num_div_denom -> Rat.num_div_den is a dubious translation:
lean 3 declaration is
  forall (r : Rat), Eq.{1} Rat (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.hasDiv) ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Int Rat (HasLiftT.mk.{1, 1} Int Rat (CoeTCₓ.coe.{1, 1} Int Rat (Int.castCoe.{0} Rat Rat.hasIntCast))) (Rat.num r)) ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Rat (HasLiftT.mk.{1, 1} Nat Rat (CoeTCₓ.coe.{1, 1} Nat Rat (Nat.castCoe.{0} Rat (AddMonoidWithOne.toNatCast.{0} Rat (AddGroupWithOne.toAddMonoidWithOne.{0} Rat (AddCommGroupWithOne.toAddGroupWithOne.{0} Rat (Ring.toAddCommGroupWithOne.{0} Rat (CommRing.toRing.{0} Rat Rat.commRing)))))))) (Rat.den r))) r
but is expected to have type
  forall (r : Rat), Eq.{1} Rat (HDiv.hDiv.{0, 0, 0} Rat Rat Rat (instHDiv.{0} Rat Rat.instDivRat) (Int.cast.{0} Rat Rat.instIntCastRat (Rat.num r)) (Nat.cast.{0} Rat (NonAssocRing.toNatCast.{0} Rat (Ring.toNonAssocRing.{0} Rat (CommRing.toRing.{0} Rat Rat.commRing))) (Rat.den r))) r
Case conversion may be inaccurate. Consider using '#align rat.num_div_denom Rat.num_div_denₓ'. -/
@[simp]
theorem num_div_den (r : ℚ) : (r.num / r.den : ℚ) = r := by
  rw [← Int.cast_ofNat, ← mk_eq_div, num_denom]
#align rat.num_div_denom Rat.num_div_den

#print Rat.coe_int_num_of_den_eq_one /-
theorem coe_int_num_of_den_eq_one {q : ℚ} (hq : q.den = 1) : ↑q.num = q :=
  by
  conv_rhs => rw [← @num_denom q, hq]
  rw [coe_int_eq_mk]
  rfl
#align rat.coe_int_num_of_denom_eq_one Rat.coe_int_num_of_den_eq_one
-/

#print Rat.den_eq_one_iff /-
theorem den_eq_one_iff (r : ℚ) : r.den = 1 ↔ ↑r.num = r :=
  ⟨Rat.coe_int_num_of_den_eq_one, fun h => h ▸ Rat.coe_int_den r.num⟩
#align rat.denom_eq_one_iff Rat.den_eq_one_iff
-/

#print Rat.canLift /-
instance canLift : CanLift ℚ ℤ coe fun q => q.den = 1 :=
  ⟨fun q hq => ⟨q.num, coe_int_num_of_den_eq_one hq⟩⟩
#align rat.can_lift Rat.canLift
-/

/- warning: rat.coe_nat_eq_mk -> Rat.coe_nat_eq_divInt is a dubious translation:
lean 3 declaration is
  forall (n : Nat), Eq.{1} Rat ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Rat (HasLiftT.mk.{1, 1} Nat Rat (CoeTCₓ.coe.{1, 1} Nat Rat (Nat.castCoe.{0} Rat (AddMonoidWithOne.toNatCast.{0} Rat (AddGroupWithOne.toAddMonoidWithOne.{0} Rat (AddCommGroupWithOne.toAddGroupWithOne.{0} Rat (Ring.toAddCommGroupWithOne.{0} Rat (CommRing.toRing.{0} Rat Rat.commRing)))))))) n) (Rat.mk ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) n) (OfNat.ofNat.{0} Int 1 (OfNat.mk.{0} Int 1 (One.one.{0} Int Int.hasOne))))
but is expected to have type
  forall (n : Nat), Eq.{1} Rat (Nat.cast.{0} Rat (NonAssocRing.toNatCast.{0} Rat (Ring.toNonAssocRing.{0} Rat (CommRing.toRing.{0} Rat Rat.commRing))) n) (Rat.divInt (Nat.cast.{0} Int instNatCastInt n) (OfNat.ofNat.{0} Int 1 (instOfNatInt 1)))
Case conversion may be inaccurate. Consider using '#align rat.coe_nat_eq_mk Rat.coe_nat_eq_divIntₓ'. -/
theorem coe_nat_eq_divInt (n : ℕ) : ↑n = n /. 1 := by rw [← Int.cast_ofNat, coe_int_eq_mk]
#align rat.coe_nat_eq_mk Rat.coe_nat_eq_divInt

/- warning: rat.coe_nat_num -> Rat.coe_nat_num is a dubious translation:
lean 3 declaration is
  forall (n : Nat), Eq.{1} Int (Rat.num ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Rat (HasLiftT.mk.{1, 1} Nat Rat (CoeTCₓ.coe.{1, 1} Nat Rat (Nat.castCoe.{0} Rat (AddMonoidWithOne.toNatCast.{0} Rat (AddGroupWithOne.toAddMonoidWithOne.{0} Rat (AddCommGroupWithOne.toAddGroupWithOne.{0} Rat (Ring.toAddCommGroupWithOne.{0} Rat (CommRing.toRing.{0} Rat Rat.commRing)))))))) n)) ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Int (HasLiftT.mk.{1, 1} Nat Int (CoeTCₓ.coe.{1, 1} Nat Int (coeBase.{1, 1} Nat Int Int.hasCoe))) n)
but is expected to have type
  forall (n : Nat), Eq.{1} Int (Rat.num (Nat.cast.{0} Rat (NonAssocRing.toNatCast.{0} Rat (Ring.toNonAssocRing.{0} Rat (CommRing.toRing.{0} Rat Rat.commRing))) n)) (Nat.cast.{0} Int instNatCastInt n)
Case conversion may be inaccurate. Consider using '#align rat.coe_nat_num Rat.coe_nat_numₓ'. -/
@[simp, norm_cast]
theorem coe_nat_num (n : ℕ) : (n : ℚ).num = n := by rw [← Int.cast_ofNat, coe_int_num]
#align rat.coe_nat_num Rat.coe_nat_num

/- warning: rat.coe_nat_denom -> Rat.coe_nat_den is a dubious translation:
lean 3 declaration is
  forall (n : Nat), Eq.{1} Nat (Rat.den ((fun (a : Type) (b : Type) [self : HasLiftT.{1, 1} a b] => self.0) Nat Rat (HasLiftT.mk.{1, 1} Nat Rat (CoeTCₓ.coe.{1, 1} Nat Rat (Nat.castCoe.{0} Rat (AddMonoidWithOne.toNatCast.{0} Rat (AddGroupWithOne.toAddMonoidWithOne.{0} Rat (AddCommGroupWithOne.toAddGroupWithOne.{0} Rat (Ring.toAddCommGroupWithOne.{0} Rat (CommRing.toRing.{0} Rat Rat.commRing)))))))) n)) (OfNat.ofNat.{0} Nat 1 (OfNat.mk.{0} Nat 1 (One.one.{0} Nat Nat.hasOne)))
but is expected to have type
  forall (n : Nat), Eq.{1} Nat (Rat.den (Nat.cast.{0} Rat (NonAssocRing.toNatCast.{0} Rat (Ring.toNonAssocRing.{0} Rat (CommRing.toRing.{0} Rat Rat.commRing))) n)) (OfNat.ofNat.{0} Nat 1 (instOfNatNat 1))
Case conversion may be inaccurate. Consider using '#align rat.coe_nat_denom Rat.coe_nat_denₓ'. -/
@[simp, norm_cast]
theorem coe_nat_den (n : ℕ) : (n : ℚ).den = 1 := by rw [← Int.cast_ofNat, coe_int_denom]
#align rat.coe_nat_denom Rat.coe_nat_den

#print Rat.coe_int_inj /-
-- Will be subsumed by `int.coe_inj` after we have defined
-- `linear_ordered_field ℚ` (which implies characteristic zero).
theorem coe_int_inj (m n : ℤ) : (m : ℚ) = n ↔ m = n :=
  ⟨congr_arg num, congr_arg _⟩
#align rat.coe_int_inj Rat.coe_int_inj
-/

end Casts

end Rat

-- Guard against import creep.
assert_not_exists Field


/-
Copyright (c) 2019 Sébastien Gouëzel. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sébastien Gouëzel
-/
import analysis.normed_space.multilinear

/-!
# Formal multilinear series

In this file we define `formal_multilinear_series 𝕜 E F` to be a family of `n`-multilinear maps for
all `n`, designed to model the sequence of derivatives of a function. In other files we use this
notion to define `C^n` functions (called `cont_diff` in `mathlib`) and analytic functions.

## Notations

We use the notation `E [×n]→L[𝕜] F` for the space of continuous multilinear maps on `E^n` with
values in `F`. This is the space in which the `n`-th derivative of a function from `E` to `F` lives.

## Tags

multilinear, formal series
-/

noncomputable theory

open set fin
open_locale topology

variables {𝕜 𝕜' E F G : Type*}

section
variables [comm_ring 𝕜]
  [add_comm_group E] [module 𝕜 E] [topological_space E] [topological_add_group E]
  [has_continuous_const_smul 𝕜 E]
  [add_comm_group F] [module 𝕜 F] [topological_space F] [topological_add_group F]
  [has_continuous_const_smul 𝕜 F]
  [add_comm_group G] [module 𝕜 G] [topological_space G] [topological_add_group G]
  [has_continuous_const_smul 𝕜 G]

/-- A formal multilinear series over a field `𝕜`, from `E` to `F`, is given by a family of
multilinear maps from `E^n` to `F` for all `n`. -/
@[derive add_comm_group, nolint unused_arguments]
def formal_multilinear_series (𝕜 : Type*) (E : Type*) (F : Type*)
  [ring 𝕜]
  [add_comm_group E] [module 𝕜 E] [topological_space E] [topological_add_group E]
    [has_continuous_const_smul 𝕜 E]
  [add_comm_group F] [module 𝕜 F] [topological_space F] [topological_add_group F]
    [has_continuous_const_smul 𝕜 F] :=
Π (n : ℕ), (E [×n]→L[𝕜] F)

instance : inhabited (formal_multilinear_series 𝕜 E F) := ⟨0⟩

section module
/- `derive` is not able to find the module structure, probably because Lean is confused by the
dependent types. We register it explicitly. -/

instance : module 𝕜 (formal_multilinear_series 𝕜 E F) :=
begin
  letI : Π n, module 𝕜 (continuous_multilinear_map 𝕜 (λ (i : fin n), E) F) :=
    λ n, by apply_instance,
  refine pi.module _ _ _,
end

end module

namespace formal_multilinear_series

protected lemma ext_iff {p q : formal_multilinear_series 𝕜 E F} : p = q ↔ ∀ n, p n = q n :=
function.funext_iff

protected lemma ne_iff {p q : formal_multilinear_series 𝕜 E F} : p ≠ q ↔ ∃ n, p n ≠ q n :=
function.ne_iff

/-- Killing the zeroth coefficient in a formal multilinear series -/
def remove_zero (p : formal_multilinear_series 𝕜 E F) : formal_multilinear_series 𝕜 E F
| 0       := 0
| (n + 1) := p (n + 1)

@[simp] lemma remove_zero_coeff_zero (p : formal_multilinear_series 𝕜 E F) :
  p.remove_zero 0 = 0 := rfl

@[simp] lemma remove_zero_coeff_succ (p : formal_multilinear_series 𝕜 E F) (n : ℕ) :
  p.remove_zero (n+1) = p (n+1) := rfl

lemma remove_zero_of_pos (p : formal_multilinear_series 𝕜 E F) {n : ℕ} (h : 0 < n) :
  p.remove_zero n = p n :=
by { rw ← nat.succ_pred_eq_of_pos h, refl }

/-- Convenience congruence lemma stating in a dependent setting that, if the arguments to a formal
multilinear series are equal, then the values are also equal. -/
lemma congr (p : formal_multilinear_series 𝕜 E F) {m n : ℕ} {v : fin m → E} {w : fin n → E}
  (h1 : m = n) (h2 : ∀ (i : ℕ) (him : i < m) (hin : i < n), v ⟨i, him⟩ = w ⟨i, hin⟩) :
  p m v = p n w :=
by { cases h1, congr' with ⟨i, hi⟩, exact h2 i hi hi }

/-- Composing each term `pₙ` in a formal multilinear series with `(u, ..., u)` where `u` is a fixed
continuous linear map, gives a new formal multilinear series `p.comp_continuous_linear_map u`. -/
def comp_continuous_linear_map (p : formal_multilinear_series 𝕜 F G) (u : E →L[𝕜] F) :
  formal_multilinear_series 𝕜 E G :=
λ n, (p n).comp_continuous_linear_map (λ (i : fin n), u)

@[simp] lemma comp_continuous_linear_map_apply
  (p : formal_multilinear_series 𝕜 F G) (u : E →L[𝕜] F) (n : ℕ) (v : fin n → E) :
  (p.comp_continuous_linear_map u) n v = p n (u ∘ v) := rfl

variables (𝕜) [comm_ring 𝕜'] [has_smul 𝕜 𝕜']
variables [module 𝕜' E] [has_continuous_const_smul 𝕜' E] [is_scalar_tower 𝕜 𝕜' E]
variables [module 𝕜' F] [has_continuous_const_smul 𝕜' F] [is_scalar_tower 𝕜 𝕜' F]

/-- Reinterpret a formal `𝕜'`-multilinear series as a formal `𝕜`-multilinear series. -/
@[simp] protected def restrict_scalars (p : formal_multilinear_series 𝕜' E F) :
  formal_multilinear_series 𝕜 E F :=
λ n, (p n).restrict_scalars 𝕜

end formal_multilinear_series

end

namespace formal_multilinear_series

variables [nontrivially_normed_field 𝕜]
  [normed_add_comm_group E] [normed_space 𝕜 E]
  [normed_add_comm_group F] [normed_space 𝕜 F]
  [normed_add_comm_group G] [normed_space 𝕜 G]

variables (p : formal_multilinear_series 𝕜 E F)

/-- Forgetting the zeroth term in a formal multilinear series, and interpreting the following terms
as multilinear maps into `E →L[𝕜] F`. If `p` corresponds to the Taylor series of a function, then
`p.shift` is the Taylor series of the derivative of the function. -/
def shift : formal_multilinear_series 𝕜 E (E →L[𝕜] F) :=
λn, (p n.succ).curry_right

/-- Adding a zeroth term to a formal multilinear series taking values in `E →L[𝕜] F`. This
corresponds to starting from a Taylor series for the derivative of a function, and building a Taylor
series for the function itself. -/
def unshift (q : formal_multilinear_series 𝕜 E (E →L[𝕜] F)) (z : F) :
  formal_multilinear_series 𝕜 E F
| 0       := (continuous_multilinear_curry_fin0 𝕜 E F).symm z
| (n + 1) := continuous_multilinear_curry_right_equiv' 𝕜 n E F (q n)

end formal_multilinear_series

namespace continuous_linear_map
variables [comm_ring 𝕜]
  [add_comm_group E] [module 𝕜 E] [topological_space E] [topological_add_group E]
  [has_continuous_const_smul 𝕜 E]
  [add_comm_group F] [module 𝕜 F] [topological_space F] [topological_add_group F]
  [has_continuous_const_smul 𝕜 F]
  [add_comm_group G] [module 𝕜 G] [topological_space G] [topological_add_group G]
  [has_continuous_const_smul 𝕜 G]

/-- Composing each term `pₙ` in a formal multilinear series with a continuous linear map `f` on the
left gives a new formal multilinear series `f.comp_formal_multilinear_series p` whose general term
is `f ∘ pₙ`. -/
def comp_formal_multilinear_series (f : F →L[𝕜] G) (p : formal_multilinear_series 𝕜 E F) :
  formal_multilinear_series 𝕜 E G :=
λ n, f.comp_continuous_multilinear_map (p n)

@[simp] lemma comp_formal_multilinear_series_apply
  (f : F →L[𝕜] G) (p : formal_multilinear_series 𝕜 E F) (n : ℕ) :
  (f.comp_formal_multilinear_series p) n = f.comp_continuous_multilinear_map (p n) :=
rfl

lemma comp_formal_multilinear_series_apply'
  (f : F →L[𝕜] G) (p : formal_multilinear_series 𝕜 E F) (n : ℕ) (v : fin n → E) :
  (f.comp_formal_multilinear_series p) n v = f (p n v) :=
rfl

end continuous_linear_map

namespace formal_multilinear_series

section order

variables [comm_ring 𝕜] {n : ℕ}
  [add_comm_group E] [module 𝕜 E] [topological_space E] [topological_add_group E]
  [has_continuous_const_smul 𝕜 E]
  [add_comm_group F] [module 𝕜 F] [topological_space F] [topological_add_group F]
  [has_continuous_const_smul 𝕜 F]
  {p : formal_multilinear_series 𝕜 E F}

/-- The index of the first non-zero coefficient in `p` (or `0` if all coefficients are zero). This
  is the order of the isolated zero of an analytic function `f` at a point if `p` is the Taylor
  series of `f` at that point. -/
noncomputable def order (p : formal_multilinear_series 𝕜 E F) : ℕ :=
Inf { n | p n ≠ 0 }

@[simp] lemma order_zero : (0 : formal_multilinear_series 𝕜 E F).order = 0 := by simp [order]

lemma ne_zero_of_order_ne_zero (hp : p.order ≠ 0) : p ≠ 0 :=
λ h, by simpa [h] using hp

lemma order_eq_find [decidable_pred (λ n, p n ≠ 0)] (hp : ∃ n, p n ≠ 0) :
  p.order = nat.find hp :=
by simp [order, Inf, hp]

lemma order_eq_find' [decidable_pred (λ n, p n ≠ 0)] (hp : p ≠ 0) :
  p.order = nat.find (formal_multilinear_series.ne_iff.mp hp) :=
order_eq_find _

lemma order_eq_zero_iff (hp : p ≠ 0) : p.order = 0 ↔ p 0 ≠ 0 :=
begin
  classical,
  have : ∃ n, p n ≠ 0 := formal_multilinear_series.ne_iff.mp hp,
  simp [order_eq_find this, hp]
end

lemma order_eq_zero_iff' : p.order = 0 ↔ p = 0 ∨ p 0 ≠ 0 :=
by { by_cases h : p = 0; simp [h, order_eq_zero_iff] }

lemma apply_order_ne_zero (hp : p ≠ 0) : p p.order ≠ 0 :=
begin
  classical,
  let h := formal_multilinear_series.ne_iff.mp hp,
  exact (order_eq_find h).symm ▸ nat.find_spec h
end

lemma apply_order_ne_zero' (hp : p.order ≠ 0) : p p.order ≠ 0 :=
apply_order_ne_zero (ne_zero_of_order_ne_zero hp)

lemma apply_eq_zero_of_lt_order (hp : n < p.order) : p n = 0 :=
begin
  by_cases p = 0,
  { simp [h] },
  { classical,
    rw [order_eq_find' h] at hp,
    simpa using nat.find_min _ hp }
end

end order

section coef

variables [nontrivially_normed_field 𝕜]
  [normed_add_comm_group E] [normed_space 𝕜 E] {s : E}
  {p : formal_multilinear_series 𝕜 𝕜 E} {f : 𝕜 → E}
  {n : ℕ} {z z₀ : 𝕜} {y : fin n → 𝕜}

open_locale big_operators

/-- The `n`th coefficient of `p` when seen as a power series. -/
def coeff (p : formal_multilinear_series 𝕜 𝕜 E) (n : ℕ) : E := p n 1

@[simp] lemma apply_eq_prod_smul_coeff : p n y = (∏ i, y i) • p.coeff n :=
begin
  convert (p n).to_multilinear_map.map_smul_univ y 1,
  funext; simp only [pi.one_apply, algebra.id.smul_eq_mul, mul_one],
end

lemma coeff_eq_zero : p.coeff n = 0 ↔ p n = 0 :=
by rw [← mk_pi_field_coeff_eq p, continuous_multilinear_map.mk_pi_field_eq_zero_iff]

@[simp] lemma apply_eq_pow_smul_coeff : p n (λ _, z) = z ^ n • p.coeff n :=
by simp

@[simp] lemma norm_apply_eq_norm_coef : ‖p n‖ = ‖coeff p n‖ :=
by rw [← mk_pi_field_coeff_eq p, continuous_multilinear_map.norm_mk_pi_field]

end coef

section fslope

variables [nontrivially_normed_field 𝕜]
  [normed_add_comm_group E] [normed_space 𝕜 E]
  {p : formal_multilinear_series 𝕜 𝕜 E} {n : ℕ}

/-- The formal counterpart of `dslope`, corresponding to the expansion of `(f z - f 0) / z`. If `f`
has `p` as a power series, then `dslope f` has `fslope p` as a power series. -/
noncomputable def fslope (p : formal_multilinear_series 𝕜 𝕜 E) : formal_multilinear_series 𝕜 𝕜 E :=
  λ n, (p (n + 1)).curry_left 1

@[simp] lemma coeff_fslope : p.fslope.coeff n = p.coeff (n + 1) :=
begin
  have : @fin.cons n (λ _, 𝕜) 1 (1 : fin n → 𝕜) = 1 := fin.cons_self_tail 1,
  simp only [fslope, coeff, continuous_multilinear_map.curry_left_apply, this],
end

@[simp] lemma coeff_iterate_fslope (k n : ℕ) :
  (fslope^[k] p).coeff n = p.coeff (n + k) :=
by induction k with k ih generalizing p; refl <|> simpa [ih]

end fslope

end formal_multilinear_series

section const

/-- The formal multilinear series where all terms of positive degree are equal to zero, and the term
of degree zero is `c`. It is the power series expansion of the constant function equal to `c`
everywhere. -/
def const_formal_multilinear_series (𝕜 : Type*) [nontrivially_normed_field 𝕜]
  (E : Type*) [normed_add_comm_group E] [normed_space 𝕜 E] [has_continuous_const_smul 𝕜 E]
  [topological_add_group E] {F : Type*} [normed_add_comm_group F] [topological_add_group F]
  [normed_space 𝕜 F]  [has_continuous_const_smul 𝕜 F] (c : F) : formal_multilinear_series 𝕜 E F
| 0 := continuous_multilinear_map.curry0 _ _ c
| _ := 0

@[simp] lemma const_formal_multilinear_series_apply [nontrivially_normed_field 𝕜]
  [normed_add_comm_group E] [normed_add_comm_group F] [normed_space 𝕜 E] [normed_space 𝕜 F]
  {c : F} {n : ℕ} (hn : n ≠ 0) :
  const_formal_multilinear_series 𝕜 E c n = 0 :=
nat.cases_on n (λ hn, (hn rfl).elim) (λ _ _, rfl) hn

end const


/-
Copyright (c) 2020 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison
-/
import Mathlib.PrePort
import Mathlib.Lean3Lib.init.default
import Mathlib.ring_theory.tensor_product
import Mathlib.PostPort

universes u v w

namespace Mathlib

/-!
We provide the `R`-algebra structure on `matrix n n A` when `A` is an `R`-algebra,
and show `matrix n n A ≃ₐ[R] (A ⊗[R] matrix n n R)`.
-/

protected instance matrix.algebra {R : Type u} [comm_semiring R] {A : Type v} [semiring A]
    [algebra R A] {n : Type w} [fintype n] [DecidableEq n] : algebra R (matrix n n A) :=
  algebra.mk
    (ring_hom.mk (ring_hom.to_fun (ring_hom.comp (matrix.scalar n) (algebra_map R A))) sorry sorry
      sorry sorry)
    sorry sorry

theorem algebra_map_matrix_apply {R : Type u} [comm_semiring R] {A : Type v} [semiring A]
    [algebra R A] {n : Type w} [fintype n] [DecidableEq n] {r : R} {i : n} {j : n} :
    coe_fn (algebra_map R (matrix n n A)) r i j = ite (i = j) (coe_fn (algebra_map R A) r) 0 :=
  sorry

namespace matrix_equiv_tensor

/--
(Implementation detail).
The bare function underlying `(A ⊗[R] matrix n n R) →ₐ[R] matrix n n A`, on pure tensors.
-/
def to_fun (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A] (n : Type w)
    [fintype n] (a : A) (m : matrix n n R) : matrix n n A :=
  fun (i j : n) => a * coe_fn (algebra_map R A) (m i j)

/--
(Implementation detail).
The function underlying `(A ⊗[R] matrix n n R) →ₐ[R] matrix n n A`,
as an `R`-linear map in the second tensor factor.
-/
def to_fun_right_linear (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A]
    (n : Type w) [fintype n] (a : A) : linear_map R (matrix n n R) (matrix n n A) :=
  linear_map.mk (to_fun R A n a) sorry sorry

/--
(Implementation detail).
The function underlying `(A ⊗[R] matrix n n R) →ₐ[R] matrix n n A`,
as an `R`-bilinear map.
-/
def to_fun_bilinear (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A]
    (n : Type w) [fintype n] : linear_map R A (linear_map R (matrix n n R) (matrix n n A)) :=
  linear_map.mk (to_fun_right_linear R A n) sorry sorry

/--
(Implementation detail).
The function underlying `(A ⊗[R] matrix n n R) →ₐ[R] matrix n n A`,
as an `R`-linear map.
-/
def to_fun_linear (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A]
    (n : Type w) [fintype n] : linear_map R (tensor_product R A (matrix n n R)) (matrix n n A) :=
  tensor_product.lift (to_fun_bilinear R A n)

/--
The function `(A ⊗[R] matrix n n R) →ₐ[R] matrix n n A`, as an algebra homomorphism.
-/
def to_fun_alg_hom (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A]
    (n : Type w) [fintype n] [DecidableEq n] :
    alg_hom R (tensor_product R A (matrix n n R)) (matrix n n A) :=
  algebra.tensor_product.alg_hom_of_linear_map_tensor_product (to_fun_linear R A n) sorry sorry

@[simp] theorem to_fun_alg_hom_apply (R : Type u) [comm_semiring R] (A : Type v) [semiring A]
    [algebra R A] (n : Type w) [fintype n] [DecidableEq n] (a : A) (m : matrix n n R) :
    coe_fn (to_fun_alg_hom R A n) (tensor_product.tmul R a m) =
        fun (i j : n) => a * coe_fn (algebra_map R A) (m i j) :=
  sorry

/--
(Implementation detail.)

The bare function `matrix n n A → A ⊗[R] matrix n n R`.
(We don't need to show that it's an algebra map, thankfully --- just that it's an inverse.)
-/
def inv_fun (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A] (n : Type w)
    [fintype n] [DecidableEq n] (M : matrix n n A) : tensor_product R A (matrix n n R) :=
  finset.sum finset.univ
    fun (p : n × n) =>
      tensor_product.tmul R (M (prod.fst p) (prod.snd p))
        (matrix.std_basis_matrix (prod.fst p) (prod.snd p) 1)

@[simp] theorem inv_fun_zero (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A]
    (n : Type w) [fintype n] [DecidableEq n] : inv_fun R A n 0 = 0 :=
  sorry

@[simp] theorem inv_fun_add (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A]
    (n : Type w) [fintype n] [DecidableEq n] (M : matrix n n A) (N : matrix n n A) :
    inv_fun R A n (M + N) = inv_fun R A n M + inv_fun R A n N :=
  sorry

@[simp] theorem inv_fun_smul (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A]
    (n : Type w) [fintype n] [DecidableEq n] (a : A) (M : matrix n n A) :
    (inv_fun R A n fun (i j : n) => a * M i j) = tensor_product.tmul R a 1 * inv_fun R A n M :=
  sorry

@[simp] theorem inv_fun_algebra_map (R : Type u) [comm_semiring R] (A : Type v) [semiring A]
    [algebra R A] (n : Type w) [fintype n] [DecidableEq n] (M : matrix n n R) :
    (inv_fun R A n fun (i j : n) => coe_fn (algebra_map R A) (M i j)) = tensor_product.tmul R 1 M :=
  sorry

theorem right_inv (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A]
    (n : Type w) [fintype n] [DecidableEq n] (M : matrix n n A) :
    coe_fn (to_fun_alg_hom R A n) (inv_fun R A n M) = M :=
  sorry

theorem left_inv (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A] (n : Type w)
    [fintype n] [DecidableEq n] (M : tensor_product R A (matrix n n R)) :
    inv_fun R A n (coe_fn (to_fun_alg_hom R A n) M) = M :=
  sorry

/--
(Implementation detail)

The equivalence, ignoring the algebra structure, `(A ⊗[R] matrix n n R) ≃ matrix n n A`.
-/
def equiv (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A] (n : Type w)
    [fintype n] [DecidableEq n] : tensor_product R A (matrix n n R) ≃ matrix n n A :=
  equiv.mk (⇑(to_fun_alg_hom R A n)) (inv_fun R A n) sorry sorry

end matrix_equiv_tensor

/--
The `R`-algebra isomorphism `matrix n n A ≃ₐ[R] (A ⊗[R] matrix n n R)`.
-/
def matrix_equiv_tensor (R : Type u) [comm_semiring R] (A : Type v) [semiring A] [algebra R A]
    (n : Type w) [fintype n] [DecidableEq n] :
    alg_equiv R (matrix n n A) (tensor_product R A (matrix n n R)) :=
  alg_equiv.symm
    (alg_equiv.mk (alg_hom.to_fun sorry) (equiv.inv_fun sorry) sorry sorry sorry sorry sorry)

@[simp] theorem matrix_equiv_tensor_apply (R : Type u) [comm_semiring R] (A : Type v) [semiring A]
    [algebra R A] (n : Type w) [fintype n] [DecidableEq n] (M : matrix n n A) :
    coe_fn (matrix_equiv_tensor R A n) M =
        finset.sum finset.univ
          fun (p : n × n) =>
            tensor_product.tmul R (M (prod.fst p) (prod.snd p))
              (matrix.std_basis_matrix (prod.fst p) (prod.snd p) 1) :=
  rfl

@[simp] theorem matrix_equiv_tensor_apply_std_basis (R : Type u) [comm_semiring R] (A : Type v)
    [semiring A] [algebra R A] (n : Type w) [fintype n] [DecidableEq n] (i : n) (j : n) (x : A) :
    coe_fn (matrix_equiv_tensor R A n) (matrix.std_basis_matrix i j x) =
        tensor_product.tmul R x (matrix.std_basis_matrix i j 1) :=
  sorry

@[simp] theorem matrix_equiv_tensor_apply_symm (R : Type u) [comm_semiring R] (A : Type v)
    [semiring A] [algebra R A] (n : Type w) [fintype n] [DecidableEq n] (a : A) (M : matrix n n R) :
    coe_fn (alg_equiv.symm (matrix_equiv_tensor R A n)) (tensor_product.tmul R a M) =
        fun (i j : n) => a * coe_fn (algebra_map R A) (M i j) :=
  sorry

end Mathlib


/-
Copyright (c) 2019 Kenny Lau. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Kenny Lau
-/
import data.dfinsupp.basic
import group_theory.submonoid.operations
import group_theory.subgroup.basic

/-!
# Direct sum

This file defines the direct sum of abelian groups, indexed by a discrete type.

## Notation

`⨁ i, β i` is the n-ary direct sum `direct_sum`.
This notation is in the `direct_sum` locale, accessible after `open_locale direct_sum`.

## References

* https://en.wikipedia.org/wiki/Direct_sum
-/

open_locale big_operators

universes u v w u₁

variables (ι : Type v) [dec_ι : decidable_eq ι] (β : ι → Type w)

/-- `direct_sum β` is the direct sum of a family of additive commutative monoids `β i`.

Note: `open_locale direct_sum` will enable the notation `⨁ i, β i` for `direct_sum β`. -/
@[derive [add_comm_monoid, inhabited]]
def direct_sum [Π i, add_comm_monoid (β i)] : Type* := Π₀ i, β i

instance [Π i, add_comm_monoid (β i)] : has_coe_to_fun (direct_sum ι β) (λ _, Π i : ι, β i) :=
dfinsupp.has_coe_to_fun

localized "notation `⨁` binders `, ` r:(scoped f, direct_sum _ f) := r" in direct_sum

namespace direct_sum

variables {ι}

section add_comm_group

variables [Π i, add_comm_group (β i)]

instance : add_comm_group (direct_sum ι β) := dfinsupp.add_comm_group

variables {β}
@[simp] lemma sub_apply (g₁ g₂ : ⨁ i, β i) (i : ι) : (g₁ - g₂) i = g₁ i - g₂ i :=
dfinsupp.sub_apply _ _ _

end add_comm_group

variables [Π i, add_comm_monoid (β i)]

@[simp] lemma zero_apply (i : ι) : (0 : ⨁ i, β i) i = 0 := rfl

variables {β}
@[simp] lemma add_apply (g₁ g₂ : ⨁ i, β i) (i : ι) : (g₁ + g₂) i = g₁ i + g₂ i :=
dfinsupp.add_apply _ _ _

variables (β)
include dec_ι

/-- `mk β s x` is the element of `⨁ i, β i` that is zero outside `s`
and has coefficient `x i` for `i` in `s`. -/
def mk (s : finset ι) : (Π i : (↑s : set ι), β i.1) →+ ⨁ i, β i :=
{ to_fun := dfinsupp.mk s,
  map_add' := λ _ _, dfinsupp.mk_add,
  map_zero' := dfinsupp.mk_zero, }

/-- `of i` is the natural inclusion map from `β i` to `⨁ i, β i`. -/
def of (i : ι) : β i →+ ⨁ i, β i :=
dfinsupp.single_add_hom β i

@[simp] lemma of_eq_same (i : ι) (x : β i) : (of _ i x) i = x :=
dfinsupp.single_eq_same

lemma of_eq_of_ne (i j : ι) (x : β i) (h : i ≠ j) : (of _ i x) j = 0 :=
dfinsupp.single_eq_of_ne h

@[simp] lemma support_zero [Π (i : ι) (x : β i), decidable (x ≠ 0)] :
  (0 : ⨁ i, β i).support = ∅ := dfinsupp.support_zero

@[simp] lemma support_of [Π (i : ι) (x : β i), decidable (x ≠ 0)]
  (i : ι) (x : β i) (h : x ≠ 0) :
  (of _ i x).support = {i} := dfinsupp.support_single_ne_zero h

lemma support_of_subset [Π (i : ι) (x : β i), decidable (x ≠ 0)] {i : ι} {b : β i} :
  (of _ i b).support ⊆ {i} := dfinsupp.support_single_subset

lemma sum_support_of [Π (i : ι) (x : β i), decidable (x ≠ 0)] (x : ⨁ i, β i) :
  ∑ i in x.support, of β i (x i) = x := dfinsupp.sum_single

variables {β}

theorem mk_injective (s : finset ι) : function.injective (mk β s) :=
dfinsupp.mk_injective s

theorem of_injective (i : ι) : function.injective (of β i) :=
dfinsupp.single_injective

@[elab_as_eliminator]
protected theorem induction_on {C : (⨁ i, β i) → Prop}
  (x : ⨁ i, β i) (H_zero : C 0)
  (H_basic : ∀ (i : ι) (x : β i), C (of β i x))
  (H_plus : ∀ x y, C x → C y → C (x + y)) : C x :=
begin
  apply dfinsupp.induction x H_zero,
  intros i b f h1 h2 ih,
  solve_by_elim
end

/-- If two additive homomorphisms from `⨁ i, β i` are equal on each `of β i y`,
then they are equal. -/
lemma add_hom_ext {γ : Type*} [add_monoid γ] ⦃f g : (⨁ i, β i) →+ γ⦄
  (H : ∀ (i : ι) (y : β i), f (of _ i y) = g (of _ i y)) : f = g :=
dfinsupp.add_hom_ext H

/-- If two additive homomorphisms from `⨁ i, β i` are equal on each `of β i y`,
then they are equal.

See note [partially-applied ext lemmas]. -/
@[ext] lemma add_hom_ext' {γ : Type*} [add_monoid γ] ⦃f g : (⨁ i, β i) →+ γ⦄
  (H : ∀ (i : ι), f.comp (of _ i) = g.comp (of _ i)) : f = g :=
add_hom_ext $ λ i, add_monoid_hom.congr_fun $ H i

variables {γ : Type u₁} [add_comm_monoid γ]

section to_add_monoid

variables (φ : Π i, β i →+ γ) (ψ : (⨁ i, β i) →+ γ)

/-- `to_add_monoid φ` is the natural homomorphism from `⨁ i, β i` to `γ`
induced by a family `φ` of homomorphisms `β i → γ`. -/
def to_add_monoid : (⨁ i, β i) →+ γ :=
(dfinsupp.lift_add_hom φ)

@[simp] lemma to_add_monoid_of (i) (x : β i) : to_add_monoid φ (of β i x) = φ i x :=
dfinsupp.lift_add_hom_apply_single φ i x

theorem to_add_monoid.unique (f : ⨁ i, β i) :
  ψ f = to_add_monoid (λ i, ψ.comp (of β i)) f :=
by {congr, ext, simp [to_add_monoid, of]}

end to_add_monoid

section from_add_monoid

/-- `from_add_monoid φ` is the natural homomorphism from `γ` to `⨁ i, β i`
induced by a family `φ` of homomorphisms `γ → β i`.

Note that this is not an isomorphism. Not every homomorphism `γ →+ ⨁ i, β i` arises in this way. -/
def from_add_monoid : (⨁ i, γ →+ β i) →+ (γ →+ ⨁ i, β i) :=
to_add_monoid $ λ i, add_monoid_hom.comp_hom (of β i)

@[simp] lemma from_add_monoid_of (i : ι) (f : γ →+ β i) :
  from_add_monoid (of _ i f) = (of _ i).comp f :=
by { rw [from_add_monoid, to_add_monoid_of], refl }

lemma from_add_monoid_of_apply (i : ι) (f : γ →+ β i) (x : γ) :
  from_add_monoid (of _ i f) x = of _ i (f x) :=
by rw [from_add_monoid_of, add_monoid_hom.coe_comp]

end from_add_monoid

variables (β)
/-- `set_to_set β S T h` is the natural homomorphism `⨁ (i : S), β i → ⨁ (i : T), β i`,
where `h : S ⊆ T`. -/
-- TODO: generalize this to remove the assumption `S ⊆ T`.
def set_to_set (S T : set ι) (H : S ⊆ T) :
  (⨁ (i : S), β i) →+ (⨁ (i : T), β i) :=
to_add_monoid $ λ i, of (λ (i : subtype T), β i) ⟨↑i, H i.prop⟩
variables {β}

omit dec_ι

/-- The natural equivalence between `⨁ _ : ι, M` and `M` when `unique ι`. -/
protected def id (M : Type v) (ι : Type* := punit) [add_comm_monoid M] [unique ι] :
  (⨁ (_ : ι), M) ≃+ M :=
{ to_fun := direct_sum.to_add_monoid (λ _, add_monoid_hom.id M),
  inv_fun := of (λ _, M) default,
  left_inv := λ x, direct_sum.induction_on x
    (by rw [add_monoid_hom.map_zero, add_monoid_hom.map_zero])
    (λ p x, by rw [unique.default_eq p, to_add_monoid_of]; refl)
    (λ x y ihx ihy, by rw [add_monoid_hom.map_add, add_monoid_hom.map_add, ihx, ihy]),
  right_inv := λ x, to_add_monoid_of _ _ _,
  ..direct_sum.to_add_monoid (λ _, add_monoid_hom.id M) }

/-- The canonical embedding from `⨁ i, A i` to `M` where `A` is a collection of `add_submonoid M`
indexed by `ι`-/
def add_submonoid_coe {M : Type*} [decidable_eq ι] [add_comm_monoid M]
  (A : ι → add_submonoid M) : (⨁ i, A i) →+ M :=
to_add_monoid (λ i, (A i).subtype)

@[simp] lemma add_submonoid_coe_of {M : Type*} [decidable_eq ι] [add_comm_monoid M]
  (A : ι → add_submonoid M) (i : ι) (x : A i) :
  add_submonoid_coe A (of (λ i, A i) i x) = x :=
to_add_monoid_of _ _ _

lemma coe_of_add_submonoid_apply {M : Type*} [decidable_eq ι] [add_comm_monoid M]
  {A : ι → add_submonoid M} (i j : ι) (x : A i) :
  (of _ i x j : M) = if i = j then x else 0 :=
begin
  obtain rfl | h := decidable.eq_or_ne i j,
  { rw [direct_sum.of_eq_same, if_pos rfl], },
  { rw [direct_sum.of_eq_of_ne _ _ _ _ h, if_neg h, add_submonoid.coe_zero], },
end

/-- The `direct_sum` formed by a collection of `add_submonoid`s of `M` is said to be internal if the
canonical map `(⨁ i, A i) →+ M` is bijective.

See `direct_sum.add_subgroup_is_internal` for the same statement about `add_subgroup`s. -/
def add_submonoid_is_internal {M : Type*} [decidable_eq ι] [add_comm_monoid M]
  (A : ι → add_submonoid M) : Prop :=
function.bijective (add_submonoid_coe A)

lemma add_submonoid_is_internal.supr_eq_top {M : Type*} [decidable_eq ι] [add_comm_monoid M]
  (A : ι → add_submonoid M)
  (h : add_submonoid_is_internal A) : supr A = ⊤ :=
begin
  rw [add_submonoid.supr_eq_mrange_dfinsupp_sum_add_hom, add_monoid_hom.mrange_top_iff_surjective],
  exact function.bijective.surjective h,
end

/-- The canonical embedding from `⨁ i, A i` to `M`  where `A` is a collection of `add_subgroup M`
indexed by `ι`-/
def add_subgroup_coe {M : Type*} [decidable_eq ι] [add_comm_group M]
  (A : ι → add_subgroup M) : (⨁ i, A i) →+ M :=
to_add_monoid (λ i, (A i).subtype)

@[simp] lemma add_subgroup_coe_of {M : Type*} [decidable_eq ι] [add_comm_group M]
  (A : ι → add_subgroup M) (i : ι) (x : A i) :
  add_subgroup_coe A (of (λ i, A i) i x) = x :=
to_add_monoid_of _ _ _

lemma coe_of_add_subgroup_apply {M : Type*} [decidable_eq ι] [add_comm_group M]
  {A : ι → add_subgroup M} (i j : ι) (x : A i) :
  (of _ i x j : M) = if i = j then x else 0 :=
begin
  obtain rfl | h := decidable.eq_or_ne i j,
  { rw [direct_sum.of_eq_same, if_pos rfl], },
  { rw [direct_sum.of_eq_of_ne _ _ _ _ h, if_neg h, add_subgroup.coe_zero], },
end

/-- The `direct_sum` formed by a collection of `add_subgroup`s of `M` is said to be internal if the
canonical map `(⨁ i, A i) →+ M` is bijective.

See `direct_sum.submodule_is_internal` for the same statement about `submodules`s. -/
def add_subgroup_is_internal {M : Type*} [decidable_eq ι] [add_comm_group M]
  (A : ι → add_subgroup M) : Prop :=
function.bijective (add_subgroup_coe A)

lemma add_subgroup_is_internal.to_add_submonoid
  {M : Type*} [decidable_eq ι] [add_comm_group M] (A : ι → add_subgroup M) :
  add_subgroup_is_internal A ↔
    add_submonoid_is_internal (λ i, (A i).to_add_submonoid) :=
iff.rfl

end direct_sum