Definition substituteFormulaImp (f : fol.Formula L)
  (frec : nat * fol.Term L -> {y : fol.Formula L | depth L y = depth L f})
  (g : fol.Formula L)
  (grec : nat * fol.Term L -> {y : fol.Formula L | depth L y = depth L g})
  (p : nat * fol.Term L) :
  {y : fol.Formula L | depth L y = depth L (impH f g)} :=
  match frec p with
  | exist f' prf1 =>
      match grec p with
      | exist g' prf2 =>
          exist
            (fun y : fol.Formula L =>
             depth L y = S (max (depth L f) (depth L g))) 
            (impH f' g')
            (eq_ind_r
               (fun n : nat =>
                S (max n (depth L g')) = S (max (depth L f) (depth L g)))
               (eq_ind_r
                  (fun n : nat =>
                   S (max (depth L f) n) = S (max (depth L f) (depth L g)))
                  (refl_equal (S (max (depth L f) (depth L g)))) prf2) prf1)
      end
  end.Remark substituteFormulaImpNice :
 forall (f g : fol.Formula L)
   (z1 z2 : nat * fol.Term L -> {y : fol.Formula L | depth L y = depth L f}),
 (forall q : nat * fol.Term L, z1 q = z2 q) ->
 forall
   z3 z4 : nat * fol.Term L -> {y : fol.Formula L | depth L y = depth L g},
 (forall q : nat * fol.Term L, z3 q = z4 q) ->
 forall q : nat * fol.Term L,
 substituteFormulaImp f z1 g z3 q = substituteFormulaImp f z2 g z4 q.Definition substituteFormulaNot (f : fol.Formula L)
  (frec : nat * fol.Term L -> {y : fol.Formula L | depth L y = depth L f})
  (p : nat * fol.Term L) :
  {y : fol.Formula L | depth L y = depth L (notH f)} :=
  match frec p with
  | exist f' prf1 =>
      exist (fun y : fol.Formula L => depth L y = S (depth L f)) 
        (notH f')
        (eq_ind_r (fun n : nat => S n = S (depth L f))
           (refl_equal (S (depth L f))) prf1)
  end.Remark substituteFormulaNotNice :
 forall (f : fol.Formula L)
   (z1 z2 : nat * fol.Term L -> {y : fol.Formula L | depth L y = depth L f}),
 (forall q : nat * fol.Term L, z1 q = z2 q) ->
 forall q : nat * fol.Term L,
 substituteFormulaNot f z1 q = substituteFormulaNot f z2 q.Definition substituteFormulaForall (n : nat) (f : fol.Formula L)
  (frec : forall b : fol.Formula L,
          lt_depth b (forallH n f) ->
          nat * fol.Term L -> {y : fol.Formula L | depth L y = depth L b})
  (p : nat * fol.Term L) :
  {y : fol.Formula L | depth L y = depth L (forallH n f)} :=
  match p with
  | (v, s) =>
      match eq_nat_dec n v with
      | left _ =>
          exist (fun y : fol.Formula L => depth L y = S (depth L f))
            (forallH n f) (refl_equal (depth L (forallH n f)))
      | right _ =>
          match In_dec eq_nat_dec n (freeVarTerm s) with
          | left _ =>
              let nv := newVar (v :: freeVarTerm s ++ freeVarFormula f) in
              match frec f (depthForall L f n) (n, var nv) with
              | exist f' prf1 =>
                  match
                    frec f'
                      (eqDepth L f' f (forallH n f) 
                         (sym_eq prf1) (depthForall L f n)) p
                  with
                  | exist f'' prf2 =>
                      exist
                        (fun y : fol.Formula L => depth L y = S (depth L f))
                        (forallH nv f'')
                        (eq_ind_r (fun n : nat => S n = S (depth L f))
                           (refl_equal (S (depth L f))) 
                           (trans_eq prf2 prf1))
                  end
              end
          | right _ =>
              match frec f (depthForall L f n) p with
              | exist f' prf1 =>
                  exist (fun y : fol.Formula L => depth L y = S (depth L f))
                    (forallH n f')
                    (eq_ind_r (fun n : nat => S n = S (depth L f))
                       (refl_equal (S (depth L f))) prf1)
              end
          end
      end
  end.Remark substituteFormulaForallNice :
 forall (v : nat) (a : fol.Formula L)
   (z1
    z2 : forall b : fol.Formula L,
         lt_depth b (forallH v a) ->
         nat * fol.Term L -> {y : fol.Formula L | depth L y = depth L b}),
 (forall (b : fol.Formula L) (q : lt_depth b (forallH v a))
    (r : nat * fol.Term L), z1 b q r = z2 b q r) ->
 forall q : nat * fol.Term L,
 substituteFormulaForall v a z1 q = substituteFormulaForall v a z2 q.Definition substituteFormulaHelp (f : fol.Formula L) 
  (v : nat) (s : fol.Term L) : {y : fol.Formula L | depth L y = depth L f}.Definition substituteFormula (f : fol.Formula L) (v : nat) 
  (s : fol.Term L) : fol.Formula L := proj1_sig (substituteFormulaHelp f v s).

(* Specifications: *)
Lemma subFormulaEqual : forall (t1 t2 : fol.Term L) (v : nat) (s : fol.Term L), substituteFormula (equal t1 t2) v s = equal (substituteTerm t1 v s) (substituteTerm t2 v s).
Lemma subFormulaRelation : forall (r : Relations L) (ts : fol.Terms L (arity L (inl _ r))) (v : nat) (s : fol.Term L), substituteFormula (atomic r ts) v s = atomic r (substituteTerms (arity L (inl _ r)) ts v s).
Lemma subFormulaImp : forall (f1 f2 : fol.Formula L) (v : nat) (s : fol.Term L), substituteFormula (impH f1 f2) v s = impH (substituteFormula f1 v s) (substituteFormula f2 v s).
Lemma subFormulaNot : forall (f : fol.Formula L) (v : nat) (s : fol.Term L), substituteFormula (notH f) v s = notH (substituteFormula f v s).
Lemma subFormulaForall : forall (f : fol.Formula L) (x v : nat) (s : fol.Term L), let nv := newVar (v :: freeVarTerm s ++ freeVarFormula f) in substituteFormula (forallH x f) v s = match eq_nat_dec x v with | left _ => forallH x f | right _ => match In_dec eq_nat_dec x (freeVarTerm s) with | right _ => forallH x (substituteFormula f v s) | left _ => forallH nv (substituteFormula (substituteFormula f x (var nv)) v s) end end.
Lemma subFormulaOr : forall (f1 f2 : fol.Formula L) (v : nat) (s : fol.Term L), substituteFormula (orH f1 f2) v s = orH (substituteFormula f1 v s) (substituteFormula f2 v s).
Lemma subFormulaAnd : forall (f1 f2 : fol.Formula L) (v : nat) (s : fol.Term L), substituteFormula (andH f1 f2) v s = andH (substituteFormula f1 v s) (substituteFormula f2 v s).
Lemma subFormulaExist : forall (f : fol.Formula L) (x v : nat) (s : fol.Term L), let nv := newVar (v :: freeVarTerm s ++ freeVarFormula f) in substituteFormula (existH x f) v s = match eq_nat_dec x v with | left _ => existH x f | right _ => match In_dec eq_nat_dec x (freeVarTerm s) with | right _ => existH x (substituteFormula f v s) | left _ => existH nv (substituteFormula (substituteFormula f x (var nv)) v s) end end.
Lemma subFormulaIff : forall (f1 f2 : fol.Formula L) (v : nat) (s : fol.Term L), substituteFormula (iffH f1 f2) v s = iffH (substituteFormula f1 v s) (substituteFormula f2 v s).
Lemma subFormulaIfThenElse : forall (f1 f2 f3 : fol.Formula L) (v : nat) (s : fol.Term L), substituteFormula (ifThenElseH f1 f2 f3) v s = ifThenElseH (substituteFormula f1 v s) (substituteFormula f2 v s) (substituteFormula f3 v s).
Lemma subFormulaDepth : forall (f : fol.Formula L) (v : nat) (s : fol.Term L), depth L (substituteFormula f v s) = depth L f.
Lemma subTermId : forall (t : fol.Term L) (v : nat), substituteTerm t v (var v) = t.
Lemma subTermsId : forall (n : nat) (ts : fol.Terms L n) (v : nat), substituteTerms n ts v (var v) = ts.
Lemma subFormulaId : forall (f : fol.Formula L) (v : nat), substituteFormula f v (var v) = f.
Lemma subFormulaForall2 : forall (f : fol.Formula L) (x v : nat) (s : fol.Term L), exists nv : nat, ~ In nv (freeVarTerm s) /\ nv <> v /\ ~ In nv (list_remove _ eq_nat_dec x (freeVarFormula f)) /\ substituteFormula (forallH x f) v s = match eq_nat_dec x v with | left _ => forallH x f | right _ => forallH nv (substituteFormula (substituteFormula f x (var nv)) v s) end.
Lemma subFormulaExist2 : forall (f : fol.Formula L) (x v : nat) (s : fol.Term L), exists nv : nat, ~ In nv (freeVarTerm s) /\ nv <> v /\ ~ In nv (list_remove _ eq_nat_dec x (freeVarFormula f)) /\ substituteFormula (existH x f) v s = match eq_nat_dec x v with | left _ => existH x f | right _ => existH nv (substituteFormula (substituteFormula f x (var nv)) v s) end.