Search code examples
setlogicisabellemultiset

How can I subtract a multiset from a set with a given multiset?


So I'm trying to define a function apply_C :: "('a multiset ⇒ 'a option) ⇒ 'a multiset ⇒ 'a multiset"

It takes in a function C that may convert an 'a multiset into a single element of type 'a. Here we assume that each element in the domain of C is pairwise mutually exclusive and not the empty multiset (I already have another function that checks these things). apply will also take another multiset inp. What I'd like the function to do is check if there is at least one element in the domain of C that is completely contained in inp. If this is the case, then perform a set difference inp - s where s is the element in the domain of C and add the element the (C s) into this resulting multiset. Afterwards, keep running the function until there are no more elements in the domain of C that are completely contained in the given inp multiset.

What I tried was the following:

fun apply_C :: "('a multiset ⇒ 'a option) ⇒ 'a multiset ⇒ 'a multiset" where
"apply_C C inp = (if ∃s ∈ (domain C). s ⊆# inp then apply_C C (add_mset (the (C s)) (inp - s)) else inp)"

However, I get this error:

Variable "s" occurs on right hand side only:
⋀C inp s.
   apply_C C inp =
   (if ∃s∈domain C. s ⊆# inp
    then apply_C C
          (add_mset (the (C s)) (inp - s))
    else inp)

I have been thinking about this problem for days now, and I haven't been able to find a way to implement this functionality in Isabelle. Could I please have some help?


Solution

  • After thinking more about it, I don't believe there is a simple solutions for that Isabelle.

    Do you need that?

    I have not said why you want that. Maybe you can reduce your assumptions? Do you really need a function to calculate the result?

    How to express the definition?

    I would use an inductive predicate that express one step of rewriting and prove that the solution is unique. Something along:

    context
      fixes C :: ‹'a multiset ⇒ 'a option›
    begin
    inductive apply_CI where
     ‹apply_CI (M + M') (add_mset (the (C M)) M')›
    if ‹M ∈ dom C›
    
    context
      assumes
         distinct: ‹⋀a b. a ∈ dom C ⟹ b ∈ dom C ⟹ a ≠ b ⟹ a ∩# b = {#}› and
         strictly_smaller: ‹⋀a b. a ∈ dom C ⟹ size a > 1› 
    begin
    
    lemma apply_CI_determ:
      assumes
        ‹apply_CI⇧*⇧* M M⇩1› and
        ‹apply_CI⇧*⇧* M M⇩2› and
        ‹⋀M⇩3. ¬apply_CI M⇩1 M⇩3›
        ‹⋀M⇩3. ¬apply_CI M⇩2 M⇩3›
      shows ‹M⇩1 = M⇩2›
      sorry
    
    lemma apply_CI_smaller:
      ‹apply_CI M M' ⟹ size M' ≤ size M›
      apply (induction rule: apply_CI.induct)
      subgoal for M M'
        using strictly_smaller[of M]
        by auto
      done
    
    lemma wf_apply_CI:
       ‹wf {(x, y). apply_CI y x}›
    (*trivial but very annoying because not enough useful lemmas on wf*)
      sorry
    end
    end
    

    I have no clue how to prove apply_CI_determ (no idea if the conditions I wrote down are sufficient or not), but I did spend much thinking about it.

    After that you can define your definitions with:

    definition apply_C where
      ‹apply_C M = (SOME M'. apply_CI⇧*⇧* M M' ∧ (∀M⇩3. ¬apply_CI M' M⇩3))›
    

    and prove the property in your definition.

    How to execute it

    I don't see how to write an executable function on multisets directly. The problem you face is that one step of apply_C is nondeterministic.

    If you can use lists instead of multisets, you get an order on the elements for free and you can use subseqs that gives you all possible subsets. Rewrite using the first element in subseqs that is in the domain of C. Iterate as long as there is any possible rewriting.

    Link that to the inductive predicate to prove termination and that it calculates the right thing.

    Remark that in general you cannot extract a list out of a multiset, but it is possible to do so in some cases (e.g., if you have a linorder over 'a).