Using `defines` with induction - isabelle

Consider following lemma which should be easily provable:
lemma
fixes n m::nat
defines "m ≡ n - 1"
shows "m ≤ n"
proof(induction n)
case 0
then show ?case unfolding m_def
(* Why does «n» appear here? *)
next
case (Suc n)
then show ?case sorry
qed
However after unfolding m, the goal becomes n - 1 ≤ 0 instead of 0 - 1 ≤ 0 rendering the goal unprovable since n = 2 is a counterexample.
Is this a bug in Isabelle? How can I unfold the definition correctly?

I think a useful explanation could be the following: Recall the definition of nat.induct, namely
?P 0 ⟹ (⋀n. ?P n ⟹ ?P (Suc n)) ⟹ ?P ?n
and note that ?n means that n is implicitly universally quantified, that is, the previous definition is equivalent to
⋀n. ?P 0 ⟹ (⋀n. ?P n ⟹ ?P (Suc n)) ⟹ ?P n
Now, when applying nat.induct to your example, clearly the first subgoal to prove is ?P 0, i.e., m ≤ 0. However, in that context, n is still an arbitrary but fixed nat, in particular it does not hold that n = 0, and that is the reason why after unfolding the definition of m you get n - 1 ≤ 0 as the new subgoal. With respect to your specific question, the problem is that you cannot prove your result by induction on n (but you can easily prove it using unfolding m_def by simp).

As Javier pointed out, the n defined in the lemma head is different from the n created by induction. In other words, any facts from "outside" that reference n are not directly usable within the proof (induction n) environment.
However, Isabelle does offer a way to "inject" such facts, by piping them into induction:
lemma
fixes n m::nat
defines "m ≡ n - 1"
shows "m ≤ n"
using m_def (* this allows induction to use this fact *)
proof(induction n)
case 0
then show ?case by simp
next
case (Suc n)
then show ?case by simp
qed
using assms will work just as well in this case.
Note that direcly referring to m_def is no longer necessary, since a version of it is included for each case (in 0.hyps and Suc.hyps; use print_cases inside the proof for more information).

Related

Focusing on a subgoal

Having worked with Coq before, I'm used to its system of "focusing" and "unfocusing" goals, so you can work with one goal at a time.
Does a similar system exists in Isabelle?
As an example, this code:
theory Scratch
imports Main
begin
theorem add_0: "n+0 = (n::nat)"
apply(induction n)
Generates a proof state with 2 subgoals:
proof (prove)
goal (2 subgoals):
1. 0 + 0 = 0
2. ⋀n. n + 0 = n ⟹
Suc n + 0 = Suc n
If I use apply(auto), both of them are solved. Let's suppose however that I want to work only on goal 1, is it possible to "focus" on it? If not, how may I apply auto to only one (or some) of the subgoals?
If you don't want to use Isar (which probably is better for readability), you can use subgoal to focus on the goal:
theorem add_0: "n+0 = (n::nat)"
apply(induction n)
subgoal by auto
subgoal by auto
or the brackets:
apply auto[]
to focus auto on the first goal only.
The main difference is that subgoal makes it impossible to instantiate schematic variables.
Mathias and Manuel mentioned the Isar style as the preferred way to focus on subgoals. Here is an example of how that could look like:
theorem add_0: "n+0 = (n::nat)"
proof (induction n)
case 0 ― ‹Focus on induction base subgoal here›
show "0 + 0 = (0::nat)"
by (rule plus_nat.add_0)
next
case (Suc n) ― ‹Focus on induction step subgoal here›
show "Suc n + 0 = Suc n"
proof (subst plus_nat.add_Suc)
show "Suc (n + 0) = Suc n"
by (subst Suc.IH) (rule refl)
qed
qed
Or implicitly, without naming cases:
theorem add_0: "n+0 = (n::nat)"
proof (induction n)
show "0 + 0 = (0::nat)"
by (rule plus_nat.add_0)
next
fix n :: nat
assume IH: "n + 0 = n"
show "Suc n + 0 = Suc n"
proof (subst plus_nat.add_Suc)
show "Suc (n + 0) = Suc n"
by (subst IH) (rule refl)
qed
qed

How to let Isabelle "compute" THE output of an inductive predicate

I have an inductive predicate P that behaves like a partial function. In other words, P x y = P x y' ⟹ y = y'. I'd like to let Isabelle "compute" THE output of the predicate when proving theorems on a concrete value (for an example).
For example, let's say that we have the following predicate div2.
inductive div2 :: "nat ⇒ nat ⇒ bool" where
Zero: "div2 0 0" |
SS: "div2 n m ⟹ div2 (Suc (Suc n)) (Suc m)"
code_pred[show_modes] div2 .
How can I prove the following lemma without providing the output m (the term is too big to type in the actual case)?
lemma "(THE m. div2 8 m) ≠ 5"
sorry
Properties on the and some work nearly always the same way (and sledgehammer does not work well on them).
Prove existence of a witness ;
For the only: prove uniqueness of the witness ;
Deduce with theI or someI that the property holds on the value ;
Prove the theorem you actually wanted to prove.
In your case that translates to proving that 5 is not a witness:
inductive_cases div2E: ‹div2 m n›
lemma "(THE m. div2 8 m) ≠ 5"
proof -
have ex_div2: ‹div2 8 4› (*1: witness*)
by (auto simp: numeral_eq_Suc div2.intros)
moreover have ‹div2 8 m ⟹ m = 4› for m (*2: uniqueness*)
by (force simp: numeral_eq_Suc elim: div2E)
ultimately have ‹div2 8 (THE x. div2 8 x)› (*3: property holds*)
by (rule theI)
(*4 use the property*)
then show ?thesis
by (force simp: numeral_eq_Suc elim: div2E)
qed
If you don't need the, use some instead, that avoids the very annoying uniqueness proof each time.
For your use case, I would advise to write the theorem as div2 8 m ⟹ m ≠ 5, which is equivalent, but much easier to use and to prove.
lemma "div2 8 m ⟹ m ≠ 5"
by (force simp: numeral_eq_Suc elim: div2E)
For reusability:
Factor step 3 in a separate lemma (if there is a meaningful way to express when an invert exists)
Hide as much as possible the predicates by introducing definitions and avoid referring to the lambda-definition as much as possible.

Why can't we do case analysis on inductively defined predicates *directly* when doing rule inversion?

There seems to be something about inductive predicates I don't understand since I keep getting issues with them. My most recent struggle is to understand case analysis with inductively defined predicates on ev from chapter 5 of the concrete semantics books.
Assume I am proving
lemma
shows "ev n ⟹ ev (n - 2)"
I've tried to start the proof immediately in Isabelle/HOL but it complains when I try or gives weird goals:
lemma
shows "ev n ⟹ ev (n - 2)"
proof (cases)
which shows:
proof (state)
goal (2 subgoals):
1. ⟦ev n; ?P⟧ ⟹ ev (n - 2)
2. ⟦ev n; ¬ ?P⟧ ⟹ ev (n - 2)
which is not what I expected.
When I pass n to cases we instead induct on the definition of natural numbers (note other times it does the induction on ev correctly, see later example):
lemma
shows "ev n ⟹ ev (n - 2)"
proof (cases n)
gives:
proof (state)
goal (2 subgoals):
1. ⟦ev n; n = 0⟧ ⟹ ev (n - 2)
2. ⋀nat. ⟦ev n; n = Suc nat⟧ ⟹ ev (n - 2)
which is not what I expected. Note however that the following DOES work (i.e. it inducts on ev not on natural numbers) even with n as a parameter:
lemma
shows "ev n ⟹ ev (n - 2)"
proof -
assume 0: "ev n"
from this show "ev (n - 2)"
proof (cases n)
I realize that there must be some magic about assuming ev n first and then stating to show ev (n-2) otherwise the error wouldn't occur.
I understand the idea of rule inversion (of arriving at a given fact to be proven in reverse, by analysis the cases that could have lead to it). For the "even" predicate the rule inversion is:
ev n ==> n = 0 ∨ (∃k. n = Suc (Suc k) ∧ ev k)
which makes sense based on the inductively defined predicate:
inductive ev :: "nat ⇒ bool" where
ev0: "ev 0" |
evSS: "ev n ⟹ ev (Suc (Suc n))"
but I don't understand. Why wouldn't directly doing the cases work? or why is this syntax invalid:
proof (cases ev)
or this:
proof (cases ev.case)
etc.
I think the crux is that at the heart I don't know when dealing with inductively define predicates if this induction is applied to the goal or the assumption, but from the writing on of the textbook:
The name rule inversion emphasizes that we are reasoning backwards: by which rules could some given fact have been proved?
I'd assume it's applying rule inversion to the goals since it says "by which rules could some given fact have been proved".
In addition, this example ev ==> ev (n-2) froom the book does not help because both the premise and conclusion have ev involved.
How is case analysis with rule inversion really working and why do we need to assume things first for Isabelle to give sensible goal for case analysis?
Not sure I understand the entire question but this:
lemma
shows "ev n ⟹ ev (n - 2)"
proof (cases)
Gives you:
proof (state)
goal (2 subgoals):
1. ⟦ev n; ?P⟧ ⟹ ev (n - 2)
2. ⟦ev n; ¬ ?P⟧ ⟹ ev (n - 2)
because Isabelle is splitting on the truth of ev n, i.e. either true or false. I believe the syntax you are looking for is:
proof (cases rule: ev.cases)
Which is how you tell Isabelle explicitly what rule it should use for a proof by cases.
The way to do it is as the answer Ben Sheffield said:
proof (cases rule: ev.cases)
I also noticed that:
apply (rule ev.cases)
works, but I think it would be helpful to go through a small example to see the cases explicitly outlined:
Consider:
lemma "ev n ⟹ ev (n - 2)"
first inspect it's cases theorem:
thm ev.cases
⟦ev ?a; ?a = 0 ⟹ ?P; ⋀n. ⟦?a = Suc (Suc n); ev n⟧ ⟹ ?P⟧ ⟹ ?P
then it unifies the goal and introduces the new goals with the original assumptions and all the assumption for the cases. That is why there is a ev n in all of them.
apply (rule ev.cases)
has goals:
proof (prove)
goal (3 subgoals):
1. ev n ⟹ ev ?a
2. ⟦ev n; ?a = 0⟧ ⟹ ev (n - 2)
3. ⋀na. ⟦ev n; ?a = Suc (Suc na); ev na⟧ ⟹ ev (n - 2)
and you can do simp and proceed the proof as normal.

How can I prove irreflexivity of an inductively defined relation in Isabelle?

Consider as an example the following definition of inequality of natural numbers in Isabelle:
inductive unequal :: "nat ⇒ nat ⇒ bool" where
zero_suc: "unequal 0 (Suc _)" |
suc_zero: "unequal (Suc _) 0" |
suc_suc: "unequal n m ⟹ unequal (Suc n) (Suc m)"
I want to prove irreflexivity of unequal, that is, ¬ unequal n n. For illustration purposes let me first prove the contrived lemma ¬ unequal (n + m) (n + m):
lemma "¬ unequal (n + m) (n + m)"
proof
assume "unequal (n + m) (n + m)"
then show False
proof (induction "n + m" "n + m" arbitrary: n m)
case zero_suc
then show False by simp
next
case suc_zero
then show False by simp
next
case suc_suc
then show False by presburger
qed
qed
In the first two cases, False must be deduced from the assumptions 0 = n + m and Suc _ = n + m, which is trivial.
I would expect that the proof of ¬ unequal n n can be done in an analogous way, that is, according to the following pattern:
lemma "¬ unequal n n"
proof
assume "unequal n n"
then show False
proof (induction n n arbitrary: n)
case zero_suc
then show False sorry
next
case suc_zero
then show False sorry
next
case suc_suc
then show False sorry
qed
qed
In particular, I would expect that in the first two cases, I get the assumptions 0 = n and Suc _ = n. However, I get no assumptions at all, meaning that I am asked to prove False from nothing. Why is this and how can I conduct the proof of inequality?
You are inducting over unequal. Instead, you should induct over n, like this:
lemma "¬ (unequal n n)"
proof (induct n)
case 0
then show ?case sorry
next
case (Suc n)
then show ?case sorry
qed
Then we can use Sledgehammer on each of the subgoals marked with sorry. Sledgehammer (with CVC4) recommends us to complete the proof as follows:
lemma "¬ (unequal n n)"
proof (induct n)
case 0
then show ?case using unequal.cases by blast
next
case (Suc n)
then show ?case using unequal.cases by blast
qed
The induction method handles variable instantiations and non-variable instantiations differently. A non-variable instantiation t is a shorthand for x ≡ t where x is a fresh variable. As a result, induction is done on x, and the context additionally contains the definition x ≡ t.
Therefore, (induction "n + m" "n + m" arbitrary: n m) in the first proof is equivalent to (induction k ≡ "n + m" l ≡ "n + m" arbitrary: n m) with the effect described above. To get this effect for the second proof, you have to replace (induction n n arbitrary: n) with (induction k ≡ n l ≡ n arbitrary: n). The assumptions will actually become so simple that the pre-simplifier, which is run by the induction method, can derive False from them. As a result, there will be no cases left to prove, and you can replace the whole inner proof–qed block with by (induction k ≡ n l ≡ n arbitrary: n).

Proof by induction with three base cases (Isabelle)

I want to be able to prove a statement by induction on n (of type nat). It consists of a conditional whose antecedent is only true for n >= 2. A conditional whose antecedent is false is always true. So I'd like to prove the cases n=0, n=1 and n=2 all separately from the main inductive step. Is it possible to do a proof by induction with three base cases like the following:
lemma "P (n::nat) --> Q"
proof (induct n)
case 0
show ?case sorry
next
case 1
show ?case sorry
next
case 2
show ?case sorry
next
case (Suc n)
show ?case sorry
qed
As it stands, this doesn't seem to work. I could prove "P (n+2) --> Q" by induction instead, but it wouldn't be as strong a statement. I'm considering a case split into "n=0","n=1" and "n>=2", and proving only the last case by induction.
The cleanest way is probably to prove a custom induction rule for the kind of induction that you want, like this:
lemma nat_0_1_2_induct [case_names 0 1 2 step]:
assumes "P 0" "P 1" "P 2" "⋀n. n ≥ 2 ⟹ P n ⟹ P (Suc n)"
shows "P n"
proof (induction n rule: less_induct)
case (less n)
show ?case using assms(4)[OF _ less.IH[of "n - 1"]]
by (cases "n ≤ 2") (insert assms(1-3), auto simp: eval_nat_numeral le_Suc_eq)
qed
lemma "P (n::nat) ⟶ Q"
proof (induction n rule: nat_0_1_2_induct)
In theory, the induction_schema method is also very useful to prove such custom induction rules, but in this case, it doesn't help a lot:
lemma nat_0_1_2_induct [case_names 0 1 2 step]:
"P 0 ⟹ P 1 ⟹ P 2 ⟹ (⋀n. n ≥ 2 ⟹ P n ⟹ P (Suc n)) ⟹ P n"
proof (induction_schema, goal_cases complete wf terminate)
case (complete P n)
thus ?case by (cases n) force+
next
show "wf (Wellfounded.measure id)" by (rule wf_measure)
qed simp_all
You could also use less_induct directly and then do a case distinction within the induction step for the base cases.

Resources