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
Related
I've been working with Isabelle/HOL for a few months now, but I've been unable to figure out the exact intention of the use of _tac.
Specifically, I'm talking about cases vs case_tac and induct vs indut_tac (although it would be nice to know the meaning of tac in general, since I'm also using other methods such as cut_tac).
I've noticed I can't use cases or induct using apply with ⋀-bound variables, but I can if it's an structured proof. Why?
An example of this:
lemma "¬(∀x. ¬(P x)) ⟹ ∃x. P x"
apply (rule ccontr)
apply (erule notE)
apply (rule allI)
apply (case_tac "P x")
apply (erule notE)
apply (erule exI)
apply assumption
done
On the other hand, another difference I've noticed between induct and induct_tac is that I can use double induction with the latter, but not with the former. Again, I'm clueless why.
Thanks in advance.
*_tac are built-in tactics used in apply-scripts. In particular, case_tac and induct_tac have been basically superseded by the cases and induction proof methods in Isabelle/Isar. As you mentioned, case_tac and induct_tac can handle ⋀-bound variables. However, this is quite fragile, since their names are often generated automatically and may change when Isabelle changes (of course, you could use rename_tac to choose fixed names). That's one of the reasons why nowadays structured proof methods are preferred to unstructured tactic scripts. Now, back to your example: In order to be able to use cases, you can introduce a structured block as follows:
lemma "¬(∀x. ¬(P x)) ⟹ ∃x. P x"
apply (rule ccontr)
apply (erule notE)
proof (intro allI)
fix x
assume "∄x. P x"
then show "¬ P x"
apply (cases "P x")
apply (erule notE)
apply (erule exI)
apply assumption
done
qed
As you can see, structured proofs are typically verbose but much more readable than linear apply-scripts.
If you're still curious about the "double-induction" issue, an example would be very welcome. Finally, if you want to learn more about structured proofs using the Isabelle/Isar language environment, I'd strongly suggest you read this tutorial on Isabelle/HOL and The Isabelle/Isar Reference Manual for more detailed information.
Frequently, when proving a statement in "prove" mode, I find myself in need of some intermediate statements that are not yet stated nor proved. To state them, I usually make use of the subgoal command, followed by proof- to change to "state" mode. In the process, however, all of the local assumptions are removed. A typical example could look like this
lemma "0 < n ⟷ ((2::nat)^n < 3^n)"
apply(auto)
subgoal
proof-
have "0<n" sorry (* here I would like to refer to the assumption from the subgoal *)
then show ?thesis sorry
qed
subgoal sorry
done
I am aware that I could state the assumptions using assume explicitly. However, this becomes quickly rather tedious when multiple assumptions are involved. Is there an easier way to simply refer to all of the assumptions? Alternatively, is there a good way to implement statements with short proofs directly in "prove" mode?
There is the syntax subgoal premises prems to bind the premises of the subgoal to the name prems (or any other name – but prems is a sensible default):
lemma "0 < n ⟷ ((2::nat)^n < 3^n)"
apply(auto)
subgoal premises prems
proof -
thm prems
There is also a method called goal_cases that automatically gives names to all the current subgoals – I find it very useful. If subgoal premises did not exist, you could do this instead:
lemma "0 < n ⟷ ((2::nat)^n < 3^n)"
apply(auto)
subgoal
proof goal_cases
case 1
By the way, looking at your example, it is considered a bad idea to do anything after auto that depends on the exact form of the proof state, such as metis calls or Isar proofs. auto is fairly brutal and might behave differently in the next Isabelle release so that such proofs break. I recommend doing a nice structured Isar proof here.
Also note that your theorem is a direct consequence of power_strict_mono and power_less_imp_less_base and can be proven in a single line:
lemma "0 < n ⟷ ((2::nat)^n < 3^n)"
by (auto intro: Nat.gr0I power_strict_mono)`
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.
I have another theorem that I am not being able to prove in Isabelle, involving identity and transitive closure.
It is the following:
lemma "r ⊆ Id ⟹ r^* = Id"
Update: Using apply-style I have the following:
lemma "r ⊆ Id ⟹r^* = Id"
apply (rule equalityI)
apply (rule subrelI)
apply (erule rtrancl_induct)
apply (blast+)
done
How can the same be done in Isar?
It seems that your question is more about transforming apply-style proofs into proper Isar. For the specific example you have this can be done as follows. As you mentioned yourself in
lemma "r ⊆ Id ⟹ r^* = Id"
there are difficulties to refer to the assumption r ⊆ Id. The canonical Isar way of structuring this proof is as follows. We start a proof via
proof -
where the - indicates that no initial rule should be used. This just serves the purpose to be able to state assumptions explicitly.
assume *: "r ⊆ Id"
show "r^* = Id"
In addition we give the name * to the assumption. Alternatively we could have stated the whole lemma differently as
lemma
assumes *: "r ⊆ Id"
shows "r^* = Id"
which saves one level of nesting. Anyway, having this, as you said, equality of sets is again canonical, namely:
proof
show "r^* ⊆ Id"
proof (rule subrelI)
fix x y
assume "(x, y) ∈ r^*"
then show "(x, y) ∈ Id"
using * by (induct) blast+
The above line is where we use the assumption (alternatively, we could refer to the assumption literally via ‹r ⊆ Id› or via the implicit name assms that is introduced for the facts following assumes). And we finish by:
qed
next
show "Id ⊆ r^*" by blast
qed
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 *)