(* ========================================================================= *)
(* General "reduction" properties of binary relations,                       *)
(* ========================================================================= *)
needs "Library/rstc.ml";;
(* ------------------------------------------------------------------------- *)
(* Field of a binary relation.                                               *)
(* ------------------------------------------------------------------------- *)
let FL = new_definition
  `FL(R) x <=> (?y:A. R x y) \/ (?y. R y x)`;;
let CR = new_definition
  `CR(R:A->A->bool) <=> !x y1 y2. R x y1 /\ R x y2 ==> ?z. R y1 z /\ R y2 z`;;
let WCR = new_definition
  `WCR(R:A->A->bool) <=>
   !x y1 y2. R x y1 /\ R x y2 ==> ?z. RTC R y1 z /\ RTC R y2 z`;;
let WN = new_definition
  `WN(R:A->A->bool) <=> !x. ?y. RTC R x y /\ NORMAL(R) y`;;
let SN = new_definition
  `SN(R:A->A->bool) <=> ~(?seq. !n. R (seq n) (seq (SUC n)))`;;
let TREE = new_definition
  `TREE(R:A->A->bool) <=>
        (!y. ~(TC R y y)) /\
        ?a. a IN FL(R) /\
            !y. y IN FL(R) ==> (y = a) \/ TC R a y /\ ?!x. R x y`;;let LF = new_definition
  `LF(R:A->A->bool) <=> !x. FINITE {y | R x y}`;;let WF_TC = prove
 (`!R:A->A->bool. 
WF(
TC R) <=> 
WF(R)`,
  GEN_TAC THEN EQ_TAC THENL
   [MESON_TAC[
WF_SUBSET; 
TC_INC];
    REWRITE_TAC[
WF] THEN DISCH_TAC THEN X_GEN_TAC `P:A->bool` THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `\y:A. ?z. P z /\ 
TC(R) z y`) THEN
    REWRITE_TAC[] THEN MESON_TAC[
TC_CASES_L]]);;
 
let STRIP_LEMMA = prove
 (`!R S. (!x y1 y2.    R x y1 /\ S x y2 ==> ?z:A. S y1 z /\    R y2 z) ==>
         (!x y1 y2. 
TC R x y1 /\ S x y2 ==> ?z:A. S y1 z /\ 
TC R y2 z)`,
 
let NEWMAN_LEMMA = prove
 (`!R:A->A->bool. 
SN(R) /\ 
WCR(R) ==> 
CR(
RTC R)`,
  GEN_TAC THEN STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP 
SN_WN) THEN
  DISCH_THEN(fun th -> ASSUME_TAC(REWRITE_RULE[
WN] th) THEN MP_TAC th) THEN
  DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP 
NORM_CR th]) THEN
  FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[
WF_IND; 
SN_WF]) THEN
  REWRITE_TAC[
INV] THEN X_GEN_TAC `x:A` THEN REPEAT STRIP_TAC THEN
  MAP_EVERY UNDISCH_TAC [`
RTC R (x:A) y1`; `
RTC R (x:A) y2`] THEN
  ONCE_REWRITE_TAC[
RTC_CASES_R] THEN
  DISCH_THEN(DISJ_CASES_THEN2 ASSUME_TAC (X_CHOOSE_TAC `z2:A`)) THEN
  DISCH_THEN(DISJ_CASES_THEN2 ASSUME_TAC (X_CHOOSE_TAC `z1:A`)) THENL
   [ASM_MESON_TAC[];ASM_MESON_TAC[
NORMAL];ASM_MESON_TAC[
NORMAL]; ALL_TAC] THEN
  FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
WCR]) THEN
  ASM_MESON_TAC[
RTC_TRANS]);;
 
let LF_TC_FINITE = prove
 (`!R. 
LF(R) /\ 
SN(R) ==> !x:A. 
FINITE {y | 
TC(R) x y}`,
  GEN_TAC THEN REWRITE_TAC[
LF] THEN STRIP_TAC THEN
  FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[
WF_IND; 
SN_WF; 
INV]) THEN
  GEN_TAC THEN DISCH_TAC THEN SUBGOAL_THEN
    `{y:A | 
TC(R) x y} = {y | R x y} 
UNION
                         (
UNIONS { s | ?z. R x z /\ (s = {y | 
TC(R) z y})})`
  SUBST1_TAC THENL
   [REWRITE_TAC[
EXTENSION; 
IN_UNION; 
IN_UNIONS] THEN
    REWRITE_TAC[
IN_ELIM_THM] THEN REWRITE_TAC[
IN] THEN
    GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [
TC_CASES_R] THEN
    AP_TERM_TAC THEN EQ_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
    ASM_MESON_TAC[]; ALL_TAC] THEN
  ASM_REWRITE_TAC[
FINITE_UNION; 
FINITE_UNIONS] THEN CONJ_TAC THENL
   [MP_TAC(ISPECL [`\z:A. {y | 
TC R z y}`; `{z | (R:A->A->bool) x z}`]
                  
FINITE_IMAGE_EXPAND) THEN
    ASM_REWRITE_TAC[] THEN REWRITE_TAC[
IN; 
IN_ELIM_THM];
    GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [
IN_ELIM_THM] THEN
    REWRITE_TAC[] THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
    FIRST_ASSUM MATCH_MP_TAC THEN FIRST_ASSUM ACCEPT_TAC]);;
 
let SN_NOLOOP = prove
 (`!R:A->A->bool. 
SN(R) ==> !z. ~(
TC(R) z z)`,
  GEN_TAC THEN ONCE_REWRITE_TAC[GSYM 
SN_TC] THEN
  SPEC_TAC(`
TC(R:A->A->bool)`,`R:A->A->bool`) THEN
  GEN_TAC THEN REWRITE_TAC[
SN_WF; 
INV; 
WF] THEN
  DISCH_THEN(fun th -> GEN_TAC THEN MP_TAC th) THEN
  DISCH_THEN(MP_TAC o SPEC `\x:A. x = z`) THEN
  REWRITE_TAC[] THEN MESON_TAC[]);;
 
let FC_FINITE_BOUND_LEMMA = prove
 (`!R. (!z. ~(
TC R z z))
       ==> !n. {y:A | 
RTC(R) x y} 
HAS_SIZE n
               ==> !m y. 
RELPOW m R x y ==> m <= n`,
  REPEAT STRIP_TAC THEN
  FIRST_ASSUM(X_CHOOSE_THEN `f:num->A` STRIP_ASSUME_TAC o
    REWRITE_RULE[
RELPOW_SEQUENCE]) THEN
  SUBGOAL_THEN `!i. i <= m ==> 
RELPOW i R (x:A) (f i)` ASSUME_TAC THENL
   [INDUCT_TAC THEN ASM_REWRITE_TAC[
RELPOW] THEN
    REWRITE_TAC[
LE_SUC_LT] THEN ASM_MESON_TAC[
LT_IMP_LE]; ALL_TAC] THEN
  SUBGOAL_THEN `{z:A | ?i:num. i < m /\ (z = f i)} 
SUBSET {y | 
RTC R x y}`
  ASSUME_TAC THENL
   [REWRITE_TAC[
SUBSET; 
IN_ELIM_THM] THEN ASM_MESON_TAC[
RELPOW_RTC; 
LT_IMP_LE];
    ALL_TAC] THEN
  SUBGOAL_THEN `!p. p <= m ==> {z:A | ?i. i < p /\ (z = f i)} 
HAS_SIZE p`
  (fun th -> ASSUME_TAC(MATCH_MP th (SPEC `m:num` 
LE_REFL))) THENL
   [ALL_TAC;
    MATCH_MP_TAC 
HAS_SIZE_SUBSET THEN
    EXISTS_TAC `{z:A | ?i. i < m /\ (z = f i)}` THEN
    EXISTS_TAC `{y:A | 
RTC(R) x y}` THEN ASM_REWRITE_TAC[]] THEN
  INDUCT_TAC THEN DISCH_TAC THENL
   [REWRITE_TAC[
HAS_SIZE_0; 
EXTENSION; 
NOT_IN_EMPTY; 
IN_ELIM_THM; 
LT];
    ALL_TAC] THEN
  SUBGOAL_THEN `{z:A | ?i. i < SUC p /\ (z = f i)} =
                f(p) 
INSERT {z | ?i. i < p /\ (z = f i)}`
  SUBST1_TAC THENL
   [REWRITE_TAC[
EXTENSION; 
IN_INSERT; 
IN_ELIM_THM] THEN
    REWRITE_TAC[
LT] THEN MESON_TAC[]; ALL_TAC] THEN
  REWRITE_TAC[
HAS_SIZE; 
CARD_CLAUSES; 
SUC_INJ] THEN
  SUBGOAL_THEN `{z:A | ?i. i < p /\ (z = f i)} 
HAS_SIZE p` MP_TAC THENL
   [FIRST_ASSUM MATCH_MP_TAC THEN UNDISCH_TAC `SUC p <= m` THEN ARITH_TAC;
    ALL_TAC] THEN
  REWRITE_TAC[
HAS_SIZE] THEN STRIP_TAC THEN
  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP (CONJUNCT2 
CARD_CLAUSES) th]) THEN
  COND_CASES_TAC THEN ASM_REWRITE_TAC[
FINITE_INSERT] THEN
  UNDISCH_TAC `f p 
IN {z:A | ?i:num. i < p /\ (z = f i)}` THEN
  CONV_TAC CONTRAPOS_CONV THEN DISCH_TAC THEN
  REWRITE_TAC[
IN_ELIM_THM; 
NOT_EXISTS_THM] THEN
  X_GEN_TAC `q:num` THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  SUBGOAL_THEN `
TC(R) ((f:num->A) q) (f p)` (fun th -> ASM_MESON_TAC[th]) THEN
  UNDISCH_TAC `SUC p <= m` THEN UNDISCH_TAC `q < p` THEN
  REWRITE_TAC[
LT_EXISTS] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:num` SUBST1_TAC) THEN
  SPEC_TAC(`d:num`,`d:num`) THEN INDUCT_TAC THENL
   [REWRITE_TAC[
ADD_CLAUSES] THEN DISCH_TAC THEN
    MATCH_MP_TAC 
TC_INC THEN FIRST_ASSUM MATCH_MP_TAC THEN
    UNDISCH_TAC `SUC (SUC q) <= m` THEN ARITH_TAC;
    DISCH_TAC THEN MATCH_MP_TAC 
TC_TRANS_L THEN
    EXISTS_TAC `(f:num->A)(q + SUC d)` THEN CONJ_TAC THENL
     [ALL_TAC; REWRITE_TAC[
ADD_CLAUSES]] THEN
    FIRST_ASSUM MATCH_MP_TAC THEN
    UNDISCH_TAC `SUC (q + SUC (SUC d)) <= m` THEN ARITH_TAC]);;
 
let BOUND_SN = prove
 (`!R. (!x:A. ?N. !n y. 
RELPOW n R x y ==> n <= N) ==> 
SN(R)`,
  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[
SN_WF; 
WF_DCHAIN; 
INV] THEN
  DISCH_THEN(X_CHOOSE_TAC `f:num->A`) THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `(f:num->A) 0`) THEN
  DISCH_THEN(X_CHOOSE_THEN `N:num`
   (MP_TAC o SPECL [`SUC N`; `f(SUC N):A`])) THEN
  REWRITE_TAC[GSYM 
NOT_LT; 
LT] THEN
  SUBGOAL_THEN `!n. 
RELPOW n R (f 0 :A) (f n)` (fun th -> REWRITE_TAC[th]) THEN
  INDUCT_TAC THEN ASM_REWRITE_TAC[
RELPOW] THEN ASM_MESON_TAC[]);;
 
let TREE_FL = prove
 (`!R. 
TREE(R) ==> ?a:A. 
FL(R) = {y | 
RTC(R) a y}`,
  GEN_TAC THEN REWRITE_TAC[
TREE] THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC
   (X_CHOOSE_THEN `a:A` STRIP_ASSUME_TAC)) THEN
  EXISTS_TAC `a:A` THEN REWRITE_TAC[
EXTENSION; 
IN_ELIM_THM] THEN
  X_GEN_TAC `x:A` THEN EQ_TAC THENL
   [DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN REWRITE_TAC[
RTC; 
RC_EXPLICIT] THEN
    MESON_TAC[]; ONCE_REWRITE_TAC[
RTC_CASES_L] THEN ASM_MESON_TAC[
IN; 
FL]]);;