l3lab/ntp-mathlib huggingface dataset:
/-- Give an injective map `f : M × N →ₗ[R] M` we can find a nested sequence of submodules
all isomorphic to `M`.
-/
def tunnel (f : M × N →ₗ[R] M) (i : Injective f) : ℕ →o (Submodule R M)ᵒᵈ :=
  ⟨fun n => OrderDual.toDual (tunnel' f i n).1,
    monotone_nat_of_le_succ fun n => by
      dsimp [tunnel', tunnelAux]
      rw [Submodule.map_comp, Submodule.map_comp]
      

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ OrderDual.toDual (tunnel' f i n).fst ≤
    OrderDual.toDual
      (Submodule.map (Submodule.subtype (tunnel' f i n).fst)
        (Submodule.map (↑(LinearEquiv.symm (tunnel' f i n).snd)) (Submodule.map f (Submodule.fst R M N))))

Next tactic:
apply Submodule.map_subtype_le
theorem tailing_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    tailing f i n ≤ OrderDual.ofDual (tunnel f i n) := by
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ tailing f i n ≤ OrderDual.ofDual ((tunnel f i) n)

Next tactic:
dsimp [tailing, tunnelAux]
theorem tailing_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    tailing f i n ≤ OrderDual.ofDual (tunnel f i n) := by
  dsimp [tailing, tunnelAux]
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ Submodule.map (comp (comp (Submodule.subtype (tunnel' f i n).fst) ↑(LinearEquiv.symm (tunnel' f i n).snd)) f)
      (Submodule.snd R M N) ≤
    OrderDual.ofDual ((tunnel f i) n)

Next tactic:
rw [Submodule.map_comp, Submodule.map_comp]
theorem tailing_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    tailing f i n ≤ OrderDual.ofDual (tunnel f i n) := by
  dsimp [tailing, tunnelAux]
  rw [Submodule.map_comp, Submodule.map_comp]
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ Submodule.map (Submodule.subtype (tunnel' f i n).fst)
      (Submodule.map (↑(LinearEquiv.symm (tunnel' f i n).snd)) (Submodule.map f (Submodule.snd R M N))) ≤
    OrderDual.ofDual ((tunnel f i) n)

Next tactic:
apply Submodule.map_subtype_le
theorem tailing_disjoint_tunnel_succ (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    Disjoint (tailing f i n) (OrderDual.ofDual $ tunnel f i (n + 1)) := by
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ Disjoint (tailing f i n) (OrderDual.ofDual ((tunnel f i) (n + 1)))

Next tactic:
rw [disjoint_iff]
theorem tailing_disjoint_tunnel_succ (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    Disjoint (tailing f i n) (OrderDual.ofDual $ tunnel f i (n + 1)) := by
  rw [disjoint_iff]
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ tailing f i n ⊓ OrderDual.ofDual ((tunnel f i) (n + 1)) = ⊥

Next tactic:
dsimp [tailing, tunnel, tunnel']
theorem tailing_disjoint_tunnel_succ (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    Disjoint (tailing f i n) (OrderDual.ofDual $ tunnel f i (n + 1)) := by
  rw [disjoint_iff]
  dsimp [tailing, tunnel, tunnel']
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ Submodule.map (tunnelAux f (tunnel' f i n)) (Submodule.snd R M N) ⊓
      Submodule.map (tunnelAux f (tunnel' f i n)) (Submodule.fst R M N) =
    ⊥

Next tactic:
erw [Submodule.map_inf_eq_map_inf_comap,
    Submodule.comap_map_eq_of_injective (tunnelAux_injective _ i _), inf_comm,
    Submodule.fst_inf_snd, Submodule.map_bot]
theorem tailing_sup_tunnel_succ_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    tailing f i n ⊔ (OrderDual.ofDual $ tunnel f i (n + 1)) ≤
      (OrderDual.ofDual $ tunnel f i n) := by
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ tailing f i n ⊔ OrderDual.ofDual ((tunnel f i) (n + 1)) ≤ OrderDual.ofDual ((tunnel f i) n)

Next tactic:
dsimp [tailing, tunnel, tunnel', tunnelAux]
theorem tailing_sup_tunnel_succ_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    tailing f i n ⊔ (OrderDual.ofDual $ tunnel f i (n + 1)) ≤
      (OrderDual.ofDual $ tunnel f i n) := by
  dsimp [tailing, tunnel, tunnel', tunnelAux]
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ Submodule.map (comp (comp (Submodule.subtype (tunnel' f i n).fst) ↑(LinearEquiv.symm (tunnel' f i n).snd)) f)
        (Submodule.snd R M N) ⊔
      Submodule.map (comp (comp (Submodule.subtype (tunnel' f i n).fst) ↑(LinearEquiv.symm (tunnel' f i n).snd)) f)
        (Submodule.fst R M N) ≤
    (tunnel' f i n).fst

Next tactic:
erw [← Submodule.map_sup, sup_comm, Submodule.fst_sup_snd, Submodule.map_comp, Submodule.map_comp]
theorem tailing_sup_tunnel_succ_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    tailing f i n ⊔ (OrderDual.ofDual $ tunnel f i (n + 1)) ≤
      (OrderDual.ofDual $ tunnel f i n) := by
  dsimp [tailing, tunnel, tunnel', tunnelAux]
  erw [← Submodule.map_sup, sup_comm, Submodule.fst_sup_snd, Submodule.map_comp, Submodule.map_comp]
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ Submodule.map (Submodule.subtype (tunnel' f i n).fst)
      (Submodule.map (↑(LinearEquiv.symm (tunnel' f i n).snd)) (Submodule.map f ⊤)) ≤
    (tunnel' f i n).fst

Next tactic:
apply Submodule.map_subtype_le
@[simp]
theorem tailings_zero (f : M × N →ₗ[R] M) (i : Injective f) : tailings f i 0 = tailing f i 0 := by
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
⊢ tailings f i 0 = tailing f i 0

Next tactic:
simp [tailings]
@[simp]
theorem tailings_succ (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    tailings f i (n + 1) = tailings f i n ⊔ tailing f i (n + 1) := by 

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ tailings f i (n + 1) = tailings f i n ⊔ tailing f i (n + 1)

Next tactic:
simp [tailings]
theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    Disjoint (tailings f i n) (OrderDual.ofDual $ tunnel f i (n + 1)) := by
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
⊢ Disjoint (tailings f i n) (OrderDual.ofDual ((tunnel f i) (n + 1)))

Next tactic:
induction' n with n ih
theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    Disjoint (tailings f i n) (OrderDual.ofDual $ tunnel f i (n + 1)) := by
  induction' n with n ih
  · 

Proof state:
case zero
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
⊢ Disjoint (tailings f i Nat.zero) (OrderDual.ofDual ((tunnel f i) (Nat.zero + 1)))

Next tactic:
simp only [tailings_zero]
theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    Disjoint (tailings f i n) (OrderDual.ofDual $ tunnel f i (n + 1)) := by
  induction' n with n ih
  · simp only [tailings_zero]
    

Proof state:
case zero
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
⊢ Disjoint (tailing f i 0) (OrderDual.ofDual ((tunnel f i) (Nat.zero + 1)))

Next tactic:
apply tailing_disjoint_tunnel_succ
theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    Disjoint (tailings f i n) (OrderDual.ofDual $ tunnel f i (n + 1)) := by
  induction' n with n ih
  · simp only [tailings_zero]
    apply tailing_disjoint_tunnel_succ
  · 

Proof state:
case succ
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
ih : Disjoint (tailings f i n) (OrderDual.ofDual ((tunnel f i) (n + 1)))
⊢ Disjoint (tailings f i (Nat.succ n)) (OrderDual.ofDual ((tunnel f i) (Nat.succ n + 1)))

Next tactic:
simp only [tailings_succ]
theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    Disjoint (tailings f i n) (OrderDual.ofDual $ tunnel f i (n + 1)) := by
  induction' n with n ih
  · simp only [tailings_zero]
    apply tailing_disjoint_tunnel_succ
  · simp only [tailings_succ]
    

Proof state:
case succ
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
ih : Disjoint (tailings f i n) (OrderDual.ofDual ((tunnel f i) (n + 1)))
⊢ Disjoint (tailings f i n ⊔ tailing f i (n + 1)) (OrderDual.ofDual ((tunnel f i) (Nat.succ n + 1)))

Next tactic:
refine' Disjoint.disjoint_sup_left_of_disjoint_sup_right _ _
theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    Disjoint (tailings f i n) (OrderDual.ofDual $ tunnel f i (n + 1)) := by
  induction' n with n ih
  · simp only [tailings_zero]
    apply tailing_disjoint_tunnel_succ
  · simp only [tailings_succ]
    refine' Disjoint.disjoint_sup_left_of_disjoint_sup_right _ _
    

Proof state:
case succ.refine'_1
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
ih : Disjoint (tailings f i n) (OrderDual.ofDual ((tunnel f i) (n + 1)))
⊢ Disjoint (tailing f i (n + 1)) (OrderDual.ofDual ((tunnel f i) (Nat.succ n + 1)))
case succ.refine'_2
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
ih : Disjoint (tailings f i n) (OrderDual.ofDual ((tunnel f i) (n + 1)))
⊢ Disjoint (tailings f i n) (tailing f i (n + 1) ⊔ OrderDual.ofDual ((tunnel f i) (Nat.succ n + 1)))

Next tactic:
apply tailing_disjoint_tunnel_succ
theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    Disjoint (tailings f i n) (OrderDual.ofDual $ tunnel f i (n + 1)) := by
  induction' n with n ih
  · simp only [tailings_zero]
    apply tailing_disjoint_tunnel_succ
  · simp only [tailings_succ]
    refine' Disjoint.disjoint_sup_left_of_disjoint_sup_right _ _
    apply tailing_disjoint_tunnel_succ
    

Proof state:
case succ.refine'_2
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
ih : Disjoint (tailings f i n) (OrderDual.ofDual ((tunnel f i) (n + 1)))
⊢ Disjoint (tailings f i n) (tailing f i (n + 1) ⊔ OrderDual.ofDual ((tunnel f i) (Nat.succ n + 1)))

Next tactic:
apply Disjoint.mono_right _ ih
theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) :
    Disjoint (tailings f i n) (OrderDual.ofDual $ tunnel f i (n + 1)) := by
  induction' n with n ih
  · simp only [tailings_zero]
    apply tailing_disjoint_tunnel_succ
  · simp only [tailings_succ]
    refine' Disjoint.disjoint_sup_left_of_disjoint_sup_right _ _
    apply tailing_disjoint_tunnel_succ
    apply Disjoint.mono_right _ ih
    

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁴ : Ring R
N : Type u_3
inst✝³ : AddCommGroup M
inst✝² : Module R M
inst✝¹ : AddCommGroup N
inst✝ : Module R N
f : M × N →ₗ[R] M
i : Injective ⇑f
n : ℕ
ih : Disjoint (tailings f i n) (OrderDual.ofDual ((tunnel f i) (n + 1)))
⊢ tailing f i (n + 1) ⊔ OrderDual.ofDual ((tunnel f i) (Nat.succ n + 1)) ≤ OrderDual.ofDual ((tunnel f i) (n + 1))

Next tactic:
apply tailing_sup_tunnel_succ_le_tunnel
/-- Graph of a linear map. -/
def graph : Submodule R (M × M₂)
    where
  carrier := { p | p.2 = f p.1 }
  add_mem' (ha : _ = _) (hb : _ = _) := by
    

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁸ : Semiring R
inst✝⁷ : AddCommMonoid M
inst✝⁶ : AddCommMonoid M₂
inst✝⁵ : AddCommGroup M₃
inst✝⁴ : AddCommGroup M₄
inst✝³ : Module R M
inst✝² : Module R M₂
inst✝¹ : Module R M₃
inst✝ : Module R M₄
f : M →ₗ[R] M₂
g : M₃ →ₗ[R] M₄
a✝ b✝ : M × M₂
ha : a✝.2 = f a✝.1
hb : b✝.2 = f b✝.1
⊢ a✝ + b✝ ∈ {p | p.2 = f p.1}

Next tactic:
change _ + _ = f (_ + _)
/-- Graph of a linear map. -/
def graph : Submodule R (M × M₂)
    where
  carrier := { p | p.2 = f p.1 }
  add_mem' (ha : _ = _) (hb : _ = _) := by
    change _ + _ = f (_ + _)
    

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁸ : Semiring R
inst✝⁷ : AddCommMonoid M
inst✝⁶ : AddCommMonoid M₂
inst✝⁵ : AddCommGroup M₃
inst✝⁴ : AddCommGroup M₄
inst✝³ : Module R M
inst✝² : Module R M₂
inst✝¹ : Module R M₃
inst✝ : Module R M₄
f : M →ₗ[R] M₂
g : M₃ →ₗ[R] M₄
a✝ b✝ : M × M₂
ha : a✝.2 = f a✝.1
hb : b✝.2 = f b✝.1
⊢ a✝.2 + b✝.2 = f (a✝.1 + b✝.1)

Next tactic:
rw [map_add, ha, hb]
/-- Graph of a linear map. -/
def graph : Submodule R (M × M₂)
    where
  carrier := { p | p.2 = f p.1 }
  add_mem' (ha : _ = _) (hb : _ = _) := by
    change _ + _ = f (_ + _)
    rw [map_add, ha, hb]
  zero_mem' := Eq.symm (map_zero f)
  smul_mem' c x (hx : _ = _) := by
    

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁸ : Semiring R
inst✝⁷ : AddCommMonoid M
inst✝⁶ : AddCommMonoid M₂
inst✝⁵ : AddCommGroup M₃
inst✝⁴ : AddCommGroup M₄
inst✝³ : Module R M
inst✝² : Module R M₂
inst✝¹ : Module R M₃
inst✝ : Module R M₄
f : M →ₗ[R] M₂
g : M₃ →ₗ[R] M₄
c : R
x : M × M₂
hx : x.2 = f x.1
⊢ c • x ∈
    {
          toAddSubsemigroup :=
            { carrier := {p | p.2 = f p.1},
              add_mem' := (_ : ∀ {a b : M × M₂}, a.2 = f a.1 → b.2 = f b.1 → a.2 + b.2 = f (a.1 + b.1)) },
          zero_mem' := (_ : 0.2 = f 0.1) }.toAddSubsemigroup.carrier

Next tactic:
change _ • _ = f (_ • _)
/-- Graph of a linear map. -/
def graph : Submodule R (M × M₂)
    where
  carrier := { p | p.2 = f p.1 }
  add_mem' (ha : _ = _) (hb : _ = _) := by
    change _ + _ = f (_ + _)
    rw [map_add, ha, hb]
  zero_mem' := Eq.symm (map_zero f)
  smul_mem' c x (hx : _ = _) := by
    change _ • _ = f (_ • _)
    

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁸ : Semiring R
inst✝⁷ : AddCommMonoid M
inst✝⁶ : AddCommMonoid M₂
inst✝⁵ : AddCommGroup M₃
inst✝⁴ : AddCommGroup M₄
inst✝³ : Module R M
inst✝² : Module R M₂
inst✝¹ : Module R M₃
inst✝ : Module R M₄
f : M →ₗ[R] M₂
g : M₃ →ₗ[R] M₄
c : R
x : M × M₂
hx : x.2 = f x.1
⊢ c • x.2 = f (c • x.1)

Next tactic:
rw [map_smul, hx]
theorem graph_eq_ker_coprod : g.graph = ker ((-g).coprod LinearMap.id) := by
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁸ : Semiring R
inst✝⁷ : AddCommMonoid M
inst✝⁶ : AddCommMonoid M₂
inst✝⁵ : AddCommGroup M₃
inst✝⁴ : AddCommGroup M₄
inst✝³ : Module R M
inst✝² : Module R M₂
inst✝¹ : Module R M₃
inst✝ : Module R M₄
f : M →ₗ[R] M₂
g : M₃ →ₗ[R] M₄
⊢ graph g = ker (coprod (-g) id)

Next tactic:
ext x
theorem graph_eq_ker_coprod : g.graph = ker ((-g).coprod LinearMap.id) := by
  ext x
  

Proof state:
case h
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁸ : Semiring R
inst✝⁷ : AddCommMonoid M
inst✝⁶ : AddCommMonoid M₂
inst✝⁵ : AddCommGroup M₃
inst✝⁴ : AddCommGroup M₄
inst✝³ : Module R M
inst✝² : Module R M₂
inst✝¹ : Module R M₃
inst✝ : Module R M₄
f : M →ₗ[R] M₂
g : M₃ →ₗ[R] M₄
x : M₃ × M₄
⊢ x ∈ graph g ↔ x ∈ ker (coprod (-g) id)

Next tactic:
change _ = _ ↔ -g x.1 + x.2 = _
theorem graph_eq_ker_coprod : g.graph = ker ((-g).coprod LinearMap.id) := by
  ext x
  change _ = _ ↔ -g x.1 + x.2 = _
  

Proof state:
case h
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁸ : Semiring R
inst✝⁷ : AddCommMonoid M
inst✝⁶ : AddCommMonoid M₂
inst✝⁵ : AddCommGroup M₃
inst✝⁴ : AddCommGroup M₄
inst✝³ : Module R M
inst✝² : Module R M₂
inst✝¹ : Module R M₃
inst✝ : Module R M₄
f : M →ₗ[R] M₂
g : M₃ →ₗ[R] M₄
x : M₃ × M₄
⊢ x.2 = g x.1 ↔ -g x.1 + x.2 = 0

Next tactic:
rw [add_comm, add_neg_eq_zero]
theorem graph_eq_range_prod : f.graph = range (LinearMap.id.prod f) := by
  

Proof state:
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁸ : Semiring R
inst✝⁷ : AddCommMonoid M
inst✝⁶ : AddCommMonoid M₂
inst✝⁵ : AddCommGroup M₃
inst✝⁴ : AddCommGroup M₄
inst✝³ : Module R M
inst✝² : Module R M₂
inst✝¹ : Module R M₃
inst✝ : Module R M₄
f : M →ₗ[R] M₂
g : M₃ →ₗ[R] M₄
⊢ graph f = range (prod id f)

Next tactic:
ext x
theorem graph_eq_range_prod : f.graph = range (LinearMap.id.prod f) := by
  ext x
  

Proof state:
case h
R : Type u
K : Type u'
M : Type v
V : Type v'
M₂ : Type w
V₂ : Type w'
M₃ : Type y
V₃ : Type y'
M₄ : Type z
ι : Type x
M₅ : Type u_1
M₆ : Type u_2
inst✝⁸ : Semiring R
inst✝⁷ : AddCommMonoid M
inst✝⁶ : AddCommMonoid M₂
inst✝⁵ : AddCommGroup M₃
inst✝⁴ : AddCommGroup M₄
inst✝³ : Module R M
inst✝² : Module R M₂
inst✝¹ : Module R M₃
inst✝ : Module R M₄
f : M →ₗ[R] M₂
g : M₃ →ₗ[R] M₄
x : M × M₂
⊢ x ∈ graph f ↔ x ∈ range (prod id f)

Next tactic:
exact ⟨fun hx => ⟨x.1, Prod.ext rfl hx.symm⟩, fun ⟨u, hu⟩ => hu ▸ rfl⟩
theorem hom_elementwise [Category C] [ConcreteCategory C]
    {X Y : C} {f g : X ⟶ Y} (h : f = g) (x : X) : f x = g x := by 

Proof state:
C : Type u_1
inst✝¹ : Category.{u_2, u_1} C
inst✝ : ConcreteCategory C
X Y : C
f g : X ⟶ Y
h : f = g
x : (forget C).obj X
⊢ f x = g x

Next tactic:
rw [h]
@[simp]
theorem mod_two_ne_one : ¬n % 2 = 1 ↔ n % 2 = 0 := by
  

Proof state:
m n : ℕ
⊢ ¬n % 2 = 1 ↔ n % 2 = 0

Next tactic:
cases' mod_two_eq_zero_or_one n with h h
@[simp]
theorem mod_two_ne_one : ¬n % 2 = 1 ↔ n % 2 = 0 := by
  cases' mod_two_eq_zero_or_one n with h h <;> 

Proof state:
case inl
m n : ℕ
h : n % 2 = 0
⊢ ¬n % 2 = 1 ↔ n % 2 = 0

Next tactic:
simp [h]
@[simp]
theorem mod_two_ne_one : ¬n % 2 = 1 ↔ n % 2 = 0 := by
  cases' mod_two_eq_zero_or_one n with h h <;> 

Proof state:
case inr
m n : ℕ
h : n % 2 = 1
⊢ ¬n % 2 = 1 ↔ n % 2 = 0

Next tactic:
simp [h]
@[simp]
theorem mod_two_ne_zero : ¬n % 2 = 0 ↔ n % 2 = 1 := by
  

Proof state:
m n : ℕ
⊢ ¬n % 2 = 0 ↔ n % 2 = 1

Next tactic:
cases' mod_two_eq_zero_or_one n with h h
@[simp]
theorem mod_two_ne_zero : ¬n % 2 = 0 ↔ n % 2 = 1 := by
  cases' mod_two_eq_zero_or_one n with h h <;> 

Proof state:
case inl
m n : ℕ
h : n % 2 = 0
⊢ ¬n % 2 = 0 ↔ n % 2 = 1

Next tactic:
simp [h]
@[simp]
theorem mod_two_ne_zero : ¬n % 2 = 0 ↔ n % 2 = 1 := by
  cases' mod_two_eq_zero_or_one n with h h <;> 

Proof state:
case inr
m n : ℕ
h : n % 2 = 1
⊢ ¬n % 2 = 0 ↔ n % 2 = 1

Next tactic:
simp [h]
theorem even_iff : Even n ↔ n % 2 = 0 :=
  ⟨fun ⟨m, hm⟩ => by 

Proof state:
m✝ n : ℕ
x✝ : Even n
m : ℕ
hm : n = m + m
⊢ n % 2 = 0

Next tactic:
simp [← two_mul, hm]
theorem even_iff : Even n ↔ n % 2 = 0 :=
  ⟨fun ⟨m, hm⟩ => by simp [← two_mul, hm], fun h =>
    ⟨n / 2, (mod_add_div n 2).symm.trans (by 

Proof state:
m n : ℕ
h : n % 2 = 0
⊢ n % 2 + 2 * (n / 2) = n / 2 + n / 2

Next tactic:
simp [← two_mul, h]
theorem odd_iff : Odd n ↔ n % 2 = 1 :=
  ⟨fun ⟨m, hm⟩ => by 

Proof state:
m✝ n : ℕ
x✝ : Odd n
m : ℕ
hm : n = 2 * m + 1
⊢ n % 2 = 1

Next tactic:
norm_num [hm, add_mod]
theorem odd_iff : Odd n ↔ n % 2 = 1 :=
  ⟨fun ⟨m, hm⟩ => by norm_num [hm, add_mod],
    fun h => ⟨n / 2, (mod_add_div n 2).symm.trans (by 

Proof state:
m n : ℕ
h : n % 2 = 1
⊢ n % 2 + 2 * (n / 2) = 2 * (n / 2) + 1

Next tactic:
rw [h, add_comm]
theorem not_even_iff : ¬Even n ↔ n % 2 = 1 := by 

Proof state:
m n : ℕ
⊢ ¬Even n ↔ n % 2 = 1

Next tactic:
rw [even_iff, mod_two_ne_zero]
theorem not_odd_iff : ¬Odd n ↔ n % 2 = 0 := by 

Proof state:
m n : ℕ
⊢ ¬Odd n ↔ n % 2 = 0

Next tactic:
rw [odd_iff, mod_two_ne_one]
theorem even_iff_not_odd : Even n ↔ ¬Odd n := by 

Proof state:
m n : ℕ
⊢ Even n ↔ ¬Odd n

Next tactic:
rw [not_odd_iff, even_iff]
@[simp]
theorem odd_iff_not_even : Odd n ↔ ¬Even n := by 

Proof state:
m n : ℕ
⊢ Odd n ↔ ¬Even n

Next tactic:
rw [not_even_iff, odd_iff]