Require Import Equations.Equations.
Require Import Lia Arith.
Require Import Undecidability.PCP.PCP.
From Undecidability Require Import FOLP.FOLFS.
Require Import Undecidability.Shared.ListAutomation.
Import ListAutomationNotations.
Derive Signature for le.
Lemma le_irrel' n :
forall H : n <= n, H = le_n n.
Proof.
induction n; depelim H.
- reflexivity.
- assert (H = eq_refl) as -> by apply Eqdep_dec.UIP_refl_nat.
cbn in H1. assumption.
- exfalso. lia.
Qed.
Lemma le_irrel k l :
forall H1 H2 : k <= l, H1 = H2.
Proof.
induction l; depelim H1.
- intros H2. now rewrite le_irrel'.
- intros H2. now rewrite le_irrel'.
- depelim H2; try apply le_irrel'. f_equal. apply IHl.
Qed.
Local Notation "| s |" := (length s) (at level 100).
Definition bstring n :=
{ s : string bool | | s | <= n}.
Lemma string_nil (s : string bool) :
|s| <= 0 <-> s = nil.
Proof.
destruct s; cbn.
- split; trivial; lia.
- split; try congruence. intros H. depelim H.
Qed.
Definition bnil n :
bstring n.
Proof.
exists nil. cbn. lia.
Defined.
Definition bcons n (b : bool) :
bstring n -> bstring (S n).
Proof.
intros [s H]. exists (b::s). cbn. lia.
Defined.
Lemma bstring_eq n (s t : bstring n) :
proj1_sig s = proj1_sig t <-> s = t.
Proof.
split; try now intros ->.
destruct s as [s H1], t as [t H2]; cbn.
intros ->. now rewrite (le_irrel H1 H2).
Qed.
Lemma bstring_eq' n (s t : bstring n) :
proj1_sig s = proj1_sig t -> s = t.
Proof.
apply bstring_eq.
Qed.
Definition bstring_step n (L : list (bstring n)) :=
[bnil (S n)] ++ map (bcons true) L ++ map (bcons false) L.
Definition bcast n s (H : |s| <= n) : bstring n :=
exist _ _ H.
Lemma listable_bstring n :
listable (bstring n).
Proof.
induction n.
- exists [bnil 0]. intros [s H].
assert (s = nil) as -> by now apply string_nil.
left. now apply bstring_eq.
- destruct IHn as [L HL]. exists (bstring_step L).
intros [ [|[] s] H]; apply in_app_iff; cbn in H.
+ left. left. now apply bstring_eq.
+ right. apply in_app_iff. left. apply in_map_iff.
assert (H' : |s| <= n) by lia. exists (bcast H').
split; trivial. now apply bstring_eq.
+ right. apply in_app_iff. right. apply in_map_iff.
assert (H' : |s| <= n) by lia. exists (bcast H').
split; trivial. now apply bstring_eq.
Qed.
Inductive what := pred | func.
Definition make_sig (T : what -> nat -> Type) : Signature :=
{| Funcs := {n & T func n} ;
fun_ar := @projT1 _ _ ;
Preds := {n & T pred n} ;
pred_ar := @projT1 _ _ |}.
Inductive finsat_sig' : what -> nat -> Type :=
| f : bool -> finsat_sig' func 1
| e : finsat_sig' func 0
| dum : finsat_sig' func 0
| P : finsat_sig' pred 2
| less : finsat_sig' pred 2
| equiv : finsat_sig' pred 2.
Instance finsat_sig : Signature := make_sig finsat_sig'.
Definition i_f domain {I : interp domain} : bool -> domain -> domain :=
fun b x => (FullTarski.i_f (f := existT _ 1 (f b))) (Vector.cons x Vector.nil).
Definition i_e domain {I : interp domain} : domain :=
(FullTarski.i_f (f := existT _ 0 e)) Vector.nil.
Definition i_P domain {I : interp domain} : domain -> domain -> Prop :=
fun x y => (FullTarski.i_P (P := existT _ 2 P)) (Vector.cons x (Vector.cons y Vector.nil)).
Notation i_equiv x y :=
((FullTarski.i_P (P := existT _ 2 equiv)) (Vector.cons x (Vector.cons y Vector.nil))).
Fixpoint iprep domain {I : interp domain} (x : list bool) (y : domain) :=
match x with
| nil => y
| b::x => i_f b (iprep x y)
end.
Definition ienc domain {I : interp domain} (x : list bool) := iprep x i_e.
Local Definition BSRS := list (card bool).
Local Notation "x / y" := (x, y).
Section FIB.
Variable R : BSRS.
Definition obstring n :=
option (bstring n).
Lemma listable_obstring n :
listable (obstring n).
Proof.
destruct (listable_bstring n) as [L HL]. exists (None :: map Some L).
intros [x|].
- right. apply in_map, HL.
- cbn. eauto.
Qed.
Notation obcast H := (Some (bcast H)).
Definition ccons n b (s : obstring n) : obstring n :=
match s with
| Some (exist _ s _) => match (le_dec (|b::s|) n) with
| left H => obcast H
| right _ => None
end
| None => None
end.
Definition cdrv n (s t : obstring n) :=
match s, t with
| Some (exist _ s _), Some (exist _ t _) => derivable R s t
| _, _ => False
end.
Definition sub n (x y : obstring n) :=
match x, y with
| Some (exist _ s _), Some (exist _ t _) => s <> t /\ exists s', t = s'++s
| _, _ => False
end.
Global Instance FIB n : interp (obstring n).
Proof.
split.
- intros [k H]; cbn. inversion H; subst.
+ intros v. exact (ccons H0 (Vector.hd v)).
+ intros _. exact (Some (bnil n)).
+ intros _. exact None.
- intros [k H]; cbn. inversion H; subst.
+ intros v. exact (cdrv (Vector.hd v) (Vector.hd (Vector.tl v))).
+ intros v. exact (sub (Vector.hd v) (Vector.hd (Vector.tl v))).
+ intros v. exact (eq (Vector.hd v) (Vector.hd (Vector.tl v))).
Defined.
Lemma app_bound n (s t : string bool) :
|t| <= n -> |s++t| <= n + |s|.
Proof.
intros H. rewrite app_length. lia.
Qed.
Lemma obstring_iprep n x u (HX : |x++u| <= n) (HU : |u| <= n) :
iprep x (obcast HU) = obcast HX.
Proof.
induction x; cbn.
- f_equal. now apply bstring_eq.
- assert (H : |x++u| <= n).
{ rewrite app_length in *. cbn in HX. lia. }
rewrite (IHx H). unfold ccons, bcast at 1. destruct le_dec.
+ f_equal. now apply bstring_eq.
+ exfalso. cbn in *. rewrite app_length in *. lia.
Qed.
Lemma obstring_ienc n s (H : |s| <= n) :
ienc s = obcast H.
Proof.
unfold ienc. cbn.
setoid_rewrite obstring_iprep.
f_equal. apply bstring_eq, app_nil_r.
Unshelve. rewrite app_length. cbn. lia.
Qed.
Lemma obstring_ienc' n s (H : ~ |s| <= n) :
@ienc _ (FIB n) s = None.
Proof.
induction s; cbn in *; try lia.
change (@ccons n a (ienc s) = None).
destruct (le_dec (|s|) n) as [H'|H'].
- setoid_rewrite (obstring_ienc H'). cbn.
destruct le_dec; tauto.
- now rewrite IHs.
Qed.
Lemma crdv_iff n (x y : obstring n) :
i_P x y <-> exists s t, derivable R s t /\ x = ienc s /\ y = ienc t /\ |s| <= n /\ |t| <= n.
Proof.
destruct x as [ [x HX]|], y as [ [y HY]|]; split; cbn; auto.
{ intros H. exists x, y. repeat setoid_rewrite obstring_ienc. now repeat split. }
all: intros (s&t&H1&H2&H3&H4&H5). all: try unshelve setoid_rewrite obstring_ienc in H2; try unshelve setoid_rewrite obstring_ienc in H3; auto.
all: try discriminate. depelim H2. depelim H3. assumption.
Qed.
Definition obembed n (s : obstring n) : obstring (S n) :=
match s with
| Some (exist _ s H) => Some (exist _ s (le_S _ _ H))
| None => None
end.
Lemma cdrv_mon n (s t : obstring n) :
cdrv s t -> @cdrv (S n) (obembed s) (obembed t).
Proof.
now destruct s as [ [s HS]|], t as [ [t HT]|].
Qed.
Lemma cdrv_mon' n s t :
@cdrv n (ienc s) (ienc t) -> @cdrv (S n) (ienc s) (ienc t).
Proof.
destruct (le_dec (|s|) n) as [H|H], (le_dec (|t|) n) as [H'|H'].
- repeat unshelve setoid_rewrite obstring_ienc; trivial; lia.
- setoid_rewrite (obstring_ienc H). setoid_rewrite (obstring_ienc' H'). cbn. tauto.
- rewrite (obstring_ienc' H). cbn. tauto.
- rewrite (obstring_ienc' H). cbn. tauto.
Qed.
Lemma drv_cdrv s t :
derivable R s t <-> @cdrv (max (|s|) (|t|)) (ienc s) (ienc t).
Proof.
repeat unshelve setoid_rewrite obstring_ienc; try reflexivity; lia.
Qed.
Lemma drv_cdrv' s :
derivable R s s <-> @cdrv (|s|) (ienc s) (ienc s).
Proof.
repeat unshelve setoid_rewrite obstring_ienc; try reflexivity; lia.
Qed.
Lemma BPCP_P :
dPCPb R <-> exists n x, @i_P _ (FIB n) x x.
Proof.
split.
- intros [s H]. exists (|s|), (ienc s). cbn. now apply drv_cdrv'.
- intros [n[ [ [s H]|] H'] ].
+ cbn in H'. now exists s.
+ destruct H'.
Qed.
Section Ax.
Variable n : nat.
Implicit Type x y : obstring n.
Lemma app_eq_nil' (s t : string bool) :
s = t++s -> t = nil.
Proof.
destruct t; trivial. intros H. exfalso.
assert (H' : |s| = |(b :: t) ++ s|) by now rewrite H at 1.
cbn in H'. rewrite app_length in H'. lia.
Qed.
Lemma app_neq b (s t : string bool) :
s <> (b :: t) ++ s.
Proof.
intros H. apply app_eq_nil' in H. discriminate.
Qed.
Lemma FIB_HP x y :
i_P x y -> x <> None /\ y <> None.
Proof.
destruct x as [ [s HS] |], y as [ [t HT]|]; auto.
intros _. split; discriminate.
Qed.
Lemma FIB_HS1 x :
~ sub x x.
Proof.
destruct x as [ [s HS]|]; cbn; firstorder.
Qed.
Lemma FIB_HS2 x y z :
sub x y -> sub y z -> sub x z.
Proof.
destruct x as [ [s HS]|], y as [ [t HT]|], z as [ [u HU]|]; cbn; auto.
intros [H1[s' HS'] ] [H2[t' HT'] ]. subst. split.
- rewrite app_assoc. intros H % app_eq_nil'.
apply app_eq_nil in H as [-> ->]. now apply H1.
- exists (t'++s'). apply app_assoc.
Qed.
Lemma FIB_HF1 b x :
i_f b x <> i_e.
Proof.
destruct x as [ [s H]|]; cbn; try congruence.
destruct le_dec; try congruence. injection. congruence.
Qed.
Lemma FIB_HF2 b1 b2 x y :
i_f b1 x <> None -> i_f b1 x = i_f b2 y -> x = y /\ b1 = b2.
Proof.
destruct x as [ [s HS] |], y as [ [t HT]|]; cbn.
all: repeat destruct le_dec; cbn. all: try congruence.
intros _ H. depelim H. split; trivial. f_equal. now apply bstring_eq.
Qed.
Lemma None_dec X (x : option X) :
{x = None} + {x <> None}.
Proof.
destruct x; auto. right. discriminate.
Qed.
Lemma FIB_HF2' x y :
i_f true x = i_f false y -> i_f true x = None /\ i_f false y = None.
Proof.
intros H. destruct (None_dec (i_f true x)), (None_dec (i_f false y)); try tauto; exfalso.
- symmetry in H. specialize (FIB_HF2 n0 H). congruence.
- specialize (FIB_HF2 n0 H). congruence.
- specialize (FIB_HF2 n0 H). intros [_ H']. discriminate.
Qed.
Lemma FIB_HF3 b x :
i_f b x <> None -> x <> None.
Proof.
destruct x as [ [s HS] |]; cbn; congruence.
Qed.
Lemma FIB_HI x y :
i_P x y -> (exists s t, s/t el R /\ x = ienc s /\ y = ienc t)
\/ (exists s t u v, s/t el R /\ x = iprep s u /\ y = iprep t v /\ i_P u v /\
((sub u x /\ v = y) \/ (sub v y /\ u = x) \/ (sub u x /\ sub v y))).
Proof.
destruct x as [ [x HX]|], y as [ [y HY]|]; cbn; auto. induction 1.
- left. exists x, y. repeat setoid_rewrite obstring_ienc. repeat split; trivial.
- assert (HU : |u| <= n). { rewrite app_length in HX. lia. }
assert (HV : |v| <= n). { rewrite app_length in HY. lia. }
destruct x as [|b x], y as [|c y].
+ cbn. apply IHderivable.
+ right. exists [], (c::y), (obcast HU), (obcast HV).
repeat setoid_rewrite obstring_iprep. repeat split; trivial.
right. left. repeat split; eauto using app_neq. f_equal. now apply bstring_eq.
+ right. exists (b::x), [], (obcast HU), (obcast HV).
repeat setoid_rewrite obstring_iprep. repeat split; trivial.
left. repeat split; eauto using app_neq. f_equal. now apply bstring_eq.
+ right. exists (b::x), (c::y), (obcast HU), (obcast HV).
repeat setoid_rewrite obstring_iprep. repeat split; trivial.
right. right. repeat split; eauto using app_neq.
Qed.
End Ax.
End FIB.
Section Conv.
Variable R : BSRS.
Variable D : Type.
Hypothesis HD : listable D.
Variable I : interp D.
Notation sub x y :=
((FullTarski.i_P (P := existT _ 2 less)) (Vector.cons x (Vector.cons y Vector.nil))).
Notation dum :=
((FullTarski.i_f (f := existT _ 0 dum)) Vector.nil).
Hypothesis HP : forall x y, i_P x y -> x <> dum /\ y <> dum.
Hypothesis HS1 : forall x, ~ sub x x.
Hypothesis HS2 : forall x y z, sub x y -> sub y z -> sub x z.
Hypothesis HF1 : forall b x, i_f b x <> i_e.
Hypothesis HF2 : forall b1 b2 x y, i_f b1 x <> dum -> i_f b1 x = i_f b2 y -> x = y /\ b1 = b2.
Hypothesis HF3 : forall b x, i_f b x <> dum -> x <> dum.
Hypothesis HI :
forall x y, i_P x y -> (exists s t, s/t el R /\ x = ienc s /\ y = ienc t)
\/ (exists s t u v, s/t el R /\ x = iprep s u /\ y = iprep t v /\ i_P u v /\
((sub u x /\ v = y) \/ (sub v y /\ u = x) \/ (sub u x /\ sub v y))).
Lemma ienc_inj s t :
ienc s <> dum -> ienc s = ienc t -> s = t.
Proof.
revert t. induction s; intros [|]; cbn; trivial.
- intros _ H. symmetry in H. now apply HF1 in H.
- intros _ H. now apply HF1 in H.
- intros H [H' ->] % HF2; trivial. f_equal.
apply IHs; trivial. now apply HF3 in H.
Qed.
Definition sub' L x y :=
sub x y /\ x el L.
Lemma sub_acc_pred L x y :
sub y x -> Acc (sub' L) x -> Acc (sub' L) y.
Proof.
intros H H'. constructor. intros z [H1 H2].
apply H'. split; trivial. now apply (HS2 H1).
Qed.
Lemma sub_acc_cons L x y :
Acc (sub' L) x -> ~ sub y x -> Acc (sub' (y::L)) x.
Proof.
induction 1 as [x HX IH]. intros H.
constructor. intros z [H1[->|H2] ].
- contradiction.
- apply IH; firstorder.
Qed.
Lemma sub_acc_cons' L x y :
sub y x -> Acc (sub' L) x -> Acc (sub' (y::L)) y.
Proof.
intros H1 H2. apply sub_acc_cons; trivial.
now apply (sub_acc_pred H1).
Qed.
Lemma sub_acc_step L a x :
Acc (sub' L) x -> Acc (sub' (a::L)) x.
Proof.
induction 1 as [x HX IH].
constructor. intros y [H [->|H'] ].
- now apply (sub_acc_cons' H).
- apply IH. now split.
Qed.
Lemma sub_acc' L x :
Acc (sub' L) x.
Proof.
induction L.
- constructor. intros y [_ [] ].
- apply sub_acc_step, IHL.
Qed.
Lemma sub_acc x :
Acc (fun a b => sub a b) x.
Proof.
destruct HD as [L HL].
induction (sub_acc' L x) as [x _ IH].
constructor. intros y H. now apply IH.
Qed.
Inductive psub : (D * D) -> (D * D) -> Prop :=
| psub1 x u : sub u x -> forall y, psub (u,y) (x,y)
| psub2 y u : sub u y -> forall x, psub (x,u) (x,y)
| psub3 x y u v : sub u x -> sub v y -> psub (u,v) (x,y).
Lemma psub_acc p :
Acc psub p.
Proof.
destruct p as [x y]. revert y.
induction (sub_acc x) as [x HX IHX]. intros y.
induction (sub_acc y) as [y HY IHY]. constructor.
intros [u v]. inversion 1; subst; auto.
Qed.
Lemma ienc_iprep s t :
iprep s (ienc t) = ienc (s ++ t).
Proof.
induction s; cbn; trivial. now rewrite IHs.
Qed.
Lemma P_drv' p :
i_P (fst p) (snd p) -> exists s t, derivable R s t /\ fst p = ienc s /\ snd p = ienc t.
Proof.
intros H. induction (psub_acc p) as [ [x' y'] _ IH]; cbn in *.
destruct (HI H) as [(s&t&H1&H2&H3)|(s&t&u&v&H1&H2&H3&H4&H5)]; subst.
- exists s, t. repeat split; trivial. now constructor.
- destruct (IH (u,v)) as (s'&t'&H6&H7&H'); cbn in *; trivial; subst.
+ destruct H5 as [ [H5 <-]|[ [H5 <-]|[] ] ]; eauto using psub.
+ exists (s++s'), (t++t'). rewrite !ienc_iprep. repeat split; trivial. now right.
Qed.
Lemma P_drv x y :
i_P x y -> exists s t, derivable R s t /\ x = ienc s /\ y = ienc t.
Proof.
apply P_drv' with (p:=(x,y)).
Qed.
Lemma P_BPCP x :
i_P x x -> dPCPb R.
Proof.
intros H. destruct (P_drv H) as (s&t&H1&H2&H3); subst.
apply ienc_inj in H3 as ->; try apply (HP H). now exists t.
Qed.
End Conv.
Definition finsat phi :=
exists D (I : interp D) rho, listable D /\ (forall x y, i_equiv x y <-> eq x y) /\ rho ⊨ phi.
Section Reduction.
Notation "# x" := (var_term x) (at level 2).
Definition t_f b x := Func (existT _ 1 (f b)) (Vector.cons x Vector.nil).
Definition t_e := Func (existT _ 0 e) Vector.nil.
Definition t_dum := Func (existT _ 0 dum) Vector.nil.
Definition f_P x y := Pred (existT _ 2 P) (Vector.cons x (Vector.cons y Vector.nil)).
Notation "x ≡ y" := (Pred (existT _ 2 equiv) (Vector.cons x (Vector.cons y Vector.nil))) (at level 20).
Notation "x ≢ y" := (¬ (x ≡ y)) (at level 20).
Notation "x ≺ y" := (Pred (existT _ 2 less) (Vector.cons x (Vector.cons y Vector.nil))) (at level 20).
Fixpoint tprep (x : list bool) (y : term) :=
match x with
| nil => y
| b::x => t_f b (tprep x y)
end.
Lemma tprep_eval D (I : interp D) rho x t :
eval rho (tprep x t) = iprep x (eval rho t).
Proof.
induction x; cbn.
- reflexivity.
- rewrite IHx. reflexivity.
Qed.
Definition tenc (x : list bool) := tprep x t_e.
Definition ax_P := ∀ ∀ f_P #1 #0 --> (#1 ≢ t_dum) ∧ (#0 ≢ t_dum).
Definition ax_S1 := ∀ ¬ (#0 ≺ #0).
Definition ax_S2 := ∀ ∀ ∀ #2 ≺ #1 --> #1 ≺ #0 --> #2 ≺ #0.
Definition ax_HF1_true := ∀ t_f true #0 ≢ t_e.
Definition ax_HF1_false := ∀ t_f false #0 ≢ t_e.
Definition ax_HF2_true := ∀ ∀ t_f true #1 ≢ t_dum --> t_f true #1 ≡ t_f true #0 --> #1 ≡ #0.
Definition ax_HF2_false := ∀ ∀ t_f false #1 ≢ t_dum --> t_f false #1 ≡ t_f false #0 --> #1 ≡ #0.
Definition ax_HF2 := ∀ ∀ t_f true #1 ≡ t_f false #0 --> (t_f true #1 ≡ t_dum ∧ t_f false #0 ≡ t_dum).
Definition ax_HF3_true := ∀ t_f true #0 ≢ t_dum --> #0 ≢ t_dum.
Definition ax_HF3_false := ∀ t_f false #0 ≢ t_dum --> #0 ≢ t_dum.
Definition ax_HI' c :=
(#1 ≡ tenc (fst c) ∧ #0 ≡ tenc (snd c))
∨ (∃ ∃ #3 ≡ tprep (fst c) #1 ∧ #2 ≡ tprep (snd c) #0 ∧ f_P #1 #0
∧ ((#1 ≺ #3 ∧ #0 ≡ #2) ∨ (#0 ≺ #2 ∧ #1 ≡ #3) ∨ (#1 ≺ #3 ∧ #0 ≺ #2))).
Definition ax_HI (R : BSRS) := ∀ ∀ f_P #1 #0 --> list_or (map ax_HI' R).
Definition finsat_formula (R : BSRS) :=
ax_P ∧ ax_S1 ∧ ax_S2 ∧ ax_HF1_true ∧ ax_HF1_false ∧ ax_HF2_true ∧ ax_HF2_false
∧ ax_HF2 ∧ ax_HF3_true ∧ ax_HF3_false ∧ ax_HI R ∧ ∃ f_P #0 #0.
Theorem finsat_reduction R :
dPCPb R <-> finsat (finsat_formula R).
Proof.
split; intros H.
- apply BPCP_P in H as [n [s H]]. exists (obstring n), (@FIB R n), (fun _ => None).
split; try apply listable_obstring. cbn.
split. reflexivity.
split. apply (@FIB_HP R).
split. apply FIB_HS1.
split. apply FIB_HS2.
split. intros x. apply (@FIB_HF1 R _ true x).
split. intros x. apply (@FIB_HF1 R _ false x).
split. intros x y H1 H2. now destruct (FIB_HF2 (R:=R) H1 H2).
split. intros x y H1 H2. now destruct (FIB_HF2 (R:=R) H1 H2).
split. apply (@FIB_HF2' R).
split. intros x. apply (@FIB_HF3 R _ true x).
split. intros x. apply (@FIB_HF3 R _ false x).
split; try now exists s. cbn.
intros u v [[a[b[H1 H2]]]|[a[b[a'[b'[H1 H2]]]]]] % (@FIB_HI R _ u v); apply list_or_spec.
+ exists (ax_HI' (a/b)). split; try now apply in_map.
left. cbn. now rewrite !tprep_eval.
+ exists (ax_HI' (a/b)). split; try now apply in_map.
right. exists a', b'. cbn. now rewrite !tprep_eval.
- destruct H as (D & I & rho & HF & HE & H1 & H2 & H3 & H4 &
H5 & H6 & H7 & H8 & H9 & H10 & H11 & s & H12).
cbn in *.
eapply P_BPCP with (x:=s); trivial.
+ cbn in H1. intros x y. specialize (H1 x y). now rewrite !HE in H1.
+ cbn in H4, H5. intros b x. specialize (H4 x). specialize (H5 x).
rewrite !HE in H4, H5. now destruct b.
+ cbn in H6, H7, H8. intros b1 b2 x y.
specialize (H6 x y). specialize (H7 x y).
rewrite !HE in H6, H7. destruct b1, b2; eauto.
* specialize (H8 x y). rewrite !HE in H8. tauto.
* specialize (H8 y x). rewrite !HE in H8.
intros I1 I2. exfalso. symmetry in I2. tauto.
+ cbn in H9, H10. intros b x. specialize (H9 x). specialize (H10 x).
rewrite !HE in H9, H10. now destruct b.
+ cbn in H11. intros x y H. specialize (H11 x y H).
apply list_or_spec in H11 as [c[[[u v][<- HR]] % in_map_iff [H'|[a[b H']]]]].
* left. exists u, v. split; trivial. cbn in H'. now rewrite !tprep_eval, !HE in H'.
* right. exists u, v, a, b. split; trivial. cbn in H'. now rewrite !tprep_eval, !HE in H'.
Qed.
End Reduction.