(* ========================================================================= *)
(* All you wanted to know about reflexive symmetric and transitive closures. *)
(* ========================================================================= *)
prioritize_num();;
let RULE_INDUCT_TAC =
MATCH_MP_TAC o DISCH_ALL o SPEC_ALL o UNDISCH o SPEC_ALL;;
(* ------------------------------------------------------------------------- *)
(* Little lemmas about equivalent forms of symmetry and transitivity. *)
(* ------------------------------------------------------------------------- *)
let SYM_ALT = prove
(`!R:A->A->bool. (!x y. R x y ==> R y x) <=> (!x y. R x y <=> R y x)`,
GEN_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
[EQ_TAC THEN DISCH_TAC THEN FIRST_ASSUM MATCH_MP_TAC;
FIRST_ASSUM(fun
th -> GEN_REWRITE_TAC I [
th])] THEN
FIRST_ASSUM MATCH_ACCEPT_TAC);;
let TRANS_ALT = prove
(`!(R:A->A->bool) (S:A->A->bool) U.
(!x z. (?y. R x y /\ S y z) ==> U x z) <=>
(!x y z. R x y /\ S y z ==> U x z)`,
REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN
EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Reflexive closure *)
(* ------------------------------------------------------------------------- *)
let RC_RULES,RC_INDUCT,RC_CASES = new_inductive_definition
`(!x y. R x y ==> RC R x y) /\
(!x:A. RC R x x)`;;
let RC_MONO = prove
(`!(R:A->A->bool) S.
(!x y. R x y ==> S x y) ==>
(!x y.
RC R x y ==>
RC S x y)`,
let RC_SYM = prove
(`!R:A->A->bool.
(!x y. R x y ==> R y x) ==> (!x y.
RC R x y ==>
RC R y x)`,
let RC_TRANS = prove
(`!R:A->A->bool.
(!x y z. R x y /\ R y z ==> R x z) ==>
(!x y z.
RC R x y /\
RC R y z ==>
RC R x z)`,
REWRITE_TAC[
RC_CASES] THEN MESON_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Symmetric closure *)
(* ------------------------------------------------------------------------- *)
let SC_RULES,SC_INDUCT,SC_CASES = new_inductive_definition
`(!x y. R x y ==> SC R x y) /\
(!x:A y. SC R x y ==> SC R y x)`;;
let SC_MONO = prove
(`!(R:A->A->bool) S.
(!x y. R x y ==> S x y) ==>
(!x y.
SC R x y ==>
SC S x y)`,
(* ------------------------------------------------------------------------- *)
(* Transitive closure *)
(* ------------------------------------------------------------------------- *)
let TC_RULES,TC_INDUCT,TC_CASES = new_inductive_definition
`(!x y. R x y ==> TC R x y) /\
(!(x:A) y z. TC R x y /\ TC R y z ==> TC R x z)`;;
let TC_MONO = prove
(`!(R:A->A->bool) S.
(!x y. R x y ==> S x y) ==>
(!x y.
TC R x y ==>
TC S x y)`,
REPEAT GEN_TAC THEN STRIP_TAC THEN
MATCH_MP_TAC
TC_INDUCT THEN ASM_MESON_TAC[
TC_RULES]);;
let TC_CLOSED = prove
(`!R:A->A->bool. (
TC R = R) <=> !x y z. R x y /\ R y z ==> R x z`,
GEN_TAC THEN REWRITE_TAC[
FUN_EQ_THM] THEN EQ_TAC THENL
[MESON_TAC[
TC_RULES]; REPEAT STRIP_TAC] THEN
EQ_TAC THENL [RULE_INDUCT_TAC
TC_INDUCT; ALL_TAC] THEN
ASM_MESON_TAC[
TC_RULES]);;
let TC_SYM = prove
(`!R:A->A->bool. (!x y. R x y ==> R y x) ==> (!x y.
TC R x y ==>
TC R y x)`,
(* ------------------------------------------------------------------------- *)
(* Commutativity properties of the three basic closure operations *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Left and right variants of TC. *)
(* ------------------------------------------------------------------------- *)
let TC_INDUCT_L = prove
(`!(R:A->A->bool) P.
(!x y. R x y ==> P x y) /\
(!x y z. P x y /\ R y z ==> P x z) ==>
(!x y.
TC R x y ==> P x y)`,
REPEAT GEN_TAC THEN STRIP_TAC THEN
SUBGOAL_THEN `!y:A z.
TC(R) y z ==> !x:A. P x y ==> P x z` MP_TAC THENL
[MATCH_MP_TAC
TC_INDUCT THEN ASM_MESON_TAC[]; ASM_MESON_TAC[
TC_CASES_R]]);;
let TC_INDUCT_R = prove
(`!(R:A->A->bool) P.
(!x y. R x y ==> P x y) /\
(!x z. (?y. R x y /\ P y z) ==> P x z) ==>
(!x y.
TC R x y ==> P x y)`,
REPEAT GEN_TAC THEN STRIP_TAC THEN
SUBGOAL_THEN `!x:A y.
TC(R) x y ==> !z:A. P y z ==> P x z` MP_TAC THENL
[MATCH_MP_TAC
TC_INDUCT THEN ASM_MESON_TAC[]; ASM_MESON_TAC[
TC_CASES_L]]);;
(* ------------------------------------------------------------------------- *)
(* Reflexive symmetric closure *)
(* ------------------------------------------------------------------------- *)
let RSC_INDUCT = prove
(`!(R:A->A->bool) P.
(!x y. R x y ==> P x y) /\
(!x. P x x) /\
(!x y. P x y ==> P y x)
==> !x y.
RSC R x y ==> P x y`,
(* ------------------------------------------------------------------------- *)
(* Reflexive transitive closure *)
(* ------------------------------------------------------------------------- *)
let RTC_INDUCT = prove
(`!(R:A->A->bool) P.
(!x y. R x y ==> P x y) /\
(!x. P x x) /\
(!x y z. P x y /\ P y z ==> P x z)
==> !x y.
RTC R x y ==> P x y`,
REPEAT GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC[
RTC;
RC_TC] THEN
MATCH_MP_TAC
TC_INDUCT THEN REWRITE_TAC[
RC_EXPLICIT] THEN ASM_MESON_TAC[]);;
let RTC_INDUCT_L = prove
(`!(R:A->A->bool) P.
(!x. P x x) /\
(!x y z. P x y /\ R y z ==> P x z)
==> !x y.
RTC R x y ==> P x y`,
let RTC_INDUCT_R = prove
(`!(R:A->A->bool) P.
(!x. P x x) /\
(!x y z. R x y /\ P y z ==> P x z)
==> !x y.
RTC R x y ==> P x y`,
let RTC_CLOSED = prove
(`!R:A->A->bool. (
RTC R = R) <=> (!x. R x x) /\
(!x y z. R x y /\ R y z ==> R x z)`,
(* ------------------------------------------------------------------------- *)
(* Symmetric transitive closure *)
(* ------------------------------------------------------------------------- *)
let STC_INDUCT = prove
(`!(R:A->A->bool) P.
(!x y. R x y ==> P x y) /\
(!x y. P x y ==> P y x) /\
(!x y z. P x y /\ P y z ==> P x z) ==>
!x y.
STC R x y ==> P x y`,
let STC_CLOSED = prove
(`!R:A->A->bool. (
STC R = R) <=> (!x y. R x y ==> R y x) /\
(!x y z. R x y /\ R y z ==> R x z)`,
(* ------------------------------------------------------------------------- *)
(* Reflexive symmetric transitive closure (smallest equivalence relation) *)
(* ------------------------------------------------------------------------- *)
let RSTC_INDUCT = prove
(`!(R:A->A->bool) P.
(!x y. R x y ==> P x y) /\
(!x. P x x) /\
(!x y. P x y ==> P y x) /\
(!x y z. P x y /\ P y z ==> P x z)
==> !x y.
RSTC R x y ==> P x y`,
let RSTC_CLOSED = prove
(`!R:A->A->bool. (
RSTC R = R) <=> (!x. R x x) /\
(!x y. R x y ==> R y x) /\
(!x y z. R x y /\ R y z ==> R x z)`,
(* ------------------------------------------------------------------------- *)
(* Finally, we prove the inclusion properties for composite closures *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Handy things about reverse relations. *)
(* ------------------------------------------------------------------------- *)
let INV = new_definition
`INV R (x:A) (y:B) <=> R y x`;;
(* ------------------------------------------------------------------------- *)
(* An iterative version of (R)TC. *)
(* ------------------------------------------------------------------------- *)
let RELPOW = new_recursive_definition num_RECURSION
`(RELPOW 0 (R:A->A->bool) x y <=> (x = y)) /\
(RELPOW (SUC n) R x y <=> ?z. RELPOW n R x z /\ R z y)`;;
let RELPOW_R = prove
(`(
RELPOW 0 (R:A->A->bool) x y <=> (x = y)) /\
(
RELPOW (SUC n) R x y <=> ?z. R x z /\
RELPOW n R z y)`,
CONJ_TAC THENL [REWRITE_TAC[
RELPOW]; ALL_TAC] THEN
MAP_EVERY (fun t -> SPEC_TAC(t,t)) [`x:A`; `y:A`; `n:num`] THEN
INDUCT_TAC THEN ASM_MESON_TAC[
RELPOW]);;
let RELPOW_SEQUENCE = prove
(`!R n x y.
RELPOW n R x y <=> ?f. (f(0) = x:A) /\ (f(n) = y) /\
!i. i < n ==> R (f i) (f(SUC i))`,
GEN_TAC THEN INDUCT_TAC THEN ASM_REWRITE_TAC[
LT;
RELPOW] THENL
[REPEAT GEN_TAC THEN EQ_TAC THENL
[DISCH_THEN SUBST1_TAC THEN EXISTS_TAC `\n:num. y:A` THEN REWRITE_TAC[];
MESON_TAC[]];
REPEAT GEN_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
[DISJ_CASES_TAC(ARITH_RULE `(n = 0) \/ 0 < n`) THENL
[EXISTS_TAC `\i. if i = 0 then x else y:A` THEN
ASM_REWRITE_TAC[ARITH;
LT] THEN
REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[
NOT_SUC] THEN
ASM_MESON_TAC[];
EXISTS_TAC `\i. if i <= n then f(i) else (y:A)` THEN
ASM_REWRITE_TAC[
LE_0; ARITH_RULE `~(SUC n <= n)`] THEN
REPEAT STRIP_TAC THEN
ASM_REWRITE_TAC[
LE_REFL; ARITH_RULE `~(SUC n <= n)`] THEN
ASM_REWRITE_TAC[
LE_SUC_LT] THEN
ASM_REWRITE_TAC[
LE_LT] THEN
FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]];
EXISTS_TAC `(f:num->A) n` THEN CONJ_TAC THENL
[EXISTS_TAC `f:num->A` THEN ASM_REWRITE_TAC[] THEN
REPEAT STRIP_TAC THEN FIRST_ASSUM MATCH_MP_TAC THEN
ASM_REWRITE_TAC[];
ASM_MESON_TAC[]]]]);;