Theory MultisetSum

(*  Title:      ZF/UNITY/MultisetSum.thy
    Author:     Sidi O Ehmety
*)

section ‹Setsum for Multisets›

theory MultisetSum
imports "ZF-Induct.Multiset"
begin

definition
  lcomm :: "[i, i, [i,i]i]o"  where
  "lcomm(A, B, f) 
   (x  A. y  A. z  B. f(x, f(y, z))= f(y, f(x, z)))  
   (x  A. y  B. f(x, y)  B)"

definition
  general_setsum :: "[i,i,i, [i,i]i, ii] i"  where
   "general_setsum(C, B, e, f, g) 
    if Finite(C) then fold[cons(e, B)](λx y. f(g(x), y), e, C) else e"

definition
  msetsum :: "[ii, i, i]i"  where
  "msetsum(g, C, B)  normalize(general_setsum(C, Mult(B), 0, (+#), g))"


definition  (* sum for naturals *)
  nsetsum :: "[ii, i] i"  where
  "nsetsum(g, C)  general_setsum(C, nat, 0, (#+), g)"


lemma mset_of_normalize: "mset_of(normalize(M))  mset_of(M)"
by (auto simp add: mset_of_def normalize_def)

lemma general_setsum_0 [simp]: "general_setsum(0, B, e, f, g) = e"
by (simp add: general_setsum_def)

lemma general_setsum_cons [simp]: 
"C  Fin(A); a  A; aC; e  B; x  A. g(x)  B; lcomm(B, B, f)   
  general_setsum(cons(a, C), B, e, f, g) =  
    f(g(a), general_setsum(C, B, e, f,g))"
apply (simp add: general_setsum_def)
apply  (auto simp add: Fin_into_Finite [THEN Finite_cons] cons_absorb)
prefer 2 apply (blast dest: Fin_into_Finite)
apply (rule fold_typing.fold_cons)
apply (auto simp add: fold_typing_def lcomm_def)
done

(** lcomm **)

lemma lcomm_mono: "CA; lcomm(A, B, f)  lcomm(C, B,f)"
by (auto simp add: lcomm_def, blast)

lemma munion_lcomm [simp]: "lcomm(Mult(A), Mult(A), (+#))"
by (auto simp add: lcomm_def Mult_iff_multiset munion_lcommute)

(** msetsum **)

lemma multiset_general_setsum: 
     "C  Fin(A); x  A. multiset(g(x)) mset_of(g(x))B   
       multiset(general_setsum(C, B -||> nat - {0}, 0, λu v. u +# v, g))"
apply (erule Fin_induct, auto)
apply (subst general_setsum_cons)
apply (auto simp add: Mult_iff_multiset)
done

lemma msetsum_0 [simp]: "msetsum(g, 0, B) = 0"
by (simp add: msetsum_def)

lemma msetsum_cons [simp]: 
  "C  Fin(A); aC; a  A; x  A. multiset(g(x))  mset_of(g(x))B   
    msetsum(g, cons(a, C), B) = g(a) +#  msetsum(g, C, B)"
apply (simp add: msetsum_def)
apply (subst general_setsum_cons)
apply (auto simp add: multiset_general_setsum Mult_iff_multiset)
done

(* msetsum type *)

lemma msetsum_multiset: "multiset(msetsum(g, C, B))"
by (simp add: msetsum_def)

lemma mset_of_msetsum: 
     "C  Fin(A); x  A. multiset(g(x))  mset_of(g(x))B   
       mset_of(msetsum(g, C, B))B"
by (erule Fin_induct, auto)


(*The reversed orientation looks more natural, but LOOPS as a simprule!*)
lemma msetsum_Un_Int: 
     "C  Fin(A); D  Fin(A); x  A. multiset(g(x))  mset_of(g(x))B
       msetsum(g, C  D, B) +# msetsum(g, C  D, B)  
        = msetsum(g, C, B) +# msetsum(g, D, B)"
apply (erule Fin_induct)
apply (subgoal_tac [2] "cons (x, y)  D = cons (x, y  D) ")
apply (auto simp add: msetsum_multiset)
apply (subgoal_tac "y  D  Fin (A)  y  D  Fin (A) ")
apply clarify
apply (case_tac "x ∈ D")
apply (subgoal_tac [2] "cons (x, y)  D = y  D")
apply (subgoal_tac "cons (x, y)  D = cons (x, y  D) ")
apply (simp_all (no_asm_simp) add: cons_absorb munion_assoc msetsum_multiset)
apply (simp (no_asm_simp) add: munion_lcommute msetsum_multiset)
apply auto
done


lemma msetsum_Un_disjoint:
     "C  Fin(A); D  Fin(A); C  D = 0;  
         x  A. multiset(g(x))  mset_of(g(x))B  
       msetsum(g, C  D, B) = msetsum(g, C, B) +# msetsum(g,D, B)"
apply (subst msetsum_Un_Int [symmetric])
apply (auto simp add: msetsum_multiset)
done

lemma UN_Fin_lemma [rule_format (no_asm)]:
     "I  Fin(A)  (i  I. C(i)  Fin(B))  (i  I. C(i)):Fin(B)"
by (erule Fin_induct, auto)
 
lemma msetsum_UN_disjoint [rule_format (no_asm)]:
     "I  Fin(K); i  K. C(i)  Fin(A)   
      (x  A. multiset(f(x))  mset_of(f(x))B)    
      (i  I. j  I. ij  C(i)  C(j) = 0)   
        msetsum(f, i  I. C(i), B) = msetsum (λi. msetsum(f, C(i),B), I, B)"
apply (erule Fin_induct, auto)
apply (subgoal_tac "i  y. x  i")
 prefer 2 apply blast
apply (subgoal_tac "C(x)  (i  y. C (i)) = 0")
 prefer 2 apply blast
apply (subgoal_tac " (i  y. C (i)):Fin (A)  C(x) :Fin (A) ")
prefer 2 apply (blast intro: UN_Fin_lemma dest: FinD, clarify)
apply (simp (no_asm_simp) add: msetsum_Un_disjoint)
apply (subgoal_tac "x  K. multiset (msetsum (f, C(x), B))  mset_of (msetsum (f, C(x), B))  B")
apply (simp (no_asm_simp))
apply clarify
apply (drule_tac x = xa in bspec)
apply (simp_all (no_asm_simp) add: msetsum_multiset mset_of_msetsum)
done

lemma msetsum_addf: 
    "C  Fin(A);  
      x  A. multiset(f(x))  mset_of(f(x))B;  
      x  A. multiset(g(x))  mset_of(g(x))B  
      msetsum(λx. f(x) +# g(x), C, B) = msetsum(f, C, B) +# msetsum(g, C, B)"
apply (subgoal_tac "x  A. multiset (f(x) +# g(x))  mset_of (f(x) +# g(x))  B")
apply (erule Fin_induct)
apply (auto simp add: munion_ac) 
done

lemma msetsum_cong: 
    "C=D; x. x  D  f(x) = g(x)
      msetsum(f, C, B) = msetsum(g, D, B)"
by (simp add: msetsum_def general_setsum_def cong add: fold_cong)

lemma multiset_union_diff: "multiset(M); multiset(N)  M +# N -# N = M"
by (simp add: multiset_equality)

lemma msetsum_Un: "C  Fin(A); D  Fin(A);  
  x  A. multiset(f(x))  mset_of(f(x))  B  
    msetsum(f, C  D, B) =  
          msetsum(f, C, B) +# msetsum(f, D, B) -# msetsum(f, C  D, B)"
apply (subgoal_tac "C  D  Fin (A)  C  D  Fin (A) ")
apply clarify
apply (subst msetsum_Un_Int [symmetric])
apply (simp_all (no_asm_simp) add: msetsum_multiset multiset_union_diff)
apply (blast dest: FinD)
done

lemma nsetsum_0 [simp]: "nsetsum(g, 0)=0"
by (simp add: nsetsum_def)

lemma nsetsum_cons [simp]: 
     "Finite(C); xC  nsetsum(g, cons(x, C))= g(x) #+ nsetsum(g, C)"
apply (simp add: nsetsum_def general_setsum_def)
apply (rule_tac A = "cons (x, C)" in fold_typing.fold_cons)
apply (auto intro: Finite_cons_lemma simp add: fold_typing_def)
done

lemma nsetsum_type [simp,TC]: "nsetsum(g, C)  nat"
apply (case_tac "Finite (C) ")
 prefer 2 apply (simp add: nsetsum_def general_setsum_def)
apply (erule Finite_induct, auto)
done

end