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
Related
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).
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).
I am trying to prove something, that I thought would be relatively simple.
(k≥10 ⟹ 2^(k::nat) > (k::nat)^3)
However, I am getting stuck and do not know how to progress.
lemma "(k≥10 ⟹ 2^(k::nat) > (k::nat)^3)"
proof (induction k)
case 0
then show ?case by simp
next
case (Suc k)
assume "10 ≤ k ⟹ k ^ 3 < 2 ^ k"
assume "10 ≤ Suc k"
show "(Suc k) ^ 3 < 2 ^( Suc k)"
apply (simp add: algebra_simps)
then show ?case sorry
qed
A good induction rule can save a lot of hassle. You want to start induction with 10, not 0, so maybe there is a better induction rule? Using
find_theorems name:ind name:Nat
I find this one
Nat.dec_induct: ?i ≤ ?j ⟹ ?P ?i ⟹ (⋀n. ?i ≤ n ⟹ n < ?j ⟹ ?P n ⟹ ?P (Suc n)) ⟹ ?P ?j
From now on it is simple equational reasoning, and I was able to follow the proof in this math stackexchange answer step by step:
lemma
assumes "k≥10"
shows "2^(k::nat) > (k::nat)^3"
using assms
proof(induction rule: Nat.dec_induct)
case base show ?case by simp
next
case (step n)
note power2_eq_square[simp] power3_eq_cube[simp] ring_distribs[simp]
have "Suc n ^ 3 = 1 + 3*n + 3*n^2 + n^3" by simp
also have "… < 51*n + 3*n + 3*n^2 + n^3" using `n ≥ 10` by simp
also have "… = 54*n + 3*n^2 + n^3" by simp
also have "… < 6*n^2 + 3*n^2 + n^3" using `n ≥ 10` by simp
also have "… = 9*n^2 + n^3" by simp
also have "… < n^3 + n^3" using `n ≥ 10` by simp
also have "… = 2 * n^3" by simp
also have "… < 2 * 2^n" using `n ^ 3 < 2 ^ n` by simp
also have "… = 2^(Suc n)" by simp
finally show ?case.
qed
For algebraic proofs, the trick is to exactly identify the simplification steps and then find_theorems to search the relevant rules. Algebraic simp set doesn't contain aggressive simplifaction rules, probably because oversimplification might leave the goals unprovable. (Someone can add more reasons)
In this particular case, you have to assume 10 ≤ k for induction hypothesis to work. You can easily do that by case_tac "10 ≤ k", and then rewriting by monoid_mult_class.power3_eq_cube and le_Suc_ex. For ¬ 10 ≤ k, you can prove the goal using not_less_eq_eq.
I have a function called feedback which calculates the power of 3 (i.e)
feedback(t) = 3^t
primrec feedback :: "nat ⇒ nat" where
"feedback 0 = Suc(0)"|
"feedback (Suc t) = (feedback t)*3"
I want to prove that
if t > 5 then feedback(t) > 200
using Induction
lemma th2: "¬(t>5) ∨ ((feedback t) > 200)" (is "?H(t)" is "?P(t)∨?Q(t)" is "(?P(t))∨(?F(t) > 200)")
proof(induct t)
case 0 show "?P 0 ∨ ?Q 0" by simp
next
assume a:" ?F(t) > 200"
assume d: "?P(t) = False"
have b: "?F (Suc(t)) ≥ ?F(t)" by simp
from b and a have c: "?F(Suc(t)) > 200" by simp
from c have e: "?Q(Suc(t))" by simp
from d have f:"?P(Suc(t)) = False" by simp
from f and e have g: "?P(Suc(t))∨?Q(Suc(t))" by simp
from a and d and g have h: "?P(t)∨?Q(t) ⟹ ?P(Suc(t))∨?Q(Suc(t))" by simp
from a and d have "?H(Suc(t))" by simp
qed
First I prove that
feedback(t+1) >= feedback(t)
then assume feedback(t) > 200, so feedback(t+1)>200
Assume t>5
this implies (t+1) > 5
Also ~((t+1)>5) V (feedback (t+1) > 200) is True
Thus if P(t) is true then P(t+1) is true
But this is not working. I have no idea what the problem is
Well, first of all, you cannot simply assume arbitrary things in Isar. Or rather, you can do that, but you won't be able to show your goal after you've done that. The things that Isar allows you to assume are quite rigid; in your case, it's ¬ 5 < t ∨ 200 < feedback t.
I recommend using the case command, which assumes the right things for you. Then you can do a case distinction about that disjunction and then another one about whether t = 5:
lemma th2: "¬(t>5) ∨ ((feedback t) > 200)"
proof (induct t)
case 0
show ?case by simp
next
case (Suc t)
thus ?case
proof
assume "¬t > 5"
moreover have "feedback 6 = 729" by code_simp
-- ‹"simp add: eval_nat_numeral" would also work›
ultimately show ?thesis
by (cases "t = 5") auto
next
assume "feedback t > 200"
thus ?thesis by simp
qed
qed
Or, more compactly:
lemma th2: "¬(t>5) ∨ ((feedback t) > 200)"
proof (induct t)
case (Suc t)
moreover have "feedback 6 = 729" by code_simp
ultimately show ?case by (cases "t = 5") auto
qed simp_all
If your feedback function is actually monotonic, I would recommend proving that first, then the proof becomes a little less tedious.
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.