l3lab/ntp-mathlib huggingface dataset:
/-- Sufficient conditions for a class to be the age of a countably-generated structure. -/
theorem exists_cg_is_age_of (hn : K.Nonempty)
    (h : ∀ M N : Bundled.{w} L.Structure, Nonempty (M ≃[L] N) → (M ∈ K ↔ N ∈ K))
    (hc : (Quotient.mk' '' K).Countable)
    (fg : ∀ M : Bundled.{w} L.Structure, M ∈ K → Structure.FG L M) (hp : Hereditary K)
    (jep : JointEmbedding K) : ∃ M : Bundled.{w} L.Structure, Structure.CG L M ∧ L.age M = K := by
  obtain ⟨F, hF⟩ := hc.exists_eq_range (hn.image _)
  simp only [Set.ext_iff, Quotient.forall, mem_image, mem_range, Quotient.eq'] at hF
  simp_rw [Quotient.eq_mk_iff_out] at hF
  have hF' : ∀ n : ℕ, (F n).out ∈ K := by
    intro n
    obtain ⟨P, hP1, hP2⟩ := (hF (F n).out).2 ⟨n, Setoid.refl _⟩
    -- Porting note: fix hP2 because `Quotient.out (Quotient.mk' x) ≈ a` was not simplified
    -- to `x ≈ a` in hF
    replace hP2 := Setoid.trans (Setoid.symm (Quotient.mk_out P)) hP2
    exact (h _ _ hP2).1 hP1
  choose P hPK hP hFP using fun (N : K) (n : ℕ) => jep N N.2 (F (n + 1)).out (hF' _)
  let G : ℕ → K := @Nat.rec (fun _ => K) ⟨(F 0).out, hF' 0⟩ fun n N => ⟨P N n, hPK N n⟩
  -- Poting note: was
  -- let f : ∀ i j, i ≤ j → G i ↪[L] G j := DirectedSystem.natLeRec fun n => (hP _ n).some
  let f : ∀ (i j : ℕ), i ≤ j → (G i).val ↪[L] (G j).val := by
    refine DirectedSystem.natLERec (G' := fun i => (G i).val) (L := L) ?_
    dsimp only
    exact (fun n => (hP _ n).some)
  have : DirectedSystem (fun n ↦ (G n).val) fun i j h ↦ ↑(f i j h) := by
    dsimp; infer_instance
  

Proof state:
case intro
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝¹ : Structure L M
N : Type w
inst✝ : Structure L N
hn : Set.Nonempty K
h : ∀ (M N : Bundled (Structure L)), Nonempty (↑M ≃[L] ↑N) → (M ∈ K ↔ N ∈ K)
hc : Set.Countable (Quotient.mk' '' K)
fg : ∀ M ∈ K, Structure.FG L ↑M
hp : Hereditary K
jep : JointEmbedding K
F : ℕ → Quotient equivSetoid
hF : ∀ (a : Bundled (Structure L)), (∃ x ∈ K, Quotient.out (Quotient.mk' x) ≈ a) ↔ ∃ y, Quotient.out (F y) ≈ a
hF' : ∀ (n : ℕ), Quotient.out (F n) ∈ K
P : ↑K → ℕ → Bundled (Structure L)
hPK : ∀ (N : ↑K) (n : ℕ), P N n ∈ K
hP : ∀ (N : ↑K) (n : ℕ), (fun M N => Nonempty (↑M ↪[L] ↑N)) (↑N) (P N n)
hFP : ∀ (N : ↑K) (n : ℕ), (fun M N => Nonempty (↑M ↪[L] ↑N)) (Quotient.out (F (n + 1))) (P N n)
G : ℕ → ↑K :=
  Nat.rec { val := Quotient.out (F 0), property := (_ : Quotient.out (F 0) ∈ K) } fun n N =>
    { val := P N n, property := (_ : P N n ∈ K) }
f : (i j : ℕ) → i ≤ j → ↑↑(G i) ↪[L] ↑↑(G j) :=
  DirectedSystem.natLERec
    (id fun n =>
      Nonempty.some
        (_ :
          (fun M N => Nonempty (↑M ↪[L] ↑N))
            (↑(Nat.rec { val := Quotient.out (F 0), property := (_ : Quotient.out (F 0) ∈ K) }
                (fun n N => { val := P N n, property := (_ : P N n ∈ K) }) n))
            (P
              (Nat.rec { val := Quotient.out (F 0), property := (_ : Quotient.out (F 0) ∈ K) }
                (fun n N => { val := P N n, property := (_ : P N n ∈ K) }) n)
              n)))
this : DirectedSystem (fun n => ↑↑(G n)) fun i j h => ⇑(f i j h)
⊢ ∃ M, Structure.CG L ↑M ∧ age L ↑M = K

Next tactic:
refine ⟨Bundled.of (@DirectLimit L _ _ (fun n ↦ (G n).val) _ f _ _), ?_, ?_⟩
theorem exists_countable_is_age_of_iff [Countable (Σ l, L.Functions l)] :
    (∃ M : Bundled.{w} L.Structure, Countable M ∧ L.age M = K) ↔
      K.Nonempty ∧ (∀ M N : Bundled.{w} L.Structure, Nonempty (M ≃[L] N) → (M ∈ K ↔ N ∈ K)) ∧
      (Quotient.mk' '' K).Countable ∧ (∀ M : Bundled.{w} L.Structure, M ∈ K → Structure.FG L M) ∧
      Hereditary K ∧ JointEmbedding K := by
  

Proof state:
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝² : Structure L M
N : Type w
inst✝¹ : Structure L N
inst✝ : Countable ((l : ℕ) × Functions L l)
⊢ (∃ M, Countable ↑M ∧ age L ↑M = K) ↔
    Set.Nonempty K ∧
      (∀ (M N : Bundled (Structure L)), Nonempty (↑M ≃[L] ↑N) → (M ∈ K ↔ N ∈ K)) ∧
        Set.Countable (Quotient.mk' '' K) ∧ (∀ M ∈ K, Structure.FG L ↑M) ∧ Hereditary K ∧ JointEmbedding K

Next tactic:
constructor
theorem exists_countable_is_age_of_iff [Countable (Σ l, L.Functions l)] :
    (∃ M : Bundled.{w} L.Structure, Countable M ∧ L.age M = K) ↔
      K.Nonempty ∧ (∀ M N : Bundled.{w} L.Structure, Nonempty (M ≃[L] N) → (M ∈ K ↔ N ∈ K)) ∧
      (Quotient.mk' '' K).Countable ∧ (∀ M : Bundled.{w} L.Structure, M ∈ K → Structure.FG L M) ∧
      Hereditary K ∧ JointEmbedding K := by
  constructor
  · 

Proof state:
case mp
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝² : Structure L M
N : Type w
inst✝¹ : Structure L N
inst✝ : Countable ((l : ℕ) × Functions L l)
⊢ (∃ M, Countable ↑M ∧ age L ↑M = K) →
    Set.Nonempty K ∧
      (∀ (M N : Bundled (Structure L)), Nonempty (↑M ≃[L] ↑N) → (M ∈ K ↔ N ∈ K)) ∧
        Set.Countable (Quotient.mk' '' K) ∧ (∀ M ∈ K, Structure.FG L ↑M) ∧ Hereditary K ∧ JointEmbedding K

Next tactic:
rintro ⟨M, h1, h2, rfl⟩
theorem exists_countable_is_age_of_iff [Countable (Σ l, L.Functions l)] :
    (∃ M : Bundled.{w} L.Structure, Countable M ∧ L.age M = K) ↔
      K.Nonempty ∧ (∀ M N : Bundled.{w} L.Structure, Nonempty (M ≃[L] N) → (M ∈ K ↔ N ∈ K)) ∧
      (Quotient.mk' '' K).Countable ∧ (∀ M : Bundled.{w} L.Structure, M ∈ K → Structure.FG L M) ∧
      Hereditary K ∧ JointEmbedding K := by
  constructor
  · rintro ⟨M, h1, h2, rfl⟩
    

Proof state:
case mp.intro.intro.refl
L : Language
M✝ : Type w
inst✝² : Structure L M✝
N : Type w
inst✝¹ : Structure L N
inst✝ : Countable ((l : ℕ) × Functions L l)
M : Bundled (Structure L)
h1 : Countable ↑M
⊢ Set.Nonempty (age L ↑M) ∧
    (∀ (M_1 N : Bundled (Structure L)), Nonempty (↑M_1 ≃[L] ↑N) → (M_1 ∈ age L ↑M ↔ N ∈ age L ↑M)) ∧
      Set.Countable (Quotient.mk' '' age L ↑M) ∧
        (∀ M_1 ∈ age L ↑M, Structure.FG L ↑M_1) ∧ Hereditary (age L ↑M) ∧ JointEmbedding (age L ↑M)

Next tactic:
refine' ⟨age.nonempty M, age.is_equiv_invariant L M, age.countable_quotient M, fun N hN => hN.1,
      age.hereditary M, age.jointEmbedding M⟩
theorem exists_countable_is_age_of_iff [Countable (Σ l, L.Functions l)] :
    (∃ M : Bundled.{w} L.Structure, Countable M ∧ L.age M = K) ↔
      K.Nonempty ∧ (∀ M N : Bundled.{w} L.Structure, Nonempty (M ≃[L] N) → (M ∈ K ↔ N ∈ K)) ∧
      (Quotient.mk' '' K).Countable ∧ (∀ M : Bundled.{w} L.Structure, M ∈ K → Structure.FG L M) ∧
      Hereditary K ∧ JointEmbedding K := by
  constructor
  · rintro ⟨M, h1, h2, rfl⟩
    refine' ⟨age.nonempty M, age.is_equiv_invariant L M, age.countable_quotient M, fun N hN => hN.1,
      age.hereditary M, age.jointEmbedding M⟩
  · 

Proof state:
case mpr
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝² : Structure L M
N : Type w
inst✝¹ : Structure L N
inst✝ : Countable ((l : ℕ) × Functions L l)
⊢ Set.Nonempty K ∧
      (∀ (M N : Bundled (Structure L)), Nonempty (↑M ≃[L] ↑N) → (M ∈ K ↔ N ∈ K)) ∧
        Set.Countable (Quotient.mk' '' K) ∧ (∀ M ∈ K, Structure.FG L ↑M) ∧ Hereditary K ∧ JointEmbedding K →
    ∃ M, Countable ↑M ∧ age L ↑M = K

Next tactic:
rintro ⟨Kn, eqinv, cq, hfg, hp, jep⟩
theorem exists_countable_is_age_of_iff [Countable (Σ l, L.Functions l)] :
    (∃ M : Bundled.{w} L.Structure, Countable M ∧ L.age M = K) ↔
      K.Nonempty ∧ (∀ M N : Bundled.{w} L.Structure, Nonempty (M ≃[L] N) → (M ∈ K ↔ N ∈ K)) ∧
      (Quotient.mk' '' K).Countable ∧ (∀ M : Bundled.{w} L.Structure, M ∈ K → Structure.FG L M) ∧
      Hereditary K ∧ JointEmbedding K := by
  constructor
  · rintro ⟨M, h1, h2, rfl⟩
    refine' ⟨age.nonempty M, age.is_equiv_invariant L M, age.countable_quotient M, fun N hN => hN.1,
      age.hereditary M, age.jointEmbedding M⟩
  · rintro ⟨Kn, eqinv, cq, hfg, hp, jep⟩
    

Proof state:
case mpr.intro.intro.intro.intro.intro
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝² : Structure L M
N : Type w
inst✝¹ : Structure L N
inst✝ : Countable ((l : ℕ) × Functions L l)
Kn : Set.Nonempty K
eqinv : ∀ (M N : Bundled (Structure L)), Nonempty (↑M ≃[L] ↑N) → (M ∈ K ↔ N ∈ K)
cq : Set.Countable (Quotient.mk' '' K)
hfg : ∀ M ∈ K, Structure.FG L ↑M
hp : Hereditary K
jep : JointEmbedding K
⊢ ∃ M, Countable ↑M ∧ age L ↑M = K

Next tactic:
obtain ⟨M, hM, rfl⟩ := exists_cg_is_age_of Kn eqinv cq hfg hp jep
theorem exists_countable_is_age_of_iff [Countable (Σ l, L.Functions l)] :
    (∃ M : Bundled.{w} L.Structure, Countable M ∧ L.age M = K) ↔
      K.Nonempty ∧ (∀ M N : Bundled.{w} L.Structure, Nonempty (M ≃[L] N) → (M ∈ K ↔ N ∈ K)) ∧
      (Quotient.mk' '' K).Countable ∧ (∀ M : Bundled.{w} L.Structure, M ∈ K → Structure.FG L M) ∧
      Hereditary K ∧ JointEmbedding K := by
  constructor
  · rintro ⟨M, h1, h2, rfl⟩
    refine' ⟨age.nonempty M, age.is_equiv_invariant L M, age.countable_quotient M, fun N hN => hN.1,
      age.hereditary M, age.jointEmbedding M⟩
  · rintro ⟨Kn, eqinv, cq, hfg, hp, jep⟩
    obtain ⟨M, hM, rfl⟩ := exists_cg_is_age_of Kn eqinv cq hfg hp jep
    

Proof state:
case mpr.intro.intro.intro.intro.intro.intro.intro
L : Language
M✝ : Type w
inst✝² : Structure L M✝
N : Type w
inst✝¹ : Structure L N
inst✝ : Countable ((l : ℕ) × Functions L l)
M : Bundled (Structure L)
hM : Structure.CG L ↑M
Kn : Set.Nonempty (age L ↑M)
eqinv : ∀ (M_1 N : Bundled (Structure L)), Nonempty (↑M_1 ≃[L] ↑N) → (M_1 ∈ age L ↑M ↔ N ∈ age L ↑M)
cq : Set.Countable (Quotient.mk' '' age L ↑M)
hfg : ∀ M_1 ∈ age L ↑M, Structure.FG L ↑M_1
hp : Hereditary (age L ↑M)
jep : JointEmbedding (age L ↑M)
⊢ ∃ M_1, Countable ↑M_1 ∧ age L ↑M_1 = age L ↑M

Next tactic:
exact ⟨M, Structure.cg_iff_countable.1 hM, rfl⟩
theorem IsUltrahomogeneous.amalgamation_age (h : L.IsUltrahomogeneous M) :
    Amalgamation (L.age M) := by
  

Proof state:
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝¹ : Structure L M
N : Type w
inst✝ : Structure L N
h : IsUltrahomogeneous L M
⊢ Amalgamation (age L M)

Next tactic:
rintro N P Q NP NQ ⟨Nfg, ⟨-⟩⟩ ⟨Pfg, ⟨PM⟩⟩ ⟨Qfg, ⟨QM⟩⟩
theorem IsUltrahomogeneous.amalgamation_age (h : L.IsUltrahomogeneous M) :
    Amalgamation (L.age M) := by
  rintro N P Q NP NQ ⟨Nfg, ⟨-⟩⟩ ⟨Pfg, ⟨PM⟩⟩ ⟨Qfg, ⟨QM⟩⟩
  

Proof state:
case intro.intro.intro.intro.intro.intro
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝¹ : Structure L M
N✝ : Type w
inst✝ : Structure L N✝
h : IsUltrahomogeneous L M
N P Q : Bundled (Structure L)
NP : ↑N ↪[L] ↑P
NQ : ↑N ↪[L] ↑Q
Nfg : Structure.FG L ↑N
Pfg : Structure.FG L ↑P
PM : ↑P ↪[L] M
Qfg : Structure.FG L ↑Q
QM : ↑Q ↪[L] M
⊢ ∃ Q_1 NQ_1 PQ, Q_1 ∈ age L M ∧ Embedding.comp NQ_1 NP = Embedding.comp PQ NQ

Next tactic:
obtain ⟨g, hg⟩ := h (PM.comp NP).toHom.range (Nfg.range _)
    ((QM.comp NQ).comp (PM.comp NP).equivRange.symm.toEmbedding)
theorem IsUltrahomogeneous.amalgamation_age (h : L.IsUltrahomogeneous M) :
    Amalgamation (L.age M) := by
  rintro N P Q NP NQ ⟨Nfg, ⟨-⟩⟩ ⟨Pfg, ⟨PM⟩⟩ ⟨Qfg, ⟨QM⟩⟩
  obtain ⟨g, hg⟩ := h (PM.comp NP).toHom.range (Nfg.range _)
    ((QM.comp NQ).comp (PM.comp NP).equivRange.symm.toEmbedding)
  

Proof state:
case intro.intro.intro.intro.intro.intro.intro
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝¹ : Structure L M
N✝ : Type w
inst✝ : Structure L N✝
h : IsUltrahomogeneous L M
N P Q : Bundled (Structure L)
NP : ↑N ↪[L] ↑P
NQ : ↑N ↪[L] ↑Q
Nfg : Structure.FG L ↑N
Pfg : Structure.FG L ↑P
PM : ↑P ↪[L] M
Qfg : Structure.FG L ↑Q
QM : ↑Q ↪[L] M
g : M ≃[L] M
hg :
  Embedding.comp (Embedding.comp QM NQ) (Equiv.toEmbedding (Equiv.symm (Embedding.equivRange (Embedding.comp PM NP)))) =
    Embedding.comp (Equiv.toEmbedding g) (subtype (Hom.range (Embedding.toHom (Embedding.comp PM NP))))
⊢ ∃ Q_1 NQ_1 PQ, Q_1 ∈ age L M ∧ Embedding.comp NQ_1 NP = Embedding.comp PQ NQ

Next tactic:
let s := (g.toHom.comp PM.toHom).range ⊔ QM.toHom.range
theorem IsUltrahomogeneous.amalgamation_age (h : L.IsUltrahomogeneous M) :
    Amalgamation (L.age M) := by
  rintro N P Q NP NQ ⟨Nfg, ⟨-⟩⟩ ⟨Pfg, ⟨PM⟩⟩ ⟨Qfg, ⟨QM⟩⟩
  obtain ⟨g, hg⟩ := h (PM.comp NP).toHom.range (Nfg.range _)
    ((QM.comp NQ).comp (PM.comp NP).equivRange.symm.toEmbedding)
  let s := (g.toHom.comp PM.toHom).range ⊔ QM.toHom.range
  

Proof state:
case intro.intro.intro.intro.intro.intro.intro
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝¹ : Structure L M
N✝ : Type w
inst✝ : Structure L N✝
h : IsUltrahomogeneous L M
N P Q : Bundled (Structure L)
NP : ↑N ↪[L] ↑P
NQ : ↑N ↪[L] ↑Q
Nfg : Structure.FG L ↑N
Pfg : Structure.FG L ↑P
PM : ↑P ↪[L] M
Qfg : Structure.FG L ↑Q
QM : ↑Q ↪[L] M
g : M ≃[L] M
hg :
  Embedding.comp (Embedding.comp QM NQ) (Equiv.toEmbedding (Equiv.symm (Embedding.equivRange (Embedding.comp PM NP)))) =
    Embedding.comp (Equiv.toEmbedding g) (subtype (Hom.range (Embedding.toHom (Embedding.comp PM NP))))
s : Substructure L M := Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)
⊢ ∃ Q_1 NQ_1 PQ, Q_1 ∈ age L M ∧ Embedding.comp NQ_1 NP = Embedding.comp PQ NQ

Next tactic:
refine' ⟨Bundled.of s,
    Embedding.comp (Substructure.inclusion le_sup_left)
      (g.toEmbedding.comp PM).equivRange.toEmbedding,
    Embedding.comp (Substructure.inclusion le_sup_right) QM.equivRange.toEmbedding,
    ⟨(fg_iff_structure_fg _).1 (FG.sup (Pfg.range _) (Qfg.range _)), ⟨Substructure.subtype _⟩⟩, _⟩
theorem IsUltrahomogeneous.amalgamation_age (h : L.IsUltrahomogeneous M) :
    Amalgamation (L.age M) := by
  rintro N P Q NP NQ ⟨Nfg, ⟨-⟩⟩ ⟨Pfg, ⟨PM⟩⟩ ⟨Qfg, ⟨QM⟩⟩
  obtain ⟨g, hg⟩ := h (PM.comp NP).toHom.range (Nfg.range _)
    ((QM.comp NQ).comp (PM.comp NP).equivRange.symm.toEmbedding)
  let s := (g.toHom.comp PM.toHom).range ⊔ QM.toHom.range
  refine' ⟨Bundled.of s,
    Embedding.comp (Substructure.inclusion le_sup_left)
      (g.toEmbedding.comp PM).equivRange.toEmbedding,
    Embedding.comp (Substructure.inclusion le_sup_right) QM.equivRange.toEmbedding,
    ⟨(fg_iff_structure_fg _).1 (FG.sup (Pfg.range _) (Qfg.range _)), ⟨Substructure.subtype _⟩⟩, _⟩
  

Proof state:
case intro.intro.intro.intro.intro.intro.intro
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝¹ : Structure L M
N✝ : Type w
inst✝ : Structure L N✝
h : IsUltrahomogeneous L M
N P Q : Bundled (Structure L)
NP : ↑N ↪[L] ↑P
NQ : ↑N ↪[L] ↑Q
Nfg : Structure.FG L ↑N
Pfg : Structure.FG L ↑P
PM : ↑P ↪[L] M
Qfg : Structure.FG L ↑Q
QM : ↑Q ↪[L] M
g : M ≃[L] M
hg :
  Embedding.comp (Embedding.comp QM NQ) (Equiv.toEmbedding (Equiv.symm (Embedding.equivRange (Embedding.comp PM NP)))) =
    Embedding.comp (Equiv.toEmbedding g) (subtype (Hom.range (Embedding.toHom (Embedding.comp PM NP))))
s : Substructure L M := Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)
⊢ Embedding.comp
      (Embedding.comp
        (Substructure.inclusion
          (_ :
            Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ≤
              Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)))
        (Equiv.toEmbedding (Embedding.equivRange (Embedding.comp (Equiv.toEmbedding g) PM))))
      NP =
    Embedding.comp
      (Embedding.comp
        (Substructure.inclusion
          (_ :
            Hom.range (Embedding.toHom QM) ≤
              Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)))
        (Equiv.toEmbedding (Embedding.equivRange QM)))
      NQ

Next tactic:
ext n
theorem IsUltrahomogeneous.amalgamation_age (h : L.IsUltrahomogeneous M) :
    Amalgamation (L.age M) := by
  rintro N P Q NP NQ ⟨Nfg, ⟨-⟩⟩ ⟨Pfg, ⟨PM⟩⟩ ⟨Qfg, ⟨QM⟩⟩
  obtain ⟨g, hg⟩ := h (PM.comp NP).toHom.range (Nfg.range _)
    ((QM.comp NQ).comp (PM.comp NP).equivRange.symm.toEmbedding)
  let s := (g.toHom.comp PM.toHom).range ⊔ QM.toHom.range
  refine' ⟨Bundled.of s,
    Embedding.comp (Substructure.inclusion le_sup_left)
      (g.toEmbedding.comp PM).equivRange.toEmbedding,
    Embedding.comp (Substructure.inclusion le_sup_right) QM.equivRange.toEmbedding,
    ⟨(fg_iff_structure_fg _).1 (FG.sup (Pfg.range _) (Qfg.range _)), ⟨Substructure.subtype _⟩⟩, _⟩
  ext n
  

Proof state:
case intro.intro.intro.intro.intro.intro.intro.h
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝¹ : Structure L M
N✝ : Type w
inst✝ : Structure L N✝
h : IsUltrahomogeneous L M
N P Q : Bundled (Structure L)
NP : ↑N ↪[L] ↑P
NQ : ↑N ↪[L] ↑Q
Nfg : Structure.FG L ↑N
Pfg : Structure.FG L ↑P
PM : ↑P ↪[L] M
Qfg : Structure.FG L ↑Q
QM : ↑Q ↪[L] M
g : M ≃[L] M
hg :
  Embedding.comp (Embedding.comp QM NQ) (Equiv.toEmbedding (Equiv.symm (Embedding.equivRange (Embedding.comp PM NP)))) =
    Embedding.comp (Equiv.toEmbedding g) (subtype (Hom.range (Embedding.toHom (Embedding.comp PM NP))))
s : Substructure L M := Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)
n : ↑N
⊢ (Embedding.comp
        (Embedding.comp
          (Substructure.inclusion
            (_ :
              Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ≤
                Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)))
          (Equiv.toEmbedding (Embedding.equivRange (Embedding.comp (Equiv.toEmbedding g) PM))))
        NP)
      n =
    (Embedding.comp
        (Embedding.comp
          (Substructure.inclusion
            (_ :
              Hom.range (Embedding.toHom QM) ≤
                Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)))
          (Equiv.toEmbedding (Embedding.equivRange QM)))
        NQ)
      n

Next tactic:
apply Subtype.ext
theorem IsUltrahomogeneous.amalgamation_age (h : L.IsUltrahomogeneous M) :
    Amalgamation (L.age M) := by
  rintro N P Q NP NQ ⟨Nfg, ⟨-⟩⟩ ⟨Pfg, ⟨PM⟩⟩ ⟨Qfg, ⟨QM⟩⟩
  obtain ⟨g, hg⟩ := h (PM.comp NP).toHom.range (Nfg.range _)
    ((QM.comp NQ).comp (PM.comp NP).equivRange.symm.toEmbedding)
  let s := (g.toHom.comp PM.toHom).range ⊔ QM.toHom.range
  refine' ⟨Bundled.of s,
    Embedding.comp (Substructure.inclusion le_sup_left)
      (g.toEmbedding.comp PM).equivRange.toEmbedding,
    Embedding.comp (Substructure.inclusion le_sup_right) QM.equivRange.toEmbedding,
    ⟨(fg_iff_structure_fg _).1 (FG.sup (Pfg.range _) (Qfg.range _)), ⟨Substructure.subtype _⟩⟩, _⟩
  ext n
  apply Subtype.ext
  

Proof state:
case intro.intro.intro.intro.intro.intro.intro.h.a
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝¹ : Structure L M
N✝ : Type w
inst✝ : Structure L N✝
h : IsUltrahomogeneous L M
N P Q : Bundled (Structure L)
NP : ↑N ↪[L] ↑P
NQ : ↑N ↪[L] ↑Q
Nfg : Structure.FG L ↑N
Pfg : Structure.FG L ↑P
PM : ↑P ↪[L] M
Qfg : Structure.FG L ↑Q
QM : ↑Q ↪[L] M
g : M ≃[L] M
hg :
  Embedding.comp (Embedding.comp QM NQ) (Equiv.toEmbedding (Equiv.symm (Embedding.equivRange (Embedding.comp PM NP)))) =
    Embedding.comp (Equiv.toEmbedding g) (subtype (Hom.range (Embedding.toHom (Embedding.comp PM NP))))
s : Substructure L M := Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)
n : ↑N
⊢ ↑((Embedding.comp
          (Embedding.comp
            (Substructure.inclusion
              (_ :
                Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ≤
                  Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)))
            (Equiv.toEmbedding (Embedding.equivRange (Embedding.comp (Equiv.toEmbedding g) PM))))
          NP)
        n) =
    ↑((Embedding.comp
          (Embedding.comp
            (Substructure.inclusion
              (_ :
                Hom.range (Embedding.toHom QM) ≤
                  Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)))
            (Equiv.toEmbedding (Embedding.equivRange QM)))
          NQ)
        n)

Next tactic:
have hgn := (Embedding.ext_iff.1 hg) ((PM.comp NP).equivRange n)
theorem IsUltrahomogeneous.amalgamation_age (h : L.IsUltrahomogeneous M) :
    Amalgamation (L.age M) := by
  rintro N P Q NP NQ ⟨Nfg, ⟨-⟩⟩ ⟨Pfg, ⟨PM⟩⟩ ⟨Qfg, ⟨QM⟩⟩
  obtain ⟨g, hg⟩ := h (PM.comp NP).toHom.range (Nfg.range _)
    ((QM.comp NQ).comp (PM.comp NP).equivRange.symm.toEmbedding)
  let s := (g.toHom.comp PM.toHom).range ⊔ QM.toHom.range
  refine' ⟨Bundled.of s,
    Embedding.comp (Substructure.inclusion le_sup_left)
      (g.toEmbedding.comp PM).equivRange.toEmbedding,
    Embedding.comp (Substructure.inclusion le_sup_right) QM.equivRange.toEmbedding,
    ⟨(fg_iff_structure_fg _).1 (FG.sup (Pfg.range _) (Qfg.range _)), ⟨Substructure.subtype _⟩⟩, _⟩
  ext n
  apply Subtype.ext
  have hgn := (Embedding.ext_iff.1 hg) ((PM.comp NP).equivRange n)
  

Proof state:
case intro.intro.intro.intro.intro.intro.intro.h.a
L : Language
K : Set (Bundled (Structure L))
M : Type w
inst✝¹ : Structure L M
N✝ : Type w
inst✝ : Structure L N✝
h : IsUltrahomogeneous L M
N P Q : Bundled (Structure L)
NP : ↑N ↪[L] ↑P
NQ : ↑N ↪[L] ↑Q
Nfg : Structure.FG L ↑N
Pfg : Structure.FG L ↑P
PM : ↑P ↪[L] M
Qfg : Structure.FG L ↑Q
QM : ↑Q ↪[L] M
g : M ≃[L] M
hg :
  Embedding.comp (Embedding.comp QM NQ) (Equiv.toEmbedding (Equiv.symm (Embedding.equivRange (Embedding.comp PM NP)))) =
    Embedding.comp (Equiv.toEmbedding g) (subtype (Hom.range (Embedding.toHom (Embedding.comp PM NP))))
s : Substructure L M := Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)
n : ↑N
hgn :
  (Embedding.comp (Embedding.comp QM NQ) (Equiv.toEmbedding (Equiv.symm (Embedding.equivRange (Embedding.comp PM NP)))))
      ((Embedding.equivRange (Embedding.comp PM NP)) n) =
    (Embedding.comp (Equiv.toEmbedding g) (subtype (Hom.range (Embedding.toHom (Embedding.comp PM NP)))))
      ((Embedding.equivRange (Embedding.comp PM NP)) n)
⊢ ↑((Embedding.comp
          (Embedding.comp
            (Substructure.inclusion
              (_ :
                Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ≤
                  Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)))
            (Equiv.toEmbedding (Embedding.equivRange (Embedding.comp (Equiv.toEmbedding g) PM))))
          NP)
        n) =
    ↑((Embedding.comp
          (Embedding.comp
            (Substructure.inclusion
              (_ :
                Hom.range (Embedding.toHom QM) ≤
                  Hom.range (Hom.comp (Equiv.toHom g) (Embedding.toHom PM)) ⊔ Hom.range (Embedding.toHom QM)))
            (Equiv.toEmbedding (Embedding.equivRange QM)))
          NQ)
        n)

Next tactic:
simp only [Embedding.comp_apply, Equiv.coe_toEmbedding, Equiv.symm_apply_apply,
    Substructure.coeSubtype, Embedding.equivRange_apply] at hgn