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 |