(*
  File:    Harmonic_Numbers_Are_Not_Integers.thy
  Author:  Jose Manuel Rodriguez Caballero, University of Tartu
*)
section \<open>Harmonic numbers are not integers, except for the trivial case of 1\<close>
theory Harmonic_Numbers_Are_Not_Integers

imports
  Complex_Main
  Pnorm
begin

text \<open>
 In 1915, L. Theisinger ~\cite{theisinger1915bemerkung} proved that, except for the trivial
 case of 1, the harmonic numbers are not integers. In 1918,
 J. K{\"u}rsch{\'a}k  ~\cite{kurschak1918harmonic} provided a sufficient condition for the
 difference between two harmonic numbers not to be an integer. We formalize these result as theorems
 @{text Taeisinger} and @{text Kurschak}, respectively. These results will be deduced from the
 computation of the 2-adic norm of harmonic numbers (lemma @{text harmonic_numbers_2norm}).
\<close>

subsection \<open>Main definition\<close>

text \<open>
 We start by defining the harmonic numbers.
\<close>

fun harmonic :: \<open>nat \<Rightarrow> rat\<close> where
  \<open>harmonic 0 = 0\<close> |
  \<open>harmonic (Suc n) = harmonic n + Fract 1 (Suc n)\<close>

lemma harmonic_explicit:
  \<open>harmonic n = (\<Sum>k = 1..n. (Fract 1 (of_nat k)))\<close>
proof(induction n)
  case 0
  thus ?case
    by simp
next
  case (Suc n)
  thus ?case
    by simp
qed

lemma harmonic_diff_explicit:
  \<open>n \<ge> m+1 \<Longrightarrow> harmonic n - harmonic m = (\<Sum>k = m+1..n. (Fract 1 (of_nat k)))\<close>
proof-
  assume \<open>n \<ge> m+1\<close>
  then obtain k::nat where \<open>n = m + 1 + k\<close>
    using le_Suc_ex
    by blast
  show ?thesis
  proof -
    have "\<forall>n na f nb. \<not> (n::nat) \<le> na + 1 \<or> sum f {n..na + nb} = (sum f {n..na}::rat) + sum f {na + 1..na + nb}"
      by (meson sum.ub_add_nat)
    then show ?thesis
      by (metis (no_types) \<open>n = m + 1 + k\<close> add_diff_cancel_left' harmonic_explicit le_add2 linordered_field_class.sign_simps(1))
  qed
qed

subsection \<open>Auxiliary result\<close>

lemma sum_last:
  fixes n::nat and a::\<open>nat \<Rightarrow> real\<close>
  assumes \<open>n \<ge> 2\<close>
  shows \<open>(\<Sum>k = 1..n - 1. (a k)) + (a n) = (\<Sum>k = 1..n. (a k))\<close>
  using \<open>n \<ge> 2\<close>
  apply auto
  by (smt Suc_leD le_add_diff_inverse numeral_1_eq_Suc_0 numeral_2_eq_2 numeral_One plus_1_eq_Suc sum.nat_ivl_Suc')

lemma harmonic_numbers_2norm:
  fixes n :: nat
  assumes \<open>n \<ge> 1\<close>
  shows \<open>pnorm 2 (harmonic n) = 2^(nat(\<lfloor>log 2 n\<rfloor>))\<close>
proof(cases \<open>n = 1\<close>)
  case True
  have \<open>prime (2::nat)\<close>
    by simp
  hence \<open>harmonic (1::nat) = 1\<close>
    by (simp add: One_rat_def)
  hence \<open>pnorm 2 (harmonic (1::nat)) = pnorm 2 1\<close>
    by simp
  also have \<open>\<dots> = 1\<close>
    by (simp add: pnorm_1)
  also have \<open>\<dots> = 2^(nat(\<lfloor>log 2 1\<rfloor>))\<close>
  proof-
    have \<open>log 2 1 = 0\<close>
      by simp
    hence \<open>\<lfloor>log 2 1\<rfloor> = 0\<close>
      by simp
    thus ?thesis
      by auto
  qed
  finally show ?thesis
    using \<open>n = 1\<close>
    by auto
next
  case False
  hence \<open>n \<ge> 2\<close>
    using \<open>n \<ge> 1\<close>
    by auto
  define l where \<open>l = nat(\<lfloor>log 2 n\<rfloor>)\<close>
  define H where \<open>H = (\<Sum>k = 1..n. (Fract 1 (of_nat k)))\<close>
  have \<open>prime (2::nat)\<close>
    by simp
  have \<open>l \<ge> 1\<close>
  proof-
    have \<open>log 2 n \<ge> 1\<close>
      using \<open>n \<ge> 2\<close>
      by auto
    hence \<open>\<lfloor>log 2 n\<rfloor> \<ge> 1\<close>
      by simp
    thus ?thesis
      using \<open>l = nat(\<lfloor>log 2 n\<rfloor>)\<close> \<open>1 \<le> \<lfloor>log 2 (real n)\<rfloor>\<close> \<open>l = nat \<lfloor>log 2 (real n)\<rfloor>\<close> nat_mono
      by presburger
  qed
  hence \<open>(2::nat)^l \<ge> 2\<close>
  proof -
    have "(2::nat) ^ 1 \<le> 2 ^ l"
      by (metis \<open>1 \<le> l\<close> one_le_numeral power_increasing)
    then show ?thesis
      by (metis semiring_normalization_rules(33))
  qed
  have \<open>pnorm 2 ((2^l) * H) = 1\<close>
  proof-
    define pre_H where \<open>pre_H = (\<Sum>k = 1..(2^l-1). (Fract 1 (of_nat k)))\<close>
    define post_H where \<open>post_H = (\<Sum>k = (2^l+1)..n. (Fract 1 (of_nat k)))\<close>
    have \<open>H = pre_H + (Fract 1 (of_nat (2^l))) + post_H\<close>
    proof-
      have \<open>pre_H + (Fract 1 (of_nat (2^l))) = (\<Sum>k = 1..(2^l-1). (Fract 1 (of_nat k)))
                  + (Fract 1 (of_nat (2^l)))\<close>
        unfolding pre_H_def
        by auto
      also have \<open>\<dots> = (\<Sum>k = 1..2^l. (Fract 1 (of_nat k)))\<close>
      proof-
        have \<open>(\<Sum>k = 1..2 ^ l - 1. real_of_rat (Fract 1 (int k)))
                + real_of_rat (Fract 1 (int (2 ^ l)))
                = (\<Sum>k = 1..2 ^ l. real_of_rat (Fract 1 (int k)))\<close>
          using sum_last[where n = \<open>2^l\<close> and a = \<open>(\<lambda> k. of_rat (Fract 1 (of_nat k)))\<close>]
            \<open>(2::nat)^l \<ge> 2\<close>
          by auto
        moreover have \<open>(\<Sum>k = 1..2 ^ l - 1. real_of_rat (Fract 1 (int k)))
                + real_of_rat (Fract 1 (int (2 ^ l)))
                = real_of_rat ((\<Sum>k = 1..2 ^ l - 1. (Fract 1 (int k)))
                +  (Fract 1 (int (2 ^ l))))\<close>
          by (simp add: of_rat_add of_rat_sum)
        moreover have \<open>(\<Sum>k = 1..2 ^ l. real_of_rat (Fract 1 (int k)))
                      = real_of_rat (\<Sum>k = 1..2 ^ l. (Fract 1 (int k)))\<close>
          by (simp add: of_rat_sum)
        ultimately have \<open>real_of_rat ((\<Sum>k = 1..2 ^ l - 1. (Fract 1 (int k)))
                +  (Fract 1 (int (2 ^ l)))) = real_of_rat (\<Sum>k = 1..2 ^ l. (Fract 1 (int k)))\<close>
          by simp
        thus ?thesis
          by simp
      qed
      finally have \<open>pre_H + Fract 1 (int (2 ^ l)) =
                  (\<Sum>k = 1..2 ^ l. Fract 1 (int k))\<close>
        by blast
      moreover have \<open>(\<Sum>k = 1..2 ^ l. Fract 1 (int k)) + post_H = H\<close>
      proof-
        have \<open>(\<Sum>k = 1..2 ^ l. Fract 1 (int k)) + post_H
              = (\<Sum>k = 1..2 ^ l. Fract 1 (int k)) +
                (\<Sum>k = 2 ^ l + 1..n. Fract 1 (int k))\<close>
          unfolding post_H_def
          by blast
        also have \<open>\<dots>  = (\<Sum>k = 1..n. Fract 1 (int k))\<close>
        proof-
          have \<open>2 ^ l \<le> n\<close>
          proof-
            have \<open>2 ^ l =  2 ^ nat \<lfloor>log 2 (real n)\<rfloor>\<close>
              unfolding l_def
              by simp
            also have \<open>\<dots> =  2 powr (nat \<lfloor>log 2 (real n)\<rfloor>)\<close>
              by (simp add: powr_realpow)
            also have \<open>\<dots> \<le>  2 powr (log 2 (real n))\<close>
            proof-
              have \<open>\<lfloor>log 2 (real n)\<rfloor> \<le> log 2 (real n)\<close>
                by simp
              moreover have \<open>(2::real) > 1\<close>
                by simp
              ultimately show ?thesis
                using Transcendental.powr_le_cancel_iff[where x = 2
                    and a = "\<lfloor>log 2 (real n)\<rfloor>" and b = "log 2 (real n)"]
                using assms
                by auto
            qed
            also have \<open>\<dots> = n\<close>
            proof-
              have \<open>(2::real) > 1\<close>
                by simp
              moreover have \<open>n > 0\<close>
                using \<open>n \<ge> 2\<close>
                by auto
              ultimately show ?thesis
                by simp
            qed
            finally show ?thesis
              by simp
          qed
          thus ?thesis
            by (metis le_add2 le_add_diff_inverse sum.ub_add_nat)
        qed
        finally have \<open>(\<Sum>k = 1..2 ^ l. Fract 1 (int k)) + post_H = (\<Sum>k = 1..n. Fract 1 (int k))\<close>
          by blast
        thus ?thesis
          unfolding pre_H_def H_def
          by blast
      qed
      ultimately show ?thesis
        by simp
    qed
    moreover have \<open>pnorm 2 ((2^l) * (Fract 1 (of_nat (2^l)))) = 1\<close>
    proof-
      have \<open>(2::nat)^l \<noteq> 0\<close>
        by auto
      hence \<open>((2::nat)^l) * (Fract 1 (of_nat ((2::nat)^l))) = 1\<close>
      proof -
        have "int (2 ^ l) \<noteq> 0"
          using \<open>2 ^ l \<noteq> 0\<close> by linarith
        hence "1 = Fract (int (2 ^ l) * 1) (int (2 ^ l) * 1)"
          by (metis (no_types) One_rat_def mult_rat_cancel)
        thus ?thesis
          by (metis (full_types) Fract_of_nat_eq mult_rat of_rat_1 of_rat_mult of_rat_of_nat_eq semiring_normalization_rules(7))
      qed
      hence \<open>pnorm 2 (((2::rat)^l) * (Fract 1 (of_nat ((2::nat)^l)))) = pnorm 2 1\<close>
        by (metis (mono_tags, lifting) of_nat_numeral of_nat_power of_rat_1 of_rat_eq_iff
            of_rat_mult of_rat_of_nat_eq)
      also have \<open>\<dots> = 1\<close>
        using pnorm_1
        by blast
      finally show ?thesis
        by blast
    qed
    moreover have \<open>pnorm 2 ((2^l) * pre_H) < 1\<close>
    proof-
      have \<open>(2^l) * pre_H = (\<Sum>k = 1..2 ^ l - 1. (2^l) * (Fract 1 (int k)))\<close>
        unfolding pre_H_def
        using Groups_Big.semiring_0_class.sum_distrib_left[where r = \<open>2^l\<close>
            and f = \<open>(\<lambda> k. Fract 1 (int k))\<close> and A = \<open>{1..(2^l - 1)}\<close>]
        by blast
      also have \<open>\<dots> = (\<Sum>k = 1..2 ^ l - 1. (Fract (2^l) (int k)))\<close>
        by (metis Fract_of_nat_eq mult.left_neutral mult.right_neutral mult_rat of_nat_numeral
            of_nat_power)
      finally have \<open>2 ^ l * pre_H =
              (\<Sum>k = 1..2 ^ l - 1. Fract (2 ^ l) (int k))\<close>
        by blast
      hence \<open>pnorm 2 (2 ^ l * pre_H) =
              pnorm 2 (\<Sum>k = 1..2 ^ l - 1. Fract (2 ^ l) (int k))\<close>
        by simp
      also have \<open>\<dots> \<le>
              Max ((\<lambda> k. pnorm 2 (Fract (2 ^ l) (int k)))`{1..2^l-1})\<close>
      proof-
        have \<open>pnorm 2 (\<Sum>k = 1..2 ^ l - 1. Fract (2 ^ l) (int k))
           = pnorm 2 (sum (\<lambda> k. Fract (2 ^ l) (int k)) {1..(2::nat)^l-1})\<close>
          by blast
        also have \<open>\<dots> \<le> Max ((\<lambda> k. pnorm 2 (Fract (2 ^ l) (int k)))`{1..2^l-1})\<close>
          using \<open>prime 2\<close>  pnorm_ultrametric_sum[where p = 2 and A = \<open>{1..2^l-1}\<close>
              and x = \<open>(\<lambda> k. (Fract (2 ^ l) (int k)))\<close>]
          by (metis Nat.le_diff_conv2 \<open>2 \<le> 2 ^ l\<close> atLeastatMost_empty_iff2 finite_atLeastAtMost
              nat_1_add_1 one_le_power prime_ge_1_nat)
        finally show ?thesis
          using \<open>pnorm 2 (\<Sum>k = 1..2 ^ l - 1. Fract (2 ^ l) (int k)) \<le> (MAX k\<in>{1..2 ^ l - 1}.
              pnorm 2 (Fract (2 ^ l) (int k)))\<close>
          by blast
      qed
      also have \<open>\<dots> < 1\<close>
      proof-
        have \<open>finite ((\<lambda> k. pnorm 2 (Fract (2 ^ l) (int k)))`{1..2^l-1})\<close>
          by blast
        moreover have \<open>((\<lambda> k. pnorm 2 (Fract (2 ^ l) (int k)))`{1..2^l-1}) \<noteq> {}\<close>
        proof-
          have \<open>(1::nat) \<le> (2::nat)^l-1\<close>
            using \<open>(2::nat)^l \<ge> 2\<close>
            by auto
          hence \<open>{(1::nat)..(2::nat)^l-1} \<noteq> {}\<close>
            using Set_Interval.order_class.atLeastatMost_empty_iff2[where a = "1::nat"
                and b = "(2::nat)^l - 1"]
            by auto
          thus ?thesis
            by blast
        qed
        moreover have \<open>x \<in> ((\<lambda> k. pnorm 2 (Fract (2 ^ l) (int k)))`{1..2^l-1}) \<Longrightarrow> x < 1\<close>
          for x
        proof-
          assume \<open>x \<in> ((\<lambda> k. pnorm 2 (Fract (2 ^ l) (int k)))`{1..2^l-1})\<close>
          then obtain k where \<open>x = pnorm 2 (Fract (2 ^ l) (int k))\<close> and \<open>k \<in> {1..2^l-1}\<close>
            by blast
          have \<open>pnorm 2 (Fract (2 ^ l) (int k)) < 1\<close>
          proof-
            have \<open>Fract (2 ^ l) (int k) = (2 ^ l)*(Fract 1 (int k))\<close>
              by (metis (no_types) Fract_of_nat_eq mult_numeral_1 mult_of_nat_commute mult_rat
                  numeral_One of_nat_numeral of_nat_power)
            hence \<open>pnorm 2 (Fract (2 ^ l) (int k)) = pnorm 2 ((2 ^ l)*(Fract 1 (int k)))\<close>
              by simp
            also have \<open>\<dots> < 1\<close>
            proof-
              have \<open>pnorm 2 ((2::rat)^l) = 1/(2::nat)^l\<close>
                using  \<open>prime (2::nat)\<close> pnorm_primepow[where p = "(2::nat)"]
                by auto
              moreover have \<open>pnorm 2 (Fract 1 k) < (2::nat)^l\<close>
              proof-
                have \<open>2 powr (- pval 2 (Fract 1 k)) < (2::nat)^l\<close>
                proof-
                  have \<open>pval 2 (Fract k 1) < l\<close>
                  proof-
                    have \<open>pval 2 (Fract k 1) = multiplicity (2::int) k\<close>
                      using \<open>prime 2\<close>  pval_integer[where p = 2 and k = k]
                      by auto
                    also have \<open>\<dots> < l\<close>
                    proof(rule classical)
                      assume \<open>\<not>(multiplicity 2 (int k) < int l)\<close>
                      hence \<open>multiplicity 2 (int k) \<ge> int l\<close>
                        by simp
                      hence \<open>((2::nat)^l) dvd k\<close>
                        by (metis (full_types) int_dvd_int_iff multiplicity_dvd' of_nat_numeral
                            of_nat_power zle_int)
                      hence \<open>(2::nat)^l \<le> k\<close>
                        using \<open>k \<in> {1..2 ^ l - 1}\<close> dvd_nat_bounds
                        by auto
                      moreover have \<open>k < (2::nat)^l\<close>
                        using  \<open>k\<in>{1..(2::nat)^l - 1}\<close>
                        by auto
                      ultimately show ?thesis
                        by linarith
                    qed
                    finally show ?thesis
                      by blast
                  qed
                  hence \<open>- pval 2 (Fract 1 k) < l\<close>
                    using \<open>prime 2\<close> pval_inverse[where p = "2" and x = \<open>Fract 1 k\<close>]
                      Fract_of_int_quotient
                    by auto
                  hence \<open>2 powr (- pval 2 (Fract 1 k)) < 2 powr l\<close>
                    by auto
                  also have \<open>\<dots> = (2::nat)^l\<close>
                  proof -
                    have f1: "\<not> 2 \<le> (1::real)"
                      by auto
                    have f2: "\<forall>x1. ((1::real) < x1) = (\<not> x1 \<le> 1)"
                      by force
                    have "real (2 ^ l) = 2 ^ l"
                      by simp
                    hence "real l = log 2 (real (2 ^ l))"
                      using f2 f1 by (meson log_of_power_eq)
                    thus ?thesis
                      by simp
                  qed
                  finally show ?thesis
                    by blast
                qed
                moreover have \<open>pnorm 2 (Fract 1 k) = 2 powr (- pval 2 (Fract 1 k))\<close>
                proof-
                  have \<open>k \<noteq> 0\<close>
                    using \<open>k\<in>{1..2^l - 1}\<close>
                    by simp
                  hence \<open>Fract 1 k \<noteq> 0\<close>
                    by (smt Fract_le_zero_iff le_numeral_extra(3) of_nat_le_0_iff)
                  thus \<open>pnorm 2 (Fract 1 k) = 2 powr (- pval 2 (Fract 1 k))\<close>
                    using \<open>prime 2\<close>
                    by (simp add: pnorm_simplified)
                qed
                ultimately show ?thesis
                  by simp
              qed
              moreover have \<open>pnorm 2 ((2::rat)^l) > 0\<close>
              proof-
                have \<open>(2::rat)^l \<noteq> 0\<close>
                  by simp
                moreover have \<open>pnorm 2 ((2::rat)^l) \<ge> 0\<close>
                  using \<open>prime (2::nat)\<close> pnorm_geq_zero
                  by simp
                ultimately show ?thesis
                  using pnorm_eq_zero \<open>prime (2::nat)\<close>
                  by (simp add: less_eq_real_def)
              qed
              moreover have \<open>pnorm 2 (Fract 1 k) > 0\<close>
              proof-
                have \<open>Fract 1 k \<noteq> 0\<close>
                  using \<open>k \<in> {1..2^l-1}\<close>
                  by (metis Fract_le_zero_iff atLeastAtMost_iff int.nat_pow_one int.zero_not_one int_ops(1) less_le_not_le less_one linorder_neqE_nat nat_int_comparison(2) not_less0 order_refl power2_less_eq_zero_iff)
                moreover have \<open>pnorm 2 (Fract 1 k) \<ge> 0\<close>
                  using \<open>prime (2::nat)\<close> pnorm_geq_zero
                  by blast
                ultimately show ?thesis
                  using pnorm_eq_zero \<open>prime (2::nat)\<close>
                  by (simp add: less_eq_real_def)
              qed
              ultimately have \<open>(pnorm 2 ((2::rat)^l))*(pnorm 2 (Fract 1 k))
                  < (1/(2::nat)^l)*((2::nat)^l)\<close>
                by simp
              also have \<open>\<dots> = 1\<close>
              proof-
                have \<open>(2::nat)^l \<noteq> 0\<close>
                  by simp
                thus ?thesis
                  by simp
              qed
              finally have \<open>(pnorm 2 ((2::rat)^l))*(pnorm 2 (Fract 1 k)) < 1\<close>
                by blast
              moreover have \<open>(pnorm 2 ((2::rat)^l))*(pnorm 2 (Fract 1 k))
                  = pnorm 2 (2 ^ l * Fract 1 (int k))\<close>
                using \<open>prime 2\<close>
                by (simp add: pnorm_multiplicativity)
              ultimately show ?thesis
                by simp
            qed
            finally show \<open>pnorm 2 (Fract (2 ^ l) (int k)) < 1\<close>
              by blast
          qed
          thus ?thesis
            using \<open>x = pnorm 2 (Fract (2 ^ l) (int k))\<close>
            by blast
        qed
        ultimately show ?thesis
          using Lattices_Big.linorder_class.Max_less_iff
            [where A = "((\<lambda> k. pnorm 2 (Fract (2 ^ l) (int k)))`{1..2^l-1})"]
          by blast
      qed
      finally show \<open>pnorm 2 (2 ^ l * pre_H) < 1\<close>
        by blast
    qed
    ultimately have \<open>pnorm 2 ((2^l) * (Fract 1 (of_nat (2^l))) + (2^l) * pre_H) = 1\<close>
      using pnorm_unit_ball[where p = 2 and x = "(2^l) *  (Fract 1 (of_nat (2^l)))" and y = "(2^l) * pre_H"]
      by simp
    moreover have \<open>pnorm 2 ((2^l) * post_H) < 1\<close>
    proof(cases \<open>2^l + 1 \<le> n\<close>)
      case True
      have \<open>pnorm 2 ((2^l) * post_H) = pnorm 2 (\<Sum>k = 2 ^ l + 1..n.  (2 ^ l)*(Fract 1 k))\<close>
      proof-
        have \<open>(2^l) * post_H = (\<Sum>k = 2 ^ l+1..n. (2 ^ l)*(Fract 1 k))\<close>
          unfolding post_H_def
          using Groups_Big.semiring_0_class.sum_distrib_left[where r = \<open>2^l\<close>
              and f = \<open>(\<lambda> k. Fract 1 k)\<close> and A = \<open>{2 ^ l+1..n}\<close>]
          by auto
        thus ?thesis
          by simp
      qed
      also have \<open>\<dots>
           = pnorm 2 (sum (\<lambda> k. (2 ^ l)*(Fract 1 k)) {2 ^ l + 1..n})\<close>
        by blast
      also have \<open>\<dots>
           \<le> Max ((\<lambda> k. pnorm 2 ((2 ^ l)*(Fract 1 k))) ` {2 ^ l + 1..n})\<close>
      proof-
        have \<open>finite {2 ^ l + 1..n}\<close>
          by simp
        moreover have \<open>{2 ^ l + 1..n} \<noteq> {}\<close>
          using True
          by auto
        ultimately show ?thesis
          using \<open>prime 2\<close>  pnorm_ultrametric_sum[where p = 2 and A = \<open>{2 ^ l + 1..n}\<close>
              and x = \<open>(\<lambda> k. (2 ^ l)*(Fract 1 k))\<close>]
          by auto
      qed
      finally have \<open>pnorm 2 ((2^l) * post_H) \<le>
          Max ((\<lambda> k. pnorm 2 ((2 ^ l)*(Fract 1 k))) ` {2 ^ l + 1..n})\<close>
        using \<open>pnorm 2 (2 ^ l * post_H) = pnorm 2 (\<Sum>k = 2 ^ l + 1..n. 2 ^ l * Fract 1 (int k))\<close> \<open>pnorm 2 (\<Sum>k = 2 ^ l + 1..n. 2 ^ l * Fract 1 (int k)) \<le> (MAX k\<in>{2 ^ l + 1..n}. pnorm 2 (2 ^ l * Fract 1 (int k)))\<close>
        by linarith
      moreover have \<open>((\<lambda> k. pnorm 2 ((2 ^ l)*(Fract 1 k))) ` {2 ^ l + 1..n}) \<noteq> {}\<close>
        using True
        by auto
      moreover have \<open>finite ((\<lambda> k. pnorm 2 ((2 ^ l)*(Fract 1 k))) ` {2 ^ l + 1..n})\<close>
        by blast
      moreover have \<open>x \<in> (\<lambda> k. pnorm 2 ((2 ^ l)*(Fract 1 k))) ` {2 ^ l + 1..n} \<Longrightarrow> x < 1\<close>
        for x
      proof-
        assume \<open>x \<in> (\<lambda> k. pnorm 2 ((2 ^ l)*(Fract 1 k))) ` {2 ^ l + 1..n}\<close>
        then obtain t where \<open>t \<in> {2 ^ l + 1..n}\<close> and \<open>x = pnorm 2 ((2 ^ l)*(Fract 1 t))\<close>
          by auto
        have  \<open>x = (pnorm 2 (2 ^ l)) * (pnorm 2 (Fract 1 t))\<close>
          using \<open>prime 2\<close> \<open>x = pnorm 2 ((2 ^ l)*(Fract 1 t))\<close> pnorm_multiplicativity
          by auto
        moreover have \<open>pnorm 2 (2 ^ l) = 1/(2^l)\<close>
          using \<open>prime 2\<close> pval_primepow[where p = "2::nat"]
          by (metis of_int_numeral of_nat_numeral pnorm_primepow)
        moreover have \<open>pnorm 2 (Fract 1 t) < 2^l\<close>
        proof(rule classical)
          assume \<open>\<not> (pnorm 2 (Fract 1 t) < 2^l)\<close>
          hence \<open>pnorm 2 (Fract 1 t) \<ge> 2^l\<close>
            by auto
          moreover have \<open>2 powr l = 2^l\<close>
            using powr_realpow
            by auto
          ultimately have \<open>pnorm 2 (Fract 1 t) \<ge> 2 powr l\<close>
            by auto
          moreover have \<open>pnorm 2 (Fract 1 t) = 2 powr (-pval 2 (Fract 1 t))\<close>
          proof-
            have \<open>t \<noteq> 0\<close>
              using \<open>t \<in> {2^l + 1 .. n}\<close>
              by simp
            hence \<open>Fract 1 t \<noteq> 0\<close>
            proof -
              have "\<not> int t \<le> 0"
                by (metis \<open>t \<noteq> 0\<close> of_nat_le_0_iff)
              hence "\<not> Fract 1 (int t) \<le> 0"
                by (simp add: Fract_le_zero_iff)
              thus ?thesis
                by linarith
            qed
            thus ?thesis
              using pnorm_simplified
              by simp
          qed
          ultimately have \<open>-pval 2 (Fract 1 t) \<ge> l\<close>
            by simp
          hence \<open>-(multiplicity 2 (fst (quotient_of (Fract 1 t))))
               + (multiplicity 2 (snd (quotient_of (Fract 1 t))))
                     \<ge> l\<close>
            unfolding pval_def
            by auto
          have \<open>quotient_of (Fract (1::int) t) = (1, t)\<close>
          proof-
            have \<open>coprime (1::int) t\<close>
              by simp
            moreover have \<open>t > 0\<close>
              using \<open>t \<in> {2^l + 1 .. n}\<close>
              by simp
            ultimately show ?thesis
              by (simp add: quotient_of_Fract)
          qed
          hence \<open>fst (quotient_of (Fract 1 t)) = 1\<close>
            by simp
          moreover have \<open>snd (quotient_of (Fract 1 t)) = t\<close>
            using \<open>quotient_of (Fract (1::int) t) = (1, t)\<close>
            by auto
          ultimately have \<open>- int(multiplicity (2::int) 1) + int(multiplicity (2::int) t) \<ge> l\<close>
            using \<open>-(multiplicity 2 (fst (quotient_of (Fract 1 t))))
               + (multiplicity 2 (snd (quotient_of (Fract 1 t))))
                     \<ge> l\<close>
            by auto
          moreover have \<open>multiplicity (2::int) 1 = 0\<close>
            by simp
          ultimately have \<open>multiplicity (2::int) t \<ge> l\<close>
            by auto
          hence \<open>2^l dvd t\<close>
            by (metis int_dvd_int_iff multiplicity_dvd' of_nat_numeral of_nat_power)
          hence \<open>\<exists> k::nat. 2^l * k = t\<close>
            by auto
          then obtain k::nat where \<open>2^l * k = t\<close>
            by blast
          have \<open>k \<ge> 2\<close>
          proof(rule classical)
            assume \<open>\<not>(k \<ge> 2)\<close>
            hence \<open>k < 2\<close>
              by simp
            moreover have \<open>k \<noteq> 0\<close>
            proof(rule classical)
              assume \<open>\<not>(k \<noteq> 0)\<close>
              hence \<open>k = 0\<close>
                by simp
              hence \<open>t = 0\<close>
                using \<open>2^l * k = t\<close>
                by auto
              thus ?thesis
                using \<open>t \<in> {2^l + 1 .. n}\<close>
                by auto
            qed
            moreover have \<open>k \<noteq> 1\<close>
            proof(rule classical)
              assume \<open>\<not>(k \<noteq> 1)\<close>
              hence \<open>k = 1\<close>
                by simp
              hence \<open>t = 2^l\<close>
                using \<open>2^l * k = t\<close>
                by auto
              thus ?thesis
                using \<open>t \<in> {2^l + 1 .. n}\<close>
                by auto
            qed
            ultimately show ?thesis
              by auto
          qed
          hence \<open>2^(Suc l) \<le> t\<close>
            using \<open>2 ^ l * k = t\<close>
            by auto
          hence \<open>2^(Suc l) \<le> n\<close>
            using \<open>t \<in> {2^l + 1 .. n}\<close>
            by auto
          moreover have \<open>n < 2^(Suc l)\<close>
          proof -
            have f1: "\<forall>n na. (n \<le> na) = (int n + - 1 * int na \<le> 0)"
              by auto
            have f2: "int (Suc (nat \<lfloor>log 2 (real n)\<rfloor>)) + - 1 * int (Suc l) \<le> 0"
              by (simp add: l_def)
            have f3: "(- 1 * log 2 (real n) + real (Suc l) \<le> 0) = (0 \<le> log 2 (real n) + - 1 * real (Suc l))"
              by fastforce
            have f4: "real (Suc l) + - 1 * log 2 (real n) = - 1 * log 2 (real n) + real (Suc l)"
              by auto
            have f5: "\<forall>n na. \<not> 2 ^ n \<le> na \<or> real n + - 1 * log 2 (real na) \<le> 0"
              by (simp add: le_log2_of_power)
            have f6: "\<forall>x0 x1. (- 1 * int x0 + int (2 ^ x1) \<le> 0) = (0 \<le> int x0 + - 1 * int (2 ^ x1))"
              by auto
            have f7: "\<forall>x0 x1. int (2 ^ x1) + - 1 * int x0 = - 1 * int x0 + int (2 ^ x1)"
              by auto
            have "\<not> 0 \<le> log 2 (real n) + - 1 * real (Suc l)"
              using f2 by linarith
            then have "\<not> 0 \<le> int n + - 1 * int (2 ^ Suc l)"
              using f7 f6 f5 f4 f3 f1 by (metis (no_types))
            then show ?thesis
              by linarith
          qed
          ultimately show ?thesis
            by auto
        qed
        moreover have \<open>pnorm 2 (2 ^ l) \<ge> 0\<close>
          using \<open>prime 2\<close> pnorm_geq_zero
          by blast
        moreover have \<open>pnorm 2 (Fract 1 t) \<ge> 0\<close>
          using \<open>prime 2\<close> pnorm_geq_zero
          by blast
        ultimately show ?thesis
          by simp
      qed
      ultimately show ?thesis
        by (smt Max_in)
    next
      case False
      hence \<open>2 ^ l + 1 > n\<close>
        by simp
      hence \<open>{2 ^ l + 1..n} = {}\<close>
        by simp
      hence \<open>post_H = 0\<close>
        unfolding post_H_def
        by simp
      hence \<open>(2^l) * post_H = 0\<close>
        by (simp add: \<open>post_H = 0\<close>)
      thus ?thesis
        unfolding pnorm_def
        by auto
    qed
    ultimately have \<open>pnorm 2 (((2^l) *  (Fract 1 (of_nat (2^l)))
                                  + (2^l) * pre_H) + ((2^l) * post_H)) = 1\<close>
      using pnorm_unit_ball[where p = 2 and x = "(2^l) *  (Fract 1 (of_nat (2^l))) + (2^l) * pre_H"
          and y = "(2^l) * post_H"]
      by simp
    thus ?thesis
      by (simp add: \<open>H = pre_H + Fract 1 (int (2 ^ l)) + post_H\<close> semiring_normalization_rules(24) semiring_normalization_rules(34))
  qed
  hence \<open>(pnorm 2 (2^l)) * (pnorm 2 H) = 1\<close>
    using pnorm_multiplicativity
    by auto
  hence \<open>(1/2^l) * (pnorm 2 H) = 1\<close>
  proof-
    have \<open>prime (2::nat)\<close>
      by simp
    hence \<open>pnorm 2 (2^l) = 1/2^l\<close>
      using pnorm_primepow[where p = 2 and l = "l"]
      by simp
    thus ?thesis
      using \<open>pnorm 2 (2 ^ l) * pnorm 2 H = 1\<close>
      by auto
  qed
  hence \<open>pnorm 2 H = 2^l\<close>
    by simp
  thus ?thesis
    using H_def l_def harmonic_explicit[where n = n]
    by simp
qed

subsection \<open>Main results\<close>

text\<open>The following result is due to L. Taeisinger ~\cite{theisinger1915bemerkung}.\<close>
theorem Taeisinger:
  fixes n :: nat
  assumes \<open>n \<ge> 2\<close>
  shows \<open>harmonic n \<notin> \<int>\<close>
proof-
  have \<open>pnorm 2 (\<Sum>k = 1..n. (Fract 1 (of_nat k)) ) > 1\<close>
    using harmonic_numbers_2norm[where n = "n"] \<open>n \<ge> 2\<close> harmonic_explicit
    by auto
  thus ?thesis
  proof -
    have "\<not> pnorm 2 (\<Sum>n = 1..n. Fract 1 (int n)) \<le> 1"
      using \<open>1 < pnorm 2 (\<Sum>k = 1..n. Fract 1 (int k))\<close> by linarith
    then show ?thesis
      by (metis (no_types) harmonic_explicit integers_pnorm_D two_is_prime_nat)
  qed
qed

text\<open>The following result is due to J. K{\"u}rsch{\'a}k  ~\cite{kurschak1918harmonic}.\<close>
theorem Kurschak:
  fixes n m :: nat
  assumes \<open>m + 2 \<le> n\<close>
  shows \<open>harmonic n - harmonic m \<notin> \<int>\<close>
proof(cases \<open>2*m \<le> n\<close>)
  case True
  show ?thesis
  proof(cases \<open>m = 0\<close>)
    case True
    thus ?thesis
      using Taeisinger assms
      by auto
  next
    case False
    hence \<open>m \<ge> 1\<close>
      by simp
    have \<open>n \<ge> 2\<close>
      using \<open>m+2 \<le> n\<close>
      by auto
    have \<open>prime (2::nat)\<close>
      by auto
    have \<open>harmonic n = (harmonic n - harmonic m) + (harmonic m)\<close>
      by simp
    hence \<open>pnorm 2 (harmonic n) \<le> max (pnorm 2 (harmonic n - harmonic m)) (pnorm 2 (harmonic m))\<close>
      using \<open>prime 2\<close> pnorm_ultrametric[where p = "2::nat" and x = "harmonic n - harmonic m"
          and y = "harmonic m"]
      by auto
    moreover have \<open>pnorm 2 (harmonic m) < pnorm 2 (harmonic n)\<close>
    proof-
      have \<open>pnorm 2 (harmonic m) =  2 ^ nat \<lfloor>log 2 (real m)\<rfloor>\<close>
        using harmonic_numbers_2norm[where n = "n"] \<open>m \<ge> 1\<close>
        by (meson \<open>1 \<le> m\<close> harmonic_numbers_2norm)
      moreover have \<open>pnorm 2 (harmonic n) =  2 ^ nat \<lfloor>log 2 (real n)\<rfloor>\<close>
        using harmonic_numbers_2norm[where n = "n"] \<open>2 \<le> n\<close>
        by linarith
      moreover have \<open>(2::nat) ^ nat \<lfloor>log 2 (real m)\<rfloor> < (2::nat) ^ nat \<lfloor>log 2 (real n)\<rfloor>\<close>
      proof-
        have \<open>log 2 (real m) + 1 = log 2 (real m) + log 2 (2::real)\<close>
        proof-
          have \<open>log 2 (real 2) = 1\<close>
            by simp
          thus ?thesis
            by simp
        qed
        also have \<open>\<dots> = log 2 ((real m) * (2::real)) \<close>
        proof-
          have \<open>(2::real) > 0\<close>
            by simp
          moreover have \<open>(2::real) \<noteq> 1\<close>
            by simp
          moreover have \<open>m > 0\<close>
            using False
            by auto
          ultimately show ?thesis
            using log_mult[where a = 2 and x = "real m" and y = "2::real"]
            by simp
        qed
        also have \<open>\<dots> = log 2 (2*real m) \<close>
        proof-
          have \<open>(real m)*(2::real) = 2*m\<close>
            by auto
          thus ?thesis
            by (simp add: \<open>real m * 2 = real (2 * m)\<close>)
        qed
        also have \<open>\<dots> \<le> log 2 (real n)\<close>
          using \<open>2*m \<le> n\<close>  \<open>m \<noteq> 0\<close>
          by auto
        finally have \<open>log 2 (real m) + 1 \<le> log 2 (real n)\<close>
          by blast
        hence \<open>\<lfloor>log 2 (real m)\<rfloor> < \<lfloor>log 2 (real n)\<rfloor>\<close>
          by linarith
        moreover have \<open>(2::nat) > 1\<close>
          by auto
        ultimately show ?thesis
          by (smt \<open>1 \<le> m\<close> floor_less_zero log_less_zero_cancel_iff nat_mono_iff of_nat_1
              of_nat_mono power_strict_increasing)
      qed
      ultimately show ?thesis
        by auto
    qed
    ultimately have \<open>pnorm 2 (harmonic n) \<le> pnorm 2 (harmonic n - harmonic m)\<close>
      by linarith
    moreover have \<open>1 < pnorm 2 (harmonic n)\<close>
      using harmonic_numbers_2norm[where n = "n"] \<open>n \<ge> 2\<close>
      by auto
    ultimately have \<open>1 < pnorm 2 (harmonic n - harmonic m) \<close>
      by auto
    thus ?thesis
      using integers_pnorm_D[where p = "2::nat" and x = "harmonic n - harmonic m"] \<open>prime 2\<close>
      by auto
  qed
next
  case False
  have explicit: \<open>harmonic n - harmonic m = (\<Sum>k = m + 1..n. Fract 1 (int k))\<close>
    using \<open>n \<ge> m + 2\<close> harmonic_diff_explicit[where m = m and n = n]
    by linarith
  have \<open>harmonic n - harmonic m < 1\<close>
  proof-
    have \<open>(\<Sum>k = m + 1..n. Fract 1 (int k)) < 1\<close>
    proof-
      have \<open>finite {m + 1..n}\<close>
        by simp
      moreover have \<open>{m + 1..n} \<noteq> {}\<close>
        using \<open>m+2 \<le> n\<close>
        by simp
      moreover have \<open>k \<in> {m + 1..n} \<Longrightarrow> Fract 1 k \<le> Fract 1 (m+1)\<close>
        for k
      proof-
        assume \<open>k \<in> {m + 1..n}\<close>
        have \<open>k \<ge> m+1\<close>
          using \<open>k \<in> {m + 1..n}\<close>
          by auto
        thus ?thesis
          by auto
      qed
      ultimately have \<open>(\<Sum>k = m + 1..n. Fract 1 k) \<le> of_nat (card {m + 1..n})*Fract 1 (int (m + 1))\<close>
        using  Groups_Big.sum_bounded_above[where A = "{m+1..n}" and K = "Fract 1 (m+1)"
            and f = "\<lambda> k. Fract 1 k"]
        by auto
      also  have \<open>\<dots> \<le> of_nat m*Fract 1 ((m + 1))\<close>
      proof-
        have \<open>card {m+1..n} \<le> m\<close>
        proof-
          have \<open>card {m+1..n} = n - m\<close>
            by auto
          thus ?thesis
            using False
            by simp
        qed
        moreover have \<open>card  {m + 1..n} > 0\<close>
          using \<open>{m + 1..n} \<noteq> {}\<close> card_gt_0_iff
          by blast
        ultimately show ?thesis
          by (smt add_is_0 less_eq_rat_def mult_mono of_nat_0_le_iff of_nat_le_0_iff of_nat_mono
              zero_le_Fract_iff)
      qed
      also have \<open>\<dots> < 1\<close>
      proof -
        have "Fract (int m * 1) (int (1 + m)) < 1"
          by (simp add: Fract_less_one_iff)
        then show ?thesis
          by (metis (no_types) Fract_of_nat_eq add.commute mult.left_neutral mult_rat)
      qed
      finally show ?thesis
        by blast
    qed
    thus ?thesis
      using explicit
      by simp
  qed
  moreover have \<open>0 < harmonic n - harmonic m\<close>
  proof-
    have \<open>finite {m + 1..n}\<close>
      by simp
    moreover have \<open>{m + 1..n} \<noteq> {}\<close>
      using \<open>m+2 \<le> n\<close>
      by simp
    moreover have \<open>k \<in> {m + 1..n} \<Longrightarrow> 0 < Fract 1 k\<close>
      for k
    proof-
      assume \<open>k \<in> {m + 1..n}\<close>
      hence \<open>k \<ge> 1\<close>
        by auto
      thus ?thesis
        by (simp add: zero_less_Fract_iff)
    qed
    ultimately have \<open>0 < (\<Sum>k = m + 1..n. Fract 1 k)\<close>
      using Groups_Big.ordered_comm_monoid_add_class.sum_pos[where I = "{m+1..n}"
          and f = "\<lambda> k. Fract 1 k"]
      by blast
    thus ?thesis
      using explicit
      by simp
  qed
  ultimately show ?thesis
  proof -
    have f1: "sgn (harmonic n - harmonic m) = 1"
      by (metis \<open>0 < harmonic n - harmonic m\<close> sgn_pos)
    have "0 \<le> harmonic n - harmonic m"
      by (metis \<open>0 < harmonic n - harmonic m\<close> less_eq_rat_def)
    thus ?thesis
      using f1 by (metis (no_types) Ints_0 \<open>harmonic n - harmonic m < 1\<close> eq_iff_diff_eq_0 frac_eq_0_iff frac_unique_iff sgn_if zero_neq_one)
  qed
qed

end


(*
    File:     Miscellaneous_Groups.thy
    Author:   Joseph Thommes, TU München
*)
section \<open>Miscellaneous group facts\<close>

theory Miscellaneous_Groups
  imports Set_Multiplication
begin

text \<open>As the name suggests, this section contains several smaller lemmas about groups.\<close>

(* Manuel Eberl *)
lemma (in subgroup) nat_pow_closed [simp,intro]: "a \<in> H \<Longrightarrow> pow G a (n::nat) \<in> H"
  by (induction n) (auto simp: nat_pow_def)

(* Manuel Eberl *)
lemma nat_pow_modify_carrier: "a [^]\<^bsub>G\<lparr>carrier := H\<rparr>\<^esub> b = a [^]\<^bsub>G\<^esub> (b::nat)"
  by (simp add: nat_pow_def)

lemma (in group) subgroup_card_dvd_group_ord:
  assumes "subgroup H G"
  shows "card H dvd order G"
  using Coset.group.lagrange[of G H] assms group_axioms by (metis dvd_triv_right)

lemma (in group) subgroup_card_eq_order:
  assumes "subgroup H G"
  shows "card H = order (G\<lparr>carrier := H\<rparr>)"
  unfolding order_def by simp

lemma (in group) finite_subgroup_card_neq_0:
  assumes "subgroup H G" "finite H"
  shows "card H \<noteq> 0"
  using subgroup_nonempty assms by auto

lemma (in group) subgroup_order_dvd_group_order:
  assumes "subgroup H G"
  shows "order (G\<lparr>carrier := H\<rparr>) dvd order G"
  by (metis subgroup_card_dvd_group_ord[of H] assms subgroup_card_eq_order)

lemma (in group) sub_subgroup_dvd_card:
  assumes "subgroup H G" "subgroup J G" "J \<subseteq> H"
  shows "card J dvd card H"
  by (metis subgroup_incl[of J H] subgroup_card_eq_order[of H]
            group.subgroup_card_dvd_group_ord[of "(G\<lparr>carrier := H\<rparr>)" J] assms
            subgroup.subgroup_is_group[of H G] group_axioms)

lemma (in group) inter_subgroup_dvd_card:
  assumes "subgroup H G" "subgroup J G"
  shows "card (H \<inter> J) dvd card H"
  using subgroups_Inter_pair[of H J] assms sub_subgroup_dvd_card[of H "H \<inter> J"] by blast

lemma (in group) subgroups_card_coprime_inter_card_one:
  assumes "subgroup H G" "subgroup J G" "coprime (card H) (card J)"
  shows "card (H \<inter> J) = 1"
proof -
  from assms inter_subgroup_dvd_card have "is_unit (card (H \<inter> J))" unfolding coprime_def
    by (metis assms(3) coprime_common_divisor inf_commute)
  then show ?thesis by simp
qed

lemma (in group) coset_neq_imp_empty_inter:
  assumes "subgroup H G" "a \<in> carrier G" "b \<in> carrier G"
  shows "H #> a \<noteq> H #> b \<Longrightarrow> (H #> a) \<inter> (H #> b) = {}"
  by (metis Int_emptyI assms repr_independence)

lemma (in comm_group) subgroup_is_comm_group:
  assumes "subgroup H G"
  shows "comm_group (G\<lparr>carrier := H\<rparr>)" unfolding comm_group_def
proof
  interpret H: subgroup H G by fact
  interpret H: submonoid H G using H.subgroup_is_submonoid .
  show "Group.group (G\<lparr>carrier := H\<rparr>)" by blast
  show "comm_monoid (G\<lparr>carrier := H\<rparr>)" using submonoid_is_comm_monoid H.submonoid_axioms by blast
qed

lemma (in group) pow_int_mod_ord:
  assumes [simp]:"a \<in> carrier G" "ord a \<noteq> 0"
  shows "a [^] (n::int) = a [^] (n mod ord a)"
proof -
  obtain q r where d: "q = n div ord a" "r = n mod ord a" "n = q * ord a + r"
    using mod_div_decomp by blast
  hence "a [^] n = (a [^] int (ord a)) [^] q \<otimes> a [^] r"
    using assms(1) int_pow_mult int_pow_pow
    by (metis mult_of_nat_commute)
  also have "\<dots> = \<one> [^] q \<otimes> a [^] r"
    by (simp add: int_pow_int)
  also have "\<dots> = a [^] r" by simp
  finally show ?thesis using d(2) by blast
qed

lemma (in group) pow_nat_mod_ord:
  assumes [simp]:"a \<in> carrier G" "ord a \<noteq> 0"
  shows "a [^] (n::nat) = a [^] (n mod ord a)"
proof -
  obtain q r where d: "q = n div ord a" "r = n mod ord a" "n = q * ord a + r"
    using mod_div_decomp by blast
  hence "a [^] n = (a [^] ord a) [^] q \<otimes> a [^] r"
    using assms(1) nat_pow_mult nat_pow_pow by presburger
  also have "\<dots> = \<one> [^] q \<otimes> a [^] r" by auto
  also have "\<dots> = a [^] r" by simp
  finally show ?thesis using d(2) by blast
qed

lemma (in group) ord_min:
  assumes "m \<ge> 1" "x \<in> carrier G" "x [^] m = \<one>"
  shows   "ord x \<le> m"
  using assms pow_eq_id by auto

(* Manuel Eberl *)
lemma (in group) bij_betw_mult_left[intro]:
  assumes [simp]: "x \<in> carrier G"
  shows "bij_betw (\<lambda>y. x \<otimes> y) (carrier G) (carrier G)"
  by (intro bij_betwI[where ?g = "\<lambda>y. inv x \<otimes> y"])
     (auto simp: m_assoc [symmetric])

(* Manuel Eberl *)
lemma (in subgroup) inv_in_iff:
  assumes "x \<in> carrier G" "group G"
  shows   "inv x \<in> H \<longleftrightarrow> x \<in> H"
proof safe
  assume "inv x \<in> H"
  hence "inv (inv x) \<in> H" by blast
  also have "inv (inv x) = x"
    by (intro group.inv_inv) (use assms in auto)
  finally show "x \<in> H" .
qed auto

(* Manuel Eberl *)
lemma (in subgroup) mult_in_cancel_left:
  assumes "y \<in> carrier G" "x \<in> H" "group G"
  shows   "x \<otimes> y \<in> H \<longleftrightarrow> y \<in> H"
proof safe
  assume "x \<otimes> y \<in> H"
  hence "inv x \<otimes> (x \<otimes> y) \<in> H"
    using assms by blast
  also have "inv x \<otimes> (x \<otimes> y) = y"
    using assms by (simp add: \<open>x \<otimes> y \<in> H\<close> group.inv_solve_left')
  finally show "y \<in> H" .
qed (use assms in auto)

(* Manuel Eberl *)
lemma (in subgroup) mult_in_cancel_right:
  assumes "x \<in> carrier G" "y \<in> H" "group G"
  shows   "x \<otimes> y \<in> H \<longleftrightarrow> x \<in> H"
proof safe
  assume "x \<otimes> y \<in> H"
  hence "(x \<otimes> y) \<otimes> inv y \<in> H"
    using assms by blast
  also have "(x \<otimes> y) \<otimes> inv y = x"
    using assms by (simp add: \<open>x \<otimes> y \<in> H\<close> group.inv_solve_right')
  finally show "x \<in> H" .
qed (use assms in auto)

lemma (in group) (* Manuel Eberl *)
  assumes "x \<in> carrier G" and "x [^] n = \<one>" and "n > 0"
  shows   ord_le: "ord x \<le> n" and ord_pos: "ord x > 0"
proof -
  have "ord x dvd n"
    using pow_eq_id[of x n] assms by auto
  thus "ord x \<le> n" "ord x > 0"
    using assms by (auto intro: dvd_imp_le)
qed

lemma (in group) ord_conv_Least: (* Manuel Eberl *)
  assumes "x \<in> carrier G" "\<exists>n::nat > 0. x [^] n = \<one>"
  shows   "ord x = (LEAST n::nat. 0 < n \<and> x [^] n = \<one>)"
proof (rule antisym)
  show "ord x \<le> (LEAST n::nat. 0 < n \<and> x [^] n = \<one>)"
    using assms LeastI_ex[OF assms(2)] by (intro ord_le) auto
  show "ord x \<ge> (LEAST n::nat. 0 < n \<and> x [^] n = \<one>)"
    using assms by (intro Least_le) (auto intro: pow_ord_eq_1 ord_pos)
qed

lemma (in group) ord_conv_Gcd: (* Manuel Eberl *)
  assumes "x \<in> carrier G"
  shows   "ord x = Gcd {n. x [^] n = \<one>}"
  by (rule sym, rule Gcd_eqI) (use assms in \<open>auto simp: pow_eq_id\<close>)

lemma (in group) subgroup_ord_eq:
  assumes "subgroup H G" "x \<in> H"
  shows "group.ord (G\<lparr>carrier := H\<rparr>) x = ord x"
  using nat_pow_consistent ord_def group.ord_def[of "(G\<lparr>carrier := H\<rparr>)" x]
        subgroup.subgroup_is_group[of H G] assms by simp

lemma (in group) ord_FactGroup:
  assumes "subgroup P G" "group (G Mod P)"
  shows "order (G Mod P) * card P = order G"
  using lagrange[of P] FactGroup_def[of G P] assms order_def[of "(G Mod P)"] by fastforce

lemma (in group) one_is_same:
  assumes "subgroup H G"
  shows "\<one>\<^bsub>G\<lparr>carrier := H\<rparr>\<^esub> = \<one>"
  by simp

lemma (in group) kernel_FactGroup:
  assumes "P \<lhd> G"
  shows "kernel G (G Mod P) (\<lambda>x. P #> x) = P"
proof(rule equalityI; rule subsetI)
  fix x
  assume "x \<in> kernel G (G Mod P) ((#>) P)"
  then have "P #> x = \<one>\<^bsub>G Mod P\<^esub>" "x \<in> carrier G" unfolding kernel_def by simp+
  with coset_join1[of P x] show "x \<in> P" using assms unfolding normal_def by simp
next
  fix x
  assume x:"x \<in> P"
  then have xc: "x \<in> carrier G" using assms subgroup.subset unfolding normal_def by fast
  from x have "P #> x = P" using assms
    by (simp add: normal_imp_subgroup subgroup.rcos_const)
  thus "x \<in> kernel G (G Mod P) ((#>) P)" unfolding kernel_def using xc by simp
qed

lemma (in group) sub_subgroup_coprime:
  assumes "subgroup H G" "subgroup J G" "coprime (card H) (card J)"
  and "subgroup sH G" "subgroup sJ G" "sH \<subseteq> H" "sJ \<subseteq> J"
shows "coprime (card sH) (card sJ)"
  using assms by (meson coprime_divisors sub_subgroup_dvd_card)

lemma (in group) pow_eq_nat_mod:
  assumes "a \<in> carrier G" "a [^] n = a [^] m"
  shows "n mod (ord a) = m mod (ord a)"
proof -
  from assms have "a [^] (n - m) = \<one>" using pow_eq_div2 by blast
  hence "ord a dvd n - m" using assms(1) pow_eq_id by blast
  thus ?thesis
    by (metis assms mod_eq_dvd_iff_nat nat_le_linear pow_eq_div2 pow_eq_id)
qed

lemma (in group) pow_eq_int_mod:
  fixes n m::int
  assumes "a \<in> carrier G" "a [^] n = a [^] m"
  shows "n mod (ord a) = m mod (ord a)"
proof -
  from assms have "a [^] (n - m) = \<one>" using int_pow_closed int_pow_diff r_inv by presburger
  hence "ord a dvd n - m" using assms(1) int_pow_eq_id by blast
  thus ?thesis by (meson mod_eq_dvd_iff)
qed

end


theory Exercise11
  imports Main
begin

datatype exp = Var | Const int | Add exp exp | Mult exp exp

fun eval :: "exp \<Rightarrow> int \<Rightarrow> int" where
  "eval Var x = x"
  | "eval (Const n) x = n"
  | "eval (Add l r) x = (eval l x) + (eval r x)"
  | "eval (Mult l r) x = (eval l x) * (eval r x)"

(*
fun polynomiate :: "int list \<Rightarrow> exp" where
  "polynomiate Nil = Const 0"
  | "polynomiate (Cons x xs) = Add (Const x) (Mult (Var) (polynomiate xs))"

fun evalp :: "int list \<Rightarrow> int \<Rightarrow> int" where
  "evalp xs n = eval (polynomiate xs) n"
*)

fun evalp :: "int list \<Rightarrow> int \<Rightarrow> int" where
  "evalp Nil n = 0"
  | "evalp (Cons x xs) n = x + n * (evalp xs n)"

(* 2*(7^2) + 4*7 + 3 = 129 *)
lemma evalp_sanity [simp]: "evalp [3, 4, 2] 7 = 129"
  apply auto
done

fun linear_add :: "int list \<Rightarrow> int list \<Rightarrow> int list" where
  "linear_add Nil ys = ys"
  | "linear_add xs Nil = xs"
  | "linear_add (Cons x xs) (Cons y ys) = Cons (x + y) (linear_add xs ys)"

fun linear_scale :: "int \<Rightarrow> int list \<Rightarrow> int list" where
  "linear_scale x Nil = Nil"
  | "linear_scale x (Cons y ys) = Cons (x*y) (linear_scale x ys)"

fun linear_mult :: "int list \<Rightarrow> int list \<Rightarrow> int list" where
  "linear_mult Nil ys = Nil"
  | "linear_mult (Cons x xs) ys = linear_add (linear_scale x ys) (Cons 0 (linear_mult xs ys))"

lemma linear_mult_binomial_sanity [simp]: "linear_mult [a, b] [c, d] = [(a*c), ((a*d) + (b*c)), (b*d)]"
  apply auto
done

fun coeffs :: "exp \<Rightarrow> int list" where
  "coeffs (Const n) = [n]"
  | "coeffs Var = [0, 1]"
  | "coeffs (Add l r) = linear_add (coeffs l) (coeffs r)"
  | "coeffs (Mult l r) = linear_mult (coeffs l) (coeffs r)"

(* (x^2 + 3) * (2x + 7) = 2x^3 + 7x^2 + 6x + 21 *)
lemma coeffs_sanity [simp]: "coeffs (Mult (Add (Mult (Var) (Var)) (Const 3)) (Add (Mult (Const 2) (Var)) (Const 7))) = [21, 6, 7, 2]"
  apply auto
done

lemma linear_add_zero [simp]: "linear_add xs Nil = xs"
  apply (induction xs)
  apply auto
done

lemma evalp_linear_add [simp]: "evalp (linear_add xs ys) n = (evalp xs n) + (evalp ys n)"
(*
  apply (induction xs rule: polynomiate.induct)
  apply (auto simp add: algebra_simps)
*)
  apply (induction xs rule: linear_add.induct)
  apply (auto simp add: algebra_simps)
done

lemma evalp_nil_zero [simp]: "evalp (linear_mult xs Nil) n = 0"
  apply (induction xs arbitrary: n)
  apply auto
done

lemma evalp_linear_scale [simp]: "evalp (linear_scale x xs) n = x * (evalp xs n)"
  apply (induction xs)
  apply (auto simp add: algebra_simps)
done

lemma evalp_linear_mult [simp]: "evalp (linear_mult xs ys) n = (evalp xs n) * (evalp ys n)"
  apply (induction xs)
  apply (auto simp add: algebra_simps)
done

theorem evalp_coeffs_preserves_eval: "evalp (coeffs e) x = eval e x"
  apply (induction e arbitrary: x)
  apply simp
  apply simp
  apply (auto simp add: algebra_simps)
done

end


theory BExp imports AExp begin

subsection "Boolean Expressions"

datatype bexp = Bc bool | Not bexp | And bexp bexp | Less aexp aexp

fun bval :: "bexp \<Rightarrow> state \<Rightarrow> bool" where
"bval (Bc v) s = v" |
"bval (Not b) s = (\<not> bval b s)" |
"bval (And b\<^sub>1 b\<^sub>2) s = (bval b\<^sub>1 s \<and> bval b\<^sub>2 s)" |
"bval (Less a\<^sub>1 a\<^sub>2) s = (aval a\<^sub>1 s < aval a\<^sub>2 s)"

value "bval (Less (V ''x'') (Plus (N 3) (V ''y'')))
            <''x'' := 3, ''y'' := 1>"

subsection "Constant Folding"

text \<open>Optimizing constructors:\<close>

fun less :: "aexp \<Rightarrow> aexp \<Rightarrow> bexp" where
"less "

fun "and" :: "bexp \<Rightarrow> bexp \<Rightarrow> bexp" where
"and = "

lemma bval_and[simp]: "bval (and b1 b2) s = (bval b1 s \<and> bval b2 s)"
apply(induction b1 b2 rule: and.induct)
apply auto
done

fun not :: "bexp \<Rightarrow> bexp" where
"not (Bc v) = Bc(\<not> v)" |
"not b = Not b"

lemma bval_not[simp]: "bval (not b) s = (\<not> bval b s)"
apply(induction )
apply auto
done

text \<open>Now the overall optimizer:\<close>

fun bsimp :: "bexp \<Rightarrow> bexp" where
"bsimp (Bc v) = Bc v" |
"bsimp (Not b) = not(bsimp b)" |
"bsimp (And b\<^sub>1 b\<^sub>2) = and (bsimp b\<^sub>1) (bsimp b\<^sub>2)" |
"bsimp (Less a\<^sub>1 a\<^sub>2) = less (asimp a\<^sub>1) (asimp a\<^sub>2)"

value "bsimp (And (Less (N 0) (N 1)) b)"

value "bsimp (And (Less (N 1) (N 0)) (Bc True))"

theorem "bval (bsimp b) s = bval b s"
apply(induction b)
apply auto
done

end


(*  Title:      HOL/Parity.thy
    Author:     Jeremy Avigad
    Author:     Jacques D. Fleuriot
*)

section \<open>Parity in rings and semirings\<close>

theory Parity
  imports Euclidean_Division
begin

subsection \<open>Ring structures with parity and \<open>even\<close>/\<open>odd\<close> predicates\<close>

class semiring_parity = comm_semiring_1 + semiring_modulo +
  assumes even_iff_mod_2_eq_zero: "2 dvd a \<longleftrightarrow> a mod 2 = 0"
    and odd_iff_mod_2_eq_one: "\<not> 2 dvd a \<longleftrightarrow> a mod 2 = 1"
    and odd_one [simp]: "\<not> 2 dvd 1"
begin

abbreviation even :: "'a \<Rightarrow> bool"
  where "even a \<equiv> 2 dvd a"

abbreviation odd :: "'a \<Rightarrow> bool"
  where "odd a \<equiv> \<not> 2 dvd a"

lemma parity_cases [case_names even odd]:
  assumes "even a \<Longrightarrow> a mod 2 = 0 \<Longrightarrow> P"
  assumes "odd a \<Longrightarrow> a mod 2 = 1 \<Longrightarrow> P"
  shows P
  using assms by (cases "even a")
    (simp_all add: even_iff_mod_2_eq_zero [symmetric] odd_iff_mod_2_eq_one [symmetric])

lemma odd_of_bool_self [simp]:
  \<open>odd (of_bool p) \<longleftrightarrow> p\<close>
  by (cases p) simp_all

lemma not_mod_2_eq_0_eq_1 [simp]:
  "a mod 2 \<noteq> 0 \<longleftrightarrow> a mod 2 = 1"
  by (cases a rule: parity_cases) simp_all

lemma not_mod_2_eq_1_eq_0 [simp]:
  "a mod 2 \<noteq> 1 \<longleftrightarrow> a mod 2 = 0"
  by (cases a rule: parity_cases) simp_all

lemma evenE [elim?]:
  assumes "even a"
  obtains b where "a = 2 * b"
  using assms by (rule dvdE)

lemma oddE [elim?]:
  assumes "odd a"
  obtains b where "a = 2 * b + 1"
proof -
  have "a = 2 * (a div 2) + a mod 2"
    by (simp add: mult_div_mod_eq)
  with assms have "a = 2 * (a div 2) + 1"
    by (simp add: odd_iff_mod_2_eq_one)
  then show ?thesis ..
qed

lemma mod_2_eq_odd:
  "a mod 2 = of_bool (odd a)"
  by (auto elim: oddE simp add: even_iff_mod_2_eq_zero)

lemma of_bool_odd_eq_mod_2:
  "of_bool (odd a) = a mod 2"
  by (simp add: mod_2_eq_odd)

lemma even_mod_2_iff [simp]:
  \<open>even (a mod 2) \<longleftrightarrow> even a\<close>
  by (simp add: mod_2_eq_odd)

lemma mod2_eq_if:
  "a mod 2 = (if even a then 0 else 1)"
  by (simp add: mod_2_eq_odd)

lemma even_zero [simp]:
  "even 0"
  by (fact dvd_0_right)

lemma odd_even_add:
  "even (a + b)" if "odd a" and "odd b"
proof -
  from that obtain c d where "a = 2 * c + 1" and "b = 2 * d + 1"
    by (blast elim: oddE)
  then have "a + b = 2 * c + 2 * d + (1 + 1)"
    by (simp only: ac_simps)
  also have "\<dots> = 2 * (c + d + 1)"
    by (simp add: algebra_simps)
  finally show ?thesis ..
qed

lemma even_add [simp]:
  "even (a + b) \<longleftrightarrow> (even a \<longleftrightarrow> even b)"
  by (auto simp add: dvd_add_right_iff dvd_add_left_iff odd_even_add)

lemma odd_add [simp]:
  "odd (a + b) \<longleftrightarrow> \<not> (odd a \<longleftrightarrow> odd b)"
  by simp

lemma even_plus_one_iff [simp]:
  "even (a + 1) \<longleftrightarrow> odd a"
  by (auto simp add: dvd_add_right_iff intro: odd_even_add)

lemma even_mult_iff [simp]:
  "even (a * b) \<longleftrightarrow> even a \<or> even b" (is "?P \<longleftrightarrow> ?Q")
proof
  assume ?Q
  then show ?P
    by auto
next
  assume ?P
  show ?Q
  proof (rule ccontr)
    assume "\<not> (even a \<or> even b)"
    then have "odd a" and "odd b"
      by auto
    then obtain r s where "a = 2 * r + 1" and "b = 2 * s + 1"
      by (blast elim: oddE)
    then have "a * b = (2 * r + 1) * (2 * s + 1)"
      by simp
    also have "\<dots> = 2 * (2 * r * s + r + s) + 1"
      by (simp add: algebra_simps)
    finally have "odd (a * b)"
      by simp
    with \<open>?P\<close> show False
      by auto
  qed
qed

lemma even_numeral [simp]: "even (numeral (Num.Bit0 n))"
proof -
  have "even (2 * numeral n)"
    unfolding even_mult_iff by simp
  then have "even (numeral n + numeral n)"
    unfolding mult_2 .
  then show ?thesis
    unfolding numeral.simps .
qed

lemma odd_numeral [simp]: "odd (numeral (Num.Bit1 n))"
proof
  assume "even (numeral (num.Bit1 n))"
  then have "even (numeral n + numeral n + 1)"
    unfolding numeral.simps .
  then have "even (2 * numeral n + 1)"
    unfolding mult_2 .
  then have "2 dvd numeral n * 2 + 1"
    by (simp add: ac_simps)
  then have "2 dvd 1"
    using dvd_add_times_triv_left_iff [of 2 "numeral n" 1] by simp
  then show False by simp
qed

lemma odd_numeral_BitM [simp]:
  \<open>odd (numeral (Num.BitM w))\<close>
  by (cases w) simp_all

lemma even_power [simp]: "even (a ^ n) \<longleftrightarrow> even a \<and> n > 0"
  by (induct n) auto

lemma mask_eq_sum_exp:
  \<open>2 ^ n - 1 = (\<Sum>m\<in>{q. q < n}. 2 ^ m)\<close>
proof -
  have *: \<open>{q. q < Suc m} = insert m {q. q < m}\<close> for m
    by auto
  have \<open>2 ^ n = (\<Sum>m\<in>{q. q < n}. 2 ^ m) + 1\<close>
    by (induction n) (simp_all add: ac_simps mult_2 *)
  then have \<open>2 ^ n - 1 = (\<Sum>m\<in>{q. q < n}. 2 ^ m) + 1 - 1\<close>
    by simp
  then show ?thesis
    by simp
qed

end

class ring_parity = ring + semiring_parity
begin

subclass comm_ring_1 ..

lemma even_minus:
  "even (- a) \<longleftrightarrow> even a"
  by (fact dvd_minus_iff)

lemma even_diff [simp]:
  "even (a - b) \<longleftrightarrow> even (a + b)"
  using even_add [of a "- b"] by simp

end

subsection \<open>Special case: euclidean rings containing the natural numbers\<close>

context unique_euclidean_semiring_with_nat
begin

subclass semiring_parity
proof
  show "2 dvd a \<longleftrightarrow> a mod 2 = 0" for a
    by (fact dvd_eq_mod_eq_0)
  show "\<not> 2 dvd a \<longleftrightarrow> a mod 2 = 1" for a
  proof
    assume "a mod 2 = 1"
    then show "\<not> 2 dvd a"
      by auto
  next
    assume "\<not> 2 dvd a"
    have eucl: "euclidean_size (a mod 2) = 1"
    proof (rule order_antisym)
      show "euclidean_size (a mod 2) \<le> 1"
        using mod_size_less [of 2 a] by simp
      show "1 \<le> euclidean_size (a mod 2)"
        using \<open>\<not> 2 dvd a\<close> by (simp add: Suc_le_eq dvd_eq_mod_eq_0)
    qed
    from \<open>\<not> 2 dvd a\<close> have "\<not> of_nat 2 dvd division_segment a * of_nat (euclidean_size a)"
      by simp
    then have "\<not> of_nat 2 dvd of_nat (euclidean_size a)"
      by (auto simp only: dvd_mult_unit_iff' is_unit_division_segment)
    then have "\<not> 2 dvd euclidean_size a"
      using of_nat_dvd_iff [of 2] by simp
    then have "euclidean_size a mod 2 = 1"
      by (simp add: semidom_modulo_class.dvd_eq_mod_eq_0)
    then have "of_nat (euclidean_size a mod 2) = of_nat 1"
      by simp
    then have "of_nat (euclidean_size a) mod 2 = 1"
      by (simp add: of_nat_mod)
    from \<open>\<not> 2 dvd a\<close> eucl
    show "a mod 2 = 1"
      by (auto intro: division_segment_eq_iff simp add: division_segment_mod)
  qed
  show "\<not> is_unit 2"
  proof (rule notI)
    assume "is_unit 2"
    then have "of_nat 2 dvd of_nat 1"
      by simp
    then have "is_unit (2::nat)"
      by (simp only: of_nat_dvd_iff)
    then show False
      by simp
  qed
qed

lemma even_succ_div_two [simp]:
  "even a \<Longrightarrow> (a + 1) div 2 = a div 2"
  by (cases "a = 0") (auto elim!: evenE dest: mult_not_zero)

lemma odd_succ_div_two [simp]:
  "odd a \<Longrightarrow> (a + 1) div 2 = a div 2 + 1"
  by (auto elim!: oddE simp add: add.assoc)

lemma even_two_times_div_two:
  "even a \<Longrightarrow> 2 * (a div 2) = a"
  by (fact dvd_mult_div_cancel)

lemma odd_two_times_div_two_succ [simp]:
  "odd a \<Longrightarrow> 2 * (a div 2) + 1 = a"
  using mult_div_mod_eq [of 2 a]
  by (simp add: even_iff_mod_2_eq_zero)

lemma coprime_left_2_iff_odd [simp]:
  "coprime 2 a \<longleftrightarrow> odd a"
proof
  assume "odd a"
  show "coprime 2 a"
  proof (rule coprimeI)
    fix b
    assume "b dvd 2" "b dvd a"
    then have "b dvd a mod 2"
      by (auto intro: dvd_mod)
    with \<open>odd a\<close> show "is_unit b"
      by (simp add: mod_2_eq_odd)
  qed
next
  assume "coprime 2 a"
  show "odd a"
  proof (rule notI)
    assume "even a"
    then obtain b where "a = 2 * b" ..
    with \<open>coprime 2 a\<close> have "coprime 2 (2 * b)"
      by simp
    moreover have "\<not> coprime 2 (2 * b)"
      by (rule not_coprimeI [of 2]) simp_all
    ultimately show False
      by blast
  qed
qed

lemma coprime_right_2_iff_odd [simp]:
  "coprime a 2 \<longleftrightarrow> odd a"
  using coprime_left_2_iff_odd [of a] by (simp add: ac_simps)

end

context unique_euclidean_ring_with_nat
begin

subclass ring_parity ..

lemma minus_1_mod_2_eq [simp]:
  "- 1 mod 2 = 1"
  by (simp add: mod_2_eq_odd)

lemma minus_1_div_2_eq [simp]:
  "- 1 div 2 = - 1"
proof -
  from div_mult_mod_eq [of "- 1" 2]
  have "- 1 div 2 * 2 = - 1 * 2"
    using add_implies_diff by fastforce
  then show ?thesis
    using mult_right_cancel [of 2 "- 1 div 2" "- 1"] by simp
qed

end

subsection \<open>Instance for \<^typ>\<open>nat\<close>\<close>

instance nat :: unique_euclidean_semiring_with_nat
  by standard (simp_all add: dvd_eq_mod_eq_0)

lemma even_Suc_Suc_iff [simp]:
  "even (Suc (Suc n)) \<longleftrightarrow> even n"
  using dvd_add_triv_right_iff [of 2 n] by simp

lemma even_Suc [simp]: "even (Suc n) \<longleftrightarrow> odd n"
  using even_plus_one_iff [of n] by simp

lemma even_diff_nat [simp]:
  "even (m - n) \<longleftrightarrow> m < n \<or> even (m + n)" for m n :: nat
proof (cases "n \<le> m")
  case True
  then have "m - n + n * 2 = m + n" by (simp add: mult_2_right)
  moreover have "even (m - n) \<longleftrightarrow> even (m - n + n * 2)" by simp
  ultimately have "even (m - n) \<longleftrightarrow> even (m + n)" by (simp only:)
  then show ?thesis by auto
next
  case False
  then show ?thesis by simp
qed

lemma odd_pos:
  "odd n \<Longrightarrow> 0 < n" for n :: nat
  by (auto elim: oddE)

lemma Suc_double_not_eq_double:
  "Suc (2 * m) \<noteq> 2 * n"
proof
  assume "Suc (2 * m) = 2 * n"
  moreover have "odd (Suc (2 * m))" and "even (2 * n)"
    by simp_all
  ultimately show False by simp
qed

lemma double_not_eq_Suc_double:
  "2 * m \<noteq> Suc (2 * n)"
  using Suc_double_not_eq_double [of n m] by simp

lemma odd_Suc_minus_one [simp]: "odd n \<Longrightarrow> Suc (n - Suc 0) = n"
  by (auto elim: oddE)

lemma even_Suc_div_two [simp]:
  "even n \<Longrightarrow> Suc n div 2 = n div 2"
  using even_succ_div_two [of n] by simp

lemma odd_Suc_div_two [simp]:
  "odd n \<Longrightarrow> Suc n div 2 = Suc (n div 2)"
  using odd_succ_div_two [of n] by simp

lemma odd_two_times_div_two_nat [simp]:
  assumes "odd n"
  shows "2 * (n div 2) = n - (1 :: nat)"
proof -
  from assms have "2 * (n div 2) + 1 = n"
    by (rule odd_two_times_div_two_succ)
  then have "Suc (2 * (n div 2)) - 1 = n - 1"
    by simp
  then show ?thesis
    by simp
qed

lemma not_mod2_eq_Suc_0_eq_0 [simp]:
  "n mod 2 \<noteq> Suc 0 \<longleftrightarrow> n mod 2 = 0"
  using not_mod_2_eq_1_eq_0 [of n] by simp

lemma odd_card_imp_not_empty:
  \<open>A \<noteq> {}\<close> if \<open>odd (card A)\<close>
  using that by auto

lemma nat_induct2 [case_names 0 1 step]:
  assumes "P 0" "P 1" and step: "\<And>n::nat. P n \<Longrightarrow> P (n + 2)"
  shows "P n"
proof (induct n rule: less_induct)
  case (less n)
  show ?case
  proof (cases "n < Suc (Suc 0)")
    case True
    then show ?thesis
      using assms by (auto simp: less_Suc_eq)
  next
    case False
    then obtain k where k: "n = Suc (Suc k)"
      by (force simp: not_less nat_le_iff_add)
    then have "k<n"
      by simp
    with less assms have "P (k+2)"
      by blast
    then show ?thesis
      by (simp add: k)
  qed
qed

lemma mask_eq_sum_exp_nat:
  \<open>2 ^ n - Suc 0 = (\<Sum>m\<in>{q. q < n}. 2 ^ m)\<close>
  using mask_eq_sum_exp [where ?'a = nat] by simp

context semiring_parity
begin

lemma even_of_nat_iff [simp]:
  "even (of_nat n) \<longleftrightarrow> even n"
  by (induction n) simp_all

lemma even_sum_iff:
  \<open>even (sum f A) \<longleftrightarrow> even (card {a\<in>A. odd (f a)})\<close> if \<open>finite A\<close>
using that proof (induction A)
  case empty
  then show ?case
    by simp
next
  case (insert a A)
  moreover have \<open>{b \<in> insert a A. odd (f b)} = (if odd (f a) then {a} else {}) \<union> {b \<in> A. odd (f b)}\<close>
    by auto
  ultimately show ?case
    by simp
qed

lemma even_prod_iff:
  \<open>even (prod f A) \<longleftrightarrow> (\<exists>a\<in>A. even (f a))\<close> if \<open>finite A\<close>
  using that by (induction A) simp_all

lemma even_mask_iff [simp]:
  \<open>even (2 ^ n - 1) \<longleftrightarrow> n = 0\<close>
proof (cases \<open>n = 0\<close>)
  case True
  then show ?thesis
    by simp
next
  case False
  then have \<open>{a. a = 0 \<and> a < n} = {0}\<close>
    by auto
  then show ?thesis
    by (auto simp add: mask_eq_sum_exp even_sum_iff)
qed

end

subsection \<open>Parity and powers\<close>

context ring_1
begin

lemma power_minus_even [simp]: "even n \<Longrightarrow> (- a) ^ n = a ^ n"
  by (auto elim: evenE)

lemma power_minus_odd [simp]: "odd n \<Longrightarrow> (- a) ^ n = - (a ^ n)"
  by (auto elim: oddE)

lemma uminus_power_if:
  "(- a) ^ n = (if even n then a ^ n else - (a ^ n))"
  by auto

lemma neg_one_even_power [simp]: "even n \<Longrightarrow> (- 1) ^ n = 1"
  by simp

lemma neg_one_odd_power [simp]: "odd n \<Longrightarrow> (- 1) ^ n = - 1"
  by simp

lemma neg_one_power_add_eq_neg_one_power_diff: "k \<le> n \<Longrightarrow> (- 1) ^ (n + k) = (- 1) ^ (n - k)"
  by (cases "even (n + k)") auto

lemma minus_one_power_iff: "(- 1) ^ n = (if even n then 1 else - 1)"
  by (induct n) auto

end

context linordered_idom
begin

lemma zero_le_even_power: "even n \<Longrightarrow> 0 \<le> a ^ n"
  by (auto elim: evenE)

lemma zero_le_odd_power: "odd n \<Longrightarrow> 0 \<le> a ^ n \<longleftrightarrow> 0 \<le> a"
  by (auto simp add: power_even_eq zero_le_mult_iff elim: oddE)

lemma zero_le_power_eq: "0 \<le> a ^ n \<longleftrightarrow> even n \<or> odd n \<and> 0 \<le> a"
  by (auto simp add: zero_le_even_power zero_le_odd_power)

lemma zero_less_power_eq: "0 < a ^ n \<longleftrightarrow> n = 0 \<or> even n \<and> a \<noteq> 0 \<or> odd n \<and> 0 < a"
proof -
  have [simp]: "0 = a ^ n \<longleftrightarrow> a = 0 \<and> n > 0"
    unfolding power_eq_0_iff [of a n, symmetric] by blast
  show ?thesis
    unfolding less_le zero_le_power_eq by auto
qed

lemma power_less_zero_eq [simp]: "a ^ n < 0 \<longleftrightarrow> odd n \<and> a < 0"
  unfolding not_le [symmetric] zero_le_power_eq by auto

lemma power_le_zero_eq: "a ^ n \<le> 0 \<longleftrightarrow> n > 0 \<and> (odd n \<and> a \<le> 0 \<or> even n \<and> a = 0)"
  unfolding not_less [symmetric] zero_less_power_eq by auto

lemma power_even_abs: "even n \<Longrightarrow> \<bar>a\<bar> ^ n = a ^ n"
  using power_abs [of a n] by (simp add: zero_le_even_power)

lemma power_mono_even:
  assumes "even n" and "\<bar>a\<bar> \<le> \<bar>b\<bar>"
  shows "a ^ n \<le> b ^ n"
proof -
  have "0 \<le> \<bar>a\<bar>" by auto
  with \<open>\<bar>a\<bar> \<le> \<bar>b\<bar>\<close> have "\<bar>a\<bar> ^ n \<le> \<bar>b\<bar> ^ n"
    by (rule power_mono)
  with \<open>even n\<close> show ?thesis
    by (simp add: power_even_abs)
qed

lemma power_mono_odd:
  assumes "odd n" and "a \<le> b"
  shows "a ^ n \<le> b ^ n"
proof (cases "b < 0")
  case True
  with \<open>a \<le> b\<close> have "- b \<le> - a" and "0 \<le> - b" by auto
  then have "(- b) ^ n \<le> (- a) ^ n" by (rule power_mono)
  with \<open>odd n\<close> show ?thesis by simp
next
  case False
  then have "0 \<le> b" by auto
  show ?thesis
  proof (cases "a < 0")
    case True
    then have "n \<noteq> 0" and "a \<le> 0" using \<open>odd n\<close> [THEN odd_pos] by auto
    then have "a ^ n \<le> 0" unfolding power_le_zero_eq using \<open>odd n\<close> by auto
    moreover from \<open>0 \<le> b\<close> have "0 \<le> b ^ n" by auto
    ultimately show ?thesis by auto
  next
    case False
    then have "0 \<le> a" by auto
    with \<open>a \<le> b\<close> show ?thesis
      using power_mono by auto
  qed
qed

text \<open>Simplify, when the exponent is a numeral\<close>

lemma zero_le_power_eq_numeral [simp]:
  "0 \<le> a ^ numeral w \<longleftrightarrow> even (numeral w :: nat) \<or> odd (numeral w :: nat) \<and> 0 \<le> a"
  by (fact zero_le_power_eq)

lemma zero_less_power_eq_numeral [simp]:
  "0 < a ^ numeral w \<longleftrightarrow>
    numeral w = (0 :: nat) \<or>
    even (numeral w :: nat) \<and> a \<noteq> 0 \<or>
    odd (numeral w :: nat) \<and> 0 < a"
  by (fact zero_less_power_eq)

lemma power_le_zero_eq_numeral [simp]:
  "a ^ numeral w \<le> 0 \<longleftrightarrow>
    (0 :: nat) < numeral w \<and>
    (odd (numeral w :: nat) \<and> a \<le> 0 \<or> even (numeral w :: nat) \<and> a = 0)"
  by (fact power_le_zero_eq)

lemma power_less_zero_eq_numeral [simp]:
  "a ^ numeral w < 0 \<longleftrightarrow> odd (numeral w :: nat) \<and> a < 0"
  by (fact power_less_zero_eq)

lemma power_even_abs_numeral [simp]:
  "even (numeral w :: nat) \<Longrightarrow> \<bar>a\<bar> ^ numeral w = a ^ numeral w"
  by (fact power_even_abs)

end

context unique_euclidean_semiring_with_nat
begin

lemma even_mask_div_iff':
  \<open>even ((2 ^ m - 1) div 2 ^ n) \<longleftrightarrow> m \<le> n\<close>
proof -
  have \<open>even ((2 ^ m - 1) div 2 ^ n) \<longleftrightarrow> even (of_nat ((2 ^ m - Suc 0) div 2 ^ n))\<close>
    by (simp only: of_nat_div) (simp add: of_nat_diff)
  also have \<open>\<dots> \<longleftrightarrow> even ((2 ^ m - Suc 0) div 2 ^ n)\<close>
    by simp
  also have \<open>\<dots> \<longleftrightarrow> m \<le> n\<close>
  proof (cases \<open>m \<le> n\<close>)
    case True
    then show ?thesis
      by (simp add: Suc_le_lessD)
  next
    case False
    then obtain r where r: \<open>m = n + Suc r\<close>
      using less_imp_Suc_add by fastforce
    from r have \<open>{q. q < m} \<inter> {q. 2 ^ n dvd (2::nat) ^ q} = {q. n \<le> q \<and> q < m}\<close>
      by (auto simp add: dvd_power_iff_le)
    moreover from r have \<open>{q. q < m} \<inter> {q. \<not> 2 ^ n dvd (2::nat) ^ q} = {q. q < n}\<close>
      by (auto simp add: dvd_power_iff_le)
    moreover from False have \<open>{q. n \<le> q \<and> q < m \<and> q \<le> n} = {n}\<close>
      by auto
    then have \<open>odd ((\<Sum>a\<in>{q. n \<le> q \<and> q < m}. 2 ^ a div (2::nat) ^ n) + sum ((^) 2) {q. q < n} div 2 ^ n)\<close>
      by (simp_all add: euclidean_semiring_cancel_class.power_diff_power_eq semiring_parity_class.even_sum_iff not_less mask_eq_sum_exp_nat [symmetric])
    ultimately have \<open>odd (sum ((^) (2::nat)) {q. q < m} div 2 ^ n)\<close>
      by (subst euclidean_semiring_cancel_class.sum_div_partition) simp_all
    with False show ?thesis
      by (simp add: mask_eq_sum_exp_nat)
  qed
  finally show ?thesis .
qed

end

subsection \<open>Instance for \<^typ>\<open>int\<close>\<close>

lemma even_diff_iff:
  "even (k - l) \<longleftrightarrow> even (k + l)" for k l :: int
  by (fact even_diff)

lemma even_abs_add_iff:
  "even (\<bar>k\<bar> + l) \<longleftrightarrow> even (k + l)" for k l :: int
  by simp

lemma even_add_abs_iff:
  "even (k + \<bar>l\<bar>) \<longleftrightarrow> even (k + l)" for k l :: int
  by simp

lemma even_nat_iff: "0 \<le> k \<Longrightarrow> even (nat k) \<longleftrightarrow> even k"
  by (simp add: even_of_nat_iff [of "nat k", where ?'a = int, symmetric])

context
  assumes "SORT_CONSTRAINT('a::division_ring)"
begin

lemma power_int_minus_left:
  "power_int (-a :: 'a) n = (if even n then power_int a n else -power_int a n)"
  by (auto simp: power_int_def minus_one_power_iff even_nat_iff)

lemma power_int_minus_left_even [simp]: "even n \<Longrightarrow> power_int (-a :: 'a) n = power_int a n"
  by (simp add: power_int_minus_left)

lemma power_int_minus_left_odd [simp]: "odd n \<Longrightarrow> power_int (-a :: 'a) n = -power_int a n"
  by (simp add: power_int_minus_left)

lemma power_int_minus_left_distrib:
  "NO_MATCH (-1) x \<Longrightarrow> power_int (-a :: 'a) n = power_int (-1) n * power_int a n"
  by (simp add: power_int_minus_left)

lemma power_int_minus_one_minus: "power_int (-1 :: 'a) (-n) = power_int (-1) n"
  by (simp add: power_int_minus_left)

lemma power_int_minus_one_diff_commute: "power_int (-1 :: 'a) (a - b) = power_int (-1) (b - a)"
  by (subst power_int_minus_one_minus [symmetric]) auto

lemma power_int_minus_one_mult_self [simp]:
  "power_int (-1 :: 'a) m * power_int (-1) m = 1"
  by (simp add: power_int_minus_left)

lemma power_int_minus_one_mult_self' [simp]:
  "power_int (-1 :: 'a) m * (power_int (-1) m * b) = b"
  by (simp add: power_int_minus_left)

end

subsection \<open>Computing congruences modulo \<open>2 ^ q\<close>\<close>

context unique_euclidean_semiring_with_nat_division
begin

lemma cong_exp_iff_simps:
  "numeral n mod numeral Num.One = 0
    \<longleftrightarrow> True"
  "numeral (Num.Bit0 n) mod numeral (Num.Bit0 q) = 0
    \<longleftrightarrow> numeral n mod numeral q = 0"
  "numeral (Num.Bit1 n) mod numeral (Num.Bit0 q) = 0
    \<longleftrightarrow> False"
  "numeral m mod numeral Num.One = (numeral n mod numeral Num.One)
    \<longleftrightarrow> True"
  "numeral Num.One mod numeral (Num.Bit0 q) = (numeral Num.One mod numeral (Num.Bit0 q))
    \<longleftrightarrow> True"
  "numeral Num.One mod numeral (Num.Bit0 q) = (numeral (Num.Bit0 n) mod numeral (Num.Bit0 q))
    \<longleftrightarrow> False"
  "numeral Num.One mod numeral (Num.Bit0 q) = (numeral (Num.Bit1 n) mod numeral (Num.Bit0 q))
    \<longleftrightarrow> (numeral n mod numeral q) = 0"
  "numeral (Num.Bit0 m) mod numeral (Num.Bit0 q) = (numeral Num.One mod numeral (Num.Bit0 q))
    \<longleftrightarrow> False"
  "numeral (Num.Bit0 m) mod numeral (Num.Bit0 q) = (numeral (Num.Bit0 n) mod numeral (Num.Bit0 q))
    \<longleftrightarrow> numeral m mod numeral q = (numeral n mod numeral q)"
  "numeral (Num.Bit0 m) mod numeral (Num.Bit0 q) = (numeral (Num.Bit1 n) mod numeral (Num.Bit0 q))
    \<longleftrightarrow> False"
  "numeral (Num.Bit1 m) mod numeral (Num.Bit0 q) = (numeral Num.One mod numeral (Num.Bit0 q))
    \<longleftrightarrow> (numeral m mod numeral q) = 0"
  "numeral (Num.Bit1 m) mod numeral (Num.Bit0 q) = (numeral (Num.Bit0 n) mod numeral (Num.Bit0 q))
    \<longleftrightarrow> False"
  "numeral (Num.Bit1 m) mod numeral (Num.Bit0 q) = (numeral (Num.Bit1 n) mod numeral (Num.Bit0 q))
    \<longleftrightarrow> numeral m mod numeral q = (numeral n mod numeral q)"
  by (auto simp add: case_prod_beta dest: arg_cong [of _ _ even])

end

code_identifier
  code_module Parity \<rightharpoonup> (SML) Arith and (OCaml) Arith and (Haskell) Arith

lemmas even_of_nat = even_of_nat_iff

end


theory sample2
  imports Main begin
type_synonym string = "char list"

datatype
  'a tree = Leaf |
  Node "'a tree" 'a "'a tree"

fun mirror :: "'a tree\<Rightarrow>'a tree" where
  "mirror Leaf = Leaf" |
  (*left and right is swapped*)
  "mirror (Node left a right) = Node (mirror right) a (mirror left)"

lemma "mirror (mirror t) = t"
  apply(induction t)
   apply(auto)
  done

datatype 'a option = None | Some 'a

(* t1 * t2 is the type of pairs*)
fun lookup :: "('a * 'b) list \<Rightarrow> 'a \<Rightarrow> 'b option" where
  "lookup Nil x = None" |
  "lookup ((a, b) # ps) x = (
    if a = x then
      Some b
    else
    lookup ps x
)"

(*
  Pairs can be taken apart either by pattern
  matching(as above) or with the projection
  functions fst and snd (first, second)
  Tuples are simulated by pairs nested to the
  right: (a, b, c) is short for (a, (b, c))
  and t1 * t2 * t3 is short for
  t1 * (t2 * t3)
*)

(*non-recursive function*)
definition sq :: "nat\<Rightarrow>nat" where
  "sq n = n * n"

(*abbreviations*)
abbreviations sq' :: "nat\<Rightarrow>nat" where
  "sq' n = n * n"

(*
  the key difference is that sq' is only
  syntactic suger, sq' t is replaced by
  t * t;
  before printing, every occurrence
  of u * u is replaced by sq' u.
  Internally, sq' does not exist
*)

(*recursive functions: defined with fun
  by pattern matching over datatype
  constructors
  The order of equations matters! ! !
  (as in functional programming languages)
  However, all HOL functions must be total.
  This simplifies the logic -
  terms are always defined -
  but means that recursive functions must
  terminate.
  Otherwise one could define a function
  f n = f n + 1 and conclude 0 = 1 by
  subtracting f n on both sides.
*)
(*
  Isabelle's automatic termination checker
  requires that arguments of ercursive calls
  on the right-hand side must be strictly
  smaller than the arguments on the left-hand
  side.
  This means that one fixed argument position
  decreases in size with each recursive call.
  The size is measured as the number of
  constructor(excluding 0-ary ones, e.g. Nil)
  Lexicographic combinations are also
  recognized.
*)

(*functions defined with fun come with their
  own induction schema that mirrors the
  recursion schema and is derived from the
  termination order.*)

fun div2 :: "nat\<Rightarrow>nat" where
  "div2 0 = 0" | (* 0 *)
  "div2 (Suc 0) = 0" | (* 1 *)
  "div2 (Suc (Suc n)) = Suc(div2 n)" (* 2~ *)
  (*e.g.: div2 (Suc (Suc 2)) = Suc (div2 2)
   Suc (Suc 2) \<Rightarrow> 4 *)

(*it does not just define div2 but also proves
  a customized induction rule
  P 0  P (Suc 0)  \<forall>n. P n \<Longrightarrow> P (Suc (Suc n))
  -------------------------------------------
              P m

  This induction rule can simplify inductive
  proofs.
*)

lemma "div2(n) = n div 2"
  apply(induction n rule: div2.induct)
  apply(auto)
  done

(*
  Function rev has quadratic worst-case
  running time because it calls append
  for each element of the list and append
  is linear in its first argument. A linear
  time version of rev requires an extra
  argument where the result is accumulated
  gradually, using only #
*)

fun itrev :: "'a list \<Rightarrow> 'a list \<Rightarrow> 'a list" where
  "itrev Nil ys = ys" |
  "itrev (x # xs) ys = itrev xs (x # ys)"

thm itrev.induct

(*
  it reverses its first argument by stacking
  its elements onto the second argument, and
  it returns that second argument when the
  first one becomes empty. Note that itrev
  is tail-recursive: it can be compiled
  into a loop; no stack is necessary
  for executing it.
*)

lemma "itrev xs Nil = rev xs"
  apply(induction xs)
   apply(auto)
  (* IH is too weak to remove subgoal*)
  sorry

(*xs @ ys = app xs ys*)
lemma "itrev xs ys = rev xs @ ys"
  (*apply(induction xs)*)
  (*apply(auto)*)
  (*IH is still too weak, use this instead*)
  apply(induction xs arbitrary: ys)
  apply(auto)
  done


(* Property from Productive Use of Failure in Inductive Proof,
   Andrew Ireland and Alan Bundy, JAR 1996.
   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.
   Some proofs were added by Yutaka Nagashima.*)
  theory TIP_prop_01
  imports "../../Test_Base"
begin

datatype Nat = Z | S "Nat"

fun double :: "Nat => Nat" where
  "double (Z) = Z"
| "double (S y) = S (S (double y))"

fun t2 :: "Nat => Nat => Nat" where
  "t2 (Z) y = y"
| "t2 (S z) y = S (t2 z y)"

(* manipulation of sub-terms (t2 x (S x) = t2 (S x) x)) and generalization by renaming.*)
theorem property0 :
  "((double x) = (t2 x x))"
  apply(induct x)
   apply simp
  apply clarsimp
  apply(subgoal_tac
      "(\<And>x. t2 x (S x) = t2 (S x) x) &&&
     (\<And>x. double x = t2 x x \<Longrightarrow> S (t2 x x) = t2 (S x) x)")
   apply presburger
  apply(thin_tac "double x = t2 x x")
  apply (rule conjunctionI)
   apply simp(*mostly to get rid of x, a bit of simplification as well*)
   apply(subgoal_tac "(\<And>x y. t2 x (S y) = S (t2 x y))")(*generalization by renaming*)
    apply presburger
   apply simp(*to get rid of xa*)
   apply(induct_tac x)
    apply auto[1]
   apply auto[1]
  apply auto[1]
  done

lemma aux2:
  shows "double x = t2 x x \<Longrightarrow> S (t2 x x) = t2 (S x) x"
  apply auto done

theorem aux11:
  shows "t2 x (S y) = t2 (S x) y"
  apply(induct x)
  apply auto done

theorem aux1:
  assumes "\<And>x y. t2 x (S y) = t2 (S x) y"
  shows "t2 x (S x) = t2 (S x) x"
  apply(fastforce simp: assms) done

theorem aux0:
  assumes "(\<And>x. t2 x (S x) = t2 (S x) x)" (*the original term equals the new term whose arguments swapped*)
          "(\<And>x. double x = t2 x x \<Longrightarrow> S (t2 x x) = t2 (S x) x)" (*swaps two unequal arguments*)
        shows "double x = t2 x x \<Longrightarrow> S (t2 x x) = t2 x (S x)"
  using assms
  apply metis done

theorem property0' :
  "((double x) = (t2 x x))"
  apply(induct x)
   apply clarsimp
  apply clarsimp
  apply(rule aux0)
    apply(rule aux1)
    apply(rule aux11)
   apply(rule aux2)
   apply clarsimp
  apply clarsimp
  done

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_sort_nat_MSortTDSorts
  imports "../../Test_Base"
begin

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

datatype Nat = Z | S "Nat"

fun plus :: "Nat => Nat => Nat" where
  "plus (Z) y = y"
| "plus (S z) y = S (plus z y)"

fun minus :: "Nat => Nat => Nat" where
  "minus (Z) y = Z"
| "minus (S z) (S y2) = minus z y2"

fun lt :: "Nat => Nat => bool" where
  "lt x (Z) = False"
| "lt (Z) (S z) = True"
| "lt (S n) (S z) = lt n z"

fun length :: "'a list => Nat" where
  "length (nil2) = Z"
| "length (cons2 y l) = plus (S Z) (length l)"

fun le :: "Nat => Nat => bool" where
  "le (Z) y = True"
| "le (S z) (Z) = False"
| "le (S z) (S x2) = le z x2"

fun lmerge :: "Nat list => Nat list => Nat list" where
  "lmerge (nil2) y = y"
| "lmerge (cons2 z x2) (nil2) = cons2 z x2"
| "lmerge (cons2 z x2) (cons2 x3 x4) =
     (if le z x3 then cons2 z (lmerge x2 (cons2 x3 x4)) else
        cons2 x3 (lmerge (cons2 z x2) x4))"

fun ordered :: "Nat list => bool" where
  "ordered (nil2) = True"
| "ordered (cons2 y (nil2)) = True"
| "ordered (cons2 y (cons2 y2 xs)) =
     ((le y y2) & (ordered (cons2 y2 xs)))"

fun take :: "Nat => 'a list => 'a list" where
  "take x y =
   (if le x Z then nil2 else
      (case y of
         nil2 => nil2
         | cons2 z xs => (case x of S x2 => cons2 z (take x2 xs))))"

(*fun did not finish the proof*)
function idiv :: "Nat => Nat => Nat" where
  "idiv x y = (if lt x y then Z else S (idiv (minus x y) y))"
  by pat_completeness auto

fun drop :: "Nat => 'a list => 'a list" where
  "drop x y =
   (if le x Z then y else
      (case y of
         nil2 => nil2
         | cons2 z xs1 => (case x of S x2 => drop x2 xs1)))"

(*fun did not finish the proof*)
function msorttd :: "Nat list => Nat list" where
  "msorttd (nil2) = nil2"
| "msorttd (cons2 y (nil2)) = cons2 y (nil2)"
| "msorttd (cons2 y (cons2 x2 x3)) =
     (let k :: Nat = idiv (length (cons2 y (cons2 x2 x3))) (S (S Z))
     in lmerge
          (msorttd (take k (cons2 y (cons2 x2 x3))))
          (msorttd (drop k (cons2 y (cons2 x2 x3)))))"
  by pat_completeness auto

theorem property0 :
  "ordered (msorttd xs)"
  oops

end


subsection \<open>Theorems about the extended naturals\<close>

text \<open>Extended naturals are the natural numbers plus infinity.
      They are slightly more cumbersome to reason about, and this file contains
      some lemmas that should help with that.\<close>

theory MoreENat
  imports MoreCoinductiveList2
begin

lemma eSuc_n_not_le_n[simp]:
"(eSuc x \<le> x) \<longleftrightarrow> x = \<infinity>"
  by (metis enat_ord_simps(3) Suc_n_not_le_n antisym ile_eSuc le_add2 plus_1_eq_Suc the_enat_eSuc)

lemma mult_two_impl1[elim]:
  assumes "a * 2 = 2 * b"
  shows "(a::enat) = b" using assms by(cases a;cases b,auto simp add: mult_2 mult_2_right)

lemma mult_two_impl2[dest]:
  assumes "a * 2 = 1 + 2 * b"
  shows "(a::enat) = \<infinity> \<and> b=\<infinity>"
  apply(cases a;cases b)
  using assms Suc_double_not_eq_double[unfolded mult_2, symmetric]
  by (auto simp add: mult_2 one_enat_def mult_2_right)

lemma mult_two_impl3[dest]:
  assumes "a * 2 = 1 + (2 * b - 1)"
  shows "(a::enat) = b \<and> a \<ge> 1"
  using assms by(cases a;cases b,auto simp add: one_enat_def mult_2 mult_2_right)

lemma mult_two_impl4[dest]:
  assumes "a * 2 = 2 * b - 1"
  shows "((a::enat) = 0 \<and> b = 0) \<or> (a = \<infinity> \<and> b=\<infinity>)"
proof(cases a;cases b)
  fix anat bnat
  assume *:"a = enat anat" "b = enat bnat"
  hence "anat + anat = bnat + bnat - Suc 0"
    using assms by (auto simp add:enat_0_iff one_enat_def mult_2 mult_2_right)
  thus ?thesis unfolding * using Suc_double_not_eq_double[unfolded mult_2, symmetric]
    by (metis Suc_pred add_gr_0 enat_0_iff(1) neq0_conv not_less0 zero_less_diff)
qed(insert assms,auto simp add:enat_0_iff one_enat_def mult_2 mult_2_right)

lemma times_two_div_two[intro]:
  assumes "enat n < x" shows "2 * enat (n div 2) < x"
proof -
  have "2 * n div 2 \<le> n" by auto
  hence "2 * enat (n div 2) \<le> enat n"
    using enat_numeral enat_ord_simps(2) linorder_not_less mult.commute times_enat_simps(1)
  by (metis div_times_less_eq_dividend)
  with assms show ?thesis by auto
qed

lemma enat_sum_le[simp]:
  shows "enat (a + b) \<le> c \<Longrightarrow> b \<le> c"
  by (meson dual_order.trans enat_ord_simps(1) le_add2)

lemma enat_Suc_nonzero[simp]:
shows "enat (Suc n)\<noteq> 0"
 by (metis Zero_not_Suc enat.inject zero_enat_def)

end


(*
    Author:     René Thiemann
    License:    BSD
*)
section \<open>Calculating All Possible Sums of Sub-Multisets\<close>
theory Sub_Sums
  imports
    Main
    "HOL-Library.Multiset"
begin

fun sub_mset_sums :: "'a :: comm_monoid_add list \<Rightarrow> 'a set" where
  "sub_mset_sums [] = {0}"
| "sub_mset_sums (x # xs) = (let S = sub_mset_sums xs in S \<union> ( (+) x) ` S)"

lemma subset_add_mset: "ys \<subseteq># add_mset x zs \<longleftrightarrow> (ys \<subseteq># zs \<or> (\<exists> xs. xs \<subseteq># zs \<and> ys = add_mset x xs))"
  (is "?l = ?r")
proof
  have sub: "ys \<subseteq># zs \<Longrightarrow> ys \<subseteq># add_mset x zs"
    by (metis add_mset_remove_trivial diff_subset_eq_self subset_mset.dual_order.trans)
  assume ?r
  thus ?l using sub by auto
next
  assume l: ?l
  show ?r
  proof (cases "x \<in># ys")
    case True
    define xs where "xs = (ys - {# x #})"
    from True have ys: "ys = add_mset x xs" unfolding xs_def by auto
    from l[unfolded ys] have "xs \<subseteq># zs" by auto
    thus ?r unfolding ys by auto
  next
    case False
    with l have "ys \<subseteq># zs" by (simp add: subset_mset.le_iff_sup)
    thus ?thesis by auto
  qed
qed

lemma sub_mset_sums[simp]: "sub_mset_sums xs = sum_mset ` { ys. ys \<subseteq># mset xs }"
proof (induct xs)
  case (Cons x xs)
  have id: "{ys. ys \<subseteq># mset (x # xs)} = {ys. ys \<subseteq># mset xs} \<union> {add_mset x ys | ys. ys \<subseteq># mset xs}"
    unfolding mset.simps subset_add_mset by auto
  show ?case unfolding sub_mset_sums.simps Let_def Cons id image_Un
    by force
qed auto

end


chapter {* R7: Árboles binarios completos *}

theory R7_Arboles_binarios_completos
imports Main
begin

text {*
  En esta relación se piden demostraciones automáticas (lo más cortas
  posibles). Para ello, en algunos casos es necesario incluir lemas
  auxiliares (que se demuestran automáticamente) y usar ejercicios
  anteriores.

  ---------------------------------------------------------------------
  Ejercicio 1. Definir el tipo de datos arbol para representar los
  árboles binarios que no tienen información ni en los nodos y ni en las
  hojas. Por ejemplo, el árbol
          ·
         / \
        /   \
       ·     ·
      / \   / \
     ·   · ·   ·
  se representa por "N (N H H) (N H H)".
  ---------------------------------------------------------------------
*}

datatype arbol = H | N arbol arbol

value "N (N H H) (N H H) = (N (N H H) (N H H) :: arbol)"

text {*
  ---------------------------------------------------------------------
  Ejercicio 2. Definir la función
     hojas :: "arbol => nat"
  tal que (hojas a) es el número de hojas del árbol a. Por ejemplo,
     hojas (N (N H H) (N H H)) = 4
  ---------------------------------------------------------------------
*}

fun hojas :: "arbol => nat" where
  "hojas H = 1"
| "hojas (N i d) = hojas i + hojas d"

value "hojas (N (N H H) (N H H)) = 4"

text {*
  ---------------------------------------------------------------------
  Ejercicio 4. Definir la función
     profundidad :: "arbol => nat"
  tal que (profundidad a) es la profundidad del árbol a. Por ejemplo,
     profundidad (N (N H H) (N H H)) = 2
  ---------------------------------------------------------------------
*}

fun profundidad :: "arbol => nat" where
  "profundidad H = 0"
| "profundidad (N i d) = 1 + (max (profundidad i)(profundidad d))"

value "profundidad (N (N H H) (N H H)) = 2"

text {*
  ---------------------------------------------------------------------
  Ejercicio 5. Definir la función
     abc :: "nat \<Rightarrow> arbol"
  tal que (abc n) es el árbol binario completo de profundidad n. Por
  ejemplo,
     abc 3 = N (N (N H H) (N H H)) (N (N H H) (N H H))
  ---------------------------------------------------------------------
*}

fun abc :: "nat \<Rightarrow> arbol" where
  "abc 0 = H"
| "abc (Suc n) = (N (abc n) (abc n))"

value "abc 3 = N (N (N H H) (N H H)) (N (N H H) (N H H))"

text {*
  ---------------------------------------------------------------------
  Ejercicio 6. Un árbol binario a es completo respecto de la medida f si
  a es una hoja o bien a es de la forma (N i d) y se cumple que tanto i
  como d son árboles binarios completos respecto de f y, además,
  f(i) = f(r).

  Definir la función
     es_abc :: "(arbol => 'a) => arbol => bool
  tal que (es_abc f a) se verifica si a es un árbol binario completo
  respecto de f.
  ---------------------------------------------------------------------
*}

fun es_abc :: "(arbol => 'a) => arbol => bool" where
  "es_abc _ H = True"
|  "es_abc f (N i d) = (es_abc f i \<and> es_abc f d \<and> (f i = f d))"

text {*
  ---------------------------------------------------------------------
  Nota. (size a) es el número de nodos del árbol a. Por ejemplo,
     size (N (N H H) (N H H)) = 3
  ---------------------------------------------------------------------
*}

value "size (N (N H H) (N H H)) = 3"
value "size (N (N (N H H) (N H H)) (N (N H H) (N H H))) = 7"

text {*
  ---------------------------------------------------------------------
  Nota. Tenemos 3 funciones de medida sobre los árboles: número de
  hojas, número de nodos y profundidad. A cada una le corresponde un
  concepto de completitud. En los siguientes ejercicios demostraremos
  que los tres conceptos de completitud son iguales.
  ---------------------------------------------------------------------
*}

text {*
  ---------------------------------------------------------------------
  Ejercicio 7. Demostrar que un árbol binario a es completo respecto de
  la profundidad syss es completo respecto del número de hojas.
  ---------------------------------------------------------------------
*}

lemma arbol_profundidad_respecto_num_hojas:
  assumes "es_abc profundidad n"
  shows "hojas n = 2^(profundidad n)"
using assms
by (induct n) auto

lemma lej7: "es_abc profundidad a = es_abc hojas a"
by (induct a) (auto simp add: arbol_profundidad_respecto_num_hojas)

text {*
  ---------------------------------------------------------------------
  Ejercicio 8. Demostrar que un árbol binario a es completo respecto del
  número de hojas syss es completo respecto del número de nodos.
  ---------------------------------------------------------------------
*}

lemma arbol_completo_respecto_num_hojas:
  assumes "es_abc hojas n"
  shows "Suc(size n) = hojas n"
using assms
by (induct n) auto

lemma lej8: "es_abc hojas a = es_abc size a"
by (induct a) (auto simp add:arbol_completo_respecto_num_hojas [symmetric])

text {*
  ---------------------------------------------------------------------
  Ejercicio 9. Demostrar que un árbol binario a es completo respecto de
  la profundidad syss es completo respecto del número de nodos.
  ---------------------------------------------------------------------
*}

lemma arbol_completo_respecto_profundidad: "es_abc profundidad n = es_abc size n"
by (simp add: lej7 lej8)

text {*
  ---------------------------------------------------------------------
  Ejercicio 10. Demostrar que (abc n) es un árbol binario completo.
  ---------------------------------------------------------------------
*}

lemma lej10:  "es_abc profundidad (abc n)"
by (induct n) auto

text {*
  ---------------------------------------------------------------------
  Ejercicio 11. Demostrar que si a es un árbolo binario completo
  respecto de la profundidad, entonces a es igual a
  (abc (profundidad a)).
  ---------------------------------------------------------------------
*}

lemma lej11:
  assumes " es_abc profundidad n"
  shows "n = (abc (profundidad n))"
using assms
by (induct n) auto

text {*
  ---------------------------------------------------------------------
  Ejercicio 12. Encontrar una medida f tal que (es_abc f) es distinto de
  (es_abc size).
  ---------------------------------------------------------------------
*}

lemma "es_abc f n =  es_abc size n"
quickcheck

end


(*  Title:      HOL/ex/MergeSort.thy
    Author:     Tobias Nipkow
    Copyright   2002 TU Muenchen
*)

section\<open>Merge Sort\<close>

theory MergeSort
imports "~~/src/HOL/Library/Multiset"
begin

context linorder
begin

fun merge :: "'a list \<Rightarrow> 'a list \<Rightarrow> 'a list"
where
  "merge (x#xs) (y#ys) =
         (if x \<le> y then x # merge xs (y#ys) else y # merge (x#xs) ys)"
| "merge xs [] = xs"
| "merge [] ys = ys"

lemma mset_merge [simp]:
  "mset (merge xs ys) = mset xs + mset ys"
  by (induct xs ys rule: merge.induct) (simp_all add: ac_simps)

lemma set_merge [simp]:
  "set (merge xs ys) = set xs \<union> set ys"
  by (induct xs ys rule: merge.induct) auto

lemma sorted_merge [simp]:
  "sorted (merge xs ys) \<longleftrightarrow> sorted xs \<and> sorted ys"
  by (induct xs ys rule: merge.induct) (auto simp add: ball_Un not_le less_le sorted_Cons)

fun msort :: "'a list \<Rightarrow> 'a list"
where
  "msort [] = []"
| "msort [x] = [x]"
| "msort xs = merge (msort (take (size xs div 2) xs))
                    (msort (drop (size xs div 2) xs))"

lemma sorted_msort:
  "sorted (msort xs)"
  by (induct xs rule: msort.induct) simp_all

lemma mset_msort:
  "mset (msort xs) = mset xs"
  by (induct xs rule: msort.induct)
    (simp_all, metis append_take_drop_id drop_Suc_Cons mset.simps(2) mset_append take_Suc_Cons)

theorem msort_sort:
  "sort = msort"
  by (rule ext, rule properties_for_sort) (fact mset_msort sorted_msort)+

end

end