merged
authordesharna
Wed, 07 Sep 2022 08:58:27 +0200
changeset 76057 e07d873c18a4
parent 76056 c2fd8b88d262 (current diff)
parent 76053 3310317cc484 (diff)
child 76093 ce66ff654e59
merged
NEWS
--- a/CONTRIBUTORS	Fri Sep 02 13:41:55 2022 +0200
+++ b/CONTRIBUTORS	Wed Sep 07 08:58:27 2022 +0200
@@ -6,6 +6,9 @@
 Contributions to this Isabelle version
 --------------------------------------
 
+* August 2022: Norbert Schirmer, Apple
+  Record simproc that sorts update expressions.
+
 * June 2022: Jan van Brügge, TU München
   Strict cardinality bounds for BNFs.
 
--- a/NEWS	Fri Sep 02 13:41:55 2022 +0200
+++ b/NEWS	Wed Sep 07 08:58:27 2022 +0200
@@ -66,6 +66,10 @@
 
 *** HOL ***
 
+* HOL record: new simproc that sorts update expressions, guarded by
+configuration option "record_sort_updates" (default: false). Some
+examples are in theory "HOL-Examples.Records".
+
 * HOL-Algebra: Facts renamed to avoid fact name clashes on interpretation:
 
     is_ring ~> ring_axioms
--- a/etc/options	Fri Sep 02 13:41:55 2022 +0200
+++ b/etc/options	Wed Sep 07 08:58:27 2022 +0200
@@ -133,7 +133,7 @@
   -- "build process output tail shown to user (in lines, 0 = unlimited)"
 
 option profiling : string = "" (standard "time")
-  -- "ML profiling (possible values: time, allocations)"
+  -- "ML profiling (possible values: time, time_thread, allocations)"
 
 option system_log : string = "" (standard "-")
   -- "output for system messages (log file or \"-\" for console progress)"
--- a/src/HOL/Code_Numeral.thy	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/HOL/Code_Numeral.thy	Wed Sep 07 08:58:27 2022 +0200
@@ -276,9 +276,11 @@
 declare division_segment_integer.rep_eq [simp]
 
 instance
-  by (standard; transfer)
-    (use mult_le_mono2 [of 1] in \<open>auto simp add: sgn_mult_abs abs_mult sgn_mult abs_mod_less sgn_mod nat_mult_distrib
-     division_segment_mult division_segment_mod intro: div_eqI\<close>)
+  apply (standard; transfer)
+  apply (use mult_le_mono2 [of 1] in \<open>auto simp add: sgn_mult_abs abs_mult sgn_mult abs_mod_less sgn_mod nat_mult_distrib
+     division_segment_mult division_segment_mod\<close>)
+  apply (simp add: division_segment_int_def split: if_splits)
+  done
 
 end
 
--- a/src/HOL/Divides.thy	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/HOL/Divides.thy	Wed Sep 07 08:58:27 2022 +0200
@@ -114,155 +114,6 @@
 qed (use assms in auto)
 
 
-subsubsection \<open>Computing \<open>div\<close> and \<open>mod\<close> with shifting\<close>
-
-inductive eucl_rel_int :: "int \<Rightarrow> int \<Rightarrow> int \<times> int \<Rightarrow> bool"
-  where eucl_rel_int_by0: "eucl_rel_int k 0 (0, k)"
-  | eucl_rel_int_dividesI: "l \<noteq> 0 \<Longrightarrow> k = q * l \<Longrightarrow> eucl_rel_int k l (q, 0)"
-  | eucl_rel_int_remainderI: "sgn r = sgn l \<Longrightarrow> \<bar>r\<bar> < \<bar>l\<bar>
-      \<Longrightarrow> k = q * l + r \<Longrightarrow> eucl_rel_int k l (q, r)"
-
-lemma eucl_rel_int_iff:    
-  "eucl_rel_int k l (q, r) \<longleftrightarrow> 
-    k = l * q + r \<and>
-     (if 0 < l then 0 \<le> r \<and> r < l else if l < 0 then l < r \<and> r \<le> 0 else q = 0)"
-  by (cases "r = 0")
-    (auto elim!: eucl_rel_int.cases intro: eucl_rel_int_by0 eucl_rel_int_dividesI eucl_rel_int_remainderI
-    simp add: ac_simps sgn_1_pos sgn_1_neg)
-
-lemma unique_quotient:
-  "eucl_rel_int a b (q, r) \<Longrightarrow> eucl_rel_int a b (q', r') \<Longrightarrow> q = q'"
-  apply (rule order_antisym)
-   apply (simp_all add: eucl_rel_int_iff linorder_neq_iff split: if_split_asm)
-     apply (blast intro: order_eq_refl [THEN unique_quotient_lemma] order_eq_refl [THEN unique_quotient_lemma_neg] sym)+
-  done
-
-lemma unique_remainder:
-  assumes "eucl_rel_int a b (q, r)"
-    and "eucl_rel_int a b (q', r')"
-  shows "r = r'"
-proof -
-  have "q = q'"
-    using assms by (blast intro: unique_quotient)
-  then show "r = r'"
-    using assms by (simp add: eucl_rel_int_iff)
-qed
-
-lemma eucl_rel_int:
-  "eucl_rel_int k l (k div l, k mod l)"
-proof (cases k rule: int_cases3)
-  case zero
-  then show ?thesis
-    by (simp add: eucl_rel_int_iff divide_int_def modulo_int_def)
-next
-  case (pos n)
-  then show ?thesis
-    using div_mult_mod_eq [of n]
-    by (cases l rule: int_cases3)
-      (auto simp del: of_nat_mult of_nat_add
-        simp add: mod_greater_zero_iff_not_dvd of_nat_mult [symmetric] of_nat_add [symmetric] algebra_simps
-        eucl_rel_int_iff divide_int_def modulo_int_def)
-next
-  case (neg n)
-  then show ?thesis
-    using div_mult_mod_eq [of n]
-    by (cases l rule: int_cases3)
-      (auto simp del: of_nat_mult of_nat_add
-        simp add: mod_greater_zero_iff_not_dvd of_nat_mult [symmetric] of_nat_add [symmetric] algebra_simps
-        eucl_rel_int_iff divide_int_def modulo_int_def)
-qed
-
-lemma divmod_int_unique:
-  assumes "eucl_rel_int k l (q, r)"
-  shows div_int_unique: "k div l = q" and mod_int_unique: "k mod l = r"
-  using assms eucl_rel_int [of k l]
-  using unique_quotient [of k l] unique_remainder [of k l]
-  by auto
-
-lemma div_pos_geq:
-  fixes k l :: int
-  assumes "0 < l" and "l \<le> k"
-  shows "k div l = (k - l) div l + 1"
-proof -
-  have "k = (k - l) + l" by simp
-  then obtain j where k: "k = j + l" ..
-  with assms show ?thesis by (simp add: div_add_self2)
-qed
-
-lemma mod_pos_geq:
-  fixes k l :: int
-  assumes "0 < l" and "l \<le> k"
-  shows "k mod l = (k - l) mod l"
-proof -
-  have "k = (k - l) + l" by simp
-  then obtain j where k: "k = j + l" ..
-  with assms show ?thesis by simp
-qed
-
-lemma pos_eucl_rel_int_mult_2:
-  assumes "0 \<le> b"
-  assumes "eucl_rel_int a b (q, r)"
-  shows "eucl_rel_int (1 + 2*a) (2*b) (q, 1 + 2*r)"
-  using assms unfolding eucl_rel_int_iff by auto
-
-lemma neg_eucl_rel_int_mult_2:
-  assumes "b \<le> 0"
-  assumes "eucl_rel_int (a + 1) b (q, r)"
-  shows "eucl_rel_int (1 + 2*a) (2*b) (q, 2*r - 1)"
-  using assms unfolding eucl_rel_int_iff by auto
-
-text\<open>computing div by shifting\<close>
-
-lemma pos_zdiv_mult_2: "(0::int) \<le> a ==> (1 + 2*b) div (2*a) = b div a"
-  using pos_eucl_rel_int_mult_2 [OF _ eucl_rel_int]
-  by (rule div_int_unique)
-
-lemma neg_zdiv_mult_2:
-  assumes A: "a \<le> (0::int)" shows "(1 + 2*b) div (2*a) = (b+1) div a"
-  using neg_eucl_rel_int_mult_2 [OF A eucl_rel_int]
-  by (rule div_int_unique)
-
-lemma zdiv_numeral_Bit0 [simp]:
-  "numeral (Num.Bit0 v) div numeral (Num.Bit0 w) =
-    numeral v div (numeral w :: int)"
-  unfolding numeral.simps unfolding mult_2 [symmetric]
-  by (rule div_mult_mult1, simp)
-
-lemma zdiv_numeral_Bit1 [simp]:
-  "numeral (Num.Bit1 v) div numeral (Num.Bit0 w) =
-    (numeral v div (numeral w :: int))"
-  unfolding numeral.simps
-  unfolding mult_2 [symmetric] add.commute [of _ 1]
-  by (rule pos_zdiv_mult_2, simp)
-
-lemma pos_zmod_mult_2:
-  fixes a b :: int
-  assumes "0 \<le> a"
-  shows "(1 + 2 * b) mod (2 * a) = 1 + 2 * (b mod a)"
-  using pos_eucl_rel_int_mult_2 [OF assms eucl_rel_int]
-  by (rule mod_int_unique)
-
-lemma neg_zmod_mult_2:
-  fixes a b :: int
-  assumes "a \<le> 0"
-  shows "(1 + 2 * b) mod (2 * a) = 2 * ((b + 1) mod a) - 1"
-  using neg_eucl_rel_int_mult_2 [OF assms eucl_rel_int]
-  by (rule mod_int_unique)
-
-lemma zmod_numeral_Bit0 [simp]:
-  "numeral (Num.Bit0 v) mod numeral (Num.Bit0 w) =
-    (2::int) * (numeral v mod numeral w)"
-  unfolding numeral_Bit0 [of v] numeral_Bit0 [of w]
-  unfolding mult_2 [symmetric] by (rule mod_mult_mult1)
-
-lemma zmod_numeral_Bit1 [simp]:
-  "numeral (Num.Bit1 v) mod numeral (Num.Bit0 w) =
-    2 * (numeral v mod numeral w) + (1::int)"
-  unfolding numeral_Bit1 [of v] numeral_Bit0 [of w]
-  unfolding mult_2 [symmetric] add.commute [of _ 1]
-  by (rule pos_zmod_mult_2, simp)
-
-  
 subsubsection \<open>Quotients of Signs\<close>
 
 lemma div_eq_minus1: "0 < b \<Longrightarrow> - 1 div b = - 1" for b :: int
@@ -402,6 +253,29 @@
     sgn_mult sgn_1_pos sgn_1_neg sgn_eq_0_iff nonneg1_imp_zdiv_pos_iff * dest: sgn_not_eq_imp)
 qed
 
+lemma
+  fixes a b q r :: int
+  assumes \<open>a = b * q + r\<close> \<open>0 \<le> r\<close> \<open>r < b\<close>
+  shows int_div_pos_eq:
+      \<open>a div b = q\<close> (is ?Q)
+    and int_mod_pos_eq:
+      \<open>a mod b = r\<close> (is ?R)
+proof -
+  from assms have \<open>(a div b, a mod b) = (q, r)\<close>
+    by (cases b q r a rule: euclidean_relationI)
+      (auto simp add: division_segment_int_def ac_simps dvd_add_left_iff dest: zdvd_imp_le)
+  then show ?Q and ?R
+    by simp_all
+qed
+
+lemma int_div_neg_eq:
+  \<open>a div b = q\<close> if \<open>a = b * q + r\<close> \<open>r \<le> 0\<close> \<open>b < r\<close> for a b q r :: int
+  using that int_div_pos_eq [of a \<open>- b\<close> \<open>- q\<close> \<open>- r\<close>] by simp_all
+
+lemma int_mod_neg_eq:
+  \<open>a mod b = r\<close> if \<open>a = b * q + r\<close> \<open>r \<le> 0\<close> \<open>b < r\<close> for a b q r :: int
+  using that int_div_neg_eq [of a b q r] by simp
+
 
 subsubsection \<open>Further properties\<close>
 
@@ -430,21 +304,6 @@
 
 text \<open>Simplify expressions in which div and mod combine numerical constants\<close>
 
-lemma int_div_pos_eq: "\<lbrakk>(a::int) = b * q + r; 0 \<le> r; r < b\<rbrakk> \<Longrightarrow> a div b = q"
-  by (rule div_int_unique [of a b q r]) (simp add: eucl_rel_int_iff)
-
-lemma int_div_neg_eq: "\<lbrakk>(a::int) = b * q + r; r \<le> 0; b < r\<rbrakk> \<Longrightarrow> a div b = q"
-  by (rule div_int_unique [of a b q r],
-    simp add: eucl_rel_int_iff)
-
-lemma int_mod_pos_eq: "\<lbrakk>(a::int) = b * q + r; 0 \<le> r; r < b\<rbrakk> \<Longrightarrow> a mod b = r"
-  by (rule mod_int_unique [of a b q r],
-    simp add: eucl_rel_int_iff)
-
-lemma int_mod_neg_eq: "\<lbrakk>(a::int) = b * q + r; r \<le> 0; b < r\<rbrakk> \<Longrightarrow> a mod b = r"
-  by (rule mod_int_unique [of a b q r],
-    simp add: eucl_rel_int_iff)
-
 lemma abs_div: "(y::int) dvd x \<Longrightarrow> \<bar>x div y\<bar> = \<bar>x\<bar> div \<bar>y\<bar>"
   unfolding dvd_def by (cases "y=0") (auto simp add: abs_mult)
 
@@ -541,6 +400,157 @@
 qed
 
 
+subsubsection \<open>Uniqueness rules\<close>
+
+inductive eucl_rel_int :: "int \<Rightarrow> int \<Rightarrow> int \<times> int \<Rightarrow> bool"
+  where eucl_rel_int_by0: "eucl_rel_int k 0 (0, k)"
+  | eucl_rel_int_dividesI: "l \<noteq> 0 \<Longrightarrow> k = q * l \<Longrightarrow> eucl_rel_int k l (q, 0)"
+  | eucl_rel_int_remainderI: "sgn r = sgn l \<Longrightarrow> \<bar>r\<bar> < \<bar>l\<bar>
+      \<Longrightarrow> k = q * l + r \<Longrightarrow> eucl_rel_int k l (q, r)"
+
+lemma eucl_rel_int_iff:    
+  "eucl_rel_int k l (q, r) \<longleftrightarrow> 
+    k = l * q + r \<and>
+     (if 0 < l then 0 \<le> r \<and> r < l else if l < 0 then l < r \<and> r \<le> 0 else q = 0)"
+  by (cases "r = 0")
+    (auto elim!: eucl_rel_int.cases intro: eucl_rel_int_by0 eucl_rel_int_dividesI eucl_rel_int_remainderI
+    simp add: ac_simps sgn_1_pos sgn_1_neg)
+
+lemma eucl_rel_int:
+  "eucl_rel_int k l (k div l, k mod l)"
+proof (cases k rule: int_cases3)
+  case zero
+  then show ?thesis
+    by (simp add: eucl_rel_int_iff divide_int_def modulo_int_def)
+next
+  case (pos n)
+  then show ?thesis
+    using div_mult_mod_eq [of n]
+    by (cases l rule: int_cases3)
+      (auto simp del: of_nat_mult of_nat_add
+        simp add: mod_greater_zero_iff_not_dvd of_nat_mult [symmetric] of_nat_add [symmetric] algebra_simps
+        eucl_rel_int_iff divide_int_def modulo_int_def)
+next
+  case (neg n)
+  then show ?thesis
+    using div_mult_mod_eq [of n]
+    by (cases l rule: int_cases3)
+      (auto simp del: of_nat_mult of_nat_add
+        simp add: mod_greater_zero_iff_not_dvd of_nat_mult [symmetric] of_nat_add [symmetric] algebra_simps
+        eucl_rel_int_iff divide_int_def modulo_int_def)
+qed
+
+lemma unique_quotient:
+  \<open>q = q'\<close> if \<open>eucl_rel_int a b (q, r)\<close> \<open>eucl_rel_int a b (q', r')\<close>
+  apply (rule order_antisym)
+  using that
+   apply (simp_all add: eucl_rel_int_iff linorder_neq_iff split: if_split_asm)
+     apply (blast intro: order_eq_refl [THEN unique_quotient_lemma] order_eq_refl [THEN unique_quotient_lemma_neg] sym)+
+  done
+
+lemma unique_remainder:
+  \<open>r = r'\<close> if \<open>eucl_rel_int a b (q, r)\<close> \<open>eucl_rel_int a b (q', r')\<close>
+proof -
+  have \<open>q = q'\<close>
+    using that by (blast intro: unique_quotient)
+  then show ?thesis
+    using that by (simp add: eucl_rel_int_iff)
+qed
+
+lemma divmod_int_unique:
+  assumes \<open>eucl_rel_int k l (q, r)\<close>
+  shows div_int_unique: \<open>k div l = q\<close> and mod_int_unique: \<open>k mod l = r\<close>
+  using assms eucl_rel_int [of k l]
+  using unique_quotient [of k l] unique_remainder [of k l]
+  by auto
+
+
+subsubsection \<open>Computing \<open>div\<close> and \<open>mod\<close> with shifting\<close>
+
+lemma div_pos_geq:
+  fixes k l :: int
+  assumes "0 < l" and "l \<le> k"
+  shows "k div l = (k - l) div l + 1"
+proof -
+  have "k = (k - l) + l" by simp
+  then obtain j where k: "k = j + l" ..
+  with assms show ?thesis by (simp add: div_add_self2)
+qed
+
+lemma mod_pos_geq:
+  fixes k l :: int
+  assumes "0 < l" and "l \<le> k"
+  shows "k mod l = (k - l) mod l"
+proof -
+  have "k = (k - l) + l" by simp
+  then obtain j where k: "k = j + l" ..
+  with assms show ?thesis by simp
+qed
+
+lemma pos_eucl_rel_int_mult_2:
+  assumes "0 \<le> b"
+  assumes "eucl_rel_int a b (q, r)"
+  shows "eucl_rel_int (1 + 2*a) (2*b) (q, 1 + 2*r)"
+  using assms unfolding eucl_rel_int_iff by auto
+
+lemma neg_eucl_rel_int_mult_2:
+  assumes "b \<le> 0"
+  assumes "eucl_rel_int (a + 1) b (q, r)"
+  shows "eucl_rel_int (1 + 2*a) (2*b) (q, 2*r - 1)"
+  using assms unfolding eucl_rel_int_iff by auto
+
+text\<open>computing div by shifting\<close>
+
+lemma pos_zdiv_mult_2: "(0::int) \<le> a ==> (1 + 2*b) div (2*a) = b div a"
+  using pos_eucl_rel_int_mult_2 [OF _ eucl_rel_int]
+  by (rule div_int_unique)
+
+lemma neg_zdiv_mult_2:
+  assumes A: "a \<le> (0::int)" shows "(1 + 2*b) div (2*a) = (b+1) div a"
+  using neg_eucl_rel_int_mult_2 [OF A eucl_rel_int]
+  by (rule div_int_unique)
+
+lemma zdiv_numeral_Bit0 [simp]:
+  "numeral (Num.Bit0 v) div numeral (Num.Bit0 w) =
+    numeral v div (numeral w :: int)"
+  unfolding numeral.simps unfolding mult_2 [symmetric]
+  by (rule div_mult_mult1, simp)
+
+lemma zdiv_numeral_Bit1 [simp]:
+  "numeral (Num.Bit1 v) div numeral (Num.Bit0 w) =
+    (numeral v div (numeral w :: int))"
+  unfolding numeral.simps
+  unfolding mult_2 [symmetric] add.commute [of _ 1]
+  by (rule pos_zdiv_mult_2, simp)
+
+lemma pos_zmod_mult_2:
+  fixes a b :: int
+  assumes "0 \<le> a"
+  shows "(1 + 2 * b) mod (2 * a) = 1 + 2 * (b mod a)"
+  using pos_eucl_rel_int_mult_2 [OF assms eucl_rel_int]
+  by (rule mod_int_unique)
+
+lemma neg_zmod_mult_2:
+  fixes a b :: int
+  assumes "a \<le> 0"
+  shows "(1 + 2 * b) mod (2 * a) = 2 * ((b + 1) mod a) - 1"
+  using neg_eucl_rel_int_mult_2 [OF assms eucl_rel_int]
+  by (rule mod_int_unique)
+
+lemma zmod_numeral_Bit0 [simp]:
+  "numeral (Num.Bit0 v) mod numeral (Num.Bit0 w) =
+    (2::int) * (numeral v mod numeral w)"
+  unfolding numeral_Bit0 [of v] numeral_Bit0 [of w]
+  unfolding mult_2 [symmetric] by (rule mod_mult_mult1)
+
+lemma zmod_numeral_Bit1 [simp]:
+  "numeral (Num.Bit1 v) mod numeral (Num.Bit0 w) =
+    2 * (numeral v mod numeral w) + (1::int)"
+  unfolding numeral_Bit1 [of v] numeral_Bit0 [of w]
+  unfolding mult_2 [symmetric] add.commute [of _ 1]
+  by (rule pos_zmod_mult_2, simp)
+
+  
 code_identifier
   code_module Divides \<rightharpoonup> (SML) Arith and (OCaml) Arith and (Haskell) Arith
 
--- a/src/HOL/Euclidean_Division.thy	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/HOL/Euclidean_Division.thy	Wed Sep 07 08:58:27 2022 +0200
@@ -605,205 +605,235 @@
 subsection \<open>Uniquely determined division\<close>
 
 class unique_euclidean_semiring = euclidean_semiring + 
-  assumes euclidean_size_mult: "euclidean_size (a * b) = euclidean_size a * euclidean_size b"
-  fixes division_segment :: "'a \<Rightarrow> 'a"
-  assumes is_unit_division_segment [simp]: "is_unit (division_segment a)"
+  assumes euclidean_size_mult: \<open>euclidean_size (a * b) = euclidean_size a * euclidean_size b\<close>
+  fixes division_segment :: \<open>'a \<Rightarrow> 'a\<close>
+  assumes is_unit_division_segment [simp]: \<open>is_unit (division_segment a)\<close>
     and division_segment_mult:
-    "a \<noteq> 0 \<Longrightarrow> b \<noteq> 0 \<Longrightarrow> division_segment (a * b) = division_segment a * division_segment b"
+    \<open>a \<noteq> 0 \<Longrightarrow> b \<noteq> 0 \<Longrightarrow> division_segment (a * b) = division_segment a * division_segment b\<close>
     and division_segment_mod:
-    "b \<noteq> 0 \<Longrightarrow> \<not> b dvd a \<Longrightarrow> division_segment (a mod b) = division_segment b"
+    \<open>b \<noteq> 0 \<Longrightarrow> \<not> b dvd a \<Longrightarrow> division_segment (a mod b) = division_segment b\<close>
   assumes div_bounded:
-    "b \<noteq> 0 \<Longrightarrow> division_segment r = division_segment b
+    \<open>b \<noteq> 0 \<Longrightarrow> division_segment r = division_segment b
     \<Longrightarrow> euclidean_size r < euclidean_size b
-    \<Longrightarrow> (q * b + r) div b = q"
+    \<Longrightarrow> (q * b + r) div b = q\<close>
 begin
 
 lemma division_segment_not_0 [simp]:
-  "division_segment a \<noteq> 0"
-  using is_unit_division_segment [of a] is_unitE [of "division_segment a"] by blast
-
-lemma divmod_cases [case_names divides remainder by0]:
-  obtains 
-    (divides) q where "b \<noteq> 0"
-      and "a div b = q"
-      and "a mod b = 0"
-      and "a = q * b"
-  | (remainder) q r where "b \<noteq> 0"
-      and "division_segment r = division_segment b"
-      and "euclidean_size r < euclidean_size b"
-      and "r \<noteq> 0"
-      and "a div b = q"
-      and "a mod b = r"
-      and "a = q * b + r"
-  | (by0) "b = 0"
-proof (cases "b = 0")
+  \<open>division_segment a \<noteq> 0\<close>
+  using is_unit_division_segment [of a] is_unitE [of \<open>division_segment a\<close>] by blast
+
+lemma euclidean_relationI [case_names by0 divides euclidean_relation]:
+  \<open>(a div b, a mod b) = (q, r)\<close>
+    if by0: \<open>b = 0 \<Longrightarrow> q = 0 \<and> r = a\<close>
+    and divides: \<open>b \<noteq> 0 \<Longrightarrow> b dvd a \<Longrightarrow> r = 0 \<and> a = q * b\<close>
+    and euclidean_relation: \<open>b \<noteq> 0 \<Longrightarrow> \<not> b dvd a \<Longrightarrow> division_segment r = division_segment b
+      \<and> euclidean_size r < euclidean_size b \<and> a = q * b + r\<close>
+proof (cases \<open>b = 0\<close>)
   case True
-  then show thesis
-  by (rule by0)
+  with by0 show ?thesis
+    by simp
 next
   case False
-  show thesis
-  proof (cases "b dvd a")
+  show ?thesis
+  proof (cases \<open>b dvd a\<close>)
     case True
-    then obtain q where "a = b * q" ..
     with \<open>b \<noteq> 0\<close> divides
-    show thesis
-      by (simp add: ac_simps)
+    show ?thesis
+      by simp
   next
     case False
-    then have "a mod b \<noteq> 0"
-      by (simp add: mod_eq_0_iff_dvd)
-    moreover from \<open>b \<noteq> 0\<close> \<open>\<not> b dvd a\<close> have "division_segment (a mod b) = division_segment b"
-      by (rule division_segment_mod)
-    moreover have "euclidean_size (a mod b) < euclidean_size b"
-      using \<open>b \<noteq> 0\<close> by (rule mod_size_less)
-    moreover have "a = a div b * b + a mod b"
+    with \<open>b \<noteq> 0\<close> euclidean_relation
+    have \<open>division_segment r = division_segment b\<close>
+      \<open>euclidean_size r < euclidean_size b\<close> \<open>a = q * b + r\<close>
+      by simp_all
+    from \<open>b \<noteq> 0\<close> \<open>division_segment r = division_segment b\<close>
+      \<open>euclidean_size r < euclidean_size b\<close>
+    have \<open>(q * b + r) div b = q\<close>
+      by (rule div_bounded)
+    with \<open>a = q * b + r\<close>
+    have \<open>q = a div b\<close>
+      by simp
+    from \<open>a = q * b + r\<close>
+    have \<open>a div b * b + a mod b = q * b + r\<close>
       by (simp add: div_mult_mod_eq)
-    ultimately show thesis
-      using \<open>b \<noteq> 0\<close> by (blast intro!: remainder)
+    with \<open>q = a div b\<close>
+    have \<open>q * b + a mod b = q * b + r\<close>
+      by simp
+    then have \<open>r = a mod b\<close>
+      by simp
+    with \<open>q = a div b\<close>
+    show ?thesis
+      by simp
   qed
 qed
 
-lemma div_eqI:
-  "a div b = q" if "b \<noteq> 0" "division_segment r = division_segment b"
-    "euclidean_size r < euclidean_size b" "q * b + r = a"
-proof -
-  from that have "(q * b + r) div b = q"
-    by (auto intro: div_bounded)
-  with that show ?thesis
-    by simp
-qed
-
-lemma mod_eqI:
-  "a mod b = r" if "b \<noteq> 0" "division_segment r = division_segment b"
-    "euclidean_size r < euclidean_size b" "q * b + r = a" 
-proof -
-  from that have "a div b = q"
-    by (rule div_eqI)
-  moreover have "a div b * b + a mod b = a"
-    by (fact div_mult_mod_eq)
-  ultimately have "a div b * b + a mod b = a div b * b + r"
-    using \<open>q * b + r = a\<close> by simp
-  then show ?thesis
-    by simp
-qed
-
 subclass euclidean_semiring_cancel
 proof
-  show "(a + c * b) div b = c + a div b" if "b \<noteq> 0" for a b c
-  proof (cases a b rule: divmod_cases)
+  fix a b c
+  assume \<open>b \<noteq> 0\<close>
+  have \<open>((a + c * b) div b, (a + c * b) mod b) = (c + a div b, a mod b)\<close>
+  proof (cases b \<open>c + a div b\<close> \<open>a mod b\<close> \<open>a + c * b\<close> rule: euclidean_relationI)
     case by0
-    with \<open>b \<noteq> 0\<close> show ?thesis
+    with \<open>b \<noteq> 0\<close>
+    show ?case
+      by simp
+  next
+    case divides
+    then show ?case
+      by (simp add: algebra_simps dvd_add_left_iff)
+  next
+    case euclidean_relation
+    then have \<open>\<not> b dvd a\<close>
+      by (simp add: dvd_add_left_iff)
+    have \<open>a mod b + (b * c + b * (a div b)) = b * c + ((a div b) * b + a mod b)\<close>
+      by (simp add: ac_simps)
+    with \<open>b \<noteq> 0\<close> have *: \<open>a mod b + (b * c + b * (a div b)) = b * c + a\<close>
+      by (simp add: div_mult_mod_eq)
+    from \<open>\<not> b dvd a\<close> euclidean_relation show ?case
+      by (simp_all add: algebra_simps division_segment_mod mod_size_less *)
+  qed
+  then show \<open>(a + c * b) div b = c + a div b\<close>
+    by simp
+next
+  fix a b c
+  assume \<open>c \<noteq> 0\<close>
+  have \<open>((c * a) div (c * b), (c * a) mod (c * b)) = (a div b, c * (a mod b))\<close>
+  proof (cases \<open>c * b\<close> \<open>a div b\<close> \<open>c * (a mod b)\<close> \<open>c * a\<close> rule: euclidean_relationI)
+    case by0
+    with \<open>c \<noteq> 0\<close> show ?case
       by simp
   next
-    case (divides q)
-    then show ?thesis
-      by (simp add: ac_simps)
+    case divides
+    then show ?case
+      by (auto simp add: algebra_simps)
   next
-    case (remainder q r)
-    then show ?thesis
-      by (auto intro: div_eqI simp add: algebra_simps)
+    case euclidean_relation
+    then have \<open>b \<noteq> 0\<close> \<open>a mod b \<noteq> 0\<close>
+      by (simp_all add: mod_eq_0_iff_dvd)
+    have \<open>c * (a mod b) + b * (c * (a div b)) = c * ((a div b) * b + a mod b)\<close>
+      by (simp add: algebra_simps)
+    with \<open>b \<noteq> 0\<close> have *: \<open>c * (a mod b) + b * (c * (a div b)) = c * a\<close>
+      by (simp add: div_mult_mod_eq)
+    from \<open>b \<noteq> 0\<close> \<open>c \<noteq> 0\<close> have \<open>euclidean_size c * euclidean_size (a mod b)
+      < euclidean_size c * euclidean_size b\<close>
+      using mod_size_less [of b a] by simp
+    with euclidean_relation \<open>b \<noteq> 0\<close> \<open>a mod b \<noteq> 0\<close> show ?case
+      by (simp add: algebra_simps division_segment_mult division_segment_mod euclidean_size_mult *)
   qed
+  then show \<open>(c * a) div (c * b) = a div b\<close>
+    by simp
+qed
+
+lemma div_eq_0_iff:
+  \<open>a div b = 0 \<longleftrightarrow> euclidean_size a < euclidean_size b \<or> b = 0\<close> (is "_ \<longleftrightarrow> ?P")
+  if \<open>division_segment a = division_segment b\<close>
+proof (cases \<open>a = 0 \<or> b = 0\<close>)
+  case True
+  then show ?thesis by auto
 next
-  show"(c * a) div (c * b) = a div b" if "c \<noteq> 0" for a b c
-  proof (cases a b rule: divmod_cases)
-    case by0
-    then show ?thesis
+  case False
+  then have \<open>a \<noteq> 0\<close> \<open>b \<noteq> 0\<close>
+    by simp_all
+  have \<open>a div b = 0 \<longleftrightarrow> euclidean_size a < euclidean_size b\<close>
+  proof
+    assume \<open>a div b = 0\<close>
+    then have \<open>a mod b = a\<close>
+      using div_mult_mod_eq [of a b] by simp
+    with \<open>b \<noteq> 0\<close> mod_size_less [of b a]
+    show \<open>euclidean_size a < euclidean_size b\<close>
       by simp
   next
-    case (divides q)
-    with \<open>c \<noteq> 0\<close> show ?thesis
-      by (simp add: mult.left_commute [of c])
-  next
-    case (remainder q r)
-    from \<open>b \<noteq> 0\<close> \<open>c \<noteq> 0\<close> have "b * c \<noteq> 0"
+    assume \<open>euclidean_size a < euclidean_size b\<close>
+    have \<open>(a div b, a mod b) = (0, a)\<close>
+    proof (cases b 0 a a rule: euclidean_relationI)
+      case by0
+      show ?case
+        by simp
+    next
+      case divides
+      with \<open>euclidean_size a < euclidean_size b\<close> show ?case
+        using dvd_imp_size_le [of b a] \<open>a \<noteq> 0\<close> by simp
+    next
+      case euclidean_relation
+      with \<open>euclidean_size a < euclidean_size b\<close> that
+      show ?case
+        by simp
+    qed
+    then show \<open>a div b = 0\<close>
       by simp
-    from remainder \<open>c \<noteq> 0\<close>
-    have "division_segment (r * c) = division_segment (b * c)"
-      and "euclidean_size (r * c) < euclidean_size (b * c)"
-      by (simp_all add: division_segment_mult division_segment_mod euclidean_size_mult)
-    with remainder show ?thesis
-      by (auto intro!: div_eqI [of _ "c * (a mod b)"] simp add: algebra_simps)
-        (use \<open>b * c \<noteq> 0\<close> in simp)
   qed
+  with \<open>b \<noteq> 0\<close> show ?thesis
+    by simp
 qed
 
 lemma div_mult1_eq:
-  "(a * b) div c = a * (b div c) + a * (b mod c) div c"
-proof (cases "a * (b mod c)" c rule: divmod_cases)
-  case (divides q)
-  have "a * b = a * (b div c * c + b mod c)"
-    by (simp add: div_mult_mod_eq)
-  also have "\<dots> = (a * (b div c) + q) * c"
-    using divides by (simp add: algebra_simps)
-  finally have "(a * b) div c = \<dots> div c"
-    by simp
-  with divides show ?thesis
-    by simp
-next
-  case (remainder q r)
-  from remainder(1-3) show ?thesis
-  proof (rule div_eqI)
-    have "a * b = a * (b div c * c + b mod c)"
-      by (simp add: div_mult_mod_eq)
-    also have "\<dots> = a * c * (b div c) + q * c + r"
-      using remainder by (simp add: algebra_simps)
-    finally show "(a * (b div c) + a * (b mod c) div c) * c + r = a * b"
-      using remainder(5-7) by (simp add: algebra_simps)
+  \<open>(a * b) div c = a * (b div c) + a * (b mod c) div c\<close>
+proof -
+  have *: \<open>(a * b) mod c + (a * (c * (b div c)) + c * (a * (b mod c) div c)) = a * b\<close> (is \<open>?A + (?B + ?C) = _\<close>)
+  proof -
+    have \<open>?A = a * (b mod c) mod c\<close>
+      by (simp add: mod_mult_right_eq)
+    then have \<open>?C + ?A = a * (b mod c)\<close>
+      by (simp add: mult_div_mod_eq)
+    then have \<open>?B + (?C + ?A) = a * (c * (b div c) + (b mod c))\<close>
+      by (simp add: algebra_simps)
+    also have \<open>\<dots> = a * b\<close>
+      by (simp add: mult_div_mod_eq)
+    finally show ?thesis
+      by (simp add: algebra_simps)
   qed
-next
-  case by0
+  have \<open>((a * b) div c, (a * b) mod c) = (a * (b div c) + a * (b mod c) div c, (a * b) mod c)\<close>
+  proof (cases c \<open>a * (b div c) + a * (b mod c) div c\<close> \<open>(a * b) mod c\<close> \<open>a * b\<close> rule: euclidean_relationI)
+    case by0
+    then show ?case by simp
+  next
+    case divides
+    with * show ?case
+      by (simp add: algebra_simps)
+  next
+    case euclidean_relation
+    with * show ?case
+      by (simp add: division_segment_mod mod_size_less algebra_simps)
+  qed
   then show ?thesis
     by simp
 qed
 
 lemma div_add1_eq:
-  "(a + b) div c = a div c + b div c + (a mod c + b mod c) div c"
-proof (cases "a mod c + b mod c" c rule: divmod_cases)
-  case (divides q)
-  have "a + b = (a div c * c + a mod c) + (b div c * c + b mod c)"
-    using mod_mult_div_eq [of a c] mod_mult_div_eq [of b c] by (simp add: ac_simps)
-  also have "\<dots> = (a div c + b div c) * c + (a mod c + b mod c)"
-    by (simp add: algebra_simps)
-  also have "\<dots> = (a div c + b div c + q) * c"
-    using divides by (simp add: algebra_simps)
-  finally have "(a + b) div c = (a div c + b div c + q) * c div c"
-    by simp
-  with divides show ?thesis
-    by simp
-next
-  case (remainder q r)
-  from remainder(1-3) show ?thesis
-  proof (rule div_eqI)
-    have "(a div c + b div c + q) * c + r + (a mod c + b mod c) =
-        (a div c * c + a mod c) + (b div c * c + b mod c) + q * c + r"
+  \<open>(a + b) div c = a div c + b div c + (a mod c + b mod c) div c\<close>
+proof -
+  have *: \<open>(a + b) mod c + (c * (a div c) + (c * (b div c) + c * ((a mod c + b mod c) div c))) = a + b\<close>
+    (is \<open>?A + (?B + (?C + ?D)) = _\<close>)
+  proof -
+    have \<open>?A + (?B + (?C + ?D)) = ?A + ?D + (?B + ?C)\<close>
+      by (simp add: ac_simps)
+    also have \<open>?A + ?D = (a mod c + b mod c) mod c + ?D\<close>
+      by (simp add: mod_add_eq)
+    also have \<open>\<dots> = a mod c + b mod c\<close>
+      by (simp add: mod_mult_div_eq)
+    finally have \<open>?A + (?B + (?C + ?D)) = (a mod c + ?B) + (b mod c + ?C)\<close>
+      by (simp add: ac_simps)
+    then show ?thesis
+      by (simp add: mod_mult_div_eq)
+  qed
+  have \<open>((a + b) div c, (a + b) mod c) = (a div c + b div c + (a mod c + b mod c) div c, (a + b) mod c)\<close>
+  proof (cases c \<open>a div c + b div c + (a mod c + b mod c) div c\<close> \<open>(a + b) mod c\<close> \<open>a + b\<close> rule: euclidean_relationI)
+    case by0
+    then show ?case
+      by simp
+  next
+    case divides
+    with * show ?case
       by (simp add: algebra_simps)
-    also have "\<dots> = a + b + (a mod c + b mod c)"
-      by (simp add: div_mult_mod_eq remainder) (simp add: ac_simps)
-    finally show "(a div c + b div c + (a mod c + b mod c) div c) * c + r = a + b"
-      using remainder by simp
+  next
+    case euclidean_relation
+    with * show ?case
+      by (simp add: division_segment_mod mod_size_less algebra_simps)
   qed
-next
-  case by0
   then show ?thesis
     by simp
 qed
 
-lemma div_eq_0_iff:
-  "a div b = 0 \<longleftrightarrow> euclidean_size a < euclidean_size b \<or> b = 0" (is "_ \<longleftrightarrow> ?P")
-  if "division_segment a = division_segment b"
-proof
-  assume ?P
-  with that show "a div b = 0"
-    by (cases "b = 0") (auto intro: div_eqI)
-next
-  assume "a div b = 0"
-  then have "a mod b = a"
-    using div_mult_mod_eq [of a b] by simp
-  with mod_size_less [of b a] show ?P
-    by auto
-qed
-
 end
 
 class unique_euclidean_ring = euclidean_ring + unique_euclidean_semiring
@@ -819,19 +849,19 @@
 instantiation nat :: normalization_semidom
 begin
 
-definition normalize_nat :: "nat \<Rightarrow> nat"
-  where [simp]: "normalize = (id :: nat \<Rightarrow> nat)"
-
-definition unit_factor_nat :: "nat \<Rightarrow> nat"
-  where "unit_factor n = (if n = 0 then 0 else 1 :: nat)"
+definition normalize_nat :: \<open>nat \<Rightarrow> nat\<close>
+  where [simp]: \<open>normalize = (id :: nat \<Rightarrow> nat)\<close>
+
+definition unit_factor_nat :: \<open>nat \<Rightarrow> nat\<close>
+  where \<open>unit_factor n = of_bool (n > 0)\<close> for n :: nat
 
 lemma unit_factor_simps [simp]:
-  "unit_factor 0 = (0::nat)"
-  "unit_factor (Suc n) = 1"
+  \<open>unit_factor 0 = (0::nat)\<close>
+  \<open>unit_factor (Suc n) = 1\<close>
   by (simp_all add: unit_factor_nat_def)
 
-definition divide_nat :: "nat \<Rightarrow> nat \<Rightarrow> nat"
-  where "m div n = (if n = 0 then 0 else Max {k::nat. k * n \<le> m})"
+definition divide_nat :: \<open>nat \<Rightarrow> nat \<Rightarrow> nat\<close>
+  where \<open>m div n = (if n = 0 then 0 else Max {k. k * n \<le> m})\<close> for m n :: nat
 
 instance
   by standard (auto simp add: divide_nat_def ac_simps unit_factor_nat_def intro: Max_eqI)
@@ -853,14 +883,14 @@
 instantiation nat :: unique_euclidean_semiring
 begin
 
-definition euclidean_size_nat :: "nat \<Rightarrow> nat"
-  where [simp]: "euclidean_size_nat = id"
-
-definition division_segment_nat :: "nat \<Rightarrow> nat"
-  where [simp]: "division_segment_nat n = 1"
-
-definition modulo_nat :: "nat \<Rightarrow> nat \<Rightarrow> nat"
-  where "m mod n = m - (m div n * (n::nat))"
+definition euclidean_size_nat :: \<open>nat \<Rightarrow> nat\<close>
+  where [simp]: \<open>euclidean_size_nat = id\<close>
+
+definition division_segment_nat :: \<open>nat \<Rightarrow> nat\<close>
+  where [simp]: \<open>division_segment n = 1\<close> for n :: nat
+
+definition modulo_nat :: \<open>nat \<Rightarrow> nat \<Rightarrow> nat\<close>
+  where \<open>m mod n = m - (m div n * n)\<close> for m n :: nat
 
 instance proof
   fix m n :: nat
@@ -938,12 +968,60 @@
 end
 
 lemma div_nat_eqI:
-  "m div n = q" if "n * q \<le> m" and "m < n * Suc q" for m n q :: nat
-  by (rule div_eqI [of _ "m - n * q"]) (use that in \<open>simp_all add: algebra_simps\<close>)
+  \<open>m div n = q\<close> if \<open>n * q \<le> m\<close> and \<open>m < n * Suc q\<close> for m n q :: nat
+proof -
+  have \<open>(m div n, m mod n) = (q, m - n * q)\<close>
+  proof (cases n q \<open>m - n * q\<close>  m rule: euclidean_relationI)
+    case by0
+    with that show ?case
+      by simp
+  next
+    case divides
+    from \<open>n dvd m\<close> obtain s where \<open>m = n * s\<close> ..
+    with \<open>n \<noteq> 0\<close> that have \<open>s < Suc q\<close>
+      by (simp only: mult_less_cancel1)
+    with \<open>m = n * s\<close> \<open>n \<noteq> 0\<close> that have \<open>q = s\<close>
+      by simp
+    with \<open>m = n * s\<close> show ?case
+      by (simp add: ac_simps)
+  next
+    case euclidean_relation
+    with that show ?case
+      by (simp add: ac_simps)
+  qed
+  then show ?thesis
+    by simp
+qed
 
 lemma mod_nat_eqI:
-  "m mod n = r" if "r < n" and "r \<le> m" and "n dvd m - r" for m n r :: nat
-  by (rule mod_eqI [of _ _ "(m - r) div n"]) (use that in \<open>simp_all add: algebra_simps\<close>)
+  \<open>m mod n = r\<close> if \<open>r < n\<close> and \<open>r \<le> m\<close> and \<open>n dvd m - r\<close> for m n r :: nat
+proof -
+  have \<open>(m div n, m mod n) = ((m - r) div n, r)\<close>
+  proof (cases n \<open>(m - r) div n\<close> r  m rule: euclidean_relationI)
+    case by0
+    with that show ?case
+      by simp
+  next
+    case divides
+    from that dvd_minus_add [of r \<open>m\<close> 1 n]
+    have \<open>n dvd m + (n - r)\<close>
+      by simp
+    with divides have \<open>n dvd n - r\<close>
+      by (simp add: dvd_add_right_iff)
+    then have \<open>n \<le> n - r\<close>
+      by (rule dvd_imp_le) (use \<open>r < n\<close> in simp)
+    with \<open>n \<noteq> 0\<close> have \<open>r = 0\<close>
+      by simp
+    with \<open>n \<noteq> 0\<close> that show ?case
+      by simp
+  next
+    case euclidean_relation
+    with that show ?case
+      by (simp add: ac_simps)
+  qed
+  then show ?thesis
+    by simp
+qed
 
 text \<open>Tool support\<close>
 
@@ -1029,7 +1107,7 @@
   div_less [simp]: "m div n = 0"
   and mod_less [simp]: "m mod n = m"
   if "m < n" for m n :: nat
-  using that by (auto intro: div_eqI mod_eqI) 
+  using that by (auto intro: div_nat_eqI mod_nat_eqI)
  
 lemma split_div:
   \<open>P (m div n) \<longleftrightarrow>
@@ -1176,54 +1254,43 @@
   "Suc 0 mod n = of_bool (n \<noteq> Suc 0)"
   by (cases n) simp_all
 
-context
-  fixes m n q :: nat
-begin
-
-private lemma eucl_rel_mult2:
-  "m mod n + n * (m div n mod q) < n * q"
-  if "n > 0" and "q > 0"
+lemma div_mult2_eq:
+    \<open>m div (n * q) = (m div n) div q\<close> (is ?Q)
+  and mod_mult2_eq:
+    \<open>m mod (n * q) = n * (m div n mod q) + m mod n\<close> (is ?R)
+  for m n q :: nat
 proof -
-  from \<open>n > 0\<close> have "m mod n < n"
-    by (rule mod_less_divisor)
-  from \<open>q > 0\<close> have "m div n mod q < q"
-    by (rule mod_less_divisor)
-  then obtain s where "q = Suc (m div n mod q + s)"
-    by (blast dest: less_imp_Suc_add)
-  moreover have "m mod n + n * (m div n mod q) < n * Suc (m div n mod q + s)"
-    using \<open>m mod n < n\<close> by (simp add: add_mult_distrib2)
-  ultimately show ?thesis
-    by simp
+  have \<open>(m div (n * q), m mod (n * q)) = ((m div n) div q, n * (m div n mod q) + m mod n)\<close>
+  proof (cases \<open>n * q\<close> \<open>(m div n) div q\<close> \<open>n * (m div n mod q) + m mod n\<close> m rule: euclidean_relationI)
+    case by0
+    then show ?case
+      by auto
+  next
+    case divides
+    from \<open>n * q dvd m\<close> obtain t where \<open>m = n * q * t\<close> ..
+    with \<open>n * q \<noteq> 0\<close> show ?case
+      by (simp add: algebra_simps)
+  next
+    case euclidean_relation
+    then have \<open>n > 0\<close> \<open>q > 0\<close>
+      by simp_all
+    from \<open>n > 0\<close> have \<open>m mod n < n\<close>
+      by (rule mod_less_divisor)
+    from \<open>q > 0\<close> have \<open>m div n mod q < q\<close>
+      by (rule mod_less_divisor)
+    then obtain s where \<open>q = Suc (m div n mod q + s)\<close>
+      by (blast dest: less_imp_Suc_add)
+    moreover have \<open>m mod n + n * (m div n mod q) < n * Suc (m div n mod q + s)\<close>
+      using \<open>m mod n < n\<close> by (simp add: add_mult_distrib2)
+    ultimately have \<open>m mod n + n * (m div n mod q) < n * q\<close>
+      by simp
+    then show ?case
+      by (simp add: algebra_simps flip: add_mult_distrib2)
+  qed
+  then show ?Q and ?R
+    by simp_all
 qed
 
-lemma div_mult2_eq:
-  "m div (n * q) = (m div n) div q"
-proof (cases "n = 0 \<or> q = 0")
-  case True
-  then show ?thesis
-    by auto
-next
-  case False
-  with eucl_rel_mult2 show ?thesis
-    by (auto intro: div_eqI [of _ "n * (m div n mod q) + m mod n"]
-      simp add: algebra_simps add_mult_distrib2 [symmetric])
-qed
-
-lemma mod_mult2_eq:
-  "m mod (n * q) = n * (m div n mod q) + m mod n"
-proof (cases "n = 0 \<or> q = 0")
-  case True
-  then show ?thesis
-    by auto
-next
-  case False
-  with eucl_rel_mult2 show ?thesis
-    by (auto intro: mod_eqI [of _ _ "(m div n) div q"]
-      simp add: algebra_simps add_mult_distrib2 [symmetric])
-qed
-
-end
-
 lemma div_le_mono:
   "m div k \<le> n div k" if "m \<le> n" for m n k :: nat
 proof -
@@ -1864,42 +1931,54 @@
   using div_mult_mod_eq [of 1 "2 ^ n"] by auto
 
 lemma div_mult2_eq':
-  "a div (of_nat m * of_nat n) = a div of_nat m div of_nat n"
-proof (cases a "of_nat m * of_nat n" rule: divmod_cases)
-  case (divides q)
-  then show ?thesis
-    using nonzero_mult_div_cancel_right [of "of_nat m" "q * of_nat n"]
-    by (simp add: ac_simps)
-next
-  case (remainder q r)
-  then have "division_segment r = 1"
-    using division_segment_of_nat [of "m * n"] by simp
-  with division_segment_euclidean_size [of r]
-  have "of_nat (euclidean_size r) = r"
-    by simp
-  have "a mod (of_nat m * of_nat n) div (of_nat m * of_nat n) = 0"
-    by simp
-  with remainder(6) have "r div (of_nat m * of_nat n) = 0"
-    by simp
-  with \<open>of_nat (euclidean_size r) = r\<close>
-  have "of_nat (euclidean_size r) div (of_nat m * of_nat n) = 0"
-    by simp
-  then have "of_nat (euclidean_size r div (m * n)) = 0"
-    by (simp add: of_nat_div)
-  then have "of_nat (euclidean_size r div m div n) = 0"
-    by (simp add: div_mult2_eq)
-  with \<open>of_nat (euclidean_size r) = r\<close> have "r div of_nat m div of_nat n = 0"
-    by (simp add: of_nat_div)
-  with remainder(1)
-  have "q = (r div of_nat m + q * of_nat n * of_nat m div of_nat m) div of_nat n"
-    by simp
-  with remainder(5) remainder(7) show ?thesis
-    using div_plus_div_distrib_dvd_right [of "of_nat m" "q * (of_nat m * of_nat n)" r]
-    by (simp add: ac_simps)
-next
-  case by0
+  \<open>a div (of_nat m * of_nat n) = a div of_nat m div of_nat n\<close>
+proof (cases \<open>m = 0 \<or> n = 0\<close>)
+  case True
   then show ?thesis
     by auto
+next
+  case False
+  then have \<open>m > 0\<close> \<open>n > 0\<close>
+    by simp_all
+  show ?thesis
+  proof (cases \<open>of_nat m * of_nat n dvd a\<close>)
+    case True
+    then obtain b where \<open>a = (of_nat m * of_nat n) * b\<close> ..
+    then have \<open>a = of_nat m * (of_nat n * b)\<close>
+      by (simp add: ac_simps)
+    then show ?thesis
+      by simp
+  next
+    case False
+    define q where \<open>q = a div (of_nat m * of_nat n)\<close>
+    define r where \<open>r = a mod (of_nat m * of_nat n)\<close>
+    from \<open>m > 0\<close> \<open>n > 0\<close> \<open>\<not> of_nat m * of_nat n dvd a\<close> r_def have "division_segment r = 1"
+      using division_segment_of_nat [of "m * n"] by (simp add: division_segment_mod)
+    with division_segment_euclidean_size [of r]
+    have "of_nat (euclidean_size r) = r"
+      by simp
+    have "a mod (of_nat m * of_nat n) div (of_nat m * of_nat n) = 0"
+      by simp
+    with \<open>m > 0\<close> \<open>n > 0\<close> r_def have "r div (of_nat m * of_nat n) = 0"
+      by simp
+    with \<open>of_nat (euclidean_size r) = r\<close>
+    have "of_nat (euclidean_size r) div (of_nat m * of_nat n) = 0"
+      by simp
+    then have "of_nat (euclidean_size r div (m * n)) = 0"
+      by (simp add: of_nat_div)
+    then have "of_nat (euclidean_size r div m div n) = 0"
+      by (simp add: div_mult2_eq)
+    with \<open>of_nat (euclidean_size r) = r\<close> have "r div of_nat m div of_nat n = 0"
+      by (simp add: of_nat_div)
+    with \<open>m > 0\<close> \<open>n > 0\<close> q_def
+    have "q = (r div of_nat m + q * of_nat n * of_nat m div of_nat m) div of_nat n"
+      by simp
+    moreover have \<open>a = q * (of_nat m * of_nat n) + r\<close>
+      by (simp add: q_def r_def div_mult_mod_eq)
+    ultimately show \<open>a div (of_nat m * of_nat n) = a div of_nat m div of_nat n\<close>
+      using q_def [symmetric] div_plus_div_distrib_dvd_right [of \<open>of_nat m\<close> \<open>q * (of_nat m * of_nat n)\<close> r]
+      by (simp add: ac_simps)
+  qed
 qed
 
 lemma mod_mult2_eq':
@@ -2033,31 +2112,45 @@
   using that by (simp add: mod_eq_self_iff_div_eq_0)
 
 lemma div_pos_neg_trivial:
-  "k div l = - 1" if "0 < k" and "k + l \<le> 0" for k l :: int
-proof (cases \<open>l = - k\<close>)
+  \<open>k div l = - 1\<close> if \<open>0 < k\<close> and \<open>k + l \<le> 0\<close> for k l :: int
+proof (cases \<open>l dvd k\<close>)
   case True
-  with that show ?thesis
-    by (simp add: divide_int_def)
+  then obtain j where \<open>k = l * j\<close> ..
+  from that have \<open>l < 0\<close>
+    by simp
+  with \<open>k = l * j\<close> \<open>0 < k\<close> have \<open>j \<le> - 1\<close>
+    by (simp add: zero_less_mult_iff)
+  moreover from \<open>k + l \<le> 0\<close> \<open>k = l * j\<close> have \<open>l * (j + 1) \<le> 0\<close>
+    by (simp add: algebra_simps)
+  with \<open>l < 0\<close> have \<open>- 1 \<le> j\<close>
+    by (simp add: mult_le_0_iff)
+  ultimately have \<open>j = - 1\<close>
+    by (rule order.antisym)
+  with \<open>k = l * j\<close> \<open>l < 0\<close> show ?thesis
+    by (simp add: dvd_neg_div)
 next
   case False
-  show ?thesis
-    apply (rule div_eqI [of _ "k + l"])
-    using False that apply (simp_all add: division_segment_int_def)
-    done
+  have \<open>k + l < 0\<close>
+  proof (rule ccontr)
+    assume \<open>\<not> k + l < 0\<close>
+    with \<open>k + l \<le> 0\<close> have \<open>k + l = 0\<close>
+      by simp
+    then have \<open>k = - l\<close>
+      by simp
+    then have \<open>l dvd k\<close>
+      by simp
+    with \<open>\<not> l dvd k\<close> show False ..
+  qed
+  with that \<open>\<not> l dvd k\<close> show ?thesis
+    by (simp add: div_eq_div_abs [of k l])
 qed
 
 lemma mod_pos_neg_trivial:
-  "k mod l = k + l" if "0 < k" and "k + l \<le> 0" for k l :: int
-proof (cases \<open>l = - k\<close>)
-  case True
-  with that show ?thesis
-    by (simp add: divide_int_def)
-next
-  case False
-  show ?thesis
-    apply (rule mod_eqI [of _ _ \<open>- 1\<close>])
-    using False that apply (simp_all add: division_segment_int_def)
-    done
+  \<open>k mod l = k + l\<close> if \<open>0 < k\<close> and \<open>k + l \<le> 0\<close> for k l :: int
+proof -
+  from that have \<open>k mod l = k div l * l + k mod l + l\<close>
+    by (simp add: div_pos_neg_trivial)
+  then show ?thesis by simp
 qed
 
 text \<open>There is neither \<open>div_neg_pos_trivial\<close> nor \<open>mod_neg_pos_trivial\<close>
--- a/src/HOL/Examples/Records.thy	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/HOL/Examples/Records.thy	Wed Sep 07 08:58:27 2022 +0200
@@ -1,6 +1,7 @@
 (*  Title:      HOL/Examples/Records.thy
     Author:     Wolfgang Naraschewski, TU Muenchen
     Author:     Norbert Schirmer, TU Muenchen
+    Author:     Norbert Schirmer, Apple, 2022
     Author:     Markus Wenzel, TU Muenchen
 *)
 
@@ -294,8 +295,72 @@
   by the following lemma.\<close>
 
 lemma "\<exists>r. xpos r = x"
-  by (tactic \<open>simp_tac (put_simpset HOL_basic_ss \<^context>
-    addsimprocs [Record.ex_sel_eq_simproc]) 1\<close>)
+  supply [[simproc add: Record.ex_sel_eq]]
+  apply (simp)
+  done
+
+subsection \<open>Simprocs for update and equality\<close>
+
+record alph1 =
+a::nat
+b::nat
+
+record alph2 = alph1 +
+c::nat
+d::nat
+
+record alph3 = alph2 + 
+  e::nat
+  f::nat
+
+text \<open>The simprocs that are activated by default are:
+\<^item> @{ML [source] Record.simproc}: field selection of (nested) record updates.
+\<^item> @{ML [source] Record.upd_simproc}: nested record updates.
+\<^item> @{ML [source] Record.eq_simproc}: (componentwise) equality of records.
+\<close>
+
+
+text \<open>By default record updates are not ordered by simplification.\<close>
+schematic_goal "r\<lparr>b := x, a:= y\<rparr> = ?X"
+  by simp
+
+text \<open>Normalisation towards an update ordering (string ordering of update function names) can
+be configured as follows.\<close>
+schematic_goal "r\<lparr>b := y, a := x\<rparr> = ?X"
+  supply [[record_sort_updates]]
+  by simp
+
+text \<open>Note the interplay between update ordering and record equality. Without update ordering
+the following equality is handled by @{ML [source] Record.eq_simproc}. Record equality is thus
+solved by componentwise comparison of all the fields of the records which can be expensive 
+in the presence of many fields.\<close>
+
+lemma "r\<lparr>f := x1, a:= x2\<rparr> = r\<lparr>a := x2, f:= x1\<rparr>"
+  by simp
+
+lemma "r\<lparr>f := x1, a:= x2\<rparr> = r\<lparr>a := x2, f:= x1\<rparr>"
+  supply [[simproc del: Record.eq]]
+  apply (simp?)
+  oops
+
+text \<open>With update ordering the equality is already established after update normalisation. There
+is no need for componentwise comparison.\<close>
+
+lemma "r\<lparr>f := x1, a:= x2\<rparr> = r\<lparr>a := x2, f:= x1\<rparr>"
+  supply [[record_sort_updates, simproc del: Record.eq]]
+  apply simp
+  done
+
+schematic_goal "r\<lparr>f := x1, e := x2, d:= x3, c:= x4, b:=x5, a:= x6\<rparr> = ?X"
+  supply [[record_sort_updates]]
+  by simp
+
+schematic_goal "r\<lparr>f := x1, e := x2, d:= x3, c:= x4, e:=x5, a:= x6\<rparr> = ?X"
+  supply [[record_sort_updates]]
+  by simp
+
+schematic_goal "r\<lparr>f := x1, e := x2, d:= x3, c:= x4, e:=x5, a:= x6\<rparr> = ?X"
+  by simp
 
 
 subsection \<open>A more complex record expression\<close>
@@ -324,6 +389,24 @@
   bar520 :: nat
   bar521 :: "nat \<times> nat"
 
-declare [[record_codegen = true]]
+
+setup \<open>
+let
+ val N = 300
+in
+  Record.add_record {overloaded=false} ([], \<^binding>\<open>large_record\<close>) NONE 
+    (map (fn i => (Binding.make ("fld_" ^ string_of_int i, \<^here>), @{typ nat}, Mixfix.NoSyn)) 
+      (1 upto N))
+end
+\<close>
+
+declare [[record_codegen]]
+
+schematic_goal \<open>fld_1 (r\<lparr>fld_300 := x300, fld_20 := x20, fld_200 := x200\<rparr>) = ?X\<close>
+  by simp
+
+schematic_goal \<open>r\<lparr>fld_300 := x300, fld_20 := x20, fld_200 := x200\<rparr> = ?X\<close>
+  supply [[record_sort_updates]]
+  by simp
 
 end
--- a/src/HOL/Library/conditional_parametricity.ML	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/HOL/Library/conditional_parametricity.ML	Wed Sep 07 08:58:27 2022 +0200
@@ -110,8 +110,7 @@
 (* Tactics  *)
 (* helper tactics for printing *)
 fun error_tac ctxt msg st =
-  (error(msg ^ "\n" ^ Pretty.string_of (Pretty.chunks (Goal_Display.pretty_goals ctxt st)));
-  Seq.single st);
+  (error (msg ^ "\n" ^ Goal_Display.string_of_goal ctxt st); Seq.single st);
 
 fun error_tac' ctxt msg = SELECT_GOAL (error_tac ctxt msg);
 
--- a/src/HOL/Tools/Sledgehammer/sledgehammer_prover.ML	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/HOL/Tools/Sledgehammer/sledgehammer_prover.ML	Wed Sep 07 08:58:27 2022 +0200
@@ -245,12 +245,14 @@
     (if keep_chained then is_fact_chained else K false))
 
 val max_fact_instances = 10 (* FUDGE *)
+val max_schematics = 20 (* FUDGE *)
 
 fun repair_monomorph_context max_iters best_max_iters max_new_instances best_max_new_instances =
   Config.put Monomorph.max_rounds (max_iters |> the_default best_max_iters)
   #> Config.put Monomorph.max_new_instances
        (max_new_instances |> the_default best_max_new_instances)
   #> Config.put Monomorph.max_thm_instances max_fact_instances
+  #> Config.put Monomorph.max_schematics max_schematics
 
 fun supported_provers ctxt =
   let
--- a/src/HOL/Tools/monomorph.ML	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/HOL/Tools/monomorph.ML	Wed Sep 07 08:58:27 2022 +0200
@@ -36,6 +36,7 @@
   val max_rounds: int Config.T
   val max_new_instances: int Config.T
   val max_thm_instances: int Config.T
+  val max_schematics: int Config.T
   val max_new_const_instances_per_round: int Config.T
   val max_duplicated_instances: int Config.T
 
@@ -72,6 +73,9 @@
 val max_thm_instances =
   Attrib.setup_config_int \<^binding>\<open>monomorph_max_thm_instances\<close> (K 20)
 
+val max_schematics =
+  Attrib.setup_config_int \<^binding>\<open>monomorph_max_schematics\<close> (K 1000)
+
 val max_new_const_instances_per_round =
   Attrib.setup_config_int \<^binding>\<open>monomorph_max_new_const_instances_per_round\<close> (K 5)
 
@@ -177,8 +181,8 @@
       | add _ = I
   in Term.fold_aterms add (Thm.prop_of thm) end
 
-fun add_insts max_instances max_duplicated_instances max_thm_insts ctxt round used_grounds
-    new_grounds id thm tvars schematics cx =
+fun add_insts max_instances max_duplicated_instances max_thm_insts max_schematics ctxt round
+    used_grounds new_grounds id thm tvars schematics cx =
   let
     exception ENOUGH of
       typ list Symtab.table * (int * int * ((int * (sort * typ) Vartab.table) * thm) list Inttab.table)
@@ -242,22 +246,24 @@
        instance is the usage of at least one ground from the new_grounds
        table. The approach used here is to match all schematics of the theorem
        with all relevant grounds. *)
-    for_schematics false schematics Vartab.empty cx
+    if length schematics > max_schematics then cx
+    else for_schematics false schematics Vartab.empty cx
     handle ENOUGH cx' => cx'
   end
 
 fun is_new round initial_round = (round = initial_round)
 fun is_active round initial_round = (round > initial_round)
 
-fun find_instances max_instances max_duplicated_instances max_thm_insts max_new_grounds thm_infos
-    ctxt round (known_grounds, new_grounds0, insts) =
+fun find_instances max_instances max_duplicated_instances max_thm_insts max_schematics
+    max_new_grounds thm_infos ctxt round (known_grounds, new_grounds0, insts) =
   let
     val new_grounds =
       Symtab.map (fn _ => fn grounds =>
         if length grounds <= max_new_grounds then grounds
         else take max_new_grounds (sort Term_Ord.typ_ord grounds)) new_grounds0
 
-    val add_new = add_insts max_instances max_duplicated_instances max_thm_insts ctxt round
+    val add_new = add_insts max_instances max_duplicated_instances max_thm_insts max_schematics
+      ctxt round
     fun consider_all pred f (cx as (_, (hits, misses, _))) =
       if hits >= max_instances orelse misses >= max_duplicated_instances then
         cx
@@ -279,7 +285,7 @@
   let fun add (n, T) = Symtab.map_entry n (insert (op =) T)
   in Term.fold_aterms (fn Const c => add c | _ => I) (Thm.prop_of thm) end
 
-fun collect_instances ctxt max_thm_insts max_new_grounds thm_infos consts =
+fun collect_instances ctxt max_thm_insts max_schematics max_new_grounds thm_infos consts =
   let
     val known_grounds = fold_grounds add_ground_types thm_infos consts
     val empty_grounds = clear_grounds known_grounds
@@ -288,7 +294,8 @@
     val max_duplicated_instances = Config.get ctxt max_duplicated_instances
     val (_, _, (_, _, insts)) =
       limit_rounds ctxt (find_instances max_instances max_duplicated_instances max_thm_insts
-      max_new_grounds thm_infos) (empty_grounds, known_grounds, (0, 0, Inttab.empty))
+          max_schematics max_new_grounds thm_infos)
+        (empty_grounds, known_grounds, (0, 0, Inttab.empty))
   in
     insts
   end
@@ -313,11 +320,14 @@
 fun monomorph schematic_consts_of ctxt rthms =
   let
     val max_thm_insts = Config.get ctxt max_thm_instances
+    val max_schematics = Config.get ctxt max_schematics
     val max_new_grounds = Config.get ctxt max_new_const_instances_per_round
     val (thm_infos, consts) = prepare schematic_consts_of rthms
     val insts =
-      if Symtab.is_empty consts then Inttab.empty
-      else collect_instances ctxt max_thm_insts max_new_grounds thm_infos consts
+      if Symtab.is_empty consts then
+        Inttab.empty
+      else
+        collect_instances ctxt max_thm_insts max_schematics max_new_grounds thm_infos consts
   in map (instantiated_thms max_thm_insts insts) thm_infos end
 
 end
--- a/src/HOL/Tools/record.ML	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/HOL/Tools/record.ML	Wed Sep 07 08:58:27 2022 +0200
@@ -2,6 +2,7 @@
     Author:     Wolfgang Naraschewski, TU Muenchen
     Author:     Markus Wenzel, TU Muenchen
     Author:     Norbert Schirmer, TU Muenchen
+    Author:     Norbert Schirmer, Apple, 2022
     Author:     Thomas Sewell, NICTA
 
 Extensible records with structural subtyping.
@@ -50,6 +51,7 @@
   val string_of_record: Proof.context -> string -> string
 
   val codegen: bool Config.T
+  val sort_updates: bool Config.T
   val updateN: string
   val ext_typeN: string
   val extN: string
@@ -196,6 +198,7 @@
 val updacc_cong_from_eq = @{thm iso_tuple_update_accessor_cong_from_eq};
 
 val codegen = Attrib.setup_config_bool \<^binding>\<open>record_codegen\<close> (K true);
+val sort_updates = Attrib.setup_config_bool \<^binding>\<open>record_sort_updates\<close> (K false);
 
 
 (** name components **)
@@ -984,9 +987,8 @@
     val dest = if comp then @{thm o_eq_dest_lhs} else @{thm o_eq_dest};
   in Drule.export_without_context (othm RS dest) end;
 
-fun get_updupd_simps ctxt term defset =
+fun gen_get_updupd_simps ctxt upd_funs defset =
   let
-    val upd_funs = get_upd_funs term;
     val cname = fst o dest_Const;
     fun getswap u u' = get_updupd_simp ctxt defset u u' (cname u = cname u');
     fun build_swaps_to_eq _ [] swaps = swaps
@@ -1007,7 +1009,9 @@
           else swaps_needed us (u :: prev) (Symtab.insert (K true) (cname u, ()) seen) swaps;
   in swaps_needed upd_funs [] Symtab.empty Symreltab.empty end;
 
-fun prove_unfold_defs thy ex_simps ex_simprs prop =
+fun get_updupd_simps ctxt term defset = gen_get_updupd_simps ctxt (get_upd_funs term) defset;
+
+fun prove_unfold_defs thy upd_funs ex_simps ex_simprs prop =
   let
     val ctxt = Proof_Context.init_global thy;
 
@@ -1015,7 +1019,10 @@
     val prop' = Envir.beta_eta_contract prop;
     val (lhs, _) = Logic.dest_equals (Logic.strip_assums_concl prop');
     val (_, args) = strip_comb lhs;
-    val simps = (if length args = 1 then get_accupd_simps else get_updupd_simps) ctxt lhs defset;
+    val simps =
+      if null upd_funs then
+        (if length args = 1 then get_accupd_simps else get_updupd_simps) ctxt lhs defset
+      else gen_get_updupd_simps ctxt upd_funs defset
   in
     Goal.prove ctxt [] [] prop'
       (fn {context = ctxt', ...} =>
@@ -1053,8 +1060,7 @@
   - If X is a more-selector we have to make sure that S is not in the updated
     subrecord.
 *)
-val simproc =
-  Simplifier.make_simproc \<^context> "record"
+val  _ = Theory.setup (Named_Target.theory_map (Simplifier.define_simproc \<^binding>\<open>select_update\<close>
    {lhss = [\<^term>\<open>x::'a::{}\<close>],
     proc = fn _ => fn ctxt => fn ct =>
       let
@@ -1102,13 +1108,17 @@
                 (case mk_eq_terms (upd $ k $ r) of
                   SOME (trm, trm', vars) =>
                     SOME
-                      (prove_unfold_defs thy [] []
+                      (prove_unfold_defs thy [] [] []
                         (Logic.list_all (vars, Logic.mk_equals (sel $ trm, trm'))))
                 | NONE => NONE)
               end
             else NONE
         | _ => NONE)
-      end};
+      end}));
+
+val simproc_name =
+  Simplifier.check_simproc (Context.the_local_context ()) ("select_update", Position.none);
+val simproc = Simplifier.the_simproc (Context.the_local_context ()) simproc_name;
 
 fun get_upd_acc_cong_thm upd acc thy ss =
   let
@@ -1126,6 +1136,24 @@
         TRY (resolve_tac ctxt' [updacc_cong_idI] 1))
   end;
 
+fun sorted ord [] = true
+  | sorted ord [x] = true
+  | sorted ord (x::y::xs) =
+      (case ord (x, y) of
+         LESS => sorted ord (y::xs)
+       | EQUAL => sorted ord (y::xs)
+       | GREATER => false)
+
+fun insert_unique ord x [] = [x]
+  | insert_unique ord x (y::ys) =
+      (case ord (x, y) of
+         LESS => (x::y::ys)
+       | EQUAL => (x::ys)
+       | GREATER => y :: insert_unique ord x ys)
+
+fun insert_unique_hd ord (x::xs) = x :: insert_unique ord x xs
+  | insert_unique_hd ord xs = xs
+
 
 (* upd_simproc *)
 
@@ -1137,8 +1165,7 @@
   In both cases "more" updates complicate matters: for this reason
   we omit considering further updates if doing so would introduce
   both a more update and an update to a field within it.*)
-val upd_simproc =
-  Simplifier.make_simproc \<^context> "record_upd"
+val  _ = Theory.setup (Named_Target.theory_map (Simplifier.define_simproc \<^binding>\<open>update\<close>
    {lhss = [\<^term>\<open>x::'a::{}\<close>],
     proc = fn _ => fn ctxt => fn ct =>
       let
@@ -1169,6 +1196,13 @@
           | getupdseq term _ _ = ([], term, HOLogic.unitT);
 
         val (upds, base, baseT) = getupdseq t 0 ~1;
+        val orig_upds = map_index (fn (i, (x, y, z)) => (x, y, z, i)) upds
+        val upd_ord = rev_order o fast_string_ord o apply2 #2
+        val (upds, commuted) =
+          if not (null orig_upds) andalso Config.get ctxt sort_updates andalso not (sorted upd_ord orig_upds) then
+             (sort upd_ord orig_upds, true)
+          else
+             (orig_upds, false)
 
         fun is_upd_noop s (Abs (n, T, Const (s', T') $ tm')) tm =
               if s = s' andalso null (loose_bnos tm')
@@ -1193,7 +1227,7 @@
           | add_upd f fs = (f :: fs);
 
         (*mk_updterm returns
-          (orig-term-skeleton, simplified-skeleton,
+          (orig-term-skeleton-update list , simplified-skeleton,
             variables, duplicate-updates, simp-flag, noop-simps)
 
           where duplicate-updates is a table used to pass upward
@@ -1201,9 +1235,9 @@
           into an update above them, simp-flag indicates whether
           any simplification was achieved, and noop-simps are
           used for eliminating case (2) defined above*)
-        fun mk_updterm ((upd as Const (u, T), s, f) :: upds) above term =
+        fun mk_updterm ((upd as Const (u, T), s, f, i) :: upds) above term =
               let
-                val (lhs, rhs, vars, dups, simp, noops) =
+                val (lhs_upds, rhs, vars, dups, simp, noops) =
                   mk_updterm upds (Symtab.update (u, ()) above) term;
                 val (fvar, skelf) =
                   K_skeleton (Long_Name.base_name s) (domain_type T) (Bound (length vars)) f;
@@ -1213,35 +1247,46 @@
                   Const (\<^const_name>\<open>Fun.comp\<close>, funT --> funT --> funT) $ f $ f';
               in
                 if isnoop then
-                  (upd $ skelf' $ lhs, rhs, vars,
+                  ((upd $ skelf', i)::lhs_upds, rhs, vars,
                     Symtab.update (u, []) dups, true,
                     if Symtab.defined noops u then noops
                     else Symtab.update (u, get_noop_simps upd skelf') noops)
                 else if Symtab.defined above u then
-                  (upd $ skelf $ lhs, rhs, fvar :: vars,
+                  ((upd $ skelf, i)::lhs_upds, rhs, fvar :: vars,
                     Symtab.map_default (u, []) (add_upd skelf) dups,
                     true, noops)
                 else
                   (case Symtab.lookup dups u of
                     SOME fs =>
-                     (upd $ skelf $ lhs,
+                     ((upd $ skelf, i)::lhs_upds,
                       upd $ foldr1 mk_comp_local (add_upd skelf fs) $ rhs,
                       fvar :: vars, dups, true, noops)
-                  | NONE => (upd $ skelf $ lhs, upd $ skelf $ rhs, fvar :: vars, dups, simp, noops))
+                  | NONE => ((upd $ skelf, i)::lhs_upds, upd $ skelf $ rhs, fvar :: vars, dups, simp, noops))
               end
           | mk_updterm [] _ _ =
-              (Bound 0, Bound 0, [("r", baseT)], Symtab.empty, false, Symtab.empty)
-          | mk_updterm us _ _ = raise TERM ("mk_updterm match", map (fn (x, _, _) => x) us);
-
-        val (lhs, rhs, vars, _, simp, noops) = mk_updterm upds Symtab.empty base;
+              ([], Bound 0, [("r", baseT)], Symtab.empty, false, Symtab.empty)
+          | mk_updterm us _ _ = raise TERM ("mk_updterm match", map (fn (x, _, _, _) => x) us);
+
+        val (lhs_upds, rhs, vars, _, simp, noops) = mk_updterm upds Symtab.empty base;
+        val orig_order_lhs_upds = lhs_upds |> sort (rev_order o int_ord o apply2 snd)
+        val lhs = Bound 0 |> fold (fn (upd, _) => fn s => upd $ s) orig_order_lhs_upds
+        (* Note that the simplifier works bottom up. So all nested updates are already
+           normalised, e.g. sorted. 'commuted' thus means that the outermost update has to be
+           inserted at its place inside the sorted nested updates. The necessary swaps can be
+           expressed via 'upd_funs' by replicating the outer update at the designated position: *)
+        val upd_funs = (if commuted then insert_unique_hd upd_ord orig_upds else orig_upds) |> map #1
         val noops' = maps snd (Symtab.dest noops);
       in
-        if simp then
+        if simp orelse commuted then
           SOME
-            (prove_unfold_defs thy noops' [simproc]
+            (prove_unfold_defs thy upd_funs noops' [simproc]
               (Logic.list_all (vars, Logic.mk_equals (lhs, rhs))))
         else NONE
-      end};
+      end}));
+
+val upd_simproc_name =
+  Simplifier.check_simproc (Context.the_local_context ()) ("update", Position.none);
+val upd_simproc = Simplifier.the_simproc (Context.the_local_context ()) upd_simproc_name;
 
 end;
 
@@ -1260,8 +1305,8 @@
              eq_simproc          split_simp_tac
  Complexity: #components * #updates     #updates
 *)
-val eq_simproc =
-  Simplifier.make_simproc \<^context> "record_eq"
+
+val  _ = Theory.setup (Named_Target.theory_map (Simplifier.define_simproc \<^binding>\<open>eq\<close>
    {lhss = [\<^term>\<open>r = s\<close>],
     proc = fn _ => fn ctxt => fn ct =>
       (case Thm.term_of ct of
@@ -1272,8 +1317,10 @@
               (case get_equalities (Proof_Context.theory_of ctxt) name of
                 NONE => NONE
               | SOME thm => SOME (thm RS @{thm Eq_TrueI})))
-      | _ => NONE)};
-
+      | _ => NONE)}));
+
+val eq_simproc_name = Simplifier.check_simproc (Context.the_local_context ()) ("eq", Position.none);
+val eq_simproc = Simplifier.the_simproc (Context.the_local_context ()) eq_simproc_name;
 
 (* split_simproc *)
 
@@ -1311,8 +1358,7 @@
           else NONE
       | _ => NONE)};
 
-val ex_sel_eq_simproc =
-  Simplifier.make_simproc \<^context> "ex_sel_eq"
+val  _ = Theory.setup (Named_Target.theory_map (Simplifier.define_simproc \<^binding>\<open>ex_sel_eq\<close>
    {lhss = [\<^term>\<open>Ex t\<close>],
     proc = fn _ => fn ctxt => fn ct =>
       let
@@ -1350,7 +1396,12 @@
                     addsimps @{thms simp_thms} addsimprocs [split_simproc (K ~1)]) 1))
             end handle TERM _ => NONE)
         | _ => NONE)
-      end};
+      end}));
+
+val ex_sel_eq_simproc_name =
+  Simplifier.check_simproc (Context.the_local_context ()) ("ex_sel_eq", Position.none);
+val ex_sel_eq_simproc = Simplifier.the_simproc (Context.the_local_context ()) ex_sel_eq_simproc_name;
+val _ = Theory.setup (map_theory_simpset (fn ctxt => ctxt delsimprocs [ex_sel_eq_simproc]));
 
 
 (* split_simp_tac *)
@@ -1431,11 +1482,6 @@
     else no_tac
   end);
 
-val _ =
-  Theory.setup
-    (map_theory_simpset (fn ctxt => ctxt addsimprocs [simproc, upd_simproc, eq_simproc]));
-
-
 (* wrapper *)
 
 val split_name = "record_split_tac";
--- a/src/Pure/Isar/proof.ML	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/Pure/Isar/proof.ML	Wed Sep 07 08:58:27 2022 +0200
@@ -1147,13 +1147,13 @@
 
 fun schematic_goal state =
   let val (_, {statement = (_, _, prop), ...}) = find_goal state
-  in Goal.is_schematic prop end;
+  in Term.is_schematic prop end;
 
 fun is_relevant state =
   (case try find_goal state of
     NONE => true
   | SOME (_, {statement = (_, _, prop), goal, ...}) =>
-      Goal.is_schematic prop orelse not (Logic.protect prop aconv Thm.concl_of goal));
+      Term.is_schematic prop orelse not (Logic.protect prop aconv Thm.concl_of goal));
 
 
 (* terminal proof steps *)
--- a/src/Pure/PIDE/resources.ML	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/Pure/PIDE/resources.ML	Wed Sep 07 08:58:27 2022 +0200
@@ -256,9 +256,11 @@
     SOME qualifier => qualifier
   | NONE => Long_Name.qualifier theory);
 
+fun literal_theory theory =
+  Long_Name.is_qualified theory orelse is_some (global_theory theory);
+
 fun theory_name qualifier theory =
-  if Long_Name.is_qualified theory orelse is_some (global_theory theory)
-  then theory
+  if literal_theory theory then theory
   else Long_Name.qualify qualifier theory;
 
 fun theory_bibtex_entries theory =
@@ -284,15 +286,21 @@
 fun import_name qualifier dir s =
   let
     val theory = theory_name qualifier (Thy_Header.import_name s);
-    fun theory_node () =
-      make_theory_node (File.full_path dir (thy_path (Path.expand (Path.explode s)))) theory;
+    fun theory_node path = make_theory_node path theory;
+    val literal_import = literal_theory theory andalso qualifier <> theory_qualifier theory;
+    val _ =
+      if literal_import andalso not (Thy_Header.is_base_name s) then
+        error ("Bad import of theory from other session via file-path: " ^ quote s)
+      else ();
   in
-    if not (Thy_Header.is_base_name s) then theory_node ()
-    else if loaded_theory theory then loaded_theory_node theory
+    if loaded_theory theory then loaded_theory_node theory
     else
       (case find_theory_file theory of
-        SOME node_name => make_theory_node node_name theory
-      | NONE => if Long_Name.is_qualified s then loaded_theory_node theory else theory_node ())
+        SOME node_name => theory_node node_name
+      | NONE =>
+          if Thy_Header.is_base_name s andalso Long_Name.is_qualified s
+          then loaded_theory_node theory
+          else theory_node (File.full_path dir (thy_path (Path.expand (Path.explode s)))))
   end;
 
 fun check_file dir file = File.check_file (File.full_path dir file);
--- a/src/Pure/PIDE/resources.scala	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/Pure/PIDE/resources.scala	Wed Sep 07 08:58:27 2022 +0200
@@ -150,8 +150,11 @@
   def global_theory(theory: String): Boolean =
     sessions_structure.global_theories.isDefinedAt(theory)
 
+  def literal_theory(theory: String): Boolean =
+    Long_Name.is_qualified(theory) || global_theory(theory)
+
   def theory_name(qualifier: String, theory: String): String =
-    if (Long_Name.is_qualified(theory) || global_theory(theory)) theory
+    if (literal_theory(theory)) theory
     else Long_Name.qualify(qualifier, theory)
 
   def find_theory_node(theory: String): Option[Document.Node.Name] = {
@@ -168,14 +171,18 @@
 
   def import_name(qualifier: String, dir: String, s: String): Document.Node.Name = {
     val theory = theory_name(qualifier, Thy_Header.import_name(s))
-    def theory_node = file_node(Path.explode(s).thy, dir = dir, theory = theory)
-
-    if (!Thy_Header.is_base_name(s)) theory_node
-    else if (session_base.loaded_theory(theory)) loaded_theory_node(theory)
+    val literal_import =
+      literal_theory(theory) && qualifier != sessions_structure.theory_qualifier(theory)
+    if (literal_import && !Thy_Header.is_base_name(s)) {
+      error("Bad import of theory from other session via file-path: " + quote(s))
+    }
+    if (session_base.loaded_theory(theory)) loaded_theory_node(theory)
     else {
       find_theory_node(theory) match {
         case Some(node_name) => node_name
-        case None => if (Long_Name.is_qualified(s)) loaded_theory_node(theory) else theory_node
+        case None =>
+          if (Thy_Header.is_base_name(s) && literal_theory(s)) loaded_theory_node(theory)
+          else file_node(Path.explode(s).thy, dir = dir, theory = theory)
       }
     }
   }
--- a/src/Pure/PIDE/session.scala	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/Pure/PIDE/session.scala	Wed Sep 07 08:58:27 2022 +0200
@@ -65,7 +65,6 @@
   case object Caret_Focus
   case class Raw_Edits(doc_blobs: Document.Blobs, edits: List[Document.Edit_Text])
   case class Dialog_Result(id: Document_ID.Generic, serial: Long, result: String)
-  case class Build_Theories(id: String, master_dir: Path, theories: List[(Options, List[Path])])
   case class Commands_Changed(
     assignment: Boolean, nodes: Set[Document.Node.Name], commands: Set[Command])
 
--- a/src/Pure/Thy/sessions.scala	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/Pure/Thy/sessions.scala	Wed Sep 07 08:58:27 2022 +0200
@@ -193,8 +193,9 @@
 
             val imported_files = if (inlined_files) dependencies.imported_files else Nil
 
-            if (list_files)
+            if (list_files) {
               progress.echo(cat_lines(session_files.map(_.implode).sorted.map("  " + _)))
+            }
 
             if (check_keywords.nonEmpty) {
               Check_Keywords.check_keywords(
@@ -207,8 +208,9 @@
 
               def node(name: Document.Node.Name): Graph_Display.Node = {
                 val qualifier = sessions_structure.theory_qualifier(name)
-                if (qualifier == info.name)
+                if (qualifier == info.name) {
                   Graph_Display.Node(name.theory_base_name, "theory." + name.theory)
+                }
                 else session_node(qualifier)
               }
 
@@ -590,9 +592,10 @@
         for { (_, thys) <- entry.theories; ((thy, pos), global) <- thys if global }
         yield {
           val thy_name = Path.explode(thy).file_name
-          if (Long_Name.is_qualified(thy_name))
+          if (Long_Name.is_qualified(thy_name)) {
             error("Bad qualified name for global theory " +
               quote(thy_name) + Position.here(pos))
+          }
           else thy_name
         }
 
@@ -664,9 +667,10 @@
         edges: Info => Iterable[String]
       ) : Graph[String, Info] = {
         def add_edge(pos: Position.T, name: String, g: Graph[String, Info], parent: String) = {
-          if (!g.defined(parent))
+          if (!g.defined(parent)) {
             error("Bad " + kind + " session " + quote(parent) + " for " +
               quote(name) + Position.here(pos))
+          }
 
           try { g.add_edge_acyclic(parent, name) }
           catch {
@@ -685,9 +689,10 @@
       val info_graph =
         infos.foldLeft(Graph.string[Info]) {
           case (graph, info) =>
-            if (graph.defined(info.name))
+            if (graph.defined(info.name)) {
               error("Duplicate session " + quote(info.name) + Position.here(info.pos) +
                 Position.here(graph.get_node(info.name).pos))
+            }
             else graph.new_node(info.name, info)
         }
       val build_graph = add_edges(info_graph, "parent", _.parent)
@@ -784,8 +789,9 @@
 
     def check_sessions(names: List[String]): Unit = {
       val bad_sessions = SortedSet(names.filterNot(defined): _*).toList
-      if (bad_sessions.nonEmpty)
+      if (bad_sessions.nonEmpty) {
         error("Undefined session(s): " + commas_quote(bad_sessions))
+      }
     }
 
     def check_sessions(sel: Selection): Unit =
--- a/src/Pure/goal.ML	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/Pure/goal.ML	Wed Sep 07 08:58:27 2022 +0200
@@ -25,7 +25,6 @@
   val skip_proofs_enabled: unit -> bool
   val future_result: Proof.context -> thm future -> term -> thm
   val prove_internal: Proof.context -> cterm list -> cterm -> (thm list -> tactic) -> thm
-  val is_schematic: term -> bool
   val prove_common: Proof.context -> int option -> string list -> term list -> term list ->
     ({prems: thm list, context: Proof.context} -> tactic) -> thm list
   val prove_future: Proof.context -> string list -> term list -> term ->
@@ -81,8 +80,7 @@
 *)
 fun check_finished ctxt th =
   if Thm.no_prems th then th
-  else
-    raise THM ("Proof failed.\n" ^ Pretty.string_of (Goal_Display.pretty_goal ctxt th), 0, [th]);
+  else raise THM ("Proof failed.\n" ^ Goal_Display.string_of_goal ctxt th, 0, [th]);
 
 fun finish ctxt = check_finished ctxt #> conclude;
 
@@ -162,15 +160,11 @@
 
 (* prove variations *)
 
-fun is_schematic t =
-  Term.exists_subterm Term.is_Var t orelse
-  Term.exists_type (Term.exists_subtype Term.is_TVar) t;
-
 fun prove_common ctxt fork_pri xs asms props tac =
   let
     val thy = Proof_Context.theory_of ctxt;
 
-    val schematic = exists is_schematic props;
+    val schematic = exists Term.is_schematic props;
     val immediate = is_none fork_pri;
     val future = Future.proofs_enabled 1 andalso not (Proofterm.proofs_enabled ());
     val skip = not immediate andalso not schematic andalso future andalso skip_proofs_enabled ();
--- a/src/Pure/tactical.ML	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/Pure/tactical.ML	Wed Sep 07 08:58:27 2022 +0200
@@ -176,8 +176,7 @@
 
 (*Print the current proof state and pass it on.*)
 fun print_tac ctxt msg st =
- (tracing (msg ^ "\n" ^ Pretty.string_of (Pretty.chunks (Goal_Display.pretty_goals ctxt st)));
-  Seq.single st);
+  (tracing (msg ^ "\n" ^ Goal_Display.string_of_goal ctxt st); Seq.single st);
 
 
 (*Deterministic REPEAT: only retains the first outcome;
--- a/src/Pure/term.ML	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/Pure/term.ML	Wed Sep 07 08:58:27 2022 +0200
@@ -114,6 +114,7 @@
   val exists_type: (typ -> bool) -> term -> bool
   val exists_subterm: (term -> bool) -> term -> bool
   val exists_Const: (string * typ -> bool) -> term -> bool
+  val is_schematic: term -> bool
 end;
 
 signature TERM =
@@ -950,6 +951,10 @@
 
 fun exists_Const P = exists_subterm (fn Const c => P c | _ => false);
 
+fun is_schematic t =
+  exists_subterm is_Var t orelse
+  (exists_type o exists_subtype) is_TVar t;
+
 
 (* contraction *)
 
--- a/src/Tools/jEdit/src/jedit_editor.scala	Fri Sep 02 13:41:55 2022 +0200
+++ b/src/Tools/jEdit/src/jedit_editor.scala	Wed Sep 07 08:58:27 2022 +0200
@@ -30,19 +30,19 @@
   override def flush(): Unit = flush_edits()
   def purge(): Unit = flush_edits(purge = true)
 
-  private val delay1_flush =
+  private val delay_input: Delay =
     Delay.last(PIDE.options.seconds("editor_input_delay"), gui = true) { flush() }
 
-  private val delay2_flush =
+  private val delay_generated_input: Delay =
     Delay.first(PIDE.options.seconds("editor_generated_input_delay"), gui = true) { flush() }
 
-  def invoke(): Unit = delay1_flush.invoke()
-  def invoke_generated(): Unit = { delay1_flush.invoke(); delay2_flush.invoke() }
+  def invoke(): Unit = delay_input.invoke()
+  def invoke_generated(): Unit = { delay_input.invoke(); delay_generated_input.invoke() }
 
   def shutdown(): Unit =
     GUI_Thread.require {
-      delay1_flush.revoke()
-      delay2_flush.revoke()
+      delay_input.revoke()
+      delay_generated_input.revoke()
       Document_Model.flush_edits(hidden = false, purge = false)
     }