l3lab/ntp-mathlib huggingface dataset:
/-- Let `K` be the fraction field of an integrally closed domain `R` and let `L` be a finite
separable extension of `K`. Let `B : PowerBasis K L` be such that `IsIntegral R B.gen`.
Then for all, `z : L` that are integral over `R`, we have
`(discr K B.basis) • z ∈ adjoin R ({B.gen} : Set L)`. -/
theorem discr_mul_isIntegral_mem_adjoin [IsSeparable K L] [IsIntegrallyClosed R]
    [IsFractionRing R K] {B : PowerBasis K L} (hint : IsIntegral R B.gen) {z : L}
    (hz : IsIntegral R z) : discr K B.basis • z ∈ adjoin R ({B.gen} : Set L) := by
  have hinv : IsUnit (traceMatrix K B.basis).det := by
    simpa [← discr_def] using discr_isUnit_of_basis _ B.basis
  have H :
    (traceMatrix K B.basis).det • (traceMatrix K B.basis).mulVec (B.basis.equivFun z) =
      (traceMatrix K B.basis).det • fun i => trace K L (z * B.basis i) :=
    by congr; exact traceMatrix_of_basis_mulVec _ _
  have cramer := mulVec_cramer (traceMatrix K B.basis) fun i => trace K L (z * B.basis i)
  suffices ∀ i, ((traceMatrix K B.basis).det • B.basis.equivFun z) i ∈ (⊥ : Subalgebra R K) by
    rw [← B.basis.sum_repr z, Finset.smul_sum]
    refine' Subalgebra.sum_mem _ fun i _ => _
    replace this := this i
    rw [← discr_def, Pi.smul_apply, mem_bot] at this
    obtain ⟨r, hr⟩ := this
    rw [Basis.equivFun_apply] at hr
    rw [← smul_assoc, ← hr, algebraMap_smul]
    refine' Subalgebra.smul_mem _ _ _
    rw [B.basis_eq_pow i]
    refine' Subalgebra.pow_mem _ (subset_adjoin (Set.mem_singleton _)) _
  intro i
  rw [← H, ← mulVec_smul] at cramer
  replace cramer := congr_arg (mulVec (traceMatrix K B.basis)⁻¹) cramer
  rw [mulVec_mulVec, nonsing_inv_mul _ hinv, mulVec_mulVec, nonsing_inv_mul _ hinv, one_mulVec,
    one_mulVec] at cramer
  

Proof state:
A : Type u
B✝ : Type v
C : Type z
ι : Type w
inst✝²² : DecidableEq ι
inst✝²¹ : CommRing A
inst✝²⁰ : CommRing B✝
inst✝¹⁹ : Algebra A B✝
inst✝¹⁸ : CommRing C
inst✝¹⁷ : Algebra A C
ι' : Type u_1
inst✝¹⁶ : Fintype ι'
inst✝¹⁵ : Fintype ι
inst✝¹⁴ : DecidableEq ι'
K : Type u
L : Type v
E : Type z
inst✝¹³ : Field K
inst✝¹² : Field L
inst✝¹¹ : Field E
inst✝¹⁰ : Algebra K L
inst✝⁹ : Algebra K E
inst✝⁸ : Module.Finite K L
inst✝⁷ : IsAlgClosed E
b : ι → L
pb : PowerBasis K L
R : Type z
inst✝⁶ : CommRing R
inst✝⁵ : Algebra R K
inst✝⁴ : Algebra R L
inst✝³ : IsScalarTower R K L
inst✝² : IsSeparable K L
inst✝¹ : IsIntegrallyClosed R
inst✝ : IsFractionRing R K
B : PowerBasis K L
hint : IsIntegral R B.gen
z : L
hz : IsIntegral R z
hinv : IsUnit (det (traceMatrix K ⇑B.basis))
H :
  det (traceMatrix K ⇑B.basis) • mulVec (traceMatrix K ⇑B.basis) ((Basis.equivFun B.basis) z) =
    det (traceMatrix K ⇑B.basis) • fun i => (trace K L) (z * B.basis i)
i : Fin B.dim
cramer :
  ((Matrix.cramer (traceMatrix K ⇑B.basis)) fun i => (trace K L) (z * B.basis i)) =
    det (traceMatrix K ⇑B.basis) • (Basis.equivFun B.basis) z
⊢ (det (traceMatrix K ⇑B.basis) • (Basis.equivFun B.basis) z) i ∈ ⊥

Next tactic:
rw [← congr_fun cramer i, cramer_apply, det_apply]
/-- Two (finite) ℤ-bases have the same discriminant. -/
theorem discr_eq_discr [Fintype ι] (b : Basis ι ℤ A) (b' : Basis ι ℤ A) :
    Algebra.discr ℤ b = Algebra.discr ℤ b' := by
  

Proof state:
A : Type u
B : Type v
C : Type z
ι : Type w
inst✝⁹ : DecidableEq ι
inst✝⁸ : CommRing A
inst✝⁷ : CommRing B
inst✝⁶ : Algebra A B
inst✝⁵ : CommRing C
inst✝⁴ : Algebra A C
ι' : Type u_1
inst✝³ : Fintype ι'
inst✝² : Fintype ι
inst✝¹ : DecidableEq ι'
inst✝ : Fintype ι
b b' : Basis ι ℤ A
⊢ discr ℤ ⇑b = discr ℤ ⇑b'

Next tactic:
convert Algebra.discr_of_matrix_vecMul b' (b'.toMatrix b)
/-- Two (finite) ℤ-bases have the same discriminant. -/
theorem discr_eq_discr [Fintype ι] (b : Basis ι ℤ A) (b' : Basis ι ℤ A) :
    Algebra.discr ℤ b = Algebra.discr ℤ b' := by
  convert Algebra.discr_of_matrix_vecMul b' (b'.toMatrix b)
  · 

Proof state:
case h.e'_2.h.e'_9
A : Type u
B : Type v
C : Type z
ι : Type w
inst✝⁹ : DecidableEq ι
inst✝⁸ : CommRing A
inst✝⁷ : CommRing B
inst✝⁶ : Algebra A B
inst✝⁵ : CommRing C
inst✝⁴ : Algebra A C
ι' : Type u_1
inst✝³ : Fintype ι'
inst✝² : Fintype ι
inst✝¹ : DecidableEq ι'
inst✝ : Fintype ι
b b' : Basis ι ℤ A
⊢ ⇑b = vecMul (⇑b') (Matrix.map (Basis.toMatrix b' ⇑b) ⇑(algebraMap ℤ A))

Next tactic:
rw [Basis.toMatrix_map_vecMul]
/-- Two (finite) ℤ-bases have the same discriminant. -/
theorem discr_eq_discr [Fintype ι] (b : Basis ι ℤ A) (b' : Basis ι ℤ A) :
    Algebra.discr ℤ b = Algebra.discr ℤ b' := by
  convert Algebra.discr_of_matrix_vecMul b' (b'.toMatrix b)
  · rw [Basis.toMatrix_map_vecMul]
  · 

Proof state:
case h.e'_3
A : Type u
B : Type v
C : Type z
ι : Type w
inst✝⁹ : DecidableEq ι
inst✝⁸ : CommRing A
inst✝⁷ : CommRing B
inst✝⁶ : Algebra A B
inst✝⁵ : CommRing C
inst✝⁴ : Algebra A C
ι' : Type u_1
inst✝³ : Fintype ι'
inst✝² : Fintype ι
inst✝¹ : DecidableEq ι'
inst✝ : Fintype ι
b b' : Basis ι ℤ A
⊢ discr ℤ ⇑b' = det (Basis.toMatrix b' ⇑b) ^ 2 * discr ℤ ⇑b'

Next tactic:
suffices IsUnit (b'.toMatrix b).det by
      rw [Int.isUnit_iff, ← sq_eq_one_iff] at this
      rw [this, one_mul]
/-- Two (finite) ℤ-bases have the same discriminant. -/
theorem discr_eq_discr [Fintype ι] (b : Basis ι ℤ A) (b' : Basis ι ℤ A) :
    Algebra.discr ℤ b = Algebra.discr ℤ b' := by
  convert Algebra.discr_of_matrix_vecMul b' (b'.toMatrix b)
  · rw [Basis.toMatrix_map_vecMul]
  · suffices IsUnit (b'.toMatrix b).det by
      

Proof state:
A : Type u
B : Type v
C : Type z
ι : Type w
inst✝⁹ : DecidableEq ι
inst✝⁸ : CommRing A
inst✝⁷ : CommRing B
inst✝⁶ : Algebra A B
inst✝⁵ : CommRing C
inst✝⁴ : Algebra A C
ι' : Type u_1
inst✝³ : Fintype ι'
inst✝² : Fintype ι
inst✝¹ : DecidableEq ι'
inst✝ : Fintype ι
b b' : Basis ι ℤ A
this : IsUnit (det (Basis.toMatrix b' ⇑b))
⊢ discr ℤ ⇑b' = det (Basis.toMatrix b' ⇑b) ^ 2 * discr ℤ ⇑b'

Next tactic:
rw [Int.isUnit_iff, ← sq_eq_one_iff] at this
/-- Two (finite) ℤ-bases have the same discriminant. -/
theorem discr_eq_discr [Fintype ι] (b : Basis ι ℤ A) (b' : Basis ι ℤ A) :
    Algebra.discr ℤ b = Algebra.discr ℤ b' := by
  convert Algebra.discr_of_matrix_vecMul b' (b'.toMatrix b)
  · rw [Basis.toMatrix_map_vecMul]
  · suffices IsUnit (b'.toMatrix b).det by
      rw [Int.isUnit_iff, ← sq_eq_one_iff] at this
      

Proof state:
A : Type u
B : Type v
C : Type z
ι : Type w
inst✝⁹ : DecidableEq ι
inst✝⁸ : CommRing A
inst✝⁷ : CommRing B
inst✝⁶ : Algebra A B
inst✝⁵ : CommRing C
inst✝⁴ : Algebra A C
ι' : Type u_1
inst✝³ : Fintype ι'
inst✝² : Fintype ι
inst✝¹ : DecidableEq ι'
inst✝ : Fintype ι
b b' : Basis ι ℤ A
this : det (Basis.toMatrix b' ⇑b) ^ 2 = 1
⊢ discr ℤ ⇑b' = det (Basis.toMatrix b' ⇑b) ^ 2 * discr ℤ ⇑b'

Next tactic:
rw [this, one_mul]
/-- Two (finite) ℤ-bases have the same discriminant. -/
theorem discr_eq_discr [Fintype ι] (b : Basis ι ℤ A) (b' : Basis ι ℤ A) :
    Algebra.discr ℤ b = Algebra.discr ℤ b' := by
  convert Algebra.discr_of_matrix_vecMul b' (b'.toMatrix b)
  · rw [Basis.toMatrix_map_vecMul]
  · suffices IsUnit (b'.toMatrix b).det by
      rw [Int.isUnit_iff, ← sq_eq_one_iff] at this
      rw [this, one_mul]
    

Proof state:
case h.e'_3
A : Type u
B : Type v
C : Type z
ι : Type w
inst✝⁹ : DecidableEq ι
inst✝⁸ : CommRing A
inst✝⁷ : CommRing B
inst✝⁶ : Algebra A B
inst✝⁵ : CommRing C
inst✝⁴ : Algebra A C
ι' : Type u_1
inst✝³ : Fintype ι'
inst✝² : Fintype ι
inst✝¹ : DecidableEq ι'
inst✝ : Fintype ι
b b' : Basis ι ℤ A
⊢ IsUnit (det (Basis.toMatrix b' ⇑b))

Next tactic:
rw [← LinearMap.toMatrix_id_eq_basis_toMatrix b b']
/-- Two (finite) ℤ-bases have the same discriminant. -/
theorem discr_eq_discr [Fintype ι] (b : Basis ι ℤ A) (b' : Basis ι ℤ A) :
    Algebra.discr ℤ b = Algebra.discr ℤ b' := by
  convert Algebra.discr_of_matrix_vecMul b' (b'.toMatrix b)
  · rw [Basis.toMatrix_map_vecMul]
  · suffices IsUnit (b'.toMatrix b).det by
      rw [Int.isUnit_iff, ← sq_eq_one_iff] at this
      rw [this, one_mul]
    rw [← LinearMap.toMatrix_id_eq_basis_toMatrix b b']
    

Proof state:
case h.e'_3
A : Type u
B : Type v
C : Type z
ι : Type w
inst✝⁹ : DecidableEq ι
inst✝⁸ : CommRing A
inst✝⁷ : CommRing B
inst✝⁶ : Algebra A B
inst✝⁵ : CommRing C
inst✝⁴ : Algebra A C
ι' : Type u_1
inst✝³ : Fintype ι'
inst✝² : Fintype ι
inst✝¹ : DecidableEq ι'
inst✝ : Fintype ι
b b' : Basis ι ℤ A
⊢ IsUnit (det ((LinearMap.toMatrix b b') LinearMap.id))

Next tactic:
exact LinearEquiv.isUnit_det (LinearEquiv.refl ℤ A) b b'
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  

Proof state:
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l : List (Term L α)
⊢ listDecode (List.bind l listEncode) = List.map some l

Next tactic:
suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · 

Proof state:
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l : List (Term L α)
h : ∀ (t : Term L α) (l : List (α ⊕ (i : ℕ) × Functions L i)), listDecode (listEncode t ++ l) = some t :: listDecode l
⊢ listDecode (List.bind l listEncode) = List.map some l

Next tactic:
induction' l with t l lih
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · 

Proof state:
case nil
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
h : ∀ (t : Term L α) (l : List (α ⊕ (i : ℕ) × Functions L i)), listDecode (listEncode t ++ l) = some t :: listDecode l
⊢ listDecode (List.bind [] listEncode) = List.map some []

Next tactic:
rfl
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · 

Proof state:
case cons
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
h : ∀ (t : Term L α) (l : List (α ⊕ (i : ℕ) × Functions L i)), listDecode (listEncode t ++ l) = some t :: listDecode l
t : Term L α
l : List (Term L α)
lih : listDecode (List.bind l listEncode) = List.map some l
⊢ listDecode (List.bind (t :: l) listEncode) = List.map some (t :: l)

Next tactic:
rw [cons_bind, h t (l.bind listEncode), lih, List.map]
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · rw [cons_bind, h t (l.bind listEncode), lih, List.map]
  · 

Proof state:
case h
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l : List (Term L α)
⊢ ∀ (t : Term L α) (l : List (α ⊕ (i : ℕ) × Functions L i)), listDecode (listEncode t ++ l) = some t :: listDecode l

Next tactic:
intro t
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · rw [cons_bind, h t (l.bind listEncode), lih, List.map]
  · intro t
    

Proof state:
case h
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l : List (Term L α)
t : Term L α
⊢ ∀ (l : List (α ⊕ (i : ℕ) × Functions L i)), listDecode (listEncode t ++ l) = some t :: listDecode l

Next tactic:
induction' t with a n f ts ih
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · rw [cons_bind, h t (l.bind listEncode), lih, List.map]
  · intro t
    induction' t with a n f ts ih <;> 

Proof state:
case h.var
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l : List (Term L α)
a : α
⊢ ∀ (l : List (α ⊕ (i : ℕ) × Functions L i)), listDecode (listEncode (var a) ++ l) = some (var a) :: listDecode l

Next tactic:
intro l
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · rw [cons_bind, h t (l.bind listEncode), lih, List.map]
  · intro t
    induction' t with a n f ts ih <;> 

Proof state:
case h.func
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l : List (Term L α)
n : ℕ
f : Functions L n
ts : Fin n → Term L α
ih :
  ∀ (a : Fin n) (l : List (α ⊕ (i : ℕ) × Functions L i)),
    listDecode (listEncode (ts a) ++ l) = some (ts a) :: listDecode l
⊢ ∀ (l : List (α ⊕ (i : ℕ) × Functions L i)),
    listDecode (listEncode (func f ts) ++ l) = some (func f ts) :: listDecode l

Next tactic:
intro l
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · rw [cons_bind, h t (l.bind listEncode), lih, List.map]
  · intro t
    induction' t with a n f ts ih <;> intro l
    · 

Proof state:
case h.var
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l✝ : List (Term L α)
a : α
l : List (α ⊕ (i : ℕ) × Functions L i)
⊢ listDecode (listEncode (var a) ++ l) = some (var a) :: listDecode l

Next tactic:
rw [listEncode, singleton_append, listDecode]
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · rw [cons_bind, h t (l.bind listEncode), lih, List.map]
  · intro t
    induction' t with a n f ts ih <;> intro l
    · rw [listEncode, singleton_append, listDecode]
    · 

Proof state:
case h.func
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l✝ : List (Term L α)
n : ℕ
f : Functions L n
ts : Fin n → Term L α
ih :
  ∀ (a : Fin n) (l : List (α ⊕ (i : ℕ) × Functions L i)),
    listDecode (listEncode (ts a) ++ l) = some (ts a) :: listDecode l
l : List (α ⊕ (i : ℕ) × Functions L i)
⊢ listDecode (listEncode (func f ts) ++ l) = some (func f ts) :: listDecode l

Next tactic:
rw [listEncode, cons_append, listDecode]
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · rw [cons_bind, h t (l.bind listEncode), lih, List.map]
  · intro t
    induction' t with a n f ts ih <;> intro l
    · rw [listEncode, singleton_append, listDecode]
    · rw [listEncode, cons_append, listDecode]
      

Proof state:
case h.func
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l✝ : List (Term L α)
n : ℕ
f : Functions L n
ts : Fin n → Term L α
ih :
  ∀ (a : Fin n) (l : List (α ⊕ (i : ℕ) × Functions L i)),
    listDecode (listEncode (ts a) ++ l) = some (ts a) :: listDecode l
l : List (α ⊕ (i : ℕ) × Functions L i)
⊢ (if h :
        ∀ (i : Fin n),
          Option.isSome
              (Option.join (get? (listDecode ((List.bind (finRange n) fun i => listEncode (ts i)) ++ l)) ↑i)) =
            true then
      some
          (func f fun i =>
            Option.get (Option.join (get? (listDecode ((List.bind (finRange n) fun i => listEncode (ts i)) ++ l)) ↑i))
              (_ :
                Option.isSome
                    (Option.join (get? (listDecode ((List.bind (finRange n) fun i => listEncode (ts i)) ++ l)) ↑i)) =
                  true)) ::
        drop n (listDecode ((List.bind (finRange n) fun i => listEncode (ts i)) ++ l))
    else [none]) =
    some (func f ts) :: listDecode l

Next tactic:
have h : listDecode (((finRange n).bind fun i : Fin n => (ts i).listEncode) ++ l) =
          (finRange n).map (Option.some ∘ ts) ++ listDecode l := by
        induction' finRange n with i l' l'ih
        · rfl
        · rw [cons_bind, List.append_assoc, ih, map_cons, l'ih, cons_append, Function.comp]
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · rw [cons_bind, h t (l.bind listEncode), lih, List.map]
  · intro t
    induction' t with a n f ts ih <;> intro l
    · rw [listEncode, singleton_append, listDecode]
    · rw [listEncode, cons_append, listDecode]
      have h : listDecode (((finRange n).bind fun i : Fin n => (ts i).listEncode) ++ l) =
          (finRange n).map (Option.some ∘ ts) ++ listDecode l := by
        

Proof state:
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l✝ : List (Term L α)
n : ℕ
f : Functions L n
ts : Fin n → Term L α
ih :
  ∀ (a : Fin n) (l : List (α ⊕ (i : ℕ) × Functions L i)),
    listDecode (listEncode (ts a) ++ l) = some (ts a) :: listDecode l
l : List (α ⊕ (i : ℕ) × Functions L i)
⊢ listDecode ((List.bind (finRange n) fun i => listEncode (ts i)) ++ l) =
    List.map (some ∘ ts) (finRange n) ++ listDecode l

Next tactic:
induction' finRange n with i l' l'ih
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · rw [cons_bind, h t (l.bind listEncode), lih, List.map]
  · intro t
    induction' t with a n f ts ih <;> intro l
    · rw [listEncode, singleton_append, listDecode]
    · rw [listEncode, cons_append, listDecode]
      have h : listDecode (((finRange n).bind fun i : Fin n => (ts i).listEncode) ++ l) =
          (finRange n).map (Option.some ∘ ts) ++ listDecode l := by
        induction' finRange n with i l' l'ih
        · 

Proof state:
case nil
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l✝ : List (Term L α)
n : ℕ
f : Functions L n
ts : Fin n → Term L α
ih :
  ∀ (a : Fin n) (l : List (α ⊕ (i : ℕ) × Functions L i)),
    listDecode (listEncode (ts a) ++ l) = some (ts a) :: listDecode l
l : List (α ⊕ (i : ℕ) × Functions L i)
⊢ listDecode ((List.bind [] fun i => listEncode (ts i)) ++ l) = List.map (some ∘ ts) [] ++ listDecode l

Next tactic:
rfl
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · rw [cons_bind, h t (l.bind listEncode), lih, List.map]
  · intro t
    induction' t with a n f ts ih <;> intro l
    · rw [listEncode, singleton_append, listDecode]
    · rw [listEncode, cons_append, listDecode]
      have h : listDecode (((finRange n).bind fun i : Fin n => (ts i).listEncode) ++ l) =
          (finRange n).map (Option.some ∘ ts) ++ listDecode l := by
        induction' finRange n with i l' l'ih
        · rfl
        · 

Proof state:
case cons
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l✝ : List (Term L α)
n : ℕ
f : Functions L n
ts : Fin n → Term L α
ih :
  ∀ (a : Fin n) (l : List (α ⊕ (i : ℕ) × Functions L i)),
    listDecode (listEncode (ts a) ++ l) = some (ts a) :: listDecode l
l : List (α ⊕ (i : ℕ) × Functions L i)
i : Fin n
l' : List (Fin n)
l'ih : listDecode ((List.bind l' fun i => listEncode (ts i)) ++ l) = List.map (some ∘ ts) l' ++ listDecode l
⊢ listDecode ((List.bind (i :: l') fun i => listEncode (ts i)) ++ l) = List.map (some ∘ ts) (i :: l') ++ listDecode l

Next tactic:
rw [cons_bind, List.append_assoc, ih, map_cons, l'ih, cons_append, Function.comp]
theorem listDecode_encode_list (l : List (L.Term α)) :
    listDecode (l.bind listEncode) = l.map Option.some := by
  suffices h : ∀ (t : L.Term α) (l : List (Sum α (Σi, L.Functions i))),
      listDecode (t.listEncode ++ l) = some t::listDecode l
  · induction' l with t l lih
    · rfl
    · rw [cons_bind, h t (l.bind listEncode), lih, List.map]
  · intro t
    induction' t with a n f ts ih <;> intro l
    · rw [listEncode, singleton_append, listDecode]
    · rw [listEncode, cons_append, listDecode]
      have h : listDecode (((finRange n).bind fun i : Fin n => (ts i).listEncode) ++ l) =
          (finRange n).map (Option.some ∘ ts) ++ listDecode l := by
        induction' finRange n with i l' l'ih
        · rfl
        · rw [cons_bind, List.append_assoc, ih, map_cons, l'ih, cons_append, Function.comp]
      

Proof state:
case h.func
L : Language
M : Type w
N : Type u_1
P : Type u_2
inst✝² : Structure L M
inst✝¹ : Structure L N
inst✝ : Structure L P
α : Type u'
β : Type v'
l✝ : List (Term L α)
n : ℕ
f : Functions L n
ts : Fin n → Term L α
ih :
  ∀ (a : Fin n) (l : List (α ⊕ (i : ℕ) × Functions L i)),
    listDecode (listEncode (ts a) ++ l) = some (ts a) :: listDecode l
l : List (α ⊕ (i : ℕ) × Functions L i)
h :
  listDecode ((List.bind (finRange n) fun i => listEncode (ts i)) ++ l) =
    List.map (some ∘ ts) (finRange n) ++ listDecode l
⊢ (if h :
        ∀ (i : Fin n),
          Option.isSome
              (Option.join (get? (listDecode ((List.bind (finRange n) fun i => listEncode (ts i)) ++ l)) ↑i)) =
            true then
      some
          (func f fun i =>
            Option.get (Option.join (get? (listDecode ((List.bind (finRange n) fun i => listEncode (ts i)) ++ l)) ↑i))
              (_ :
                Option.isSome
                    (Option.join (get? (listDecode ((List.bind (finRange n) fun i => listEncode (ts i)) ++ l)) ↑i)) =
                  true)) ::
        drop n (listDecode ((List.bind (finRange n) fun i => listEncode (ts i)) ++ l))
    else [none]) =
    some (func f ts) :: listDecode l

Next tactic:
have h' : ∀ i : Fin n,
          (listDecode (((finRange n).bind fun i : Fin n => (ts i).listEncode) ++ l)).get? ↑i =
            some (some (ts i)) := by
        intro i
        rw [h, get?_append, get?_map]
        · simp only [Option.map_eq_some', Function.comp_apply, get?_eq_some]
          refine' ⟨i, ⟨lt_of_lt_of_le i.2 (ge_of_eq (length_finRange _)), _⟩, rfl⟩
          rw [get_finRange, Fin.eta]
        · refine' lt_of_lt_of_le i.2 _
          simp