src/HOL/Algebra/Cycles.thy
changeset 68569 c64319959bab
child 68582 b9b9e2985878
equal deleted inserted replaced
68565:1b9462304e1d 68569:c64319959bab
       
     1 (* ************************************************************************** *)
       
     2 (* Title:      Cycles.thy                                                     *)
       
     3 (* Author:     Paulo Emílio de Vilhena                                        *)
       
     4 (* ************************************************************************** *)
       
     5 
       
     6 theory Cycles
       
     7   imports "HOL-Library.Permutations" "HOL-Library.FuncSet"
       
     8     
       
     9 begin
       
    10 
       
    11 section \<open>Cycles\<close>
       
    12 
       
    13 abbreviation cycle :: "'a list \<Rightarrow> bool" where
       
    14   "cycle cs \<equiv> distinct cs"
       
    15 
       
    16 fun cycle_of_list :: "'a list \<Rightarrow> 'a \<Rightarrow> 'a"
       
    17   where
       
    18     "cycle_of_list (i # j # cs) = (Fun.swap i j id) \<circ> (cycle_of_list (j # cs))"
       
    19   | "cycle_of_list cs = id"
       
    20 
       
    21 
       
    22 subsection\<open>Cycles as Rotations\<close>
       
    23 
       
    24 text\<open>We start proving that the function derived from a cycle rotates its support list.\<close>
       
    25 
       
    26 lemma id_outside_supp:
       
    27   assumes "cycle cs" and "x \<notin> set cs"
       
    28   shows "(cycle_of_list cs) x = x" using assms
       
    29 proof (induction cs rule: cycle_of_list.induct)
       
    30   case (1 i j cs)
       
    31   have "cycle_of_list (i # j # cs) x = (Fun.swap i j id) (cycle_of_list (j # cs) x)" by simp
       
    32   also have " ... = (Fun.swap i j id) x"
       
    33     using "1.IH" "1.prems"(1) "1.prems"(2) by auto
       
    34   also have " ... = x" using 1(3) by simp
       
    35   finally show ?case .
       
    36 next
       
    37   case "2_1" thus ?case by simp
       
    38 next
       
    39   case "2_2" thus ?case by simp
       
    40 qed
       
    41 
       
    42 lemma cycle_permutes:
       
    43   assumes "cycle cs"
       
    44   shows "permutation (cycle_of_list cs)"
       
    45 proof (induction rule: cycle_of_list.induct)
       
    46   case (1 i j cs) thus ?case
       
    47     by (metis cycle_of_list.simps(1) permutation_compose permutation_swap_id)
       
    48 next
       
    49   case "2_1" thus ?case by simp
       
    50 next
       
    51   case "2_2" thus ?case by simp
       
    52 qed
       
    53 
       
    54 theorem cyclic_rotation:
       
    55   assumes "cycle cs"
       
    56   shows "map ((cycle_of_list cs) ^^ n) cs = rotate n cs"
       
    57 proof -
       
    58   { have "map (cycle_of_list cs) cs = rotate1 cs" using assms(1)
       
    59     proof (induction cs rule: cycle_of_list.induct)
       
    60       case (1 i j cs) thus ?case
       
    61       proof (cases)
       
    62         assume "cs = Nil" thus ?thesis by simp
       
    63       next
       
    64         assume "cs \<noteq> Nil" hence ge_two: "length (j # cs) \<ge> 2"
       
    65           using not_less by auto
       
    66         have "map (cycle_of_list (i # j # cs)) (i # j # cs) =
       
    67               map (Fun.swap i j id) (map (cycle_of_list (j # cs)) (i # j # cs))" by simp
       
    68         also have " ... = map (Fun.swap i j id) (i # (rotate1 (j # cs)))"
       
    69           by (metis "1.IH" "1.prems" distinct.simps(2) id_outside_supp list.simps(9))
       
    70         also have " ... = map (Fun.swap i j id) (i # (cs @ [j]))" by simp
       
    71         also have " ... = j # (map (Fun.swap i j id) cs) @ [i]" by simp
       
    72         also have " ... = j # cs @ [i]"
       
    73           by (metis "1.prems" distinct.simps(2) list.set_intros(2) map_idI swap_id_eq)
       
    74         also have " ... = rotate1 (i # j # cs)" by simp
       
    75         finally show ?thesis .
       
    76       qed
       
    77     next
       
    78       case "2_1" thus ?case by simp
       
    79     next
       
    80       case "2_2" thus ?case by simp
       
    81     qed }
       
    82   note cyclic_rotation' = this
       
    83 
       
    84   from assms show ?thesis
       
    85   proof (induction n)
       
    86     case 0 thus ?case by simp
       
    87   next
       
    88     case (Suc n)
       
    89     have "map ((cycle_of_list cs) ^^ (Suc n)) cs =
       
    90           map (cycle_of_list cs) (map ((cycle_of_list cs) ^^ n) cs)" by simp
       
    91     also have " ... = map (cycle_of_list cs) (rotate n cs)"
       
    92       by (simp add: Suc.IH assms)
       
    93     also have " ... = rotate (Suc n) cs"
       
    94       using cyclic_rotation'
       
    95       by (metis rotate1_rotate_swap rotate_Suc rotate_map)
       
    96     finally show ?case .
       
    97   qed
       
    98 qed
       
    99 
       
   100 corollary cycle_is_surj:
       
   101   assumes "cycle cs"
       
   102   shows "(cycle_of_list cs) ` (set cs) = (set cs)"
       
   103   using cyclic_rotation[OF assms, of 1] by (simp add: image_set)
       
   104 
       
   105 corollary cycle_is_id_root:
       
   106   assumes "cycle cs"
       
   107   shows "(cycle_of_list cs) ^^ (length cs) = id"
       
   108 proof -
       
   109   have "map ((cycle_of_list cs) ^^ (length cs)) cs = cs"
       
   110     by (simp add: assms cyclic_rotation)
       
   111   hence "\<And>x. x \<in> (set cs) \<Longrightarrow> ((cycle_of_list cs) ^^ (length cs)) x = x"
       
   112     using map_eq_conv by fastforce
       
   113   moreover have "\<And>n x. x \<notin> (set cs) \<Longrightarrow> ((cycle_of_list cs) ^^ n) x = x"
       
   114   proof -
       
   115     fix n show "\<And>x. x \<notin> (set cs) \<Longrightarrow> ((cycle_of_list cs) ^^ n) x = x"
       
   116     proof (induction n)
       
   117       case 0 thus ?case by simp
       
   118     next
       
   119       case (Suc n) thus ?case using id_outside_supp[OF assms] by simp
       
   120     qed
       
   121   qed
       
   122   hence "\<And>x. x \<notin> (set cs) \<Longrightarrow> ((cycle_of_list cs) ^^ (length cs)) x = x" by simp
       
   123   ultimately show ?thesis
       
   124     by (meson eq_id_iff)
       
   125 qed
       
   126 
       
   127 corollary
       
   128   assumes "cycle cs"
       
   129   shows "(cycle_of_list cs) = (cycle_of_list (rotate n cs))"
       
   130 proof -
       
   131   { fix cs :: "'a list" assume A: "cycle cs"
       
   132     have "(cycle_of_list cs) = (cycle_of_list (rotate1 cs))"
       
   133     proof
       
   134       have "\<And>x. x \<in> set cs \<Longrightarrow> (cycle_of_list cs) x = (cycle_of_list (rotate1 cs)) x"
       
   135       proof -
       
   136         have "cycle (rotate1 cs)" using A by simp
       
   137         hence "map (cycle_of_list (rotate1 cs)) (rotate1 cs) = (rotate 2 cs)"
       
   138           using cyclic_rotation by (metis Suc_eq_plus1 add.left_neutral
       
   139           funpow.simps(2) funpow_simps_right(1) o_id one_add_one rotate_Suc rotate_def)
       
   140         also have " ... = map (cycle_of_list cs) (rotate1 cs)"
       
   141           using cyclic_rotation[OF A]
       
   142           by (metis One_nat_def Suc_1 funpow.simps(2) id_apply map_map rotate0 rotate_Suc)
       
   143         finally have "map (cycle_of_list (rotate1 cs)) (rotate1 cs) = 
       
   144                     map (cycle_of_list cs) (rotate1 cs)" .
       
   145         moreover fix x assume "x \<in> set cs"
       
   146         ultimately show "(cycle_of_list cs) x = (cycle_of_list (rotate1 cs)) x" by auto
       
   147       qed
       
   148       moreover have "\<And>x. x \<notin> set cs \<Longrightarrow> (cycle_of_list cs) x = (cycle_of_list (rotate1 cs)) x"
       
   149         using A by (simp add: id_outside_supp)
       
   150       ultimately show "\<And>x. (cycle_of_list cs) x = (cycle_of_list (rotate1 cs)) x" by blast
       
   151     qed }
       
   152   note rotate1_lemma = this
       
   153 
       
   154   show "cycle_of_list cs = cycle_of_list (rotate n cs)"
       
   155   proof (induction n)
       
   156     case 0 thus ?case by simp
       
   157   next
       
   158     case (Suc n)
       
   159     have "cycle (rotate n cs)" by (simp add: assms)
       
   160     thus ?case using rotate1_lemma[of "rotate n cs"]
       
   161       by (simp add: Suc.IH)
       
   162   qed
       
   163 qed
       
   164 
       
   165 
       
   166 subsection\<open>Conjugation of cycles\<close>
       
   167 
       
   168 lemma conjugation_of_cycle:
       
   169   assumes "cycle cs" and "bij p"
       
   170   shows "p \<circ> (cycle_of_list cs) \<circ> (inv p) = cycle_of_list (map p cs)"
       
   171   using assms
       
   172 proof (induction cs rule: cycle_of_list.induct)
       
   173   case (1 i j cs)
       
   174   have "p \<circ> cycle_of_list (i # j # cs) \<circ> inv p =
       
   175        (p \<circ> (Fun.swap i j id) \<circ> inv p) \<circ> (p \<circ> cycle_of_list (j # cs) \<circ> inv p)"
       
   176     by (simp add: assms(2) bij_is_inj fun.map_comp)
       
   177   also have " ... = (Fun.swap (p i) (p j) id) \<circ> (p \<circ> cycle_of_list (j # cs) \<circ> inv p)"
       
   178     by (simp add: "1.prems"(2) bij_is_inj bij_swap_comp comp_swap o_assoc)
       
   179   finally have "p \<circ> cycle_of_list (i # j # cs) \<circ> inv p =
       
   180                (Fun.swap (p i) (p j) id) \<circ> (cycle_of_list (map p (j # cs)))"
       
   181     using "1.IH" "1.prems"(1) assms(2) by fastforce
       
   182   thus ?case by (metis cycle_of_list.simps(1) list.simps(9))
       
   183 next
       
   184   case "2_1" thus ?case
       
   185     by (metis bij_is_surj comp_id cycle_of_list.simps(2) list.simps(8) surj_iff) 
       
   186 next
       
   187   case "2_2" thus ?case
       
   188     by (metis bij_is_surj comp_id cycle_of_list.simps(3) list.simps(8) list.simps(9) surj_iff) 
       
   189 qed
       
   190 
       
   191 
       
   192 subsection\<open>When Cycles Commute\<close>
       
   193 
       
   194 lemma cycles_commute:
       
   195   assumes "cycle \<sigma>1" "cycle \<sigma>2" and "set \<sigma>1 \<inter> set \<sigma>2 = {}"
       
   196   shows "(cycle_of_list \<sigma>1) \<circ> (cycle_of_list \<sigma>2) = (cycle_of_list \<sigma>2) \<circ> (cycle_of_list \<sigma>1)"
       
   197 proof -
       
   198   { fix \<pi>1 :: "'a list" and \<pi>2 :: "'a list" and x :: "'a"
       
   199     assume A: "cycle \<pi>1" "cycle \<pi>2" "set \<pi>1 \<inter> set \<pi>2 = {}" "x \<in> set \<pi>1" "x \<notin> set \<pi>2"
       
   200     have "((cycle_of_list \<pi>1) \<circ> (cycle_of_list \<pi>2)) x =
       
   201           ((cycle_of_list \<pi>2) \<circ> (cycle_of_list \<pi>1)) x"
       
   202     proof -
       
   203       have "((cycle_of_list \<pi>1) \<circ> (cycle_of_list \<pi>2)) x = (cycle_of_list \<pi>1) x"
       
   204         using id_outside_supp[OF A(2) A(5)] by simp
       
   205       also have " ... = ((cycle_of_list \<pi>2) \<circ> (cycle_of_list \<pi>1)) x"
       
   206         using id_outside_supp[OF A(2), of "(cycle_of_list \<pi>1) x"]
       
   207               cycle_is_surj[OF A(1)] A(3) A(4) by fastforce
       
   208       finally show ?thesis .
       
   209     qed }
       
   210   note aux_lemma = this
       
   211 
       
   212   let ?\<sigma>12 = "\<lambda>x. ((cycle_of_list \<sigma>1) \<circ> (cycle_of_list \<sigma>2)) x"
       
   213   let ?\<sigma>21 = "\<lambda>x. ((cycle_of_list \<sigma>2) \<circ> (cycle_of_list \<sigma>1)) x"
       
   214 
       
   215   show ?thesis
       
   216   proof
       
   217     fix x have "x \<in> set \<sigma>1 \<union> set \<sigma>2 \<or> x \<notin> set \<sigma>1 \<union> set \<sigma>2" by blast
       
   218     from this show "?\<sigma>12 x = ?\<sigma>21 x"
       
   219     proof 
       
   220       assume "x \<in> set \<sigma>1 \<union> set \<sigma>2"
       
   221       hence "(x \<in> set \<sigma>1 \<and> x \<notin> set \<sigma>2) \<or> (x \<notin> set \<sigma>1 \<and> x \<in> set \<sigma>2)" using assms(3) by blast
       
   222       from this show "?\<sigma>12 x = ?\<sigma>21 x"
       
   223       proof
       
   224         assume "x \<in> set \<sigma>1 \<and> x \<notin> set \<sigma>2" thus ?thesis
       
   225           using aux_lemma[OF assms(1-3)] by simp
       
   226       next
       
   227         assume "x \<notin> set \<sigma>1 \<and> x \<in> set \<sigma>2" thus ?thesis
       
   228           using assms aux_lemma inf_commute by metis
       
   229       qed
       
   230     next
       
   231       assume "x \<notin> set \<sigma>1 \<union> set \<sigma>2" thus ?thesis using id_outside_supp assms(1-2)
       
   232         by (metis UnCI comp_apply)
       
   233     qed
       
   234   qed
       
   235 qed
       
   236 
       
   237 
       
   238 subsection\<open>Cycles from Permutations\<close>
       
   239 
       
   240 subsubsection\<open>Exponentiation of permutations\<close>
       
   241 
       
   242 text\<open>Some important properties of permutations before defining how to extract its cycles\<close>
       
   243 
       
   244 lemma exp_of_permutation1:
       
   245   assumes "p permutes S"
       
   246   shows "(p ^^ n) permutes S" using assms
       
   247 proof (induction n)
       
   248   case 0 thus ?case by (simp add: permutes_def) 
       
   249 next
       
   250   case (Suc n) thus ?case by (metis funpow_Suc_right permutes_compose) 
       
   251 qed
       
   252 
       
   253 lemma exp_of_permutation2:
       
   254   assumes "p permutes S"
       
   255     and "i < j" "(p ^^ j) = (p ^^ i)"
       
   256   shows "(p ^^ (j - i)) = id" using assms
       
   257 proof -
       
   258   have "(p ^^ i) \<circ> (p ^^ (j - i)) = (p ^^ j)"
       
   259     by (metis add_diff_inverse_nat assms(2) funpow_add le_eq_less_or_eq not_le)
       
   260   also have " ... = (p ^^ i)" using assms(3) by simp
       
   261   finally have "(p ^^ i) \<circ> (p ^^ (j - i)) = (p ^^ i)" .
       
   262   moreover have "bij (p ^^ i)" using exp_of_permutation1[OF assms(1)]
       
   263     using permutes_bij by auto
       
   264   ultimately show ?thesis
       
   265     by (metis (no_types, lifting) bij_is_inj comp_assoc fun.map_id inv_o_cancel)
       
   266 qed
       
   267 
       
   268 lemma exp_of_permutation3:
       
   269   assumes "p permutes S" "finite S"
       
   270   shows "\<exists>n. (p ^^ n) = id \<and> n > 0"
       
   271 proof (rule ccontr)
       
   272   assume "\<nexists>n. (p ^^ n) = id \<and> 0 < n"
       
   273   hence S: "\<And>n. n > 0 \<Longrightarrow> (p ^^ n) \<noteq> id" by auto
       
   274   hence "\<And>i j. \<lbrakk> i \<ge> 0; j \<ge> 0 \<rbrakk> \<Longrightarrow> i \<noteq> j \<Longrightarrow> (p ^^ i) \<noteq> (p ^^ j)"
       
   275   proof -
       
   276     fix i :: "nat" and j :: "nat" assume "i \<ge> 0" "j \<ge> 0" and Ineq: "i \<noteq> j"
       
   277     show "(p ^^ i) \<noteq> (p ^^ j)"
       
   278     proof (rule ccontr)
       
   279       assume "\<not> (p ^^ i) \<noteq> (p ^^ j)" hence Eq: "(p ^^ i) = (p ^^ j)" by simp
       
   280       have "(p ^^ (j - i)) = id" if "j > i"
       
   281         using Eq exp_of_permutation2[OF assms(1) that] by simp
       
   282       moreover have "(p ^^ (i - j)) = id" if "i > j"
       
   283         using Eq exp_of_permutation2[OF assms(1) that] by simp
       
   284       ultimately show False using Ineq S
       
   285         by (meson le_eq_less_or_eq not_le zero_less_diff)
       
   286     qed
       
   287   qed
       
   288   hence "bij_betw (\<lambda>i. (p ^^ i)) {i :: nat . i \<ge> 0} {(p ^^ i) | i :: nat . i \<ge> 0}"
       
   289     unfolding bij_betw_def inj_on_def by blast
       
   290   hence "infinite {(p ^^ i) | i :: nat . i \<ge> 0}"
       
   291     using bij_betw_finite by auto
       
   292   moreover have "{(p ^^ i) | i :: nat . i \<ge> 0} \<subseteq> {\<pi>. \<pi> permutes S}"
       
   293     using exp_of_permutation1[OF assms(1)] by blast
       
   294   hence "finite {(p ^^ i) | i :: nat . i \<ge> 0}"
       
   295     by (simp add: assms(2) finite_permutations finite_subset)
       
   296   ultimately show False ..
       
   297 qed
       
   298 
       
   299 lemma power_prop:
       
   300   assumes "(p ^^ k) x = x" 
       
   301   shows "(p ^^ (k * l)) x = x"
       
   302 proof (induction l)
       
   303   case 0 thus ?case by simp
       
   304 next
       
   305   case (Suc l)
       
   306   hence "(p ^^ (k * (Suc l))) x = ((p ^^ (k * l)) \<circ> (p ^^ k)) x"
       
   307     by (metis funpow_Suc_right funpow_mult)
       
   308   also have " ... = (p ^^ (k * l)) x"
       
   309     by (simp add: assms)
       
   310   also have " ... = x"
       
   311     using Suc.IH Suc.prems assms by blast
       
   312   finally show ?case . 
       
   313 qed
       
   314 
       
   315 lemma exp_of_permutation4:
       
   316   assumes "p permutes S" "finite S"
       
   317   shows "\<exists>n. (p ^^ n) = id \<and> n > m"
       
   318 proof -
       
   319   obtain k where "k > 0" "(p ^^ k) = id"
       
   320     using exp_of_permutation3[OF assms] by blast
       
   321   moreover obtain n where "n * k > m"
       
   322     by (metis calculation(1) dividend_less_times_div mult.commute mult_Suc_right)
       
   323   ultimately show ?thesis
       
   324     using funpow_mult[of n k p] id_funpow[of n] mult.commute[of k n] by smt
       
   325 qed
       
   326 
       
   327 
       
   328 subsubsection\<open>Extraction of cycles from permutations\<close>
       
   329 
       
   330 definition
       
   331   least_power :: "('a \<Rightarrow> 'a) \<Rightarrow> 'a \<Rightarrow> nat"
       
   332   where "least_power f x = (LEAST n. (f ^^ n) x = x \<and> n > 0)"
       
   333 
       
   334 abbreviation
       
   335   support :: "('a \<Rightarrow> 'a) \<Rightarrow> 'a \<Rightarrow> 'a list"
       
   336   where "support p x \<equiv> map (\<lambda>i. (p ^^ i) x) [0..< (least_power p x)]"
       
   337 
       
   338 lemma least_power_wellfounded:
       
   339   assumes "permutation p"
       
   340   shows "(p ^^ (least_power p x)) x = x"
       
   341 proof -
       
   342   obtain S where "p permutes S" "finite S"
       
   343     using assms permutation_permutes by blast
       
   344   hence "\<exists>n. (p ^^ n) x = x \<and> n > 0"
       
   345     using eq_id_iff exp_of_permutation3 by metis
       
   346   thus ?thesis unfolding least_power_def
       
   347     by (metis (mono_tags, lifting) LeastI_ex)
       
   348 qed
       
   349 
       
   350 lemma least_power_gt_zero:
       
   351   assumes "permutation p"
       
   352   shows "least_power p x > 0"
       
   353 proof (rule ccontr)
       
   354   obtain S where "p permutes S" "finite S"
       
   355     using assms permutation_permutes by blast
       
   356   hence Ex: "\<exists>n. (p ^^ n) x = x \<and> n > 0"
       
   357     using eq_id_iff exp_of_permutation3 by metis
       
   358   assume "\<not> 0 < least_power p x" hence "least_power p x = 0"
       
   359     using Ex unfolding least_power_def by (metis (mono_tags, lifting) LeastI)
       
   360   thus False unfolding least_power_def
       
   361     by (metis (mono_tags, lifting) Ex LeastI_ex less_irrefl) 
       
   362 qed
       
   363 
       
   364 lemma least_power_gt_one:
       
   365   assumes "permutation p" "p x \<noteq> x"
       
   366   shows "least_power p x > Suc 0"
       
   367 proof (rule ccontr)
       
   368   obtain S where "p permutes S" "finite S"
       
   369     using assms permutation_permutes by blast
       
   370   hence Ex: "\<exists>n. (p ^^ n) x = x \<and> n > 0"
       
   371     using eq_id_iff exp_of_permutation3 by metis
       
   372   assume "\<not> Suc 0 < least_power p x" hence "least_power p x = (Suc 0)"
       
   373     using Ex unfolding least_power_def by (metis (mono_tags, lifting) LeastI Suc_lessI)
       
   374   hence "p x = x" using least_power_wellfounded[OF assms(1), of x] by simp
       
   375   from \<open>p x = x\<close> and \<open>p x \<noteq> x\<close> show False by simp
       
   376 qed
       
   377 
       
   378 lemma least_power_bound:
       
   379   assumes "permutation p" shows "\<exists>m > 0. (least_power p x) \<le> m"
       
   380 proof -
       
   381   obtain S where "p permutes S" "finite S"
       
   382     using assms permutation_permutes by blast
       
   383   hence "\<exists>n. (p ^^ n) x = x \<and> n > 0"
       
   384     using eq_id_iff exp_of_permutation3 by metis
       
   385   then obtain m :: "nat"  where "m > 0" "m = (least_power p x)"
       
   386     unfolding least_power_def by (metis (mono_tags, lifting) LeastI_ex)
       
   387   thus ?thesis by blast
       
   388 qed
       
   389 
       
   390 lemma lt_least_power:
       
   391   assumes "Suc n = least_power p x"
       
   392     and "0 < i" "i \<le> n"
       
   393   shows "(p ^^ i) x \<noteq> x"
       
   394 proof (rule ccontr)
       
   395   assume "\<not> (p ^^ i) x \<noteq> x" hence "(p ^^ i) x = x" by simp
       
   396   hence "i \<in> {n. (p ^^ n) x = x \<and> n > 0}"
       
   397     using assms(2-3) by blast
       
   398   moreover have "i < least_power p x"
       
   399     using assms(3) assms(1) by linarith
       
   400   ultimately show False unfolding least_power_def
       
   401     using not_less_Least by auto
       
   402 qed
       
   403 
       
   404 lemma least_power_welldefined:
       
   405   assumes "permutation p" and "y \<in> {(p ^^ k) x | k. k \<ge> 0}"
       
   406   shows "least_power p x = least_power p y"
       
   407 proof -
       
   408   have aux_lemma: "\<And>z. least_power p z = least_power p (p z)"
       
   409   proof -
       
   410     fix z
       
   411     have "(p ^^ (least_power p z)) z = z"
       
   412       by (metis assms(1) least_power_wellfounded)
       
   413     hence "(p ^^ (least_power p z)) (p z) = (p z)"
       
   414       by (metis funpow_swap1)
       
   415     hence "least_power p z \<ge> least_power p (p z)"
       
   416       by (metis assms(1) inc_induct le_SucE least_power_gt_zero lt_least_power nat_le_linear)
       
   417 
       
   418     moreover have "(p ^^ (least_power p (p z))) (p z) = (p z)"
       
   419       by (simp add: assms(1) least_power_wellfounded)
       
   420     hence "(p ^^ (least_power p (p z))) z = z"
       
   421       by (metis assms(1) funpow_swap1 permutation_permutes permutes_def)
       
   422     hence "least_power p z \<le> least_power p (p z)"
       
   423       by (metis assms(1) least_power_gt_zero less_imp_Suc_add lt_least_power not_less_eq_eq)
       
   424 
       
   425     ultimately show "least_power p z = least_power p (p z)" by simp 
       
   426   qed
       
   427 
       
   428   obtain k where "k \<ge> 0" "y = (p ^^ k) x"
       
   429     using assms(2) by blast
       
   430   thus ?thesis
       
   431   proof (induction k arbitrary: x y)
       
   432     case 0 thus ?case by simp
       
   433   next
       
   434     case (Suc k)
       
   435     have "least_power p ((p ^^ k) x) = least_power p x"
       
   436       using Suc.IH by fastforce
       
   437     thus ?case using aux_lemma
       
   438       using Suc.prems(2) by auto
       
   439   qed
       
   440 qed
       
   441 
       
   442 theorem cycle_of_permutation:
       
   443   assumes "permutation p"
       
   444   shows "cycle (support p x)"
       
   445 proof (rule ccontr)
       
   446   assume "\<not> cycle (support p x)"
       
   447   hence "\<exists> i j. i \<in> {0..<least_power p x} \<and> j \<in> {0..<least_power p x} \<and> i \<noteq> j \<and> (p ^^ i) x = (p ^^ j) x"
       
   448     using atLeast_upt by (simp add: distinct_conv_nth) 
       
   449   then obtain i j where ij: "0 \<le> i" "i < j" "j < least_power p x"
       
   450                     and "(p ^^ i) x = (p ^^ j) x"
       
   451     by (metis atLeast_upt le0 le_eq_less_or_eq lessThan_iff not_less set_upt)
       
   452   hence "(p ^^ i) x = (p ^^ i) ((p ^^ (j - i)) x)"
       
   453     by (metis add_diff_inverse_nat funpow_add not_less_iff_gr_or_eq o_apply)
       
   454   hence "(p ^^ (j - i)) x = x"
       
   455     using exp_of_permutation1 assms by (metis bij_pointE permutation_permutes permutes_bij)
       
   456   moreover have "0 \<le> j - i \<and> j - i < least_power p x"
       
   457     by (simp add: ij(3) less_imp_diff_less)
       
   458   hence "(p ^^ (j - i)) x \<noteq> x" using lt_least_power ij
       
   459     by (metis diff_le_self lessE less_imp_diff_less less_imp_le zero_less_diff)
       
   460   ultimately show False by simp
       
   461 qed
       
   462 
       
   463 
       
   464 subsection\<open>Decomposition on Cycles\<close>
       
   465 
       
   466 text\<open>We show that a permutation can be decomposed on cycles\<close>
       
   467 
       
   468 subsubsection\<open>Preliminaries\<close>
       
   469 
       
   470 lemma support_set:
       
   471   assumes "permutation p"
       
   472   shows "set (support p x) = {(p ^^ k) x | k. k \<ge> 0}"
       
   473 proof -
       
   474   have "{(p ^^ k) x | k. k \<ge> 0} = {(p ^^ k) x | k. 0 \<le> k \<and> k < (least_power p x)}" (is "?A = ?B")
       
   475   proof
       
   476     show "?B \<subseteq> ?A" by blast
       
   477   next
       
   478     show "?A \<subseteq> ?B"
       
   479     proof
       
   480       fix y assume "y \<in> ?A"
       
   481       then obtain k :: "nat" where k: "k \<ge> 0" "(p ^^ k) x = y" by blast
       
   482       hence "k = (least_power p x) * (k div (least_power p x)) + (k mod (least_power p x))" by simp
       
   483       hence "y = (p ^^ ((least_power p x) * (k div (least_power p x)) + (k mod (least_power p x)))) x"
       
   484         using k by auto
       
   485       hence " y = (p ^^ (k mod (least_power p x))) x"
       
   486         using power_prop[OF least_power_wellfounded[OF assms, of x], of "k div (least_power p x)"]
       
   487         by (metis add.commute funpow_add o_apply)
       
   488       moreover have "k mod (least_power p x) < least_power p x"
       
   489         using k mod_less_divisor[of "least_power p x" k, OF least_power_gt_zero[OF assms]] by simp
       
   490       ultimately show "y \<in> ?B"
       
   491         by blast
       
   492     qed
       
   493   qed
       
   494 
       
   495   moreover have "{(p ^^ k) x | k. 0 \<le> k \<and> k < (least_power p x)} = set (support p x)" (is "?B = ?C")
       
   496   proof
       
   497     show "?B \<subseteq> ?C"
       
   498     proof
       
   499       fix y assume "y \<in> {(p ^^ k) x | k. 0 \<le> k \<and> k < (least_power p x)}"
       
   500       then obtain k where "k \<ge> 0" "k < (least_power p x)" "y = (p ^^ k) x" by blast
       
   501       thus "y \<in> ?C" by auto
       
   502     qed
       
   503   next
       
   504     show "?C \<subseteq> ?B"
       
   505     proof
       
   506       fix y assume "y \<in> ?C"
       
   507       then obtain k where "k \<ge> 0" "k < (least_power p x)" "(support p x) ! k = y" by auto
       
   508       thus "y \<in> ?B" by auto
       
   509     qed
       
   510   qed
       
   511 
       
   512   ultimately show ?thesis by simp
       
   513 qed
       
   514 
       
   515 lemma disjoint_support:
       
   516   assumes "p permutes S" "finite S"
       
   517   shows "disjoint {{(p ^^ k) x | k. k \<ge> 0} | x. x \<in> S}" (is "disjoint ?A")
       
   518 proof (rule disjointI)
       
   519   { fix a b assume "a \<in> ?A" "b \<in> ?A" "a \<inter> b \<noteq> {}"
       
   520     then obtain x y where x: "x \<in> S" "a = {(p ^^ k) x | k. k \<ge> 0}"
       
   521                       and y: "y \<in> S" "b = {(p ^^ k) y | k. k \<ge> 0}" by blast 
       
   522     assume "a \<inter> b \<noteq> {}"
       
   523     then obtain z kx ky where z: "kx \<ge> 0" "ky \<ge> 0" "z = (p ^^ kx) x" "z = (p ^^ ky) y"
       
   524       using x(2) y(2) by blast
       
   525     have "a \<subseteq> b"
       
   526     proof
       
   527       fix w assume "w \<in> a"
       
   528       then obtain k where k: "k \<ge> 0" "w = (p ^^ k) x" using x by blast
       
   529       define l where "l = (kx div (least_power p w)) + 1"
       
   530       hence l: "l * (least_power p w) > kx"
       
   531         using least_power_gt_zero assms One_nat_def add.right_neutral add_Suc_right
       
   532             mult.commute permutation_permutes
       
   533         by (metis dividend_less_times_div mult_Suc_right) 
       
   534 
       
   535       have "w = (p ^^ (l * (least_power p w))) w"
       
   536         by (metis assms least_power_wellfounded mult.commute permutation_permutes power_prop)
       
   537       also have "... = (p ^^ (l * (least_power p w) + k)) x"
       
   538         using k by (simp add: funpow_add) 
       
   539       also have " ... = (p ^^ (l * (least_power p w) + k - kx + kx)) x"
       
   540         using l by auto
       
   541       also have " ... = (p ^^ (l * (least_power p w) + k - kx)) ((p ^^ kx) x)"
       
   542         by (simp add: funpow_add)
       
   543       also have " ... = (p ^^ (l * (least_power p w) + k - kx)) ((p ^^ ky) y)" using z
       
   544         by simp
       
   545       finally have "w = (p ^^ (l * (least_power p w) + k - kx + ky)) y"
       
   546         by (simp add: funpow_add)
       
   547       thus "w \<in> b" using y by blast
       
   548     qed } note aux_lemma = this
       
   549 
       
   550   fix a b assume ab: "a \<in> ?A" "b \<in> ?A" "a \<noteq> b"
       
   551   show "a \<inter> b = {}"
       
   552   proof (rule ccontr)
       
   553     assume "a \<inter> b \<noteq> {}" thus False using aux_lemma ab
       
   554       by (metis (no_types, lifting) inf.absorb2 inf.orderE)
       
   555   qed
       
   556 qed
       
   557 
       
   558 lemma support_coverture:
       
   559   assumes "p permutes S" "finite S"
       
   560   shows "\<Union>{{(p ^^ k) x | k. k \<ge> 0} | x. x \<in> S} = S"
       
   561 proof
       
   562   show "\<Union>{{(p ^^ k) x |k. 0 \<le> k} |x. x \<in> S} \<subseteq> S"
       
   563   proof
       
   564     fix y assume "y \<in> \<Union>{{(p ^^ k) x |k. 0 \<le> k} |x. x \<in> S}"
       
   565     then obtain x k where x: "x \<in> S" and k: "k \<ge> 0" and y: "y = (p ^^ k) x" by blast
       
   566     have "(p ^^ k) x \<in> S"
       
   567     proof (induction k)
       
   568       case 0 thus ?case using x by simp
       
   569     next
       
   570       case (Suc k) thus ?case using assms
       
   571         by (simp add: permutes_in_image) 
       
   572     qed
       
   573     thus "y \<in> S" using y by simp
       
   574   qed
       
   575 next
       
   576   show "S \<subseteq> \<Union>{{(p ^^ k) x |k. 0 \<le> k} |x. x \<in> S}"
       
   577   proof
       
   578     fix x assume x: "x \<in> S"
       
   579     hence "x \<in> {(p ^^ k) x |k. 0 \<le> k}"
       
   580       by (metis (mono_tags, lifting) CollectI funpow_0 le_numeral_extra(3))
       
   581     thus "x \<in> \<Union>{{(p ^^ k) x |k. 0 \<le> k} |x. x \<in> S}" using x by blast
       
   582   qed
       
   583 qed
       
   584 
       
   585 theorem cycle_restrict:
       
   586   assumes "permutation p" "y \<in> set (support p x)"
       
   587   shows "p y = (cycle_of_list (support p x)) y"
       
   588 proof -
       
   589   have "\<And> i. \<lbrakk> 0 \<le> i; i < length (support p x) - 1 \<rbrakk> \<Longrightarrow>
       
   590          p ((support p x) ! i) = (support p x) ! (i + 1)"
       
   591   proof -
       
   592     fix i assume i: "0 \<le> i" "i < length (support p x) - 1"
       
   593     hence "p ((support p x) ! i) = p ((p ^^ i) x)" by simp
       
   594     also have " ... = (p ^^ (i + 1)) x" by simp
       
   595     also have " ... = (support p x) ! (i + 1)"
       
   596       using i by simp
       
   597     finally show "p ((support p x) ! i) = (support p x) ! (i + 1)" .
       
   598   qed
       
   599   hence 1: "map p (butlast (support p x)) = tl (support p x)"
       
   600     using nth_equalityI[of "map p (butlast (support p x))" "tl (support p x)"]
       
   601     by (smt Suc_eq_plus1 le0 length_butlast length_map length_tl nth_butlast nth_map nth_tl)
       
   602 
       
   603   have "p ((support p x) ! (length (support p x) - 1)) = p ((p ^^ (length (support p x) - 1)) x)"
       
   604     using assms(2) by auto
       
   605   also have " ... = (p ^^ (length (support p x))) x"
       
   606     by (metis (mono_tags, lifting) Suc_pred' assms(2) funpow_Suc_right
       
   607         funpow_swap1 length_pos_if_in_set o_apply)
       
   608   also have " ... = x"
       
   609     by (simp add: assms(1) least_power_wellfounded)
       
   610   also have " ... = (support p x) ! 0"
       
   611     by (simp add: assms(1) least_power_gt_zero)
       
   612   finally have "p ((support p x) ! (length (support p x) - 1)) = (support p x) ! 0" .
       
   613   hence 2: "p (last (support p x)) = hd (support p x)"
       
   614     by (metis assms(2) hd_conv_nth last_conv_nth length_greater_0_conv length_pos_if_in_set)
       
   615 
       
   616   have "map p (support p x) = (tl (support p x)) @ [hd (support p x)]" using 1 2
       
   617     by (metis (no_types, lifting) assms(2) last_map length_greater_0_conv
       
   618         length_pos_if_in_set list.map_disc_iff map_butlast snoc_eq_iff_butlast) 
       
   619   hence "map p (support p x) = rotate1 (support p x)"
       
   620     by (metis assms(2) length_greater_0_conv length_pos_if_in_set rotate1_hd_tl)
       
   621 
       
   622   moreover have "map (cycle_of_list (support p x)) (support p x) = rotate1 (support p x)"
       
   623     using cyclic_rotation[OF cycle_of_permutation[OF assms(1)], of 1 x] by simp
       
   624 
       
   625   ultimately show ?thesis using assms(2)
       
   626     using map_eq_conv by fastforce
       
   627 qed
       
   628 
       
   629 
       
   630 subsubsection\<open>Decomposition\<close>
       
   631 
       
   632 inductive cycle_decomp :: "'a set \<Rightarrow> ('a \<Rightarrow> 'a) \<Rightarrow> bool" where
       
   633 empty:  "cycle_decomp {} id" |
       
   634 comp: "\<lbrakk> cycle_decomp I p; cycle cs; set cs \<inter> I = {} \<rbrakk> \<Longrightarrow>
       
   635          cycle_decomp (set cs \<union> I) ((cycle_of_list cs) \<circ> p)"
       
   636 
       
   637 
       
   638 lemma semidecomposition:
       
   639   assumes "p permutes S" "finite S"
       
   640   shows "(\<lambda>y. if y \<in> (S - set (support p x)) then p y else y) permutes (S - set (support p x))"
       
   641     (is "?q permutes ?S'")
       
   642 proof -
       
   643   have "\<And>y. y \<notin> S \<Longrightarrow> p y = y"
       
   644     by (meson assms permutes_not_in)
       
   645 
       
   646   moreover have cycle_surj: "(cycle_of_list (support p x)) ` set (support p x) = set (support p x)"
       
   647     using cycle_is_surj cycle_of_permutation assms permutation_permutes by metis
       
   648   hence "\<And>y. y \<in> set (support p x) \<Longrightarrow> p y \<in> set (support p x)"
       
   649     using cycle_restrict assms permutation_permutes by (metis imageI)
       
   650 
       
   651   ultimately
       
   652   have 1: "\<And>y. y \<notin> ?S' \<Longrightarrow> p y \<notin> ?S'" by auto
       
   653   have 2: "\<And>y. y \<in> ?S' \<Longrightarrow> p y \<in> ?S'"
       
   654   proof -
       
   655     fix y assume y: "y \<in> ?S'" show "p y \<in> ?S'"
       
   656     proof (rule ccontr)
       
   657       assume "p y \<notin> ?S'" hence "p y \<in> set (support p x)"
       
   658         using assms(1) permutes_in_image y by fastforce
       
   659       then obtain y' where y': "y' \<in> set (support p x)" "(cycle_of_list (support p x)) y' = p y"
       
   660         using cycle_surj by (metis (mono_tags, lifting) imageE)
       
   661       hence "p y' = p y"
       
   662         using cycle_restrict assms permutation_permutes by metis
       
   663       hence "y = y'" by (metis assms(1) permutes_def)
       
   664       thus False using y y' by blast
       
   665     qed
       
   666   qed
       
   667   
       
   668   have "p ` ?S' = ?S'"
       
   669   proof -
       
   670     have "\<And> y. y \<in> ?S' \<Longrightarrow> \<exists>!x. p x = y"
       
   671       by (metis assms(1) permutes_def)
       
   672     hence "\<And> y. y \<in> ?S' \<Longrightarrow> \<exists>x \<in> ?S'. p x = y" using 1 by metis
       
   673     thus ?thesis using 2 by blast
       
   674   qed
       
   675   hence "bij_betw p ?S' ?S'"
       
   676     by (metis DiffD1 assms(1) bij_betw_subset permutes_imp_bij subsetI)
       
   677   hence "bij_betw ?q ?S' ?S'" by (smt bij_betw_cong) 
       
   678   moreover have "\<And>y. y \<notin> ?S' \<Longrightarrow> ?q y = y" by auto
       
   679   ultimately show ?thesis
       
   680     using bij_imp_permutes by blast 
       
   681 qed
       
   682 
       
   683 
       
   684 lemma cycle_decomposition_aux:
       
   685   assumes "p permutes S" "finite S" "card S = k"
       
   686   shows "cycle_decomp S p" using assms
       
   687 proof(induct arbitrary: S p rule: less_induct)
       
   688   case (less x) thus ?case
       
   689   proof (cases "S = {}")
       
   690     case True thus ?thesis
       
   691       (* using less empty by auto *)
       
   692       by (metis empty less.prems(1) permutes_empty) 
       
   693   next
       
   694     case False
       
   695     then obtain x where x: "x \<in> S" by blast
       
   696     define S' :: "'a set"   where S': "S' = S - set (support p x)"
       
   697     define q  :: "'a \<Rightarrow> 'a" where  q: "q  = (\<lambda>x. if x \<in> S' then p x else x)"
       
   698     hence q_permutes: "q permutes S'"
       
   699       using semidecomposition[OF less.prems(1-2), of x] S' q by blast
       
   700     moreover have "x \<in> set (support p x)"
       
   701       by (smt add.left_neutral diff_zero funpow_0 in_set_conv_nth least_power_gt_zero
       
   702           length_map length_upt less.prems(1) less.prems(2) nth_map_upt permutation_permutes)
       
   703     hence "card S' < card S"
       
   704       by (metis Diff_iff S' \<open>x \<in> S\<close> card_seteq leI less.prems(2) subsetI)
       
   705     ultimately have "cycle_decomp S' q"
       
   706       using S' less.hyps less.prems(2) less.prems(3) by blast
       
   707 
       
   708     moreover have "p = (cycle_of_list (support p x)) \<circ> q"
       
   709     proof
       
   710       fix y show "p y = ((cycle_of_list (support p x)) \<circ> q) y"
       
   711       proof (cases)
       
   712         assume y: "y \<in> set (support p x)" hence "y \<notin> S'" using S' by simp
       
   713         hence "q y = y" using q by simp
       
   714         thus ?thesis
       
   715           (* using cycle_restrict less.prems(1) less.prems(2) permutation_permutes y by fastforce *)
       
   716           using comp_apply cycle_restrict less.prems permutation_permutes y by fastforce
       
   717       next
       
   718         assume y: "y \<notin> set (support p x)" thus ?thesis
       
   719         proof (cases)
       
   720           assume "y \<in> S'"
       
   721           hence "q y \<in> S'" using q_permutes
       
   722             by (simp add: permutes_in_image)
       
   723           hence "q y \<notin> set (support p x)"
       
   724             using S' by blast
       
   725           hence "(cycle_of_list (support p x)) (q y) = (q y)"
       
   726             by (metis cycle_of_permutation id_outside_supp less.prems(1-2) permutation_permutes)
       
   727           thus ?thesis by (simp add: \<open>y \<in> S'\<close> q)
       
   728         next
       
   729           assume "y \<notin> S'" hence "y \<notin> S" using y S' by blast
       
   730           hence "(cycle_of_list (support p x) \<circ> q) y = (cycle_of_list (support p x)) y"
       
   731             by (simp add: \<open>y \<notin> S'\<close> q)
       
   732           also have " ... = y"
       
   733             by (metis cycle_of_permutation id_outside_supp less.prems(1-2) permutation_permutes y)
       
   734           also have " ... = p y"
       
   735             by (metis \<open>y \<notin> S\<close> less.prems(1) permutes_def)
       
   736           finally show ?thesis by simp
       
   737         qed
       
   738       qed
       
   739     qed
       
   740     moreover have "cycle (support p x)"
       
   741       using cycle_of_permutation less.prems permutation_permutes by fastforce
       
   742     moreover have "set (support p x) \<inter> S' = {}" using S' by simp
       
   743     moreover have "set (support p x) \<subseteq> S"
       
   744       using support_coverture[OF less.prems(1-2)] support_set[of p x] x
       
   745             permutation_permutes[of p] less.prems(1-2) by blast
       
   746     hence "S = set (support p x) \<union> S'" using S' by blast 
       
   747     ultimately show ?thesis using comp[of S' q "support p x"] by auto
       
   748   qed
       
   749 qed
       
   750 
       
   751 theorem cycle_decomposition:
       
   752   assumes "p permutes S" "finite S"
       
   753   shows "cycle_decomp S p"
       
   754   using assms cycle_decomposition_aux by blast
       
   755 
       
   756 end