l3lab/ntp-mathlib huggingface dataset:
theorem iInf_ker_truncate : ⨅ i : ℕ, RingHom.ker (@WittVector.truncate p _ i R _) = ⊥ := by
  rw [Submodule.eq_bot_iff]
  intro x hx
  ext
  simp only [WittVector.mem_ker_truncate, Ideal.mem_iInf, WittVector.zero_coeff] at hx ⊢
  

Proof state:
case h
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝ : CommRing R
x : 𝕎 R
n✝ : ℕ
hx : ∀ (i i_1 : ℕ), i_1 < i → WittVector.coeff x i_1 = 0
⊢ WittVector.coeff x n✝ = 0

Next tactic:
exact hx _ _ (Nat.lt_succ_self _)
@[simp]
theorem truncate_liftFun (s : S) : WittVector.truncate n (liftFun f s) = f n s := by
  

Proof state:
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
s : S
⊢ (truncate n) (liftFun f s) = (f n) s

Next tactic:
ext i
@[simp]
theorem truncate_liftFun (s : S) : WittVector.truncate n (liftFun f s) = f n s := by
  ext i
  

Proof state:
case h
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
s : S
i : Fin n
⊢ TruncatedWittVector.coeff i ((truncate n) (liftFun f s)) = TruncatedWittVector.coeff i ((f n) s)

Next tactic:
simp only [liftFun, TruncatedWittVector.coeff_mk, WittVector.truncate_mk']
@[simp]
theorem truncate_liftFun (s : S) : WittVector.truncate n (liftFun f s) = f n s := by
  ext i
  simp only [liftFun, TruncatedWittVector.coeff_mk, WittVector.truncate_mk']
  

Proof state:
case h
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
s : S
i : Fin n
⊢ TruncatedWittVector.coeff (Fin.last ↑i) ((f (↑i + 1)) s) = TruncatedWittVector.coeff i ((f n) s)

Next tactic:
rw [← f_compat (i + 1) n i.is_lt, RingHom.comp_apply, TruncatedWittVector.coeff_truncate]
@[simp]
theorem truncate_liftFun (s : S) : WittVector.truncate n (liftFun f s) = f n s := by
  ext i
  simp only [liftFun, TruncatedWittVector.coeff_mk, WittVector.truncate_mk']
  rw [← f_compat (i + 1) n i.is_lt, RingHom.comp_apply, TruncatedWittVector.coeff_truncate]
  

Proof state:
case h
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
s : S
i : Fin n
⊢ TruncatedWittVector.coeff (Fin.castLE (_ : ↑i < n) (Fin.last ↑i)) ((f n) s) = TruncatedWittVector.coeff i ((f n) s)

Next tactic:
congr 1 with _
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  

Proof state:
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ S →+* 𝕎 R

Next tactic:
refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ }
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( 

Proof state:
case refine'_1
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ liftFun f 1 = 1

Next tactic:
intros
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    

Proof state:
case refine'_1
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ liftFun f 1 = 1

Next tactic:
dsimp only
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    dsimp only
    

Proof state:
case refine'_1
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ liftFun f 1 = 1

Next tactic:
rw [← sub_eq_zero, ← Ideal.mem_bot, ← iInf_ker_truncate, Ideal.mem_iInf]
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    dsimp only
    rw [← sub_eq_zero, ← Ideal.mem_bot, ← iInf_ker_truncate, Ideal.mem_iInf]
    

Proof state:
case refine'_1
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ ∀ (i : ℕ), liftFun f 1 - 1 ∈ RingHom.ker (truncate i)

Next tactic:
simp [RingHom.mem_ker, f_compat]
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( 

Proof state:
case refine'_2
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ ∀ (x y : S),
    OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } (x * y) =
      OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } x *
        OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } y

Next tactic:
intros
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    

Proof state:
case refine'_2
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
x✝ y✝ : S
⊢ OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } (x✝ * y✝) =
    OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } x✝ *
      OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } y✝

Next tactic:
dsimp only
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    dsimp only
    

Proof state:
case refine'_2
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
x✝ y✝ : S
⊢ liftFun f (x✝ * y✝) = liftFun f x✝ * liftFun f y✝

Next tactic:
rw [← sub_eq_zero, ← Ideal.mem_bot, ← iInf_ker_truncate, Ideal.mem_iInf]
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    dsimp only
    rw [← sub_eq_zero, ← Ideal.mem_bot, ← iInf_ker_truncate, Ideal.mem_iInf]
    

Proof state:
case refine'_2
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
x✝ y✝ : S
⊢ ∀ (i : ℕ), liftFun f (x✝ * y✝) - liftFun f x✝ * liftFun f y✝ ∈ RingHom.ker (truncate i)

Next tactic:
simp [RingHom.mem_ker, f_compat]
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( 

Proof state:
case refine'_3
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ OneHom.toFun
      (↑{ toOneHom := { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) },
          map_mul' :=
            (_ :
              ∀ (x y : S),
                OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } (x * y) =
                  OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } x *
                    OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } y) })
      0 =
    0

Next tactic:
intros
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    

Proof state:
case refine'_3
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ OneHom.toFun
      (↑{ toOneHom := { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) },
          map_mul' :=
            (_ :
              ∀ (x y : S),
                OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } (x * y) =
                  OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } x *
                    OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } y) })
      0 =
    0

Next tactic:
dsimp only
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    dsimp only
    

Proof state:
case refine'_3
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ liftFun f 0 = 0

Next tactic:
rw [← sub_eq_zero, ← Ideal.mem_bot, ← iInf_ker_truncate, Ideal.mem_iInf]
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    dsimp only
    rw [← sub_eq_zero, ← Ideal.mem_bot, ← iInf_ker_truncate, Ideal.mem_iInf]
    

Proof state:
case refine'_3
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ ∀ (i : ℕ), liftFun f 0 - 0 ∈ RingHom.ker (truncate i)

Next tactic:
simp [RingHom.mem_ker, f_compat]
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( 

Proof state:
case refine'_4
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ ∀ (x y : S),
    OneHom.toFun
        (↑{ toOneHom := { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) },
            map_mul' :=
              (_ :
                ∀ (x y : S),
                  OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } (x * y) =
                    OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } x *
                      OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } y) })
        (x + y) =
      OneHom.toFun
          (↑{ toOneHom := { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) },
              map_mul' :=
                (_ :
                  ∀ (x y : S),
                    OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } (x * y) =
                      OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } x *
                        OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } y) })
          x +
        OneHom.toFun
          (↑{ toOneHom := { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) },
              map_mul' :=
                (_ :
                  ∀ (x y : S),
                    OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } (x * y) =
                      OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } x *
                        OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } y) })
          y

Next tactic:
intros
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    

Proof state:
case refine'_4
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
x✝ y✝ : S
⊢ OneHom.toFun
      (↑{ toOneHom := { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) },
          map_mul' :=
            (_ :
              ∀ (x y : S),
                OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } (x * y) =
                  OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } x *
                    OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } y) })
      (x✝ + y✝) =
    OneHom.toFun
        (↑{ toOneHom := { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) },
            map_mul' :=
              (_ :
                ∀ (x y : S),
                  OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } (x * y) =
                    OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } x *
                      OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } y) })
        x✝ +
      OneHom.toFun
        (↑{ toOneHom := { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) },
            map_mul' :=
              (_ :
                ∀ (x y : S),
                  OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } (x * y) =
                    OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } x *
                      OneHom.toFun { toFun := liftFun f, map_one' := (_ : liftFun f 1 = 1) } y) })
        y✝

Next tactic:
dsimp only
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    dsimp only
    

Proof state:
case refine'_4
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
x✝ y✝ : S
⊢ liftFun f (x✝ + y✝) = liftFun f x✝ + liftFun f y✝

Next tactic:
rw [← sub_eq_zero, ← Ideal.mem_bot, ← iInf_ker_truncate, Ideal.mem_iInf]
/--
Given compatible ring homs from `S` into `TruncatedWittVector n` for each `n`, we can lift these
to a ring hom `S → 𝕎 R`.

`lift` defines the universal property of `𝕎 R` as the inverse limit of `TruncatedWittVector n`.
-/
def lift : S →+* 𝕎 R := by
  refine' { toFun := liftFun f
            map_zero' := _
            map_one' := _
            map_add' := _
            map_mul' := _ } <;>
  ( intros
    dsimp only
    rw [← sub_eq_zero, ← Ideal.mem_bot, ← iInf_ker_truncate, Ideal.mem_iInf]
    

Proof state:
case refine'_4
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
x✝ y✝ : S
⊢ ∀ (i : ℕ), liftFun f (x✝ + y✝) - (liftFun f x✝ + liftFun f y✝) ∈ RingHom.ker (truncate i)

Next tactic:
simp [RingHom.mem_ker, f_compat]
@[simp]
theorem truncate_comp_lift : (WittVector.truncate n).comp (lift _ f_compat) = f n := by
  

Proof state:
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
⊢ RingHom.comp (truncate n) (lift (fun k₂ => f k₂) f_compat) = f n

Next tactic:
ext1
@[simp]
theorem truncate_comp_lift : (WittVector.truncate n).comp (lift _ f_compat) = f n := by
  ext1; 

Proof state:
case a
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
x✝ : S
⊢ (RingHom.comp (truncate n) (lift (fun k₂ => f k₂) f_compat)) x✝ = (f n) x✝

Next tactic:
rw [RingHom.comp_apply, truncate_lift]
/-- The uniqueness part of the universal property of `𝕎 R`. -/
theorem lift_unique (g : S →+* 𝕎 R) (g_compat : ∀ k, (WittVector.truncate k).comp g = f k) :
    lift _ f_compat = g := by
  

Proof state:
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
g : S →+* 𝕎 R
g_compat : ∀ (k : ℕ), RingHom.comp (truncate k) g = f k
⊢ lift (fun k₂ => f k₂) f_compat = g

Next tactic:
ext1 x
/-- The uniqueness part of the universal property of `𝕎 R`. -/
theorem lift_unique (g : S →+* 𝕎 R) (g_compat : ∀ k, (WittVector.truncate k).comp g = f k) :
    lift _ f_compat = g := by
  ext1 x
  

Proof state:
case a
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
g : S →+* 𝕎 R
g_compat : ∀ (k : ℕ), RingHom.comp (truncate k) g = f k
x : S
⊢ (lift (fun k₂ => f k₂) f_compat) x = g x

Next tactic:
rw [← sub_eq_zero, ← Ideal.mem_bot, ← iInf_ker_truncate, Ideal.mem_iInf]
/-- The uniqueness part of the universal property of `𝕎 R`. -/
theorem lift_unique (g : S →+* 𝕎 R) (g_compat : ∀ k, (WittVector.truncate k).comp g = f k) :
    lift _ f_compat = g := by
  ext1 x
  rw [← sub_eq_zero, ← Ideal.mem_bot, ← iInf_ker_truncate, Ideal.mem_iInf]
  

Proof state:
case a
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
g : S →+* 𝕎 R
g_compat : ∀ (k : ℕ), RingHom.comp (truncate k) g = f k
x : S
⊢ ∀ (i : ℕ), (lift (fun k₂ => f k₂) f_compat) x - g x ∈ RingHom.ker (truncate i)

Next tactic:
intro i
/-- The uniqueness part of the universal property of `𝕎 R`. -/
theorem lift_unique (g : S →+* 𝕎 R) (g_compat : ∀ k, (WittVector.truncate k).comp g = f k) :
    lift _ f_compat = g := by
  ext1 x
  rw [← sub_eq_zero, ← Ideal.mem_bot, ← iInf_ker_truncate, Ideal.mem_iInf]
  intro i
  

Proof state:
case a
p : ℕ
hp : Fact (Nat.Prime p)
n : ℕ
R : Type u_1
inst✝¹ : CommRing R
S : Type u_2
inst✝ : Semiring S
f : (k : ℕ) → S →+* TruncatedWittVector p k R
f_compat : ∀ (k₁ k₂ : ℕ) (hk : k₁ ≤ k₂), RingHom.comp (TruncatedWittVector.truncate hk) (f k₂) = f k₁
g : S →+* 𝕎 R
g_compat : ∀ (k : ℕ), RingHom.comp (truncate k) g = f k
x : S
i : ℕ
⊢ (lift (fun k₂ => f k₂) f_compat) x - g x ∈ RingHom.ker (truncate i)

Next tactic:
simp only [RingHom.mem_ker, g_compat, ← RingHom.comp_apply, truncate_comp_lift, RingHom.map_sub,
    sub_self]