Isabelle : proof using metis causes infinite loop - infinite-loop

I want to prove Lemma 1 and 2 and Lemma 21 is one of the subgoals for Lemma 2. However while proving Lemma 2 it hangs at apply (metis step) and I believe there's no other way to prove it. Are there any ways to stop this infinite loop from occuring? Thanks in advance.
inductive star :: "('a ⇒ 'a ⇒ bool) ⇒ 'a ⇒ 'a ⇒ bool" for r where
refl: "star r x x"|
step: "r x y ⟹star r y z⟹star r x z"
inductive star' ::"('a ⇒ 'a ⇒ bool) ⇒ 'a ⇒ 'a ⇒ bool"for r where
refl' : "star' r x x" |
step' : "star' r x y ⟹ r y z ⟹ star' r x z"
lemma 21 : "r x y ⟹
star r y z ⟹
star' r y z ⟹
star' r x z"
apply (metis step)
lemma 1 : "star' r x y ⟹ star r x y"
apply (induction rule : star'.induct)
apply (metis refl)
done
lemma 2 : "star r x y ⟹ star' r x y"
apply (induction rule: star.induct)
apply (metis refl')
done

I believe that you are referring to an exercise from [0]. I will refrain from posting a complete answer out of fear that this is a homework problem. However, I will give a tip. There is a redundant assumption in lemma 21. Once you remove this assumption, the lemma becomes easier to prove (as stated, using an apply-style script, and very standard textbook techniques). However, most likely, metis alone will not be enough.
If the worst comes to worst, you may also get an idea about how to prove this from the theory Transitive_Closure.thy in Main. However, I would like to emphasize that the proof is very simple, so this should not be necessary.
[0] Nipkow T, Klein G. Concrete Semantics with Isabelle/HOL. Heidelberg: Springer-Verlag; 2017.

Related

Generalize a claim in a structural induction proof to be able to use the induction hypothesis

I want to prove the following
lemma
fixes pi :: "'a path" and T :: "'a ts"
shows "valid_path T pi s ⟹ ∀ op ∈ set pi. valid_operator T op"
by induction on pi where
fun valid_path :: "'a ts ⇒ 'a path ⇒ 'a state ⇒ bool" where
"valid_path T [] s = True" |
"valid_path T (op#ops) s = (valid_operator T op ∧ valid_path T ops (effect op s))
and path is just a type synonym for an operator list.
The other definitions should not play a role for the proof.
The base case works fine.
The problem is that, informally, for the inductive step where pi = (x # xs) I'm assuming that
if valid_path T xs s
then ∀ op ∈ set xs. valid_operator T op
and I must show that this implies
if valid_path T (x#xs) s
then ∀ op ∈ set (x#xs). valid_operator T op
I can use the definition of valid_path here, so this last expression is equivalent to
if valid_path T (xs) (effect x s)
then ∀ op ∈ set (x#xs). valid_operator T op
If I could be able to use the induction hypothesis on valid_path T (xs) (effect x s) I would be done.
I can't since the hypothesis only holds for valid_path T (xs) s instead of valid_path T xs (effect x s).
But this does not really matter since the predicate of that if statement does not depend on s at all!
But Isabelle does not know that so it complains.
How can I make it such that I can apply the inductive hypothesis on valid_path T (xs) (effect x s)?
I have a feeling that I have to make the claim more general, so that I can use the hypothesis on the proof, but I don't know how.
It is very common that you have to generalize some terms in an induction. Use the keyword arbitrary in the induct method.
proof (induct pi arbitrary: s)
This is explained in Chapter 2.4 of Programming and Proving in Isabelle/HOL.

Proving existence in Isabelle/HOL in this example

I'm trying to learn how to use Isabelle/Isar with HOL, and I decided a good way to do that would be to develop some elementary number theory. I defined my own plus and times operations so that proof methods wouldn't be doing all the work for me as there's already plenty proved about +, * in Main. My versions are defined as:
fun p:: "nat ⇒ nat ⇒ nat" (infix "⊕" 80) where
p_0: "0 ⊕ n =n" |
p_rec: " (Suc m) ⊕ n = Suc (m ⊕ n)"
fun t:: "nat ⇒ nat ⇒ nat" (infix "⊗" 90) where
t_0: "0 ⊗ n= 0" |
t_rec: "Suc m ⊗ n = n + m ⊗ n"
and I've already shown that multiplication and addition are commutative the distributive law holds. Then I tried to show the following:
lemma euclidean_division_existence: "∃q r. n=q⊗m⊕r"
proof (induction n)
case 0
have "0= 0 ⊗ m" by auto
hence "∃q. 0 =q ⊗ m" by auto
but it's telling me it can't finish the proof of the last step. I've tried various things, but I can't figure out how to tell Isabelle I just gave it a witness for the existence statement I'm trying to prove. How can I make Isabelle recognize that?
Edit:
xanonec helped me get past this step, but I immediately got stuck on the next step by a seemingly similar problem. Ultimately I want to show:
"∃ q r. 0 = q ⊗ m⊕r"
but I can't figure out how to simultaneously introduce the two existentially quantified variable from
"0 = 0 ⊗ m ⊕ 0"
A suitable strategy for the solution could be a direct rule application (in jEdit you can cntrl+LMB or cmd+LMB on exI to navigate to its statement):
lemma euclidean_division_existence: "∃q r. n=q⊗m⊕r"
proof(induction n)
case 0
have "0 = 0 ⊗ m" by auto
hence "∃q. 0 = q ⊗ m" by (rule exI)
qed
More generally, in many similar cases sledgehammer can find a suitable (but, often, suboptimal) proof. A tutorial on the use of sledgehammer is a part of the official documentation of Isabelle. Also, I would like to suggest the following resources: "Concrete Semantics with Isabelle/HOL" by Tobias Nipkow and Gerwin Klein and "A Proof Assistant for Higher-Order Logic" by Tobias Nipkow et al.
An update following an amendment made to the statement of the question
The following listing presents a proof that relies only on the most basic methods and direct rule application:
lemma euclidean_division_existence: "∃q r. n=q⊗m⊕r"
proof (induction n)
case 0 show ?case
proof-
have "0 = 0 ⊗ m ⊕ 0" by simp
then have "∃r. 0 = 0 ⊗ m ⊕ r" by (rule exI)
then show "∃q r. 0 = q ⊗ m ⊕ r" by (rule exI)
qed
case (Suc n) show ?case sorry
qed
However, if you can afford to rely more on proof automation, then you can use metis to prove the entire theorem:
lemma euclidean_division_existence: "∃q r. n=q⊗m⊕r" by (metis p_0 t_0)

Negation of set membership, equality

I noticed that Isabelle automatically simplifies ¬ (a ∈ (- A)) and ¬ (x = y) to a ∉ A and x ≠ y, respectively.
Here is a simple pen-and-paper proof in natural deduction but fails in Isabelle. In the 2nd line, ¬ (a ∈ (- A)) is simplified to a ∉ - A. From the latter, we cannot apply ComplD, but why?
lemma "- (- A) ⊆ (A::'a set)"
proof
fix a assume "a ∈ - (- A)"
hence "¬ (a ∈ (- A))" by (rule ComplD)
hence "¬ (¬ (a ∈ A))" by (rule ComplD) (* fail! *)
thus "a ∈ A" by (rule notnotD)
qed
Is there a way to go back to the non-simplified expression?
Of course, the lemma can be proved in one line by simp. But my purpose is to explicitly use natural deduction rules (for teaching).
These are not simplifications. If you look at the definitions of a ≠ b and x ∉ A in Isabelle (e.g. by ctrl-clicking on the symbols), you will find that they are simply abbreviations for ¬(a = b) and ¬(x ∈ A). The statements are internally represented exactly the way you wrote them above, they are just printed differently for increased readability.
The reason why you cannot apply the rule ComplD is that it simply does not match. ComplD says that ?c ∈ - ?A ⟹ ?c ∉ ?A. However, in the failing step, your assumption is a ∉ -A, and that cannot be unified to the premise ?c ∈ -?A of ComplD, and therefore rule fails.
I am relatively certain that you will need classical reasoning for this proof since your statement does not hold intuitionistically. This means you will have to do a proof by contradiction, e.g. like this:
lemma "- (- A) ⊆ (A::'a set)"
proof
fix a assume a: "a ∈ - (- A)"
show "a ∈ A"
proof (rule ccontr)
assume "a ∉ A"
have "a ∈ -A"
proof (rule ComplI)
assume "a ∈ A"
with ‹a ∉ A› show False by contradiction
qed
moreover from a have "a ∉ -A" by (rule ComplD)
ultimately show False by contradiction
qed
qed
The rule ccontr in there starts the proof by contradiction; the proof method contradiction is merely a nice way to derive anything when one has proven a fact and its negation.

How to fix "Illegal schematic variable(s)" in mutually recursive rule induction?

In Isabelle, I'm trying to do rule induction on mutually recursive inductive definitions. Here's the simplest example I was able to create:
theory complex_exprs
imports Main
begin
datatype A = NumA int
| AB B
and B = NumB int
| BA A
inductive eval_a :: "A ⇒ int ⇒ bool" and eval_b :: "B ⇒ int ⇒ bool" where
eval_num_a: "eval_a (NumA i) i" |
eval_a_b: "eval_b b i ⟹ eval_a (AB b) i" |
eval_num_b: "eval_b (NumB i) i" |
eval_b_a: "eval_a a i ⟹ eval_b (BA a) i"
lemma foo:
assumes "eval_a a result"
shows "True"
using assms
proof (induction a)
case (NumA x)
show ?case by auto
case (AB x)
At this point, Isabelle stops with 'Illegal schematic variable(s) in case "AB"'. Indeed the current goal is ⋀x. ?P2.2 x ⟹ eval_a (AB x) result ⟹ True which contains the assumption ?P2.2 x. Is that the 'schematic variable' Isabelle is talking about? Where does it come from, and how can I get rid of it?
I get the same problem if I try to do the induction on the rules:
proof (induction)
case (eval_num_a i)
show ?case by auto
case (eval_a_b b i)
Again, the goal is ⋀b i. eval_b b i ⟹ ?P2.0 b i ⟹ True with the unknown ?P2.0 b i, and I can't continue.
As a related question: I tried to do the induction using
proof (induction rule: eval_a_eval_b.induct)
but Isabelle doesn't accept this, saying 'Failed to apply initial proof method'.
How do I make this induction go through? (In my actual application, I do actually need induction because the goal is more complex than True.)
Proofs about mutually recursive definitions, be they datatypes, functions or inductive predicates, must be mutually recursive themselves. However, in your lemma, you only state the inductive property for eval_a, but not for eval_b. In the case for AB, you obviously want to use the induction hypothesis for eval_b, but as the lemma does not state the inductive property for eval_b, Isabelle does not know what it is. So it leaves it as a schematic variable ?P2.0.
So, you have to state two goals, say
lemma
shows "eval_a a result ==> True"
and "eval_b b result ==> True"
Then, the method induction a b will figure out that the first statement corresponds to A and the second to B.
The induction rule for the inductive predicates fails because this rule eliminates the inductive predicate (induction over datatypes only "eliminates" the type information, but this is not a HOL formula) and it cannot find the assumption for the second inductive predicate.
More examples on induction over mutually recursive objects can be found in src/HOL/Induct/Common_Patterns.thy.

How to prove basic facts about datatypes and codatatypes?

I would like to prove some basic facts about a datatype_new and a codatatype: the first does not have an infinite element, and that the latter does have one.
theory Co
imports BNF
begin
datatype_new natural = Zero | Successor natural
lemma "¬ (∃ x. x = Successor x)"
oops
codatatype conat = CoZero | CoSucc conat
lemma "∃ x. x = CoSucc x"
oops
The problem was that I could not come up with a pen-and-paper proof, let alone a proof script.
An idea for the first was to use the size function, which has a theorem
size (Successor ?natural) = size ?natural + Suc 0
and somehow using that size is a function, applying it to the two sides of the original equation one cannot have a natural number equal to its successor. But I do not see how I could formalise this.
For the latter I did not even have an idea how to derive this theorem from the facts that the codatatype package proves.
How can I prove these?
Personally, I don't know the first thing about codatatypes. But let me try to help you nevertheless.
The first lemma you posted can be proven automatically by sledgehammer. It finds a proof using the size function, effectively reducing the problem on natural to the same problem on nat:
by (metis Scratch.natural.size(2) n_not_Suc_n nat.size(4) size_nat)
If you want a very basic, step-by-step version of this proof, you could write it like this:
lemma "¬(∃x. x = Successor x)"
proof clarify
fix x assume "x = Successor x"
hence "size x = size (Successor x)" by (rule subst) (rule refl)
also have "... = size x + Suc 0" by (rule natural.size)
finally have "0 = Suc 0" by (subst (asm) add_0_iff) (rule sym)
moreover have "0 ≠ Suc 0" by (rule nat.distinct(1))
ultimately show False by contradiction
qed
If you want a more “elementary” proof, without the use of HOL natural numbers, you can do a proof by contradiction using induction on your natural:
lemma "¬(∃x. x = Successor x)"
proof clarify
fix x assume "x = Successor x"
thus False by (induction x) simp_all
qed
You basically get the two cases in the induction:
Zero = Successor Zero ⟹ False
⋀x. (x = Successor x ⟹ False) ⟹
Successor x = Successor (Successor x) ⟹ False
The first subgoal is a direct consequence of natural.distinct(1), the second one can be reduced to the induction hypothesis using natural.inject. Since these rules are in the simpset, simp_all can solve it automatically.
As for the second lemma, the only solution I can think of is to explicitly construct the infinite element using primcorec:
primcorec infinity :: conat where
"infinity = CoSucc infinity"
Then you can prove your second lemma simply by unfolding the definition:
lemma "∃x. x = CoSucc x"
proof
show "infinity = CoSucc infinity" by (rule infinity.ctr)
qed
Caveat: these proofs work, but I am not sure whether they are the easiest and/or most elegant solution to this problem. I have virtually no knowledge of codatatypes or the new datatype package.

Resources