(*
  File:   Arith_Prog_Rel_Primes.thy
  Author: Jose Manuel Rodriguez Caballero, University of Tartu
*)
section \<open>Problem ARITHMETIC PROGRESSIONS (Putnam exam problems 2002)\<close>
theory Arith_Prog_Rel_Primes
  imports
    Complex_Main
    "HOL-Number_Theory.Number_Theory"
begin

text \<open>
 Statement of the problem (from ~\cite{putnam}): For which integers $n>1$ does the set of positive
 integers less than and relatively prime to $n$ constitute an arithmetic progression?

 The solution of the above problem is theorem @{text arith_prog_rel_primes_solution}.

 First, we will require some auxiliary material before we get started with the actual
 solution.
\<close>

subsection \<open>Auxiliary results\<close>

lemma even_and_odd_parts:
  fixes n::nat
  assumes \<open>n \<noteq> 0\<close>
  shows \<open>\<exists> k q::nat. n = (2::nat)^k*q \<and> odd q\<close>
proof-
  have \<open>prime (2::nat)\<close>
    by simp
  thus ?thesis
    using prime_power_canonical[where p = "2" and m = "n"]
      assms semiring_normalization_rules(7) by auto
qed

lemma only_one_odd_div_power2:
  fixes n::nat
  assumes \<open>n \<noteq> 0\<close> and  \<open>\<And> x. x dvd n \<Longrightarrow> odd x \<Longrightarrow> x = 1\<close>
  shows \<open>\<exists> k. n = (2::nat)^k\<close>
  by (metis even_and_odd_parts assms(1) assms(2) dvd_triv_left semiring_normalization_rules(11)
      semiring_normalization_rules(7))

lemma coprime_power2:
  fixes n::nat
  assumes \<open>n \<noteq> 0\<close> and \<open>\<And> x. x < n \<Longrightarrow> (coprime x n \<longleftrightarrow> odd x)\<close>
  shows \<open>\<exists> k. n = (2::nat)^k\<close>
proof-
  have \<open>x dvd n \<Longrightarrow> odd x \<Longrightarrow> x = 1\<close>
    for x
    by (metis neq0_conv One_nat_def Suc_1 Suc_lessI assms(1) assms(2) coprime_left_2_iff_odd
        dvd_refl linorder_neqE_nat nat_dvd_1_iff_1 nat_dvd_not_less not_coprimeI)
  thus ?thesis
    using assms(1) only_one_odd_div_power2
    by auto
qed

subsection \<open>Main result\<close>

text \<open>
  The solution to the problem  ARITHMETIC PROGRESSIONS (Putnam exam problems 2002)
\<close>

theorem arith_prog_rel_primes_solution:
  fixes n :: nat
  assumes \<open>n > 1\<close>
  shows \<open>(prime n \<or> (\<exists> k. n = 2^k) \<or> n = 6) \<longleftrightarrow>
(\<exists> a b m. m \<noteq> 0 \<and> {x | x. x < n \<and> coprime x n} = {a+j*b| j::nat. j < m})\<close>
proof-
  have \<open> (prime n \<or> (\<exists> k. n = 2^k) \<or>  n = 6) \<longleftrightarrow>
 (\<exists> b m. m \<noteq> 0 \<and> {x | x :: nat. x < n \<and> coprime x n} = {1+j*b| j::nat. j < m})\<close>
  proof
    show "\<exists>b m. m \<noteq> 0 \<and> {x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}"
      if "prime n \<or> (\<exists>k. n = 2 ^ k) \<or> n = 6"
    proof-
      have "\<exists>b m. m \<noteq> 0 \<and> {x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}"
        if "prime n"
      proof-
        have \<open>\<exists>m.   m \<noteq> 0 \<and> {x | x :: nat. x < n \<and> coprime x n} = {1+j| j::nat. j < m}\<close>
        proof-
          have \<open>{x | x :: nat. x < n \<and> coprime x n} =  {x | x :: nat. x \<noteq> 0 \<and> x < n}\<close>
          proof
            show "{x |x. x < n \<and> coprime x n} \<subseteq> {x |x. x \<noteq> 0 \<and> x < n}"
              by (smt Collect_mono not_le ord_0_nat ord_eq_0 order_refl prime_gt_1_nat that zero_neq_one)
            show "{x |x. x \<noteq> 0 \<and> x < n} \<subseteq> {x |x. x < n \<and> coprime x n}"
              using coprime_commute prime_nat_iff'' that
              by fastforce
          qed
          obtain m where \<open>m+1 = n\<close>
            using add.commute assms less_imp_add_positive by blast
          have \<open>{1+j| j::nat. j < (m::nat)} =  {x | x :: nat. x \<noteq> 0 \<and> x < m+1}\<close>
            by (metis Suc_eq_plus1   \<open>m + 1 = n\<close> gr0_implies_Suc le_simps(3)   less_nat_zero_code   linorder_not_less nat.simps(3) nat_neq_iff  plus_1_eq_Suc )
          hence  \<open>{x | x :: nat. x < n \<and> coprime x n} = {1+j| j::nat. j < (m::nat)}\<close>
            using \<open>{x | x :: nat. x < n \<and> coprime x n} =  {x | x :: nat. x \<noteq> 0 \<and> x < n}\<close>  \<open>m+1 = n\<close>
            by auto
          from \<open>n > 1\<close> have \<open>m \<noteq> 0\<close>
            using \<open>m + 1 = n\<close> by linarith
          have \<open>{x | x :: nat. x < n \<and> coprime x n} = {1+j| j::nat. j < m}\<close>
            using Suc_eq_plus1 \<open>1 < n\<close> \<open>{x |x. x < n \<and> coprime x n} = {1 + j |j. j < m}\<close>
            by auto
          hence \<open>(\<exists> m.  m \<noteq> 0 \<and> {x | x :: nat. x < n \<and> coprime x n} = {1+j| j::nat. j < m})\<close>
            using \<open>m \<noteq> 0\<close>
            by blast
          thus ?thesis by blast
        qed
        hence \<open>\<exists>m.  m \<noteq> 0 \<and> {x | x :: nat. x < n \<and> coprime x n} = {1+j*1| j::nat. j < m}\<close>
          by auto
        thus ?thesis
          by blast
      qed
      moreover have "\<exists>b m. m \<noteq> 0 \<and> {x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}"
        if "\<exists>k. n = 2 ^ k"
      proof-
        obtain k where \<open>n = 2 ^ k\<close>
          using \<open>\<exists>k. n = 2 ^ k\<close> by auto
        have \<open>k \<noteq> 0\<close>
          by (metis \<open>1 < n\<close> \<open>n = 2 ^ k\<close> nat_less_le power.simps(1))
        obtain t where \<open>Suc t = k\<close>
          by (metis \<open>k \<noteq> 0\<close> fib.cases)
        have \<open>n = 2^(Suc t)\<close>
          by (simp add: \<open>Suc t = k\<close> \<open>n = 2 ^ k\<close>)
        have \<open>{x | x :: nat. x < n \<and> coprime x n} = {1+j*2| j::nat. j < 2^t}\<close>
        proof
          show "{x |x. x < n \<and> coprime x n} \<subseteq> {1 + j * 2 |j. j < 2^t}"
          proof
            fix x
            assume \<open>x \<in> {x |x. x < n \<and> coprime x n}\<close>
            hence \<open>x < n\<close>
              by blast
            have \<open>coprime x n\<close>
              using \<open>x \<in> {x |x. x < n \<and> coprime x n}\<close>
              by blast
            hence \<open>coprime x (2^(Suc k))\<close>
              by (simp add: \<open>k \<noteq> 0\<close> \<open>n = 2 ^ k\<close>)
            have \<open>odd x\<close>
              using \<open>coprime x n\<close> \<open>k \<noteq> 0\<close> \<open>n = 2 ^ k\<close>
              by auto
            then obtain j where \<open>x = 1+j*2\<close>
              by (metis add.commute add.left_commute left_add_twice mult_2_right oddE)
            have \<open>x < 2^k\<close>
              using \<open>n = 2 ^ k\<close> \<open>x < n\<close> \<open>x = 1+j*2\<close>
              by linarith
            hence \<open>1+j*2 < 2^k\<close>
              using \<open>x = 1+j*2\<close>
              by blast
            hence \<open>j < 2^t\<close>
              using \<open>Suc t = k\<close> by auto
            thus \<open>x \<in> {1 + j * 2 |j. j < 2^t}\<close>
              using \<open>x = 1+j*2\<close>
              by blast
          qed
          show "{1 + j * 2 |j. j < 2 ^ t} \<subseteq> {x |x. x < n \<and> coprime x n}"
          proof
            fix x::nat
            assume \<open>x \<in> {1 + j * 2 |j. j < 2 ^ t}\<close>
            then obtain j where \<open>x = 1 + j * 2\<close> and \<open>j < 2 ^ t\<close>
              by blast
            have \<open>x < 2*(2^t)\<close>
              using  \<open>x = 1 + j * 2\<close>  \<open>j < 2 ^ t\<close>
              by linarith
            hence \<open>x < n\<close>
              by (simp add: \<open>n = 2 ^ Suc t\<close>)
            moreover have \<open>coprime x n\<close>
              by (metis (no_types) \<open>\<And>thesis. (\<And>j. \<lbrakk>x = 1 + j * 2; j < 2 ^ t\<rbrakk> \<Longrightarrow> thesis) \<Longrightarrow> thesis\<close> \<open>n = 2 ^ k\<close> coprime_Suc_left_nat coprime_mult_right_iff coprime_power_right_iff plus_1_eq_Suc)
            ultimately show \<open>x \<in> {x |x. x < n \<and> coprime x n}\<close>
              by blast
          qed
        qed
        have \<open>(2::nat)^(t::nat) \<noteq> 0\<close>
          by simp
        obtain m where \<open>m = (2::nat)^t\<close> by blast
        have \<open>m \<noteq> 0\<close>
          using \<open>m = 2 ^ t\<close>
          by auto
        have \<open>{x | x :: nat. x < n \<and> coprime x n} = {1+j*2| j::nat. j < m}\<close>
          using \<open>m = 2 ^ t\<close> \<open>{x |x. x < n \<and> coprime x n} = {1 + j * 2 |j. j < 2 ^ t}\<close>
          by auto
        from  \<open>m \<noteq> 0\<close>  \<open>{x | x :: nat. x < n \<and> coprime x n} = {1+j*2| j::nat. j < m}\<close>
        show ?thesis by blast
      qed
      moreover have "\<exists>b m. m \<noteq> 0 \<and> {x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}"
        if "n = 6"
      proof-
        have  \<open>{x | x. x < 6 \<and> coprime x 6} = {1+j*4| j::nat. j < 2}\<close>
        proof-
          have \<open>{x | x::nat. x < 6 \<and> coprime x 6} = {1, 5}\<close>
          proof
            show "{u. \<exists>x. u = (x::nat) \<and> x < 6 \<and> coprime x 6} \<subseteq> {1, 5}"
            proof
              fix u::nat
              assume \<open>u \<in> {u. \<exists>x. u = x \<and> x < 6 \<and> coprime x 6}\<close>
              hence \<open>coprime u 6\<close>
                by blast
              have \<open>u < 6\<close>
                using \<open>u \<in> {u. \<exists>x. u = x \<and> x < 6 \<and> coprime x 6}\<close>
                by blast
              moreover have \<open>u \<noteq> 0\<close>
                using \<open>coprime u 6\<close> ord_eq_0
                by fastforce
              moreover have \<open>u \<noteq> 2\<close>
                using \<open>coprime u 6\<close>
                by auto
              moreover have \<open>u \<noteq> 3\<close>
              proof-
                have \<open>gcd (3::nat) 6 = 3\<close>
                  by auto
                thus ?thesis
                  by (metis (no_types) \<open>coprime u 6\<close> \<open>gcd 3 6 = 3\<close> coprime_iff_gcd_eq_1
                      numeral_eq_one_iff semiring_norm(86))
              qed
              moreover have \<open>u \<noteq> 4\<close>
              proof-
                have \<open>gcd (4::nat) 6 = 2\<close>
                  by (metis (no_types, lifting) add_numeral_left gcd_add1 gcd_add2 gcd_nat.idem
                      numeral_Bit0 numeral_One one_plus_numeral semiring_norm(4) semiring_norm(5))
                thus ?thesis
                  using \<open>coprime u 6\<close> coprime_iff_gcd_eq_1
                  by auto
              qed
              ultimately have \<open>u = 1 \<or> u = 5\<close>
                by auto
              thus \<open>u \<in> {1, 5}\<close>
                by blast
            qed
            show "{1::nat, 5} \<subseteq> {x |x. x < 6 \<and> coprime x 6}"
            proof-
              have \<open>(1::nat) \<in> {x |x. x < 6 \<and> coprime x 6}\<close>
                by simp
              moreover have \<open>(5::nat) \<in> {x |x. x < 6 \<and> coprime x 6}\<close>
                by (metis Suc_numeral coprime_Suc_right_nat less_add_one mem_Collect_eq
                    numeral_plus_one semiring_norm(5) semiring_norm(8))
              ultimately show ?thesis
                by blast
            qed
          qed
          moreover have \<open>{1+j*4| j::nat. j < 2} = {1, 5}\<close>
            by auto
          ultimately show ?thesis by auto
        qed
        moreover have \<open>(2::nat) \<noteq> 0\<close>
          by simp
        ultimately have \<open>\<exists> m.  m \<noteq> 0 \<and> {x | x :: nat. x < 6 \<and> coprime x 6} = {1+j*4| j::nat. j < m}\<close>
          by blast
        thus ?thesis
          using that
          by auto
      qed
      ultimately show ?thesis
        using that
        by blast
    qed
    show "prime n \<or> (\<exists>k. n = 2 ^ k) \<or> n = 6"
      if "\<exists>b m. m \<noteq> 0 \<and> {x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}"
    proof-
      obtain b m where \<open>m \<noteq> 0\<close> and \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
        using \<open>\<exists>b m. m \<noteq> 0 \<and> {x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
        by auto
      show ?thesis
      proof(cases \<open>n = 2\<close>)
        case True
        thus ?thesis
          by auto
      next
        case False
        have \<open>b \<le> 4\<close>
        proof(cases \<open>odd b\<close>)
          case True
          show ?thesis
          proof(rule classical)
            assume \<open>\<not>(b \<le> 4)\<close>
            hence \<open>b > 4\<close>
              using le_less_linear
              by blast
            obtain m where \<open>m \<noteq> 0\<close>
              and \<open>{x | x :: nat. x < n \<and> coprime x n} = {1+j*b| j::nat. j < m}\<close>
              using \<open>m \<noteq> 0\<close> \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
              by blast
            have \<open>b \<noteq> 0\<close>
              using \<open>4 < b\<close>
              by linarith
            have \<open>n = 2 + (m-1)*b\<close>
            proof-
              have \<open>n-1 \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
                using \<open>1 < n\<close> coprime_diff_one_left_nat
                by auto
              have \<open>n-1 \<in> {1+j*b| j::nat. j < m}\<close>
                using \<open>n - 1 \<in> {x |x. x < n \<and> coprime x n}\<close>
                  \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
                by blast
              then obtain i::nat where \<open>n-1 = 1+i*b\<close> and \<open>i < m\<close>
                by blast
              have \<open>i \<le> m-1\<close>
                using \<open>i < m\<close>
                by linarith
              have \<open>1 + (m-1)*b \<in> {1+j*b| j::nat. j < m}\<close>
                using \<open>m \<noteq> 0\<close>
                by auto
              hence \<open>1 + (m-1)*b \<in> {x | x::nat. x < n \<and> coprime x n}\<close>
                using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
                by blast
              hence \<open>1 + (m-1)*b < n\<close>
                by blast
              hence \<open>1 + (m-1)*b \<le> n-1\<close>
                by linarith
              hence \<open>1 + (m-1)*b \<le> 1+i*b\<close>
                using \<open>n - 1 = 1 + i * b\<close>
                by linarith
              hence \<open>(m-1)*b \<le> i*b\<close>
                by linarith
              hence \<open>m-1 \<le> i\<close>
                using \<open>b \<noteq> 0\<close>
                by auto
              hence \<open>m-1 = i\<close>
                using \<open>i \<le> m - 1\<close> le_antisym
                by blast
              thus ?thesis
                using \<open>m \<noteq> 0\<close> \<open>n - 1 = 1 + i * b\<close>
                by auto
            qed
            have \<open>m \<ge> 2\<close>
              using \<open>n = 2 + (m - 1)*b\<close> \<open>n \<noteq> 2\<close>
              by auto
            hence \<open>1+b \<in> {1+j*b| j. j < m}\<close>
              by fastforce
            hence  \<open>1+b \<in> {x | x::nat. x < n \<and> coprime x n}\<close>
              using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
              by blast
            hence \<open>coprime (1+b) n\<close>
              by blast
            have \<open>(2::nat) dvd (1+b)\<close>
              using \<open>odd b\<close>
              by simp
            hence \<open>coprime (2::nat) n\<close>
              using \<open>coprime (1 + b) n\<close> coprime_common_divisor coprime_left_2_iff_odd odd_one
              by blast
            have \<open>(2::nat) < n\<close>
              using \<open>1 < n\<close> \<open>n \<noteq> 2\<close>
              by linarith
            have \<open>2 \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
              using \<open>2 < n\<close> \<open>coprime 2 n\<close>
              by blast
            hence  \<open>2 \<in> {1+j*b| j::nat. j < m}\<close>
              using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
              by blast
            then obtain j::nat where \<open>2 = 1+j*b\<close>
              by blast
            have  \<open>1 = j*b\<close>
              using \<open>2 = 1+j*b\<close>
              by linarith
            thus ?thesis
              by simp
          qed
        next
          case False
          hence \<open>even b\<close>
            by simp
          show ?thesis
          proof(rule classical)
            assume \<open>\<not>(b \<le> 4)\<close>
            hence \<open>b > 4\<close>
              using le_less_linear
              by blast
            obtain m where  \<open> m \<noteq> 0\<close>
              and \<open>{x | x::nat. x < n \<and> coprime x n} = {1+j*b| j::nat. j < m}\<close>
              using \<open>m \<noteq> 0\<close> \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
              by blast
            have \<open>b \<noteq> 0\<close>
              using \<open>4 < b\<close>
              by linarith
            have \<open>n = 2 + (m-1)*b\<close>
            proof-
              have \<open>n-1 \<in> {x | x::nat. x < n \<and> coprime x n}\<close>
                using \<open>1 < n\<close> coprime_diff_one_left_nat
                by auto
              have \<open>n-1 \<in> {1+j*b| j::nat. j < m}\<close>
                using \<open>n - 1 \<in> {x |x. x < n \<and> coprime x n}\<close>
                  \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
                by blast
              then obtain i::nat where \<open>n-1 = 1+i*b\<close> and \<open>i < m\<close>
                by blast
              have \<open>i \<le> m-1\<close>
                using \<open>i < m\<close>
                by linarith
              have \<open>1 + (m-1)*b \<in> {1+j*b| j::nat. j < m}\<close>
                using \<open>m \<noteq> 0\<close>
                by auto
              hence \<open>1 + (m-1)*b \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
                using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
                by blast
              hence \<open>1 + (m-1)*b < n\<close>
                by blast
              hence \<open>1 + (m-1)*b \<le> n-1\<close>
                by linarith
              hence \<open>1 + (m-1)*b \<le> 1+i*b\<close>
                using \<open>n - 1 = 1 + i * b\<close>
                by linarith
              hence \<open>(m-1)*b \<le> i*b\<close>
                by linarith
              hence \<open>m-1 \<le> i\<close>
                using \<open>b \<noteq> 0\<close>
                by auto
              hence \<open>m-1 = i\<close>
                using \<open>i \<le> m - 1\<close> le_antisym
                by blast
              thus ?thesis
                using \<open>m \<noteq> 0\<close> \<open>n - 1 = 1 + i * b\<close>
                by auto
            qed
            obtain k :: nat where \<open>b = 2*k\<close>
              using \<open>even b\<close>
              by blast
            have \<open>n = 2*(1 + (m-1)*k)\<close>
              using  \<open>n = 2 + (m-1)*b\<close>  \<open>b = 2*k\<close>
              by simp
            show ?thesis
            proof (cases \<open>odd m\<close>)
              case True
              hence \<open>odd m\<close> by blast
              then obtain t::nat where \<open>m-1 = 2*t\<close>
                by (metis odd_two_times_div_two_nat)
              have  \<open>n = 2*(1 + b*t)\<close>
                using \<open>m - 1 = 2 * t\<close> \<open>n = 2 + (m - 1) * b\<close>
                by auto
              have \<open>t < m\<close>
                using \<open>m - 1 = 2 * t\<close> \<open>m \<noteq> 0\<close>
                by linarith
              have \<open>1 + b*t \<in> {1+j*b| j::nat. j < m}\<close>
                using \<open>t < m\<close>
                by auto
              hence \<open>1 + b*t \<in> {x | x::nat. x < n \<and> coprime x n}\<close>
                using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
                by blast
              hence \<open>coprime (1 + b*t) n\<close>
                by auto
              thus ?thesis
                by (metis (no_types, lifting) \<open>b = 2 * k\<close> \<open>n = 2 * (1 + (m - 1) * k)\<close> \<open>n = 2 * (1 + b * t)\<close> \<open>n = 2 + (m - 1) * b\<close> \<open>n \<noteq> 2\<close> add_cancel_right_right coprime_mult_right_iff coprime_self mult_cancel_left mult_is_0 nat_dvd_1_iff_1)
            next
              case False
              thus ?thesis
              proof(cases \<open>odd k\<close>)
                case True
                hence \<open>odd k\<close>
                  by blast
                have \<open>even (1 + (m - 1) * k)\<close>
                  by (simp add: False True \<open>m \<noteq> 0\<close>)
                have \<open>coprime (2 + (m - 1) * k) (1 + (m - 1) * k)\<close>
                  by simp
                have \<open>coprime (2 + (m - 1) * k) n\<close>
                  using \<open>coprime (2 + (m - 1) * k) (1 + (m - 1) * k)\<close> \<open>even (1 + (m - 1) * k)\<close>
                    \<open>n = 2 * (1 + (m - 1) * k)\<close> coprime_common_divisor coprime_mult_right_iff
                    coprime_right_2_iff_odd odd_one
                  by blast
                have \<open>2 + (m - 1) * k < n\<close>
                  by (metis (no_types, lifting) \<open>even (1 + (m - 1) * k)\<close> \<open>n = 2 * (1 + (m - 1) * k)\<close>
                      add_gr_0 add_mono_thms_linordered_semiring(1) dvd_add_left_iff dvd_add_triv_left_iff dvd_imp_le le_add2 le_neq_implies_less less_numeral_extra(1) mult_2 odd_one)
                have \<open>2 + (m - 1) * k  \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
                  using \<open>2 + (m - 1) * k < n\<close> \<open>coprime (2 + (m - 1) * k) n\<close>
                  by blast
                hence \<open>2 + (m - 1) * k  \<in> {1 + j * b |j. j < m}\<close>
                  using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
                  by blast
                then obtain j::nat where  \<open>2 + (m - 1) * k  = 1 + j * b\<close> and \<open>j < m\<close>
                  by blast
                have  \<open>1 + (m - 1) * k  = j * b\<close>
                  using \<open>2 + (m - 1) * k  = 1 + j * b\<close>
                  by simp
                hence  \<open>1 + (m - 1) * k  = j * (2*k)\<close>
                  using \<open>b = 2 * k\<close> by blast
                thus ?thesis
                  by (metis \<open>b = 2 * k\<close> \<open>even b\<close> \<open>n = 2 * (1 + (m - 1) * k)\<close> \<open>n = 2 + (m - 1) * b\<close> dvd_add_times_triv_right_iff dvd_antisym dvd_imp_le dvd_triv_right even_numeral mult_2 zero_less_numeral)
              next
                case False
                hence \<open>even k\<close> by auto
                have \<open>odd (1 + (m - 1) * k)\<close>
                  by (simp add: \<open>even k\<close> )
                hence \<open>coprime (3 + (m - 1) * k) (1 + (m - 1) * k)\<close>
                  by (smt add_numeral_left coprime_common_divisor coprime_right_2_iff_odd dvd_add_left_iff not_coprimeE numeral_Bit1 numeral_One numeral_plus_one one_add_one)
                hence \<open>coprime (3 + (m - 1) * k) n\<close>
                  by (metis \<open>even k\<close> \<open>n = 2 * (1 + (m - 1) * k)\<close> coprime_mult_right_iff coprime_right_2_iff_odd even_add even_mult_iff odd_numeral)
                have \<open>3 + (m - 1) * k < n\<close>
                  by (smt Groups.add_ac(2) \<open>even k\<close> \<open>n = 2 * (1 + (m - 1) * k)\<close> \<open>n = 2 + (m - 1) * b\<close> \<open>n \<noteq> 2\<close> add_Suc_right add_cancel_right_right add_mono_thms_linordered_semiring(1) dvd_imp_le even_add even_mult_iff le_add2 le_neq_implies_less left_add_twice mult_2 neq0_conv numeral_Bit1 numeral_One odd_numeral one_add_one plus_1_eq_Suc)
                have \<open>3 + (m - 1) * k \<in> {x |x. x < n \<and> coprime x n}\<close>
                  using \<open>3 + (m - 1) * k < n\<close> \<open>coprime (3 + (m - 1) * k) n\<close>
                  by blast
                hence \<open>3 + (m - 1) * k \<in> {1 + j * b |j. j < m}\<close>
                  using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
                  by blast
                then obtain j::nat where \<open>3 + (m - 1) * k = 1 + j * b\<close>
                  by blast
                have \<open>2 + (m - 1) * k = j * b\<close>
                  using \<open>3 + (m - 1) * k = 1 + j * b\<close>
                  by simp
                hence  \<open>2 + (m - 1) * k = j * 2*k\<close>
                  by (simp add: \<open>b = 2 * k\<close>)
                thus ?thesis
                  by (metis \<open>4 < b\<close> \<open>b = 2 * k\<close> \<open>even k\<close> dvd_add_times_triv_right_iff dvd_antisym
                      dvd_triv_right mult_2 nat_neq_iff numeral_Bit0)
              qed
            qed
          qed
        qed
        moreover have \<open>b \<noteq> 3\<close>
        proof (rule classical)
          assume \<open>\<not> (b \<noteq> 3)\<close>
          hence \<open>b = 3\<close>
            by blast
          obtain m where  \<open>m \<noteq> 0\<close> and
            \<open>{x | x::nat. x < n \<and> coprime x n} = {1+j*b| j::nat. j < m}\<close>
            using \<open>m \<noteq> 0\<close> \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
            by blast
          have \<open>b \<noteq> 0\<close>
            by (simp add: \<open>b = 3\<close>)
          have \<open>n = 2 + (m-1)*b\<close>
          proof-
            have \<open>n-1 \<in> {x | x::nat. x < n \<and> coprime x n}\<close>
              using \<open>1 < n\<close> coprime_diff_one_left_nat
              by auto
            have \<open>n-1 \<in> {1+j*b| j::nat. j < m}\<close>
              using \<open>n - 1 \<in> {x |x. x < n \<and> coprime x n}\<close>
                \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
              by blast
            then obtain i::nat where \<open>n-1 = 1+i*b\<close> and \<open>i < m\<close>
              by blast
            have \<open>i \<le> m-1\<close>
              using \<open>i < m\<close>
              by linarith
            have \<open>1 + (m-1)*b \<in> {1+j*b| j::nat. j < m}\<close>
              using \<open>m \<noteq> 0\<close>
              by auto
            hence \<open>1 + (m-1)*b \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
              using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
              by blast
            hence \<open>1 + (m-1)*b < n\<close>
              by blast
            hence \<open>1 + (m-1)*b \<le> n-1\<close>
              by linarith
            hence \<open>1 + (m-1)*b \<le> 1+i*b\<close>
              using \<open>n - 1 = 1 + i * b\<close>
              by linarith
            hence \<open>(m-1)*b \<le> i*b\<close>
              by linarith
            hence \<open>m-1 \<le> i\<close>
              using \<open>b \<noteq> 0\<close>
              by auto
            hence \<open>m-1 = i\<close>
              using \<open>i \<le> m - 1\<close> le_antisym
              by blast
            thus ?thesis
              using \<open>m \<noteq> 0\<close> \<open>n - 1 = 1 + i * b\<close>
              by auto
          qed
          have \<open>n > 2\<close>
            using \<open>1 < n\<close> \<open>n \<noteq> 2\<close>
            by linarith
          hence \<open> m \<ge> 2 \<close> using  \<open>n = 2 + (m-1)*b\<close> \<open>b = 3\<close>
            by simp
          have \<open>4 \<in> {1+j*(b::nat)| j::nat. j < m}\<close>
            using \<open>2 \<le> m\<close> \<open>b = 3\<close>
            by force
          hence \<open>(4::nat) \<in>  {x | x :: nat. x < n \<and> coprime x n}\<close>
            using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
            by auto
          hence \<open>coprime (4::nat) n\<close>
            by blast
          have \<open>(2::nat) dvd 4\<close>
            by auto
          hence \<open>coprime (2::nat) n\<close>
            using \<open>coprime (4::nat) n\<close> coprime_divisors dvd_refl
            by blast
          have \<open>4 < n\<close>
            using \<open>4 \<in> {x |x. x < n \<and> coprime x n}\<close>
            by blast
          have \<open>2 < (4::nat)\<close>
            by auto
          have  \<open>2 < n\<close>
            by (simp add: \<open>2 < n\<close>)
          hence \<open>2 \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
            using  \<open>coprime (2::nat) n\<close>
            by blast
          hence  \<open>2 \<in> {1+j*(b::nat)| j::nat. j < m}\<close>
            using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
            by blast
          then obtain j::nat where \<open>2 = 1+j*3\<close>
            using \<open>b = 3\<close>
            by blast
          from  \<open>2 = 1+j*3\<close>
          have  \<open>1 = j*3\<close>
            by auto
          hence \<open>3 dvd 1\<close>
            by auto
          thus ?thesis
            using nat_dvd_1_iff_1 numeral_eq_one_iff
            by blast
        qed
        ultimately have \<open>b = 0 \<or> b = 1 \<or> b = 2 \<or> b = 4\<close>
          by auto
        moreover have \<open>b = 0 \<Longrightarrow> \<exists>k. n = 2^k\<close>
        proof-
          assume \<open>b = 0\<close>
          have \<open>{1 + j * b |j. j < m} = {1}\<close>
            using \<open>b = 0\<close> \<open>m \<noteq> 0\<close>
            by auto
          hence \<open>{x |x. x < n \<and> coprime x n} = {1}\<close>
            using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
            by blast
          hence \<open>n = 2\<close>
          proof-
            have \<open>n-1 \<in>  {x | x :: nat. x < n \<and> coprime x n}\<close>
              using \<open>1 < n\<close> coprime_diff_one_left_nat
              by auto
            have \<open>n-1 \<in> {1}\<close>
              using \<open>n - 1 \<in> {x |x. x < n \<and> coprime x n}\<close> \<open>{x |x. x < n \<and> coprime x n} = {1}\<close>
              by blast
            hence \<open>n-1 = 1\<close>
              by blast
            hence \<open>n = 2\<close>
              by simp
            thus ?thesis
              by blast
          qed
          hence \<open>n = 2^1\<close>
            by auto
          thus ?thesis
            by blast
        qed
        moreover have \<open>b = 1 \<Longrightarrow> prime n\<close>
        proof-
          assume \<open>b = 1\<close>
          have \<open>x < n \<Longrightarrow> x \<noteq> 0 \<Longrightarrow> coprime x n\<close>
            for x
          proof-
            assume \<open>x < n\<close> and \<open>x \<noteq> 0\<close>
            have \<open>{1+j| j::nat. j < m} = {x | x::nat. x < m+1 \<and> x \<noteq> 0}\<close>
              by (metis (full_types) Suc_eq_plus1  add_mono1 less_Suc_eq_0_disj  nat.simps(3) plus_1_eq_Suc )
            hence \<open>{x | x :: nat. x < n \<and> coprime x n} = {x | x :: nat. x < m+1 \<and> x \<noteq> 0}\<close>
              using \<open>b = 1\<close> \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
              by auto
            have \<open>coprime (n-1) n\<close>
              using \<open>1 < n\<close> coprime_diff_one_left_nat
              by auto
            have \<open>n-1 < n\<close>
              using \<open>1 < n\<close>
              by auto
            have \<open>n-1 \<in> {x |x. x < n \<and> coprime x n}\<close>
              using \<open>coprime (n - 1) n\<close> \<open>n - 1 < n\<close>
              by blast
            have \<open>n-1 \<le> m\<close>
              by (metis (no_types, lifting) CollectD Suc_eq_plus1 Suc_less_eq2 \<open>n - 1 \<in> {x |x. x < n \<and> coprime x n}\<close> \<open>{x |x. x < n \<and> coprime x n} = {x |x. x < m + 1 \<and> x \<noteq> 0}\<close>   leD  le_less_linear not_less_eq_eq )
            have \<open>m \<in>  {x | x :: nat. x < m+1 \<and> x \<noteq> 0}\<close>
              using \<open>m \<noteq> 0\<close>
              by auto
            have \<open>m \<in> {x |x. x < n \<and> coprime x n} \<close>
              using \<open>m \<in> {x |x. x < m + 1 \<and> x \<noteq> 0}\<close>
                \<open>{x |x. x < n \<and> coprime x n} = {x |x. x < m + 1 \<and> x \<noteq> 0}\<close>
              by blast
            have \<open>m < n\<close>
              using \<open>m \<in> {x |x. x < n \<and> coprime x n}\<close>
              by blast
            have \<open>m+1 = n\<close>
              using \<open>m < n\<close> \<open>n - 1 \<le> m\<close>
              by linarith
            have \<open>x \<in>  {x | x :: nat. x < m+1 \<and> x \<noteq> 0}\<close>
              using \<open>m + 1 = n\<close> \<open>x < n\<close> \<open>x \<noteq> 0\<close>
              by blast
            hence \<open>x \<in> {x |x. x < n \<and> coprime x n}\<close>
              using \<open>{x |x. x < n \<and> coprime x n} = {x |x. x < m + 1 \<and> x \<noteq> 0}\<close>
              by blast
            thus ?thesis
              by blast
          qed
          thus ?thesis
            using assms coprime_commute nat_neq_iff prime_nat_iff'' by auto
        qed
        moreover have \<open>b = 2 \<Longrightarrow> \<exists> k. n = 2^k\<close>
        proof-
          assume \<open>b = 2\<close>
          have \<open>{x | x :: nat. x < n \<and> coprime x n} = {1+j*2| j::nat. j < m}\<close>
            using \<open>b = 2\<close> \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
            by auto
          have \<open>x < n \<Longrightarrow> coprime x n \<longleftrightarrow> odd x\<close>
            for x::nat
          proof-
            assume \<open>x < n\<close>
            have \<open>coprime x n \<Longrightarrow> odd x\<close>
            proof-
              assume \<open>coprime x n\<close>
              have \<open>x \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
                by (simp add: \<open>coprime x n\<close> \<open>x < n\<close>)
              hence \<open>x \<in> {1+j*2| j::nat. j < m}\<close>
                using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * 2 |j. j < m}\<close>
                by blast
              then obtain j where \<open>x = 1+j*2\<close>
                by blast
              thus ?thesis
                by simp
            qed
            moreover have \<open>odd x \<Longrightarrow> coprime x n\<close>
            proof-
              assume \<open>odd x\<close>
              obtain j::nat where \<open>x = 1+j*2\<close>
                by (metis \<open>odd x\<close> add.commute mult_2_right odd_two_times_div_two_succ one_add_one semiring_normalization_rules(16))
              have \<open>j < (n-1)/2\<close>
                using \<open>x < n\<close> \<open>x = 1 + j * 2\<close>
                by linarith
              have \<open>n = 2*m\<close>
              proof-
                have  \<open>(2::nat) \<noteq> 0\<close>
                  by auto
                have \<open>n = 2+(m-1)*2\<close>
                proof-
                  have \<open>n-1 \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
                    using \<open>1 < n\<close> coprime_diff_one_left_nat
                    by auto
                  have \<open>n-1 \<in> {1+j*b| j::nat. j < m}\<close>
                    using \<open>n - 1 \<in> {x |x. x < n \<and> coprime x n}\<close>
                      \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
                    by blast
                  then obtain i::nat where \<open>n-1 = 1+i*b\<close> and \<open>i < m\<close>
                    by blast
                  have \<open>i \<le> m-1\<close>
                    using \<open>i < m\<close>
                    by linarith
                  have \<open>1 + (m-1)*b \<in> {1+j*b| j::nat. j < m}\<close>
                    using \<open>m \<noteq> 0\<close> by auto
                  hence \<open>1 + (m-1)*b \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
                    using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
                    by blast
                  hence \<open>1 + (m-1)*b < n\<close>
                    by blast
                  hence \<open>1 + (m-1)*b \<le> n-1\<close>
                    by linarith
                  hence \<open>1 + (m-1)*b \<le> 1+i*b\<close>
                    using \<open>n - 1 = 1 + i * b\<close>
                    by linarith
                  hence \<open>(m-1)*b \<le> i*b\<close>
                    by linarith
                  hence \<open>m-1 \<le> i\<close>
                  proof-
                    have \<open>b \<noteq> 0\<close>
                      using \<open>b = 2\<close>
                      by simp
                    thus ?thesis
                      using \<open>(m - 1) * b \<le> i * b\<close> mult_le_cancel2
                      by blast
                  qed
                  hence \<open>m-1 = i\<close>
                    using \<open>i \<le> m - 1\<close> le_antisym
                    by blast
                  thus ?thesis
                    using \<open>m \<noteq> 0\<close> \<open>n - 1 = 1 + i * b\<close>
                    by (simp add: \<open>b = 2\<close>)
                qed
                thus  ?thesis
                  by (simp add: \<open>m \<noteq> 0\<close> \<open>n = 2 + (m - 1) * 2\<close> mult.commute mult_eq_if)
              qed
              hence \<open>j < m\<close>
                using \<open>x < n\<close> \<open>x = 1 + j * 2\<close>
                by linarith
              hence \<open>x \<in> {1+j*2| j::nat. j < m}\<close>
                using \<open>x = 1 + j * 2\<close>
                by blast
              hence \<open>x \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
                using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * 2 |j. j < m}\<close>
                by blast
              thus ?thesis
                by blast
            qed
            ultimately show ?thesis
              by blast
          qed
          thus ?thesis
            using coprime_power2 assms
            by auto
        qed
        moreover have \<open>b = 4 \<Longrightarrow> n = 6\<close>
        proof-
          assume \<open>b = 4\<close>
          have \<open>n = 2 \<or> n = 6\<close>
          proof(rule classical)
            assume \<open>\<not> (n = 2 \<or> n = 6)\<close>
            have  \<open>(4::nat) \<noteq> 0\<close>
              by auto
            have \<open>n =  2+(m-1)*4\<close>
            proof-
              have \<open>n-1 \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
                using \<open>1 < n\<close> coprime_diff_one_left_nat
                by auto
              have \<open>n-1 \<in> {1+j*b| j::nat. j < m}\<close>
                using \<open>n - 1 \<in> {x |x. x < n \<and> coprime x n}\<close>
                  \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
                by blast
              then obtain i::nat where \<open>n-1 = 1+i*b\<close> and \<open>i < m\<close>
                by blast
              have \<open>i \<le> m-1\<close>
                using \<open>i < m\<close>
                by linarith
              have \<open>1 + (m-1)*b \<in> {1+j*b| j::nat. j < m}\<close>
                using \<open>m \<noteq> 0\<close>
                by auto
              hence \<open>1 + (m-1)*b \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
                using \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
                by blast
              hence \<open>1 + (m-1)*b < n\<close>
                by blast
              hence \<open>1 + (m-1)*b \<le> n-1\<close>
                by linarith
              hence \<open>1 + (m-1)*b \<le> 1+i*b\<close>
                using \<open>n - 1 = 1 + i * b\<close>
                by linarith
              hence \<open>(m-1)*b \<le> i*b\<close>
                by linarith
              hence \<open>m-1 \<le> i\<close>
              proof-
                have \<open>b \<noteq> 0\<close>
                  using \<open>b = 4\<close> by auto
                thus ?thesis
                  using \<open>(m - 1) * b \<le> i * b\<close> mult_le_cancel2
                  by blast
              qed
              hence \<open>m-1 = i\<close>
                using \<open>i \<le> m - 1\<close> le_antisym
                by blast
              thus ?thesis
                using \<open>m \<noteq> 0\<close> \<open>n - 1 = 1 + i * b\<close>
                by (simp add: \<open>b = 4\<close>)
            qed
            hence \<open>n = 4*m - 2\<close>
              by (simp add: \<open>m \<noteq> 0\<close> mult.commute mult_eq_if)
            have \<open>m \<ge> 3\<close>
              using \<open>\<not> (n = 2 \<or> n = 6)\<close> \<open>n = 2 + (m - 1) * 4\<close>
              by auto
            hence \<open> {1+j*4| j::nat. j < 3} \<subseteq> {1+j*4| j::nat. j < m}\<close>
              by force
            hence \<open>9 \<in> {1+j*4| j::nat. j < 3}\<close>
              by force
            hence \<open>9 \<in> {1+j*4| j::nat. j < m}\<close>
              using  \<open> {1+j*4| j::nat. j < 3} \<subseteq> {1+j*4| j::nat. j < m}\<close>
              by blast
            hence \<open>9 \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
              using \<open>b = 4\<close> \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
              by auto
            hence \<open>coprime (9::nat) n\<close>
              by blast
            have \<open>(3::nat) dvd 9\<close>
              by auto
            have  \<open>coprime (3::nat) n\<close> using  \<open>coprime (9::nat) n\<close> \<open>(3::nat) dvd 9\<close>
              by (metis coprime_commute coprime_mult_right_iff dvd_def)
            have \<open>(3::nat) < n\<close>
              by (metis One_nat_def Suc_lessI \<open>1 < n\<close> \<open>\<not> (n = 2 \<or> n = 6)\<close> \<open>coprime 3 n\<close>
                  coprime_self numeral_2_eq_2 numeral_3_eq_3 less_numeral_extra(1) nat_dvd_not_less)
            have \<open>3 \<in>  {x | x :: nat. x < n \<and> coprime x n}\<close>
              using \<open>3 < n\<close> \<open>coprime 3 n\<close>
              by blast
            hence  \<open>(3::nat) \<in> {1+j*4| j::nat. j < m}\<close>
              using \<open>b = 4\<close> \<open>{x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}\<close>
              by blast
            then obtain j::nat where \<open>(3::nat) = 1 + j*4\<close>
              by blast
            have \<open>2 = j*4\<close>
              using numeral_3_eq_3 \<open>(3::nat) = 1 + j*4\<close>
              by linarith
            hence \<open>1 = j*2\<close>
              by linarith
            hence \<open>even 1\<close>
              by simp
            thus ?thesis
              using odd_one
              by blast
          qed
          thus ?thesis
            by (simp add: False)
        qed
        ultimately show ?thesis
          by blast
      qed
    qed
  qed
  moreover have \<open>(\<exists> b m. m \<noteq> 0 \<and> {x | x :: nat. x < n \<and> coprime x n} = {1+j*b| j::nat. j < m})
  \<longleftrightarrow> (\<exists> a b m. m \<noteq> 0 \<and> {x | x :: nat. x < n \<and> coprime x n} = {a+j*b| j::nat. j < m})\<close>
  proof
    show "\<exists>a b m. m \<noteq> 0 \<and> {x |x. x < n \<and> coprime x n} = {a + j * b |j. j < m}"
      if "\<exists>b m. m \<noteq> 0 \<and> {x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}"
      using that
      by blast
    show "\<exists>b m. m \<noteq> 0 \<and> {x |x. x < n \<and> coprime x n} = {1 + j * b |j. j < m}"
      if "\<exists>a b m. m \<noteq> 0 \<and> {x |x. x < n \<and> coprime x n} = {a + j * b |j. j < m}"
    proof-
      obtain a b m::nat where \<open>m \<noteq> 0\<close>
        and \<open>{x | x :: nat. x < n \<and> coprime x n} = {a+j*b| j::nat. j < m}\<close>
        using \<open>\<exists>a b m. m \<noteq> 0 \<and> {x |x. x < n \<and> coprime x n} = {a + j * b |j. j < m}\<close>
        by auto
      have \<open>a = 1\<close>
      proof-
        have \<open>{x | x :: nat. x < n \<and> coprime x n} = {(a::nat)+j*(b::nat)| j::nat. j < m} \<Longrightarrow> a = 1\<close>
        proof-
          have \<open>Min {x | x :: nat. x < n \<and> coprime x n} = Min {a+j*b| j::nat. j < m}\<close>
            using \<open>{x |x. x < n \<and> coprime x n} = {a + j * b |j. j < m}\<close>
            by auto
          have  \<open>Min {x | x :: nat. x < n \<and> coprime x n} = 1\<close>
          proof-
            have \<open>finite {x | x :: nat. x < n \<and> coprime x n}\<close>
              by auto
            have \<open>{x | x :: nat. x < n \<and> coprime x n} \<noteq> {}\<close>
              using \<open>1 < n\<close> by auto
            have \<open>1 \<in> {x | x :: nat. x < n \<and> coprime x n}\<close>
              using \<open>1 < n\<close>
              by auto
            have \<open>\<forall> x. coprime x n \<longrightarrow> x \<ge> 1\<close>
              using \<open>1 < n\<close> le_less_linear
              by fastforce
            hence \<open>\<forall> x.  x < n \<and> coprime x n \<longrightarrow> x \<ge> 1\<close>
              by blast
            hence \<open>\<forall> x \<in> {x | x :: nat. x < n \<and> coprime x n}. x \<ge> 1\<close>
              by blast
            hence \<open>Min {x | x :: nat. x < n \<and> coprime x n} \<ge> 1\<close>
              using \<open>finite {x | x :: nat. x < n \<and> coprime x n}\<close> \<open>{x |x. x < n \<and> coprime x n} \<noteq> {}\<close>
              by auto
            thus ?thesis
              using Min_le \<open>1 \<in> {x |x. x < n \<and> coprime x n}\<close> \<open>finite {x |x. x < n \<and> coprime x n}\<close>
                antisym by blast
          qed
          have \<open>Min  {a+j*b| j::nat. j < m} = a\<close>
          proof -
            have f1: "\<exists>n. a = a + n * b \<and> n < m"
              using \<open>m \<noteq> 0\<close>
              by auto
            have f2: "\<exists>n. 1 = a + n * b \<and> n < m"
              using \<open>{x |x. x < n \<and> coprime x n} = {a + j * b |j. j < m}\<close> assms coprime_1_left
              by blast
            have f3: "\<exists>na. a = na \<and> na < n \<and> coprime na n"
              using f1 \<open>{x |x. x < n \<and> coprime x n} = {a + j * b |j. j < m}\<close> by blast
            have "n \<noteq> 1"
              by (metis (lifting) assms less_irrefl_nat)
            then have "\<not> coprime 0 n"
              by simp
            then show ?thesis
              using f3 f2 by (metis \<open>Min {x |x. x < n \<and> coprime x n} = 1\<close> \<open>{x |x. x < n \<and> coprime x n} = {a + j * b |j. j < m}\<close> less_one linorder_neqE_nat not_add_less1)
          qed
          hence \<open>Min  {a+j*b| j::nat. j < m} = a\<close> by blast
          thus ?thesis
            using \<open>Min {x | x :: nat. x < n \<and> coprime x n} = 1\<close> \<open>Min {x | x :: nat. x < n \<and> coprime x n} = Min {a+j*b| j::nat. j < m}\<close>
            by linarith
        qed
        thus ?thesis
          using \<open>{x |x. x < n \<and> coprime x n} = {a + j * b |j. j < m}\<close>
          by blast
      qed
      thus ?thesis using  \<open>m \<noteq> 0\<close> \<open>{x | x. x < n \<and> coprime x n} = {a+j*b| j::nat. j < m}\<close>
        by auto
    qed
  qed
  ultimately show ?thesis
    by simp
qed

end


theory Star imports Main
begin

inductive
  star :: "('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> 'a \<Rightarrow> 'a \<Rightarrow> bool"
for r where
refl:  "star r x x" |
step:  "r x y \<Longrightarrow> star r y z \<Longrightarrow> star r x z"

hide_fact (open) refl step  --"names too generic"

lemma star_trans:
  "star r x y \<Longrightarrow> star r y z \<Longrightarrow> star r x z"
proof(induction rule: star.induct)
  case refl thus ?case .
next
  case step thus ?case by (metis star.step)
qed

 lemmas star_induct =
  star.induct[of "r:: 'a*'b \<Rightarrow> 'a*'b \<Rightarrow> bool", split_format(complete)]

declare star.refl[simp,intro]

lemma star_step1[simp, intro]: "r x y \<Longrightarrow> star r x y"
by(metis star.refl star.step)

code_pred star .

end


theory InductionSolutions
imports Main
begin

datatype 'a TREE = LEAF 'a | NODE 'a "'a TREE" "'a TREE"

thm TREE.induct

(* Appropriate induction rule:
   \<lbrakk>\<And>x. ?P (LEAF x); \<And>x1a x2 x3. \<lbrakk>?P x2; ?P x3\<rbrakk> \<Longrightarrow> ?P (NODE x1a x2 x3)\<rbrakk> \<Longrightarrow> ?P ?TREE *)

primrec MIRROR :: "'a TREE \<Rightarrow> 'a TREE" where
  "MIRROR (LEAF x) = LEAF x"
| "MIRROR (NODE x l r) = NODE x (MIRROR r) (MIRROR l)"

lemma mirror_mirror: "MIRROR(MIRROR t) = t"
proof(induct t)
 case (LEAF x) then show ?case by simp
next
 case(NODE x l r) then show ?case by simp
qed


(*
 * Copyright (C) 2014 NICTA
 * All rights reserved.
 *)

(* Author: David Cock - David.Cock@nicta.com.au *)

section "Loops"

theory LoopExamples imports "../pGCL" begin

text \<open>Reasoning about loops in pGCL is mostly familiar, in particular in the use of invariants.
Proving termination for truly probabilistic loops is slightly different: We appeal to a 0--1 law
to show that the loop terminates \emph{with probability 1}.  In our semantic model, terminating
with certainty and with probability 1 are exactly equivalent.\<close>

subsection \<open>Guaranteed Termination\<close>

text \<open>We start with a completely classical loop, to show that standard techniques apply. Here, we
have a program that simply decrements a counter until it hits zero:\<close>

definition countdown :: "int prog"
where
  "countdown = do (\<lambda>x. 0 < x) \<longrightarrow> Apply (\<lambda>s. s - 1) od"

text \<open>Clearly, this loop will only terminate from a state where @{term "0 \<le> x"}. This is, in fact,
also a loop invariant.\<close>

definition inv_count :: "int \<Rightarrow> bool"
where
  "inv_count = (\<lambda>x. 0 \<le> x)"

text \<open>Read @{term "wp_inv G body I"} as: @{term I} is an invariant of the loop
@{term "do G \<longrightarrow> body od"}, or @{term "\<guillemotleft>G\<guillemotright> && I \<tturnstile> wp body I"}.\<close>

lemma wp_inv_count:
  "wp_inv (\<lambda>x. 0 < x) (Apply (\<lambda>s. s - 1)) \<guillemotleft>inv_count\<guillemotright>"
  unfolding wp_inv_def inv_count_def wp_eval o_def
proof(clarify, cases)
  fix x::int
  assume "0 \<le> x"
  then show "\<guillemotleft>\<lambda>x. 0 < x\<guillemotright> x * \<guillemotleft>\<lambda>x. 0 \<le> x\<guillemotright> x \<le> \<guillemotleft>\<lambda>x. 0 \<le> x\<guillemotright> (x - 1)"
    by(simp add:embed_bool_def)
next
  fix x::int
  assume "\<not> 0 \<le> x"
  then show "\<guillemotleft>\<lambda>x. 0 < x\<guillemotright> x * \<guillemotleft>\<lambda>x. 0 \<le> x\<guillemotright> x \<le> \<guillemotleft>\<lambda>x. 0 \<le> x\<guillemotright> (x - 1)"
    by(simp add:embed_bool_def)
qed

text \<open>This example is contrived to give us an obvious variant, or measure function: the counter
itself.\<close>

lemma term_countdown:
  "\<guillemotleft>inv_count\<guillemotright> \<tturnstile> wp countdown (\<lambda>s. 1)"
  unfolding countdown_def
proof(intro loop_term_nat_measure[where m="\<lambda>x. nat (max x 0)"] wp_inv_count)
  let ?p = "Apply (\<lambda>x. x - 1::int)"

  txt \<open>As usual, well-definedness is trivial.\<close>
  show "well_def ?p"
    by(rule wd_intros)

  txt \<open>A measure of 0 imples termination.\<close>
  show "\<And>x. nat (max x 0) = 0 \<longrightarrow> \<not> 0 < x"
    by(auto)

  txt \<open>This is the meat of the proof: that the measure must decrease,
    whenever the invariant holds.  Note that the invariant is essential
    here, as if @{term "x \<le> 0"}, the measure will \emph{not} decrease.

    This is the kind of proof that the VCG is good at.  It leaves a purely
    logical goal, which we can solve with auto.\<close>
  show "\<And>n. \<guillemotleft>\<lambda>x. nat (max x 0) = Suc n\<guillemotright> && \<guillemotleft>inv_count\<guillemotright> \<tturnstile>
         wp ?p \<guillemotleft>\<lambda>x. nat (max x 0) = n\<guillemotright>"
    unfolding inv_count_def
    by(pvcg,
       auto simp:  o_def exp_conj_std_split[symmetric]
            intro: implies_entails)
qed

subsection \<open>Probabilistic Termination\<close>

text \<open>Loops need not terminate deterministically: it is sufficient to terminate with probability
1. Here we show the intuitively obvious result that by flipping a coin repeatedly, you will
eventually see heads.\<close>

type_synonym coin = bool
definition "Heads = True"
definition "Tails = False"

definition
  flip :: "coin prog"
where
  "flip = Apply (\<lambda>_. Heads) \<^bsub>(\<lambda>s. 1/2)\<^esub>\<oplus> Apply (\<lambda>_. Tails)"

text \<open>We can't define a measure here, as we did previously, as neither of the
  two possible states guarantee termination.\<close>
definition
  wait_for_heads :: "coin prog"
where
  "wait_for_heads = do ((\<noteq>) Heads) \<longrightarrow> flip od"

text \<open>Nonetheless, we can show termination .\<close>
lemma wait_for_heads_term:
  "\<lambda>s. 1 \<tturnstile> wp wait_for_heads (\<lambda>s. 1)"
  unfolding wait_for_heads_def
  txt \<open>We use one of the zero-one laws for termination, specifically that
    if, from every state there is a nonzero probability of satisfying the
    guard (and thus terminating) in a single step, then the loop terminates
    from \emph{any} state, with probability 1.\<close>
proof(rule termination_0_1)
  show "well_def flip"
    unfolding flip_def
    by(auto intro:wd_intros)

  txt \<open>We must show that the loop body is deterministic, meaning that
    it cannot diverge by itself.\<close>
  show "maximal (wp flip)"
    unfolding flip_def by(auto intro:max_intros)

  txt \<open>The verification condition for the loop body is one-step-termination,
    here shown to hold with probability 1/2.  As usual, this result falls to
    the VCG.\<close>
  show "\<lambda>s. 1/2 \<tturnstile> wp flip \<guillemotleft>\<N> ((\<noteq>) Heads)\<guillemotright>"
    unfolding flip_def
    by(pvcg, simp add:o_def Heads_def Tails_def)

  txt \<open>Finally, the one-step escape probability is non-zero.\<close>
  show "(0::real) < 1/2" by(simp)
qed

end


(* This Isabelle theory is produced using the TIP tool offered at the following website:
     https://github.com/tip-org/tools
   This file was originally provided as part of TIP benchmark at the following website:
     https://github.com/tip-org/benchmarks
   Yutaka Nagashima at CIIRC, CTU changed the TIP output theory file slightly
   to make it compatible with Isabelle2017.
\:w
   Some proofs were added by Yutaka Nagashima.*)
  theory TIP_list_perm_refl
imports "../../Test_Base"
begin

datatype 'a list = nil2 | cons2 "'a" "'a list"

fun elem :: "'a => 'a list => bool" where
"elem x (nil2) = False"
| "elem x (cons2 z xs) = ((z = x) | (elem x xs))"

fun deleteBy :: "('a => ('a => bool)) => 'a => 'a list =>
                 'a list" where
"deleteBy x y (nil2) = nil2"
| "deleteBy x y (cons2 y2 ys) =
     (if (x y) y2 then ys else cons2 y2 (deleteBy x y ys))"

fun isPermutation :: "'a list => 'a list => bool" where
"isPermutation (nil2) (nil2) = True"
| "isPermutation (nil2) (cons2 z x2) = False"
| "isPermutation (cons2 x3 xs) y =
     ((elem x3 y) &
        (isPermutation
           xs (deleteBy (% (x4 :: 'a) => % (x5 :: 'a) => (x4 = x5)) x3 y)))"

theorem property0 :
  "isPermutation xs xs"
  oops

end


section \<open> Combinatorics problems \<close>

subsection \<open>IMO 2018 SL - C2\<close>

theory IMO_2018_SL_C2
imports Complex_Main
begin

locale dim =
  fixes files :: int
  fixes ranks :: int
  assumes pos: "files > 0 \<and> ranks > 0"
  assumes div4: "files mod 4 = 0 \<and> ranks mod 4 = 0"
begin

type_synonym square = "int \<times> int"

definition squares :: "square set" where
  "squares = {0..<files} \<times> {0..<ranks}"

datatype piece = Queen | Knight

type_synonym board = "square \<Rightarrow> piece option"

definition empty_board :: board where
  "empty_board = (\<lambda> square. None)"

fun attacks_knight :: "square \<Rightarrow> board \<Rightarrow> bool" where
  "attacks_knight (file, rank) board \<longleftrightarrow>
     (\<exists> file' rank'. (file', rank') \<in> squares \<and> board (file', rank') = Some Knight \<and>
                     ((abs (file - file') = 1 \<and> abs (rank - rank') = 2) \<or>
                      (abs (file - file') = 2 \<and> abs (rank - rank') = 1)))"

definition valid_horst_move' :: "square \<Rightarrow> board \<Rightarrow> board \<Rightarrow> bool" where
  "valid_horst_move' square board board' \<longleftrightarrow>
       square \<in> squares \<and> board square = None \<and>
       \<not> attacks_knight square board \<and>
       board' = board (square := Some Knight)"

definition valid_horst_move :: "board \<Rightarrow> board \<Rightarrow> bool" where
  "valid_horst_move board board' \<longleftrightarrow>
     (\<exists> square. valid_horst_move' square board board')"

definition valid_queenie_move :: "board \<Rightarrow> board \<Rightarrow> bool" where
  "valid_queenie_move board board' \<longleftrightarrow>
     (\<exists> square \<in> squares. board square = None \<and>
                          board' = board (square := Some Queen))"

type_synonym strategy = "board \<Rightarrow> board \<Rightarrow> bool"

inductive valid_game :: "strategy \<Rightarrow> strategy \<Rightarrow> nat \<Rightarrow> board \<Rightarrow> bool" where
  "valid_game horst_strategy queenie_strategy 0 empty_board"
| "\<lbrakk>valid_game horst_strategy queenie_strategy k board;
    valid_horst_move board board'; horst_strategy board board';
    valid_queenie_move board' board''; queenie_strategy board' board''\<rbrakk>\<Longrightarrow> valid_game horst_strategy queenie_strategy (k + 1) board''"

definition valid_queenie_strategy :: "strategy \<Rightarrow> bool" where
  "valid_queenie_strategy queenie_strategy \<longleftrightarrow>
     (\<forall>  horst_strategy board board' k.
         valid_game horst_strategy queenie_strategy k board \<and>
         valid_horst_move board board' \<and> horst_strategy board board' \<and>
         (\<exists> square \<in> squares. board' square = None) \<longrightarrow>
            (\<exists> board''. valid_queenie_move board' board'' \<and> queenie_strategy board' board''))"

(*
text \<open>squares\<close>
lemma squares_card [simp]:
  shows "card squares = files * ranks"
sorry

lemma squares_finite [simp]:
  shows "finite squares"
sorry

text \<open>\<open>free_squares\<close>\<close>

definition free_squares :: "board \<Rightarrow> square set" where
  "free_squares board = {square \<in> squares. board square = None}"

lemma free_squares_finite [simp]:
  shows "finite (free_squares board)"
sorry

lemma valid_game_free_squares_card_even:
  assumes "valid_game horst_strategy queenie_strategy k board"
  shows "card (free_squares board) mod 2 = 0"
sorry

text \<open>black squares\<close>

fun black :: "square \<Rightarrow> bool" where
 "black (file, rank) \<longleftrightarrow> (file + rank) mod 2 = 0"

definition black_squares :: "square set" where
  "black_squares = {square \<in> squares. black square}"

lemma black_squares_finite [simp]:
  shows "finite black_squares"
sorry

lemma black_squares_card:
  "card black_squares = (files * ranks) div 2"
sorry

text \<open>free black squares\<close>

definition free_black_squares :: "board \<Rightarrow> square set" where
  "free_black_squares board = {square \<in> squares. black square \<and> board square = None}"

lemma free_black_squares_add_piece:
  shows "card (free_black_squares board) \<le> card (free_black_squares (board (square := Some piece))) + 1"
sorry

lemma free_black_squares_valid_horst_move:
  assumes "valid_horst_move board board'"
  shows "card (free_black_squares board) \<le> card (free_black_squares board') + 1"
sorry

lemma free_black_squares_valid_queenie_move:
  assumes "valid_queenie_move board board'"
  shows "card (free_black_squares board) \<le> card (free_black_squares board') + 1"
sorry

text \<open>knights\<close>

definition knights :: "board \<Rightarrow> square set" where
  "knights board = {square \<in> squares. board square = Some Knight}"

lemma knights_finite [simp]:
  shows "finite (knights board)"
sorry

lemma knights_card_horst_move [simp]:
  assumes "valid_horst_move board board'"
  shows "card (knights board') = card (knights board) + 1"
sorry

lemma knights_card_queenie_move [simp]:
  assumes "valid_queenie_move board board'"
  shows "card (knights board') = card (knights board)"
sorry

lemma valid_game_knights_card [simp]:
  assumes "valid_game horst_strategy queenie_strategy k board"
  shows "card (knights board) = k"
sorry

text \<open>Cycles\<close>

fun cycle_opposite :: "square \<Rightarrow> square" where
  "cycle_opposite (file, rank) = (4 * (file div 4) + (3 - file mod 4), 4 * (rank div 4) + (3 - rank mod 4))"

lemma cycle_opposite_cycle_opposite [simp]:
  shows "cycle_opposite (cycle_opposite square) = square"
  by (cases square) auto

lemma cycle_opposite_different [simp]:
  shows "cycle_opposite square \<noteq> square"
  by (cases square, simp, presburger)

lemma cycle_opposite_squares [simp]:
  shows "cycle_opposite square \<in> squares \<longleftrightarrow> square \<in> squares"
  using pos div4
  by (cases square) (simp add: squares_def, safe, presburger+)

fun cycle4 :: "square \<Rightarrow> int" where
  "cycle4 (x, y) =
      (if x = 0 then y
       else if x = 1 then (y + 2) mod 4
       else if x = 2 then (5 - y) mod 4
       else 3 - y)"

lemma cycle_lt_4:
  assumes "0 \<le> x" "x < 4" "0 \<le> y" "y < 4"
  shows "0 \<le> cycle4 (x, y) \<and> cycle4 (x, y) < 4"
  using assms
  by auto

lemma cycle0:
  assumes "0 \<le> x" "x < 4" "0 \<le> y" "y < 4"
  shows "cycle4 (x, y) = 0 \<longleftrightarrow> (x, y) \<in> set [(0, 0), (2, 1), (1, 2), (3, 3)]"
  using assms
  by auto presburger+

lemma cycle1:
  assumes "0 \<le> x" "x < 4" "0 \<le> y" "y < 4"
  shows "cycle4 (x, y) = 1 \<longleftrightarrow> (x, y) \<in> set [(0, 1), (1, 3), (3, 2), (2, 0)]"
  using assms
  by auto presburger+

lemma cycle2:
  assumes "0 \<le> x" "x < 4" "0 \<le> y" "y < 4"
  shows "cycle4 (x, y) = 2 \<longleftrightarrow> (x, y) \<in> set [(0, 2), (2, 3), (1, 0), (3, 1)]"
  using assms
  by auto presburger+

lemma cycle3:
  assumes "0 \<le> x" "x < 4" "0 \<le> y" "y < 4"
  shows "cycle4 (x, y) = 3 \<longleftrightarrow> (x, y) \<in> set [(0, 3), (1, 1), (2, 2), (3, 0)]"
  using assms
  by auto presburger+

fun cycle :: "square \<Rightarrow> int \<times> int \<times> int" where
  "cycle (x, y) = (x div 4, y div 4, cycle4 (x mod 4, y mod 4))"

lemma cycles_card:
  shows "card (cycle ` squares) = (files * ranks) div 4"
sorry

lemma cycle4_exhausted:
  assumes "0 \<le> f1" "f1 < 4" "0 \<le> r1" "r1 < 4"
  assumes "0 \<le> f2" "f2 < 4" "0 \<le> r2" "r2 < 4"
  assumes "(f1, r1) \<noteq> (f2, r2)"
          "abs (f1 - f2) \<noteq> 1 \<or> abs (r1 - r2) \<noteq> 2"
          "abs (f1 - f2) \<noteq> 2 \<or> abs (r1 - r2) \<noteq> 1"
          "(f2, r2) \<noteq> (3 - f1, 3 - r1)"
  shows "cycle4 (f1, r1) \<noteq> cycle4 (f2, r2)"
sorry

lemma cycle_exhausted:
  assumes "\<forall> sq \<in> squares. board sq = Some Knight \<longrightarrow> \<not> attacks_knight sq board"
          "\<forall> sq \<in> squares. board sq = Some Knight \<longrightarrow> board (cycle_opposite sq) = Some Queen"
          "sq1 \<noteq> sq2" "sq1 \<in> squares" "sq2 \<in> squares" "board sq1 = Some Knight" "board sq2 = Some Knight"
  shows "cycle sq1 \<noteq> cycle sq2"
sorry

text \<open>guaranteed game lengths\<close>
*)
definition guaranteed_game_lengths :: "nat set" where
  "guaranteed_game_lengths = {K. \<exists> horst_strategy. \<forall> queenie_strategy. valid_queenie_strategy queenie_strategy \<longrightarrow> (\<exists> board. valid_game horst_strategy queenie_strategy K board)}"
(*
lemma guaranteed_game_lengths_geq:
  shows "nat ((files * ranks) div 4) \<in> guaranteed_game_lengths"
sorry

lemma valid_game_not_attacks_knight:
  assumes "valid_game horst_strategy queenie_strategy k board"
          "square \<in> squares" "board square = Some Knight"
        shows "\<not> attacks_knight square board"
sorry

lemma guaranteed_game_lengths_leq:
  shows "\<forall> k \<in> guaranteed_game_lengths. k \<le> (files * ranks) div 4"
sorry

lemma guaranteed_game_lengths_finite:
  shows "finite guaranteed_game_lengths"
sorry
*)
theorem IMO2018SL_C2:
  shows "Max guaranteed_game_lengths = nat ((files * ranks) div 4)"
  sorry
end

end


theory Lists
  imports Permutation While
begin

no_notation Set.image (infixr "`" 90)
  and times (infixr ";" 60)

(* Swap in lists preserve permutation *)
lemma id_take_n_1_nth_drop: "\<lbrakk>0 < j; j < length A\<rbrakk> \<Longrightarrow> A = take (j - 1) A @ A ! (j - 1) # A ! j # drop (j + 1) A"
  apply (subgoal_tac "A ! (j - 1) # A ! j # drop (j + 1) A = drop (j - 1) A")
  apply simp
proof -
  assume a1: "j < length A"
  assume a2: "0 < j"
  have "Suc j = j + 1"
    by presburger
  thus "A ! (j - 1) # A ! j # drop (j + 1) A = drop (j - 1) A"
    using a2 a1 by (metis (no_types) Cons_nth_drop_Suc Suc_diff_1 less_eq_Suc_le less_le_not_le)
qed

lemma take_swap: "j < length A \<Longrightarrow> take (j - 1) (A [j := A ! (j - 1), j - 1 := A ! j]) = take (j - 1) A"
by auto

lemma drop_swap: "0 < j \<Longrightarrow> drop (j + 1) (A [j := A ! (j - 1), j - 1 := A ! j]) = drop (j + 1) A"
by simp

lemma perm_swap_list: "\<lbrakk>0 < j; j < length A\<rbrakk> \<Longrightarrow> A [j := A ! (j - 1), j - 1 := A ! j] <~~> A"
proof -
  let ?A' = "(A [j := A ! (j - 1), j - 1 := A ! j])"
  assume assms: "0 < j" "j < length A"
  hence "?A' = take (j - 1) ?A' @ ?A' ! (j - 1) # ?A' ! j # drop (j + 1) ?A'"
    by (metis id_take_n_1_nth_drop length_list_update)
  also have "... = take (j - 1) A @ A ! j # A ! (j - 1) # drop (j + 1) A" using assms
    by (simp del: Nat.One_nat_def)
  finally show ?thesis
    by (metis perm_swap assms id_take_n_1_nth_drop)
qed

(* Array is sorted except in one place *)
definition sorted_but :: "('a :: ord) list \<Rightarrow> nat \<Rightarrow> bool" where
  "sorted_but A k \<equiv> \<forall>i j. i \<le> j \<and> j < length A \<and> i \<noteq> k \<and> k \<noteq> j \<longrightarrow> A ! i \<le> A ! j"

(* Sorted list lemmas *)
lemma sorted_singleton: "A \<noteq> [] \<Longrightarrow> sorted (take 1 A)"
  by simp

lemma take_sorted_equals_nth_mono: "n \<le> length A \<Longrightarrow> (\<forall>i j. i \<le> j \<and> j < n \<longrightarrow> A ! i \<le> A ! j) \<longleftrightarrow> sorted (take n A)"
  using sorted_equals_nth_mono by fastforce

lemma take_sorted_1: "\<lbrakk>sorted (take n A); n < length A; i \<le> j; j < n\<rbrakk> \<Longrightarrow> A ! i \<le> A ! j"
  using less_imp_le_nat take_sorted_equals_nth_mono by blast

lemma sorted_butI: "sorted A \<Longrightarrow> sorted_but A k"
  by (metis sorted_but_def sorted_nth_mono)

lemma take_sorted_butI: "sorted (take n A) \<Longrightarrow> sorted_but (take (Suc n) A) n"
  by (unfold sorted_equals_nth_mono sorted_but_def, auto)

lemma sorted_butE: "\<lbrakk>sorted_but A k; k + 1 < length A; A ! (k - 1) \<le> A ! k; A ! k \<le> A ! (k + 1)\<rbrakk> \<Longrightarrow> sorted A"
  apply (unfold sorted_equals_nth_mono sorted_but_def, auto)
  by (smt Suc_le_mono Suc_pred diff_le_self eq_iff leD le_0_eq le_less_Suc_eq le_less_linear le_less_trans)

lemma take_sorted_butE_0: "\<lbrakk>sorted_but (take n A) 0; A ! 0 \<le> A ! 1\<rbrakk> \<Longrightarrow> sorted (take n A)"
  by (smt One_nat_def Suc_eq_plus1 Suc_lessI length_greater_0_conv length_take min.absorb2 nat_le_linear nth_take order_refl sorted.Nil sorted_butE sorted_singleton take_all zero_diff)

lemma take_sorted_butE: "\<lbrakk>sorted_but (take n A) k; k < n; A ! (k - 1) \<le> A ! k; A ! k \<le> A ! (k + 1)\<rbrakk> \<Longrightarrow> sorted (take n A)"
  apply (unfold sorted_equals_nth_mono sorted_but_def, auto)
  by (smt Suc_pred eq_iff le_0_eq le_less_linear lessI less_eq_Suc_le less_le_trans order.strict_iff_order)

lemma take_sorted_butE_n: "\<lbrakk>sorted_but (take (Suc n) A) n; A ! (n - 1) \<le> A ! n\<rbrakk> \<Longrightarrow> sorted (take (Suc n) A)"
  apply (unfold sorted_equals_nth_mono sorted_but_def, auto)
  by (smt Suc_le_mono Suc_pred diff_le_self eq_iff leD le_0_eq le_less_Suc_eq le_less_linear le_less_trans)

end