Isabelle - Nitpick counterexample usage - isabelle

I would like to complete this proof.
How can I easily/elegantly use the values found by nitpick? (What to write at the ... part?)
Alternatively, how can I use the fact that nitpick found a counterexample to finish the proof?
lemma Nitpick_test: "¬(((a+b) = 5) ∧ ((a-b) = (1::int)))" (is "?P")
proof (rule ccontr)
assume "¬ ?P"
nitpick
(* Nitpicking formula...
Nitpick found a counterexample:
Free variables:
a = 3
b = 2
*)
show "False" by ...
qed

The theorem does not hold as stated, because if a = 3 and b = 2, the statement evaluates to False. For other values of a and b, however, the statement does hold. Thus, as a and b are implicitly universally quantified, you cannot prove the theorem as stated.
If you want to instead prove
theorem "EX a b. a + b = 5 & a - b = (1 :: int)"
you can use rule exI[where x="..."] to provide the witness ... for the existential quantifier, so 3 and 2 in this case.

Related

Why is this seemingly incorrect proof OK with Isabelle?

While copying the following proof from the PDF tutorial of Isabelle 2020 into the IDE (about Cantor’s theorem that a function from a set to its powerset cannot be surjective), I made a typo on the "from 1 have 2" line.
lemma "¬ surj (f :: 'a ⇒ 'a set)"
proof
assume 0: "surj f"
from 0 have 1: "∀ A. ∃ a. A = f a" by(simp add: surj_def )
from 1 have 2: "∃ a. {x. x ∉ f x} = f a" by blast
from 2 show "False" by blast
qed
, so that the line now reads (with a wrong forall quantifier)
from 1 have 2: "∀ a. {x. x ∉ f x} = f a" by blast
Strangely, both the original proof in the example and this changed version work. But the changed version is incorrect, isn't it?
Am I missing something or can someone explain how the changed version (below) is correct?
lemma "¬ surj (f :: 'a ⇒ 'a set)"
proof
assume 0: "surj f"
from 0 have 1: "∀ A. ∃ a. A = f a" by(simp add: surj_def )
from 1 have 2: "∀ a. {x. x ∉ f x} = f a" by blast
from 2 show "False" by blast
qed
--- Update ---
To help diagnose the problem, below is the output when I place the mouse on the "from 2 show ..." line. It mentions an exported rule, which seems to be the theorem to be proven. (I don't remember exporting the rule myself, other than maybe accidentally getting the quantifier right in a few trials.)
show False
Successful attempt to solve goal by exported rule:
(surj f) ⟹ False
proof (state)
this:
False
goal:
No subgoals!
I just tried closing Isabelle and reopening the same .thy file, and got the same result. (As you can see, I am new to the Isabelle environment). Did I just save the theorem somewhere when I entered the right text?
Which Isabelle version are you using? On mine the blast call does not terminate (within a few seconds), as highlighted by the background:
However, Isabelle is optimistic: it assumes that blast will eventually terminate (it won't). Hence the next step is checked (and that one holds because types are not empty: "∀ a. P a", then "∃ a. P a"). That might give you the impression that the proof is going through, but it is not the case.

Eisbach term parameters and subgoal_tac

I'm currently trying to get into Eisbach.
How can I achieve that in the subgoal_tac (see below) the value
of the parameter A is used, and that A is not interpreted as some variable name? Is there some general way to do this or would this need special tailoring of the subgoal_tac tactic?
theory Scratch (* Isabelle2019 *)
imports
Main
"HOL-Eisbach.Eisbach"
begin
method test for A :: nat =
subgoal_tac "A = 5"
lemma "True"
apply (test 1)
(*
proof (prove)
goal (2 subgoals):
1. A = 5 ⟹ True
2. A = 5
*)
(* The A has a yellow background in the output pane*)
oops
end
I don't know why it does not work with subgoal_tac. I think I read somewhere that all methods ending with _tac are kind of deprecated now.
As a workaround you could use a Lemma:
method test for A :: nat =
(rule meta_mp[where P="A = 5"])
lemma "True"
apply (test 1)
(*
goal (2 subgoals):
1. 1 = 5 ⟹ True
2. 1 = 5
*)

Proving the cardinality of a more involved set

Supposing I have a set involving three conjunctions {k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2}.
How can I prove in Isabelle that the cardinality of this set is 1 ? (Namely only k=6 has gcd 3 6 = 2.) I.e., how can I prove lemma a_set : "card {k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2} = 1" ?
Using sledgehammer (or try) again doesn't yield results - I find it very difficult to find what exactly I need to give the proof methods to make them able to to the proof. (Even removing, e.g. gcd 3 k = 2, doesn't make it amenable to auto or sledgehammer.)
Your proposition is incorrect. The set you described is actually empty, as gcd 3 6 = 3. Sledgehammer can prove that the cardinality is zero without problems, although the resulting proof is again a bit ugly, as is often the case with Sledgehammer proofs:
lemma "card {k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2} = 0"
by (metis (mono_tags, lifting) card.empty coprime_Suc_nat
empty_Collect_eq eval_nat_numeral(3) gcd_nat.left_idem
numeral_One numeral_eq_iff semiring_norm(85))
Let's do it by hand, just to illustrate how to do it. These sorts of proofs do tend to get a little ugly, especially when you don't know the system well.
lemma "{k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2} = {}"
proof safe
fix x :: nat
assume "x > 2" "x ≤ 7" "gcd 3 x = 2"
from ‹x > 2› and ‹x ≤ 7› have "x = 3 ∨ x = 4 ∨ x = 5 ∨ x = 6 ∨ x = 7" by auto
with ‹gcd 3 x = 2› show "x ∈ {}" by (auto simp: gcd_non_0_nat)
qed
Another, much simpler way (but also perhaps more dubious one) would be to use eval. This uses the code generator as an oracle, i.e. it compiles the expression to ML code, compiles it, runs it, looks if the result is True, and then accepts this as a theorem without going through the Isabelle kernel like for normal proofs. One should think twice before using this, in my opinion, but for toy examples, it is perfectly all right:
lemma "card {k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2} = 0"
proof -
have "{k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2} = Set.filter (λk. gcd 3 k = 2) {2<..7}"
by (simp add: Set.filter_def)
also have "card … = 0" by eval
finally show ?thesis .
qed
Note that I had to massage the set a bit first (use Set.filter instead of the set comprehension) in order for eval to accept it. (Code generation can be a bit tricky)
UPDATE:
For the other statement from the comments, the proof has to look like this:
lemma "{k::nat. 0<k ∧ k ≤ 5 ∧ gcd 5 k = 1} = {1,2,3,4}"
proof (intro equalityI subsetI)
fix x :: nat
assume x: "x ∈ {k. 0 < k ∧ k ≤ 5 ∧ coprime 5 k}"
from x have "x = 1 ∨ x = 2 ∨ x = 3 ∨ x = 4 ∨ x = 5" by auto
with x show "x ∈ {1,2,3,4}" by (auto simp: gcd_non_0_nat)
qed (auto simp: gcd_non_0_nat)
The reason why this looks so different is because the right-hand side of the goal is no longer simply {}, so safe behaves differently and generates a pretty complicated mess of subgoals (just look at the proof state after the proof safe). With intro equalityI subsetI, we essentially just say that we want to prove that A = B by proving a ∈ A ⟹ a ∈ B and the other way round for arbitrary a. This is probably more robust than safe.

Ignoring a case to prove a goal through elimination

I have the following lemma to show the derivative of f at x is D.
lemma lm1:
assumes "(∀h. (f (x + h) - f x) = D*h)"
shows "DERIV f x :> D"
proof cases
assume notzero: "∀h. h ≠ 0"
have cs1: "(λh. (f (x + h) - f x) / h) -- 0 --> D" using assms notzero by auto
from this DERIV_def show ?thesis by auto
From the assumptions, I can easily prove the lemma by taking the limit then using DERIV_def. For this I have to assume that h ≠ 0. Continuing with the proof by cases I have to show that even when h = 0, the goal is true, however this can't be done when h = 0 as the assumption becomes 0 = 0. The lemma becomes trivial.
Is there a way I can prove the goal, which is this case is that f has derivative D at x, without the additional assumption that h ≠ 0?
edit: After further research, I came across the use of elimination rules in Isabelle which may be helpful. Also, I understand that the lemma is correct as the if the function is continuous, then the derivative at 0 also exists.
I have been searching for the correct use and implementation of the the above information. How can I improve my search, and where should I be looking?

Expressing a simple declarative proof about exponents in Isar

I'm attempting to write a simple proof about integer exponents in isar.
I've written the argument I want to make in the commented area, but I'm having a very hard time figuring out how to express it. I've been studying src/HOL/Int.thy but I either can't find an example proof along these lines or don't understand what I'm looking at yet. :)
theory Exponents
imports Main
begin
lemma rMulComm: "(a*b ::int) = (b*a ::int)"
by (rule Groups.ab_semigroup_mult_class.mult.commute)
lemma rExpMul: "((a^b)^c ::int) = (a^(b*c) ::int)"
by (rule Int.zpower_zpower)
theorem HELP: "((a^b)^c ::int) = ((a^c)^b :: int)"
(* 0. (a^b)^c
1. a^(b*c) by rExpMul
2. a^(c*b) by rMulComm
3. (a^c)^b by rExpMul *)
end
This isn't a homework assignment, btw. I'm not in school. :)
update: my final version, based on Alexander's answer, below:
theorem "((a^b)^c ::int) = ((a^c)^b :: int)"
proof -
have "(a^b)^c = a^(b*c)" by (simp only: rExpMul)
hence " ... = a^(c*b)" by (simp only: rMulComm)
thus "(a^b)^c = (a^c)^b" by (simp only: rExpMul)
qed
The issue has to do with the types of b and c in the theorem HELP as well as in the lemma rExpMul: the exponent for the operator ^ is a natural number. Therefore rMulComm specified for integers cannot be used to prove the theorem. After restating it for natural numbers
lemma rMulComm: "(a * b :: nat) = (b * a :: nat)"
the proof proceeds immediately:
theorem HELP: "((a^b)^c ::int) = ((a^c)^b :: int)"
proof -
have "(a ^ b) ^ c = a ^ (b * c)" by (simp only: rExpMul)
also have "… = a ^ (c * b)" by (simp only: rMulComm)
finally show ?thesis by (simp only: rExpMul)
qed
and can be shortened to just by (simp only: rExpMul rMulComm).

Resources