src/HOL/Library/Multiset.thy
changeset 48023 6dfe5e774012
parent 48012 b6e5e86a7303
child 48040 4caf6cd063be
equal deleted inserted replaced
48013:44de84112a67 48023:6dfe5e774012
   648     proof (rule insert)
   648     proof (rule insert)
   649       from i show "x \<in># A" by (auto dest: mset_le_insertD)
   649       from i show "x \<in># A" by (auto dest: mset_le_insertD)
   650       from i have "F \<le> A" by (auto dest: mset_le_insertD)
   650       from i have "F \<le> A" by (auto dest: mset_le_insertD)
   651       with P show "P F" .
   651       with P show "P F" .
   652     qed
   652     qed
       
   653   qed
       
   654 qed
       
   655 
       
   656 
       
   657 subsection {* The fold combinator *}
       
   658 
       
   659 text {*
       
   660   The intended behaviour is
       
   661   @{text "fold_mset f z {#x\<^isub>1, ..., x\<^isub>n#} = f x\<^isub>1 (\<dots> (f x\<^isub>n z)\<dots>)"}
       
   662   if @{text f} is associative-commutative. 
       
   663 *}
       
   664 
       
   665 text {*
       
   666   The graph of @{text "fold_mset"}, @{text "z"}: the start element,
       
   667   @{text "f"}: folding function, @{text "A"}: the multiset, @{text
       
   668   "y"}: the result.
       
   669 *}
       
   670 inductive 
       
   671   fold_msetG :: "('a \<Rightarrow> 'b \<Rightarrow> 'b) \<Rightarrow> 'b \<Rightarrow> 'a multiset \<Rightarrow> 'b \<Rightarrow> bool" 
       
   672   for f :: "'a \<Rightarrow> 'b \<Rightarrow> 'b" 
       
   673   and z :: 'b
       
   674 where
       
   675   emptyI [intro]:  "fold_msetG f z {#} z"
       
   676 | insertI [intro]: "fold_msetG f z A y \<Longrightarrow> fold_msetG f z (A + {#x#}) (f x y)"
       
   677 
       
   678 inductive_cases empty_fold_msetGE [elim!]: "fold_msetG f z {#} x"
       
   679 inductive_cases insert_fold_msetGE: "fold_msetG f z (A + {#}) y" 
       
   680 
       
   681 definition
       
   682   fold_mset :: "('a \<Rightarrow> 'b \<Rightarrow> 'b) \<Rightarrow> 'b \<Rightarrow> 'a multiset \<Rightarrow> 'b" where
       
   683   "fold_mset f z A = (THE x. fold_msetG f z A x)"
       
   684 
       
   685 lemma Diff1_fold_msetG:
       
   686   "fold_msetG f z (A - {#x#}) y \<Longrightarrow> x \<in># A \<Longrightarrow> fold_msetG f z A (f x y)"
       
   687 apply (frule_tac x = x in fold_msetG.insertI)
       
   688 apply auto
       
   689 done
       
   690 
       
   691 lemma fold_msetG_nonempty: "\<exists>x. fold_msetG f z A x"
       
   692 apply (induct A)
       
   693  apply blast
       
   694 apply clarsimp
       
   695 apply (drule_tac x = x in fold_msetG.insertI)
       
   696 apply auto
       
   697 done
       
   698 
       
   699 lemma fold_mset_empty[simp]: "fold_mset f z {#} = z"
       
   700 unfolding fold_mset_def by blast
       
   701 
       
   702 context comp_fun_commute
       
   703 begin
       
   704 
       
   705 lemma fold_msetG_insertE_aux:
       
   706   "fold_msetG f z A y \<Longrightarrow> a \<in># A \<Longrightarrow> \<exists>y'. y = f a y' \<and> fold_msetG f z (A - {#a#}) y'"
       
   707 proof (induct set: fold_msetG)
       
   708   case (insertI A y x) show ?case
       
   709   proof (cases "x = a")
       
   710     assume "x = a" with insertI show ?case by auto
       
   711   next
       
   712     assume "x \<noteq> a"
       
   713     then obtain y' where y: "y = f a y'" and y': "fold_msetG f z (A - {#a#}) y'"
       
   714       using insertI by auto
       
   715     have "f x y = f a (f x y')"
       
   716       unfolding y by (rule fun_left_comm)
       
   717     moreover have "fold_msetG f z (A + {#x#} - {#a#}) (f x y')"
       
   718       using y' and `x \<noteq> a`
       
   719       by (simp add: diff_union_swap [symmetric] fold_msetG.insertI)
       
   720     ultimately show ?case by fast
       
   721   qed
       
   722 qed simp
       
   723 
       
   724 lemma fold_msetG_insertE:
       
   725   assumes "fold_msetG f z (A + {#x#}) v"
       
   726   obtains y where "v = f x y" and "fold_msetG f z A y"
       
   727 using assms by (auto dest: fold_msetG_insertE_aux [where a=x])
       
   728 
       
   729 lemma fold_msetG_determ:
       
   730   "fold_msetG f z A x \<Longrightarrow> fold_msetG f z A y \<Longrightarrow> y = x"
       
   731 proof (induct arbitrary: y set: fold_msetG)
       
   732   case (insertI A y x v)
       
   733   from `fold_msetG f z (A + {#x#}) v`
       
   734   obtain y' where "v = f x y'" and "fold_msetG f z A y'"
       
   735     by (rule fold_msetG_insertE)
       
   736   from `fold_msetG f z A y'` have "y' = y" by (rule insertI)
       
   737   with `v = f x y'` show "v = f x y" by simp
       
   738 qed fast
       
   739 
       
   740 lemma fold_mset_equality: "fold_msetG f z A y \<Longrightarrow> fold_mset f z A = y"
       
   741 unfolding fold_mset_def by (blast intro: fold_msetG_determ)
       
   742 
       
   743 lemma fold_msetG_fold_mset: "fold_msetG f z A (fold_mset f z A)"
       
   744 proof -
       
   745   from fold_msetG_nonempty fold_msetG_determ
       
   746   have "\<exists>!x. fold_msetG f z A x" by (rule ex_ex1I)
       
   747   then show ?thesis unfolding fold_mset_def by (rule theI')
       
   748 qed
       
   749 
       
   750 lemma fold_mset_insert:
       
   751   "fold_mset f z (A + {#x#}) = f x (fold_mset f z A)"
       
   752 by (intro fold_mset_equality fold_msetG.insertI fold_msetG_fold_mset)
       
   753 
       
   754 lemma fold_mset_commute: "f x (fold_mset f z A) = fold_mset f (f x z) A"
       
   755 by (induct A) (auto simp: fold_mset_insert fun_left_comm [of x])
       
   756 
       
   757 lemma fold_mset_single [simp]: "fold_mset f z {#x#} = f x z"
       
   758 using fold_mset_insert [of z "{#}"] by simp
       
   759 
       
   760 lemma fold_mset_union [simp]:
       
   761   "fold_mset f z (A+B) = fold_mset f (fold_mset f z A) B"
       
   762 proof (induct A)
       
   763   case empty then show ?case by simp
       
   764 next
       
   765   case (add A x)
       
   766   have "A + {#x#} + B = (A+B) + {#x#}" by (simp add: add_ac)
       
   767   then have "fold_mset f z (A + {#x#} + B) = f x (fold_mset f z (A + B))" 
       
   768     by (simp add: fold_mset_insert)
       
   769   also have "\<dots> = fold_mset f (fold_mset f z (A + {#x#})) B"
       
   770     by (simp add: fold_mset_commute[of x,symmetric] add fold_mset_insert)
       
   771   finally show ?case .
       
   772 qed
       
   773 
       
   774 lemma fold_mset_fusion:
       
   775   assumes "comp_fun_commute g"
       
   776   shows "(\<And>x y. h (g x y) = f x (h y)) \<Longrightarrow> h (fold_mset g w A) = fold_mset f (h w) A" (is "PROP ?P")
       
   777 proof -
       
   778   interpret comp_fun_commute g by (fact assms)
       
   779   show "PROP ?P" by (induct A) auto
       
   780 qed
       
   781 
       
   782 lemma fold_mset_rec:
       
   783   assumes "a \<in># A" 
       
   784   shows "fold_mset f z A = f a (fold_mset f z (A - {#a#}))"
       
   785 proof -
       
   786   from assms obtain A' where "A = A' + {#a#}"
       
   787     by (blast dest: multi_member_split)
       
   788   then show ?thesis by simp
       
   789 qed
       
   790 
       
   791 end
       
   792 
       
   793 text {*
       
   794   A note on code generation: When defining some function containing a
       
   795   subterm @{term"fold_mset F"}, code generation is not automatic. When
       
   796   interpreting locale @{text left_commutative} with @{text F}, the
       
   797   would be code thms for @{const fold_mset} become thms like
       
   798   @{term"fold_mset F z {#} = z"} where @{text F} is not a pattern but
       
   799   contains defined symbols, i.e.\ is not a code thm. Hence a separate
       
   800   constant with its own code thms needs to be introduced for @{text
       
   801   F}. See the image operator below.
       
   802 *}
       
   803 
       
   804 
       
   805 subsection {* Image *}
       
   806 
       
   807 definition image_mset :: "('a \<Rightarrow> 'b) \<Rightarrow> 'a multiset \<Rightarrow> 'b multiset" where
       
   808   "image_mset f = fold_mset (op + o single o f) {#}"
       
   809 
       
   810 interpretation image_fun_commute: comp_fun_commute "op + o single o f" for f
       
   811 proof qed (simp add: add_ac fun_eq_iff)
       
   812 
       
   813 lemma image_mset_empty [simp]: "image_mset f {#} = {#}"
       
   814 by (simp add: image_mset_def)
       
   815 
       
   816 lemma image_mset_single [simp]: "image_mset f {#x#} = {#f x#}"
       
   817 by (simp add: image_mset_def)
       
   818 
       
   819 lemma image_mset_insert:
       
   820   "image_mset f (M + {#a#}) = image_mset f M + {#f a#}"
       
   821 by (simp add: image_mset_def add_ac)
       
   822 
       
   823 lemma image_mset_union [simp]:
       
   824   "image_mset f (M+N) = image_mset f M + image_mset f N"
       
   825 apply (induct N)
       
   826  apply simp
       
   827 apply (simp add: add_assoc [symmetric] image_mset_insert)
       
   828 done
       
   829 
       
   830 lemma size_image_mset [simp]: "size (image_mset f M) = size M"
       
   831 by (induct M) simp_all
       
   832 
       
   833 lemma image_mset_is_empty_iff [simp]: "image_mset f M = {#} \<longleftrightarrow> M = {#}"
       
   834 by (cases M) auto
       
   835 
       
   836 syntax
       
   837   "_comprehension1_mset" :: "'a \<Rightarrow> 'b \<Rightarrow> 'b multiset \<Rightarrow> 'a multiset"
       
   838       ("({#_/. _ :# _#})")
       
   839 translations
       
   840   "{#e. x:#M#}" == "CONST image_mset (%x. e) M"
       
   841 
       
   842 syntax
       
   843   "_comprehension2_mset" :: "'a \<Rightarrow> 'b \<Rightarrow> 'b multiset \<Rightarrow> bool \<Rightarrow> 'a multiset"
       
   844       ("({#_/ | _ :# _./ _#})")
       
   845 translations
       
   846   "{#e | x:#M. P#}" => "{#e. x :# {# x:#M. P#}#}"
       
   847 
       
   848 text {*
       
   849   This allows to write not just filters like @{term "{#x:#M. x<c#}"}
       
   850   but also images like @{term "{#x+x. x:#M #}"} and @{term [source]
       
   851   "{#x+x|x:#M. x<c#}"}, where the latter is currently displayed as
       
   852   @{term "{#x+x|x:#M. x<c#}"}.
       
   853 *}
       
   854 
       
   855 enriched_type image_mset: image_mset
       
   856 proof -
       
   857   fix f g show "image_mset f \<circ> image_mset g = image_mset (f \<circ> g)"
       
   858   proof
       
   859     fix A
       
   860     show "(image_mset f \<circ> image_mset g) A = image_mset (f \<circ> g) A"
       
   861       by (induct A) simp_all
       
   862   qed
       
   863   show "image_mset id = id"
       
   864   proof
       
   865     fix A
       
   866     show "image_mset id A = id A"
       
   867       by (induct A) simp_all
   653   qed
   868   qed
   654 qed
   869 qed
   655 
   870 
   656 
   871 
   657 subsection {* Alternative representations *}
   872 subsection {* Alternative representations *}
  1454 interpretation multiset_order: ordered_ab_semigroup_add plus le_multiset less_multiset
  1669 interpretation multiset_order: ordered_ab_semigroup_add plus le_multiset less_multiset
  1455 proof
  1670 proof
  1456 qed (auto simp add: le_multiset_def intro: union_less_mono2)
  1671 qed (auto simp add: le_multiset_def intro: union_less_mono2)
  1457 
  1672 
  1458 
  1673 
  1459 subsection {* The fold combinator *}
       
  1460 
       
  1461 text {*
       
  1462   The intended behaviour is
       
  1463   @{text "fold_mset f z {#x\<^isub>1, ..., x\<^isub>n#} = f x\<^isub>1 (\<dots> (f x\<^isub>n z)\<dots>)"}
       
  1464   if @{text f} is associative-commutative. 
       
  1465 *}
       
  1466 
       
  1467 text {*
       
  1468   The graph of @{text "fold_mset"}, @{text "z"}: the start element,
       
  1469   @{text "f"}: folding function, @{text "A"}: the multiset, @{text
       
  1470   "y"}: the result.
       
  1471 *}
       
  1472 inductive 
       
  1473   fold_msetG :: "('a \<Rightarrow> 'b \<Rightarrow> 'b) \<Rightarrow> 'b \<Rightarrow> 'a multiset \<Rightarrow> 'b \<Rightarrow> bool" 
       
  1474   for f :: "'a \<Rightarrow> 'b \<Rightarrow> 'b" 
       
  1475   and z :: 'b
       
  1476 where
       
  1477   emptyI [intro]:  "fold_msetG f z {#} z"
       
  1478 | insertI [intro]: "fold_msetG f z A y \<Longrightarrow> fold_msetG f z (A + {#x#}) (f x y)"
       
  1479 
       
  1480 inductive_cases empty_fold_msetGE [elim!]: "fold_msetG f z {#} x"
       
  1481 inductive_cases insert_fold_msetGE: "fold_msetG f z (A + {#}) y" 
       
  1482 
       
  1483 definition
       
  1484   fold_mset :: "('a \<Rightarrow> 'b \<Rightarrow> 'b) \<Rightarrow> 'b \<Rightarrow> 'a multiset \<Rightarrow> 'b" where
       
  1485   "fold_mset f z A = (THE x. fold_msetG f z A x)"
       
  1486 
       
  1487 lemma Diff1_fold_msetG:
       
  1488   "fold_msetG f z (A - {#x#}) y \<Longrightarrow> x \<in># A \<Longrightarrow> fold_msetG f z A (f x y)"
       
  1489 apply (frule_tac x = x in fold_msetG.insertI)
       
  1490 apply auto
       
  1491 done
       
  1492 
       
  1493 lemma fold_msetG_nonempty: "\<exists>x. fold_msetG f z A x"
       
  1494 apply (induct A)
       
  1495  apply blast
       
  1496 apply clarsimp
       
  1497 apply (drule_tac x = x in fold_msetG.insertI)
       
  1498 apply auto
       
  1499 done
       
  1500 
       
  1501 lemma fold_mset_empty[simp]: "fold_mset f z {#} = z"
       
  1502 unfolding fold_mset_def by blast
       
  1503 
       
  1504 context comp_fun_commute
       
  1505 begin
       
  1506 
       
  1507 lemma fold_msetG_insertE_aux:
       
  1508   "fold_msetG f z A y \<Longrightarrow> a \<in># A \<Longrightarrow> \<exists>y'. y = f a y' \<and> fold_msetG f z (A - {#a#}) y'"
       
  1509 proof (induct set: fold_msetG)
       
  1510   case (insertI A y x) show ?case
       
  1511   proof (cases "x = a")
       
  1512     assume "x = a" with insertI show ?case by auto
       
  1513   next
       
  1514     assume "x \<noteq> a"
       
  1515     then obtain y' where y: "y = f a y'" and y': "fold_msetG f z (A - {#a#}) y'"
       
  1516       using insertI by auto
       
  1517     have "f x y = f a (f x y')"
       
  1518       unfolding y by (rule fun_left_comm)
       
  1519     moreover have "fold_msetG f z (A + {#x#} - {#a#}) (f x y')"
       
  1520       using y' and `x \<noteq> a`
       
  1521       by (simp add: diff_union_swap [symmetric] fold_msetG.insertI)
       
  1522     ultimately show ?case by fast
       
  1523   qed
       
  1524 qed simp
       
  1525 
       
  1526 lemma fold_msetG_insertE:
       
  1527   assumes "fold_msetG f z (A + {#x#}) v"
       
  1528   obtains y where "v = f x y" and "fold_msetG f z A y"
       
  1529 using assms by (auto dest: fold_msetG_insertE_aux [where a=x])
       
  1530 
       
  1531 lemma fold_msetG_determ:
       
  1532   "fold_msetG f z A x \<Longrightarrow> fold_msetG f z A y \<Longrightarrow> y = x"
       
  1533 proof (induct arbitrary: y set: fold_msetG)
       
  1534   case (insertI A y x v)
       
  1535   from `fold_msetG f z (A + {#x#}) v`
       
  1536   obtain y' where "v = f x y'" and "fold_msetG f z A y'"
       
  1537     by (rule fold_msetG_insertE)
       
  1538   from `fold_msetG f z A y'` have "y' = y" by (rule insertI)
       
  1539   with `v = f x y'` show "v = f x y" by simp
       
  1540 qed fast
       
  1541 
       
  1542 lemma fold_mset_equality: "fold_msetG f z A y \<Longrightarrow> fold_mset f z A = y"
       
  1543 unfolding fold_mset_def by (blast intro: fold_msetG_determ)
       
  1544 
       
  1545 lemma fold_msetG_fold_mset: "fold_msetG f z A (fold_mset f z A)"
       
  1546 proof -
       
  1547   from fold_msetG_nonempty fold_msetG_determ
       
  1548   have "\<exists>!x. fold_msetG f z A x" by (rule ex_ex1I)
       
  1549   then show ?thesis unfolding fold_mset_def by (rule theI')
       
  1550 qed
       
  1551 
       
  1552 lemma fold_mset_insert:
       
  1553   "fold_mset f z (A + {#x#}) = f x (fold_mset f z A)"
       
  1554 by (intro fold_mset_equality fold_msetG.insertI fold_msetG_fold_mset)
       
  1555 
       
  1556 lemma fold_mset_commute: "f x (fold_mset f z A) = fold_mset f (f x z) A"
       
  1557 by (induct A) (auto simp: fold_mset_insert fun_left_comm [of x])
       
  1558 
       
  1559 lemma fold_mset_single [simp]: "fold_mset f z {#x#} = f x z"
       
  1560 using fold_mset_insert [of z "{#}"] by simp
       
  1561 
       
  1562 lemma fold_mset_union [simp]:
       
  1563   "fold_mset f z (A+B) = fold_mset f (fold_mset f z A) B"
       
  1564 proof (induct A)
       
  1565   case empty then show ?case by simp
       
  1566 next
       
  1567   case (add A x)
       
  1568   have "A + {#x#} + B = (A+B) + {#x#}" by (simp add: add_ac)
       
  1569   then have "fold_mset f z (A + {#x#} + B) = f x (fold_mset f z (A + B))" 
       
  1570     by (simp add: fold_mset_insert)
       
  1571   also have "\<dots> = fold_mset f (fold_mset f z (A + {#x#})) B"
       
  1572     by (simp add: fold_mset_commute[of x,symmetric] add fold_mset_insert)
       
  1573   finally show ?case .
       
  1574 qed
       
  1575 
       
  1576 lemma fold_mset_fusion:
       
  1577   assumes "comp_fun_commute g"
       
  1578   shows "(\<And>x y. h (g x y) = f x (h y)) \<Longrightarrow> h (fold_mset g w A) = fold_mset f (h w) A" (is "PROP ?P")
       
  1579 proof -
       
  1580   interpret comp_fun_commute g by (fact assms)
       
  1581   show "PROP ?P" by (induct A) auto
       
  1582 qed
       
  1583 
       
  1584 lemma fold_mset_rec:
       
  1585   assumes "a \<in># A" 
       
  1586   shows "fold_mset f z A = f a (fold_mset f z (A - {#a#}))"
       
  1587 proof -
       
  1588   from assms obtain A' where "A = A' + {#a#}"
       
  1589     by (blast dest: multi_member_split)
       
  1590   then show ?thesis by simp
       
  1591 qed
       
  1592 
       
  1593 end
       
  1594 
       
  1595 text {*
       
  1596   A note on code generation: When defining some function containing a
       
  1597   subterm @{term"fold_mset F"}, code generation is not automatic. When
       
  1598   interpreting locale @{text left_commutative} with @{text F}, the
       
  1599   would be code thms for @{const fold_mset} become thms like
       
  1600   @{term"fold_mset F z {#} = z"} where @{text F} is not a pattern but
       
  1601   contains defined symbols, i.e.\ is not a code thm. Hence a separate
       
  1602   constant with its own code thms needs to be introduced for @{text
       
  1603   F}. See the image operator below.
       
  1604 *}
       
  1605 
       
  1606 
       
  1607 subsection {* Image *}
       
  1608 
       
  1609 definition image_mset :: "('a \<Rightarrow> 'b) \<Rightarrow> 'a multiset \<Rightarrow> 'b multiset" where
       
  1610   "image_mset f = fold_mset (op + o single o f) {#}"
       
  1611 
       
  1612 interpretation image_fun_commute: comp_fun_commute "op + o single o f" for f
       
  1613 proof qed (simp add: add_ac fun_eq_iff)
       
  1614 
       
  1615 lemma image_mset_empty [simp]: "image_mset f {#} = {#}"
       
  1616 by (simp add: image_mset_def)
       
  1617 
       
  1618 lemma image_mset_single [simp]: "image_mset f {#x#} = {#f x#}"
       
  1619 by (simp add: image_mset_def)
       
  1620 
       
  1621 lemma image_mset_insert:
       
  1622   "image_mset f (M + {#a#}) = image_mset f M + {#f a#}"
       
  1623 by (simp add: image_mset_def add_ac)
       
  1624 
       
  1625 lemma image_mset_union [simp]:
       
  1626   "image_mset f (M+N) = image_mset f M + image_mset f N"
       
  1627 apply (induct N)
       
  1628  apply simp
       
  1629 apply (simp add: add_assoc [symmetric] image_mset_insert)
       
  1630 done
       
  1631 
       
  1632 lemma size_image_mset [simp]: "size (image_mset f M) = size M"
       
  1633 by (induct M) simp_all
       
  1634 
       
  1635 lemma image_mset_is_empty_iff [simp]: "image_mset f M = {#} \<longleftrightarrow> M = {#}"
       
  1636 by (cases M) auto
       
  1637 
       
  1638 syntax
       
  1639   "_comprehension1_mset" :: "'a \<Rightarrow> 'b \<Rightarrow> 'b multiset \<Rightarrow> 'a multiset"
       
  1640       ("({#_/. _ :# _#})")
       
  1641 translations
       
  1642   "{#e. x:#M#}" == "CONST image_mset (%x. e) M"
       
  1643 
       
  1644 syntax
       
  1645   "_comprehension2_mset" :: "'a \<Rightarrow> 'b \<Rightarrow> 'b multiset \<Rightarrow> bool \<Rightarrow> 'a multiset"
       
  1646       ("({#_/ | _ :# _./ _#})")
       
  1647 translations
       
  1648   "{#e | x:#M. P#}" => "{#e. x :# {# x:#M. P#}#}"
       
  1649 
       
  1650 text {*
       
  1651   This allows to write not just filters like @{term "{#x:#M. x<c#}"}
       
  1652   but also images like @{term "{#x+x. x:#M #}"} and @{term [source]
       
  1653   "{#x+x|x:#M. x<c#}"}, where the latter is currently displayed as
       
  1654   @{term "{#x+x|x:#M. x<c#}"}.
       
  1655 *}
       
  1656 
       
  1657 enriched_type image_mset: image_mset
       
  1658 proof -
       
  1659   fix f g show "image_mset f \<circ> image_mset g = image_mset (f \<circ> g)"
       
  1660   proof
       
  1661     fix A
       
  1662     show "(image_mset f \<circ> image_mset g) A = image_mset (f \<circ> g) A"
       
  1663       by (induct A) simp_all
       
  1664   qed
       
  1665   show "image_mset id = id"
       
  1666   proof
       
  1667     fix A
       
  1668     show "image_mset id A = id A"
       
  1669       by (induct A) simp_all
       
  1670   qed
       
  1671 qed
       
  1672 
       
  1673 
       
  1674 subsection {* Termination proofs with multiset orders *}
  1674 subsection {* Termination proofs with multiset orders *}
  1675 
  1675 
  1676 lemma multi_member_skip: "x \<in># XS \<Longrightarrow> x \<in># {# y #} + XS"
  1676 lemma multi_member_skip: "x \<in># XS \<Longrightarrow> x \<in># {# y #} + XS"
  1677   and multi_member_this: "x \<in># {# x #} + XS"
  1677   and multi_member_this: "x \<in># {# x #} + XS"
  1678   and multi_member_last: "x \<in># {# x #}"
  1678   and multi_member_last: "x \<in># {# x #}"