src/HOL/Finite_Set.thy
changeset 15480 cb3612cc41a3
parent 15479 fbc473ea9d3c
child 15483 704b3ce6d0f7
equal deleted inserted replaced
15479:fbc473ea9d3c 15480:cb3612cc41a3
     1 (*  Title:      HOL/Finite_Set.thy
     1 (*  Title:      HOL/Finite_Set.thy
     2     ID:         $Id$
     2     ID:         $Id$
     3     Author:     Tobias Nipkow, Lawrence C Paulson and Markus Wenzel
     3     Author:     Tobias Nipkow, Lawrence C Paulson and Markus Wenzel
     4                 Additions by Jeremy Avigad in Feb 2004
     4                 Additions by Jeremy Avigad in Feb 2004
     5 
       
     6 Get rid of a couple of superfluous finiteness assumptions in lemmas
       
     7 about setsum and card - see FIXME.
       
     8 NB: the analogous lemmas for setprod should also be simplified!
       
     9 *)
     5 *)
    10 
     6 
    11 header {* Finite sets *}
     7 header {* Finite sets *}
    12 
     8 
    13 theory Finite_Set
     9 theory Finite_Set
   410 
   406 
   411 
   407 
   412 subsection {* A fold functional for finite sets *}
   408 subsection {* A fold functional for finite sets *}
   413 
   409 
   414 text {* The intended behaviour is
   410 text {* The intended behaviour is
   415 @{text "fold f g e {x\<^isub>1, ..., x\<^isub>n} = f (g x\<^isub>1) (\<dots> (f (g x\<^isub>n) e)\<dots>)"}
   411 @{text "fold f g z {x\<^isub>1, ..., x\<^isub>n} = f (g x\<^isub>1) (\<dots> (f (g x\<^isub>n) z)\<dots>)"}
   416 if @{text f} is associative-commutative. For an application of @{text fold}
   412 if @{text f} is associative-commutative. For an application of @{text fold}
   417 se the definitions of sums and products over finite sets.
   413 se the definitions of sums and products over finite sets.
   418 *}
   414 *}
   419 
   415 
   420 consts
   416 consts
   421   foldSet :: "('a => 'a => 'a) => ('b => 'a) => 'a => ('b set \<times> 'a) set"
   417   foldSet :: "('a => 'a => 'a) => ('b => 'a) => 'a => ('b set \<times> 'a) set"
   422 
   418 
   423 inductive "foldSet f g e"
   419 inductive "foldSet f g z"
   424 intros
   420 intros
   425 emptyI [intro]: "({}, e) : foldSet f g e"
   421 emptyI [intro]: "({}, z) : foldSet f g z"
   426 insertI [intro]: "\<lbrakk> x \<notin> A; (A, y) : foldSet f g e \<rbrakk>
   422 insertI [intro]: "\<lbrakk> x \<notin> A; (A, y) : foldSet f g z \<rbrakk>
   427  \<Longrightarrow> (insert x A, f (g x) y) : foldSet f g e"
   423  \<Longrightarrow> (insert x A, f (g x) y) : foldSet f g z"
   428 
   424 
   429 inductive_cases empty_foldSetE [elim!]: "({}, x) : foldSet f g e"
   425 inductive_cases empty_foldSetE [elim!]: "({}, x) : foldSet f g z"
   430 
   426 
   431 constdefs
   427 constdefs
   432   fold :: "('a => 'a => 'a) => ('b => 'a) => 'a => 'b set => 'a"
   428   fold :: "('a => 'a => 'a) => ('b => 'a) => 'a => 'b set => 'a"
   433   "fold f g e A == THE x. (A, x) : foldSet f g e"
   429   "fold f g z A == THE x. (A, x) : foldSet f g z"
   434 
   430 
   435 lemma Diff1_foldSet:
   431 lemma Diff1_foldSet:
   436   "(A - {x}, y) : foldSet f g e ==> x: A ==> (A, f (g x) y) : foldSet f g e"
   432   "(A - {x}, y) : foldSet f g z ==> x: A ==> (A, f (g x) y) : foldSet f g z"
   437 by (erule insert_Diff [THEN subst], rule foldSet.intros, auto)
   433 by (erule insert_Diff [THEN subst], rule foldSet.intros, auto)
   438 
   434 
   439 lemma foldSet_imp_finite: "(A, x) : foldSet f g e ==> finite A"
   435 lemma foldSet_imp_finite: "(A, x) : foldSet f g z ==> finite A"
   440   by (induct set: foldSet) auto
   436   by (induct set: foldSet) auto
   441 
   437 
   442 lemma finite_imp_foldSet: "finite A ==> EX x. (A, x) : foldSet f g e"
   438 lemma finite_imp_foldSet: "finite A ==> EX x. (A, x) : foldSet f g z"
   443   by (induct set: Finites) auto
   439   by (induct set: Finites) auto
   444 
   440 
   445 
   441 
   446 subsubsection {* Commutative monoids *}
   442 subsubsection {* Commutative monoids *}
       
   443 
   447 locale ACf =
   444 locale ACf =
   448   fixes f :: "'a => 'a => 'a"    (infixl "\<cdot>" 70)
   445   fixes f :: "'a => 'a => 'a"    (infixl "\<cdot>" 70)
   449   assumes commute: "x \<cdot> y = y \<cdot> x"
   446   assumes commute: "x \<cdot> y = y \<cdot> x"
   450     and assoc: "(x \<cdot> y) \<cdot> z = x \<cdot> (y \<cdot> z)"
   447     and assoc: "(x \<cdot> y) \<cdot> z = x \<cdot> (y \<cdot> z)"
   451 
   448 
   452 locale ACe = ACf +
   449 locale ACe = ACf +
   453   fixes e :: 'a
   450   fixes e :: 'a
   454   assumes ident [simp]: "x \<cdot> e = x"
   451   assumes ident [simp]: "x \<cdot> e = x"
       
   452 
       
   453 locale ACIf = ACf +
       
   454   assumes idem: "x \<cdot> x = x"
   455 
   455 
   456 lemma (in ACf) left_commute: "x \<cdot> (y \<cdot> z) = y \<cdot> (x \<cdot> z)"
   456 lemma (in ACf) left_commute: "x \<cdot> (y \<cdot> z) = y \<cdot> (x \<cdot> z)"
   457 proof -
   457 proof -
   458   have "x \<cdot> (y \<cdot> z) = (y \<cdot> z) \<cdot> x" by (simp only: commute)
   458   have "x \<cdot> (y \<cdot> z) = (y \<cdot> z) \<cdot> x" by (simp only: commute)
   459   also have "... = y \<cdot> (z \<cdot> x)" by (simp only: assoc)
   459   also have "... = y \<cdot> (z \<cdot> x)" by (simp only: assoc)
   540     qed
   540     qed
   541   qed
   541   qed
   542 qed
   542 qed
   543 
   543 
   544 lemma (in ACf) foldSet_determ_aux:
   544 lemma (in ACf) foldSet_determ_aux:
   545   "!!A x x' h. \<lbrakk> A = h`{i::nat. i<n}; (A,x) : foldSet f g e; (A,x') : foldSet f g e \<rbrakk>
   545   "!!A x x' h. \<lbrakk> A = h`{i::nat. i<n}; (A,x) : foldSet f g z; (A,x') : foldSet f g z \<rbrakk>
   546    \<Longrightarrow> x' = x"
   546    \<Longrightarrow> x' = x"
   547 proof (induct n)
   547 proof (induct n)
   548   case 0 thus ?case by auto
   548   case 0 thus ?case by auto
   549 next
   549 next
   550   case (Suc n)
   550   case (Suc n)
   551   have IH: "!!A x x' h. \<lbrakk>A = h`{i::nat. i<n}; (A,x) \<in> foldSet f g e; (A,x') \<in> foldSet f g e\<rbrakk>
   551   have IH: "!!A x x' h. \<lbrakk>A = h`{i::nat. i<n}; (A,x) \<in> foldSet f g z; (A,x') \<in> foldSet f g z\<rbrakk>
   552            \<Longrightarrow> x' = x" and card: "A = h`{i. i<Suc n}"
   552            \<Longrightarrow> x' = x" and card: "A = h`{i. i<Suc n}"
   553   and Afoldx: "(A, x) \<in> foldSet f g e" and Afoldy: "(A,x') \<in> foldSet f g e" .
   553   and Afoldx: "(A, x) \<in> foldSet f g z" and Afoldy: "(A,x') \<in> foldSet f g z" .
   554   show ?case
   554   show ?case
   555   proof cases
   555   proof cases
   556     assume "EX k<n. h n = h k"
   556     assume "EX k<n. h n = h k"
   557     hence card': "A = h ` {i. i < n}"
   557     hence card': "A = h ` {i. i < n}"
   558       using card by (auto simp:image_def less_Suc_eq)
   558       using card by (auto simp:image_def less_Suc_eq)
   559     show ?thesis by(rule IH[OF card' Afoldx Afoldy])
   559     show ?thesis by(rule IH[OF card' Afoldx Afoldy])
   560   next
   560   next
   561     assume new: "\<not>(EX k<n. h n = h k)"
   561     assume new: "\<not>(EX k<n. h n = h k)"
   562     show ?thesis
   562     show ?thesis
   563     proof (rule foldSet.cases[OF Afoldx])
   563     proof (rule foldSet.cases[OF Afoldx])
   564       assume "(A, x) = ({}, e)"
   564       assume "(A, x) = ({}, z)"
   565       thus "x' = x" using Afoldy by (auto)
   565       thus "x' = x" using Afoldy by (auto)
   566     next
   566     next
   567       fix B b y
   567       fix B b y
   568       assume eq1: "(A, x) = (insert b B, g b \<cdot> y)"
   568       assume eq1: "(A, x) = (insert b B, g b \<cdot> y)"
   569 	and y: "(B,y) \<in> foldSet f g e" and notinB: "b \<notin> B"
   569 	and y: "(B,y) \<in> foldSet f g z" and notinB: "b \<notin> B"
   570       hence A1: "A = insert b B" and x: "x = g b \<cdot> y" by auto
   570       hence A1: "A = insert b B" and x: "x = g b \<cdot> y" by auto
   571       show ?thesis
   571       show ?thesis
   572       proof (rule foldSet.cases[OF Afoldy])
   572       proof (rule foldSet.cases[OF Afoldy])
   573 	assume "(A,x') = ({}, e)"
   573 	assume "(A,x') = ({}, z)"
   574 	thus ?thesis using A1 by auto
   574 	thus ?thesis using A1 by auto
   575       next
   575       next
   576 	fix C c z
   576 	fix C c r
   577 	assume eq2: "(A,x') = (insert c C, g c \<cdot> z)"
   577 	assume eq2: "(A,x') = (insert c C, g c \<cdot> r)"
   578 	  and z: "(C,z) \<in> foldSet f g e" and notinC: "c \<notin> C"
   578 	  and r: "(C,r) \<in> foldSet f g z" and notinC: "c \<notin> C"
   579 	hence A2: "A = insert c C" and x': "x' = g c \<cdot> z" by auto
   579 	hence A2: "A = insert c C" and x': "x' = g c \<cdot> r" by auto
   580 	obtain hB where lessB: "B = hB ` {i. i<n}"
   580 	obtain hB where lessB: "B = hB ` {i. i<n}"
   581 	  using card_lemma[OF A1 notinB card new] by auto
   581 	  using card_lemma[OF A1 notinB card new] by auto
   582 	obtain hC where lessC: "C = hC ` {i. i<n}"
   582 	obtain hC where lessC: "C = hC ` {i. i<n}"
   583 	  using card_lemma[OF A2 notinC card new] by auto
   583 	  using card_lemma[OF A2 notinC card new] by auto
   584 	show ?thesis
   584 	show ?thesis
   585 	proof cases
   585 	proof cases
   586 	  assume "b = c"
   586 	  assume "b = c"
   587 	  then moreover have "B = C" using A1 A2 notinB notinC by auto
   587 	  then moreover have "B = C" using A1 A2 notinB notinC by auto
   588 	  ultimately show ?thesis using IH[OF lessB] y z x x' by auto
   588 	  ultimately show ?thesis using IH[OF lessB] y r x x' by auto
   589 	next
   589 	next
   590 	  assume diff: "b \<noteq> c"
   590 	  assume diff: "b \<noteq> c"
   591 	  let ?D = "B - {c}"
   591 	  let ?D = "B - {c}"
   592 	  have B: "B = insert c ?D" and C: "C = insert b ?D"
   592 	  have B: "B = insert c ?D" and C: "C = insert b ?D"
   593 	    using A1 A2 notinB notinC diff by(blast elim!:equalityE)+
   593 	    using A1 A2 notinB notinC diff by(blast elim!:equalityE)+
   594 	  have "finite A" by(rule foldSet_imp_finite[OF Afoldx])
   594 	  have "finite A" by(rule foldSet_imp_finite[OF Afoldx])
   595 	  with A1 have "finite ?D" by simp
   595 	  with A1 have "finite ?D" by simp
   596 	  then obtain d where Dfoldd: "(?D,d) \<in> foldSet f g e"
   596 	  then obtain d where Dfoldd: "(?D,d) \<in> foldSet f g z"
   597 	    using finite_imp_foldSet by rules
   597 	    using finite_imp_foldSet by rules
   598 	  moreover have cinB: "c \<in> B" using B by(auto)
   598 	  moreover have cinB: "c \<in> B" using B by(auto)
   599 	  ultimately have "(B,g c \<cdot> d) \<in> foldSet f g e"
   599 	  ultimately have "(B,g c \<cdot> d) \<in> foldSet f g z"
   600 	    by(rule Diff1_foldSet)
   600 	    by(rule Diff1_foldSet)
   601 	  hence "g c \<cdot> d = y" by(rule IH[OF lessB y])
   601 	  hence "g c \<cdot> d = y" by(rule IH[OF lessB y])
   602           moreover have "g b \<cdot> d = z"
   602           moreover have "g b \<cdot> d = r"
   603 	  proof (rule IH[OF lessC z])
   603 	  proof (rule IH[OF lessC r])
   604 	    show "(C,g b \<cdot> d) \<in> foldSet f g e" using C notinB Dfoldd
   604 	    show "(C,g b \<cdot> d) \<in> foldSet f g z" using C notinB Dfoldd
   605 	      by fastsimp
   605 	      by fastsimp
   606 	  qed
   606 	  qed
   607 	  ultimately show ?thesis using x x' by(auto simp:AC)
   607 	  ultimately show ?thesis using x x' by(auto simp:AC)
   608 	qed
   608 	qed
   609       qed
   609       qed
   681   qed
   681   qed
   682 qed
   682 qed
   683 *)
   683 *)
   684 
   684 
   685 lemma (in ACf) foldSet_determ:
   685 lemma (in ACf) foldSet_determ:
   686   "(A, x) : foldSet f g e ==> (A, y) : foldSet f g e ==> y = x"
   686   "(A, x) : foldSet f g z ==> (A, y) : foldSet f g z ==> y = x"
   687 apply(frule foldSet_imp_finite)
   687 apply(frule foldSet_imp_finite)
   688 apply(simp add:finite_conv_nat_seg_image)
   688 apply(simp add:finite_conv_nat_seg_image)
   689 apply(blast intro: foldSet_determ_aux [rule_format])
   689 apply(blast intro: foldSet_determ_aux [rule_format])
   690 done
   690 done
   691 
   691 
   692 lemma (in ACf) fold_equality: "(A, y) : foldSet f g e ==> fold f g e A = y"
   692 lemma (in ACf) fold_equality: "(A, y) : foldSet f g z ==> fold f g z A = y"
   693   by (unfold fold_def) (blast intro: foldSet_determ)
   693   by (unfold fold_def) (blast intro: foldSet_determ)
   694 
   694 
   695 text{* The base case for @{text fold}: *}
   695 text{* The base case for @{text fold}: *}
   696 
   696 
   697 lemma fold_empty [simp]: "fold f g e {} = e"
   697 lemma fold_empty [simp]: "fold f g z {} = z"
   698   by (unfold fold_def) blast
   698   by (unfold fold_def) blast
   699 
   699 
   700 lemma (in ACf) fold_insert_aux: "x \<notin> A ==>
   700 lemma (in ACf) fold_insert_aux: "x \<notin> A ==>
   701     ((insert x A, v) : foldSet f g e) =
   701     ((insert x A, v) : foldSet f g z) =
   702     (EX y. (A, y) : foldSet f g e & v = f (g x) y)"
   702     (EX y. (A, y) : foldSet f g z & v = f (g x) y)"
   703   apply auto
   703   apply auto
   704   apply (rule_tac A1 = A and f1 = f in finite_imp_foldSet [THEN exE])
   704   apply (rule_tac A1 = A and f1 = f in finite_imp_foldSet [THEN exE])
   705    apply (fastsimp dest: foldSet_imp_finite)
   705    apply (fastsimp dest: foldSet_imp_finite)
   706   apply (blast intro: foldSet_determ)
   706   apply (blast intro: foldSet_determ)
   707   done
   707   done
   708 
   708 
   709 text{* The recursion equation for @{text fold}: *}
   709 text{* The recursion equation for @{text fold}: *}
   710 
   710 
   711 lemma (in ACf) fold_insert[simp]:
   711 lemma (in ACf) fold_insert[simp]:
   712     "finite A ==> x \<notin> A ==> fold f g e (insert x A) = f (g x) (fold f g e A)"
   712     "finite A ==> x \<notin> A ==> fold f g z (insert x A) = f (g x) (fold f g z A)"
   713   apply (unfold fold_def)
   713   apply (unfold fold_def)
   714   apply (simp add: fold_insert_aux)
   714   apply (simp add: fold_insert_aux)
   715   apply (rule the_equality)
   715   apply (rule the_equality)
   716   apply (auto intro: finite_imp_foldSet
   716   apply (auto intro: finite_imp_foldSet
   717     cong add: conj_cong simp add: fold_def [symmetric] fold_equality)
   717     cong add: conj_cong simp add: fold_def [symmetric] fold_equality)
   719 
   719 
   720 declare
   720 declare
   721   empty_foldSetE [rule del]  foldSet.intros [rule del]
   721   empty_foldSetE [rule del]  foldSet.intros [rule del]
   722   -- {* Delete rules to do with @{text foldSet} relation. *}
   722   -- {* Delete rules to do with @{text foldSet} relation. *}
   723 
   723 
       
   724 text{* A simplified version for idempotent functions: *}
       
   725 
       
   726 lemma (in ACIf) fold_insert2:
       
   727 assumes finA: "finite A"
       
   728 shows "fold (op \<cdot>) g z (insert a A) = g a \<cdot> fold f g z A"
       
   729 proof cases
       
   730   assume "a \<in> A"
       
   731   then obtain B where A: "A = insert a B" and disj: "a \<notin> B"
       
   732     by(blast dest: mk_disjoint_insert)
       
   733   show ?thesis
       
   734   proof -
       
   735     from finA A have finB: "finite B" by(blast intro: finite_subset)
       
   736     have "fold f g z (insert a A) = fold f g z (insert a B)" using A by simp
       
   737     also have "\<dots> = (g a) \<cdot> (fold f g z B)"
       
   738       using finB disj by(simp)
       
   739     also have "\<dots> = g a \<cdot> fold f g z A"
       
   740       using A finB disj by(simp add:idem assoc[symmetric])
       
   741     finally show ?thesis .
       
   742   qed
       
   743 next
       
   744   assume "a \<notin> A"
       
   745   with finA show ?thesis by simp
       
   746 qed
       
   747 
   724 subsubsection{*Lemmas about @{text fold}*}
   748 subsubsection{*Lemmas about @{text fold}*}
   725 
   749 
   726 lemma (in ACf) fold_commute:
   750 lemma (in ACf) fold_commute:
   727   "finite A ==> (!!e. f (g x) (fold f g e A) = fold f g (f (g x) e) A)"
   751   "finite A ==> (!!z. f (g x) (fold f g z A) = fold f g (f (g x) z) A)"
   728   apply (induct set: Finites, simp)
   752   apply (induct set: Finites, simp)
   729   apply (simp add: left_commute)
   753   apply (simp add: left_commute)
   730   done
   754   done
   731 
   755 
   732 lemma (in ACf) fold_nest_Un_Int:
   756 lemma (in ACf) fold_nest_Un_Int:
   733   "finite A ==> finite B
   757   "finite A ==> finite B
   734     ==> fold f g (fold f g e B) A = fold f g (fold f g e (A Int B)) (A Un B)"
   758     ==> fold f g (fold f g z B) A = fold f g (fold f g z (A Int B)) (A Un B)"
   735   apply (induct set: Finites, simp)
   759   apply (induct set: Finites, simp)
   736   apply (simp add: fold_commute Int_insert_left insert_absorb)
   760   apply (simp add: fold_commute Int_insert_left insert_absorb)
   737   done
   761   done
   738 
   762 
   739 lemma (in ACf) fold_nest_Un_disjoint:
   763 lemma (in ACf) fold_nest_Un_disjoint:
   740   "finite A ==> finite B ==> A Int B = {}
   764   "finite A ==> finite B ==> A Int B = {}
   741     ==> fold f g e (A Un B) = fold f g (fold f g e B) A"
   765     ==> fold f g z (A Un B) = fold f g (fold f g z B) A"
   742   by (simp add: fold_nest_Un_Int)
   766   by (simp add: fold_nest_Un_Int)
   743 
   767 
   744 lemma (in ACf) fold_reindex:
   768 lemma (in ACf) fold_reindex:
   745 assumes fin: "finite B"
   769 assumes fin: "finite B"
   746 shows "inj_on h B \<Longrightarrow> fold f g e (h ` B) = fold f (g \<circ> h) e B"
   770 shows "inj_on h B \<Longrightarrow> fold f g z (h ` B) = fold f (g \<circ> h) z B"
   747 using fin apply (induct)
   771 using fin apply (induct)
   748  apply simp
   772  apply simp
   749 apply simp
   773 apply simp
   750 done
   774 done
   751 
   775 
   774    prefer 2 apply blast
   798    prefer 2 apply blast
   775   apply (simp add: fold_Un_disjoint)
   799   apply (simp add: fold_Un_disjoint)
   776   done
   800   done
   777 
   801 
   778 lemma (in ACf) fold_cong:
   802 lemma (in ACf) fold_cong:
   779   "finite A \<Longrightarrow> (!!x. x:A ==> g x = h x) ==> fold f g a A = fold f h a A"
   803   "finite A \<Longrightarrow> (!!x. x:A ==> g x = h x) ==> fold f g z A = fold f h z A"
   780   apply (subgoal_tac "ALL C. C <= A --> (ALL x:C. g x = h x) --> fold f g a C = fold f h a C")
   804   apply (subgoal_tac "ALL C. C <= A --> (ALL x:C. g x = h x) --> fold f g z C = fold f h z C")
   781    apply simp
   805    apply simp
   782   apply (erule finite_induct, simp)
   806   apply (erule finite_induct, simp)
   783   apply (simp add: subset_insert_iff, clarify)
   807   apply (simp add: subset_insert_iff, clarify)
   784   apply (subgoal_tac "finite C")
   808   apply (subgoal_tac "finite C")
   785    prefer 2 apply (blast dest: finite_subset [COMP swap_prems_rl])
   809    prefer 2 apply (blast dest: finite_subset [COMP swap_prems_rl])
  1824 apply (rule the_equality)
  1848 apply (rule the_equality)
  1825 apply (auto intro: finite_nonempty_imp_foldSet1
  1849 apply (auto intro: finite_nonempty_imp_foldSet1
  1826     cong add: conj_cong simp add: fold1_def [symmetric] foldSet1_equality)
  1850     cong add: conj_cong simp add: fold1_def [symmetric] foldSet1_equality)
  1827 done
  1851 done
  1828 
  1852 
  1829 locale ACIf = ACf +
       
  1830   assumes idem: "x \<cdot> x = x"
       
  1831 
       
  1832 lemma (in ACIf) fold1_insert2:
  1853 lemma (in ACIf) fold1_insert2:
  1833 assumes finA: "finite A" and nonA: "A \<noteq> {}"
  1854 assumes finA: "finite A" and nonA: "A \<noteq> {}"
  1834 shows "fold1 f (insert a A) = f a (fold1 f A)"
  1855 shows "fold1 f (insert a A) = f a (fold1 f A)"
  1835 proof cases
  1856 proof cases
  1836   assume "a \<in> A"
  1857   assume "a \<in> A"