Enumeration of formulas and ND


From Undecidability.FOLC Require Export FOL.

(* **** Helper machinery **)

Lemma flat_map_app {X Y} A B (f : X -> list Y) :
  flat_map f (A ++ B) = flat_map f A ++ flat_map f B.
Proof.
  induction A; cbn.
  - reflexivity.
  - now rewrite IHA, app_assoc.
Qed.

Lemma switch_map {X Y} (P : Y -> Prop) (f : X -> Y) A :
  (forall x, x el A -> P (f x)) -> forall y, y el (map f A) -> P y.
Proof.
  intros H y (x & <- & Hx) % in_map_iff. eauto.
Qed.

Fixpoint at_pos {X} n x (A : list X) :=
  match A with
  | nil => False
  | a :: A' =>
    match n with
    | O => a = x
    | S n' => at_pos n' x A'
    end
  end.

Lemma el_at_pos {X} x (A : list X) :
  x el A <-> exists n, at_pos n x A.
Proof.
  induction A.
  - split. intuition. intros [ [] [] ].
  - split.
    + intros [-> | H].
      * now exists 0.
      * apply IHA in H as [n H']. now exists (S n).
    + intros [ [] H].
      * now left.
      * right. apply IHA. now exists n.
Qed.

(* **** Unused variables in the enumeration *)

Section L_T_unused.
  Context {Sigma : Signature}.

  Hypothesis enum_Funcs : enumT Funcs.
  Hypothesis enum_Preds : enumT Preds.

  Lemma L_T_nat_le n m :
    n el L_T m -> n <= m.
  Proof.
    induction m.
    - intros []; now subst.
    - intros [ | [ | [] ] ] % in_app_or.
      + constructor. now apply IHm.
      + now subst.
  Qed.

  Lemma L_T_unused_t n m t :
    m <= n -> t el (L_T m) -> unused_term n t.
  Proof.
    revert n t. induction m; intros n t.
    - inversion 1; cbn; tauto.
    - intros H [ | [ | (A & H0 & (f & <- & Hf) % in_map_iff) % in_concat_iff ]] % in_app_or.
      * apply IHm. omega. assumption.
      * subst. constructor. omega.
      * revert H0. apply switch_map. intros v H'. rewrite <- vecs_from_correct in H'. constructor.
        intros s Hs % H'. apply IHm. 1: omega. assumption.
  Qed.

  Lemma L_T_unused_v n m k (v : Vector.t term k) :
    m <= n -> v el (L_T m) -> (forall t, vec_in t v -> unused_term n t).
  Proof.
    induction m; intros Hnm.
    - intros [].
    - cbn. intros [ | H ] % in_app_or.
      + firstorder.
      + rewrite <- vecs_from_correct in H. intros t Ht. apply L_T_unused_t with m. all: omega + eauto.
  Qed.

  Lemma L_T_unused n m phi :
    m <= n -> phi el (L_T m) -> unused n phi.
  Proof.
    revert n phi. induction m; intros n phi.
    - intros ? [<- | []]. constructor.
    - intros H [ | [ | [ | [ (A & H0 & (P & <- & HP) % in_map_iff) % in_concat_iff | [] % in_app_or ] % in_app_or] % in_app_or]] % in_app_or;
        try (revert H0; apply switch_map).
      + apply IHm. omega. assumption.
      + subst. constructor.
      + contradiction H0.
      + intros v H'. constructor. intros. apply L_T_unused_v with m (pred_ar P) v. all: omega + eauto.
      + intros [phi1 phi2] [] % in_prod_iff. constructor.
        all: apply IHm; [omega | assumption].
      + intros psi H'. constructor. apply IHm. omega. assumption.
  Qed.
End L_T_unused.

(* **** Single value enumeration *)

Section Enumeration.
  Variable X : Type.
  Context {Henum : enumT X}.
  Context {Hdec : eq_dec X}.
  Hypothesis Hlen : forall n, | L_T n | > n.

  Definition plain_enum n : X := proj1_sig (@nthe_length X (L_T n) n (Hlen n)).

  Lemma L_T_sub n m :
    n <= m -> exists A, L_T m = L_T n ++ A.
  Proof.
    induction 1.
    - exists nil. now rewrite app_nil_r.
    - destruct IHle as [A HA]. destruct (cum_T m) as [B HB].
      exists (A ++ B). now rewrite HB, HA, app_assoc.
  Qed.

  Lemma L_T_sub_or n m :
    (exists A, L_T n = L_T m ++ A) \/ (exists A, L_T m = L_T n ++ A).
  Proof.
    destruct (Nat.le_ge_cases n m) as [Hl | Hl]; [right | left]; now apply L_T_sub.
  Qed.

  Lemma plain_enum_enumerates x :
    exists n, plain_enum n = x.
  Proof.
    destruct (el_T x) as [m H]. destruct (el_pos Hdec H) as [n H'].
    exists n. unfold plain_enum. destruct (nthe_length (Hlen n)) as [y H'']. cbn.
    apply pos_nthe in H'. destruct (L_T_sub_or n m) as [ [A HA] | [A HA] ].
    - rewrite HA in H''. apply (nthe_app_l A) in H'. congruence.
    - rewrite HA in H'. apply (nthe_app_l A) in H''. congruence.
  Qed.

  Lemma plain_enum_slow n :
    plain_enum n el L_T n.
  Proof.
    unfold plain_enum. destruct (nthe_length (Hlen n)) as [y H'']. cbn. now apply nth_error_In in H''.
  Qed.
End Enumeration.

(* **** Single step enumeration for formulas *)

Section L_T_Enumeration.
  Context {Sigma : Signature}.
  Context {HdF : eq_dec Funcs} {HdP : eq_dec Preds}.
  Context {HeF : enumT Funcs} {HeP : enumT Preds}.

  Lemma L_T_form_len n :
    | L_T form n | > n.
  Proof.
    induction n; cbn.
    - omega.
    - rewrite app_length. cbn. change (L_T n) with (L_form HeF HeP n) in IHn. omega.
  Qed.

  Definition form_enum n := plain_enum L_T_form_len n.

  Corollary form_enum_enumerates x :
    exists n, form_enum n = x.
  Proof. apply plain_enum_enumerates. intuition. Qed.

  Lemma form_enum_fresh n m :
    n <= m -> unused m (form_enum n).
  Proof.
    intros H. apply (@L_T_unused _ _ _ m n). exact H.
    apply plain_enum_slow.
  Qed.
End L_T_Enumeration.