Search code examples
isabelleisar

Sledgehammer gives insufficient proof tactic


I have

theory Even
imports Main

begin

inductive
  structural_even :: "nat ⇒ bool"
where
  "structural_even 0"
| "structural_even n ⟹ structural_even (Suc(Suc n))"

fun
  computational_even :: "nat ⇒ bool"
where
  "computational_even 0 = True"
| "computational_even (Suc 0) = False"
| "computational_even (Suc(Suc n)) = computational_even n"


lemma "computational_even n ⟹ structural_even n"
proof (induct n rule: computational_even.induct)
 show "computational_even 0 ⟹ structural_even 0"
 by (metis structural_even.intros(1))
next

After proof I get

goal (3 subgoals):
 1. computational_even 0 ⟹ structural_even 0
 2. computational_even (Suc 0) ⟹ structural_even (Suc 0)
 3. ⋀n. (computational_even n ⟹ structural_even n) ⟹ computational_even (Suc (Suc n)) ⟹ structural_even (Suc (Suc n))

I got the metis call from sledgehammer where

structural_even.intros(1) = structural_even 0

I get

show computational_even 0 ⟹ structural_even 0 
Successful attempt to solve goal by exported rule:
 computational_even 0 ⟹ structural_even 0 
proof (state): depth 0

then. However, after next I get

goal (3 subgoals):
 1. computational_even 0 ⟹ computational_even 0
 2. computational_even (Suc 0) ⟹ structural_even (Suc 0)
 3. ⋀n. (computational_even n ⟹ structural_even n) ⟹ computational_even (Suc (Suc n)) ⟹ structural_even (Suc (Suc n))

So there is a trivial residual subgoal at 1., despite the system said "Successful attempt to solve goal by exported rule".

Why this happens, and how can I fix it?


Solution

  • Sledgehammer has found a correct proof (though you may want to use simp instead). In fact you can continue with the second and third subgoals (that will be reduced to similar new subgoals as you have for #1 after you prove them) and to finally finish the proof with qed.

    The issue is how Isabelle handles assumptions. If, as in you case, they are not listed explicitly, it is left to the user to prove them. This effect is more explicit if

    show "computational_even 0 ⟹ structural_even 0"
    

    is replaced with equivalent

    presume "computational_even 0"
    show "structural_even 0"
    

    Your proof shows that structural_even 0 is true as soon as computational_even 0 is true, but Isabelle "has no idea" why the latter is true. Therefore it leaves you with the new subgoal that the assumption stated in the proof can be derived from the assumption stated in the subgoal. This subgoal will be handled by qed that finishes the proof by taking assumptions into account.

    BTW, the assumption for this case is not required at all, because structural_even 0 is true by its definition. So the assumption can be safely removed, leaving only

    show "structural_even 0"
    

    Moreover, you can specify arbitrary assumptions with presume, but you will have to prove them later. For example, you can prove the goal

    presume "computational_even (Suc 0)"
    show "structural_even 0"
    

    but then you will have to prove the (false) goal computational_even 0 ⟹ computational_even (Suc 0).

    In order to unify assumption with a premise of a goal, assume is used instead:

    assume "computational_even 0"
    show "structural_even 0"
    

    In that case there is no need to prove assumption of the subgoal (this is already done by the unification step with assume). As a result after finishing the proof of the subgoal, only 2 subgoals will be left as you expected.

    As a free bonus, when assume is used with a wrong assumption (e.g., as in the earlier erroneous case, computational_even (Suc 0)), Isabelle will complain that the corresponding show statement fails to refine any pending goal and you will not be able to proceed.