wenzelm@11054: (* Title: HOL/Library/Permutation.thy paulson@15005: Author: Lawrence C Paulson and Thomas M Rasmussen and Norbert Voelker wenzelm@11054: *) wenzelm@11054: wenzelm@14706: header {* Permutations *} wenzelm@11054: nipkow@15131: theory Permutation wenzelm@51542: imports Multiset nipkow@15131: begin wenzelm@11054: wenzelm@53238: inductive perm :: "'a list \ 'a list \ bool" ("_ <~~> _" [50, 50] 50) (* FIXME proper infix, without ambiguity!? *) wenzelm@53238: where wenzelm@53238: Nil [intro!]: "[] <~~> []" wenzelm@53238: | swap [intro!]: "y # x # l <~~> x # y # l" wenzelm@53238: | Cons [intro!]: "xs <~~> ys \ z # xs <~~> z # ys" wenzelm@53238: | trans [intro]: "xs <~~> ys \ ys <~~> zs \ xs <~~> zs" wenzelm@11054: wenzelm@11054: lemma perm_refl [iff]: "l <~~> l" wenzelm@17200: by (induct l) auto wenzelm@11054: wenzelm@11054: wenzelm@11054: subsection {* Some examples of rule induction on permutations *} wenzelm@11054: wenzelm@53238: lemma xperm_empty_imp: "[] <~~> ys \ ys = []" wenzelm@56796: by (induct xs == "[] :: 'a list" ys pred: perm) simp_all wenzelm@11054: wenzelm@11054: wenzelm@56796: text {* \medskip This more general theorem is easier to understand! *} wenzelm@11054: wenzelm@53238: lemma perm_length: "xs <~~> ys \ length xs = length ys" wenzelm@25379: by (induct pred: perm) simp_all wenzelm@11054: wenzelm@53238: lemma perm_empty_imp: "[] <~~> xs \ xs = []" wenzelm@17200: by (drule perm_length) auto wenzelm@11054: wenzelm@53238: lemma perm_sym: "xs <~~> ys \ ys <~~> xs" wenzelm@25379: by (induct pred: perm) auto wenzelm@11054: wenzelm@11054: wenzelm@11054: subsection {* Ways of making new permutations *} wenzelm@11054: wenzelm@56796: text {* We can insert the head anywhere in the list. *} wenzelm@11054: wenzelm@11054: lemma perm_append_Cons: "a # xs @ ys <~~> xs @ a # ys" wenzelm@17200: by (induct xs) auto wenzelm@11054: wenzelm@11054: lemma perm_append_swap: "xs @ ys <~~> ys @ xs" wenzelm@17200: apply (induct xs) wenzelm@17200: apply simp_all wenzelm@11054: apply (blast intro: perm_append_Cons) wenzelm@11054: done wenzelm@11054: wenzelm@11054: lemma perm_append_single: "a # xs <~~> xs @ [a]" wenzelm@17200: by (rule perm.trans [OF _ perm_append_swap]) simp wenzelm@11054: wenzelm@11054: lemma perm_rev: "rev xs <~~> xs" wenzelm@17200: apply (induct xs) wenzelm@17200: apply simp_all paulson@11153: apply (blast intro!: perm_append_single intro: perm_sym) wenzelm@11054: done wenzelm@11054: wenzelm@53238: lemma perm_append1: "xs <~~> ys \ l @ xs <~~> l @ ys" wenzelm@17200: by (induct l) auto wenzelm@11054: wenzelm@53238: lemma perm_append2: "xs <~~> ys \ xs @ l <~~> ys @ l" wenzelm@17200: by (blast intro!: perm_append_swap perm_append1) wenzelm@11054: wenzelm@11054: wenzelm@11054: subsection {* Further results *} wenzelm@11054: wenzelm@56796: lemma perm_empty [iff]: "[] <~~> xs \ xs = []" wenzelm@17200: by (blast intro: perm_empty_imp) wenzelm@11054: wenzelm@56796: lemma perm_empty2 [iff]: "xs <~~> [] \ xs = []" wenzelm@11054: apply auto wenzelm@11054: apply (erule perm_sym [THEN perm_empty_imp]) wenzelm@11054: done wenzelm@11054: wenzelm@53238: lemma perm_sing_imp: "ys <~~> xs \ xs = [y] \ ys = [y]" wenzelm@25379: by (induct pred: perm) auto wenzelm@11054: wenzelm@56796: lemma perm_sing_eq [iff]: "ys <~~> [y] \ ys = [y]" wenzelm@17200: by (blast intro: perm_sing_imp) wenzelm@11054: wenzelm@56796: lemma perm_sing_eq2 [iff]: "[y] <~~> ys \ ys = [y]" wenzelm@17200: by (blast dest: perm_sym) wenzelm@11054: wenzelm@11054: wenzelm@11054: subsection {* Removing elements *} wenzelm@11054: wenzelm@53238: lemma perm_remove: "x \ set ys \ ys <~~> x # remove1 x ys" wenzelm@17200: by (induct ys) auto wenzelm@11054: wenzelm@11054: wenzelm@11054: text {* \medskip Congruence rule *} wenzelm@11054: wenzelm@53238: lemma perm_remove_perm: "xs <~~> ys \ remove1 z xs <~~> remove1 z ys" wenzelm@25379: by (induct pred: perm) auto wenzelm@11054: nipkow@36903: lemma remove_hd [simp]: "remove1 z (z # xs) = xs" paulson@15072: by auto wenzelm@11054: wenzelm@53238: lemma cons_perm_imp_perm: "z # xs <~~> z # ys \ xs <~~> ys" wenzelm@17200: by (drule_tac z = z in perm_remove_perm) auto wenzelm@11054: wenzelm@56796: lemma cons_perm_eq [iff]: "z#xs <~~> z#ys \ xs <~~> ys" wenzelm@17200: by (blast intro: cons_perm_imp_perm) wenzelm@11054: wenzelm@53238: lemma append_perm_imp_perm: "zs @ xs <~~> zs @ ys \ xs <~~> ys" wenzelm@53238: by (induct zs arbitrary: xs ys rule: rev_induct) auto wenzelm@11054: wenzelm@56796: lemma perm_append1_eq [iff]: "zs @ xs <~~> zs @ ys \ xs <~~> ys" wenzelm@17200: by (blast intro: append_perm_imp_perm perm_append1) wenzelm@11054: wenzelm@56796: lemma perm_append2_eq [iff]: "xs @ zs <~~> ys @ zs \ xs <~~> ys" wenzelm@11054: apply (safe intro!: perm_append2) wenzelm@11054: apply (rule append_perm_imp_perm) wenzelm@11054: apply (rule perm_append_swap [THEN perm.trans]) wenzelm@11054: -- {* the previous step helps this @{text blast} call succeed quickly *} wenzelm@11054: apply (blast intro: perm_append_swap) wenzelm@11054: done wenzelm@11054: wenzelm@56796: lemma multiset_of_eq_perm: "multiset_of xs = multiset_of ys \ xs <~~> ys" wenzelm@17200: apply (rule iffI) wenzelm@56796: apply (erule_tac [2] perm.induct) wenzelm@56796: apply (simp_all add: union_ac) wenzelm@56796: apply (erule rev_mp) wenzelm@56796: apply (rule_tac x=ys in spec) wenzelm@56796: apply (induct_tac xs) wenzelm@56796: apply auto wenzelm@56796: apply (erule_tac x = "remove1 a x" in allE) wenzelm@56796: apply (drule sym) wenzelm@56796: apply simp wenzelm@17200: apply (subgoal_tac "a \ set x") wenzelm@53238: apply (drule_tac z = a in perm.Cons) wenzelm@56796: apply (erule perm.trans) wenzelm@56796: apply (rule perm_sym) wenzelm@56796: apply (erule perm_remove) wenzelm@56796: apply (drule_tac f=set_of in arg_cong) wenzelm@56796: apply simp paulson@15005: done paulson@15005: wenzelm@53238: lemma multiset_of_le_perm_append: "multiset_of xs \ multiset_of ys \ (\zs. xs @ zs <~~> ys)" wenzelm@17200: apply (auto simp: multiset_of_eq_perm[THEN sym] mset_le_exists_conv) wenzelm@56796: apply (insert surj_multiset_of) wenzelm@56796: apply (drule surjD) paulson@15072: apply (blast intro: sym)+ paulson@15072: done paulson@15005: wenzelm@53238: lemma perm_set_eq: "xs <~~> ys \ set xs = set ys" wenzelm@25379: by (metis multiset_of_eq_perm multiset_of_eq_setD) nipkow@25277: wenzelm@53238: lemma perm_distinct_iff: "xs <~~> ys \ distinct xs = distinct ys" wenzelm@25379: apply (induct pred: perm) wenzelm@25379: apply simp_all nipkow@44890: apply fastforce wenzelm@25379: apply (metis perm_set_eq) wenzelm@25379: done nipkow@25277: wenzelm@53238: lemma eq_set_perm_remdups: "set xs = set ys \ remdups xs <~~> remdups ys" wenzelm@25379: apply (induct xs arbitrary: ys rule: length_induct) wenzelm@53238: apply (case_tac "remdups xs") wenzelm@53238: apply simp_all wenzelm@53238: apply (subgoal_tac "a \ set (remdups ys)") blanchet@57816: prefer 2 apply (metis list.set(2) insert_iff set_remdups) wenzelm@56796: apply (drule split_list) apply (elim exE conjE) wenzelm@56796: apply (drule_tac x = list in spec) apply (erule impE) prefer 2 wenzelm@56796: apply (drule_tac x = "ysa @ zs" in spec) apply (erule impE) prefer 2 wenzelm@25379: apply simp wenzelm@53238: apply (subgoal_tac "a # list <~~> a # ysa @ zs") wenzelm@25379: apply (metis Cons_eq_appendI perm_append_Cons trans) haftmann@40122: apply (metis Cons Cons_eq_appendI distinct.simps(2) wenzelm@25379: distinct_remdups distinct_remdups_id perm_append_swap perm_distinct_iff) wenzelm@56796: apply (subgoal_tac "set (a # list) = wenzelm@56796: set (ysa @ a # zs) \ distinct (a # list) \ distinct (ysa @ a # zs)") nipkow@44890: apply (fastforce simp add: insert_ident) wenzelm@25379: apply (metis distinct_remdups set_remdups) haftmann@30742: apply (subgoal_tac "length (remdups xs) < Suc (length xs)") haftmann@30742: apply simp haftmann@30742: apply (subgoal_tac "length (remdups xs) \ length xs") haftmann@30742: apply simp haftmann@30742: apply (rule length_remdups_leq) wenzelm@25379: done nipkow@25287: wenzelm@56796: lemma perm_remdups_iff_eq_set: "remdups x <~~> remdups y \ set x = set y" wenzelm@25379: by (metis List.set_remdups perm_set_eq eq_set_perm_remdups) nipkow@25287: hoelzl@39075: lemma permutation_Ex_bij: hoelzl@39075: assumes "xs <~~> ys" hoelzl@39075: shows "\f. bij_betw f {.. (\ii Suc ` {.. Suc ` {..ii f"] conjI allI impI) hoelzl@39075: show "bij_betw (g \ f) {.. f) i" wenzelm@53238: using trans(1,3)[THEN perm_length] perm by auto hoelzl@39075: qed hoelzl@39075: qed hoelzl@39075: wenzelm@11054: end