(* ========================================================================= *)
(* Part 1: Background theories. *)
(* ========================================================================= *)
(* ------------------------------------------------------------------------- *)
(* Definition of type of finite multisets with a few basic operations. *)
(* ------------------------------------------------------------------------- *)
parse_as_infix("mmember",(11,"right"));;
parse_as_infix("munion",(16,"right"));;
parse_as_infix("mdiff",(18,"left"));;
let multiset_tybij = new_type_definition
"multiset" ("multiset","multiplicity") multiset_tybij_th;;
(* ------------------------------------------------------------------------- *)
(* Extensionality for multisets. *)
(* ------------------------------------------------------------------------- *)
let MEXTENSION = prove
(`(M = N) = !a. multiplicity M a = multiplicity N a`,
REWRITE_TAC[GSYM
FUN_EQ_THM] THEN CONV_TAC(ONCE_DEPTH_CONV ETA_CONV) THEN
MESON_TAC[multiset_tybij]);;
(* ------------------------------------------------------------------------- *)
(* Basic properties of multisets. *)
(* ------------------------------------------------------------------------- *)
let MSING = prove
(`multiplicity (msing (a:A)) b = if b = a then 1 else 0`,
let MUNION = prove
(`multiplicity (M munion N) a = multiplicity M a + multiplicity N a`,
let MDIFF = prove
(`multiplicity (M mdiff N) (a:A) = multiplicity M a - multiplicity N a`,
REWRITE_TAC[mdiff] THEN MATCH_MP_TAC
MULTIPLICITY_MULTISET THEN
REWRITE_TAC[] THEN MATCH_MP_TAC
FINITE_SUBSET THEN
EXISTS_TAC `{a:A | ~(multiplicity M a = 0)}` THEN
SIMP_TAC[
SUBSET;
IN_ELIM_THM; multiset_tybij] THEN
CONV_TAC(ONCE_DEPTH_CONV ETA_CONV) THEN REWRITE_TAC[multiset_tybij] THEN
ARITH_TAC);;
(* ------------------------------------------------------------------------- *)
(* Some trivial properties of multisets that we use later. *)
(* ------------------------------------------------------------------------- *)
let MUNION_AC = prove
(`(M1 munion M2 = M2 munion M1) /\
((M1 munion M2) munion M3 = M1 munion M2 munion M3) /\
(M1 munion M2 munion M3 = M2 munion M1 munion M3)`,
let MMEMBER_MDIFF = prove
(`(a:A) mmember M ==> (M = (M mdiff (msing a)) munion (msing a))`,
REWRITE_TAC[mmember;
MEXTENSION;
MUNION;
MDIFF;
MSING] THEN
REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN
UNDISCH_TAC `~(multiplicity M (a:A) = 0)` THEN ARITH_TAC);;
(* ------------------------------------------------------------------------- *)
(* Induction principle for multisets. *)
(* ------------------------------------------------------------------------- *)
let MULTISET_INDUCT_LEMMA1 = prove
(`(!M. ({a | ~(multiplicity M a = 0)}
SUBSET s) ==> P M) /\
(!a:A M. P M ==> P (M munion (msing a)))
==> !n M. (multiplicity M a = n) /\
{a:A | ~(multiplicity M a = 0)}
SUBSET (a
INSERT s)
==> P M`,
STRIP_TAC THEN INDUCT_TAC THEN REPEAT STRIP_TAC THENL
[FIRST_X_ASSUM MATCH_MP_TAC THEN
UNDISCH_TAC `{a:A | ~(multiplicity M a = 0)}
SUBSET (a
INSERT s)` THEN
REWRITE_TAC[
SUBSET;
IN_ELIM_THM;
IN_INSERT] THEN ASM_MESON_TAC[];
SUBGOAL_THEN `M = (M mdiff (msing(a:A))) munion (msing a)` SUBST1_TAC THENL
[MATCH_MP_TAC
MMEMBER_MDIFF THEN ASM_REWRITE_TAC[mmember;
NOT_SUC];
ALL_TAC] THEN
MAP_EVERY (MATCH_MP_TAC o ASSUME)
[`!a:A M. P M ==> P (M munion msing a)`;
`!M. (multiplicity M a = n) /\
{a:A | ~(multiplicity M a = 0)}
SUBSET (a
INSERT s)
==> P M`] THEN
ASM_REWRITE_TAC[
MDIFF;
MSING; ARITH_RULE `SUC n - 1 = n`] THEN
MATCH_MP_TAC
SUBSET_TRANS THEN
EXISTS_TAC `{a:A | ~(multiplicity M a = 0)}` THEN
ASM_SIMP_TAC[
SUBSET;
IN_ELIM_THM; CONTRAPOS_THM;
SUB_0]]);;
let MULTISET_INDUCT = prove
(`P mempty /\
(!a:A M. P M ==> P (M munion (msing a)))
==> !M. P M`,
DISCH_THEN(MP_TAC o MATCH_MP
MULTISET_INDUCT_LEMMA2) THEN
REWRITE_TAC[
RIGHT_IMP_FORALL_THM] THEN
REWRITE_TAC[IMP_IMP] THEN
GEN_TAC THEN DISCH_THEN MATCH_MP_TAC THEN
EXISTS_TAC `{a:A | ~(multiplicity M a = 0)}` THEN
REWRITE_TAC[
SUBSET_REFL; multiset_tybij] THEN
CONV_TAC(ONCE_DEPTH_CONV ETA_CONV) THEN REWRITE_TAC[multiset_tybij]);;
(* ========================================================================= *)
(* Part 2: Transcription of Tobias's paper. *)
(* ========================================================================= *)
parse_as_infix("<<",(12,"right"));;
(* ------------------------------------------------------------------------- *)
(* Wellfounded part of a relation. *)
(* ------------------------------------------------------------------------- *)
let WFP_RULES,WFP_INDUCT,WFP_CASES = new_inductive_definition
`!x. (!y. y << x ==> WFP(<<) y) ==> WFP(<<) x`;;
(* ------------------------------------------------------------------------- *)
(* Wellfounded part induction. *)
(* ------------------------------------------------------------------------- *)
let WFP_PART_INDUCT = prove
(`!P. (!x. x
IN WFP(<<) /\ (!y. y << x ==> P(y)) ==> P(x))
==> !x:A. x
IN WFP(<<) ==> P(x)`,
GEN_TAC THEN REWRITE_TAC[
IN] THEN STRIP_TAC THEN
ONCE_REWRITE_TAC[TAUT `a ==> b <=> a ==> a /\ b`] THEN
MATCH_MP_TAC
WFP_INDUCT THEN ASM_MESON_TAC[
WFP_RULES]);;
(* ------------------------------------------------------------------------- *)
(* A relation is wellfounded iff WFP is the whole universe. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* The multiset order. *)
(* ------------------------------------------------------------------------- *)
let morder = new_definition
`morder(<<) N M <=> ?M0 a K. (M = M0 munion (msing a)) /\
(N = M0 munion K) /\
(!b. b mmember K ==> b << a)`;;
(* ------------------------------------------------------------------------- *)
(* We separate off this part from the proof of LEMMA_2_1. *)
(* ------------------------------------------------------------------------- *)
let LEMMA_2_0 = prove
(`morder(<<) N (M0 munion (msing a))
==> (?M. morder(<<) M M0 /\ (N = M munion (msing a))) \/
(?K. (N = M0 munion K) /\ (!b:A. b mmember K ==> b << a))`,
GEN_REWRITE_TAC LAND_CONV [morder] THEN
DISCH_THEN(EVERY_TCL (map X_CHOOSE_THEN
[`M1:(A)multiset`; `b:A`; `K:(A)multiset`]) STRIP_ASSUME_TAC) THEN
ASM_CASES_TAC `b:A = a` THENL
[DISJ2_TAC THEN UNDISCH_THEN `b:A = a` SUBST_ALL_TAC THEN
EXISTS_TAC `K:(A)multiset` THEN ASM_MESON_TAC[
MUNION_11]; DISJ1_TAC] THEN
SUBGOAL_THEN `?M2. M1 = M2 munion (msing(a:A))` STRIP_ASSUME_TAC THENL
[EXISTS_TAC `M1 mdiff (msing(a:A))` THEN
MAP_EVERY MATCH_MP_TAC [
MMEMBER_MDIFF;
MUNION_INUNION] THEN
UNDISCH_TAC `M0 munion (msing a) = M1 munion (msing(b:A))` THEN
ASM_REWRITE_TAC[
MEXTENSION;
MUNION;
MSING; mmember] THEN
DISCH_THEN(MP_TAC o SPEC `a:A`) THEN ASM_REWRITE_TAC[] THEN
ARITH_TAC; ALL_TAC] THEN
EXISTS_TAC `M2 munion K:(A)multiset` THEN ASM_REWRITE_TAC[
MUNION_AC] THEN
REWRITE_TAC[morder] THEN
MAP_EVERY EXISTS_TAC [`M2:(A)multiset`; `b:A`; `K:(A)multiset`] THEN
UNDISCH_TAC `M0 munion msing (a:A) = M1 munion msing b` THEN
ASM_REWRITE_TAC[
MUNION_AC] THEN MESON_TAC[
MUNION_AC;
MUNION_11]);;
(* ------------------------------------------------------------------------- *)
(* The sequence of lemmas from Tobias's paper. *)
(* ------------------------------------------------------------------------- *)
let LEMMA_2_1 = prove
(`(!M b:A. b << a /\ M
IN WFP(morder(<<))
==> (M munion (msing b))
IN WFP(morder(<<))) /\
M0
IN WFP(morder(<<)) /\
(!M. morder(<<) M M0 ==> (M munion (msing a))
IN WFP(morder(<<)))
==> (M0 munion (msing a))
IN WFP(morder(<<))`,
(* ------------------------------------------------------------------------- *)
(* Hence the final result. *)
(* ------------------------------------------------------------------------- *)