src/HOL/Library/Multiset.thy
changeset 25759 6326138c1bd7
parent 25623 baa627b6f962
child 26016 f9d1bf2fc59c
equal deleted inserted replaced
25758:89c7c22e64b4 25759:6326138c1bd7
  1119 lemmas multi_count_ext = multi_count_eq [THEN iffD1, rule_format]
  1119 lemmas multi_count_ext = multi_count_eq [THEN iffD1, rule_format]
  1120 
  1120 
  1121 subsection {* The fold combinator *}
  1121 subsection {* The fold combinator *}
  1122 
  1122 
  1123 text {* The intended behaviour is
  1123 text {* The intended behaviour is
  1124 @{text "foldM f z {#x\<^isub>1, ..., x\<^isub>n#} = f x\<^isub>1 (\<dots> (f x\<^isub>n z)\<dots>)"}
  1124 @{text "fold_mset f z {#x\<^isub>1, ..., x\<^isub>n#} = f x\<^isub>1 (\<dots> (f x\<^isub>n z)\<dots>)"}
  1125 if @{text f} is associative-commutative. 
  1125 if @{text f} is associative-commutative. 
  1126 *}
  1126 *}
  1127 
  1127 
  1128 (* the graph of foldM, z = the start element, f = folding function, 
  1128 (* the graph of fold_mset, z = the start element, f = folding function, 
  1129    A the multiset, y the result *)
  1129    A the multiset, y the result *)
  1130 inductive 
  1130 inductive 
  1131   foldMG :: "('a \<Rightarrow> 'b \<Rightarrow> 'b) \<Rightarrow> 'b \<Rightarrow> 'a multiset \<Rightarrow> 'b \<Rightarrow> bool" 
  1131   fold_msetG :: "('a \<Rightarrow> 'b \<Rightarrow> 'b) \<Rightarrow> 'b \<Rightarrow> 'a multiset \<Rightarrow> 'b \<Rightarrow> bool" 
  1132   for f :: "'a \<Rightarrow> 'b \<Rightarrow> 'b" 
  1132   for f :: "'a \<Rightarrow> 'b \<Rightarrow> 'b" 
  1133   and z :: 'b
  1133   and z :: 'b
  1134 where
  1134 where
  1135   emptyI [intro]:  "foldMG f z {#} z"
  1135   emptyI [intro]:  "fold_msetG f z {#} z"
  1136 | insertI [intro]: "foldMG f z A y \<Longrightarrow> foldMG f z (A + {#x#}) (f x y)"
  1136 | insertI [intro]: "fold_msetG f z A y \<Longrightarrow> fold_msetG f z (A + {#x#}) (f x y)"
  1137 
  1137 
  1138 inductive_cases empty_foldMGE [elim!]: "foldMG f z {#} x"
  1138 inductive_cases empty_fold_msetGE [elim!]: "fold_msetG f z {#} x"
  1139 inductive_cases insert_foldMGE: "foldMG f z (A + {#}) y" 
  1139 inductive_cases insert_fold_msetGE: "fold_msetG f z (A + {#}) y" 
  1140 
  1140 
  1141 definition
  1141 definition
  1142   foldM :: "('a \<Rightarrow> 'b \<Rightarrow> 'b) \<Rightarrow> 'b \<Rightarrow> 'a multiset \<Rightarrow> 'b"
  1142   fold_mset :: "('a \<Rightarrow> 'b \<Rightarrow> 'b) \<Rightarrow> 'b \<Rightarrow> 'a multiset \<Rightarrow> 'b"
  1143 where
  1143 where
  1144   "foldM f z A \<equiv> THE x. foldMG f z A x"
  1144   "fold_mset f z A \<equiv> THE x. fold_msetG f z A x"
  1145 
  1145 
  1146 lemma Diff1_foldMG:
  1146 lemma Diff1_fold_msetG:
  1147   "\<lbrakk> foldMG f z (A - {#x#}) y; x \<in># A \<rbrakk> \<Longrightarrow> foldMG f z A (f x y)"
  1147   "\<lbrakk> fold_msetG f z (A - {#x#}) y; x \<in># A \<rbrakk> \<Longrightarrow> fold_msetG f z A (f x y)"
  1148   by (frule_tac x=x in foldMG.insertI, auto)
  1148   by (frule_tac x=x in fold_msetG.insertI, auto)
  1149 
  1149 
  1150 lemma foldMG_nonempty: "\<exists>x. foldMG f z A x"
  1150 lemma fold_msetG_nonempty: "\<exists>x. fold_msetG f z A x"
  1151   apply (induct A)
  1151   apply (induct A)
  1152    apply blast
  1152    apply blast
  1153   apply clarsimp
  1153   apply clarsimp
  1154   apply (drule_tac x=x in foldMG.insertI)
  1154   apply (drule_tac x=x in fold_msetG.insertI)
  1155   apply auto
  1155   apply auto
  1156   done
  1156   done
  1157 
  1157 
  1158 lemma foldM_empty[simp]: "foldM f z {#} = z"
  1158 lemma fold_mset_empty[simp]: "fold_mset f z {#} = z"
  1159   by (unfold foldM_def, blast)
  1159   by (unfold fold_mset_def, blast)
  1160 
  1160 
  1161 locale left_commutative = 
  1161 locale left_commutative = 
  1162   fixes f :: "'a => 'b => 'b"
  1162   fixes f :: "'a => 'b => 'b"
  1163   assumes left_commute: "f x (f y z) = f y (f x z)"
  1163   assumes left_commute: "f x (f y z) = f y (f x z)"
  1164 
  1164 
  1165 lemma (in left_commutative) foldMG_determ:
  1165 lemma (in left_commutative) fold_msetG_determ:
  1166   "\<lbrakk>foldMG f z A x; foldMG f z A y\<rbrakk> \<Longrightarrow> y = x"
  1166   "\<lbrakk>fold_msetG f z A x; fold_msetG f z A y\<rbrakk> \<Longrightarrow> y = x"
  1167 proof (induct arbitrary: x y z rule: full_multiset_induct)
  1167 proof (induct arbitrary: x y z rule: full_multiset_induct)
  1168   case (less M x\<^isub>1 x\<^isub>2 Z)
  1168   case (less M x\<^isub>1 x\<^isub>2 Z)
  1169   have IH: "\<forall>A. A \<subset># M \<longrightarrow> 
  1169   have IH: "\<forall>A. A \<subset># M \<longrightarrow> 
  1170     (\<forall>x x' x''. foldMG f x'' A x \<longrightarrow> foldMG f x'' A x'
  1170     (\<forall>x x' x''. fold_msetG f x'' A x \<longrightarrow> fold_msetG f x'' A x'
  1171                \<longrightarrow> x' = x)" by fact
  1171                \<longrightarrow> x' = x)" by fact
  1172   have Mfoldx\<^isub>1: "foldMG f Z M x\<^isub>1" and Mfoldx\<^isub>2: "foldMG f Z M x\<^isub>2" by fact+
  1172   have Mfoldx\<^isub>1: "fold_msetG f Z M x\<^isub>1" and Mfoldx\<^isub>2: "fold_msetG f Z M x\<^isub>2" by fact+
  1173   show ?case
  1173   show ?case
  1174   proof (rule foldMG.cases [OF Mfoldx\<^isub>1])
  1174   proof (rule fold_msetG.cases [OF Mfoldx\<^isub>1])
  1175     assume "M = {#}" and "x\<^isub>1 = Z"
  1175     assume "M = {#}" and "x\<^isub>1 = Z"
  1176     thus ?case using Mfoldx\<^isub>2 by auto 
  1176     thus ?case using Mfoldx\<^isub>2 by auto 
  1177   next
  1177   next
  1178     fix B b u
  1178     fix B b u
  1179     assume "M = B + {#b#}" and "x\<^isub>1 = f b u" and Bu: "foldMG f Z B u"
  1179     assume "M = B + {#b#}" and "x\<^isub>1 = f b u" and Bu: "fold_msetG f Z B u"
  1180     hence MBb: "M = B + {#b#}" and x\<^isub>1: "x\<^isub>1 = f b u" by auto
  1180     hence MBb: "M = B + {#b#}" and x\<^isub>1: "x\<^isub>1 = f b u" by auto
  1181     show ?case
  1181     show ?case
  1182     proof (rule foldMG.cases [OF Mfoldx\<^isub>2])
  1182     proof (rule fold_msetG.cases [OF Mfoldx\<^isub>2])
  1183       assume "M = {#}" "x\<^isub>2 = Z"
  1183       assume "M = {#}" "x\<^isub>2 = Z"
  1184       thus ?case using Mfoldx\<^isub>1 by auto
  1184       thus ?case using Mfoldx\<^isub>1 by auto
  1185     next
  1185     next
  1186       fix C c v
  1186       fix C c v
  1187       assume "M = C + {#c#}" and "x\<^isub>2 = f c v" and Cv: "foldMG f Z C v"
  1187       assume "M = C + {#c#}" and "x\<^isub>2 = f c v" and Cv: "fold_msetG f Z C v"
  1188       hence MCc: "M = C + {#c#}" and x\<^isub>2: "x\<^isub>2 = f c v" by auto
  1188       hence MCc: "M = C + {#c#}" and x\<^isub>2: "x\<^isub>2 = f c v" by auto
  1189       hence CsubM: "C \<subset># M" by simp
  1189       hence CsubM: "C \<subset># M" by simp
  1190       from MBb have BsubM: "B \<subset># M" by simp
  1190       from MBb have BsubM: "B \<subset># M" by simp
  1191       show ?case
  1191       show ?case
  1192       proof cases
  1192       proof cases
  1204         hence [simp]: "B + {#b#} - {#c#} = C"
  1204         hence [simp]: "B + {#b#} - {#c#} = C"
  1205           using MBb MCc binC cinB by auto
  1205           using MBb MCc binC cinB by auto
  1206         have B: "B = ?D + {#c#}" and C: "C = ?D + {#b#}"
  1206         have B: "B = ?D + {#c#}" and C: "C = ?D + {#b#}"
  1207           using MBb MCc diff binC cinB
  1207           using MBb MCc diff binC cinB
  1208           by (auto simp: multiset_add_sub_el_shuffle)
  1208           by (auto simp: multiset_add_sub_el_shuffle)
  1209         then obtain d where Dfoldd: "foldMG f Z ?D d"
  1209         then obtain d where Dfoldd: "fold_msetG f Z ?D d"
  1210           using foldMG_nonempty by iprover
  1210           using fold_msetG_nonempty by iprover
  1211         hence "foldMG f Z B (f c d)" using cinB
  1211         hence "fold_msetG f Z B (f c d)" using cinB
  1212           by (rule Diff1_foldMG)
  1212           by (rule Diff1_fold_msetG)
  1213         hence "f c d = u" using IH BsubM Bu by blast
  1213         hence "f c d = u" using IH BsubM Bu by blast
  1214         moreover 
  1214         moreover 
  1215         have "foldMG f Z C (f b d)" using binC cinB diff Dfoldd
  1215         have "fold_msetG f Z C (f b d)" using binC cinB diff Dfoldd
  1216           by (auto simp: multiset_add_sub_el_shuffle 
  1216           by (auto simp: multiset_add_sub_el_shuffle 
  1217             dest: foldMG.insertI [where x=b])
  1217             dest: fold_msetG.insertI [where x=b])
  1218         hence "f b d = v" using IH CsubM Cv by blast
  1218         hence "f b d = v" using IH CsubM Cv by blast
  1219         ultimately show ?thesis using x\<^isub>1 x\<^isub>2
  1219         ultimately show ?thesis using x\<^isub>1 x\<^isub>2
  1220           by (auto simp: left_commute)
  1220           by (auto simp: left_commute)
  1221       qed
  1221       qed
  1222     qed
  1222     qed
  1223   qed
  1223   qed
  1224 qed
  1224 qed
  1225         
  1225         
  1226 lemma (in left_commutative) foldM_insert_aux: "
  1226 lemma (in left_commutative) fold_mset_insert_aux: "
  1227     (foldMG f z (A + {#x#}) v) =
  1227     (fold_msetG f z (A + {#x#}) v) =
  1228     (\<exists>y. foldMG f z A y \<and> v = f x y)"
  1228     (\<exists>y. fold_msetG f z A y \<and> v = f x y)"
  1229   apply (rule iffI)
  1229   apply (rule iffI)
  1230    prefer 2
  1230    prefer 2
  1231    apply blast
  1231    apply blast
  1232   apply (rule_tac A=A and f=f in foldMG_nonempty [THEN exE, standard])
  1232   apply (rule_tac A=A and f=f in fold_msetG_nonempty [THEN exE, standard])
  1233   apply (blast intro: foldMG_determ)
  1233   apply (blast intro: fold_msetG_determ)
  1234   done
  1234   done
  1235 
  1235 
  1236 lemma (in left_commutative) foldM_equality: "foldMG f z A y \<Longrightarrow> foldM f z A = y"
  1236 lemma (in left_commutative) fold_mset_equality: "fold_msetG f z A y \<Longrightarrow> fold_mset f z A = y"
  1237   by (unfold foldM_def) (blast intro: foldMG_determ)
  1237   by (unfold fold_mset_def) (blast intro: fold_msetG_determ)
  1238 
  1238 
  1239 lemma (in left_commutative) foldM_insert[simp]:
  1239 lemma (in left_commutative) fold_mset_insert:
  1240   "foldM f z (A + {#x#}) = f x (foldM f z A)"
  1240   "fold_mset f z (A + {#x#}) = f x (fold_mset f z A)"
  1241   apply (simp add: foldM_def foldM_insert_aux union_commute)  
  1241   apply (simp add: fold_mset_def fold_mset_insert_aux union_commute)  
  1242   apply (rule the_equality)
  1242   apply (rule the_equality)
  1243   apply (auto cong add: conj_cong 
  1243   apply (auto cong add: conj_cong 
  1244               simp add: foldM_def [symmetric] foldM_equality foldMG_nonempty)
  1244               simp add: fold_mset_def [symmetric] fold_mset_equality fold_msetG_nonempty)
  1245   done
  1245   done
  1246 
  1246 
  1247 lemma (in left_commutative) foldM_insert_idem:
  1247 lemma (in left_commutative) fold_mset_insert_idem:
  1248   shows "foldM f z (A + {#a#}) = f a (foldM f z A)"
  1248   shows "fold_mset f z (A + {#a#}) = f a (fold_mset f z A)"
  1249   apply (simp add: foldM_def foldM_insert_aux)
  1249   apply (simp add: fold_mset_def fold_mset_insert_aux)
  1250   apply (rule the_equality)
  1250   apply (rule the_equality)
  1251   apply (auto cong add: conj_cong 
  1251   apply (auto cong add: conj_cong 
  1252               simp add: foldM_def [symmetric] foldM_equality foldMG_nonempty)
  1252               simp add: fold_mset_def [symmetric] fold_mset_equality fold_msetG_nonempty)
  1253   done
  1253   done
  1254 
  1254 
  1255 lemma (in left_commutative) foldM_fusion:
  1255 lemma (in left_commutative) fold_mset_commute:
       
  1256   "f x (fold_mset f z A) = fold_mset f (f x z) A"
       
  1257   by (induct A, auto simp: fold_mset_insert left_commute [of x])
       
  1258   
       
  1259 lemma (in left_commutative) fold_mset_single [simp]:
       
  1260    "fold_mset f z {#x#} = f x z"
       
  1261 using fold_mset_insert[of z "{#}"] by simp
       
  1262 
       
  1263 lemma (in left_commutative) fold_mset_union [simp]:
       
  1264    "fold_mset f z (A+B) = fold_mset f (fold_mset f z A) B"
       
  1265 proof (induct A)
       
  1266    case empty thus ?case by simp
       
  1267 next
       
  1268    case (add A x)
       
  1269    have "A + {#x#} + B = (A+B) + {#x#}" by(simp add:union_ac)
       
  1270    hence "fold_mset f z (A + {#x#} + B) = f x (fold_mset f z (A + B))" 
       
  1271      by (simp add: fold_mset_insert)
       
  1272    also have "\<dots> = fold_mset f (fold_mset f z (A + {#x#})) B"
       
  1273      by (simp add: fold_mset_commute[of x,symmetric] add fold_mset_insert)
       
  1274    finally show ?case .
       
  1275 qed
       
  1276 
       
  1277 lemma (in left_commutative) fold_mset_fusion:
  1256   includes left_commutative g
  1278   includes left_commutative g
  1257   shows "\<lbrakk>\<And>x y. h (g x y) = f x (h y) \<rbrakk> \<Longrightarrow> h (foldM g w A) = foldM f (h w) A"
  1279   shows "\<lbrakk>\<And>x y. h (g x y) = f x (h y) \<rbrakk> \<Longrightarrow> h (fold_mset g w A) = fold_mset f (h w) A"
  1258   by (induct A, auto)
  1280   by (induct A, auto)
  1259 
  1281 
  1260 lemma (in left_commutative) foldM_commute:
  1282 lemma (in left_commutative) fold_mset_rec:
  1261   "f x (foldM f z A) = foldM f (f x z) A"
       
  1262   by (induct A, auto simp: left_commute [of x])
       
  1263   
       
  1264 lemma (in left_commutative) foldM_rec:
       
  1265   assumes a: "a \<in># A" 
  1283   assumes a: "a \<in># A" 
  1266   shows "foldM f z A = f a (foldM f z (A - {#a#}))"
  1284   shows "fold_mset f z A = f a (fold_mset f z (A - {#a#}))"
  1267 proof -
  1285 proof -
  1268   from a obtain A' where "A = A' + {#a#}" by (blast dest: multi_member_split)
  1286   from a obtain A' where "A = A' + {#a#}" by (blast dest: multi_member_split)
  1269   thus ?thesis by simp
  1287   thus ?thesis by simp
  1270 qed
  1288 qed
  1271 
  1289 
  1272 
       
  1273 end
  1290 end