In Isabelle, one occasionally reaches a scenario where there are duplicate subgoals. For example, imagine the following proof script:
lemma "a ∧ a"
apply (rule conjI)
with goals:
proof (prove): step 1
goal (2 subgoals):
1. a
2. a
Is there any way to eliminate the duplicate subgoal in-place, so proofs need not be repeated?
The ML-level tactic distinct_subgoals_tac in Pure/tactic.ML removes duplicate subgoals, and can be used as follows:
lemma "a ∧ a"
apply (rule conjI)
apply (tactic {* distinct_subgoals_tac *})
leaving:
proof (prove): step 2
goal (1 subgoal):
1. a
There does not appear to be a way without dropping into the ML world, unfortunately.
I came across a similar behavior as a side effect of the subst method applied to any theorem, and for example refl. Then apply (subst refl) do indeed remove the duplicate subgoals.
It's not a bug, It's a feature ;-).
Adding to davidg's answer, if one does not want to use tactic for whatever reason, it is easy enough to turn distinct_subgoals_tac into a method:
method_setup distinct_subgoals =
‹Scan.succeed (K (SIMPLE_METHOD distinct_subgoals_tac))›
lemma P and P and P
(* here there are three goals P *)
apply distinct_subgoals
(* now there is only one goal P *)
Related
Is there any way in Isabelle (2021) to refer to assumptions in the old apply style proofs?
In particular, I am interested in using the assumptions as facts in the OF operator so that I can do (hypothetically):
apply(rule R[OF assm1 assm4])
, where assm1 and assm4 should refer to the 1st and 4th assumptions in the current proof state.
Often times, I can arrange assumptions of the current sugboal so that R[OF assm1 assm4] is the same as the subgoal. But then, I can't finish the proof because I don't know how to refer to assm1 assm4 etc. It seems that only global theorem names are allowed with OF.
I even tried to use the subgoal_tac method on the assumptions, but it does not seem to have an option of giving names to the fact.
In the end, I have to use an automatic script such as simp, which is somewhat opaque for something so obvious. By the way, this is for learning purposes. I tried setting up simp_trace, but still couldn't replicate the effect without using simp.
Moreover,
If there is no way to refer to assumptions, is this a limitation of the tactics or a fundamental limitation of natural deduction? (i.e. Is the rewriting style of R[OF assm1 assm4] not compatible with natural deduction?)
The whole point is Isar is that you can name assumptions...
The first low-level solution is to use drule (or frule to keep the assumptions).
Here is an example:
lemma
assumes ‹⋀x y. P x ⟹ Q y ⟹ R z› ‹P x› ‹Q y›
shows ‹R z›
using assms(2-) apply -
apply (drule assms(1))
apply assumption
apply assumption
done
Look at Chapter 5 for details on the destruction/elimination/intro rules.
The second solution is subgoal:
lemma
assumes ‹⋀x y. P x ⟹ Q y ⟹ R z› ‹P x› ‹Q y›
shows ‹R z›
using assms(2-) apply -
subgoal premises p
by (rule assms(1)[OF p])
done
but this creates hard-to-read proofs if you have very deep nesting.
The third and best solution is to use Isar proofs…
Here is a version that completely avoids using names:
lemma
assumes ‹⋀x y. P x ⟹ Q y ⟹ R z› ‹P x› ‹Q y›
shows ‹R z›
using assms apply -
apply (elim meta_allE[of _ x])
apply (elim meta_allE[of _ y])
apply (drule cut_rl)
apply assumption
apply (drule cut_rl)
apply assumption
apply assumption
done
You can see how ugly this is and why you should avoid that.
In my exercise to learn Isabelle/HOL syntax, I tried to prove a toy lemma below. It's about lambda expressions (and things like the "Greatest" notation that takes a predicate as input). The intended content of the lemma is that "the greatest natural number that is l.e. 1 is 1".
lemma "1 = Greatest (λ x::nat. x ≤ 1)"
proof -
show ?thesis
by auto
qed
However, the above proof doesn't work either by auto or simp, and generates a message that.
Failed to finish proof⌂:
goal (1 subgoal):
1. Suc 0 = (GREATEST x. x ≤ Suc 0)
Can someone help explain what went wrong with the statement or how to prove this correctly (if the statement is correct)?
There is nothing wrong with the lemma, it's just that none of the rules for Greatest are declared in such a way that auto knows about them. Which is probably good, because these kinds of rules tend to mess with automation a lot.
You can prove your statement using e.g. the rule Greatest_equality:
lemma "1 = Greatest (λ x::nat. x ≤ 1)"
proof -
have "(GREATEST (x::nat). x ≤ 1) = 1"
by (rule Greatest_equality) auto
thus ?thesis by simp
qed
You can find rules like this using the Query panel in Isabelle/jEdit or the find_theorems command by searching for the constant Greatest.
If the GREATEST thing confuses you, the syntax GREATEST x. P x is just fancy syntax for Greatest (λx. P x). Such notation is fairly standard in Isabelle, we also have ∃x. P x for Ex (λx. P x) etc.
I sometimes find it hard to use Isabelle because I cannot have a "print command" like in normal programming.
For example, I want to see what ?thesis. The concrete semantics book says:
The unknown ?thesis is implicitly matched against any goal stated by lemma or show. Here is a typical example:
My silly sample FOL proof is:
lemma
assumes "(∃ x. ∀ y. x ≤ y)"
shows "(∀x. ∃ y. y ≤ x)"
proof (rule allI)
show ?thesis
but I get the error:
proof (state)
goal (1 subgoal):
1. ⋀x. ∃y. y ≤ x
Failed to refine any pending goal
Local statement fails to refine any pending goal
Failed attempt to solve goal by exported rule:
∀x. ∃y. y ≤ x
but I do know why.
I expected
?thesis === ⋀x. ∃y. y ≤ x
since my proof state is:
proof (state)
goal (1 subgoal):
1. ⋀x. ∃y. y ≤ x
Why can't I print ?thesis?
It's really annoying to have to write the statement I'm trying to proof if it's obvious. Perhaps it's meant to be explicit but in the examples in chapter 5 they get away with using ?thesis in:
lemma fixes a b :: int assumes "b dvd (a+b)" shows "b dvd a" proof −
have "∃k′. a = b∗k′" if asm: "a+b = b∗k" for k proof
show "a = b∗(k − 1)" using asm by(simp add: algebra_simps) qed
then show ?thesis using assms by(auto simp add: dvd_def ) qed
but whenever I try to use ?thesis I always fail.
Why is it?
Note that this does work:
lemma
assumes "(∃ x. ∀ y. x ≤ y)"
shows "(∀x. ∃ y. y ≤ x)"
proof (rule allI)
show "⋀x. ∃y. y ≤ x" proof -
but I thought ?thesis was there to avoid this.
Also, thm ?thesis didn't work either.
Another example is when I use:
let ?ys = take k1 xs
but I can't print ?ys value.
TODO:
why doesn't:
lemma "length(tl xs) = length xs - 1"
thm (cases xs)
show anything? (same if your replaces cases with induction).
You can find ?theorem and others in the print context window:
As for why ?thesis doesn't work, by applying the introduction rule proof (rule allI) you are changing the goal, so it no longer matches ?thesis. The example in the book uses proof- which prevents Isabelle from applying any introduction rule.
It seems I asked a very similar question worth pointing to: What is the best way to search through general definitions, theorems, functions, etc for Isabelle?
But here is a list of thing's I've learned so far:
thm: seems to work for definition, lemmas and functions. For definition do name_def for a definition with name name. For functions do thm f.simps for all definitions in the function. For a single one do thm f.simps(1) for the first one. For lemmas do thm lemma_name or thm impI or HOL.mp etc.
term: for terms do term term_name e.g. in isar term ?thesis or term this
print_theorems: if you place this after a definition or a function it shows all the theorems defined for those! It's amazing.
print... I just noticed in jedit if you let the auto complete show you the rest for print it has a bunch of options! Probably useful!
Search engine for Isabelle: https://search.isabelle.in.tum.de/
You can use Query (TODO: improve this)
TODO: how to find good way to display stuff about tactics.
I plan to update this as I learn all the ways to debug in Isabelle.
Let's assume we have such variant of Modus Ponens
lemma invDed: ‹(A-->B)==>(A==>B)›
apply(rule mp)
apply assumption
apply assumption
done
Can it be applied for proving the theorem? (I mean A:=A, B:=A, and A-->A we use as if it was previously proved)
lemma myid2: "A==>A"
If not, why? I know several other ways to prove this theorem("apply assumption" or 5-step proof from Frege's propositional calculus axioms.), but I interested in this nuance of proof mechanics.
i have one rule, now I want obtain an another [admissible] rule, what's problem?
Application with rule only applies to the formula after the rightmost meta implication (==>). So you would get something like the following, which is not very helpful:
lemma myid2: "A==>A"
proof (rule invDed[where A=A and B=A])
show "A ⟹ A ⟶ A"
by (rule imp_refl)
show "A ⟹ A"
by assumption
qed
If you rotate your premises (done below with the [rotated] modifier) to have A==>(A-->B)==>(B), then you can apply it with erule:
lemma myid2: "A==>A"
apply (erule invDed[rotated])
apply (rule imp_refl)
done
I have been playing around with basic examples of proofs in Isabelle.
Consider the following simple proof:
lemma
fixes n::nat
shows "n*(n+1) = n^2 + n"
by simp
It seems to me that a powerful proof assistant like Isabelle should be able to prove this lemma without much guidance.
However, I was surprised to find out that Isabelle actually fails at applying the rule simp here (I also tried other "generic" rules like simp_all, auto, force, blast but the result is the same).
If I replace the last line by the following, then it works out:
by (simp add: power2_eq_square)
My concern is that I feel like I shouldn't have had to tell the system about the specific rule power2_eq_square to complete this proof.
Playing around with similar trivial examples, I found that simp is able to prove
n*(n+2)=n*n+n*2
but fails with
n*(n+3)=n*n+n*3
The last example is proven
by (simp add: distrib_left)
It is a complete mystery to me why I need to specify distrib_left in that second example, but not in the first (why is that?).
I have given these examples not for their own sake, but mainly to illustrate my main question:
Is there a way to automate the verification of routine algebraic identities such as the above in Isabelle? If there isn't, then why not? What are the technical obstacles?
Daily proof work indeed often stumbles over »routine algebraic identities«; but after some practical experience one usually develops some intuition how to solve such problems effectively. A pattern I have developed over the years, by example:
context semidom
begin
lemma "a * (b ^ 2 + c) + 2 = a * b * b + c * a + 2"
A typical explorative proof starts with
apply auto
Then associativity and commutative are considered also
apply (auto simp add: ac_simps)
Then more algebaic normalizing rules are applied
apply (auto simp add: algebra_simps)
The last gap is then easily filled by sledgehammer
apply (simp add: power2_eq_square)
After that, the proof can be compactified
by (simp add: algebra_simps power2_eq_square)
The lemma
lemma power2_eq_square: "a^2 = a * a"
is not a good rewrite rule in general, as it will easily blow up the size of terms. So it is expected that a term rewriting based automation like simp will not apply this without you telling it to.
What you want is some sort of proof search, and Isabelle provides that: After writing your lemma, you can invoke the sledgehammer tool, and it will readily and quickly find the proof for you:
Sledgehammering...
Proof found...
"z3": Try this: by (simp add: power2_eq_square) (1 ms)
"cvc4": Try this: by (simp add: power2_eq_square) (5 ms)