Search code examples
isabelletheorem-provingsimplification

Simp does not use the provided lemma in Isabelle


I am doing Exercise 2.6 from the Concrete Semantics book:

Starting from the type 'a tree defined in the text, define a function contents :: 'a tree ⇒ 'a list that collects all values in a tree in a list, in any order, without removing duplicates. Then define a function sum_tree :: nat tree ⇒ nat that sums up all values in a tree of natural numbers and prove sum_tree t = sum_list (contents t) (where sum_list is predefined).

I have started to prove the theorem not using auto but guiding Isabelle to use the necessary theorems:

theory Minimal

imports Main

begin

datatype 'a tree = Tip | Node "'a tree" 'a "'a tree"

fun contents :: "'a tree ⇒ 'a list" where
  "contents Tip = []"
| "contents (Node l a r) = a # (contents l) @ (contents r)"

fun sum_tree :: "nat tree ⇒ nat" where
  "sum_tree Tip = 0"
| "sum_tree (Node l a r) = a + (sum_tree l) + (sum_tree r)"

lemma sum_list_contents: 
  "sum_list (contents t1) + sum_list (contents t2) = sum_list (contents t1 @ contents t2)"
  apply auto
  done

lemma sum_commutes: "sum_tree(t) = sum_list(contents(t))"
  apply (induction t)
   apply (simp only: sum_tree.simps contents.simps sum_list.Nil)
   apply (simp only: sum_list.Cons contents.simps sum_tree.simps  sum_list_contents)

Here it arrives to a proof state

proof (prove)
goal (1 subgoal):
 1. ⋀t1 x2 t2.
   sum_tree t1 = sum_list (contents t1) ⟹
   sum_tree t2 = sum_list (contents t2) ⟹
   x2 + sum_list (contents t1) + sum_list (contents t2) = x2 + sum_list (contents t1 @ contents t2)

Where I wonder why simp did not use the provided sum_list_contents lemma. I know simple simp would solve the equation.

What does general simp contain that simp only would not use in this case?


Solution

  • As pointed out in the comments, the missing piece is associativity of addition for natural numbers. Adding add.assoc to the simpplification rules solves the equation.

    Alternatively, the order of operands when defining the tree sum could be changed:

    fun sum_tree_1 :: "nat tree ⇒ nat" where
      "sum_tree_1 Tip = 0"
    | "sum_tree_1 (Node l a r) = a + ((sum_tree_1 l) + (sum_tree_1 r))"
    

    Then the associativity is not required:

    lemma sum_commutes_1: "sum_tree_1(t) = sum_list(contents(t))"
      apply (induction t)
       apply (simp only: sum_tree_1.simps contents.simps sum_list.Nil)
      apply (simp only: sum_list.Cons contents.simps sum_tree_1.simps sum_list_contents)
      done