l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem nodup_bind {s : Multiset α} {t : α → Multiset β} :
    Nodup (bind s t) ↔ (∀ a ∈ s, Nodup (t a)) ∧ s.Pairwise fun a b => Disjoint (t a) (t b) :=
  have h₁ : ∀ a, ∃ l : List β, t a = l := fun a => Quot.induction_on (t a) fun l => ⟨l, rfl⟩
  let ⟨t', h'⟩ := Classical.axiom_of_choice h₁
  have : t = fun a => ofList (t' a) := funext h'
  have hd : Symmetric fun a b => List.Disjoint (t' a) (t' b) := fun a b h => h.symm
  Quot.induction_on s <| by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r : α → α → Prop
s✝ t✝ : Multiset α
a : α
s : Multiset α
t : α → Multiset β
h₁ : ∀ (a : α), ∃ l, t a = ↑l
t' : α → List β
h' : ∀ (x : α), t x = ↑(t' x)
this : t = fun a => ↑(t' a)
hd : Symmetric fun a b => List.Disjoint (t' a) (t' b)
⊢ ∀ (a : List α),
    Nodup (bind (Quot.mk Setoid.r a) t) ↔
      (∀ a_1 ∈ Quot.mk Setoid.r a, Nodup (t a_1)) ∧ Pairwise (fun a b => Disjoint (t a) (t b)) (Quot.mk Setoid.r a)

Next tactic:
simp [this, List.nodup_bind, pairwise_coe_iff_pairwise hd]
theorem mem_sub_of_nodup [DecidableEq α] {a : α} {s t : Multiset α} (d : Nodup s) :
    a ∈ s - t ↔ a ∈ s ∧ a ∉ t :=
  ⟨fun h =>
    ⟨mem_of_le tsub_le_self h, fun h' => by
      

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r : α → α → Prop
s✝ t✝ : Multiset α
a✝ : α
inst✝ : DecidableEq α
a : α
s t : Multiset α
d : Nodup s
h : a ∈ s - t
h' : a ∈ t
⊢ False

Next tactic:
refine' count_eq_zero.1 _ h
theorem mem_sub_of_nodup [DecidableEq α] {a : α} {s t : Multiset α} (d : Nodup s) :
    a ∈ s - t ↔ a ∈ s ∧ a ∉ t :=
  ⟨fun h =>
    ⟨mem_of_le tsub_le_self h, fun h' => by
      refine' count_eq_zero.1 _ h
      

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r : α → α → Prop
s✝ t✝ : Multiset α
a✝ : α
inst✝ : DecidableEq α
a : α
s t : Multiset α
d : Nodup s
h : a ∈ s - t
h' : a ∈ t
⊢ count a (s - t) = 0

Next tactic:
rw [count_sub a s t, tsub_eq_zero_iff_le]
theorem mem_sub_of_nodup [DecidableEq α] {a : α} {s t : Multiset α} (d : Nodup s) :
    a ∈ s - t ↔ a ∈ s ∧ a ∉ t :=
  ⟨fun h =>
    ⟨mem_of_le tsub_le_self h, fun h' => by
      refine' count_eq_zero.1 _ h
      rw [count_sub a s t, tsub_eq_zero_iff_le]
      

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r : α → α → Prop
s✝ t✝ : Multiset α
a✝ : α
inst✝ : DecidableEq α
a : α
s t : Multiset α
d : Nodup s
h : a ∈ s - t
h' : a ∈ t
⊢ count a s ≤ count a t

Next tactic:
exact le_trans (nodup_iff_count_le_one.1 d _) (count_pos.2 h')
theorem map_eq_map_of_bij_of_nodup (f : α → γ) (g : β → γ) {s : Multiset α} {t : Multiset β}
    (hs : s.Nodup) (ht : t.Nodup) (i : ∀ a ∈ s, β) (hi : ∀ a ha, i a ha ∈ t)
    (h : ∀ a ha, f a = g (i a ha)) (i_inj : ∀ a₁ a₂ ha₁ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂)
    (i_surj : ∀ b ∈ t, ∃ a ha, b = i a ha) : s.map f = t.map g :=
  have : t = s.attach.map fun x => i x.1 x.2 :=
    (ht.ext <|
          (nodup_attach.2 hs).map <|
            show Injective fun x : { x // x ∈ s } => i x x.2 from fun x y hxy =>
              Subtype.ext <| i_inj x y x.2 y.2 hxy).2
      fun x => by
        

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r : α → α → Prop
s✝ t✝ : Multiset α
a : α
f : α → γ
g : β → γ
s : Multiset α
t : Multiset β
hs : Nodup s
ht : Nodup t
i : (a : α) → a ∈ s → β
hi : ∀ (a : α) (ha : a ∈ s), i a ha ∈ t
h : ∀ (a : α) (ha : a ∈ s), f a = g (i a ha)
i_inj : ∀ (a₁ a₂ : α) (ha₁ : a₁ ∈ s) (ha₂ : a₂ ∈ s), i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂
i_surj : ∀ b ∈ t, ∃ a, ∃ (ha : a ∈ s), b = i a ha
x : β
⊢ x ∈ t ↔ x ∈ map (fun x => i ↑x (_ : ↑x ∈ s)) (attach s)

Next tactic:
simp only [mem_map, true_and_iff, Subtype.exists, eq_comm, mem_attach]
theorem map_eq_map_of_bij_of_nodup (f : α → γ) (g : β → γ) {s : Multiset α} {t : Multiset β}
    (hs : s.Nodup) (ht : t.Nodup) (i : ∀ a ∈ s, β) (hi : ∀ a ha, i a ha ∈ t)
    (h : ∀ a ha, f a = g (i a ha)) (i_inj : ∀ a₁ a₂ ha₁ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂)
    (i_surj : ∀ b ∈ t, ∃ a ha, b = i a ha) : s.map f = t.map g :=
  have : t = s.attach.map fun x => i x.1 x.2 :=
    (ht.ext <|
          (nodup_attach.2 hs).map <|
            show Injective fun x : { x // x ∈ s } => i x x.2 from fun x y hxy =>
              Subtype.ext <| i_inj x y x.2 y.2 hxy).2
      fun x => by
        simp only [mem_map, true_and_iff, Subtype.exists, eq_comm, mem_attach]
        

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r : α → α → Prop
s✝ t✝ : Multiset α
a : α
f : α → γ
g : β → γ
s : Multiset α
t : Multiset β
hs : Nodup s
ht : Nodup t
i : (a : α) → a ∈ s → β
hi : ∀ (a : α) (ha : a ∈ s), i a ha ∈ t
h : ∀ (a : α) (ha : a ∈ s), f a = g (i a ha)
i_inj : ∀ (a₁ a₂ : α) (ha₁ : a₁ ∈ s) (ha₂ : a₂ ∈ s), i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂
i_surj : ∀ b ∈ t, ∃ a, ∃ (ha : a ∈ s), b = i a ha
x : β
⊢ x ∈ t ↔ ∃ a, ∃ (h : a ∈ s), x = i a (_ : ↑{ val := a, property := (_ : a ∈ s) } ∈ s)

Next tactic:
exact ⟨i_surj _, fun ⟨y, hy⟩ => hy.snd.symm ▸ hi _ _⟩
theorem map_eq_map_of_bij_of_nodup (f : α → γ) (g : β → γ) {s : Multiset α} {t : Multiset β}
    (hs : s.Nodup) (ht : t.Nodup) (i : ∀ a ∈ s, β) (hi : ∀ a ha, i a ha ∈ t)
    (h : ∀ a ha, f a = g (i a ha)) (i_inj : ∀ a₁ a₂ ha₁ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂)
    (i_surj : ∀ b ∈ t, ∃ a ha, b = i a ha) : s.map f = t.map g :=
  have : t = s.attach.map fun x => i x.1 x.2 :=
    (ht.ext <|
          (nodup_attach.2 hs).map <|
            show Injective fun x : { x // x ∈ s } => i x x.2 from fun x y hxy =>
              Subtype.ext <| i_inj x y x.2 y.2 hxy).2
      fun x => by
        simp only [mem_map, true_and_iff, Subtype.exists, eq_comm, mem_attach]
        exact ⟨i_surj _, fun ⟨y, hy⟩ => hy.snd.symm ▸ hi _ _⟩
  calc
    s.map f = s.pmap (fun x _ => f x) fun _ => id := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r : α → α → Prop
s✝ t✝ : Multiset α
a : α
f : α → γ
g : β → γ
s : Multiset α
t : Multiset β
hs : Nodup s
ht : Nodup t
i : (a : α) → a ∈ s → β
hi : ∀ (a : α) (ha : a ∈ s), i a ha ∈ t
h : ∀ (a : α) (ha : a ∈ s), f a = g (i a ha)
i_inj : ∀ (a₁ a₂ : α) (ha₁ : a₁ ∈ s) (ha₂ : a₂ ∈ s), i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂
i_surj : ∀ b ∈ t, ∃ a, ∃ (ha : a ∈ s), b = i a ha
this : t = map (fun x => i ↑x (_ : ↑x ∈ s)) (attach s)
⊢ map f s = pmap (fun x x_1 => f x) s (_ : ∀ x ∈ s, x ∈ s)

Next tactic:
rw [pmap_eq_map]
theorem map_eq_map_of_bij_of_nodup (f : α → γ) (g : β → γ) {s : Multiset α} {t : Multiset β}
    (hs : s.Nodup) (ht : t.Nodup) (i : ∀ a ∈ s, β) (hi : ∀ a ha, i a ha ∈ t)
    (h : ∀ a ha, f a = g (i a ha)) (i_inj : ∀ a₁ a₂ ha₁ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂)
    (i_surj : ∀ b ∈ t, ∃ a ha, b = i a ha) : s.map f = t.map g :=
  have : t = s.attach.map fun x => i x.1 x.2 :=
    (ht.ext <|
          (nodup_attach.2 hs).map <|
            show Injective fun x : { x // x ∈ s } => i x x.2 from fun x y hxy =>
              Subtype.ext <| i_inj x y x.2 y.2 hxy).2
      fun x => by
        simp only [mem_map, true_and_iff, Subtype.exists, eq_comm, mem_attach]
        exact ⟨i_surj _, fun ⟨y, hy⟩ => hy.snd.symm ▸ hi _ _⟩
  calc
    s.map f = s.pmap (fun x _ => f x) fun _ => id := by rw [pmap_eq_map]
    _ = s.attach.map fun x => f x.1 := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r : α → α → Prop
s✝ t✝ : Multiset α
a : α
f : α → γ
g : β → γ
s : Multiset α
t : Multiset β
hs : Nodup s
ht : Nodup t
i : (a : α) → a ∈ s → β
hi : ∀ (a : α) (ha : a ∈ s), i a ha ∈ t
h : ∀ (a : α) (ha : a ∈ s), f a = g (i a ha)
i_inj : ∀ (a₁ a₂ : α) (ha₁ : a₁ ∈ s) (ha₂ : a₂ ∈ s), i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂
i_surj : ∀ b ∈ t, ∃ a, ∃ (ha : a ∈ s), b = i a ha
this : t = map (fun x => i ↑x (_ : ↑x ∈ s)) (attach s)
⊢ pmap (fun x x_1 => f x) s (_ : ∀ x ∈ s, x ∈ s) = map (fun x => f ↑x) (attach s)

Next tactic:
rw [pmap_eq_map_attach]
theorem map_eq_map_of_bij_of_nodup (f : α → γ) (g : β → γ) {s : Multiset α} {t : Multiset β}
    (hs : s.Nodup) (ht : t.Nodup) (i : ∀ a ∈ s, β) (hi : ∀ a ha, i a ha ∈ t)
    (h : ∀ a ha, f a = g (i a ha)) (i_inj : ∀ a₁ a₂ ha₁ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂)
    (i_surj : ∀ b ∈ t, ∃ a ha, b = i a ha) : s.map f = t.map g :=
  have : t = s.attach.map fun x => i x.1 x.2 :=
    (ht.ext <|
          (nodup_attach.2 hs).map <|
            show Injective fun x : { x // x ∈ s } => i x x.2 from fun x y hxy =>
              Subtype.ext <| i_inj x y x.2 y.2 hxy).2
      fun x => by
        simp only [mem_map, true_and_iff, Subtype.exists, eq_comm, mem_attach]
        exact ⟨i_surj _, fun ⟨y, hy⟩ => hy.snd.symm ▸ hi _ _⟩
  calc
    s.map f = s.pmap (fun x _ => f x) fun _ => id := by rw [pmap_eq_map]
    _ = s.attach.map fun x => f x.1 := by rw [pmap_eq_map_attach]
    _ = t.map g := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r : α → α → Prop
s✝ t✝ : Multiset α
a : α
f : α → γ
g : β → γ
s : Multiset α
t : Multiset β
hs : Nodup s
ht : Nodup t
i : (a : α) → a ∈ s → β
hi : ∀ (a : α) (ha : a ∈ s), i a ha ∈ t
h : ∀ (a : α) (ha : a ∈ s), f a = g (i a ha)
i_inj : ∀ (a₁ a₂ : α) (ha₁ : a₁ ∈ s) (ha₂ : a₂ ∈ s), i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂
i_surj : ∀ b ∈ t, ∃ a, ∃ (ha : a ∈ s), b = i a ha
this : t = map (fun x => i ↑x (_ : ↑x ∈ s)) (attach s)
⊢ map (fun x => f ↑x) (attach s) = map g t

Next tactic:
rw [this, Multiset.map_map]
theorem map_eq_map_of_bij_of_nodup (f : α → γ) (g : β → γ) {s : Multiset α} {t : Multiset β}
    (hs : s.Nodup) (ht : t.Nodup) (i : ∀ a ∈ s, β) (hi : ∀ a ha, i a ha ∈ t)
    (h : ∀ a ha, f a = g (i a ha)) (i_inj : ∀ a₁ a₂ ha₁ ha₂, i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂)
    (i_surj : ∀ b ∈ t, ∃ a ha, b = i a ha) : s.map f = t.map g :=
  have : t = s.attach.map fun x => i x.1 x.2 :=
    (ht.ext <|
          (nodup_attach.2 hs).map <|
            show Injective fun x : { x // x ∈ s } => i x x.2 from fun x y hxy =>
              Subtype.ext <| i_inj x y x.2 y.2 hxy).2
      fun x => by
        simp only [mem_map, true_and_iff, Subtype.exists, eq_comm, mem_attach]
        exact ⟨i_surj _, fun ⟨y, hy⟩ => hy.snd.symm ▸ hi _ _⟩
  calc
    s.map f = s.pmap (fun x _ => f x) fun _ => id := by rw [pmap_eq_map]
    _ = s.attach.map fun x => f x.1 := by rw [pmap_eq_map_attach]
    _ = t.map g := by rw [this, Multiset.map_map]; 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
r : α → α → Prop
s✝ t✝ : Multiset α
a : α
f : α → γ
g : β → γ
s : Multiset α
t : Multiset β
hs : Nodup s
ht : Nodup t
i : (a : α) → a ∈ s → β
hi : ∀ (a : α) (ha : a ∈ s), i a ha ∈ t
h : ∀ (a : α) (ha : a ∈ s), f a = g (i a ha)
i_inj : ∀ (a₁ a₂ : α) (ha₁ : a₁ ∈ s) (ha₂ : a₂ ∈ s), i a₁ ha₁ = i a₂ ha₂ → a₁ = a₂
i_surj : ∀ b ∈ t, ∃ a, ∃ (ha : a ∈ s), b = i a ha
this : t = map (fun x => i ↑x (_ : ↑x ∈ s)) (attach s)
⊢ map (fun x => f ↑x) (attach s) = map (g ∘ fun x => i ↑x (_ : ↑x ∈ s)) (attach s)

Next tactic:
exact map_congr rfl fun x _ => h _ _
@[simp]
theorem coe_natLERec (m n : ℕ) (h : m ≤ n) :
    (natLERec f' m n h : G' m → G' n) = Nat.leRecOn h (@fun k => f' k) := by
  

Proof state:
L : Language
ι : Type v
inst✝² : Preorder ι
G : ι → Type w
inst✝¹ : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
G' : ℕ → Type w
inst✝ : (i : ℕ) → Structure L (G' i)
f' : (n : ℕ) → G' n ↪[L] G' (n + 1)
m n : ℕ
h : m ≤ n
⊢ ⇑(natLERec f' m n h) = fun a => Nat.leRecOn h (fun k => ⇑(f' k)) a

Next tactic:
obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_le h
@[simp]
theorem coe_natLERec (m n : ℕ) (h : m ≤ n) :
    (natLERec f' m n h : G' m → G' n) = Nat.leRecOn h (@fun k => f' k) := by
  obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_le h
  

Proof state:
case intro
L : Language
ι : Type v
inst✝² : Preorder ι
G : ι → Type w
inst✝¹ : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
G' : ℕ → Type w
inst✝ : (i : ℕ) → Structure L (G' i)
f' : (n : ℕ) → G' n ↪[L] G' (n + 1)
m k : ℕ
h : m ≤ m + k
⊢ ⇑(natLERec f' m (m + k) h) = fun a => Nat.leRecOn h (fun k => ⇑(f' k)) a

Next tactic:
ext x
@[simp]
theorem coe_natLERec (m n : ℕ) (h : m ≤ n) :
    (natLERec f' m n h : G' m → G' n) = Nat.leRecOn h (@fun k => f' k) := by
  obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_le h
  ext x
  

Proof state:
case intro.h
L : Language
ι : Type v
inst✝² : Preorder ι
G : ι → Type w
inst✝¹ : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
G' : ℕ → Type w
inst✝ : (i : ℕ) → Structure L (G' i)
f' : (n : ℕ) → G' n ↪[L] G' (n + 1)
m k : ℕ
h : m ≤ m + k
x : G' m
⊢ (natLERec f' m (m + k) h) x = Nat.leRecOn h (fun k => ⇑(f' k)) x

Next tactic:
induction' k with k ih
@[simp]
theorem coe_natLERec (m n : ℕ) (h : m ≤ n) :
    (natLERec f' m n h : G' m → G' n) = Nat.leRecOn h (@fun k => f' k) := by
  obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_le h
  ext x
  induction' k with k ih
  · -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    

Proof state:
case intro.h.zero
L : Language
ι : Type v
inst✝² : Preorder ι
G : ι → Type w
inst✝¹ : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
G' : ℕ → Type w
inst✝ : (i : ℕ) → Structure L (G' i)
f' : (n : ℕ) → G' n ↪[L] G' (n + 1)
m : ℕ
x : G' m
h : m ≤ m + Nat.zero
⊢ (natLERec f' m (m + Nat.zero) h) x = Nat.leRecOn h (fun k => ⇑(f' k)) x

Next tactic:
erw [natLERec, Nat.leRecOn_self, Embedding.refl_apply, Nat.leRecOn_self]
@[simp]
theorem coe_natLERec (m n : ℕ) (h : m ≤ n) :
    (natLERec f' m n h : G' m → G' n) = Nat.leRecOn h (@fun k => f' k) := by
  obtain ⟨k, rfl⟩ := Nat.exists_eq_add_of_le h
  ext x
  induction' k with k ih
  · -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    erw [natLERec, Nat.leRecOn_self, Embedding.refl_apply, Nat.leRecOn_self]
  · -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644
    

Proof state:
case intro.h.succ
L : Language
ι : Type v
inst✝² : Preorder ι
G : ι → Type w
inst✝¹ : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
G' : ℕ → Type w
inst✝ : (i : ℕ) → Structure L (G' i)
f' : (n : ℕ) → G' n ↪[L] G' (n + 1)
m : ℕ
x : G' m
k : ℕ
ih : ∀ (h : m ≤ m + k), (natLERec f' m (m + k) h) x = Nat.leRecOn h (fun k => ⇑(f' k)) x
h : m ≤ m + Nat.succ k
⊢ (natLERec f' m (m + Nat.succ k) h) x = Nat.leRecOn h (fun k => ⇑(f' k)) x

Next tactic:
erw [Nat.leRecOn_succ le_self_add, natLERec, Nat.leRecOn_succ le_self_add, ← natLERec,
      Embedding.comp_apply, ih]
instance natLERec.directedSystem : DirectedSystem G' fun i j h => natLERec f' i j h :=
  ⟨fun i x h => congr (congr rfl (Nat.leRecOn_self _)) rfl,
   fun hij hjk => by 

Proof state:
L : Language
ι : Type v
inst✝² : Preorder ι
G : ι → Type w
inst✝¹ : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
G' : ℕ → Type w
inst✝ : (i : ℕ) → Structure L (G' i)
f' : (n : ℕ) → G' n ↪[L] G' (n + 1)
i✝ j✝ k✝ : ℕ
hij : i✝ ≤ j✝
hjk : j✝ ≤ k✝
⊢ ∀ (x : G' i✝), (natLERec f' j✝ k✝ hjk) ((natLERec f' i✝ j✝ hij) x) = (natLERec f' i✝ k✝ (_ : i✝ ≤ k✝)) x

Next tactic:
simp [Nat.leRecOn_trans hij hjk]
@[simp]
theorem unify_sigma_mk_self {α : Type*} {i : ι} {x : α → G i} :
    (unify f (fun a => .mk f i (x a)) i fun j ⟨a, hj⟩ =>
      _root_.trans (le_of_eq hj.symm) (refl _)) = x := by
  

Proof state:
L : Language
ι : Type v
inst✝² : Preorder ι
G : ι → Type w
inst✝¹ : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
inst✝ : DirectedSystem G fun i j h => ⇑(f i j h)
α : Type u_1
i : ι
x : α → G i
⊢ unify f (fun a => Structure.Sigma.mk f i (x a)) i
      (_ : ∀ j ∈ range (Sigma.fst ∘ fun a => Structure.Sigma.mk f i (x a)), j ≤ i) =
    x

Next tactic:
ext a
@[simp]
theorem unify_sigma_mk_self {α : Type*} {i : ι} {x : α → G i} :
    (unify f (fun a => .mk f i (x a)) i fun j ⟨a, hj⟩ =>
      _root_.trans (le_of_eq hj.symm) (refl _)) = x := by
  ext a
  

Proof state:
case h
L : Language
ι : Type v
inst✝² : Preorder ι
G : ι → Type w
inst✝¹ : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
inst✝ : DirectedSystem G fun i j h => ⇑(f i j h)
α : Type u_1
i : ι
x : α → G i
a : α
⊢ unify f (fun a => Structure.Sigma.mk f i (x a)) i
      (_ : ∀ j ∈ range (Sigma.fst ∘ fun a => Structure.Sigma.mk f i (x a)), j ≤ i) a =
    x a

Next tactic:
rw [unify]
@[simp]
theorem unify_sigma_mk_self {α : Type*} {i : ι} {x : α → G i} :
    (unify f (fun a => .mk f i (x a)) i fun j ⟨a, hj⟩ =>
      _root_.trans (le_of_eq hj.symm) (refl _)) = x := by
  ext a
  rw [unify]
  

Proof state:
case h
L : Language
ι : Type v
inst✝² : Preorder ι
G : ι → Type w
inst✝¹ : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
inst✝ : DirectedSystem G fun i j h => ⇑(f i j h)
α : Type u_1
i : ι
x : α → G i
a : α
⊢ (f (Structure.Sigma.mk f i (x a)).fst i (_ : (Structure.Sigma.mk f i (x a)).fst ≤ i))
      (Structure.Sigma.mk f i (x a)).snd =
    x a

Next tactic:
apply DirectedSystem.map_self
theorem comp_unify {α : Type*} {x : α → Σˣ f} {i j : ι} (ij : i ≤ j)
    (h : i ∈ upperBounds (range (Sigma.fst ∘ x))) :
    f i j ij ∘ unify f x i h = unify f x j
      fun k hk => _root_.trans (mem_upperBounds.1 h k hk) ij := by
  

Proof state:
L : Language
ι : Type v
inst✝² : Preorder ι
G : ι → Type w
inst✝¹ : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
inst✝ : DirectedSystem G fun i j h => ⇑(f i j h)
α : Type u_1
x : α → Σˣ f
i j : ι
ij : i ≤ j
h : i ∈ upperBounds (range (Sigma.fst ∘ x))
⊢ ⇑(f i j ij) ∘ unify f x i h = unify f x j (_ : ∀ k ∈ range (Sigma.fst ∘ x), k ≤ j)

Next tactic:
ext a
theorem comp_unify {α : Type*} {x : α → Σˣ f} {i j : ι} (ij : i ≤ j)
    (h : i ∈ upperBounds (range (Sigma.fst ∘ x))) :
    f i j ij ∘ unify f x i h = unify f x j
      fun k hk => _root_.trans (mem_upperBounds.1 h k hk) ij := by
  ext a
  

Proof state:
case h
L : Language
ι : Type v
inst✝² : Preorder ι
G : ι → Type w
inst✝¹ : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
inst✝ : DirectedSystem G fun i j h => ⇑(f i j h)
α : Type u_1
x : α → Σˣ f
i j : ι
ij : i ≤ j
h : i ∈ upperBounds (range (Sigma.fst ∘ x))
a : α
⊢ (⇑(f i j ij) ∘ unify f x i h) a = unify f x j (_ : ∀ k ∈ range (Sigma.fst ∘ x), k ≤ j) a

Next tactic:
simp [unify, DirectedSystem.map_map]
/-- The directed limit glues together the structures along the embeddings. -/
def setoid [DirectedSystem G fun i j h => f i j h] [IsDirected ι (· ≤ ·)] : Setoid (Σˣ f) where
  r := fun ⟨i, x⟩ ⟨j, y⟩ => ∃ (k : ι) (ik : i ≤ k) (jk : j ≤ k), f i k ik x = f j k jk y
  iseqv :=
    ⟨fun ⟨i, x⟩ => ⟨i, refl i, refl i, rfl⟩, @fun ⟨i, x⟩ ⟨j, y⟩ ⟨k, ik, jk, h⟩ =>
      ⟨k, jk, ik, h.symm⟩,
      @fun ⟨i, x⟩ ⟨j, y⟩ ⟨k, z⟩ ⟨ij, hiij, hjij, hij⟩ ⟨jk, hjjk, hkjk, hjk⟩ => by
        

Proof state:
L : Language
ι : Type v
inst✝³ : Preorder ι
G : ι → Type w
inst✝² : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
inst✝¹ : DirectedSystem G fun i j h => ⇑(f i j h)
inst✝ : IsDirected ι fun x x_1 => x ≤ x_1
x✝⁴ x✝³ x✝² : Σˣ f
i : ι
x : (fun i => G i) i
j : ι
y : (fun i => G i) j
x✝¹ :
  match { fst := i, snd := x } with
  | { fst := i, snd := x } =>
    match { fst := j, snd := y } with
    | { fst := j, snd := y } => ∃ k, ∃ (ik : i ≤ k) (jk : j ≤ k), (f i k ik) x = (f j k jk) y
k : ι
z : (fun i => G i) k
x✝ :
  match { fst := j, snd := y } with
  | { fst := i, snd := x } =>
    match { fst := k, snd := z } with
    | { fst := j, snd := y } => ∃ k, ∃ (ik : i ≤ k) (jk : j ≤ k), (f i k ik) x = (f j k jk) y
ij : ι
hiij : i ≤ ij
hjij : j ≤ ij
hij : (f i ij hiij) x = (f j ij hjij) y
jk : ι
hjjk : j ≤ jk
hkjk : k ≤ jk
hjk : (f j jk hjjk) y = (f k jk hkjk) z
⊢ match { fst := i, snd := x } with
  | { fst := i, snd := x } =>
    match { fst := k, snd := z } with
    | { fst := j, snd := y } => ∃ k, ∃ (ik : i ≤ k) (jk : j ≤ k), (f i k ik) x = (f j k jk) y

Next tactic:
obtain ⟨ijk, hijijk, hjkijk⟩ := directed_of (· ≤ ·) ij jk
/-- The directed limit glues together the structures along the embeddings. -/
def setoid [DirectedSystem G fun i j h => f i j h] [IsDirected ι (· ≤ ·)] : Setoid (Σˣ f) where
  r := fun ⟨i, x⟩ ⟨j, y⟩ => ∃ (k : ι) (ik : i ≤ k) (jk : j ≤ k), f i k ik x = f j k jk y
  iseqv :=
    ⟨fun ⟨i, x⟩ => ⟨i, refl i, refl i, rfl⟩, @fun ⟨i, x⟩ ⟨j, y⟩ ⟨k, ik, jk, h⟩ =>
      ⟨k, jk, ik, h.symm⟩,
      @fun ⟨i, x⟩ ⟨j, y⟩ ⟨k, z⟩ ⟨ij, hiij, hjij, hij⟩ ⟨jk, hjjk, hkjk, hjk⟩ => by
        obtain ⟨ijk, hijijk, hjkijk⟩ := directed_of (· ≤ ·) ij jk
        

Proof state:
case intro.intro
L : Language
ι : Type v
inst✝³ : Preorder ι
G : ι → Type w
inst✝² : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
inst✝¹ : DirectedSystem G fun i j h => ⇑(f i j h)
inst✝ : IsDirected ι fun x x_1 => x ≤ x_1
x✝⁴ x✝³ x✝² : Σˣ f
i : ι
x : (fun i => G i) i
j : ι
y : (fun i => G i) j
x✝¹ :
  match { fst := i, snd := x } with
  | { fst := i, snd := x } =>
    match { fst := j, snd := y } with
    | { fst := j, snd := y } => ∃ k, ∃ (ik : i ≤ k) (jk : j ≤ k), (f i k ik) x = (f j k jk) y
k : ι
z : (fun i => G i) k
x✝ :
  match { fst := j, snd := y } with
  | { fst := i, snd := x } =>
    match { fst := k, snd := z } with
    | { fst := j, snd := y } => ∃ k, ∃ (ik : i ≤ k) (jk : j ≤ k), (f i k ik) x = (f j k jk) y
ij : ι
hiij : i ≤ ij
hjij : j ≤ ij
hij : (f i ij hiij) x = (f j ij hjij) y
jk : ι
hjjk : j ≤ jk
hkjk : k ≤ jk
hjk : (f j jk hjjk) y = (f k jk hkjk) z
ijk : ι
hijijk : ij ≤ ijk
hjkijk : jk ≤ ijk
⊢ match { fst := i, snd := x } with
  | { fst := i, snd := x } =>
    match { fst := k, snd := z } with
    | { fst := j, snd := y } => ∃ k, ∃ (ik : i ≤ k) (jk : j ≤ k), (f i k ik) x = (f j k jk) y

Next tactic:
refine' ⟨ijk, le_trans hiij hijijk, le_trans hkjk hjkijk, _⟩
/-- The directed limit glues together the structures along the embeddings. -/
def setoid [DirectedSystem G fun i j h => f i j h] [IsDirected ι (· ≤ ·)] : Setoid (Σˣ f) where
  r := fun ⟨i, x⟩ ⟨j, y⟩ => ∃ (k : ι) (ik : i ≤ k) (jk : j ≤ k), f i k ik x = f j k jk y
  iseqv :=
    ⟨fun ⟨i, x⟩ => ⟨i, refl i, refl i, rfl⟩, @fun ⟨i, x⟩ ⟨j, y⟩ ⟨k, ik, jk, h⟩ =>
      ⟨k, jk, ik, h.symm⟩,
      @fun ⟨i, x⟩ ⟨j, y⟩ ⟨k, z⟩ ⟨ij, hiij, hjij, hij⟩ ⟨jk, hjjk, hkjk, hjk⟩ => by
        obtain ⟨ijk, hijijk, hjkijk⟩ := directed_of (· ≤ ·) ij jk
        refine' ⟨ijk, le_trans hiij hijijk, le_trans hkjk hjkijk, _⟩
        

Proof state:
case intro.intro
L : Language
ι : Type v
inst✝³ : Preorder ι
G : ι → Type w
inst✝² : (i : ι) → Structure L (G i)
f : (i j : ι) → i ≤ j → G i ↪[L] G j
inst✝¹ : DirectedSystem G fun i j h => ⇑(f i j h)
inst✝ : IsDirected ι fun x x_1 => x ≤ x_1
x✝⁴ x✝³ x✝² : Σˣ f
i : ι
x : (fun i => G i) i
j : ι
y : (fun i => G i) j
x✝¹ :
  match { fst := i, snd := x } with
  | { fst := i, snd := x } =>
    match { fst := j, snd := y } with
    | { fst := j, snd := y } => ∃ k, ∃ (ik : i ≤ k) (jk : j ≤ k), (f i k ik) x = (f j k jk) y
k : ι
z : (fun i => G i) k
x✝ :
  match { fst := j, snd := y } with
  | { fst := i, snd := x } =>
    match { fst := k, snd := z } with
    | { fst := j, snd := y } => ∃ k, ∃ (ik : i ≤ k) (jk : j ≤ k), (f i k ik) x = (f j k jk) y
ij : ι
hiij : i ≤ ij
hjij : j ≤ ij
hij : (f i ij hiij) x = (f j ij hjij) y
jk : ι
hjjk : j ≤ jk
hkjk : k ≤ jk
hjk : (f j jk hjjk) y = (f k jk hkjk) z
ijk : ι
hijijk : ij ≤ ijk
hjkijk : jk ≤ ijk
⊢ (f i ijk (_ : i ≤ ijk)) x = (f k ijk (_ : k ≤ ijk)) z

Next tactic:
rw [← DirectedSystem.map_map, hij, DirectedSystem.map_map]