(* ========================================================================= *)
(* Permutations, both general and specifically on finite sets. *)
(* ========================================================================= *)
parse_as_infix("permutes",(12,"right"));;
(* ------------------------------------------------------------------------- *)
(* Inverse function (on whole universe). *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Transpositions. *)
(* ------------------------------------------------------------------------- *)
let SWAP_GALOIS = prove
(`!a b x y. x = swap(a,b) y <=> y = swap(a,b) x`,
REWRITE_TAC[swap] THEN MESON_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Basic consequences of the definition. *)
(* ------------------------------------------------------------------------- *)
let PERMUTES_INVERSE_EQ = prove
(`!p s. p permutes s ==> !x y. inverse p y = x <=> p x = y`,
REWRITE_TAC[permutes; inverse] THEN MESON_TAC[]);;
let PERMUTES_SWAP = prove
(`!a b s. a
IN s /\ b
IN s ==> swap(a,b) permutes s`,
REWRITE_TAC[permutes; swap] THEN MESON_TAC[]);;
let PERMUTES_BIJECTIONS = prove
(`!p q. (!x. x
IN s ==> p x
IN s) /\ (!x. ~(x
IN s) ==> p x = x) /\
(!x. x
IN s ==> q x
IN s) /\ (!x. ~(x
IN s) ==> q x = x) /\
(!x. p(q x) = x) /\ (!x. q(p x) = x)
==> p permutes s`,
REWRITE_TAC[permutes] THEN MESON_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Group properties. *)
(* ------------------------------------------------------------------------- *)
let PERMUTES_INVERSE = prove
(`!p s. p permutes s ==> inverse(p) permutes s`,
REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP
PERMUTES_INVERSE_EQ) THEN
POP_ASSUM MP_TAC THEN REWRITE_TAC[permutes] THEN MESON_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* The number of permutations on a finite set. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Alternative characterizations of permutation of finite set. *)
(* ------------------------------------------------------------------------- *)
let PERMUTES_FINITE_INJECTIVE = prove
(`!s:A->bool p.
FINITE s
==> (p permutes s <=>
(!x. ~(x
IN s) ==> p x = x) /\
(!x. x
IN s ==> p x
IN s) /\
(!x y. x
IN s /\ y
IN s /\ p x = p y ==> x = y))`,
REWRITE_TAC[permutes] THEN REPEAT STRIP_TAC THEN
MATCH_MP_TAC(TAUT `(p ==> (q <=> r)) ==> (p /\ q <=> p /\ r)`) THEN
DISCH_TAC THEN EQ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN STRIP_TAC THEN
FIRST_ASSUM(MP_TAC o SPEC `p:A->A` o MATCH_MP
(REWRITE_RULE[
IMP_CONJ]
SURJECTIVE_IFF_INJECTIVE)) THEN
ASM_REWRITE_TAC[
SUBSET;
FORALL_IN_IMAGE; IMP_IMP; GSYM
CONJ_ASSOC] THEN
STRIP_TAC THEN X_GEN_TAC `y:A` THEN
ASM_CASES_TAC `(y:A)
IN s` THEN ASM_MESON_TAC[]);;
let PERMUTES_FINITE_SURJECTIVE = prove
(`!s:A->bool p.
FINITE s
==> (p permutes s <=>
(!x. ~(x
IN s) ==> p x = x) /\ (!x. x
IN s ==> p x
IN s) /\
(!y. y
IN s ==> ?x. x
IN s /\ p x = y))`,
REWRITE_TAC[permutes] THEN REPEAT STRIP_TAC THEN
MATCH_MP_TAC(TAUT `(p ==> (q <=> r)) ==> (p /\ q <=> p /\ r)`) THEN
DISCH_TAC THEN EQ_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN STRIP_TAC THEN
FIRST_ASSUM(MP_TAC o SPEC `p:A->A` o MATCH_MP
(REWRITE_RULE[
IMP_CONJ]
SURJECTIVE_IFF_INJECTIVE)) THEN
ASM_REWRITE_TAC[
SUBSET;
FORALL_IN_IMAGE; IMP_IMP; GSYM
CONJ_ASSOC] THEN
STRIP_TAC THEN X_GEN_TAC `y:A` THEN
ASM_CASES_TAC `(y:A)
IN s` THEN ASM_MESON_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Permutations of index set for iterated operations. *)
(* ------------------------------------------------------------------------- *)
let ITERATE_PERMUTE = prove
(`!op. monoidal op
==> !f p s. p permutes s ==> iterate op s f = iterate op s (f o p)`,
REPEAT STRIP_TAC THEN
FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP
ITERATE_BIJECTION) THEN
ASM_MESON_TAC[permutes]);;
(* ------------------------------------------------------------------------- *)
(* Various combinations of transpositions with 2, 1 and 0 common elements. *)
(* ------------------------------------------------------------------------- *)
let SWAP_COMMON = prove
(`!a b c:A. ~(a = c) /\ ~(b = c)
==> swap(a,b) o swap(a,c) = swap(b,c) o swap(a,b)`,
REPEAT GEN_TAC THEN REWRITE_TAC[
FUN_EQ_THM; swap;
o_THM;
I_THM] THEN
DISCH_TAC THEN X_GEN_TAC `x:A` THEN
MAP_EVERY ASM_CASES_TAC [`x:A = a`; `x:A = b`; `x:A = c`] THEN
REPEAT(FIRST_X_ASSUM SUBST_ALL_TAC) THEN ASM_REWRITE_TAC[] THEN
ASM_MESON_TAC[]);;
let SWAP_INDEPENDENT = prove
(`!a b c d:A. ~(a = c) /\ ~(a = d) /\ ~(b = c) /\ ~(b = d)
==> swap(a,b) o swap(c,d) = swap(c,d) o swap(a,b)`,
REPEAT GEN_TAC THEN REWRITE_TAC[
FUN_EQ_THM; swap;
o_THM;
I_THM] THEN
DISCH_TAC THEN X_GEN_TAC `x:A` THEN
MAP_EVERY ASM_CASES_TAC [`x:A = a`; `x:A = b`; `x:A = c`] THEN
REPEAT(FIRST_X_ASSUM SUBST_ALL_TAC) THEN ASM_REWRITE_TAC[] THEN
ASM_MESON_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Permutations as transposition sequences. *)
(* ------------------------------------------------------------------------- *)
let swapseq_RULES,swapseq_INDUCT,swapseq_CASES = new_inductive_definition
`(swapseq 0 I) /\
(!a b p n. swapseq n p /\ ~(a = b) ==> swapseq (SUC n) (swap(a,b) o p))`;;
(* ------------------------------------------------------------------------- *)
(* Some closure properties of the set of permutations, with lengths. *)
(* ------------------------------------------------------------------------- *)
let SWAPSEQ_I = CONJUNCT1 swapseq_RULES;;
(* ------------------------------------------------------------------------- *)
(* The identity map only has even transposition sequences. *)
(* ------------------------------------------------------------------------- *)
let SYMMETRY_LEMMA = prove
(`(!a b c d. P a b c d ==> P a b d c) /\
(!a b c d. ~(a = b) /\ ~(c = d) /\
(a = c /\ b = d \/ a = c /\ ~(b = d) \/ ~(a = c) /\ b = d \/
~(a = c) /\ ~(a = d) /\ ~(b = c) /\ ~(b = d))
==> P a b c d)
==> (!a b c d:A. ~(a = b) /\ ~(c = d) ==> P a b c d)`,
REPEAT STRIP_TAC THEN MAP_EVERY ASM_CASES_TAC
[`a:A = c`; `a:A = d`; `b:A = c`; `b:A = d`] THEN
ASM_MESON_TAC[]);;
let SWAP_GENERAL = prove
(`!a b c d:A.
~(a = b) /\ ~(c = d)
==> swap(a,b) o swap(c,d) = I \/
?x y z. ~(x = a) /\ ~(y = a) /\ ~(z = a) /\ ~(x = y) /\
swap(a,b) o swap(c,d) = swap(x,y) o swap(a,z)`,
MATCH_MP_TAC
SYMMETRY_LEMMA THEN CONJ_TAC THENL
[REWRITE_TAC[
SWAP_SYM] THEN SIMP_TAC[]; ALL_TAC] THEN
REPEAT STRIP_TAC THEN REPEAT(FIRST_X_ASSUM SUBST_ALL_TAC) THENL
[MESON_TAC[
SWAP_IDEMPOTENT];
DISJ2_TAC THEN MAP_EVERY EXISTS_TAC [`b:A`; `d:A`; `b:A`] THEN
ASM_MESON_TAC[
SWAP_COMMON];
DISJ2_TAC THEN MAP_EVERY EXISTS_TAC [`c:A`; `d:A`; `c:A`] THEN
ASM_MESON_TAC[SWAP_COMMON'];
DISJ2_TAC THEN MAP_EVERY EXISTS_TAC [`c:A`; `d:A`; `b:A`] THEN
ASM_MESON_TAC[
SWAP_INDEPENDENT]]);;
let FIXING_SWAPSEQ_DECREASE = prove
(`!n p a b:A.
swapseq n p /\ ~(a = b) /\ (swap(a,b) o p) a = a
==> ~(n = 0) /\
swapseq (n - 1) (swap(a,b) o p)`,
INDUCT_TAC THEN REPEAT GEN_TAC THEN
GEN_REWRITE_TAC (LAND_CONV o LAND_CONV) [
swapseq_CASES] THEN
REWRITE_TAC[
NOT_SUC] THENL
[DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
ASM_REWRITE_TAC[
I_THM;
o_THM; swap] THEN MESON_TAC[];
ALL_TAC] THEN
REWRITE_TAC[
LEFT_IMP_EXISTS_THM;
LEFT_AND_EXISTS_THM] THEN
MAP_EVERY X_GEN_TAC [`c:A`; `d:A`; `q:A->A`; `m:num`] THEN
REWRITE_TAC[
SUC_INJ; GSYM
CONJ_ASSOC] THEN
DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
FIRST_X_ASSUM SUBST_ALL_TAC THEN REWRITE_TAC[
o_ASSOC] THEN STRIP_TAC THEN
MP_TAC(SPECL [`a:A`; `b:A`; `c:A`; `d:A`]
SWAP_GENERAL) THEN
ASM_REWRITE_TAC[] THEN
DISCH_THEN(DISJ_CASES_THEN2 SUBST_ALL_TAC MP_TAC) THEN
ASM_REWRITE_TAC[
I_O_ID;
SUC_SUB1;
LEFT_IMP_EXISTS_THM] THEN
MAP_EVERY X_GEN_TAC [`x:A`; `y:A`; `z:A`] THEN
REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
DISCH_THEN SUBST_ALL_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
[`q:A->A`; `a:A`; `z:A`]) THEN
ANTS_TAC THENL
[ASM_REWRITE_TAC[] THEN
FIRST_X_ASSUM(MP_TAC o check(is_eq o concl)) THEN
REWRITE_TAC[GSYM
o_ASSOC] THEN
ABBREV_TAC `r:A->A = swap(a:A,z) o q` THEN
ASM_REWRITE_TAC[
FUN_EQ_THM;
o_THM; swap] THEN ASM_MESON_TAC[];
SPEC_TAC(`n:num`,`n:num`) THEN INDUCT_TAC THEN
REWRITE_TAC[
NOT_SUC;
SUC_SUB1; GSYM
o_ASSOC] THEN
ASM_MESON_TAC[
swapseq_RULES]]);;
let SWAPSEQ_IDENTITY_EVEN = prove
(`!n.
swapseq n (I:A->A) ==>
EVEN n`,
MATCH_MP_TAC
num_WF THEN X_GEN_TAC `n:num` THEN DISCH_TAC THEN
GEN_REWRITE_TAC LAND_CONV [
swapseq_CASES] THEN
DISCH_THEN(DISJ_CASES_THEN2 (SUBST_ALL_TAC o CONJUNCT1) MP_TAC) THEN
REWRITE_TAC[
EVEN;
LEFT_IMP_EXISTS_THM] THEN
MAP_EVERY X_GEN_TAC [`a:A`; `b:A`; `p:A->A`; `m:num`] THEN
DISCH_THEN(STRIP_ASSUME_TAC o GSYM) THEN
MP_TAC(SPECL [`m:num`; `p:A->A`; `a:A`; `b:A`]
FIXING_SWAPSEQ_DECREASE) THEN
ASM_REWRITE_TAC[
I_THM] THEN STRIP_TAC THEN
FIRST_X_ASSUM(MP_TAC o SPEC `m - 1`) THEN
UNDISCH_THEN `SUC m = n` (SUBST_ALL_TAC o SYM) THEN
ASM_REWRITE_TAC[ARITH_RULE `m - 1 < SUC m`] THEN UNDISCH_TAC `~(m = 0)` THEN
SPEC_TAC(`m:num`,`m:num`) THEN INDUCT_TAC THEN
REWRITE_TAC[
SUC_SUB1;
EVEN]);;
(* ------------------------------------------------------------------------- *)
(* Therefore we have a welldefined notion of parity. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* And it has the expected composition properties. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* A more abstract characterization of permutations. *)
(* ------------------------------------------------------------------------- *)
let PERMUTATION_LEMMA = prove
(`!s p:A->A.
FINITE s /\
(!y. ?!x. p(x) = y) /\ (!x. ~(x
IN s) ==> p x = x)
==> permutation p`,
ONCE_REWRITE_TAC[
IMP_CONJ] THEN REWRITE_TAC[
RIGHT_FORALL_IMP_THM] THEN
MATCH_MP_TAC
FINITE_INDUCT_STRONG THEN CONJ_TAC THENL
[REWRITE_TAC[
NOT_IN_EMPTY] THEN REPEAT STRIP_TAC THEN
SUBGOAL_THEN `p:A->A = I` (fun th -> REWRITE_TAC[th;
PERMUTATION_I]) THEN
ASM_REWRITE_TAC[
FUN_EQ_THM;
I_THM];
ALL_TAC] THEN
MAP_EVERY X_GEN_TAC [`a:A`; `s:A->bool`] THEN STRIP_TAC THEN
REWRITE_TAC[
IN_INSERT] THEN REPEAT STRIP_TAC THEN
SUBGOAL_THEN `permutation((swap(a,p(a)) o swap(a,p(a))) o (p:A->A))`
MP_TAC THENL [ALL_TAC; REWRITE_TAC[
SWAP_IDEMPOTENT;
I_O_ID]] THEN
REWRITE_TAC[GSYM
o_ASSOC] THEN MATCH_MP_TAC
PERMUTATION_COMPOSE THEN
REWRITE_TAC[
PERMUTATION_SWAP] THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
CONJ_TAC THENL
[UNDISCH_TAC `!y. ?!x. (p:A->A) x = y` THEN
REWRITE_TAC[
EXISTS_UNIQUE_THM; swap;
o_THM] THEN
ASM_CASES_TAC `(p:A->A) a = a` THEN ASM_REWRITE_TAC[] THENL
[ASM_MESON_TAC[]; ALL_TAC] THEN
REWRITE_TAC[TAUT
`(if p then x else y) = a <=> if p then x = a else y = a`] THEN
REWRITE_TAC[TAUT `(if p then x else y) <=> p /\ x \/ ~p /\ y`] THEN
ASM_MESON_TAC[];
REWRITE_TAC[swap;
o_THM] THEN
ASM_CASES_TAC `(p:A->A) a = a` THEN ASM_REWRITE_TAC[] THEN
ASM_MESON_TAC[]]);;
let PERMUTATION_COMPOSE_EQ = prove
(`(!p q:A->A. permutation(p) ==> (permutation(p o q) <=> permutation q)) /\
(!p q:A->A. permutation(q) ==> (permutation(p o q) <=> permutation p))`,
(* ------------------------------------------------------------------------- *)
(* Relation to "permutes". *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Hence a sort of induction principle composing by swaps. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Sign of a permutation as a real number. *)
(* ------------------------------------------------------------------------- *)
let SIGN_NZ = prove
(`!p. ~(sign p = &0)`,
REWRITE_TAC[sign] THEN REAL_ARITH_TAC);;
let SIGN_COMPOSE = prove
(`!p q. permutation p /\ permutation q ==> sign(p o q) = sign(p) * sign(q)`,
let SIGN_IDEMPOTENT = prove
(`!p. sign(p) * sign(p) = &1`,
GEN_TAC THEN REWRITE_TAC[sign] THEN
COND_CASES_TAC THEN ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV);;
(* ------------------------------------------------------------------------- *)
(* More lemmas about permutations. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Conversion for `{p | p permutes s}` where s is a set enumeration. *)
(* ------------------------------------------------------------------------- *)
let PERMSET_CONV =
(* ------------------------------------------------------------------------- *)
(* Sum over a set of permutations (could generalize to iteration). *)
(* ------------------------------------------------------------------------- *)