l3lab/ntp-mathlib huggingface dataset:
theorem FG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).FG) : s.FG := by
  rcases hs with ⟨t, h⟩
  rw [fg_def]
  refine' ⟨f ⁻¹' t, t.finite_toSet.preimage (f.injective.injOn _), _⟩
  have hf : Function.Injective f.toHom := f.injective
  refine' map_injective_of_injective hf _
  rw [← h, map_closure, Embedding.coe_toHom, image_preimage_eq_of_subset]
  

Proof state:
case intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Finset N
h : LowerAdjoint.toFun (closure L) ↑t = Substructure.map (Embedding.toHom f) s
hf : Function.Injective ⇑(Embedding.toHom f)
⊢ ↑t ⊆ range ⇑f

Next tactic:
intro x hx
theorem FG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).FG) : s.FG := by
  rcases hs with ⟨t, h⟩
  rw [fg_def]
  refine' ⟨f ⁻¹' t, t.finite_toSet.preimage (f.injective.injOn _), _⟩
  have hf : Function.Injective f.toHom := f.injective
  refine' map_injective_of_injective hf _
  rw [← h, map_closure, Embedding.coe_toHom, image_preimage_eq_of_subset]
  intro x hx
  

Proof state:
case intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Finset N
h : LowerAdjoint.toFun (closure L) ↑t = Substructure.map (Embedding.toHom f) s
hf : Function.Injective ⇑(Embedding.toHom f)
x : N
hx : x ∈ ↑t
⊢ x ∈ range ⇑f

Next tactic:
have h' := subset_closure (L := L) hx
theorem FG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).FG) : s.FG := by
  rcases hs with ⟨t, h⟩
  rw [fg_def]
  refine' ⟨f ⁻¹' t, t.finite_toSet.preimage (f.injective.injOn _), _⟩
  have hf : Function.Injective f.toHom := f.injective
  refine' map_injective_of_injective hf _
  rw [← h, map_closure, Embedding.coe_toHom, image_preimage_eq_of_subset]
  intro x hx
  have h' := subset_closure (L := L) hx
  

Proof state:
case intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Finset N
h : LowerAdjoint.toFun (closure L) ↑t = Substructure.map (Embedding.toHom f) s
hf : Function.Injective ⇑(Embedding.toHom f)
x : N
hx : x ∈ ↑t
h' : x ∈ ↑(LowerAdjoint.toFun (closure L) ↑t)
⊢ x ∈ range ⇑f

Next tactic:
rw [h] at h'
theorem FG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).FG) : s.FG := by
  rcases hs with ⟨t, h⟩
  rw [fg_def]
  refine' ⟨f ⁻¹' t, t.finite_toSet.preimage (f.injective.injOn _), _⟩
  have hf : Function.Injective f.toHom := f.injective
  refine' map_injective_of_injective hf _
  rw [← h, map_closure, Embedding.coe_toHom, image_preimage_eq_of_subset]
  intro x hx
  have h' := subset_closure (L := L) hx
  rw [h] at h'
  

Proof state:
case intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Finset N
h : LowerAdjoint.toFun (closure L) ↑t = Substructure.map (Embedding.toHom f) s
hf : Function.Injective ⇑(Embedding.toHom f)
x : N
hx : x ∈ ↑t
h' : x ∈ ↑(Substructure.map (Embedding.toHom f) s)
⊢ x ∈ range ⇑f

Next tactic:
exact Hom.map_le_range h'
theorem FG.cg {N : L.Substructure M} (h : N.FG) : N.CG := by
  

Proof state:
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
h : FG N
⊢ CG N

Next tactic:
obtain ⟨s, hf, rfl⟩ := fg_def.1 h
theorem FG.cg {N : L.Substructure M} (h : N.FG) : N.CG := by
  obtain ⟨s, hf, rfl⟩ := fg_def.1 h
  

Proof state:
case intro.intro
L : Language
M : Type u_1
inst✝ : Structure L M
s : Set M
hf : Set.Finite s
h : FG (LowerAdjoint.toFun (closure L) s)
⊢ CG (LowerAdjoint.toFun (closure L) s)

Next tactic:
refine' ⟨s, hf.countable, rfl⟩
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  

Proof state:
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
⊢ CG N ↔ ↑N = ∅ ∨ ∃ s, LowerAdjoint.toFun (closure L) (range s) = N

Next tactic:
rw [cg_def]
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  

Proof state:
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
⊢ (∃ S, Set.Countable S ∧ LowerAdjoint.toFun (closure L) S = N) ↔
    ↑N = ∅ ∨ ∃ s, LowerAdjoint.toFun (closure L) (range s) = N

Next tactic:
constructor
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · 

Proof state:
case mp
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
⊢ (∃ S, Set.Countable S ∧ LowerAdjoint.toFun (closure L) S = N) →
    ↑N = ∅ ∨ ∃ s, LowerAdjoint.toFun (closure L) (range s) = N

Next tactic:
rintro ⟨S, Scount, hS⟩
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    

Proof state:
case mp.intro.intro
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
S : Set M
Scount : Set.Countable S
hS : LowerAdjoint.toFun (closure L) S = N
⊢ ↑N = ∅ ∨ ∃ s, LowerAdjoint.toFun (closure L) (range s) = N

Next tactic:
rcases eq_empty_or_nonempty (N : Set M) with h | h
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · 

Proof state:
case mp.intro.intro.inl
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
S : Set M
Scount : Set.Countable S
hS : LowerAdjoint.toFun (closure L) S = N
h : ↑N = ∅
⊢ ↑N = ∅ ∨ ∃ s, LowerAdjoint.toFun (closure L) (range s) = N

Next tactic:
exact Or.intro_left _ h
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · exact Or.intro_left _ h
    

Proof state:
case mp.intro.intro.inr
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
S : Set M
Scount : Set.Countable S
hS : LowerAdjoint.toFun (closure L) S = N
h : Set.Nonempty ↑N
⊢ ↑N = ∅ ∨ ∃ s, LowerAdjoint.toFun (closure L) (range s) = N

Next tactic:
obtain ⟨f, h'⟩ :=
      (Scount.union (Set.countable_singleton h.some)).exists_eq_range
        (singleton_nonempty h.some).inr
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · exact Or.intro_left _ h
    obtain ⟨f, h'⟩ :=
      (Scount.union (Set.countable_singleton h.some)).exists_eq_range
        (singleton_nonempty h.some).inr
    

Proof state:
case mp.intro.intro.inr.intro
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
S : Set M
Scount : Set.Countable S
hS : LowerAdjoint.toFun (closure L) S = N
h : Set.Nonempty ↑N
f : ℕ → M
h' : S ∪ {Set.Nonempty.some h} = range f
⊢ ↑N = ∅ ∨ ∃ s, LowerAdjoint.toFun (closure L) (range s) = N

Next tactic:
refine' Or.intro_right _ ⟨f, _⟩
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · exact Or.intro_left _ h
    obtain ⟨f, h'⟩ :=
      (Scount.union (Set.countable_singleton h.some)).exists_eq_range
        (singleton_nonempty h.some).inr
    refine' Or.intro_right _ ⟨f, _⟩
    

Proof state:
case mp.intro.intro.inr.intro
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
S : Set M
Scount : Set.Countable S
hS : LowerAdjoint.toFun (closure L) S = N
h : Set.Nonempty ↑N
f : ℕ → M
h' : S ∪ {Set.Nonempty.some h} = range f
⊢ LowerAdjoint.toFun (closure L) (range f) = N

Next tactic:
rw [← h', closure_union, hS, sup_eq_left, closure_le]
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · exact Or.intro_left _ h
    obtain ⟨f, h'⟩ :=
      (Scount.union (Set.countable_singleton h.some)).exists_eq_range
        (singleton_nonempty h.some).inr
    refine' Or.intro_right _ ⟨f, _⟩
    rw [← h', closure_union, hS, sup_eq_left, closure_le]
    

Proof state:
case mp.intro.intro.inr.intro
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
S : Set M
Scount : Set.Countable S
hS : LowerAdjoint.toFun (closure L) S = N
h : Set.Nonempty ↑N
f : ℕ → M
h' : S ∪ {Set.Nonempty.some h} = range f
⊢ {Set.Nonempty.some h} ⊆ ↑N

Next tactic:
exact singleton_subset_iff.2 h.some_mem
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · exact Or.intro_left _ h
    obtain ⟨f, h'⟩ :=
      (Scount.union (Set.countable_singleton h.some)).exists_eq_range
        (singleton_nonempty h.some).inr
    refine' Or.intro_right _ ⟨f, _⟩
    rw [← h', closure_union, hS, sup_eq_left, closure_le]
    exact singleton_subset_iff.2 h.some_mem
  · 

Proof state:
case mpr
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
⊢ (↑N = ∅ ∨ ∃ s, LowerAdjoint.toFun (closure L) (range s) = N) →
    ∃ S, Set.Countable S ∧ LowerAdjoint.toFun (closure L) S = N

Next tactic:
intro h
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · exact Or.intro_left _ h
    obtain ⟨f, h'⟩ :=
      (Scount.union (Set.countable_singleton h.some)).exists_eq_range
        (singleton_nonempty h.some).inr
    refine' Or.intro_right _ ⟨f, _⟩
    rw [← h', closure_union, hS, sup_eq_left, closure_le]
    exact singleton_subset_iff.2 h.some_mem
  · intro h
    

Proof state:
case mpr
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
h : ↑N = ∅ ∨ ∃ s, LowerAdjoint.toFun (closure L) (range s) = N
⊢ ∃ S, Set.Countable S ∧ LowerAdjoint.toFun (closure L) S = N

Next tactic:
cases' h with h h
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · exact Or.intro_left _ h
    obtain ⟨f, h'⟩ :=
      (Scount.union (Set.countable_singleton h.some)).exists_eq_range
        (singleton_nonempty h.some).inr
    refine' Or.intro_right _ ⟨f, _⟩
    rw [← h', closure_union, hS, sup_eq_left, closure_le]
    exact singleton_subset_iff.2 h.some_mem
  · intro h
    cases' h with h h
    · 

Proof state:
case mpr.inl
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
h : ↑N = ∅
⊢ ∃ S, Set.Countable S ∧ LowerAdjoint.toFun (closure L) S = N

Next tactic:
refine' ⟨∅, countable_empty, closure_eq_of_le (empty_subset _) _⟩
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · exact Or.intro_left _ h
    obtain ⟨f, h'⟩ :=
      (Scount.union (Set.countable_singleton h.some)).exists_eq_range
        (singleton_nonempty h.some).inr
    refine' Or.intro_right _ ⟨f, _⟩
    rw [← h', closure_union, hS, sup_eq_left, closure_le]
    exact singleton_subset_iff.2 h.some_mem
  · intro h
    cases' h with h h
    · refine' ⟨∅, countable_empty, closure_eq_of_le (empty_subset _) _⟩
      

Proof state:
case mpr.inl
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
h : ↑N = ∅
⊢ N ≤ LowerAdjoint.toFun (closure L) ∅

Next tactic:
rw [← SetLike.coe_subset_coe, h]
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · exact Or.intro_left _ h
    obtain ⟨f, h'⟩ :=
      (Scount.union (Set.countable_singleton h.some)).exists_eq_range
        (singleton_nonempty h.some).inr
    refine' Or.intro_right _ ⟨f, _⟩
    rw [← h', closure_union, hS, sup_eq_left, closure_le]
    exact singleton_subset_iff.2 h.some_mem
  · intro h
    cases' h with h h
    · refine' ⟨∅, countable_empty, closure_eq_of_le (empty_subset _) _⟩
      rw [← SetLike.coe_subset_coe, h]
      

Proof state:
case mpr.inl
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
h : ↑N = ∅
⊢ ∅ ⊆ ↑(LowerAdjoint.toFun (closure L) ∅)

Next tactic:
exact empty_subset _
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · exact Or.intro_left _ h
    obtain ⟨f, h'⟩ :=
      (Scount.union (Set.countable_singleton h.some)).exists_eq_range
        (singleton_nonempty h.some).inr
    refine' Or.intro_right _ ⟨f, _⟩
    rw [← h', closure_union, hS, sup_eq_left, closure_le]
    exact singleton_subset_iff.2 h.some_mem
  · intro h
    cases' h with h h
    · refine' ⟨∅, countable_empty, closure_eq_of_le (empty_subset _) _⟩
      rw [← SetLike.coe_subset_coe, h]
      exact empty_subset _
    · 

Proof state:
case mpr.inr
L : Language
M : Type u_1
inst✝ : Structure L M
N : Substructure L M
h : ∃ s, LowerAdjoint.toFun (closure L) (range s) = N
⊢ ∃ S, Set.Countable S ∧ LowerAdjoint.toFun (closure L) S = N

Next tactic:
obtain ⟨f, rfl⟩ := h
theorem cg_iff_empty_or_exists_nat_generating_family {N : L.Substructure M} :
    N.CG ↔ N = (∅ : Set M) ∨ ∃ s : ℕ → M, closure L (range s) = N := by
  rw [cg_def]
  constructor
  · rintro ⟨S, Scount, hS⟩
    rcases eq_empty_or_nonempty (N : Set M) with h | h
    · exact Or.intro_left _ h
    obtain ⟨f, h'⟩ :=
      (Scount.union (Set.countable_singleton h.some)).exists_eq_range
        (singleton_nonempty h.some).inr
    refine' Or.intro_right _ ⟨f, _⟩
    rw [← h', closure_union, hS, sup_eq_left, closure_le]
    exact singleton_subset_iff.2 h.some_mem
  · intro h
    cases' h with h h
    · refine' ⟨∅, countable_empty, closure_eq_of_le (empty_subset _) _⟩
      rw [← SetLike.coe_subset_coe, h]
      exact empty_subset _
    · obtain ⟨f, rfl⟩ := h
      

Proof state:
case mpr.inr.intro
L : Language
M : Type u_1
inst✝ : Structure L M
f : ℕ → M
⊢ ∃ S, Set.Countable S ∧ LowerAdjoint.toFun (closure L) S = LowerAdjoint.toFun (closure L) (range f)

Next tactic:
exact ⟨range f, countable_range _, rfl⟩
theorem CG.sup {N₁ N₂ : L.Substructure M} (hN₁ : N₁.CG) (hN₂ : N₂.CG) : (N₁ ⊔ N₂).CG :=
  let ⟨t₁, ht₁⟩ := cg_def.1 hN₁
  let ⟨t₂, ht₂⟩ := cg_def.1 hN₂
  cg_def.2 ⟨t₁ ∪ t₂, ht₁.1.union ht₂.1, by 

Proof state:
L : Language
M : Type u_1
inst✝ : Structure L M
N₁ N₂ : Substructure L M
hN₁ : CG N₁
hN₂ : CG N₂
t₁ : Set M
ht₁ : Set.Countable t₁ ∧ LowerAdjoint.toFun (closure L) t₁ = N₁
t₂ : Set M
ht₂ : Set.Countable t₂ ∧ LowerAdjoint.toFun (closure L) t₂ = N₂
⊢ LowerAdjoint.toFun (closure L) (t₁ ∪ t₂) = N₁ ⊔ N₂

Next tactic:
rw [closure_union, ht₁.2, ht₂.2]
theorem CG.map {N : Type*} [L.Structure N] (f : M →[L] N) {s : L.Substructure M} (hs : s.CG) :
    (s.map f).CG :=
  let ⟨t, ht⟩ := cg_def.1 hs
  cg_def.2 ⟨f '' t, ht.1.image _, by 

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M →[L] N
s : Substructure L M
hs : CG s
t : Set M
ht : Set.Countable t ∧ LowerAdjoint.toFun (closure L) t = s
⊢ LowerAdjoint.toFun (closure L) (⇑f '' t) = Substructure.map f s

Next tactic:
rw [closure_image, ht.2]
theorem CG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).CG) : s.CG := by
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
hs : CG (Substructure.map (Embedding.toHom f) s)
⊢ CG s

Next tactic:
rcases hs with ⟨t, h1, h2⟩
theorem CG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).CG) : s.CG := by
  rcases hs with ⟨t, h1, h2⟩
  

Proof state:
case intro.intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Set N
h1 : Set.Countable t
h2 : LowerAdjoint.toFun (closure L) t = Substructure.map (Embedding.toHom f) s
⊢ CG s

Next tactic:
rw [cg_def]
theorem CG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).CG) : s.CG := by
  rcases hs with ⟨t, h1, h2⟩
  rw [cg_def]
  

Proof state:
case intro.intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Set N
h1 : Set.Countable t
h2 : LowerAdjoint.toFun (closure L) t = Substructure.map (Embedding.toHom f) s
⊢ ∃ S, Set.Countable S ∧ LowerAdjoint.toFun (closure L) S = s

Next tactic:
refine' ⟨f ⁻¹' t, h1.preimage f.injective, _⟩
theorem CG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).CG) : s.CG := by
  rcases hs with ⟨t, h1, h2⟩
  rw [cg_def]
  refine' ⟨f ⁻¹' t, h1.preimage f.injective, _⟩
  

Proof state:
case intro.intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Set N
h1 : Set.Countable t
h2 : LowerAdjoint.toFun (closure L) t = Substructure.map (Embedding.toHom f) s
⊢ LowerAdjoint.toFun (closure L) (⇑f ⁻¹' t) = s

Next tactic:
have hf : Function.Injective f.toHom := f.injective
theorem CG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).CG) : s.CG := by
  rcases hs with ⟨t, h1, h2⟩
  rw [cg_def]
  refine' ⟨f ⁻¹' t, h1.preimage f.injective, _⟩
  have hf : Function.Injective f.toHom := f.injective
  

Proof state:
case intro.intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Set N
h1 : Set.Countable t
h2 : LowerAdjoint.toFun (closure L) t = Substructure.map (Embedding.toHom f) s
hf : Function.Injective ⇑(Embedding.toHom f)
⊢ LowerAdjoint.toFun (closure L) (⇑f ⁻¹' t) = s

Next tactic:
refine' map_injective_of_injective hf _
theorem CG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).CG) : s.CG := by
  rcases hs with ⟨t, h1, h2⟩
  rw [cg_def]
  refine' ⟨f ⁻¹' t, h1.preimage f.injective, _⟩
  have hf : Function.Injective f.toHom := f.injective
  refine' map_injective_of_injective hf _
  

Proof state:
case intro.intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Set N
h1 : Set.Countable t
h2 : LowerAdjoint.toFun (closure L) t = Substructure.map (Embedding.toHom f) s
hf : Function.Injective ⇑(Embedding.toHom f)
⊢ Substructure.map (Embedding.toHom f) (LowerAdjoint.toFun (closure L) (⇑f ⁻¹' t)) =
    Substructure.map (Embedding.toHom f) s

Next tactic:
rw [← h2, map_closure, Embedding.coe_toHom, image_preimage_eq_of_subset]
theorem CG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).CG) : s.CG := by
  rcases hs with ⟨t, h1, h2⟩
  rw [cg_def]
  refine' ⟨f ⁻¹' t, h1.preimage f.injective, _⟩
  have hf : Function.Injective f.toHom := f.injective
  refine' map_injective_of_injective hf _
  rw [← h2, map_closure, Embedding.coe_toHom, image_preimage_eq_of_subset]
  

Proof state:
case intro.intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Set N
h1 : Set.Countable t
h2 : LowerAdjoint.toFun (closure L) t = Substructure.map (Embedding.toHom f) s
hf : Function.Injective ⇑(Embedding.toHom f)
⊢ t ⊆ range ⇑f

Next tactic:
intro x hx
theorem CG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).CG) : s.CG := by
  rcases hs with ⟨t, h1, h2⟩
  rw [cg_def]
  refine' ⟨f ⁻¹' t, h1.preimage f.injective, _⟩
  have hf : Function.Injective f.toHom := f.injective
  refine' map_injective_of_injective hf _
  rw [← h2, map_closure, Embedding.coe_toHom, image_preimage_eq_of_subset]
  intro x hx
  

Proof state:
case intro.intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Set N
h1 : Set.Countable t
h2 : LowerAdjoint.toFun (closure L) t = Substructure.map (Embedding.toHom f) s
hf : Function.Injective ⇑(Embedding.toHom f)
x : N
hx : x ∈ t
⊢ x ∈ range ⇑f

Next tactic:
have h' := subset_closure (L := L) hx
theorem CG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).CG) : s.CG := by
  rcases hs with ⟨t, h1, h2⟩
  rw [cg_def]
  refine' ⟨f ⁻¹' t, h1.preimage f.injective, _⟩
  have hf : Function.Injective f.toHom := f.injective
  refine' map_injective_of_injective hf _
  rw [← h2, map_closure, Embedding.coe_toHom, image_preimage_eq_of_subset]
  intro x hx
  have h' := subset_closure (L := L) hx
  

Proof state:
case intro.intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Set N
h1 : Set.Countable t
h2 : LowerAdjoint.toFun (closure L) t = Substructure.map (Embedding.toHom f) s
hf : Function.Injective ⇑(Embedding.toHom f)
x : N
hx : x ∈ t
h' : x ∈ ↑(LowerAdjoint.toFun (closure L) t)
⊢ x ∈ range ⇑f

Next tactic:
rw [h2] at h'
theorem CG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L.Substructure M}
    (hs : (s.map f.toHom).CG) : s.CG := by
  rcases hs with ⟨t, h1, h2⟩
  rw [cg_def]
  refine' ⟨f ⁻¹' t, h1.preimage f.injective, _⟩
  have hf : Function.Injective f.toHom := f.injective
  refine' map_injective_of_injective hf _
  rw [← h2, map_closure, Embedding.coe_toHom, image_preimage_eq_of_subset]
  intro x hx
  have h' := subset_closure (L := L) hx
  rw [h2] at h'
  

Proof state:
case intro.intro
L : Language
M : Type u_1
inst✝¹ : Structure L M
N : Type u_2
inst✝ : Structure L N
f : M ↪[L] N
s : Substructure L M
t : Set N
h1 : Set.Countable t
h2 : LowerAdjoint.toFun (closure L) t = Substructure.map (Embedding.toHom f) s
hf : Function.Injective ⇑(Embedding.toHom f)
x : N
hx : x ∈ t
h' : x ∈ ↑(Substructure.map (Embedding.toHom f) s)
⊢ x ∈ range ⇑f

Next tactic:
exact Hom.map_le_range h'
theorem cg_iff_countable [Countable (Σl, L.Functions l)] {s : L.Substructure M} :
    s.CG ↔ Countable s := by
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
inst✝ : Countable ((l : ℕ) × Functions L l)
s : Substructure L M
⊢ CG s ↔ Countable ↥s

Next tactic:
refine' ⟨_, fun h => ⟨s, h.to_set, s.closure_eq⟩⟩
theorem cg_iff_countable [Countable (Σl, L.Functions l)] {s : L.Substructure M} :
    s.CG ↔ Countable s := by
  refine' ⟨_, fun h => ⟨s, h.to_set, s.closure_eq⟩⟩
  

Proof state:
L : Language
M : Type u_1
inst✝¹ : Structure L M
inst✝ : Countable ((l : ℕ) × Functions L l)
s : Substructure L M
⊢ CG s → Countable ↥s

Next tactic:
rintro ⟨s, h, rfl⟩