454 |
454 |
455 interpretation subset_mset: ordered_ab_semigroup_add_imp_le "op +" "op -" "op \<subseteq>#" "op \<subset>#" |
455 interpretation subset_mset: ordered_ab_semigroup_add_imp_le "op +" "op -" "op \<subseteq>#" "op \<subset>#" |
456 by standard (auto simp add: subset_mset_def subseteq_mset_def multiset_eq_iff intro: order_trans antisym) |
456 by standard (auto simp add: subset_mset_def subseteq_mset_def multiset_eq_iff intro: order_trans antisym) |
457 \<comment> \<open>FIXME: avoid junk stemming from type class interpretation\<close> |
457 \<comment> \<open>FIXME: avoid junk stemming from type class interpretation\<close> |
458 |
458 |
459 lemma mset_less_eqI: |
459 lemma mset_subset_eqI: |
460 "(\<And>a. count A a \<le> count B a) \<Longrightarrow> A \<subseteq># B" |
460 "(\<And>a. count A a \<le> count B a) \<Longrightarrow> A \<subseteq># B" |
461 by (simp add: subseteq_mset_def) |
461 by (simp add: subseteq_mset_def) |
462 |
462 |
463 lemma mset_less_eq_count: |
463 lemma mset_subset_eq_count: |
464 "A \<subseteq># B \<Longrightarrow> count A a \<le> count B a" |
464 "A \<subseteq># B \<Longrightarrow> count A a \<le> count B a" |
465 by (simp add: subseteq_mset_def) |
465 by (simp add: subseteq_mset_def) |
466 |
466 |
467 lemma mset_le_exists_conv: "(A::'a multiset) \<subseteq># B \<longleftrightarrow> (\<exists>C. B = A + C)" |
467 lemma mset_subset_eq_exists_conv: "(A::'a multiset) \<subseteq># B \<longleftrightarrow> (\<exists>C. B = A + C)" |
468 unfolding subseteq_mset_def |
468 unfolding subseteq_mset_def |
469 apply (rule iffI) |
469 apply (rule iffI) |
470 apply (rule exI [where x = "B - A"]) |
470 apply (rule exI [where x = "B - A"]) |
471 apply (auto intro: multiset_eq_iff [THEN iffD2]) |
471 apply (auto intro: multiset_eq_iff [THEN iffD2]) |
472 done |
472 done |
473 |
473 |
474 interpretation subset_mset: ordered_cancel_comm_monoid_diff "op +" 0 "op \<le>#" "op <#" "op -" |
474 interpretation subset_mset: ordered_cancel_comm_monoid_diff "op +" 0 "op \<le>#" "op <#" "op -" |
475 by standard (simp, fact mset_le_exists_conv) |
475 by standard (simp, fact mset_subset_eq_exists_conv) |
476 |
476 |
477 declare subset_mset.zero_order[simp del] |
477 lemma mset_subset_eq_mono_add_right_cancel [simp]: "(A::'a multiset) + C \<subseteq># B + C \<longleftrightarrow> A \<subseteq># B" |
478 \<comment> \<open>this removes some simp rules not in the usual order for multisets\<close> |
|
479 |
|
480 lemma mset_le_mono_add_right_cancel [simp]: "(A::'a multiset) + C \<subseteq># B + C \<longleftrightarrow> A \<subseteq># B" |
|
481 by (fact subset_mset.add_le_cancel_right) |
478 by (fact subset_mset.add_le_cancel_right) |
482 |
479 |
483 lemma mset_le_mono_add_left_cancel [simp]: "C + (A::'a multiset) \<subseteq># C + B \<longleftrightarrow> A \<subseteq># B" |
480 lemma mset_subset_eq_mono_add_left_cancel [simp]: "C + (A::'a multiset) \<subseteq># C + B \<longleftrightarrow> A \<subseteq># B" |
484 by (fact subset_mset.add_le_cancel_left) |
481 by (fact subset_mset.add_le_cancel_left) |
485 |
482 |
486 lemma mset_le_mono_add: "(A::'a multiset) \<subseteq># B \<Longrightarrow> C \<subseteq># D \<Longrightarrow> A + C \<subseteq># B + D" |
483 lemma mset_subset_eq_mono_add: "(A::'a multiset) \<subseteq># B \<Longrightarrow> C \<subseteq># D \<Longrightarrow> A + C \<subseteq># B + D" |
487 by (fact subset_mset.add_mono) |
484 by (fact subset_mset.add_mono) |
488 |
485 |
489 lemma mset_le_add_left [simp]: "(A::'a multiset) \<subseteq># A + B" |
486 lemma mset_subset_eq_add_left [simp]: "(A::'a multiset) \<subseteq># A + B" |
490 unfolding subseteq_mset_def by auto |
487 unfolding subseteq_mset_def by auto |
491 |
488 |
492 lemma mset_le_add_right [simp]: "B \<subseteq># (A::'a multiset) + B" |
489 lemma mset_subset_eq_add_right [simp]: "B \<subseteq># (A::'a multiset) + B" |
493 unfolding subseteq_mset_def by auto |
490 unfolding subseteq_mset_def by auto |
494 |
491 |
495 lemma single_subset_iff [simp]: |
492 lemma single_subset_iff [simp]: |
496 "{#a#} \<subseteq># M \<longleftrightarrow> a \<in># M" |
493 "{#a#} \<subseteq># M \<longleftrightarrow> a \<in># M" |
497 by (auto simp add: subseteq_mset_def Suc_le_eq) |
494 by (auto simp add: subseteq_mset_def Suc_le_eq) |
498 |
495 |
499 lemma mset_le_single: "a \<in># B \<Longrightarrow> {#a#} \<subseteq># B" |
496 lemma mset_subset_eq_single: "a \<in># B \<Longrightarrow> {#a#} \<subseteq># B" |
500 by (simp add: subseteq_mset_def Suc_le_eq) |
497 by (simp add: subseteq_mset_def Suc_le_eq) |
501 |
498 |
502 lemma multiset_diff_union_assoc: |
499 lemma multiset_diff_union_assoc: |
503 fixes A B C D :: "'a multiset" |
500 fixes A B C D :: "'a multiset" |
504 shows "C \<subseteq># B \<Longrightarrow> A + B - C = A + (B - C)" |
501 shows "C \<subseteq># B \<Longrightarrow> A + B - C = A + (B - C)" |
505 by (fact subset_mset.diff_add_assoc) |
502 by (fact subset_mset.diff_add_assoc) |
506 |
503 |
507 lemma mset_le_multiset_union_diff_commute: |
504 lemma mset_subset_eq_multiset_union_diff_commute: |
508 fixes A B C D :: "'a multiset" |
505 fixes A B C D :: "'a multiset" |
509 shows "B \<subseteq># A \<Longrightarrow> A - B + C = A + C - B" |
506 shows "B \<subseteq># A \<Longrightarrow> A - B + C = A + C - B" |
510 by (fact subset_mset.add_diff_assoc2) |
507 by (fact subset_mset.add_diff_assoc2) |
511 |
508 |
512 lemma diff_le_self[simp]: |
509 lemma diff_subset_eq_self[simp]: |
513 "(M::'a multiset) - N \<subseteq># M" |
510 "(M::'a multiset) - N \<subseteq># M" |
514 by (simp add: subseteq_mset_def) |
511 by (simp add: subseteq_mset_def) |
515 |
512 |
516 lemma mset_leD: |
513 lemma mset_subset_eqD: |
517 assumes "A \<subseteq># B" and "x \<in># A" |
514 assumes "A \<subseteq># B" and "x \<in># A" |
518 shows "x \<in># B" |
515 shows "x \<in># B" |
519 proof - |
516 proof - |
520 from \<open>x \<in># A\<close> have "count A x > 0" by simp |
517 from \<open>x \<in># A\<close> have "count A x > 0" by simp |
521 also from \<open>A \<subseteq># B\<close> have "count A x \<le> count B x" |
518 also from \<open>A \<subseteq># B\<close> have "count A x \<le> count B x" |
522 by (simp add: subseteq_mset_def) |
519 by (simp add: subseteq_mset_def) |
523 finally show ?thesis by simp |
520 finally show ?thesis by simp |
524 qed |
521 qed |
525 |
522 |
526 lemma mset_lessD: |
523 lemma mset_subsetD: |
527 "A \<subset># B \<Longrightarrow> x \<in># A \<Longrightarrow> x \<in># B" |
524 "A \<subset># B \<Longrightarrow> x \<in># A \<Longrightarrow> x \<in># B" |
528 by (auto intro: mset_leD [of A]) |
525 by (auto intro: mset_subset_eqD [of A]) |
529 |
526 |
530 lemma set_mset_mono: |
527 lemma set_mset_mono: |
531 "A \<subseteq># B \<Longrightarrow> set_mset A \<subseteq> set_mset B" |
528 "A \<subseteq># B \<Longrightarrow> set_mset A \<subseteq> set_mset B" |
532 by (metis mset_leD subsetI) |
529 by (metis mset_subset_eqD subsetI) |
533 |
530 |
534 lemma mset_le_insertD: |
531 lemma mset_subset_eq_insertD: |
535 "A + {#x#} \<subseteq># B \<Longrightarrow> x \<in># B \<and> A \<subset># B" |
532 "A + {#x#} \<subseteq># B \<Longrightarrow> x \<in># B \<and> A \<subset># B" |
536 apply (rule conjI) |
533 apply (rule conjI) |
537 apply (simp add: mset_leD) |
534 apply (simp add: mset_subset_eqD) |
538 apply (clarsimp simp: subset_mset_def subseteq_mset_def) |
535 apply (clarsimp simp: subset_mset_def subseteq_mset_def) |
539 apply safe |
536 apply safe |
540 apply (erule_tac x = a in allE) |
537 apply (erule_tac x = a in allE) |
541 apply (auto split: if_split_asm) |
538 apply (auto split: if_split_asm) |
542 done |
539 done |
543 |
540 |
544 lemma mset_less_insertD: |
541 lemma mset_subset_insertD: |
545 "A + {#x#} \<subset># B \<Longrightarrow> x \<in># B \<and> A \<subset># B" |
542 "A + {#x#} \<subset># B \<Longrightarrow> x \<in># B \<and> A \<subset># B" |
546 by (rule mset_le_insertD) simp |
543 by (rule mset_subset_eq_insertD) simp |
547 |
544 |
548 lemma mset_less_of_empty[simp]: "A \<subset># {#} \<longleftrightarrow> False" |
545 lemma mset_subset_of_empty[simp]: "A \<subset># {#} \<longleftrightarrow> False" |
549 by (auto simp add: subseteq_mset_def subset_mset_def multiset_eq_iff) |
546 by (auto simp add: subseteq_mset_def subset_mset_def multiset_eq_iff) |
550 |
547 |
551 lemma empty_le [simp]: "{#} \<subseteq># A" |
548 lemma empty_le [simp]: "{#} \<subseteq># A" |
552 unfolding mset_le_exists_conv by auto |
549 unfolding mset_subset_eq_exists_conv by auto |
553 |
550 |
554 lemma insert_subset_eq_iff: |
551 lemma insert_subset_eq_iff: |
555 "{#a#} + A \<subseteq># B \<longleftrightarrow> a \<in># B \<and> A \<subseteq># B - {#a#}" |
552 "{#a#} + A \<subseteq># B \<longleftrightarrow> a \<in># B \<and> A \<subseteq># B - {#a#}" |
556 using le_diff_conv2 [of "Suc 0" "count B a" "count A a"] |
553 using le_diff_conv2 [of "Suc 0" "count B a" "count A a"] |
557 apply (auto simp add: subseteq_mset_def not_in_iff Suc_le_eq) |
554 apply (auto simp add: subseteq_mset_def not_in_iff Suc_le_eq) |
565 |
562 |
566 lemma subset_eq_diff_conv: |
563 lemma subset_eq_diff_conv: |
567 "A - C \<subseteq># B \<longleftrightarrow> A \<subseteq># B + C" |
564 "A - C \<subseteq># B \<longleftrightarrow> A \<subseteq># B + C" |
568 by (simp add: subseteq_mset_def le_diff_conv) |
565 by (simp add: subseteq_mset_def le_diff_conv) |
569 |
566 |
570 lemma le_empty [simp]: "M \<subseteq># {#} \<longleftrightarrow> M = {#}" |
567 lemma subset_eq_empty [simp]: "M \<subseteq># {#} \<longleftrightarrow> M = {#}" |
571 unfolding mset_le_exists_conv by auto |
568 unfolding mset_subset_eq_exists_conv by auto |
572 |
569 |
573 lemma multi_psub_of_add_self[simp]: "A \<subset># A + {#x#}" |
570 lemma multi_psub_of_add_self[simp]: "A \<subset># A + {#x#}" |
574 by (auto simp: subset_mset_def subseteq_mset_def) |
571 by (auto simp: subset_mset_def subseteq_mset_def) |
575 |
572 |
576 lemma multi_psub_self[simp]: "(A::'a multiset) \<subset># A = False" |
573 lemma multi_psub_self[simp]: "(A::'a multiset) \<subset># A = False" |
577 by simp |
574 by simp |
578 |
575 |
579 lemma mset_less_add_bothsides: "N + {#x#} \<subset># M + {#x#} \<Longrightarrow> N \<subset># M" |
576 lemma mset_subset_add_bothsides: "N + {#x#} \<subset># M + {#x#} \<Longrightarrow> N \<subset># M" |
580 by (fact subset_mset.add_less_imp_less_right) |
577 by (fact subset_mset.add_less_imp_less_right) |
581 |
578 |
582 lemma mset_less_empty_nonempty: "{#} \<subset># S \<longleftrightarrow> S \<noteq> {#}" |
579 lemma mset_subset_empty_nonempty: "{#} \<subset># S \<longleftrightarrow> S \<noteq> {#}" |
583 by (fact subset_mset.zero_less_iff_neq_zero) |
580 by (fact subset_mset.zero_less_iff_neq_zero) |
584 |
581 |
585 lemma mset_less_diff_self: "c \<in># B \<Longrightarrow> B - {#c#} \<subset># B" |
582 lemma mset_subset_diff_self: "c \<in># B \<Longrightarrow> B - {#c#} \<subset># B" |
586 by (auto simp: subset_mset_def elim: mset_add) |
583 by (auto simp: subset_mset_def elim: mset_add) |
587 |
584 |
588 |
585 |
589 subsubsection \<open>Intersection\<close> |
586 subsubsection \<open>Intersection\<close> |
590 |
587 |
941 lemma size_mset_mono: |
938 lemma size_mset_mono: |
942 fixes A B :: "'a multiset" |
939 fixes A B :: "'a multiset" |
943 assumes "A \<subseteq># B" |
940 assumes "A \<subseteq># B" |
944 shows "size A \<le> size B" |
941 shows "size A \<le> size B" |
945 proof - |
942 proof - |
946 from assms[unfolded mset_le_exists_conv] |
943 from assms[unfolded mset_subset_eq_exists_conv] |
947 obtain C where B: "B = A + C" by auto |
944 obtain C where B: "B = A + C" by auto |
948 show ?thesis unfolding B by (induct C) auto |
945 show ?thesis unfolding B by (induct C) auto |
949 qed |
946 qed |
950 |
947 |
951 lemma size_filter_mset_lesseq[simp]: "size (filter_mset f M) \<le> size M" |
948 lemma size_filter_mset_lesseq[simp]: "size (filter_mset f M) \<le> size M" |
952 by (rule size_mset_mono[OF multiset_filter_subset]) |
949 by (rule size_mset_mono[OF multiset_filter_subset]) |
953 |
950 |
954 lemma size_Diff_submset: |
951 lemma size_Diff_submset: |
955 "M \<subseteq># M' \<Longrightarrow> size (M' - M) = size M' - size(M::'a multiset)" |
952 "M \<subseteq># M' \<Longrightarrow> size (M' - M) = size M' - size(M::'a multiset)" |
956 by (metis add_diff_cancel_left' size_union mset_le_exists_conv) |
953 by (metis add_diff_cancel_left' size_union mset_subset_eq_exists_conv) |
957 |
954 |
958 |
955 |
959 subsection \<open>Induction and case splits\<close> |
956 subsection \<open>Induction and case splits\<close> |
960 |
957 |
961 theorem multiset_induct [case_names empty add, induct type: multiset]: |
958 theorem multiset_induct [case_names empty add, induct type: multiset]: |
986 lemma multiset_partition: "M = {# x\<in>#M. P x #} + {# x\<in>#M. \<not> P x #}" |
983 lemma multiset_partition: "M = {# x\<in>#M. P x #} + {# x\<in>#M. \<not> P x #}" |
987 apply (subst multiset_eq_iff) |
984 apply (subst multiset_eq_iff) |
988 apply auto |
985 apply auto |
989 done |
986 done |
990 |
987 |
991 lemma mset_less_size: "(A::'a multiset) \<subset># B \<Longrightarrow> size A < size B" |
988 lemma mset_subset_size: "(A::'a multiset) \<subset># B \<Longrightarrow> size A < size B" |
992 proof (induct A arbitrary: B) |
989 proof (induct A arbitrary: B) |
993 case (empty M) |
990 case (empty M) |
994 then have "M \<noteq> {#}" by (simp add: mset_less_empty_nonempty) |
991 then have "M \<noteq> {#}" by (simp add: mset_subset_empty_nonempty) |
995 then obtain M' x where "M = M' + {#x#}" |
992 then obtain M' x where "M = M' + {#x#}" |
996 by (blast dest: multi_nonempty_split) |
993 by (blast dest: multi_nonempty_split) |
997 then show ?case by simp |
994 then show ?case by simp |
998 next |
995 next |
999 case (add S x T) |
996 case (add S x T) |
1000 have IH: "\<And>B. S \<subset># B \<Longrightarrow> size S < size B" by fact |
997 have IH: "\<And>B. S \<subset># B \<Longrightarrow> size S < size B" by fact |
1001 have SxsubT: "S + {#x#} \<subset># T" by fact |
998 have SxsubT: "S + {#x#} \<subset># T" by fact |
1002 then have "x \<in># T" and "S \<subset># T" |
999 then have "x \<in># T" and "S \<subset># T" |
1003 by (auto dest: mset_less_insertD) |
1000 by (auto dest: mset_subset_insertD) |
1004 then obtain T' where T: "T = T' + {#x#}" |
1001 then obtain T' where T: "T = T' + {#x#}" |
1005 by (blast dest: multi_member_split) |
1002 by (blast dest: multi_member_split) |
1006 then have "S \<subset># T'" using SxsubT |
1003 then have "S \<subset># T'" using SxsubT |
1007 by (blast intro: mset_less_add_bothsides) |
1004 by (blast intro: mset_subset_add_bothsides) |
1008 then have "size S < size T'" using IH by simp |
1005 then have "size S < size T'" using IH by simp |
1009 then show ?case using T by simp |
1006 then show ?case using T by simp |
1010 qed |
1007 qed |
1011 |
1008 |
1012 lemma size_1_singleton_mset: "size M = 1 \<Longrightarrow> \<exists>a. M = {#a#}" |
1009 lemma size_1_singleton_mset: "size M = 1 \<Longrightarrow> \<exists>a. M = {#a#}" |
2648 apply (simp_all add: add.commute) |
2645 apply (simp_all add: add.commute) |
2649 done |
2646 done |
2650 |
2647 |
2651 declare size_mset [code] |
2648 declare size_mset [code] |
2652 |
2649 |
2653 fun ms_lesseq_impl :: "'a list \<Rightarrow> 'a list \<Rightarrow> bool option" where |
2650 fun subset_eq_mset_impl :: "'a list \<Rightarrow> 'a list \<Rightarrow> bool option" where |
2654 "ms_lesseq_impl [] ys = Some (ys \<noteq> [])" |
2651 "subset_eq_mset_impl [] ys = Some (ys \<noteq> [])" |
2655 | "ms_lesseq_impl (Cons x xs) ys = (case List.extract (op = x) ys of |
2652 | "subset_eq_mset_impl (Cons x xs) ys = (case List.extract (op = x) ys of |
2656 None \<Rightarrow> None |
2653 None \<Rightarrow> None |
2657 | Some (ys1,_,ys2) \<Rightarrow> ms_lesseq_impl xs (ys1 @ ys2))" |
2654 | Some (ys1,_,ys2) \<Rightarrow> subset_eq_mset_impl xs (ys1 @ ys2))" |
2658 |
2655 |
2659 lemma ms_lesseq_impl: "(ms_lesseq_impl xs ys = None \<longleftrightarrow> \<not> mset xs \<subseteq># mset ys) \<and> |
2656 lemma subset_eq_mset_impl: "(subset_eq_mset_impl xs ys = None \<longleftrightarrow> \<not> mset xs \<subseteq># mset ys) \<and> |
2660 (ms_lesseq_impl xs ys = Some True \<longleftrightarrow> mset xs \<subset># mset ys) \<and> |
2657 (subset_eq_mset_impl xs ys = Some True \<longleftrightarrow> mset xs \<subset># mset ys) \<and> |
2661 (ms_lesseq_impl xs ys = Some False \<longrightarrow> mset xs = mset ys)" |
2658 (subset_eq_mset_impl xs ys = Some False \<longrightarrow> mset xs = mset ys)" |
2662 proof (induct xs arbitrary: ys) |
2659 proof (induct xs arbitrary: ys) |
2663 case (Nil ys) |
2660 case (Nil ys) |
2664 show ?case by (auto simp: mset_less_empty_nonempty) |
2661 show ?case by (auto simp: mset_subset_empty_nonempty) |
2665 next |
2662 next |
2666 case (Cons x xs ys) |
2663 case (Cons x xs ys) |
2667 show ?case |
2664 show ?case |
2668 proof (cases "List.extract (op = x) ys") |
2665 proof (cases "List.extract (op = x) ys") |
2669 case None |
2666 case None |
2684 obtain ys1 y ys2 where res: "res = (ys1,y,ys2)" by (cases res, auto) |
2681 obtain ys1 y ys2 where res: "res = (ys1,y,ys2)" by (cases res, auto) |
2685 note Some = Some[unfolded res] |
2682 note Some = Some[unfolded res] |
2686 from extract_SomeE[OF Some] have "ys = ys1 @ x # ys2" by simp |
2683 from extract_SomeE[OF Some] have "ys = ys1 @ x # ys2" by simp |
2687 hence id: "mset ys = mset (ys1 @ ys2) + {#x#}" |
2684 hence id: "mset ys = mset (ys1 @ ys2) + {#x#}" |
2688 by (auto simp: ac_simps) |
2685 by (auto simp: ac_simps) |
2689 show ?thesis unfolding ms_lesseq_impl.simps |
2686 show ?thesis unfolding subset_eq_mset_impl.simps |
2690 unfolding Some option.simps split |
2687 unfolding Some option.simps split |
2691 unfolding id |
2688 unfolding id |
2692 using Cons[of "ys1 @ ys2"] |
2689 using Cons[of "ys1 @ ys2"] |
2693 unfolding subset_mset_def subseteq_mset_def by auto |
2690 unfolding subset_mset_def subseteq_mset_def by auto |
2694 qed |
2691 qed |
2695 qed |
2692 qed |
2696 |
2693 |
2697 lemma [code]: "mset xs \<subseteq># mset ys \<longleftrightarrow> ms_lesseq_impl xs ys \<noteq> None" |
2694 lemma [code]: "mset xs \<subseteq># mset ys \<longleftrightarrow> subset_eq_mset_impl xs ys \<noteq> None" |
2698 using ms_lesseq_impl[of xs ys] by (cases "ms_lesseq_impl xs ys", auto) |
2695 using subset_eq_mset_impl[of xs ys] by (cases "subset_eq_mset_impl xs ys", auto) |
2699 |
2696 |
2700 lemma [code]: "mset xs \<subset># mset ys \<longleftrightarrow> ms_lesseq_impl xs ys = Some True" |
2697 lemma [code]: "mset xs \<subset># mset ys \<longleftrightarrow> subset_eq_mset_impl xs ys = Some True" |
2701 using ms_lesseq_impl[of xs ys] by (cases "ms_lesseq_impl xs ys", auto) |
2698 using subset_eq_mset_impl[of xs ys] by (cases "subset_eq_mset_impl xs ys", auto) |
2702 |
2699 |
2703 instantiation multiset :: (equal) equal |
2700 instantiation multiset :: (equal) equal |
2704 begin |
2701 begin |
2705 |
2702 |
2706 definition |
2703 definition |
2707 [code del]: "HOL.equal A (B :: 'a multiset) \<longleftrightarrow> A = B" |
2704 [code del]: "HOL.equal A (B :: 'a multiset) \<longleftrightarrow> A = B" |
2708 lemma [code]: "HOL.equal (mset xs) (mset ys) \<longleftrightarrow> ms_lesseq_impl xs ys = Some False" |
2705 lemma [code]: "HOL.equal (mset xs) (mset ys) \<longleftrightarrow> subset_eq_mset_impl xs ys = Some False" |
2709 unfolding equal_multiset_def |
2706 unfolding equal_multiset_def |
2710 using ms_lesseq_impl[of xs ys] by (cases "ms_lesseq_impl xs ys", auto) |
2707 using subset_eq_mset_impl[of xs ys] by (cases "subset_eq_mset_impl xs ys", auto) |
2711 |
2708 |
2712 instance |
2709 instance |
2713 by standard (simp add: equal_multiset_def) |
2710 by standard (simp add: equal_multiset_def) |
2714 |
2711 |
2715 end |
2712 end |