I'm an Isabelle newbie, and I'm a little (actually, a lot) confused about the relationship between ⋀ and ∀, and between ⟹ and ⟶.
I have the following goal (which is a highly simplified version of something that I've ended up with in a real proof):
⟦⋀x. P x ⟹ P z; P y⟧ ⟹ P z
which I want to prove by specialising x with y to get ⟦P y ⟹ P z; P y⟧ ⟹ P z, and then using modus ponens. This works for proving the very similar-looking:
⟦∀x. P x ⟶ P z; P y⟧ ⟹ P z
but I can't get it to work for the goal above.
Is there a way of converting the former goal into the latter? If not, is this because they are logically different statements, in which case can someone help me understand the difference?
That the two premises !!x. P x ==> P y and ALL x. P x --> P y are logically equivalent can be shown by the following proof
lemma
"(⋀x. P x ⟹ P y) ≡ (Trueprop (∀x. P x ⟶ P y))"
by (simp add: atomize_imp atomize_all)
When I tried the same kind of reasoning for your example proof I ran into a problem however. I intended to do the following proof
lemma
"⟦⋀x. P x ⟹ P z; P y⟧ ⟹ P z"
apply (subst (asm) atomize_imp)
apply (unfold atomize_all)
apply (drule spec [of _ y])
apply (erule rev_mp)
apply assumption
done
but at unfold atomize_all I get
Failed to apply proof method:
When trying to explicitly instantiate the lemma I get a more clear error message, i.e.,
apply (unfold atomize_all [of "λx. P x ⟶ P z"])
yields
Type unification failed: Variable 'a::{} not of sort type
This I find strange, since as far as I know every type variable should be of sort type. We can solve this issue by adding an explicit sort constraint:
lemma
"⟦⋀x::_::type. P x ⟹ P z; P y⟧ ⟹ P z"
Then the proof works as shown above.
Cutting a long story short. I usually work with Isar structured proofs instead of apply scripts. Then such issues are often avoided. For your statement I would actually do
lemma
"⟦⋀x. P x ⟹ P z; P y⟧ ⟹ P z"
proof -
assume *: "⋀x. P x ⟹ P z"
and **: "P y"
from * [OF **] show ?thesis .
qed
Or maybe more idiomatic
lemma
assumes *: "⋀x. P x ⟹ P z"
and **: "P y"
shows "P z"
using * [OF **] .
C.Sternagel answered your title question "How?", which satisfied your last sentence, but I go ahead and fill in some details based on his answer, to try to "help [you] understand the difference".
It can be confusing that there is ==> and -->, meta-implication and HOL-implication, and that they both have the properties of logical implication. (I don't say much about !! and !, meta-all and HOL-all, because what's said about ==> and --> can be mostly be transferred to them.)
(NOTE: I convert graphical characters to equivalent ASCII when I can, to make sure they display correctly in all browsers.)
First, I give some references:
[1] Isabelle/Isar Reference manual.
[2] HOL/HOL.thy
[3] Logic in Computer Science, by Huth and Ryan
[4] Wiki sequent entry.
[5] Wiki intuitionistic logic entry.
If you understand a few basics, there's nothing that confusing about the fact that there is both ==> and -->. Much of the confusion departs, and what's left is just the work of digging through the details about what particular source statements mean, such as the formula of C.Sternagel's first lemma.
"(!!x. P x ==> P y) == (Trueprop (!x. P x --> P y))"
C.Sternagel stopped taking the time to give me important answers, but the formula he gives you above is similar to one he gave me a while ago, to convince me that all free variables in a formula are universally quantified.
Short answer: The difference between ==> and --> is that ==> (somewhat) plays the part of the turnstile symbol, |-, of a non-generalized sequent in which there is only one conclusion on the right-hand side. That is, ==>, the meta-logic implication operator of Isabelle/Pure, is used to define the Isabelle/HOL implication object-logic operator -->, as shown by impI in the following axiomatization in HOL.thy [2].
(*line 56*)
typedecl bool
judgment
Trueprop :: "bool => prop"
(*line 166*)
axiomatization where
impI: "(P ==> Q) ==> P-->Q" and
mp: "[| P-->Q; P |] ==> Q" and
iff: "(P-->Q) --> (Q-->P) --> (P=Q)" and
True_or_False: "(P=True) | (P=False)"
Above, I show the definition of three other axioms: mp (modus ponuns), iff, and True_or_False (law of excluded middle). I do that to repeatedly show how ==> is used to define the axioms and operators of the HOL logic. I also threw in the judgement to show that some of the sequent vocabulary is used in the language Isar.
I also show the axiom True_or_False to show that the Isabelle/HOL logic has an axiom which Isabelle/Pure doesn't have, the law of excluded middle [5]. This is huge in answering your question "what is the difference?"
It was a recent answer by A.Lochbihler that finally gave meaning, for me, to "intuitionistic" [5]. I had repeatedly seen "intuitionistic" in the Isabelle literature, but it didn't sink in.
If you can understand the differences in the next source, then you can see that there's a big difference between ==> and -->, and between types prop and bool, where prop is the type of meta-logic propositions, as opposed to bool, which is the type of the HOL logic proposition. In the HOL object-logic, False implies any proposition Q::bool. However, False::bool doesn't imply any proposition Q::prop.
The type prop is a big part of the meta-logic team !!, ==>, and ==.
theorem "(!!P. P::bool) == Trueprop (False::bool)"
by(rule equal_intr_rule, auto)
theorem HOL_False_meta_implies_any_prop_Q:
"(!!P. P::bool) ==> PROP Q"
(*Currently, trying by(auto) will hang my machine due to blast, which is know
to be a problem, and supposedly is fixed in the current repository. With
`Auto methods` on in the options, it tries `auto`, thus it will hang it.*)
oops
theorem HOL_False_meta_implies_any_bool_Q:
"(!!P. P::bool) ==> Q::bool"
by(rule meta_allE)
theorem HOL_False_obj_implies_any_bool_Q:
"(!P. P::bool) --> Q::bool"
by(auto)
When you understand that Isabelle/Pure meta-logic ==> is used to define the HOL logic, and other differences, such as that the meta-logic is weaker because of no excluded middle, then you understand that there are significant differences between the meta-operators, !!, ==>, and ==, in comparison to the HOL object-logic operators, !, -->, and =.
From here, I put in more details, partly to convince any expert that I'm not totally abusing the word sequent, where my use here is based primarily on how it's used in reference [3, Huth and Ryan].
Attempting to not write a book
I throw in some quotes and references to show that there's a relationship between sequents and ==>.
From my research, I can't see that the word "sequent" is standardized. As far as I can tell, in [3.pg 5], Huth and Ryan use "sequent" to mean a sequent which has only has one conclusion on the right-hand side.
...This intention we denote by
phi1, phi2, ..., phiN |- psi
This expression is called a sequent; it is valid if a proof can be found.
A more narrow definition of sequent, in which the right-hand side has only one conclusion, matches up very nicely with the use of ==>.
We can blame L.Paulson for confusing us by separating the meta-logic from the object-logic, though we can thank him for giving us a larger logical playground.
Maybe to keep from clashing with the common definition of a sequent, as in [4, Wiki], he uses the phrase natural deduction sequent calculus in various places in the literature. In any case, the use of ==> is completely related to implementing natural deduction rules in the logic of Isabelle/HOL.
Even with generalized sequents, L.Paulson prefers the ==> notation:
Logic and Proof course 2012-13
Course materials: see slides for his generalized sequent calculus notation
You asked about differences. I throw in some source related to C.Sternagel's answer, along with the impI axiomatization again:
(*line 166*)
axiomatization where
impI: "(P ==> Q) ==> P-->Q"
(*706*)
lemma --"atomize_all [atomize]:"
"(!!x. P x) == Trueprop (ALL x. P x)"
by(rule atomize_all)
(*715*)
lemma --"atomize_imp [atomize]:"
"(A ==> B) == Trueprop (A --> B)"
by(rule atomize_imp)
(*line 304*)
lemma --"allI:"
assumes "!!x::'a. P(x)"
shows "ALL x. P(x)"
by(auto simp only: assms allI
I put impI in structured proof format:
lemma impI_again:
assumes "P ==> Q"
shows "P --> Q"
by(simp add: assms)
Now, consider ==> to be the use of the sequent turnstile, and shows to be the sequent notation horizontal bar, then you have the following sequent:
P |- Q
-------
P --> Q
This is the natural deduction implication introduction rule, as the axiom name says, impI (Cornell Lecture 15).
The Big Guys have been on top of all of this for a long time. See [1, Section 2.1, page 27] for an overview of !!, ==>, and ==. In particular, it says
The Pure logic [38, 39] is an intuitionistic fragment of higher-order logic
[13]. In type-theoretic parlance, there are three levels of lambda-calculus with
corresponding arrows =>/!!/==>`...
One general significance of the statement is that in the use of Isabelle/HOL, you are using two logics, a meta-logic and an object-logic, where those two terms come from L.Paulson, and where "intuitionistic" is a key defining point of the meta-logic.
See also [1, Section 9.4.1, Simulating sequents by natural deduction, pg 206]. According to M.Wenzel on the IsaUsersList, L.Paulson wrote this section. On page 205, Paulson first takes the definition of a sequent to be the generalized definition. On page 206, he then shows how you can line up one type of sequent with the use of ==>, which is by negating every proposition on the right-hand side of a sequent, except for one of them.
That, by all appearances, is a horn clause, which I know nothing about.
It seems obvious to me that using ==> is the use of a limited form of sequents. In any event, that's how I think of it, and thinking that way has given me an understanding of the differences between ==> and -->, along with the fact that the meta-logic has no excluded middle.
If A.Lochbhiler wouldn't have pointed out the absence of an excluded middle, I wouldn't have seen an important difference of what's possible with ==>, and what's possible with -->.
Maybe C.Sternagel will start back again to give me some of his important answers.
Please pardon the long answer.
Others have already explained some of the reasons behind the difference between meta-logic and logic, but missed the simple tactic apply atomize:
lemma "⟦⋀(x::'a). P x ⟹ P z ; P y⟧ ⟹ P z"
apply atomize
which yields the goal:
⟦ ∀x. P x ⟶ P z; P y ⟧ ⟹ P z
as desired.
(The additional type constraint ⋀(x::'a) is required for the reasons mentioned by chris.)
There is a lot of text already, so just a few brief notes:
Isabelle/Pure is minimal-higher order logic with the main connectives ⋀ and ⟹ to lay out Natural Deduction rules in a declarative way. The system knows how to compose them by basic means, e.g. in Isar proofs, proof methods like rule, attributes like OF.
Isabelle/HOL is full higher-order logic, with the full set of predicate logic connectives, e.g. ∀ ∃ ∧ ∨ ¬ ⟶ ⟷, and much more library material. Canonical introduction rules like allI, allE, exI, exE etc. for these connectives explain formally how the reasoning works wrt. the Pure framework. HOL ∀ and ⟶ somehow correspond to Pure ⋀ and ⟹, but they are of different category and should not be thrown into the same box.
Note that apart from the basic thm command to print such theorems, it occasionally helps to use print_statement to get an Isar reading of these Natural Deduction reasoning forms.
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.
I am trying to prove the following basic theorem about the existence of the inverse function of a bijective function (to learn theorem-proving with Isabelle/HOL):
For any set S and its identity map 1_S, α:S→T is bijective iff there
exists a map β: T→S such that βα=1_S and αβ=1_S.
Below is what I have so far after some attempts to define relevant things including functions and their inverses. But I am pretty stuck and couldn't make much progress due to my lack of understanding of Isabelle and/or Isar.
theory Test
imports Main
"HOL.Relation"
begin
lemma bij_iff_ex_identity : "bij_betw f A B ⟷ (∃ g. g∘f = restrict id B ∧ f∘g = restrict id A)"
unfolding bij_betw_def inj_on_def restrict_def iffI
proof
let ?g = "restrict (λ y. (if f x = y then x else undefined)) B"
assume "(∀x∈A. ∀y∈A. f x = f y ⟶ x = y)"
have "?g∘f = restrict id B"
proof
(* cannot prove this *)
end
In above, I try to give an explicit existential witness (i.e. the inverse function g of the original function f). I have several issues about the proof.
whether the concepts are defined right (functions, inverse functions etc.) in Isabelle terms.
how to expand the relevant definitions and then simplify them with function applications. I have followed some Isabelle (2021) examples/tutorials about both the apply-style simp, and structured style Isar proof but couldn't use the Isar proof fluently. Once I started the proof command, I don't know how to simp or move any further.
Isar has the new way of assumes ... shows ... for stating the theorem. Is there similar support for proving iff's (⟷) like the example above? Without it, there is no access to assms etc., and is it necessary to assume everything except the conclusion during the proof.
Can someone help explain how the above existential proof about inverse function can be accomplished?
lemma bij_iff_ex_identity : "bij_betw f A B ⟷ (∃ g. g∘f = restrict id B ∧ f∘g = restrict id A)"
I think this is not exactly what you want an I am doubtful that it is true. g∘f = restrict id B does not mean that g∘f and id are equal on B. It means that the total function g∘f (and there are only total functions in HOL) equals the total function restrict id B. The latter returns id x on x∈B and undefined otherwise. So to make this equality true, g needs to output undefined whenever the input of f is not in B. But how would g know that!
If you want to use restrict, you could write restrict (g∘f) B = restrict id B. But personally, I would rather go for the simpler (∀x∈B. (g∘f) x = x).
So the corrected theorem would be:
lemma bij_iff_ex_identity : "bij_betw f A B ⟷ (∃ g. (∀x∈A. (g∘f) x = x) ∧ (∀y∈B. (f∘g) y = y))"
(Which is still wrong, by the way, as quickcheck tells me in Isabelle/jEdit, see the output window. If A has one element and B is empty, f cannot be a bijection. So the theorem you are attempting is actually mathematically not true. I will not attempt to fix it, but just answer the remaining lines.
unfolding bij_betw_def inj_on_def restrict_def iffI
The iffI here has no effect. Unfolding can only apply theorems of the form A = B (unconditional rewriting rules). iffI is not of that form. (Use thm iffI to see.)
proof
Personally, I don't use the bare form proof but always proof - or proof (some method). Because proof just applies some default method (in this case, equivalent to (rule iffI), so I think it's better to make it explicit. proof - just starts the proof without applying an extra method.
let ?g = "restrict (λ y. (if f x = y then x else undefined)) B"
You have an unbound variable x here. (Note the background color in the IDE.) That is most likely not what you want. Formally, it is allowed, but x will be treated as if it was some arbitrary constant.
Generally, I don't think there is any way to define g in a simple way (i.e., only with quantifiers and function applications and if-then-else). I think the only way to define an inverse (even if you know it exists), is to use the THE operator, because you need to say something like g y is "the" x such that f x = y. (And then later in the proof you will run into a proof obligation that it indeed exists and that it is unique.) See the definition of inv_into in Hilbert_Choice.thy (except it uses SOME not THE). Maybe for starters, try to do the proof just using the existing inv_into constant.
assume "(∀x∈A. ∀y∈A. f x = f y ⟶ x = y)"
All assume commands must have assumptions exactly as the are in the proof goal. You can test whether you wrote it right by just temporarily writing the command show A for A (that's an unprovable goal that would, however, finish the proof, so it tricks Isabelle into checking if it would). If this command does not give an error, you got the assumes right. In your cases, you didn't, it should be (∀x∈A. ∀y∈A. f x = f y ⟶ x = y) ∧ f ' A = B. (' is the backtick symbol here. Markup doesn't let me write it.)
My recommendation: Try the proof with bij instead of bij_betw first. (One direction is in BNF_Fixpoint_Base.o_bij if you want to cheat.)
Once done, you can try to generalize.
I agree with the insightful remarks provided by Dominique Unruh. However, I would like to mention that a theorem that captures the idea underlying the theorem that you are trying to prove already exists in the source code of the main library of Isabelle/HOL. In fact, it exists in at least two different formats: let me name them the traditional Isabelle/HOL format and the canonical FuncSet format. For the former one, see the theorem bij_betw_iff_bijections:
"bij_betw f A B ⟷ (∃g. (∀x ∈ A. f x ∈ B ∧ g(f x) = x) ∧ (∀y ∈ B. g y ∈ A ∧ f(g y) = y))"
The situation is a little bit more complicated with FuncSet. There does not seem to exist a single theorem that captures the idea. However, together, the theorems bij_betwI, bij_betw_imp_funcset and inv_into_funcset are nearly equivalent to the theorem that you are trying to state. Let me provide a sketch of how one could express this theorem in a manner that would be considered reasonably canonical in the FuncSet sense (try to prove it yourself):
lemma bij_betw_iff:
shows "bij_betw f A B ⟷
(
∃g.
(∀x. x∈A ⟶ g (f x) = x) ∧
(∀y. y∈B ⟶ f (g y) = y) ∧
f ∈ A → B ∧
g ∈ B → A
)"
sorry
I would also like to repeat the advice given by Dominique Unruh and provide several side remarks:
My recommendation: Try the proof with bij instead of bij_betw first.
Indeed, this is a very good idea. In general, by trying to restrict the problem to explicitly defined sets A and B, instead of working directly with types, you touched upon a topic that is known as relativization in logic. For a mild layman's introduction see, for example, https://leanprover.github.io/logic_and_proof/first_order_logic.html [1], for a slightly more thorough introduction in the context of set theory see [2, chapter 12]. As you have probably noticed by now, it is not that easy to relativize theorems in Isabelle/HOL and requires additional proof effort.
However, there exists an extension of Isabelle/HOL that allows for the automation of the process of the relativization of theorems. For more information about this extension see the article From Types to Sets by Local Type Definition in Higher-Order Logic by Ondřej Kunčar and Andrei Popescu [3]. There also exists a large scale application example of the framework [4]. Independently, I am working on making this extension more user-friendly and very slowly approaching the final stages in my efforts: see https://gitlab.com/user9716869/tts_extension. Thus, in principle, if you know how to use Types-To-Sets and you accept its axioms, then it is sufficient to prove the theorem with bij, e.g.,
"bij f ⟷ (∃g. (∀x. g (f x) = x) ∧ (∀y. f (g y) = y))",
Then, the theorems like
bij_betw_iff_bijections and bij_betw_iff can be synthesized automatically for free upon a click of a button (almost...).
Finally, for completeness, let me offer my own advice with regard to your queries (although, as I mentioned, I agree with everything stated by Dominique Unruh)
how to expand the relevant definitions and then simplify them with
function applications. I have followed some Isabelle (2021)
examples/tutorials about both the apply-style simp, and structured
style Isar proof but couldn't use the Isar proof fluently. Once I
started the proof command, I don't know how to simp or move any
further.
I believe that the best way to learn what you are trying to learn is by following through the exercises in the book Concrete Semantics by Tobias Nipkow and Gerwin Klein [5]. Additionally, I would also look through A Proof Assistant for Higher-Order Logic by Tobias Nipkow et al [6](it is slightly outdated, but I found it to be useful specifically for learning apply-style scripting/direct rule application). By the way, I have mostly self-taught myself Isabelle from these books without any prior experience in formal methods.
Isar has the new way of assumes ... shows ... for stating the theorem.
Is there similar support for proving iff's (⟷) like the example above?
Without it, there is no access to assms etc., and is it necessary to
assume everything except the conclusion during the proof.
I will make the advice given by Dominique Unruh more explicit: use rule iffI or intro iffI for this.
Edit. When you use rule iffI (or similar) to start your structured Isar proof, you need to state your assumptions explicitly for every subgoal (using the assume ... show ... paradigm). However, there is a tool that can generate such boilerplate Isar code automatically. It is called Sketch-and-Explore and you can find it in the directory HOL/ex of the main library of Isabelle/HOL. In this case, all you need to do is to type sketch(rule iffI) and the assume/show paradigm will be generated automatically for every subgoal.
References
Avigad J, Lewis RY, and van Doorn F. Logic and Proof.
Jech T. Set theory. 3rd ed. Heidelberg: Springer; 2006. (Pure and applied mathematics, a series of monographs and textbooks).
Kunčar O, Popescu A. From Types to Sets by Local Type Definition in Higher-Order Logic. Journal of Automated Reasoning. 2019;62(2):237–60.
Immler F, Zhan B. Smooth Manifolds and Types to Sets for Linear Algebra in Isabelle/HOL. In: 8th ACM SIGPLAN International Conference on Certified Programs and Proofs. New York: ACM; 2019. p. 65–77. (CPP 2019).
Nipkow T, Klein G. Concrete Semantics with Isabelle/HOL. Heidelberg: Springer-Verlag; 2017. (http://concrete-semantics.org/)
Nipkow T, Paulson LC, Wenzel M. A Proof Assistant for Higher-Order Logic. Heidelberg: Springer-Verlag; 2017.
Suppose I write a lemma "(∀a. P a ⟹ Q a) ⟹ R b" in Isabelle. ∀a will only quantify over P a. If I want to quantify over P a ⟹ Q a however, putting parenthesis after ∀a (i.e "(∀a. (P a ⟹ Q a)) ⟹ R a") will cause Isabelle's parsing to fail.
How can I properly quantify over a specific part of the sentence?
Note: I know that free variables in lemmas are implicitly universal in Isabelle. This question is mostly for inner statements, in which the quantifier should not range over the whole sentence.
I believe that the parse failure stems from the fact that Isabelle/HOL has two distinct types of implication operators, Pure.imp (⟹) and HOL.implies (⟶). The former is part of the Isabelle metalogic while the latter is part of the HOL logic. You can find more information about why this distinction exists and when to use each in these mailing list posts:
https://lists.cam.ac.uk/pipermail/cl-isabelle-users/2018-December/msg00031.html
https://lists.cam.ac.uk/pipermail/cl-isabelle-users/2019-January/msg00019.html
The ⟹ operator has very low precedence, lower than ∀ and as a result ∀a. (P a ⟹ Q a) cannot be parsed as you would expect. You may fix the parse failure in your lemma by using the ⟶ operator instead which has higher precedence than ∀. Another option is to change ∀ to the meta quantifier ⋀, making your sentence more in line with Isabelle's framework.
A table of operator precedence is available but I cannot guarantee that it is up to date. You can use the print_syntax command in Isabelle for a more reliably up-to-date ordering.
Table: https://lists.cam.ac.uk/pipermail/cl-isabelle-users/2012-November/pdfi7tZP06fqA.pdf
I am trying to understand the lemma below.
Why is the ?y2 schematic variable introduced in exI?
And why it is not considered in refl (so: x = x)?
lemma "∀x. ∃y. x = y"
apply(rule allI) (* ⋀x. ∃y. x = y *)
thm exI (* ?P ?x ⟹ ∃x. ?P x *)
apply(rule exI) (* ⋀x. x = ?y2 x *)
thm refl (* ?t = ?t *)
apply(rule refl)
done
UPDATE (because I can't format code in comments):
This is the same lemma with a different proof, using simp.
lemma "∀x. ∃y. x = y"
using [[simp_trace, simp_trace_depth_limit = 20]]
apply (rule allI) (*So that we start from the same problem state. *)
apply (simp only:exI)
done
The trace shows:
[0]Adding rewrite rule "HOL.exI":
?P1 ?x1 ⟹ ∃x. ?P1 x ≡ True
[1]SIMPLIFIER INVOKED ON THE FOLLOWING TERM:
⋀x. ∃y. x = y
[1]Applying instance of rewrite rule "HOL.exI":
?P1 ?x1 ⟹ ∃x. ?P1 x ≡ True
[1]Trying to rewrite:
x = ?x1 ⟹ ∃xa. x = xa ≡ True <-- NOTE: not ?y2 xa or similar!
[2]SIMPLIFIER INVOKED ON THE FOLLOWING TERM:
x = ?x1
[1]SUCCEEDED
∃xa. x = xa ≡ True
So apparently simp and rule handles exI differently. And the remaining question is: what is the mechanical (programmatical) reasoning behind rule's behavior.
When you use rule thm for some fact thm, Isabelle performs higher-order unification of the conclusion of thm with the current goal. If there is a unifier, it is used to instantiate both the goal and the conclusion of the theorem, and then resolution is performed (i.e. the goal is replaced with the assumptions of thm).
This means that:
Schematic variables in the goal can be instantiated by rule through unification
Variables that appear only in the assumptions of thm will not be instantiated by the unification and will therefore remain schematic. That way, you end up with schematic variables in your new goals. Such variables can be seen as existential in some sense, because the conclusion of thm holds if you can prove the assumptions for just one arbitrary value.
In the case of exI, you have ?P ?x ⟹ ∃x. ?P x. When you apply rule exI, the variable ?P is instantiated to λy. x = y, but the variable ?x appears only in the assumptions of exI, so it remains schematic. This means that you can pick any value you want for ?x later on in your proof.
To be more precise, you end up with ⋀x. x = ?y2 x as your goal. You might ask ‘Why not just ⋀x. x = ?y2?’ That would mean that you have to show that x equals some fixed value y2 for all possible values of x. That is obviously not true in general. ⋀x. x = ?y2 x means you have to show that every x equals some y2 that may depend on x – or, equivalently, that there is a function y2 that, when given x, outputs x.
Of course, there is such a function and it is simply the identity function λx. x. That is precisely what ?y2 gets instantiated to when you apply rule refl: the goal x = ?y2 x is unified with the conclusion of refl ?t = ?t and you end up with ?t = x and ?y2 = λx. x, and since refl has no assumptions, this resolution finishes the proof.
I am not entirely sure what you mean with ‘And why it is not considered in refl?’, but I hope that I have answered your questions.
Get a more complete answer from an expert, but I give a short, brief answer to your second part.
The great thing about Isabelle is that it provides many different ways to prove a problem.
Your new question is similar to L.Paulson's comment on FOM: you moved the goal post by switching the question to rule vs. simp:
http://www.cs.nyu.edu/pipermail/fom/2015-October/019312.html
Getting a basic understanding of simp is actually a much easier goal to pursue, or I wouldn't be adding my reponse here.
rule and natural deduction
The use of rule is the use of natural deduction (ND), where most people aren't up to speed on ND. The use of ND requires understanding ND, so questions like your first question can lead to a non-simple answer, because anything informative can't be a one-liner answer, especially due to things like schematic variables (which you asked about), resolution, unification, rewriting, etc.
Do a search on natural deduction and you'll find the standard wiki page about it. There are numerous books on natural deduction, though they get swamped in searches on "logic" due to first-order logic books. A popular book is Logic in Computer Science, 2nd, by Huth and Ryan.
If you study ND, you'll see that exI matches one of the ND rules.
I have yet to take the time to come up to speed on ND, because I keep making progress without having more than a basic understanding of ND.
Sledgehammer, and auto-methods auto, simp, blast, induct, cases, etc., and Sledgehammer's use of some of those, keep me from finding the time to become good with natural decution.
Answer's like M.Eberl's, though not simple explanations, help me absorb a little here and a little there.
Simp, I think of it as simple substitution (rewriting)
The mechanics behind simp is really simple, compared to natural deduction. You define a formula and prove it:
lemma foo [simp]: "left_hand_side = right_hand_side"
In the proof of another theorem, when simp is invoked in one way or another, or foo is unfolded, where there is left_hand_side, it's replaced with right_hand_side. It's just classic mathematical substitution.
I suppose it could also be "rewriting", but I don't know anything about rewriting, other than they talk about it.
There are lots of details about how and whether one should set things up automatically (to prevent looping), like with [simp] or declare foo_def [simp add], but that's just details along the line of normal programming.
Here, I ask for a proof of a Isabelle meta-logic conjunction elimination rule.
The source below contains comments of mine which explain a little of what I'm doing. In the theory, there are two pairs of a meta-false definition and conjunction elimination rule. The two pairs are the following:
falseH, andH_E1, and
falseM, andM_E1.
The form of my andM conjunction is (P ==> Q ==> falseM) ==> falseM), and it's this form for which I cannot get an easy proof.
In the future, I plan on duplicating the HOL.thy natural deduction rules using meta-logic operators which will be similar to the andM above. As part of that, the operator ==> will be treated as a primitive operator. Because the Pure operator !! is also primitive in the same sense as ==>, I'm guessing that I may not be able to develop rules which will help me with the meta-false definition, !!P. PROP P, as I use it below. I could be wrong, though.
It's not like I have to have the falseM I try to use below, because falseH is conducive to the simp magic that already works in conjunction with HOL, pun not intended. Though I don't have to have it, having it would be good.
theory i131210a__SO_question_andM_elim
imports Complex_Main
begin
(*This is conjunct1 from HOL.thy, line 426. Someday, I'll get rules to
use by duplicating the HOL rules as meta-logic rules, but my question
here is about proving andM_E1 below with what's already available.*)
lemma conjunct1_from_HOL:
"[| P & Q |] ==> P"
by(unfold and_def, iprover intro: impI dest: spec mp)
(*Using bool for falseH allows the auto magic to work for andH_E1.*)
definition falseH :: "prop" ("falseH") where
"falseH == (!!P. P::bool)"
theorem andH_E1:
"((P ==> Q ==> falseH) ==> falseH) ==> P"
by(unfold falseH_def, auto)
(*Using Pure &&&, auto-tools work too, but I want a different meta-and.*)
theorem mand_E1:
"(P &&& Q) ==> P"
by(linarith)
(*Here I define a pure meta-false. That's what I want, if I can get it.*)
definition falseM :: "prop" ("falseM") where
"falseM == (!!P. PROP P)"
(*But here, I need an IsaMagician to do what may be easy, or may be hard.
A proof for this might give me a good template to follow.*)
theorem andM_E1:
"((P ==> Q ==> falseM) ==> falseM) ==> P"
apply(unfold falseM_def)
oops
end
Update (131211)
I update this with three things, where two of them are related to Andreas' answer that an axiom of excluded middle is needed. What I say below is not really an answer to anything, and it's open to more comments, since I can be wrong on simple things.
I put my lengthy comments in here to consolidate some ideas related to the core idea of my question, which is how to use a meta-logic false to define meta-logic operators.
I show how I think I would add a meta-logic axiom of excluded middle in a locale.
I show what led to me understanding what form of an axiom of excluded middle I need. Most all the literature will say that an excluded middle is P or not P, which is deceptive, since I rarely think about an excluded middle, because it is ingrained my thinking.
I note that "(P &&& Q) ==> P is proved by conjunctionD1 in conjunction.ML, and an unfolded version is proved using meta_allE. I wonder why andM, with !! on the inside rather than outside, can't be manipulated so that it can be proved.
Putting a Meta-Logic Excluded Middle in a Locale
So Adreas saved me many months, probably at least a year, and possibly many years of fruitless scheming by pointing out that Isabelle/Pure doesn't have an excluded middle, and that I need it. This has helped answer related questions I had, and helps make more sense to me what Isabelle/Pure is.
If using the HOL excluded middle is forced on me, I would just use False, instead of (!!P. P::bool).
If I want a meta-false, I think I would add a meta-logic excluded middle in a locale like this:
abbreviation (input) trueM :: "prop" ("trueM") where
"trueM == (falseM ==> falseM)"
locale pure_with_em =
assumes t_or_f: "((P == trueM) ==> falseM) ==> (P == falseM)"
begin
theorem andM_E1:
"((P ==> Q ==> falseM) ==> falseM) ==> P"
unfolding falseM_def
oops
end
Like I said, this is not an answer because I would have to work it out.
From the proof that Andreas provided, there is classical from HOL:
lemma classical:
assumes prem: "~P ==> P" shows "P"
apply (rule True_or_False [THEN disjE, THEN eqTrueE])
...
The proof steps of HOL theorems like this tell me what I need for meta-logic versions. I did the easy part by providing the locale axiom t_or_f. The rest is just plain ole work.
Isabelle/Pure Not Having an Excluded Middle
Here, I don't talk just to talk, which I do at times, but I put in what I worked through to see that == is needed as part of an excluded middle. I could need to look at all this again, so maybe it won't be held against me.
First, jumping ahead of what I say next about the HOL lemma excluded_middle, a person, me in particular, would also want to be thinking about this
HOL.thy axiom, line 171:
True_or_False: "(P = True) | (P = False)".
Andreas points out that the law of excluded middle is needed, and that Pure does not provide it. This is the HOL.thy theorem named
excluded_middle, line 604:
lemma excluded_middle: "~P | P" by (iprover intro: disjCI)
Analogously, I state this as a meta-logic theorem using falseM, where my meta-or is (P ==> falseM) ==> Q, and meta-not is P ==> falseM.
theorem
"(P ==> falseM) ==> (P ==> falseM)"
by(simp)
If meta-or notation is defined to obscure what it actually is, a logical novice (not me of course) might not recognize this as "if P is false then P is false", rather than what's needed, "if P is not false, then it must be true".
Update (131213): I put this in because I can forget why I did something, then when I try to work back through the logic, I think I messed up big time, when I didn't, though my logical awareness may not have been complete.
I didn't actually implement a meta-logic version of ~P | P, but of P | ~P. If it's not obvious, which it probably is, I'm using a truth table based definition of implication along with DeMorgan's laws, and using the basic theorems of logic, which ultimately must be true for me.
However, I'm now working with hindsight in regards to the axiom of excluded middle, which makes the fact that I used P | ~P less acceptable, since it becomes "((P ==> falseM) ==> falseM) ==> P", which involves double negation, which I vaguely remember is related to all this. Until now, I've never in my life ever had to concern myself with the excluded middle. That's supposed to be what constructivists think about.
It's actually fortuitous that I made the switch, because that took me to seeing the significance of = in True_or_False.
A meaningful theorem would be "not (P and not P)" (or would it?).
So I substitute (P ==> falseM) for Q in the meta-and expression
(P ==> Q ==> falseM) ==> falseM.
theorem
"((P ==> (P ==> falseM) ==> falseM) ==> falseM) ==> falseM"
by(auto,assumption)
This has gone into full play-the-logical-fool red alert, because falseM
didn't have to be expanded. Now, I state the same theorem, but without
bool variables and without falseM, to make explicit that it has nothing
to do with falseM or bool.
theorem
"((PROP P ==> (PROP P ==> PROP Q) ==> PROP Q) ==> PROP Q) ==> PROP Q"
by(erule Pure.cut_rl Pure.meta_impE Pure.meta_mp, assumption)
Back to what I jumped ahead to at the beginning, I see now that a key
difference is that operator = is being used in True_or_False.
Now, I state a meta-logic form of True_or_False which uses operator ==,
with meta-or as (P ==> falseM) ==> Q, the true part as (P == (falseM ==> falseM)), and the false part as (P == falseM).
theorem
"((P == (falseM ==> falseM)) ==> falseM) ==> (P == falseM)"
apply(unfold falseM_def)
oops
This finally got me a meaningful meta-logic statement of the excluded
middle, in which falseM needs to be expanded. I can't prove this, which
means nothing in itself, or disprove it, which means I could be totally
confused.
This demonstrates why I have to study a lot of low-level logic to work
with theorem assistants, when my end goal is high-level mathematics,
which traditionally doesn't require this kind of knowledge.
Not having a good understanding of the significance of no excluded middle
ended up killing me, among other things.
Why Can "(P &&& Q) ==> P" Be Proved Above?
There is still the significance that (P &&& Q) ==> P can be proved by
the methods linarith and presburger above, where &&& in pure_thy.ML is this:
"(A &&& B) == (!!C::prop. (A ==> B ==> C) ==> C)"
My meta-and, using falseM, actually just moves the use of !! from the
outside to the inside, once falseM has been expanded.
Here, I prove expanded terms of meta-and elimination, and prove an unexpanded version of it using Pure.conjunctiond1.
theorem
"(PROP P &&& PROP Q) ==> PROP P"
apply(unfold Pure.conjunction_def)
by(erule Pure.meta_allE, assumption)
theorem expanded_and_1:
"(!!R. (PROP P ==> PROP Q ==> PROP R) ==> PROP R) ==> PROP P"
by(erule Pure.meta_allE, assumption)
theorem
"(PROP P &&& PROP Q) ==> PROP P"
by(erule Pure.conjunctionD1)
The rule conjunctionD1 is in conjunction.ML, and it appears that forall_elim_vars
is taking care of the operator !!, which I suppose is just doing the same thing as meta_allE.
I Could Use the Standard Meta-And, but Meta-And Is Not the Goal
I compare two expanded versions of the conjunction elimination rule. The first term uses the standard &&&, and the second term uses my andM.
term "(!!R. (P ==> Q ==> PROP R) ==> PROP R) ==> P"
term "((P ==> Q ==> (!!P. PROP P)) ==> (!!P. PROP P)) ==> P"
Using &&& allows the first term to be proved easily with meta_allE, as shown above.
It seems to me, I should be able to manipulate the second term into the form of the first term, but I wouldn't know. If that's true, then I don't need to add an axiom of excluded middle for this theorem. I'll know after studying a lot of natural deduction, like I need to.
If my goal was just meta-logic operators, I'd use &&&, but that's not my goal. My goal is to define a meta-false to use to abbreviate meta-logic operators. I'm trying to slightly expand the natural deduction framework of Isabelle/Pure, not duplicate all of HOL.
The main value I've gotten from this question is that I now know I need to be on the lookout for the need for an axiom of excluded middle. If I want a meta-false, then it seems I will need an axiom of excluded middle.
This is where I leave off. Thanks for the help, and please pardon the lengthy additions.
As a first step, you can prove the HOL version andH_E1 without using any proof tools, just plain rule, subst, and assumption. Then, you should be able to see whether you can translate your proof to andM_E1 and how to do so. I found the following proof for andH_E1:
theorem andH_E1: "((P ==> Q ==> falseH) ==> falseH) ==> P"
unfolding falseH_def
apply(rule classical)
apply(erule meta_allE)
apply(erule meta_impE)
apply(erule notE)
apply assumption
apply assumption
done
As you can see, the first step applies the rule classical, i.e., my proof works only in classical logic. However, Pure is weaker than classical logic, because there is no axiom of excluded middle. Hence, you will not be able to transfer this proof to andM_E1. You can try to find a proof of andH_E1 that does not rely on the classical axioms, but I doubt that you will find one; at least iprover does not. Otherwise, you cannot prove this theorem with Pure means only unless you introduce the axiom of excluded middle to Pure.
As excluded middle is equivalent to the classical axiom (you can derive the one from the other), the easiest way to go is probably to add the classical axiom directly, e.g., in a locale as you suggested. Then, the proof goes as follows, where I write Pure negation as _ ==> falseM.
locale classical =
assumes pure_classical: "((PROP P ==> falseM) ==> PROP P) ==> PROP P"
begin
theorem andM_E1:
"((PROP P ==> PROP Q ==> falseM) ==> falseM) ==> PROP P"
unfolding falseM_def
apply(rule pure_classical)
apply(erule meta_allE)
apply(erule meta_impE) back
apply(erule (1) meta_impE)
apply(unfold falseM_def)
apply(assumption)
apply(assumption)
done
end