/-- The equivalence between a substructure `s` and its image `s.map f.toHom`, where `f` is an
  embedding. -/
noncomputable def substructureEquivMap (f : M ↪[L] N) (s : L.Substructure M) :
    s ≃[L] s.map f.toHom where
  toFun := codRestrict (s.map f.toHom) (f.domRestrict s) fun ⟨m, hm⟩ => ⟨m, hm, rfl⟩
  invFun n := ⟨Classical.choose n.2, (Classical.choose_spec n.2).1⟩
  left_inv := fun ⟨m, hm⟩ =>
    Subtype.mk_eq_mk.2
      (f.injective
        (Classical.choose_spec
            (codRestrict (s.map f.toHom) (f.domRestrict s) (fun ⟨m, hm⟩ => ⟨m, hm, rfl⟩)
                ⟨m, hm⟩).2).2)
  right_inv := fun ⟨n, hn⟩ => Subtype.mk_eq_mk.2 (Classical.choose_spec hn).2
  map_fun' {n} f x := 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
S : Substructure L M
f✝ : M ↪[L] N
s : Substructure L M
n : ℕ
f : Functions L n
x : Fin n → ↥s
⊢ Equiv.toFun
      {
        toFun :=
          ⇑(codRestrict (Substructure.map (toHom f✝) s) (domRestrict f✝ s)
              (_ : ∀ (x : ↥s), (domRestrict f✝ s) x ∈ Substructure.map (toHom f✝) s)),
        invFun := fun n =>
          { val := Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s),
            property := (_ : Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s) ∈ ↑s) },
        left_inv :=
          (_ :
            ∀ (x : ↥s),
              (fun n =>
                    { val := Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s),
                      property := (_ : Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s) ∈ ↑s) })
                  ((codRestrict (Substructure.map (toHom f✝) s) (domRestrict f✝ s)
                      (_ : ∀ (x : ↥s), (domRestrict f✝ s) x ∈ Substructure.map (toHom f✝) s))
                    x) =
                x),
        right_inv :=
          (_ :
            ∀ (x : ↥(Substructure.map (toHom f✝) s)),
              (codRestrict (Substructure.map (toHom f✝) s) (domRestrict f✝ s)
                    (_ : ∀ (x : ↥s), (domRestrict f✝ s) x ∈ Substructure.map (toHom f✝) s))
                  ((fun n =>
                      { val := Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s),
                        property := (_ : Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s) ∈ ↑s) })
                    x) =
                x) }
      (funMap f x) =
    funMap f
      ({
            toFun :=
              ⇑(codRestrict (Substructure.map (toHom f✝) s) (domRestrict f✝ s)
                  (_ : ∀ (x : ↥s), (domRestrict f✝ s) x ∈ Substructure.map (toHom f✝) s)),
            invFun := fun n =>
              { val := Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s),
                property := (_ : Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s) ∈ ↑s) },
            left_inv :=
              (_ :
                ∀ (x : ↥s),
                  (fun n =>
                        { val := Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s),
                          property := (_ : Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s) ∈ ↑s) })
                      ((codRestrict (Substructure.map (toHom f✝) s) (domRestrict f✝ s)
                          (_ : ∀ (x : ↥s), (domRestrict f✝ s) x ∈ Substructure.map (toHom f✝) s))
                        x) =
                    x),
            right_inv :=
              (_ :
                ∀ (x : ↥(Substructure.map (toHom f✝) s)),
                  (codRestrict (Substructure.map (toHom f✝) s) (domRestrict f✝ s)
                        (_ : ∀ (x : ↥s), (domRestrict f✝ s) x ∈ Substructure.map (toHom f✝) s))
                      ((fun n =>
                          { val := Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s),
                            property := (_ : Classical.choose (_ : ↑n ∈ Substructure.map (toHom f✝) s) ∈ ↑s) })
                        x) =
                    x) }.toFun ∘
        x)

Next tactic:
aesop