Library DemoNat
Demo file on how to use the library: rewrite system for
natural numbers
Libraries...
Require Import ssreflect.
Require Import LocConfTac.
Section DemoNat.
Require Import LocConfTac.
Section DemoNat.
Definition of terms
Inductive term : Type :=
| Zero : term
| One : term
| Succ : term -> term
| Sum : term -> term -> term
| Mult : term -> term -> term.
The rewrite system we consider
Section Term.
Hypothesis R : term -> term -> Prop.
Definition Z_r_unit := forall t:term, R (Sum t Zero) t.
Definition Z_r_anni := forall t:term, R (Mult t Zero) Zero.
Definition Succ_Z := R (Succ Zero) One.
Definition O_r_unit := forall t:term, R (Mult t One) t.
Definition O_r_sum := forall t:term, R (Sum t One) (Succ t).
Definition Succ_Sum := forall s t:term, R (Sum s (Succ t)) (Succ (Sum s t)).
Definition Succ_Mult := forall s t:term, R (Mult s (Succ t)) (Sum s (Mult s t)).
Definition Sum_Mult := forall r s t:term, R (Mult r (Sum s t)) (Sum (Mult r s) (Mult r t)).
Definition Sum_cong := forall s t t':term, R t t' -> R (Sum s t) (Sum s t').
Definition Mult_cong := forall s t t':term, R t t' -> R (Mult s t) (Mult s t').
Definition Succ_cong := forall t t':term, R t t' -> R (Succ t) (Succ t').
Definition Sum_com := forall s t:term, R (Sum s t) (Sum t s).
Definition Mult_com := forall s t:term, R (Mult s t) (Mult t s).
Definition Sum_assoc := forall r s t:term, R (Sum (Sum r s) t) (Sum r (Sum s t)).
Definition Mult_assoc := forall r s t:term, R (Mult (Mult r s) t) (Mult r (Mult s t)).
End Term.
Inductive R : term -> term -> Prop :=
| ax1 : Z_r_unit R
| ax2 : Z_r_anni R
| ax3 : O_r_unit R
| ax4 : O_r_sum R
| ax5 : Succ_Sum R
| ax6 : Succ_Mult R
| ax7 : Succ_Z R
| ax8 : Sum_Mult R
| cong1 : Sum_cong R
| cong2 : Mult_cong R
| cong3 : Succ_cong R
| ac1 : Sum_com R
| ac2 : Mult_com R
| ac3 : Sum_assoc R
| ac4 : Mult_assoc R.
Hint Immediate ax1 ax2 ax3 ax4 ax5 ax6 ax7 ax8 ac1 ac2 ac3 ac4.
Some properties to be able to automate the reduction process
Section Term_prop.
Ltac startac := match goal with | [ |- ?A _ ] => unfold A end; intros;
match goal with | [ |- Rstar _ _ ?A ] => apply (Rcons _ _ _ A) end; auto.
Lemma sZ_r_unit : Z_r_unit (Rstar R).
Proof. by startac. Qed.
Lemma sZ_r_anni : Z_r_anni (Rstar R).
Proof. by startac. Qed.
Lemma sSucc_Z : Succ_Z (Rstar R).
Proof. by startac. Qed.
Lemma sO_r_unit : O_r_unit (Rstar R).
Proof. by startac. Qed.
Lemma sO_r_sum : O_r_sum (Rstar R).
Proof. by startac. Qed.
Lemma sSucc_Sum : Succ_Sum (Rstar R).
Proof. by startac. Qed.
Lemma sSucc_Mult : Succ_Mult (Rstar R).
Proof. by startac. Qed.
Lemma sSum_Mult : Sum_Mult (Rstar R).
Proof. by startac. Qed.
Lemma sSum_com : Sum_com (Rstar R).
Proof. by startac. Qed.
Lemma sMult_com : Mult_com (Rstar R).
Proof. by startac. Qed.
Lemma sSum_assoc : Sum_assoc (Rstar R).
Proof. by startac. Qed.
Lemma sMult_assoc : Mult_assoc (Rstar R).
Proof. by startac. Qed.
End Term_prop.
Hint Immediate sZ_r_unit sZ_r_anni sSucc_Z sO_r_unit sO_r_sum sSucc_Sum.
Hint Immediate sSucc_Mult sSum_Mult sSum_com sMult_com sSum_assoc sMult_assoc.
Tactic to prove automatically that Rstar R a b
for trivial cases
Ltac core_step :=
solve [
auto
| apply (Rstar_rcong _ _ cong1); core_step
| apply (Rstar_rcong _ _ cong2); core_step
| apply (Rstar_cong _ _ cong3); core_step
| try_Rstar_in_goal
].
Test
Goal forall a, Rstar R (Sum a Zero) a.
by core_step.
Qed.
Goal forall a b, Rstar R (Sum b (Sum a Zero)) (Sum b a).
move => a b.
by core_step.
Qed.
Goal forall a b, Rstar R (Mult b (Sum a Zero)) (Mult b a).
move => a b.
by core_step.
Qed.
Goal Rstar R (Succ (Succ Zero)) (Succ One).
by core_step.
Qed.
Goal forall r s t, R (Mult r (Sum s t)) (Sum (Mult r s) (Mult r t)).
move => r s t.
by core_step.
Qed.
Given x, find the possible AC-conversions and construct a list
of empty trees with these terms as roots.
Ltac find_ACequiv r :=
match r with
| Zero => constr : (Zero::nil)
| One => constr : (One::nil)
| (Sum ?a ?b) =>
let x := constr : (Sum b a) in
let yb := find_ACequiv b in
let myf := (fun x => constr : (Sum a x)) in
let y := maplist myf term yb in
match a with
| (Sum ?e ?f) =>
let z := constr : (Sum e (Sum f b)) in
constr : (x::z::y)
| _ => constr : (x::y)
end
| (Mult ?a ?b) =>
let x := constr : (Mult b a) in
let yb := find_ACequiv b in
let myf := (fun x => constr : (Mult a x)) in
let y := maplist myf term yb in
match a with
| (Mult ?e ?f) =>
let z := constr : (Mult e (Mult f b)) in
constr : (x::z::y)
| _ => constr : (x::y)
end
| (Succ ?a) =>
let xa := find_ACequiv a in
let myf := (fun x => constr : (Succ x)) in
maplist myf term xa
| ?a => constr : (nil (A:=term))
end.
match r with
| Zero => constr : (Zero::nil)
| One => constr : (One::nil)
| (Sum ?a ?b) =>
let x := constr : (Sum b a) in
let yb := find_ACequiv b in
let myf := (fun x => constr : (Sum a x)) in
let y := maplist myf term yb in
match a with
| (Sum ?e ?f) =>
let z := constr : (Sum e (Sum f b)) in
constr : (x::z::y)
| _ => constr : (x::y)
end
| (Mult ?a ?b) =>
let x := constr : (Mult b a) in
let yb := find_ACequiv b in
let myf := (fun x => constr : (Mult a x)) in
let y := maplist myf term yb in
match a with
| (Mult ?e ?f) =>
let z := constr : (Mult e (Mult f b)) in
constr : (x::z::y)
| _ => constr : (x::y)
end
| (Succ ?a) =>
let xa := find_ACequiv a in
let myf := (fun x => constr : (Succ x)) in
maplist myf term xa
| ?a => constr : (nil (A:=term))
end.
Some tests
Goal forall a b c, Rstar R (Sum a (Sum b c)) (Sum a (Sum c b)).
Proof.
move => a b c.
try_ACequiv R core_step find_ACequiv 2.
Show Proof.
Qed.
Goal forall a b c, Rstar R (Mult a (Sum b c)) (Mult (Sum c b) a).
Proof.
move => a b c.
try_ACequiv R core_step find_ACequiv 2.
Show Proof.
Qed.
Goal forall a b c, Rstar R (Mult a (Succ (Sum b c))) (Mult (Succ (Sum c b)) a).
Proof.
move => a b c.
try_ACequiv R core_step find_ACequiv 2.
Show Proof.
Qed.
Goal forall a b c d, Rstar R (Sum a (Sum b (Sum c d))) (Sum (Sum c a) (Sum d b)).
Proof.
move => a b c d.
try_ACequiv R core_step find_ACequiv 5.
Show Proof.
Qed.
Tactic that gives a potential next element using non-AC
rewrites. The idea is that since the RW system is locally
confluent (and normalizing), regardless of the term we choose it
should not matter.
Ltac find_nonAC a :=
let A := typeof a in
match a with
| (Sum ?t Zero) => constr : (LtacYes t)
| (Mult ?t Zero) => constr : (LtacYes Zero)
| (Succ Zero) => constr : (LtacYes One)
| (Mult ?t One) => constr : (LtacYes t)
| (Sum ?t One) => constr : (LtacYes (Succ t))
| (Sum ?s (Succ ?t)) => constr : (LtacYes (Succ (Sum s t)))
| (Mult ?s (Succ ?t)) => constr : (LtacYes (Sum s (Mult s t)))
| (Mult ?r (Sum ?s ?t)) => constr : (LtacYes (Sum (Mult r s) (Mult r t)))
| (Sum ?s ?t) =>
let x := find_nonAC t in
match x with
| LtacYes ?y => constr : (LtacYes (Sum s y))
| LtacNo => constr : (LtacNo (term:=A))
end
| (Mult ?s ?t) =>
let x := find_nonAC t in
match x with
| LtacYes ?y => constr : (LtacYes (Mult s y))
| LtacNo => constr : (LtacNo (term:=A))
end
| (Succ ?t) =>
let x := find_nonAC t in
match x with
| LtacYes ?y => constr : (LtacYes (Succ y))
| LtacNo => constr : (LtacNo (term:=A))
end
| ?t => match goal with
| [ L : Rstar R t t |- _ ] => constr : (LtacNo (term:=A))(* clear trivial loops *)
| [ L : Rstar R t ?u |- _ ] => constr : (LtacYes u)
| [ L : R t ?u |- _ ] => constr : (LtacYes u)
end
| ?t => constr : (LtacNo (term:=A))
end.
Goal forall r s, (exists u, Rstar R (Sum (Sum One r) s) u /\ Rstar R (Sum (Sum Zero (s)) (Sum r One)) u).
move => r s.
try_smart_solve R core_step find_nonAC find_ACequiv 2 2.
Qed.
Goal forall r s1 t2,
exists u : term,
Rstar R (Sum (Mult r s1) (Mult (Mult r s1) t2)) u /\
Rstar R (Mult r (Mult s1 (Succ t2))) u.
intros.
try_smart_solve R core_step find_nonAC find_ACequiv 2 2.
Qed.
Goal forall r s t:term, (exists u, Rstar R (Sum (Sum One r) s) u /\ Rstar R (Sum (Sum Zero (s)) (Sum r One)) u).
move => r s t.
try_smart_solve R core_step find_nonAC find_ACequiv 2 2.
Qed.
Ltac try_various d1 d2 :=
try solve [
match goal with
| [ H : R Zero _ |- _ ] => inversion H
| [ H : R One _ |- _ ] => inversion H
end
|
try_smart_solve R core_step find_nonAC find_ACequiv d1 d2
].
We can now show the local confluence of R almost automatically
Lemma R_local_confluence : forall r s t:term,
(R r s) -> (R r t) -> exists u:term, (Rstar R s u) /\ (Rstar R t u).
Proof with try_various 3 3.
elim; try intros...
inversion H0.
rewrite -H3 in H1; inversion H1...
inversion H1.
rewrite -H6 in H3...
elim (H _ _ H3 H6) => v [L1 L2]...
inversion H1.
rewrite <- H5 in *; clear H5.
rewrite <- H3 in *; clear H3.
inversion H2...
rewrite <- H5 in *; clear H5.
rewrite <- H3 in *; clear H3.
inversion H2...
rewrite <- H5 in *; clear H5.
rewrite <- H3 in *; clear H3.
inversion H2...
inversion H7...
inversion H2...
rewrite <- H9 in *...
rewrite <- H9 in *...
rewrite <- H9 in *; clear H9.
inversion H6...
elim (H0 _ _ H6 H10) => v [L1 L2]...
inversion H2...
inversion H2...
rewrite -H6 -H4...
rewrite -H4...
rewrite -H4.
try_various 5 5.
rewrite -H4.
try_various 5 5.
rewrite -H4...
rewrite -H7 in H4.
inversion_clear H4...
inversion H1.
rewrite <- H5 in *; clear H5.
rewrite <- H3 in *; clear H3.
inversion H2...
rewrite <- H5 in *; clear H5.
rewrite <- H3 in *; clear H3.
inversion H2...
rewrite <- H5 in *; clear H5.
inversion H2...
inversion H8...
rewrite <- H5 in *; clear H5.
clear H4 H3 r.
inversion H2...
inversion H6...
inversion H2...
rewrite <- H9 in *...
rewrite <- H9 in *...
rewrite <- H9 in *; clear H9.
inversion H6...
rewrite <- H9 in *; clear H9.
inversion H6...
elim (H0 _ _ H6 H10) => v [L1 L2]...
inversion H2...
rewrite -H4 in H2.
inversion H2...
try_various 0 5.
here we switch the order of things because the final AC-rewrite will be less daunting.