(* Author: Amine Chaieb, University of Cambridge With various additions by Manuel Eberl *)
section‹Permutations, both general and specifically on finite sets.›
theory Permutations imports "HOL-Library.Multiset" "HOL-Library.Disjoint_Sets"
Transposition begin
subsection‹Auxiliary›
abbreviation (input) fixpoints :: ‹('a ==> 'a) ==> 'a set› where‹fixpoints f ≡ {x. f x = x}›
lemma inj_on_fixpoints: ‹inj_on f (fixpoints f)› by (rule inj_onI) simp
lemma bij_betw_fixpoints: ‹bij_betw f (fixpoints f) (fixpoints f)› using inj_on_fixpoints by (auto simp add: bij_betw_def)
subsection‹Basic definition and consequences›
definition permutes :: ‹('a ==> 'a) ==> 'a set ==> bool› (infixr‹permutes› 41) where‹p permutes S ⟷ (∀x. x ∉ S ⟶ p x = x) ∧ (∀y. ∃!x. p x = y)›
lemma bij_imp_permutes: ‹p permutes S›if‹bij_betw p S S›and stable: ‹∧x. x ∉ S ==> p x = x› proof - note‹bij_betw p S S› moreoverhave‹bij_betw p (- S) (- S)› by (auto simp add: stable intro!: bij_betw_imageI inj_onI) ultimatelyhave‹bij_betw p (S ∪ - S) (S ∪ - S)› by (rule bij_betw_combine) simp thenhave‹∃!x. p x = y›for y by (simp add: bij_iff) with stable show ?thesis by (simp add: permutes_def) qed
lemma inj_imp_permutes: assumes i: "inj_on f S"and fin: "finite S" and fS: "∧x. x ∈ S ==> f x ∈ S" and f: "∧i. i ∉ S ==> f i = i" shows"f permutes S" unfolding permutes_def proof (intro conjI allI impI, rule f) fix y from endo_inj_surj[OF fin _ i] fS have fs: "f ` S = S"by auto show"∃!x. f x = y" proof (cases "y ∈ S") case False thus ?thesis by (intro ex1I[of _ y], insert fS f) force+ next case True with fs obtain x where x: "x ∈ S"and fx: "f x = y"by force show ?thesis proof (rule ex1I, rule fx) fix x' assume fx': "f x' = y" with True f[of x'] have"x' ∈ S"by metis from inj_onD[OF i fx[folded fx'] x this] show"x' = x"by simp qed qed qed
context fixes p :: ‹'a ==> 'a›and S :: ‹'a set› assumes perm: ‹p permutes S› begin
lemma permutes_inj: ‹inj p› using perm by (auto simp: permutes_def inj_on_def)
lemma permutes_image: ‹p ` S = S› proof (rule set_eqI) fix x show‹x ∈ p ` S ⟷ x ∈ S› proof assume‹x ∈ p ` S› thenobtain y where‹y ∈ S›‹p y = x› by blast with perm show‹x ∈ S› by (cases ‹y = x›) (auto simp add: permutes_def) next assume‹x ∈ S› with perm obtain y where‹y ∈ S›‹p y = x› by (metis permutes_def) thenshow‹x ∈ p ` S› by blast qed qed
lemma permutes_not_in: ‹x ∉ S ==> p x = x› using perm by (auto simp: permutes_def)
lemma permutes_in_image: ‹p x ∈ S ⟷ x ∈ S› using permutes_image permutes_inj by (auto dest: inj_image_mem_iff)
lemma permutes_surj: ‹surj p› proof - have‹p ` (S ∪ - S) = p ` S ∪ p ` (- S)› by (rule image_Un) thenshow ?thesis by (simp add: permutes_image permutes_image_complement) qed
lemma permutes_inv_o: shows"p ∘ inv p = id" and"inv p ∘ p = id" using permutes_inj permutes_surj unfolding inj_iff [symmetric] surj_iff [symmetric] by auto
lemma permutes_inverses: shows"p (inv p x) = x" and"inv p (p x) = x" using permutes_inv_o [unfolded fun_eq_iff o_def] by auto
lemma permutes_inv_eq: ‹inv p y = x ⟷ p x = y› by (auto simp add: permutes_inverses)
lemma permutes_inj_on: ‹inj_on p A› by (rule inj_on_subset [of _ UNIV]) (auto intro: permutes_inj)
lemma permutes_bij: ‹bij p› unfolding bij_def by (metis permutes_inj permutes_surj)
lemma permutes_imp_bij: ‹bij_betw p S S› by (simp add: bij_betw_def permutes_image permutes_inj_on)
lemma permutes_subset: ‹p permutes T›if‹S ⊆ T› proof (rule bij_imp_permutes)
define R where‹R = T - S› with that have‹T = R ∪ S›‹R ∩ S = {}› by auto thenhave‹p x = x›if‹x ∈ R›for x using that by (auto intro: permutes_not_in) thenhave‹p ` R = R› by simp with‹T = R ∪ S›show‹bij_betw p T T› by (simp add: bij_betw_def permutes_inj_on image_Un permutes_image) fix x assume‹x ∉ T› with‹T = R ∪ S›show‹p x = x› by (simp add: permutes_not_in) qed
lemma permutes_imp_permutes_insert: ‹p permutes insert x S› by (rule permutes_subset) auto
end
lemma permutes_id [simp]: ‹id permutes S› by (auto intro: bij_imp_permutes)
lemma permutes_empty [simp]: ‹p permutes {} ⟷ p = id› proof assume‹p permutes {}› thenshow‹p = id› by (auto simp add: fun_eq_iff permutes_not_in) next assume‹p = id› thenshow‹p permutes {}› by simp qed
lemma permutes_sing [simp]: ‹p permutes {a} ⟷ p = id› proof assume perm: ‹p permutes {a}› show‹p = id› proof fix x from perm have‹p ` {a} = {a}› by (rule permutes_image) with perm show‹p x = id x› by (cases ‹x = a›) (auto simp add: permutes_not_in) qed next assume‹p = id› thenshow‹p permutes {a}› by simp qed
lemma permutes_univ: "p permutes UNIV ⟷ (∀y. ∃!x. p x = y)" by (simp add: permutes_def)
lemma permutes_swap_id: "a ∈ S ==> b ∈ S ==> transpose a b permutes S" by (rule bij_imp_permutes) (auto intro: transpose_apply_other)
lemma permutes_altdef: "p permutes A ⟷ bij_betw p A A ∧ {x. p x ≠ x} ⊆ A" using permutes_not_in[of p A] by (auto simp: permutes_imp_bij intro!: bij_imp_permutes)
lemma permutes_superset: ‹p permutes T›if‹p permutes S›‹∧x. x ∈ S - T ==> p x = x› proof -
define R U where‹R = T ∩ S›and‹U = S - T› thenhave‹T = R ∪ (T - S)›‹S = R ∪ U›‹R ∩ U = {}› by auto from that ‹U = S - T›have‹p ` U = U› by simp from‹p permutes S›have‹bij_betw p (R ∪ U) (R ∪ U)› by (simp add: permutes_imp_bij ‹S = R ∪ U›) moreoverhave‹bij_betw p U U› using that ‹U = S - T›by (simp add: bij_betw_def permutes_inj_on) ultimatelyhave‹bij_betw p R R› using‹R ∩ U = {}›‹R ∩ U = {}›by (rule bij_betw_partition) thenhave‹p permutes R› proof (rule bij_imp_permutes) fix x assume‹x ∉ R› with‹R = T ∩ S›‹p permutes S›show‹p x = x› by (cases ‹x ∈ S›) (auto simp add: permutes_not_in that(2)) qed thenhave‹p permutes R ∪ (T - S)› by (rule permutes_subset) simp with‹T = R ∪ (T - S)›show ?thesis by simp qed
lemma permutes_bij_inv_into: 🍋‹contributor ‹Lukas Bulwahn›\› fixes A :: "'a set" and B :: "'b set" assumes"p permutes A" and"bij_betw f A B" shows"(λx. if x ∈ B then f (p (inv_into A f x)) else x) permutes B" proof (rule bij_imp_permutes) from assms have"bij_betw p A A""bij_betw f A B""bij_betw (inv_into A f) B A" by (auto simp add: permutes_imp_bij bij_betw_inv_into) thenhave"bij_betw (f ∘ p ∘ inv_into A f) B B" by (simp add: bij_betw_trans) thenshow"bij_betw (λx. if x ∈ B then f (p (inv_into A f x)) else x) B B" by (subst bij_betw_cong[where g="f ∘ p ∘ inv_into A f"]) auto next fix x assume"x ∉ B" thenshow"(if x ∈ B then f (p (inv_into A f x)) else x) = x"by auto qed
lemma permutes_image_mset: 🍋‹contributor ‹Lukas Bulwahn›\› assumes"p permutes A" shows"image_mset p (mset_set A) = mset_set A" using assms by (metis image_mset_mset_set bij_betw_imp_inj_on permutes_imp_bij permutes_image)
lemma permutes_implies_image_mset_eq: 🍋‹contributor ‹Lukas Bulwahn›\› assumes"p permutes A""∧x. x ∈ A ==> f x = f' (p x)" shows"image_mset f' (mset_set A) = image_mset f (mset_set A)" proof - have"f x = f' (p x)"if"x ∈# mset_set A"for x using assms(2)[of x] that by (cases "finite A") auto with assms have"image_mset f (mset_set A) = image_mset (f' ∘ p) (mset_set A)" by (auto intro!: image_mset_cong) alsohave"… = image_mset f' (image_mset p (mset_set A))" by (simp add: image_mset.compositionality) alsohave"… = image_mset f' (mset_set A)" proof - from assms permutes_image_mset have"image_mset p (mset_set A) = mset_set A" by blast thenshow ?thesis by simp qed finallyshow ?thesis .. qed
subsection‹Group properties›
lemma permutes_compose: "p permutes S ==> q permutes S ==> q ∘ p permutes S" unfolding permutes_def o_def by metis
lemma permutes_inv: assumes"p permutes S" shows"inv p permutes S" using assms unfolding permutes_def permutes_inv_eq[OF assms] by metis
lemma permutes_invI: assumes perm: "p permutes S" and inv: "∧x. x ∈ S ==> p' (p x) = x" and outside: "∧x. x ∉ S ==> p' x = x" shows"inv p = p'" proof show"inv p x = p' x"for x proof (cases "x ∈ S") case True from assms have"p' x = p' (p (inv p x))" by (simp add: permutes_inverses) alsofrom permutes_inv[OF perm] True have"… = inv p x" by (subst inv) (simp_all add: permutes_in_image) finallyshow ?thesis .. next case False with permutes_inv[OF perm] show ?thesis by (simp_all add: outside permutes_not_in) qed qed
lemma permutes_vimage: "f permutes A ==> f -` A = A" by (simp add: bij_vimage_eq_inv_image permutes_bij permutes_image[OF permutes_inv])
subsection‹Restricting a permutation to a subset›
definition restrict_id :: "('a ==> 'a) ==> 'a set ==> 'a ==> 'a" where"restrict_id f A = (λx. if x ∈ A then f x else x)"
lemma restrict_id_cong [cong]: assumes"∧x. x ∈ A ==> f x = g x""A = B" shows"restrict_id f A = restrict_id g B" using assms unfolding restrict_id_def by auto
lemma restrict_id_cong': assumes"x ∈ A ==> f x = g x""A = B" shows"restrict_id f A x = restrict_id g B x" using assms unfolding restrict_id_def by auto
lemma restrict_id_simps [simp]: "x ∈ A ==> restrict_id f A x = f x" "x ∉ A ==> restrict_id f A x = x" by (auto simp: restrict_id_def)
lemma bij_betw_restrict_id: assumes"bij_betw f A A""A ⊆ B" shows"bij_betw (restrict_id f A) B B" proof - have"bij_betw (restrict_id f A) (A ∪ (B - A)) (A ∪ (B - A))" unfolding restrict_id_def by (rule bij_betw_disjoint_Un) (use assms in‹auto intro: bij_betwI›) alsohave"A ∪ (B - A) = B" using assms(2) by blast finallyshow ?thesis . qed
lemma permutes_restrict_id: assumes"bij_betw f A A" shows"restrict_id f A permutes A" by (intro bij_imp_permutes bij_betw_restrict_id assms) auto
subsection‹Mapping a permutation›
definition map_permutation :: "'a set ==> ('a ==> 'b) ==> ('a ==> 'a) ==> 'b ==> 'b"where "map_permutation A f p = restrict_id (f ∘ p ∘ inv_into A f) (f ` A)"
lemma map_permutation_cong_strong: assumes"A = B""∧x. x ∈ A ==> f x = g x""∧x. x ∈ A ==> p x = q x" assumes"p ` A ⊆ A""inj_on f A" shows"map_permutation A f p = map_permutation B g q" proof - have fg: "f x = g y"if"x ∈ A""x = y"for x y using assms(2) that by simp have pq: "p x = q y"if"x ∈ A""x = y"for x y using assms(3) that by simp have p: "p x ∈ A"if"x ∈ A"for x using assms(4) that by blast have inv: "inv_into A f x = inv_into B g y"if"x ∈ f ` A""x = y"for x y proof - from that obtain u where u: "u ∈ A""x = f u" by blast have"inv_into A f (f u) = inv_into A g (f u)" using‹inj_on f A› u(1) by (metis assms(2) inj_on_cong inv_into_f_f) thus ?thesis using u ‹x = y›‹A = B›by simp qed
show ?thesis unfolding map_permutation_def o_def by (intro restrict_id_cong image_cong fg pq inv_into_into p inv) (auto simp: ‹A = B›) qed
lemma map_permutation_cong: assumes"inj_on f A""p permutes A" assumes"A = B""∧x. x ∈ A ==> f x = g x""∧x. x ∈ A ==> p x = q x" shows"map_permutation A f p = map_permutation B g q" proof (intro map_permutation_cong_strong assms) show"p ` A ⊆ A" using‹p permutes A›by (simp add: permutes_image) qed auto
lemma inv_into_id [simp]: "x ∈ A ==> inv_into A id x = x" by (metis f_inv_into_f id_apply image_eqI)
lemma inv_into_ident [simp]: "x ∈ A ==> inv_into A (λx. x) x = x" by (metis f_inv_into_f image_eqI)
lemma map_permutation_id [simp]: "p permutes A ==> map_permutation A id p = p" by (auto simp: fun_eq_iff map_permutation_def restrict_id_def permutes_not_in)
lemma map_permutation_ident [simp]: "p permutes A ==> map_permutation A (λx. x) p = p" by (auto simp: fun_eq_iff map_permutation_def restrict_id_def permutes_not_in)
lemma map_permutation_id': "inj_on f A ==> map_permutation A f id = id" unfolding map_permutation_def by (auto simp: restrict_id_def fun_eq_iff)
lemma map_permutation_ident': "inj_on f A ==> map_permutation A f (λx. x) = (λx. x)" unfolding map_permutation_def by (auto simp: restrict_id_def fun_eq_iff)
lemma map_permutation_permutes: assumes"bij_betw f A B""p permutes A" shows"map_permutation A f p permutes B" proof (rule bij_imp_permutes) have f_A: "f ` A = B" using assms(1) by (auto simp: bij_betw_def) from assms(2) have"bij_betw p A A" by (simp add: permutes_imp_bij) show"bij_betw (map_permutation A f p) B B" unfolding map_permutation_def f_A by (rule bij_betw_restrict_id bij_betw_trans bij_betw_inv_into assms(1)
permutes_imp_bij[OF assms(2)] order.refl)+ show"map_permutation A f p x = x"if"x ∉ B"for x using that unfolding map_permutation_def f_A by simp qed
lemma map_permutation_compose: fixes f :: "'a ==> 'b"and g :: "'b ==> 'c" assumes"bij_betw f A B""inj_on g B" shows"map_permutation B g (map_permutation A f p) = map_permutation A (g ∘ f) p" proof fix c :: 'c have bij_g: "bij_betw g B (g ` B)" using‹inj_on g B›unfolding bij_betw_def by blast have [simp]: "f x = f y ⟷ x = y"if"x ∈ A""y ∈ A"for x y using assms(1) that by (auto simp: bij_betw_def inj_on_def) have [simp]: "g x = g y ⟷ x = y"if"x ∈ B""y ∈ B"for x y using assms(2) that by (auto simp: bij_betw_def inj_on_def) show"map_permutation B g (map_permutation A f p) c = map_permutation A (g ∘ f) p c" proof (cases "c ∈ g ` B") case c: True thenobtain a where a: "a ∈ A""c = g (f a)" using assms(1,2) unfolding bij_betw_def by auto have"map_permutation B g (map_permutation A f p) c = g (f (p a))" using a assms by (auto simp: map_permutation_def restrict_id_def bij_betw_def) alsohave"… = map_permutation A (g ∘ f) p c" using a bij_betw_inv_into_left[OF bij_betw_trans[OF assms(1) bij_g]] by (auto simp: map_permutation_def restrict_id_def bij_betw_def) finallyshow ?thesis . next case c: False thus ?thesis using assms by (auto simp: map_permutation_def bij_betw_def restrict_id_def) qed qed
lemma map_permutation_compose_inv: assumes"bij_betw f A B""p permutes A""∧x. x ∈ A ==> g (f x) = x" shows"map_permutation B g (map_permutation A f p) = p" proof - have"inj_on g B" proof fix x y assume"x ∈ B""y ∈ B""g x = g y" thenobtain x' y' where *: "x' ∈ A""y' : A""x = f x'""y = f y'" using assms(1) unfolding bij_betw_def by blast thus"x = y" using assms(3)[of x'] assms(3)[of y'] ‹g x = g y›by simp qed
have"map_permutation B g (map_permutation A f p) = map_permutation A (g ∘ f) p" by (rule map_permutation_compose) (use assms ‹inj_on g B›in auto) alsohave"… = map_permutation A id p" by (intro map_permutation_cong assms comp_inj_on)
(use‹inj_on g B› assms(1,3) in‹auto simp: bij_betw_def›) alsohave"… = p" by (rule map_permutation_id) fact finallyshow ?thesis . qed
lemma map_permutation_apply: assumes"inj_on f A""x ∈ A" shows"map_permutation A f h (f x) = f (h x)" using assms by (auto simp: map_permutation_def inj_on_def)
lemma map_permutation_compose': fixes f :: "'a ==> 'b" assumes"inj_on f A""q permutes A" shows"map_permutation A f (p ∘ q) = map_permutation A f p ∘ map_permutation A f q" proof fix y :: 'b show"map_permutation A f (p ∘ q) y = (map_permutation A f p ∘ map_permutation A f q) y" proof (cases "y ∈ f ` A") case True thenobtain x where x: "x ∈ A""y = f x" by blast have"map_permutation A f (p ∘ q) y = f (p (q x))" unfolding x(2) by (subst map_permutation_apply) (use assms x in auto) alsohave"… = (map_permutation A f p ∘ map_permutation A f q) y" unfolding x o_apply using x(1) assms by (simp add: map_permutation_apply permutes_in_image) finallyshow ?thesis . next case False thus ?thesis using False by (simp add: map_permutation_def) qed qed
lemma map_permutation_transpose: assumes"inj_on f A""a ∈ A""b ∈ A" shows"map_permutation A f (Transposition.transpose a b) = Transposition.transpose (f a) (f b)" proof fix y :: 'b show"map_permutation A f (Transposition.transpose a b) y = Transposition.transpose (f a) (f b) y" proof (cases "y ∈ f ` A") case False hence"map_permutation A f (Transposition.transpose a b) y = y" unfolding map_permutation_def by (intro restrict_id_simps) moreoverhave"Transposition.transpose (f a) (f b) y = y" using False assms by (intro transpose_apply_other) auto ultimatelyshow ?thesis by simp next case True thenobtain x where x: "x ∈ A""y = f x" by blast have"map_permutation A f (Transposition.transpose a b) y = f (Transposition.transpose a b x)" unfolding x by (subst map_permutation_apply) (use x assms in auto) alsohave"… = Transposition.transpose (f a) (f b) y" using assms(2,3) x by (auto simp: Transposition.transpose_def inj_on_eq_iff[OF assms(1)]) finallyshow ?thesis . qed qed
lemma map_permutation_permutes_iff: assumes"bij_betw f A B""p ` A ⊆ A""∧x. x ∉ A ==> p x = x" shows"map_permutation A f p permutes B ⟷ p permutes A" proof assume"p permutes A" thus"map_permutation A f p permutes B" by (intro map_permutation_permutes assms) next assume *: "map_permutation A f p permutes B" hence"map_permutation B (inv_into A f) (map_permutation A f p) permutes A" by (rule map_permutation_permutes[OF bij_betw_inv_into[OF assms(1)]]) alsohave"map_permutation B (inv_into A f) (map_permutation A f p) = map_permutation A (inv_into A f ∘ f) p" by (rule map_permutation_compose[OF _ inj_on_inv_into])
(use assms in‹auto simp: bij_betw_def›) alsohave"… = map_permutation A id p" unfolding o_def id_def by (rule sym, intro map_permutation_cong_strong inv_into_f_f[symmetric]
assms(2) bij_betw_imp_inj_on[OF assms(1)]) auto alsohave"… = p" unfolding map_permutation_def using assms(3) by (auto simp: restrict_id_def fun_eq_iff split: if_splits) finallyshow"p permutes A" . qed
lemma bij_betw_permutations: assumes"bij_betw f A B" shows"bij_betw (λπ x. if x ∈ B then f (π (inv_into A f x)) else x) {π. π permutes A} {π. π permutes B}" (is"bij_betw ?f _ _") proof - let ?g = "(λπ x. if x ∈ A then inv_into A f (π (f x)) else x)" show ?thesis proof (rule bij_betw_byWitness [of _ ?g], goal_cases) case 3 show ?caseusing permutes_bij_inv_into[OF _ assms] by auto next case 4 have bij_inv: "bij_betw (inv_into A f) B A"by (intro bij_betw_inv_into assms)
{ fix π assume"π permutes B" from permutes_bij_inv_into[OF this bij_inv] and assms have"(λx. if x ∈ A then inv_into A f (π (f x)) else x) permutes A" by (simp add: inv_into_inv_into_eq cong: if_cong)
} from this show ?caseby (auto simp: permutes_inv) next case 1 thus ?caseusing assms by (auto simp: fun_eq_iff permutes_not_in permutes_in_image bij_betw_inv_into_left
dest: bij_betwE) next case 2 moreoverhave"bij_betw (inv_into A f) B A" by (intro bij_betw_inv_into assms) ultimatelyshow ?caseusing assms by (auto simp: fun_eq_iff permutes_not_in permutes_in_image bij_betw_inv_into_right
dest: bij_betwE) qed qed
lemma bij_betw_derangements: assumes"bij_betw f A B" shows"bij_betw (λπ x. if x ∈ B then f (π (inv_into A f x)) else x) {π. π permutes A ∧ (∀x∈A. π x ≠ x)} {π. π permutes B ∧ (∀x∈B. π x ≠ x)}"
(is"bij_betw ?f _ _") proof - let ?g = "(λπ x. if x ∈ A then inv_into A f (π (f x)) else x)" show ?thesis proof (rule bij_betw_byWitness [of _ ?g], goal_cases) case 3 have"?f π x ≠ x"if"π permutes A""∧x. x ∈ A ==> π x ≠ x""x ∈ B"for π x using that and assms by (metis bij_betwE bij_betw_imp_inj_on bij_betw_imp_surj_on
inv_into_f_f inv_into_into permutes_imp_bij) with permutes_bij_inv_into[OF _ assms] show ?caseby auto next case 4 have bij_inv: "bij_betw (inv_into A f) B A"by (intro bij_betw_inv_into assms) have"?g π permutes A"if"π permutes B"for π using permutes_bij_inv_into[OF that bij_inv] and assms by (simp add: inv_into_inv_into_eq cong: if_cong) moreoverhave"?g π x ≠ x"if"π permutes B""∧x. x ∈ B ==> π x ≠ x""x ∈ A"for π x using that and assms by (metis bij_betwE bij_betw_imp_surj_on f_inv_into_f permutes_imp_bij) ultimatelyshow ?caseby auto next case 1 thus ?caseusing assms by (force simp: fun_eq_iff permutes_not_in permutes_in_image bij_betw_inv_into_left
dest: bij_betwE) next case 2 moreoverhave"bij_betw (inv_into A f) B A" by (intro bij_betw_inv_into assms) ultimatelyshow ?caseusing assms by (force simp: fun_eq_iff permutes_not_in permutes_in_image bij_betw_inv_into_right
dest: bij_betwE) qed qed
subsection‹The number of permutations on a finite set›
lemma permutes_insert_lemma: assumes"p permutes (insert a S)" shows"transpose a (p a) ∘ p permutes S" proof (rule permutes_superset[where S = "insert a S"]) show"Transposition.transpose a (p a) ∘ p permutes insert a S" by (meson assms insertI1 permutes_compose permutes_in_image permutes_swap_id) qed auto
lemma permutes_insert: "{p. p permutes (insert a S)} = (λ(b, p). transpose a b ∘ p) ` {(b, p). b ∈ insert a S ∧ p ∈ {p. p permutes S}}" proof - have"p permutes insert a S ⟷ (∃b q. p = transpose a b ∘ q ∧ b ∈ insert a S ∧ q permutes S)"for p proof - have"∃b q. p = transpose a b ∘ q ∧ b ∈ insert a S ∧ q permutes S" if p: "p permutes insert a S" proof - let ?b = "p a" let ?q = "transpose a (p a) ∘ p" have *: "p = transpose a ?b ∘ ?q" by (simp add: fun_eq_iff o_assoc) have **: "?b ∈ insert a S" unfolding permutes_in_image[OF p] by simp from permutes_insert_lemma[OF p] * ** show ?thesis by blast qed moreoverhave"p permutes insert a S" if bq: "p = transpose a b ∘ q""b ∈ insert a S""q permutes S"for b q proof - from permutes_subset[OF bq(3), of "insert a S"] have q: "q permutes insert a S" by auto have a: "a ∈ insert a S" by simp from bq(1) permutes_compose[OF q permutes_swap_id[OF a bq(2)]] show ?thesis by simp qed ultimatelyshow ?thesis by blast qed thenshow ?thesis by auto qed
lemma card_permutations: assumes"card S = n" and"finite S" shows"card {p. p permutes S} = fact n" using assms(2,1) proof (induct arbitrary: n) case empty thenshow ?caseby simp next case (insert x F)
{ fix n assume card_insert: "card (insert x F) = n" let ?xF = "{p. p permutes insert x F}" let ?pF = "{p. p permutes F}" let ?pF' = "{(b, p). b ∈ insert x F ∧ p ∈ ?pF}" let ?g = "(λ(b, p). transpose x b ∘ p)" have xfgpF': "?xF = ?g ` ?pF'" by (rule permutes_insert[of x F]) from‹x ∉ F›‹finite F› card_insert have Fs: "card F = n - 1" by auto from‹finite F› insert.hyps Fs have pFs: "card ?pF = fact (n - 1)" by auto thenhave"finite ?pF" by (auto intro: card_ge_0_finite) with‹finite F› card.insert_remove have pF'f: "finite ?pF'" by simp have ginj: "inj_on ?g ?pF'" proof -
{ fix b p c q assume bp: "(b, p) ∈ ?pF'" assume cq: "(c, q) ∈ ?pF'" assume eq: "?g (b, p) = ?g (c, q)" from bp cq have pF: "p permutes F"and qF: "q permutes F" by auto from pF ‹x ∉ F› eq have"b = ?g (b, p) x" by (auto simp: permutes_def fun_upd_def fun_eq_iff) alsofrom qF ‹x ∉ F› eq have"… = ?g (c, q) x" by (auto simp: fun_upd_def fun_eq_iff) alsofrom qF ‹x ∉ F›have"… = c" by (auto simp: permutes_def fun_upd_def fun_eq_iff) finallyhave"b = c" . thenhave"transpose x b = transpose x c" by simp with eq have"transpose x b ∘ p = transpose x b ∘ q" by simp thenhave"transpose x b ∘ (transpose x b ∘ p) = transpose x b ∘ (transpose x b ∘q)" by simp thenhave"p = q" by (simp add: o_assoc) with‹b = c›have"(b, p) = (c, q)" by simp
} thenshow ?thesis unfolding inj_on_def by blast qed from‹x ∉ F›‹finite F› card_insert have"n ≠ 0" by auto thenhave"∃m. n = Suc m" by presburger thenobtain m where n: "n = Suc m" by blast from pFs card_insert have *: "card ?xF = fact n" unfolding xfgpF' card_image[OF ginj] using‹finite F›‹finite ?pF› by (simp only: Collect_case_prod Collect_mem_eq card_cartesian_product) (simp add: n) from finite_imageI[OF pF'f, of ?g] have xFf: "finite ?xF" by (simp add: xfgpF' n) from * have"card ?xF = fact n" unfolding xFf by blast
} with insert show ?caseby simp qed
lemma finite_permutations: assumes"finite S" shows"finite {p. p permutes S}" using card_permutations[OF refl assms] by (auto intro: card_ge_0_finite)
lemma permutes_doubleton_iff: "f permutes {a, b} ⟷ f = id ∨ f = Transposition.transpose a b" proof (cases "a = b") case False have"{id, Transposition.transpose a b} ⊆ {f. f permutes {a, b}}" by (auto simp: permutes_id permutes_swap_id) moreoverhave"id ≠ Transposition.transpose a b" using False by (auto simp: fun_eq_iff Transposition.transpose_def) hence"card {id, Transposition.transpose a b} = card {f. f permutes {a, b}}" using False by (simp add: card_permutations) ultimatelyhave"{id, Transposition.transpose a b} = {f. f permutes {a, b}}" by (intro card_subset_eq finite_permutations) auto thus ?thesis by auto qed auto
subsection‹Permutations of index set for iterated operations›
lemma (in comm_monoid_set) permute: assumes"p permutes S" shows"F g S = F (g ∘ p) S" proof - from‹p permutes S›have"inj p" by (rule permutes_inj) thenhave"inj_on p S" by (auto intro: inj_on_subset) thenhave"F g (p ` S) = F (g ∘ p) S" by (rule reindex) moreoverfrom‹p permutes S›have"p ` S = S" by (rule permutes_image) ultimatelyshow ?thesis by simp qed
subsection‹Permutations as transposition sequences›
inductive swapidseq :: "nat ==> ('a ==> 'a) ==> bool" where
id[simp]: "swapidseq 0 id"
| comp_Suc: "swapidseq n p ==> a ≠ b ==> swapidseq (Suc n) (transpose a b ∘ p)"
declare id[unfolded id_def, simp]
definition"permutation p ⟷ (∃n. swapidseq n p)"
subsection‹Some closure properties of the set of permutations, with lengths›
lemma swapidseq_swap: "swapidseq (if a = b then 0 else 1) (transpose a b)" using swapidseq.simps by fastforce
lemma permutation_swap_id: "permutation (transpose a b)" by (meson permutation_def swapidseq_swap)
lemma swapidseq_comp_add: "swapidseq n p ==> swapidseq m q ==> swapidseq (n + m) (p ∘ q)" proof (induct n p arbitrary: m q rule: swapidseq.induct) case (id m q) thenshow ?caseby simp next case (comp_Suc n p a b m q) thenshow ?case by (metis add_Suc comp_assoc swapidseq.comp_Suc) qed
lemma permutation_compose: "permutation p ==> permutation q ==> permutation (p ∘ q)" unfolding permutation_def using swapidseq_comp_add[of _ p _ q] by metis
lemma swapidseq_endswap: "swapidseq n p ==> a ≠ b ==> swapidseq (Suc n) (p ∘ transpose a b)" by (induct n p rule: swapidseq.induct)
(use swapidseq_swap[of a b] in‹auto simp add: comp_assoc intro: swapidseq.comp_Suc›)
lemma swapidseq_inverse_exists: "swapidseq n p ==>∃q. swapidseq n q ∧ p ∘ q = id ∧ q ∘ p = id" proof (induct n p rule: swapidseq.induct) case id thenshow ?case by (rule exI[where x=id]) simp next case (comp_Suc n p a b) from comp_Suc.hyps obtain q where q: "swapidseq n q""p ∘ q = id""q ∘ p = id" by blast let ?q = "q ∘ transpose a b" note H = comp_Suc.hyps from swapidseq_swap[of a b] H(3) have *: "swapidseq 1 (transpose a b)" by simp from swapidseq_comp_add[OF q(1) *] have **: "swapidseq (Suc n) ?q" by simp have"transpose a b ∘ p ∘ ?q = transpose a b ∘ (p ∘ q) ∘ transpose a b" by (simp add: o_assoc) alsohave"… = id" by (simp add: q(2)) finallyhave ***: "transpose a b ∘ p ∘ ?q = id" . have"?q ∘ (transpose a b ∘ p) = q ∘ (transpose a b ∘ transpose a b) ∘ p" by (simp only: o_assoc) thenhave"?q ∘ (transpose a b ∘ p) = id" by (simp add: q(3)) with ** *** show ?case by blast qed
lemma swapidseq_inverse: assumes"swapidseq n p" shows"swapidseq n (inv p)" using swapidseq_inverse_exists[OF assms] inv_unique_comp[of p] by auto
lemma permutation_inverse: "permutation p ==> permutation (inv p)" using permutation_def swapidseq_inverse by blast
subsection‹Various combinations of transpositions with 2, 1 and 0 common elements›
lemma swap_id_common:" a ≠ c ==> b ≠ c ==> transpose a b ∘ transpose a c = transpose b c ∘ transpose a b" by (simp add: fun_eq_iff transpose_def)
lemma swap_id_common': "a ≠ b ==> a ≠ c ==> transpose a c ∘ transpose b c = transpose b c ∘ transpose a b" by (simp add: fun_eq_iff transpose_def)
lemma swap_id_independent: "a ≠ c ==> a ≠ d ==> b ≠ c ==> b ≠ d ==> transpose a b ∘ transpose c d = transpose c d ∘ transpose a b" by (simp add: fun_eq_iff transpose_def)
subsection‹The identity map only has even transposition sequences›
lemma symmetry_lemma: assumes"∧a b c d. P a b c d ==> P a b d c" and"∧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" shows"∧a b c d. a ≠ b ⟶ c ≠ d ⟶ P a b c d" using assms by metis
lemma swap_general: assumes"a ≠ b""c ≠ d" shows"transpose a b ∘ transpose c d = id ∨ (∃x y z. x ≠ a ∧ y ≠ a ∧ z ≠ a ∧ x ≠ y ∧ transpose a b ∘ transpose c d = transpose x y ∘ transpose a z)" by (metis assms swap_id_common' swap_id_independent transpose_commute transpose_comp_involutory)
lemma swapidseq_id_iff[simp]: "swapidseq 0 p ⟷ p = id" using swapidseq.cases[of 0 p "p = id"] by auto
lemma swapidseq_cases: "swapidseq n p ⟷ n = 0 ∧ p = id ∨ (∃a b q m. n = Suc m ∧ p = transpose a b ∘ q ∧ swapidseq m q ∧a ≠ b)" by (meson comp_Suc id swapidseq.cases)
lemma fixing_swapidseq_decrease: assumes"swapidseq n p" and"a ≠ b" and"(transpose a b ∘ p) a = a" shows"n ≠ 0 ∧ swapidseq (n - 1) (transpose a b ∘ p)" using assms proof (induct n arbitrary: p a b) case 0 thenshow ?case by (auto simp add: fun_upd_def) next case (Suc n p a b) from Suc.prems(1) swapidseq_cases[of "Suc n" p] obtain c d q m where
cdqm: "Suc n = Suc m""p = transpose c d ∘ q""swapidseq m q""c ≠ d""n = m" by auto
consider "transpose a b ∘ transpose c d = id"
| x y z where"x ≠ a""y ≠ a""z ≠ a""x ≠ y" "transpose a b ∘ transpose c d = transpose x y ∘ transpose a z" using swap_general[OF Suc.prems(2) cdqm(4)] by metis thenshow ?case proof cases case 1 thenshow ?thesis by (simp only: cdqm o_assoc) (simp add: cdqm) next case 2 thenhave az: "a ≠ z" by simp from 2 have *: "(transpose x y ∘ h) a = a ⟷ h a = a"for h by (simp add: transpose_def) from cdqm(2) have"transpose a b ∘ p = transpose a b ∘ (transpose c d ∘ q)" by simp thenhave🍋: "transpose a b ∘ p = transpose x y ∘ (transpose a z ∘ q)" by (simp add: o_assoc 2) obtain **: "swapidseq (n - 1) (transpose a z ∘ q)"and"n≠0" by (metis "*""🍋" Suc.hyps Suc.prems(3) az cdqm(3,5)) thenhave"Suc n - 1 = Suc (n - 1)" by auto with 2 show ?thesis using"**"🍋 swapidseq.simps by blast qed qed
lemma swapidseq_identity_even: assumes"swapidseq n (id :: 'a ==> 'a)" shows"even n" using‹swapidseq n id› proof (induct n rule: nat_less_induct) case H: (1 n)
consider "n = 0"
| a b :: 'a and q m where"n = Suc m""id = transpose a b ∘ q""swapidseq m q""a ≠ b" using H(2)[unfolded swapidseq_cases[of n id]] by auto thenshow ?case proof cases case 1 thenshow ?thesis by presburger next case h: 2 from fixing_swapidseq_decrease[OF h(3,4), unfolded h(2)[symmetric]] have m: "m ≠ 0""swapidseq (m - 1) (id :: 'a ==> 'a)" by auto from h m have mn: "m - 1 < n" by arith from H(1)[rule_format, OF mn m(2)] h(1) m(1) show ?thesis by presburger qed qed
subsection‹Therefore we have a welldefined notion of parity›
definition"evenperm p = even (SOME n. swapidseq n p)"
lemma swapidseq_even_even: assumes m: "swapidseq m p" and n: "swapidseq n p" shows"even m ⟷ even n" proof - from swapidseq_inverse_exists[OF n] obtain q where q: "swapidseq n q""p ∘ q = id""q ∘ p = id" by blast from swapidseq_identity_even[OF swapidseq_comp_add[OF m q(1), unfolded q]] show ?thesis by arith qed
lemma evenperm_unique: assumes"swapidseq n p"and"even n = b" shows"evenperm p = b" by (metis evenperm_def assms someI swapidseq_even_even)
subsection‹And it has the expected composition properties›
lemma evenperm_id[simp]: "evenperm id = True" by (rule evenperm_unique[where n = 0]) simp_all
lemma evenperm_identity [simp]: ‹evenperm (λx. x)› using evenperm_id by (simp add: id_def [abs_def])
lemma evenperm_swap: "evenperm (transpose a b) = (a = b)" by (rule evenperm_unique[where n="if a = b then 0 else 1"]) (simp_all add: swapidseq_swap)
lemma evenperm_comp: assumes"permutation p""permutation q" shows"evenperm (p ∘ q) ⟷ evenperm p = evenperm q" proof - from assms obtain n m where n: "swapidseq n p"and m: "swapidseq m q" unfolding permutation_def by blast have"even (n + m) ⟷ (even n ⟷ even m)" by arith from evenperm_unique[OF n refl] evenperm_unique[OF m refl] and evenperm_unique[OF swapidseq_comp_add[OF n m] this] show ?thesis by blast qed
lemma evenperm_inv: assumes"permutation p" shows"evenperm (inv p) = evenperm p" proof - from assms obtain n where n: "swapidseq n p" unfolding permutation_def by blast show ?thesis by (rule evenperm_unique[OF swapidseq_inverse[OF n] evenperm_unique[OF n refl, symmetric]]) qed
subsection‹A more abstract characterization of permutations›
lemma permutation_finite_support: assumes"permutation p" shows"finite {x. p x ≠ x}" proof - from assms obtain n where"swapidseq n p" unfolding permutation_def by blast thenshow ?thesis proof (induct n p rule: swapidseq.induct) case id thenshow ?caseby simp next case (comp_Suc n p a b) let ?S = "insert a (insert b {x. p x ≠ x})" from comp_Suc.hyps(2) have *: "finite ?S" by simp from‹a ≠ b›have **: "{x. (transpose a b ∘ p) x ≠ x} ⊆ ?S" by auto show ?case by (rule finite_subset[OF ** *]) qed qed
lemma permutation_lemma: assumes"finite S" and"bij p" and"∀x. x ∉ S ⟶ p x = x" shows"permutation p" using assms proof (induct S arbitrary: p rule: finite_induct) case empty thenshow ?case by simp next case (insert a F p) let ?r = "transpose a (p a) ∘ p" let ?q = "transpose a (p a) ∘ ?r" have *: "?r a = a" by simp from insert * have **: "∀x. x ∉ F ⟶ ?r x = x" by (metis bij_pointE comp_apply id_apply insert_iff swap_apply(3)) have"bij ?r" using insert by (simp add: bij_comp) have"permutation ?r" by (rule insert(3)[OF ‹bij ?r› **]) thenhave"permutation ?q" by (simp add: permutation_compose permutation_swap_id) thenshow ?case by (simp add: o_assoc) qed
lemma permutation: "permutation p ⟷ bij p ∧ finite {x. p x ≠ x}" using permutation_bijective permutation_finite_support permutation_lemma by auto
lemma permutation_inverse_works: assumes"permutation p" shows"inv p ∘ p = id" and"p ∘ inv p = id" using permutation_bijective [OF assms] by (auto simp: bij_def inj_iff surj_iff)
lemma permutation_inverse_compose: assumes p: "permutation p" and q: "permutation q" shows"inv (p ∘ q) = inv q ∘ inv p" by (simp add: o_inv_distrib p permutation_bijective q)
subsection‹Relation to ‹permutes›\›
lemma permutes_imp_permutation: ‹permutation p›if‹finite S›‹p permutes S› proof - from‹p permutes S›have‹{x. p x ≠ x} ⊆ S› by (auto dest: permutes_not_in) thenhave‹finite {x. p x ≠ x}› using‹finite S›by (rule finite_subset) moreoverfrom‹p permutes S›have‹bij p› by (auto dest: permutes_bij) ultimatelyshow ?thesis by (simp add: permutation) qed
lemma permutation_permutesE: assumes‹permutation p› obtains S where‹finite S›‹p permutes S› proof - from assms have fin: ‹finite {x. p x ≠ x}› by (simp add: permutation) from assms have‹bij p› by (simp add: permutation) alsohave‹UNIV = {x. p x ≠ x} ∪ {x. p x = x}› by auto finallyhave‹bij_betw p {x. p x ≠ x} {x. p x ≠ x}› by (rule bij_betw_partition) (auto simp add: bij_betw_fixpoints) thenhave‹p permutes {x. p x ≠ x}› by (auto intro: bij_imp_permutes) with fin show thesis .. qed
lemma permutation_permutes: "permutation p ⟷ (∃S. finite S ∧ p permutes S)" by (auto elim: permutation_permutesE intro: permutes_imp_permutation)
subsection‹Sign of a permutation›
definition sign :: ‹('a ==> 'a) ==> int›🍋‹TODO: prefer less generic name› where‹sign p = (if evenperm p then 1 else - 1)›
lemma sign_cases [case_names even odd]: obtains‹sign p = 1› | ‹sign p = - 1› by (cases ‹evenperm p›) (simp_all add: sign_def)
lemma sign_nz [simp]: "sign p ≠ 0" by (cases p rule: sign_cases) simp_all
lemma sign_id [simp]: "sign id = 1" by (simp add: sign_def)
lemma apply_transps_append [simp]: "apply_transps (xs @ ys) = apply_transps xs ∘ apply_transps ys" by (induction xs) auto
lemma permutation_apply_transps [simp, intro]: "permutation (apply_transps xs)" proof (induction xs) case (Cons x xs) thus ?case unfolding apply_transps_Cons by (intro permutation_compose permutation_swap_id) qed auto
lemma permutes_apply_transps: assumes"∀(a,b)∈set xs. a ∈ A ∧ b ∈ A" shows"apply_transps xs permutes A" using assms proof (induction xs) case (Cons x xs) from Cons.prems show ?case unfolding apply_transps_Cons by (intro permutes_compose permutes_swap_id Cons) auto qed (auto simp: permutes_id)
lemma permutes_induct [consumes 2, case_names id swap]: assumes"p permutes S""finite S" assumes"P id" assumes"∧a b p. a ∈ S ==> b ∈ S ==> a ≠ b ==> P p ==> p permutes S ==> P (Transposition.transpose a b ∘ p)" shows"P p" using assms(2,1,4) proof (induct S arbitrary: p rule: finite_induct) case empty thenshow ?caseusing assms by (auto simp: id_def) next case (insert x F p) let ?r = "Transposition.transpose x (p x) ∘ p" let ?q = "Transposition.transpose x (p x) ∘ ?r" have qp: "?q = p" by (simp add: o_assoc) have"?r permutes F" using permutes_insert_lemma[OF insert.prems(1)] . have"P ?r" by (rule insert(3)[OF ‹?r permutes F›], rule insert(5)) (auto intro: permutes_subset) show ?case proof (cases "x = p x") case False have"p x ∈ F" using permutes_in_image[OF ‹p permutes _›, of x] False by auto have"P ?q" by (rule insert(5))
(use‹P ?r›‹p x ∈ F›‹?r permutes F› False in‹auto simp: o_def intro: permutes_subset›) thus"P p" by (simp add: qp) qed (use‹P ?r›in simp) qed
lemma permutes_rev_induct[consumes 2, case_names id swap]: assumes"finite S""p permutes S" assumes"P id" assumes"∧a b p. a ∈ S ==> b ∈ S ==> a ≠ b ==> P p ==> p permutes S ==> P (p ∘ Transposition.transpose a b)" shows"P p" proof - have"inv_into UNIV p permutes S" using assms by (intro permutes_inv) from this and assms(1,2) show ?thesis proof (induction"inv_into UNIV p" arbitrary: p rule: permutes_induct) case id hence"p = id" by (metis inv_id permutes_inv_inv) thus ?caseusing‹P id›by (auto simp: id_def) next case (swap a b p p') have"p = Transposition.transpose a b ∘ (Transposition.transpose a b ∘ p)" by (simp add: o_assoc) alsohave"… = Transposition.transpose a b ∘ inv_into UNIV p'" by (subst swap.hyps) auto alsohave"Transposition.transpose a b = inv_into UNIV (Transposition.transpose a b)" by (simp add: inv_swap_id) alsohave"…∘ inv_into UNIV p' = inv_into UNIV (p' ∘ Transposition.transpose a b)" using swap ‹finite S› by (intro permutation_inverse_compose [symmetric] permutation_swap_id permutation_inverse)
(auto simp: permutation_permutes) finallyhave"p = inv (p' ∘ Transposition.transpose a b)" . moreoverhave"p' ∘ Transposition.transpose a b permutes S" by (intro permutes_compose permutes_swap_id swap) ultimatelyhave *: "P (p' ∘ Transposition.transpose a b)" by (rule swap(4)) have"P (p' ∘ Transposition.transpose a b ∘ Transposition.transpose a b)" by (rule assms; intro * swap permutes_compose permutes_swap_id) alsohave"p' ∘ Transposition.transpose a b ∘ Transposition.transpose a b = p'" by (simp flip: o_assoc) finallyshow ?case . qed qed
lemma map_permutation_apply_transps: assumes f: "inj_on f A"and"set ts ⊆ A × A" shows"map_permutation A f (apply_transps ts) = apply_transps (map (map_prod f f) ts)" using assms(2) proof (induction ts) case (Cons t ts) obtain a b where [simp]: "t = (a, b)" by (cases t) have"map_permutation A f (apply_transps (t # ts)) = map_permutation A f (Transposition.transpose a b ∘ apply_transps ts)" by simp alsohave"… = map_permutation A f (Transposition.transpose a b) ∘ map_permutation A f (apply_transps ts)" by (subst map_permutation_compose')
(use f Cons.prems in‹auto intro!: permutes_apply_transps›) alsohave"map_permutation A f (Transposition.transpose a b) = Transposition.transpose (f a) (f b)" by (intro map_permutation_transpose f) (use Cons.prems in auto) alsohave"map_permutation A f (apply_transps ts) = apply_transps (map (map_prod f f) ts)" by (intro Cons.IH) (use Cons.prems in auto) alsohave"Transposition.transpose (f a) (f b) ∘ apply_transps (map (map_prod f f) ts) = apply_transps (map (map_prod f f) (t # ts))" by simp finallyshow ?case . qed (use f in‹auto simp: map_permutation_id'›)
lemma permutes_from_transpositions: assumes"p permutes A""finite A" shows"∃xs. (∀(a,b)∈set xs. a ≠ b ∧ a ∈ A ∧ b ∈ A) ∧ apply_transps xs = p" using assms proof (induction rule: permutes_induct) case id thus ?caseby (intro exI[of _ "[]"]) auto next case (swap a b p) from swap.IH obtain xs where
xs: "(∀(a,b)∈set xs. a ≠ b ∧ a ∈ A ∧ b ∈ A)""apply_transps xs = p" by blast thus ?case using swap.hyps by (intro exI[of _ "(a,b) # xs"]) auto qed
subsection‹More on the sign of permutations›
lemma evenperm_apply_transps_iff: assumes"∀(a,b)∈set xs. a ≠ b" shows"evenperm (apply_transps xs) ⟷ even (length xs)" using assms by (induction xs)
(simp_all add: case_prod_unfold evenperm_comp permutation_swap_id evenperm_swap)
lemma evenperm_map_permutation: assumes f: "inj_on f A"and"p permutes A""finite A" shows"evenperm (map_permutation A f p) ⟷ evenperm p" proof - note [simp] = inj_on_eq_iff[OF f] obtain ts where ts: "∀(a, b)∈set ts. a ≠ b ∧ a ∈ A ∧ b ∈ A""apply_transps ts = p" using permutes_from_transpositions[OF assms(2,3)] by blast have"evenperm p ⟷ even (length ts)" by (subst ts(2) [symmetric], subst evenperm_apply_transps_iff) (use ts(1) in auto) alsohave"…⟷ even (length (map (map_prod f f) ts))" by simp alsohave"…⟷ evenperm (apply_transps (map (map_prod f f) ts))" by (subst evenperm_apply_transps_iff) (use ts(1) in auto) alsohave"apply_transps (map (map_prod f f) ts) = map_permutation A f p" unfolding ts(2)[symmetric] by (rule map_permutation_apply_transps [symmetric]) (use f ts(1) in auto) finallyshow ?thesis .. qed
lemma sign_map_permutation: assumes"inj_on f A""p permutes A""finite A" shows"sign (map_permutation A f p) = sign p" unfolding sign_def by (subst evenperm_map_permutation) (use assms in auto)
text‹ Sometimes it can be useful to consider the sign of a function that is not a permutation in the Isabelle/HOL sense, but its restriction to some finite subset is. › definition sign_on :: "'a set ==> ('a ==> 'a) ==> int" where"sign_on A f = sign (restrict_id f A)"
lemma sign_on_cong [cong]: assumes"A = B""∧x. x ∈ A ==> f x = g x" shows"sign_on A f = sign_on B g" unfolding sign_on_def using assms by (intro arg_cong[of _ _ sign] restrict_id_cong)
lemma sign_on_permutes: assumes"f permutes A""A ⊆ B" shows"sign_on B f = sign f" proof - have f: "f permutes B" using assms permutes_subset by blast have"sign_on B f = sign (restrict_id f B)" by (simp add: sign_on_def) alsohave"restrict_id f B = f" using f by (auto simp: fun_eq_iff permutes_not_in restrict_id_def) finallyshow ?thesis . qed
lemma sign_on_id [simp]: "sign_on A id = 1" by (subst sign_on_permutes[of _ A]) auto
lemma sign_on_ident [simp]: "sign_on A (λx. x) = 1" using sign_on_id[of A] unfolding id_def by simp
lemma sign_on_transpose: assumes"a ∈ A""b ∈ A""a ≠ b" shows"sign_on A (Transposition.transpose a b) = -1" by (subst sign_on_permutes[of _ A])
(use assms in‹auto simp: permutes_swap_id sign_swap_id›)
lemma sign_on_compose: assumes"bij_betw f A A""bij_betw g A A""finite A" shows"sign_on A (f ∘ g) = sign_on A f * sign_on A g" proof -
define restr where"restr = (λf. restrict_id f A)" have"sign_on A (f ∘ g) = sign (restr (f ∘ g))" by (simp add: sign_on_def restr_def) alsohave"restr (f ∘ g) = restr f ∘ restr g" using assms(2) by (auto simp: restr_def fun_eq_iff bij_betw_def restrict_id_def) alsohave"sign … = sign (restr f) * sign (restr g)"unfolding restr_def by (rule sign_compose) (auto intro!: permutes_imp_permutation[of A] permutes_restrict_id assms) alsohave"… = sign_on A f * sign_on A g" by (simp add: sign_on_def restr_def) finallyshow ?thesis . qed
subsection‹Transpositions of adjacent elements›
text‹ We have shown above that every permutation can be written as a product of transpositions. We will now furthermore show that any transposition of successive natural numbers $\{m, \ldots, n\}$ can be written as a product of transpositions of 🪙‹adjacent›elements, i.e.\ transpositions of the form $i \leftrightarrow i+1$. ›
function adj_transp_seq :: "nat ==> nat ==> nat list"where "adj_transp_seq a b = (if a ≥ b then [] else if b = a + 1 then [a] else a # adj_transp_seq (a+1) b @ [a])" by auto terminationby (relation "measure (λ(a,b). b - a)") auto
lemmas [simp del] = adj_transp_seq.simps
lemma length_adj_transp_seq: "a < b ==> length (adj_transp_seq a b) = 2 * (b - a) - 1" by (induction a b rule: adj_transp_seq.induct; subst adj_transp_seq.simps) auto
definition apply_adj_transps :: "nat list ==> nat ==> nat" where"apply_adj_transps xs = foldl (∘) id (map (λx. Transposition.transpose x (x+1)) xs)"
lemma apply_adj_transps_aux: "f ∘ foldl (∘) g (map (λx. Transposition.transpose x (Suc x)) xs) = foldl (∘) (f ∘ g) (map (λx. Transposition.transpose x (Suc x)) xs)" by (induction xs arbitrary: f g) (auto simp: o_assoc)
lemma apply_adj_transps_Nil [simp]: "apply_adj_transps [] = id" and apply_adj_transps_Cons [simp]: "apply_adj_transps (x # xs) = Transposition.transpose x (x+1) ∘ apply_adj_transps xs" and apply_adj_transps_snoc [simp]: "apply_adj_transps (xs @ [x]) = apply_adj_transps xs ∘ Transposition.transpose x (x+1)" by (simp_all add: apply_adj_transps_def apply_adj_transps_aux)
lemma adj_transp_seq_correct: assumes"a < b" shows"apply_adj_transps (adj_transp_seq a b) = Transposition.transpose a b" using assms proof (induction a b rule: adj_transp_seq.induct) case (1 a b) show ?case proof (cases "b = a + 1") case True thus ?thesis by (subst adj_transp_seq.simps) (auto simp: o_def Transposition.transpose_def apply_adj_transps_def) next case False hence"apply_adj_transps (adj_transp_seq a b) = Transposition.transpose a (Suc a) ∘ Transposition.transpose (Suc a) b ∘ Transposition.transpose a (Suc a)" using 1 by (subst adj_transp_seq.simps)
(simp add: o_assoc swap_id_common swap_id_common' id_def o_def) alsohave"… = Transposition.transpose a b" using False 1 by (simp add: Transposition.transpose_def fun_eq_iff) finallyshow ?thesis . qed qed
lemma permutation_apply_adj_transps: "permutation (apply_adj_transps xs)" proof (induction xs) case (Cons x xs) have"permutation (Transposition.transpose x (Suc x) ∘ apply_adj_transps xs)" by (intro permutation_compose permutation_swap_id Cons) thus ?caseby (simp add: o_def) qed auto
lemma permutes_apply_adj_transps: assumes"∀x∈set xs. x ∈ A ∧ Suc x ∈ A" shows"apply_adj_transps xs permutes A" using assms by (induction xs) (auto intro!: permutes_compose permutes_swap_id permutes_id)
lemma set_adj_transp_seq: "a < b ==> set (adj_transp_seq a b) = {a.. by (induction a b rule: adj_transp_seq.induct, subst adj_transp_seq.simps) auto
subsection‹Transferring properties of permutations along bijections›
locale permutes_bij = fixes p :: "'a ==> 'a"and A :: "'a set"and B :: "'b set" fixes f :: "'a ==> 'b"and f' :: "'b ==> 'a" fixes p' :: "'b ==> 'b" defines"p' ≡ (λx. if x ∈ B then f (p (f' x)) else x)" assumes permutes_p: "p permutes A" assumes bij_f: "bij_betw f A B" assumes f'_f: "x ∈ A ==> f' (f x) = x" begin
lemma bij_f': "bij_betw f' B A" using bij_f f'_f by (auto simp: bij_betw_def) (auto simp: inj_on_def image_image)
lemma f_f': "x ∈ B ==> f (f' x) = x" using f'_f bij_f by (auto simp: bij_betw_def)
lemma f_in_B: "x ∈ A ==> f x ∈ B" using bij_f by (auto simp: bij_betw_def)
lemma f'_in_A: "x ∈ B ==> f' x ∈ A" using bij_f' by (auto simp: bij_betw_def)
lemma permutes_p': "p' permutes B" proof - have p': "p' x = x"if"x ∉ B"for x using that by (simp add: p'_def) have bij_p: "bij_betw p A A" using permutes_p by (simp add: permutes_imp_bij) have"bij_betw (f ∘ p ∘ f') B B" by (rule bij_betw_trans bij_f bij_f' bij_p)+ alsohave"?this ⟷ bij_betw p' B B" by (intro bij_betw_cong) (auto simp: p'_def) finallyshow ?thesis using p' by (rule bij_imp_permutes) qed
lemma f_eq_iff [simp]: "f x = f y ⟷ x = y"if"x ∈ A""y ∈ A"for x y using that bij_f by (auto simp: bij_betw_def inj_on_def)
lemma apply_transps_map_f_aux: assumes"∀(a,b)∈set xs. a ∈ A ∧ b ∈ A""y ∈ B" shows"apply_transps (map (map_prod f f) xs) y = f (apply_transps xs (f' y))" using assms proof (induction xs arbitrary: y) case Nil thus ?caseby (auto simp: f_f') next case (Cons x xs y) from Cons.prems have"apply_transps xs permutes A" by (intro permutes_apply_transps) auto hence [simp]: "apply_transps xs z ∈ A ⟷ z ∈ A"for z by (simp add: permutes_in_image) from Cons show ?case by (auto simp: Transposition.transpose_def f_f' f'_f case_prod_unfold f'_in_A) qed
lemma apply_transps_map_f: assumes"∀(a,b)∈set xs. a ∈ A ∧ b ∈ A" shows"apply_transps (map (map_prod f f) xs) = (λy. if y ∈ B then f (apply_transps xs (f' y)) else y)" proof fix y show"apply_transps (map (map_prod f f) xs) y = (if y ∈ B then f (apply_transps xs (f' y)) else y)" proof (cases "y ∈ B") case True thus ?thesis using apply_transps_map_f_aux[OF assms] by simp next case False have"apply_transps (map (map_prod f f) xs) permutes B" using assms by (intro permutes_apply_transps) (auto simp: case_prod_unfold f_in_B) with False have"apply_transps (map (map_prod f f) xs) y = y" by (intro permutes_not_in) with False show ?thesis by simp qed qed
end
locale permutes_bij_finite = permutes_bij + assumes finite_A: "finite A" begin
lemma evenperm_p'_iff: "evenperm p' ⟷ evenperm p" proof - obtain xs where xs: "∀(a,b)∈set xs. a ∈ A ∧ b ∈ A ∧ a ≠ b""apply_transps xs = p" using permutes_from_transpositions[OF permutes_p finite_A] by blast have"evenperm p ⟷ evenperm (apply_transps xs)" using xs by simp alsohave"…⟷ even (length xs)" using xs by (intro evenperm_apply_transps_iff) auto alsohave"…⟷ even (length (map (map_prod f f) xs))" by simp alsohave"…⟷ evenperm (apply_transps (map (map_prod f f) xs))"using xs by (intro evenperm_apply_transps_iff [symmetric]) (auto simp: case_prod_unfold) alsohave"apply_transps (map (map_prod f f) xs) = p'" using xs unfolding p'_defby (subst apply_transps_map_f) auto finallyshow ?thesis .. qed
lemma sign_p': "sign p' = sign p" by (auto simp: sign_def evenperm_p'_iff)
end
subsection‹Permuting a list›
text‹This function permutes a list by applying a permutation to the indices.›
definition permute_list :: "(nat ==> nat) ==> 'a list ==> 'a list" where"permute_list f xs = map (λi. xs ! (f i)) [0..
lemma permute_list_map: assumes"f permutes {.. shows"permute_list f (map g xs) = map g (permute_list f xs)" using permutes_in_image[OF assms] by (auto simp: permute_list_def)
lemma permute_list_nth: assumes"f permutes {.."i < length xs" shows"permute_list f xs ! i = xs ! f i" using permutes_in_image[OF assms(1)] assms(2) by (simp add: permute_list_def)
lemma permute_list_Nil [simp]: "permute_list f [] = []" by (simp add: permute_list_def)
lemma length_permute_list [simp]: "length (permute_list f xs) = length xs" by (simp add: permute_list_def)
lemma permute_list_compose: assumes"g permutes {.. shows"permute_list (f ∘ g) xs = permute_list g (permute_list f xs)" using assms[THEN permutes_in_image] by (auto simp add: permute_list_def)
lemma permute_list_id [simp]: "permute_list id xs = xs" by (simp add: id_def)
lemma mset_permute_list [simp]: fixes xs :: "'a list" assumes"f permutes {.. shows"mset (permute_list f xs) = mset xs" proof (rule multiset_eqI) fix y :: 'a from assms have [simp]: "f x < length xs ⟷ x < length xs"for x using permutes_in_image[OF assms] by auto have"count (mset (permute_list f xs)) y = card ((λi. xs ! f i) -` {y} ∩ {.. by (simp add: permute_list_def count_image_mset atLeast0LessThan) alsohave"(λi. xs ! f i) -` {y} ∩ {..∧ y = xs ! i}" by auto alsofrom assms have"card … = card {i. i < length xs ∧ y = xs ! i}" by (intro card_vimage_inj) (auto simp: permutes_inj permutes_surj) alsohave"… = count (mset xs) y" by (simp add: count_mset count_list_eq_length_filter length_filter_conv_card) finallyshow"count (mset (permute_list f xs)) y = count (mset xs) y" by simp qed
lemma set_permute_list [simp]: assumes"f permutes {.. shows"set (permute_list f xs) = set xs" by (rule mset_eq_setD[OF mset_permute_list]) fact
lemma distinct_permute_list [simp]: assumes"f permutes {.. shows"distinct (permute_list f xs) = distinct xs" by (simp add: distinct_count_atmost_1 assms)
lemma permute_list_zip: assumes"f permutes A""A = {.. assumes [simp]: "length xs = length ys" shows"permute_list f (zip xs ys) = zip (permute_list f xs) (permute_list f ys)" proof - from permutes_in_image[OF assms(1)] assms(2) have *: "f i < length ys ⟷ i < length ys"for i by simp have"permute_list f (zip xs ys) = map (λi. zip xs ys ! f i) [0.. by (simp_all add: permute_list_def zip_map_map) alsohave"… = map (λ(x, y). (xs ! f x, ys ! f y)) (zip [0.. by (intro nth_equalityI) (simp_all add: *) alsohave"… = zip (permute_list f xs) (permute_list f ys)" by (simp_all add: permute_list_def zip_map_map) finallyshow ?thesis . qed
lemma map_of_permute: assumes"σ permutes fst ` set xs" shows"map_of xs ∘ σ = map_of (map (λ(x,y). (inv σ x, y)) xs)"
(is"_ = map_of (map ?f _)") proof from assms have"inj σ""surj σ" by (simp_all add: permutes_inj permutes_surj) thenshow"(map_of xs ∘ σ) x = map_of (map ?f xs) x"for x by (induct xs) (auto simp: inv_f_f surj_f_inv_f) qed
lemma list_all2_permute_list_iff: ‹list_all2 P (permute_list p xs) (permute_list p ys) ⟷ list_all2 P xs ys› if‹p permutes {..🚫xs}› using that by (auto simp add: list_all2_iff simp flip: permute_list_zip)
subsection‹More lemmas about permutations›
lemma permutes_in_funpow_image: 🍋‹contributor ‹Lars Noschinski›\› assumes"f permutes S""x ∈ S" shows"(f ^^ n) x ∈ S" using assms by (induction n) (auto simp: permutes_in_image)
lemma permutation_self: 🍋‹contributor ‹Lars Noschinski›\› assumes‹permutation p› obtains n where‹n > 0›‹(p ^^ n) x = x› proof (cases ‹p x = x›) case True with that [of 1] show thesis by simp next case False from‹permutation p›have‹inj p› by (intro permutation_bijective bij_is_inj) moreoverfrom‹p x ≠ x›have‹(p ^^ Suc n) x ≠ (p ^^ n) x›for n proof (induction n arbitrary: x) case 0 thenshow ?caseby simp next case (Suc n) have"p (p x) ≠ p x" proof (rule notI) assume"p (p x) = p x" thenshow False using‹p x ≠ x›‹inj p›by (simp add: inj_eq) qed have"(p ^^ Suc (Suc n)) x = (p ^^ Suc n) (p x)" by (simp add: funpow_swap1) alsohave"…≠ (p ^^ n) (p x)" by (rule Suc) fact alsohave"(p ^^ n) (p x) = (p ^^ Suc n) x" by (simp add: funpow_swap1) finallyshow ?caseby simp qed thenhave"{y. ∃n. y = (p ^^ n) x} ⊆ {x. p x ≠ x}" by auto thenhave"finite {y. ∃n. y = (p ^^ n) x}" using permutation_finite_support[OF assms] by (rule finite_subset) ultimatelyobtain n where‹n > 0›‹(p ^^ n) x = x› by (rule funpow_inj_finite) with that [of n] show thesis by blast qed
text‹The following few lemmas were contributed by Lukas Bulwahn.›
lemma count_image_mset_eq_card_vimage: assumes"finite A" shows"count (image_mset f (mset_set A)) b = card {a ∈ A. f a = b}" using assms proof (induct A) case empty show ?caseby simp next case (insert x F) show ?case proof (cases "f x = b") case True with insert.hyps have"count (image_mset f (mset_set (insert x F))) b = Suc (card {a ∈ F. f a = f x})" by auto alsofrom insert.hyps(1,2) have"… = card (insert x {a ∈ F. f a = f x})" by simp alsofrom‹f x = b›have"card (insert x {a ∈ F. f a = f x}) = card {a ∈ insert x F. f a = b}" by (auto intro: arg_cong[where f="card"]) finallyshow ?thesis using insert by auto next case False thenhave"{a ∈ F. f a = b} = {a ∈ insert x F. f a = b}" by auto with insert False show ?thesis by simp qed qed
🍋‹Prove ‹image_mset_eq_implies_permutes›...› lemma image_mset_eq_implies_permutes: fixes f :: "'a ==> 'b" assumes"finite A" and mset_eq: "image_mset f (mset_set A) = image_mset f' (mset_set A)" obtains p where"p permutes A"and"∀x∈A. f x = f' (p x)" proof - from‹finite A›have [simp]: "finite {a ∈ A. f a = (b::'b)}"for f b by auto have"f ` A = f' ` A" proof - from‹finite A›have"f ` A = f ` (set_mset (mset_set A))" by simp alsohave"… = f' ` set_mset (mset_set A)" by (metis mset_eq multiset.set_map) alsofrom‹finite A›have"… = f' ` A" by simp finallyshow ?thesis . qed have"∀b∈(f ` A). ∃p. bij_betw p {a ∈ A. f a = b} {a ∈ A. f' a = b}" proof fix b from mset_eq have"count (image_mset f (mset_set A)) b = count (image_mset f' (mset_set A)) b" by simp with‹finite A›have"card {a ∈ A. f a = b} = card {a ∈ A. f' a = b}" by (simp add: count_image_mset_eq_card_vimage) thenshow"∃p. bij_betw p {a∈A. f a = b} {a ∈ A. f' a = b}" by (intro finite_same_card_bij) simp_all qed thenhave"∃p. ∀b∈f ` A. bij_betw (p b) {a ∈ A. f a = b} {a ∈ A. f' a = b}" by (rule bchoice) thenobtain p where p: "∀b∈f ` A. bij_betw (p b) {a ∈ A. f a = b} {a ∈ A. f' a = b}" ..
define p' where"p' = (λa. if a ∈ A then p (f a) a else a)" have"p' permutes A" proof (rule bij_imp_permutes) have"disjoint_family_on (λi. {a ∈ A. f' a = i}) (f ` A)" by (auto simp: disjoint_family_on_def) moreover have"bij_betw (λa. p (f a) a) {a ∈ A. f a = b} {a ∈ A. f' a = b}"if"b ∈ f ` A"forb using p that by (subst bij_betw_cong[where g="p b"]) auto ultimately have"bij_betw (λa. p (f a) a) (∪b∈f ` A. {a ∈ A. f a = b}) (∪b∈f ` A. {a ∈ A. f' a = b})" by (rule bij_betw_UNION_disjoint) moreoverhave"(∪b∈f ` A. {a ∈ A. f a = b}) = A" by auto moreoverfrom‹f ` A = f' ` A›have"(∪b∈f ` A. {a ∈ A. f' a = b}) = A" by auto ultimatelyshow"bij_betw p' A A" unfolding p'_defby (subst bij_betw_cong[where g="(λa. p (f a) a)"]) auto next show"∧x. x ∉ A ==> p' x = x" by (simp add: p'_def) qed moreoverfrom p have"∀x∈A. f x = f' (p' x)" unfolding p'_defusing bij_betwE by fastforce ultimatelyshow ?thesis .. qed
🍋‹... and derive the existing property:› lemma mset_eq_permutation: fixes xs ys :: "'a list" assumes mset_eq: "mset xs = mset ys" obtains p where"p permutes {.."permute_list p ys = xs" proof - from mset_eq have length_eq: "length xs = length ys" by (rule mset_eq_length) have"mset_set {.. by (rule mset_set_upto_eq_mset_upto) with mset_eq length_eq have"image_mset (λi. xs ! i) (mset_set {.. image_mset (λi. ys ! i) (mset_set {.. by (metis map_nth mset_map) from image_mset_eq_implies_permutes[OF _ this] obtain p where p: "p permutes {..and"∀i∈{.. by auto with length_eq have"permute_list p ys = xs" by (auto intro!: nth_equalityI simp: permute_list_nth) with p show thesis .. qed
lemma permutes_natset_le: fixes S :: "'a::wellorder set" assumes"p permutes S" and"∀i ∈ S. p i ≤ i" shows"p = id" proof - have"p n = n"for n using assms proof (induct n arbitrary: S rule: less_induct) case (less n) show ?case proof (cases "n ∈ S") case False with less(2) show ?thesis unfolding permutes_def by metis next case True with less(3) have"p n < n ∨ p n = n" by auto thenshow ?thesis proof assume"p n < n" with less have"p (p n) = p n" by metis with permutes_inj[OF less(2)] have"p n = n" unfolding inj_def by blast with‹p n 🚫›have False by simp thenshow ?thesis .. qed qed qed thenshow ?thesis by (auto simp: fun_eq_iff) qed
lemma permutes_natset_ge: fixes S :: "'a::wellorder set" assumes p: "p permutes S" and le: "∀i ∈ S. p i ≥ i" shows"p = id" proof - have"i ≥ inv p i"if"i ∈ S"for i proof - from that permutes_in_image[OF permutes_inv[OF p]] have"inv p i ∈ S" by simp with le have"p (inv p i) ≥ inv p i" by blast with permutes_inverses[OF p] show ?thesis by simp qed thenhave"∀i∈S. inv p i ≤ i" by blast from permutes_natset_le[OF permutes_inv[OF p] this] have"inv p = inv id" by simp thenshow ?thesis using p permutes_inv_inv by fastforce qed
lemma image_inverse_permutations: "{inv p |p. p permutes S} = {p. p permutes S}" using permutes_inv permutes_inv_inv by force
lemma image_compose_permutations_left: assumes"q permutes S" shows"{q ∘ p |p. p permutes S} = {p. p permutes S}" proof - have"∧p. p permutes S ==> q ∘ p permutes S" by (simp add: assms permutes_compose) moreoverhave"∧x. x permutes S ==>∃p. x = q ∘ p ∧ p permutes S" by (metis assms id_comp o_assoc permutes_compose permutes_inv permutes_inv_o(1)) ultimatelyshow ?thesis by auto qed
lemma image_compose_permutations_right: assumes"q permutes S" shows"{p ∘ q | p. p permutes S} = {p . p permutes S}" by (metis (no_types, opaque_lifting) assms comp_id fun.map_comp permutes_compose permutes_inv permutes_inv_o(2))
lemma permutes_in_seg: "p permutes {1 ..n} ==> i ∈ {1..n} ==> 1 ≤ p i ∧ p i ≤ n" by (simp add: permutes_def) metis
lemma sum_permutations_inverse: "sum f {p. p permutes S} = sum (λp. f(inv p)) {p. p permutes S}"
(is"?lhs = ?rhs") proof - let ?S = "{p . p permutes S}" have *: "inj_on inv ?S" proof (auto simp add: inj_on_def) fix q r assume q: "q permutes S" and r: "r permutes S" and qr: "inv q = inv r" thenhave"inv (inv q) = inv (inv r)" by simp with permutes_inv_inv[OF q] permutes_inv_inv[OF r] show"q = r" by metis qed have **: "inv ` ?S = ?S" using image_inverse_permutations by blast have ***: "?rhs = sum (f ∘ inv) ?S" by (simp add: o_def) from sum.reindex[OF *, of f] show ?thesis by (simp only: ** ***) qed
lemma setum_permutations_compose_left: assumes q: "q permutes S" shows"sum f {p. p permutes S} = sum (λp. f(q ∘ p)) {p. p permutes S}"
(is"?lhs = ?rhs") proof - let ?S = "{p. p permutes S}" have *: "?rhs = sum (f ∘ ((∘) q)) ?S" by (simp add: o_def) have **: "inj_on ((∘) q) ?S" proof (auto simp add: inj_on_def) fix p r assume"p permutes S" and r: "r permutes S" and rp: "q ∘ p = q ∘ r" thenhave"inv q ∘ q ∘ p = inv q ∘ q ∘ r" by (simp add: comp_assoc) with permutes_inj[OF q, unfolded inj_iff] show"p = r" by simp qed have"((∘) q) ` ?S = ?S" using image_compose_permutations_left[OF q] by auto with * sum.reindex[OF **, of f] show ?thesis by (simp only:) qed
lemma sum_permutations_compose_right: assumes q: "q permutes S" shows"sum f {p. p permutes S} = sum (λp. f(p ∘ q)) {p. p permutes S}"
(is"?lhs = ?rhs") proof - let ?S = "{p. p permutes S}" have *: "?rhs = sum (f ∘ (λp. p ∘ q)) ?S" by (simp add: o_def) have **: "inj_on (λp. p ∘ q) ?S" proof (auto simp add: inj_on_def) fix p r assume"p permutes S" and r: "r permutes S" and rp: "p ∘ q = r ∘ q" thenhave"p ∘ (q ∘ inv q) = r ∘ (q ∘ inv q)" by (simp add: o_assoc) with permutes_surj[OF q, unfolded surj_iff] show"p = r" by simp qed from image_compose_permutations_right[OF q] have"(λp. p ∘ q) ` ?S = ?S" by auto with * sum.reindex[OF **, of f] show ?thesis by (simp only:) qed
lemma inv_inj_on_permutes: ‹inj_on inv {p. p permutes S}› proof (intro inj_onI, unfold mem_Collect_eq) fix p q assume p: "p permutes S"and q: "q permutes S"and eq: "inv p = inv q" have"inv (inv p) = inv (inv q)"using eq by simp thus"p = q" using inv_inv_eq[OF permutes_bij] p q by metis qed
lemma permutes_pair_eq: ‹{(p s, s) |s. s ∈ S} = {(s, inv p s) |s. s ∈ S}› (is‹?L = ?R›) if‹p permutes S› proof show"?L ⊆ ?R" proof fix x assume"x ∈ ?L" thenobtain s where x: "x = (p s, s)"and s: "s ∈ S"by auto note x alsohave"(p s, s) = (p s, Hilbert_Choice.inv p (p s))" using permutes_inj [OF that] inv_f_f by auto alsohave"... ∈ ?R"using s permutes_in_image[OF that] by auto finallyshow"x ∈ ?R". qed show"?R ⊆ ?L" proof fix x assume"x ∈ ?R" thenobtain s where x: "x = (s, Hilbert_Choice.inv p s)" (is"_ = (s, ?ips)") and s: "s ∈ S"by auto note x alsohave"(s, ?ips) = (p ?ips, ?ips)" using inv_f_f[OF permutes_inj[OF permutes_inv[OF that]]] using inv_inv_eq[OF permutes_bij[OF that]] by auto alsohave"... ∈ ?L" using s permutes_in_image[OF permutes_inv[OF that]] by auto finallyshow"x ∈ ?L". qed qed
context fixes p and n i :: nat assumes p: ‹p permutes {0..🚫›and i: ‹i 🚫› begin
lemma permutes_nat_less: ‹p i 🚫› proof - have‹?thesis ⟷ p i ∈ {0..🚫› by simp alsofrom p have‹p i ∈ {0..🚫⟷ i ∈ {0..🚫› by (rule permutes_in_image) finallyshow ?thesis using i by simp qed
lemma permutes_nat_inv_less: ‹inv p i 🚫› proof - from p have‹inv p permutes {0..🚫› by (rule permutes_inv) thenshow ?thesis using i by (rule Permutations.permutes_nat_less) qed
end
context comm_monoid_set begin
lemma permutes_inv: ‹F (λs. g (p s) s) S = F (λs. g s (inv p s)) S› (is‹?l = ?r›) if‹p permutes S› proof - let ?g = "λ(x, y). g x y" let ?ps = "λs. (p s, s)" let ?ips = "λs. (s, inv p s)" have inj1: "inj_on ?ps S"by (rule inj_onI) auto have inj2: "inj_on ?ips S"by (rule inj_onI) auto have"?l = F ?g (?ps ` S)" using reindex [OF inj1, of ?g] by simp alsohave"?ps ` S = {(p s, s) |s. s ∈ S}"by auto alsohave"... = {(s, inv p s) |s. s ∈ S}" unfolding permutes_pair_eq [OF that] by simp alsohave"... = ?ips ` S"by auto alsohave"F ?g ... = ?r" using reindex [OF inj2, of ?g] by simp finallyshow ?thesis. qed
end
subsection‹Sum over a set of permutations (could generalize to iteration)›
lemma sum_over_permutations_insert: assumes fS: "finite S" and aS: "a ∉ S" shows"sum f {p. p permutes (insert a S)} = sum (λb. sum (λq. f (transpose a b ∘ q)) {p. p permutes S}) (insert a S)" proof - have *: "∧f a b. (λ(b, p). f (transpose a b ∘ p)) = f ∘ (λ(b,p). transpose a b ∘ p)" by (simp add: fun_eq_iff) have **: "∧P Q. {(a, b). a ∈ P ∧ b ∈ Q} = P × Q" by blast show ?thesis unfolding * ** sum.cartesian_product permutes_insert proof (rule sum.reindex) let ?f = "(λ(b, y). transpose a b ∘ y)" let ?P = "{p. p permutes S}"
{ fix b c p q assume b: "b ∈ insert a S" assume c: "c ∈ insert a S" assume p: "p permutes S" assume q: "q permutes S" assume eq: "transpose a b ∘ p = transpose a c ∘ q" from p q aS have pa: "p a = a"and qa: "q a = a" unfolding permutes_def by metis+ from eq have"(transpose a b ∘ p) a = (transpose a c ∘ q) a" by simp thenhave bc: "b = c" by (simp add: permutes_def pa qa o_def fun_upd_def id_def
cong del: if_weak_cong split: if_split_asm) from eq[unfolded bc] have"(λp. transpose a c ∘ p) (transpose a c ∘ p) = (λp. transpose a c ∘ p) (transpose a c ∘ q)"by simp thenhave"p = q" unfolding o_assoc swap_id_idempotent by simp with bc have"b = c ∧ p = q" by blast
} thenshow"inj_on ?f (insert a S × ?P)" unfolding inj_on_def by clarify metis qed qed
subsection‹Constructing permutations from association lists›
definition list_permutes :: "('a × 'a) list ==> 'a set ==> bool" where"list_permutes xs A ⟷ set (map fst xs) ⊆ A ∧ set (map snd xs) = set (map fst xs) ∧ distinct (map fst xs) ∧ distinct (map snd xs)"
lemma list_permutesI [simp]: assumes"set (map fst xs) ⊆ A""set (map snd xs) = set (map fst xs)""distinct (map fst xs)" shows"list_permutes xs A" proof - from assms(2,3) have"distinct (map snd xs)" by (intro card_distinct) (simp_all add: distinct_card del: set_map) with assms show ?thesis by (simp add: list_permutes_def) qed
definition permutation_of_list :: "('a × 'a) list ==> 'a ==> 'a" where"permutation_of_list xs x = (case map_of xs x of None ==> x | Some y ==> y)"
lemma permutation_of_list_Cons: "permutation_of_list ((x, y) # xs) x' = (if x = x' then y else permutation_of_list xs x')" by (simp add: permutation_of_list_def)
fun inverse_permutation_of_list :: "('a × 'a) list ==> 'a ==> 'a" where "inverse_permutation_of_list [] x = x"
| "inverse_permutation_of_list ((y, x') # xs) x = (if x = x' then y else inverse_permutation_of_list xs x)"
lemma image_map_of: assumes"distinct (map fst xs)" shows"map_of xs ` set (map fst xs) = Some ` set (map snd xs)" using assms by (auto simp: rev_image_eqI)
lemma the_Some_image [simp]: "the ` Some ` A = A" by (subst image_image) simp
lemma image_map_of': assumes"distinct (map fst xs)" shows"(the ∘ map_of xs) ` set (map fst xs) = set (map snd xs)" by (simp only: image_comp [symmetric] image_map_of assms the_Some_image)
lemma permutation_of_list_permutes [simp]: assumes"list_permutes xs A" shows"permutation_of_list xs permutes A"
(is"?f permutes _") proof (rule permutes_subset[OF bij_imp_permutes]) from assms show"set (map fst xs) ⊆ A" by (simp add: list_permutes_def) from assms have"inj_on (the ∘ map_of xs) (set (map fst xs))" (is ?P) by (intro inj_on_map_of') (simp_all add: list_permutes_def) alsohave"?P ⟷ inj_on ?f (set (map fst xs))" by (intro inj_on_cong)
(auto simp: permutation_of_list_def map_of_eq_None_iff split: option.splits) finallyhave"bij_betw ?f (set (map fst xs)) (?f ` set (map fst xs))" by (rule inj_on_imp_bij_betw) alsofrom assms have"?f ` set (map fst xs) = (the ∘ map_of xs) ` set (map fst xs)" by (intro image_cong refl)
(auto simp: permutation_of_list_def map_of_eq_None_iff split: option.splits) alsofrom assms have"… = set (map fst xs)" by (subst image_map_of') (simp_all add: list_permutes_def) finallyshow"bij_betw ?f (set (map fst xs)) (set (map fst xs))" . qed (force simp: permutation_of_list_def dest!: map_of_SomeD split: option.splits)+
lemma eval_permutation_of_list [simp]: "permutation_of_list [] x = x" "x = x' ==> permutation_of_list ((x',y)#xs) x = y" "x ≠ x' ==> permutation_of_list ((x',y')#xs) x = permutation_of_list xs x" by (simp_all add: permutation_of_list_def)
lemma eval_inverse_permutation_of_list [simp]: "inverse_permutation_of_list [] x = x" "x = x' ==> inverse_permutation_of_list ((y,x')#xs) x = y" "x ≠ x' ==> inverse_permutation_of_list ((y',x')#xs) x = inverse_permutation_of_list xs x" by (simp_all add: inverse_permutation_of_list.simps)
lemma permutation_of_list_id: "x ∉ set (map fst xs) ==> permutation_of_list xs x = x" by (induct xs) (auto simp: permutation_of_list_Cons)
lemma permutation_of_list_unique': "distinct (map fst xs) ==> (x, y) ∈ set xs ==> permutation_of_list xs x = y" by (induct xs) (force simp: permutation_of_list_Cons)+
lemma permutation_of_list_unique: "list_permutes xs A ==> (x, y) ∈ set xs ==> permutation_of_list xs x = y" by (intro permutation_of_list_unique') (simp_all add: list_permutes_def)
lemma inverse_permutation_of_list_id: "x ∉ set (map snd xs) ==> inverse_permutation_of_list xs x = x" by (induct xs) auto
lemma inverse_permutation_of_list_unique': "distinct (map snd xs) ==> (x, y) ∈ set xs ==> inverse_permutation_of_list xs y = x" by (induct xs) (force simp: inverse_permutation_of_list.simps(2))+
lemma inverse_permutation_of_list_unique: "list_permutes xs A ==> (x,y) ∈ set xs ==> inverse_permutation_of_list xs y = x" by (intro inverse_permutation_of_list_unique') (simp_all add: list_permutes_def)
lemma inverse_permutation_of_list_correct: fixes A :: "'a set" assumes"list_permutes xs A" shows"inverse_permutation_of_list xs = inv (permutation_of_list xs)" proof (rule ext, rule sym, subst permutes_inv_eq) from assms show"permutation_of_list xs permutes A" by simp show"permutation_of_list xs (inverse_permutation_of_list xs x) = x"for x proof (cases "x ∈ set (map snd xs)") case True thenobtain y where"(y, x) ∈ set xs"by auto with assms show ?thesis by (simp add: inverse_permutation_of_list_unique permutation_of_list_unique) next case False with assms show ?thesis by (auto simp: list_permutes_def inverse_permutation_of_list_id permutation_of_list_id) qed qed
end
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.57Bemerkung:
(vorverarbeitet am 2026-04-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.