Unable to evaluate expressions with a reflexive transitive closure - isabelle

The following expressions are almost identical:
value "(1,5) ∈ trancl {(1::nat,2::nat),(2,5)}"
value "(1,5) ∈ rtrancl {(1::nat,2::nat),(2,5)}"
However the first one is evaluated fine, and for the second one I get the following error:
Wellsortedness error:
Type nat not of sort {enum,equal}
No type arity nat :: enum
It seems that the error is caused by the identity relation:
value "(1::nat,5::nat) ∈ Id"
However the following code lemma doesn't help:
lemma Id_code [code]: "(a, b) ∈ Id ⟷ a = b" by simp
Could you please suggest how to fix it? Why it doesn't work from the scratch? Is it just an incompleteness of code lemmas or there are more fundamental reasons?

The problem becomes apparent when you look at the code equations for rtrancl with code_thms rtrancl:
rtrancl r ≡ trancl r ∪ Id
Here, Id is the identity relation, i.e. the set of all (x, x). If your type is infinite, both Id and its complement will also be infinite, and there is no way to represent that in a set with the Isabelle code generator's default set representation (which is as lists of either all the elements that are in the set or all the elements that are not in the set).
The code equation for Id reflects this as well:
Id = (λx. (x, x)) ` set enum_class.enum
Here, enum_class.enum comes from the enum type class and is a list of all values of a type. This is where the enum constraint comes from when you try to evaluate rtrancl.
I don't think it's possible to evaluate rtrancl without modifying the representation of sets in the code generator setup (and even then, printing the result in a readable form would be challenging). However, getting the code generator to evaluate things like (1, 5) ∈ rtrancl … is relatively easy: you can simply register a code unfold rule like this:
lemma in_rtrancl_code [code_unfold]: "z ∈ rtrancl A ⟷ fst z = snd z ∨ z ∈ trancl A"
by (metis prod.exhaust_sel rtrancl_eq_or_trancl)
Then your value command works fine.

Related

Defining a predicate; need prop=>bool

I'm trying to define a function that takes a set and a relation and returns a bool telling if the relation is reflexive on the set. I tried to define it like this:
definition refl::"'a set⇒('a×'a) set⇒bool" where
"refl A R = (∀x. x∈A⟹(x,x)∈R)"
but Isabelle gives me the following error:
Type unification failed: Clash of types "prop" and "bool"
Type error in application: incompatible operand type
Operator: (=) (refl A R) :: bool ⇒ bool
Operand: ∀x. x ∈ A ⟹ (x, x) ∈ R :: prop
I can't seem to find any function to force a "prop" into a "bool". I also tried changing the definition to set the RHS = True, but I get the same error.
What is the correct way to define my function?
You can't go from prop to bool. But you don't have to: just use the object level connectives (⟶ and ∀) instead of the meta-logical ones (⟹ and ⋀). They are logically equivalent, so this is not a problem.
The meta-logical connectives should (and usually can) only be used on the ‘outermost level’ of a proposition.
Note however that when you can use the mega-logical ones, it is usually more convenient to use them because the object-level ones are opaque to Isabelle and the Isar proof language (i.e. they are functions just like any other function) whereas Isar ‘knows’ what ⟹ and ⋀ mean. For instance, if you have a fact stated with ⟹ and ⋀, you can immediately instantiate variables and discharge assumptions in it using the of/OF attributes.
You need to write it such that the value is not prop in the first place — there's no conversion. In this case, you used the prop-level implication ⟹ between ∀x. x ∈ A and (x, x) ∈ R. You may use a single-width arrow --> instead, which is an implication of bools.

How to obtain witness instances outside a lemma in Isabelle/HOL

I'm using Isabelle/HOL, trying to prove a statement Q. On the way to proving Q, I have proven the existence of a natural number that satisfies P::"nat=>bool". How can I create an instance x::nat that satisfies P, so that I can reference it in subsequent lemmas?
Inside any given lemma, I can do it using the obtains command. I want to reference the same witness instance in a number of different lemmas, however, so I need a way to do it outside of any lemma. I tried to use fix/assume inside a new locale, as shown below:
locale outerlocale
fixes a b c ...
begin
definition Q::bool where ...
lemma existence: "EX x. P x"
proof -
...
qed
locale innerlocale = outerlocale +
fixes x::nat
assumes "P x"
begin
(*lots of lemmas that reference x*)
lemma innerlemma0
...
lemma innerlemma7
proof -
...
qed
lemma finalinnerlemma: "Q"
proof -
...
...
qed
end (*innerlocale*)
lemma outerlemma: "Q"
proof -
(*I don't know what goes here*)
qed
end (*outerlocale)
Unfortunately this just kicks the can down the road. I need a way to use the existence lemma to extract the final inner lemma into the outer locale. If I try to interpret the inner locale, I'm once again up against the problem of supplying a witness. I can't interpret locales inside lemmas (unless I'm misunderstanding the error I get), and I can't use obtain outside of lemmas, so I'm stuck.
So it looks I need to figure out either
how to specify a witness instance outside a lemma or
how to extract a lemma from a locale by proving that locale's assumptions
Or is there a better way to do what I'm trying to do? Thanks!
You can just use SOME x. P x, e.g., in a definition:
definition my_witness :: nat where
"my_witness = (SOME x. P x)"
and then use thm someI_ex to show P my_witness.

Isabelle/HOL restrict codomain

I am sorry for asking so many Isabelle questions lately. Right now I have a type problem.
I want to use a type_synonym introduced in a AFP-theory.
type_synonym my_fun = "nat ⇒ real"
I have a locale in my own theory where:
fixes n :: nat
and f :: "my_fun"
and A :: "nat set"
defines A: "A ≡ {0..n}"
However, in my use case the output of the function f is always a natural number in the set {0..n}. I want to impose this as a condition (or is there a better way to do it?). The only way I found was to:
assumes "∀v. ∃ i. f v = i ∧ i ∈ A"
since
assumes "∀v. f v ∈ A"
does not work.
If I let Isabelle show me the involved types it seems alright to me:
∀v::nat. ∃i::nat. (f::nat ⇒ real) v = real i ∧ i ∈ (A::nat set)
But of course now I cannot type something like this:
have "f ` {0..10} ⊆ A"
But I have to prove this. I understand where this problem comes from. However, I do not know how to proceed in a case like this. What is the normal way to deal with it? I would like to use my_fun as it has the same meaning as in my theory.
Thank you (again).
If you look closely at ∀v::nat. ∃i::nat. (f::nat ⇒ real) v = real i ∧ i ∈ (A::nat set), you will be able to see the mechanism that was used for making the implicit type conversion between nat and real: it is the abbreviation real (this invokes of_nat defined for semiring_1 in Nat.thy) that appears in the statement of the assumption in the context of the locale.
Of course, you can use the same mechanism explicitly. For example, you can define A::real set as A ≡ image real {0..n} instead of A::nat set as A ≡ {0..n}. Then you can use range f ⊆ A instead of assumes "∀v. ∃ i. f v = i ∧ i ∈ A”. However, I doubt that there is a universally accepted correct way to do it: it depends on what exactly you are trying to achieve. Nonetheless, for the sake of the argument, your locale could look like this:
type_synonym my_fun = "nat ⇒ real"
locale myloc_basis =
fixes n :: nat
abbreviation (in myloc_basis) A where "A ≡ image real {0..n}"
locale myloc = myloc_basis +
fixes f :: "my_fun"
assumes range: "range f ⊆ A"
lemma (in myloc) "f ` {0..10} ⊆ A"
using range by auto
I want to impose this as a condition (or is there a better way to do
it?).
The answer depends on what is known about f. If only a condition on the range of f is known, as the statement of your question seems to suggest, then, I guess, you can only state is as an assumption.
As a side note, to the best of my knowledge, defines is considered to be obsolete and it is best to avoid using it in the specifications of a locale: stackoverflow.com/questions/56497678.

Instantiating a class from a concrete object?

I'm attempting to formalize a series of proofs about topology from a book [1] in Isabelle.
I want to encode the idea that a topological space (X,T) consists of a set X of "points" (elements of some arbitrary type 'a), and a set of subsets of X, called T, such that:
A1. if an element p is in X, then there exists at least one set N in T that also contains p.
A2. if sets U and V are in T, and if p∈(U∩V), then there must exist at a set N in T where N⊆(U∩V) and x∈N. (If two sets intersect, then there must be a neighborhood that covers the intersection.).
Currently I have the following definition:
class topspace =
fixes X :: "'a set"
fixes T :: "('a set) set"
assumes A1: "p∈X ≡ ∃N∈T. p∈N"
assumes A2: "U∈T ∧ V∈T ∧ x∈(U∩V) ⟹ ∃N∈T. x∈N ∧ N⊆(U∩V)"
begin
(* ... *)
end
So far, so good. I'm able to add various definitions and prove various lemmas and theorems about hypothetical topspace instances.
But how do I actually create one? Unless I'm misinterpreting things, the examples I've seen so far for the instance and instantiate keywords all seem to be been about declaring that one particular abstract class (or type or locale) is an instance of another.
How do I tell Isabelle that a particular pair of sets (e.g. X={1::int, 2, 3}, T={X,{}}) form a topspace?
Likewise, how can I use my definition to prove that X={1::int, 2, 3}, T={} does not fit the requirements?
Finally, once I show that a particular concrete object X meets the definition of a topspace, how do I tell Isabelle to now make use of all the definitions and theorems I've proven about topspace when proving things about X?
BTW, I'm using class because I don't know any better. If it's not the right tool for the job, I'm happy to do something else.
[1]: A Bridge to Advanced Mathematics by Dennis Sentilles
I've made some progress here: a class is a special type of locale, but it isn't necessary for this sort of usage, and using the locale keyword directly simplifies the situation a bit. Every locale has an associated theorem that you can use to instantiate it:
locale topspace =
fixes X :: "'a set"
fixes T :: "('a set) set"
assumes A1 [simp]: "x∈X ≡ ∃N∈T. x∈N"
assumes A2 [simp]: "U∈T ∧ V∈T ∧ x∈(U∩V) ⟹ ∃N∈T. x∈N ∧ N⊆(U∩V)"
theorem
assumes "X⇩A={1,2,3::int}" and "T⇩A={{}, {1,2,3::int}}"
shows "topspace X⇩A T⇩A"
proof
show "⋀U V x. U∈T⇩A ∧ V∈T⇩A ∧ x∈U∩V ⟹ ∃N∈T⇩A. x∈N ∧ N⊆U∩V"
and "⋀x. x∈X⇩A ≡ ∃N∈T⇩A. x∈N" using assms by auto
qed
If we want to use definition for declarations, the proof goal becomes a bit more complex, and we need to use the unfolding keyword. (The locales.pdf that comes with isabelle covers this, but I'm not sure I'm not yet able to explain it in my own words). Anyway, this works:
experiment
begin
definition X⇩B where "X⇩B={1,2,3::int}"
definition T⇩B where "T⇩B={{}, {1,2,3::int}}"
lemma istop0: "topspace X⇩B T⇩B" proof
show "⋀U V x. U∈T⇩B ∧ V∈T⇩B ∧ x∈U∩V ⟹ ∃N∈T⇩B. x∈N ∧ N⊆U∩V"
and "⋀x. x∈X⇩B ≡ ∃N∈T⇩B. x∈N" unfolding X⇩B_def T⇩B_def by auto
qed
end
I believe it's also possible, and possibly preferable, to do all this work inside of a sub-locale, but I haven't quite worked out the syntax for this.
Although locales are implemented in the calculus itself and hence their predicates can be used in any regular proposition, this is usually not recommended. Instead, you should instantiate locales using e.g. interpretation, as in the following example.
locale topspace =
fixes X :: "'a set"
fixes T :: "('a set) set"
assumes A1 [simp]: "x∈X ⟷ (∃N∈T. x∈N)"
assumes A2 [simp]: "U∈T ∧ V∈T ∧ x∈(U∩V) ⟹ ∃N∈T. x∈N ∧ N⊆(U∩V)"
context
fixes X⇩A T⇩A
assumes X⇩A_eq: "X⇩A = {1, 2, 3 :: int}"
and T⇩A_eq: "T⇩A = {{}, {1, 2, 3 :: int}}"
begin
interpretation example: topspace X⇩A T⇩A
by standard (auto simp add: X⇩A_eq T⇩A_eq)
lemmas facts = example.A1 example.A2
end
thm facts
Whether this pattern really fits for your needs depends on your application; if you just want to have a predicate, it is better to define it directly without using locale at all.
Note: there is really need to the Pure equality »≡«; prefer HOL equality »=«, or its syntactic variant »⟷«.

How to replace ⋀ and ⟹ with ∀ and ⟶ in assumption

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.

Resources