Isabelle/HOL Question about Sets of Tuples - isabelle

I have a beginner's question about Isabelle/HOL:
I want to prove the following lemma:
lemma
shows "{(x,y) . x ∈ {0..<n} ∧ y ∈ {0..<n} ∧ x = y} = {(x,x). x < n}"
But the proof state is:
proof (prove)
goal (1 subgoal):
1. {(x, y). x ∈ {0..<n} ∧ y ∈ {0..<n} ∧ x = y} = {(xa, x). x < n}
Why did the xa appear and how can I define the set the right (succinct) way?

The (x,y) in the set comprehension {(x,y). ....} is binding variable names. As you write {(x,x). x < n}, you bind two variables named x, where the second x shadows the first.
{(x,x). x < n} is just a nice syntax for a lambda term, actually. Internally, it translates to Collect (case_prod (λx. λx. x < n)). Looking at the term this way, the shadowing is more obvious.
To fix your problem, you have to explicitly express the information that the first and the second bound variable are to be identical, that is: {(x1,x2). x1 = x2 ∧ x1 < n}.
As a side note: The lemma you are trying to show is not true. (For example, n could be an int.) If you want n to be a nat, you have to make this explicit, for example by giving a type in your goal like this {(x,y). x ∈ {0..<(n::nat)} ∧ y ∈ {0..<n} ∧ x = y} = {(x1,x2). x1 = x2 ∧ x1 < n}.
Especially, if you are a beginner, I would strongly suggest to introduce free variables in lemma heads explicitly with the syntax lemma Name: fixes n :: ‹nat› assumes ‹...› shows ‹...›.

Related

Why do I get this exception on an induction rule for a lemma?

I am trying to prove the following lemma (which is the meaning formula for the addition of two Binary numerals).
It goes like this :
lemma (in th2) addMeaningF_2: "∀m. m ≤ n ⟹ (m = (len x + len y) ⟹ (evalBinNum_1 (addBinNum x y) = plus (evalBinNum_1 x) (evalBinNum_1 y)))"
I am trying to perform strong induction. When I apply(induction n rule: less_induct) on the lemma, it throws an error.
exception THM 0 raised (line 755 of "drule.ML"):
infer_instantiate_types: type ?'a of variable ?a
cannot be unified with type 'b of term n
(⋀x. (⋀y. y < x ⟹ ?P y) ⟹ ?P x) ⟹ ?P ?a
Can anyone explain this?
Edit:
For more context
locale th2 = th1 +
fixes
plus :: "'a ⇒ 'a ⇒ 'a"
assumes
arith_1: "plus n zero = n"
and plus_suc: "plus n (suc m) = suc ( plus n m)"
len and evalBinNum_1 are both recursive functions
len gives us the length of a given binary numeral, while evalBinNum_1 evaluates binary numerals.
fun (in th2) evalBinNum_1 :: "BinNum ⇒ 'a"
where
"evalBinNum_1 Zero = zero"|
"evalBinNum_1 One = suc(zero)"|
"evalBinNum_1 (JoinZero x) = plus (evalBinNum_1 x) (evalBinNum_1 x)"|
"evalBinNum_1 (JoinOne x) = plus (plus (evalBinNum_1 x) (evalBinNum_1 x)) (suc zero)"
The problem is that Isabelle cannot infer the type of n (or the bound occurrence of m) when trying to use the induction rule less_induct. You might want to add a type annotation such as (n::nat) in your lemma. For the sake of generality, you might want to state that the type of n is an instance of the class wellorder, that is, (n::'a::wellorder). On another subject, I think there is a logical issue with your lemma statement: I guess you actually mean ∀m. m ≤ (n::nat) ⟶ ... ⟶ ... or, equivalently, ⋀m. m ≤ (n::nat) ⟹ ... ⟹ .... Finally, it would be good to know the context of your problem (e.g., there seems to be a locale th2 involved) for a more precise answer.

Representing a set with gluing conditions

I'm trying to represent projective elliptic curve addition in Isabelle:
function proj_add :: "(real × real) × bit ⇒ (real × real) × bit ⇒ (real × real) × bit" where
"proj_add ((x1,y1),l) ((x2,y2),j) = ((add (x1,y1) (x2,y2)), l+j)"
if "delta x1 y1 x2 y2 ≠ 0"
| "proj_add ((x1,y1),l) ((x2,y2),j) = ((ext_add (x1,y1) (x2,y2)), l+j)"
if "delta' x1 y1 x2 y2 ≠ 0"
so far, I was taught how to do conditional definition and suggested to use the bit type for values in {0,1}. Here is a third representation problem. Assume the following definitions:
definition "e_aff = {(x,y). e' x y = 0}"
definition "e_circ = {(x,y). x ≠ 0 ∧ y ≠ 0 ∧ (x,y) ∈ e_aff}"
A projective elliptic curve is defined by (see pages 12, 13 here for the original):
taking two copies of e_aff glued along e_circ with isomorphism τ. We write (P,i) ∈ E with i ∈ {0,1} for the image of P ∈ e_aff in E using th ith copy of e_aff. The gluing condition gives for P ∈ e_circ, (P,i)
= (τ P,i+1)
How should I represent this set in Isabelle? My idea is that this should be a quotient set with equivalence classes made of one or two elements. But then how do i restrict the above function to work on these equivalence classes?
Edit
The equivalence relation is obtained by composing this relation with an or condition making it reflexive.
Here is a sketch of the approach I followed:
definition "proj_add_class c1 c2 =
(((case_prod (λ x y. the (proj_add x y))) `
(Map.dom (case_prod proj_add) ∩ (c1 × c2)))
// gluing)"
definition "proj_addition c1 c2 = the_elem(proj_add_class c1 c2)"
where I follow the answer to Gather all non-undefined values after addition.

How to generate code for less_eq operation

I need to generate a code calculating all values greater or equal to some value:
datatype ty = A | B | C
instantiation ty :: order
begin
fun less_ty where
"A < x = (x = C)"
| "B < x = (x = C)"
| "C < x = False"
definition "(x :: ty) ≤ y ≡ x = y ∨ x < y"
instance
apply intro_classes
apply (metis less_eq_ty_def less_ty.elims(2) ty.distinct(3) ty.distinct(5))
apply (simp add: less_eq_ty_def)
apply (metis less_eq_ty_def less_ty.elims(2))
using less_eq_ty_def less_ty.elims(2) by fastforce
end
instantiation ty :: enum
begin
definition [simp]: "enum_ty ≡ [A, B, C]"
definition [simp]: "enum_all_ty P ≡ P A ∧ P B ∧ P C"
definition [simp]: "enum_ex_ty P ≡ P A ∨ P B ∨ P C"
instance
apply intro_classes
apply auto
by (case_tac x, auto)+
end
lemma less_eq_code_predI [code_pred_intro]:
"Predicate_Compile.contains {z. x ≤ z} y ⟹ x ≤ y"
(* "Predicate_Compile.contains {z. z ≤ y} x ⟹ x ≤ y"*)
by (simp_all add: Predicate_Compile.contains_def)
code_pred [show_modes] less_eq
by (simp add: Predicate_Compile.containsI)
values "{x. A ≤ x}"
(* values "{x. x ≤ C}" *)
It works fine. But the theory looks over-complicated. Also I can't calculate values less or equal to some value. If one will uncoment the 2nd part of less_eq_code_predI lemma, then less_eq will have only one mode i => i => boolpos.
Is there a simpler and more generic approach?
Can less_eq support i => o => boolpos and o => i => boolpos at the same time?
Is it possible not to declare ty as an instance of enum class? I can declare a function returning a set of elements greater or equal to some element:
fun ge_values where
"ge_values A = {A, C}"
| "ge_values B = {B, C}"
| "ge_values C = {C}"
lemma ge_values_eq_less_eq_ty:
"{y. x ≤ y} = ge_values x"
by (cases x; auto simp add: dual_order.order_iff_strict)
This would allow me to remove enum and code_pred stuff. But in this case I will not be able to use this function in the definition of other predicates. How to replace (≤) by ge_values in the following definition?
inductive pred1 where
"x ≤ y ⟹ pred1 x y"
code_pred [show_modes] pred1 .
I need pred1 to have at least i => o => boolpos mode.
The predicate compiler has an option inductify that tries to convert functional definitions into inductive ones. It is somewhat experimental and does not work in every case, so use it with care. In the above example, the type classes make the whole situation a bit more complicated. Here's what I managed to get working:
case_of_simps less_ty_alt: less_ty.simps
definition less_ty' :: "ty ⇒ ty ⇒ bool" where "less_ty' = (<)"
declare less_ty_alt [folded less_ty'_def, code_pred_def]
code_pred [inductify, show_modes] "less_ty'" .
values "{x. less_ty' A x}"
The first line convertes the pattern-matching equations into one with a case expression on the right. It uses the command case_of_simps from HOL-Library.Simps_Case_Conv.
Unfortunately, the predicate compiler seems to have trouble with compiling type class operations. At least I could not get it to work.
So the second line introduces a new constant for (<) on ty.
The attribute code_pred_def tells the predicate compiler to use the given theorem (namely less_ty_alt with less_ty' instead of (<)) as the "defining equation".
code_pred with the inductify option looks at the equation for less_ty' declared by code_pred_def and derives an inductive definition out of that. inductify usually works well with case expressions, constructors and quantifiers. Everything beyond that is at your own risk.
Alternatively, you could also manually implement the enumeration similar to ge_values and register the connection between (<) and ge_values with the predicate compiler. See the setup block at the end of the Predicate_Compile theory in the distribution for an example with Predicate.contains. Note however that the predicate compiler works best with predicates and not with sets. So you'd have to write ge_values in the predicate monad Predicate.pred.

Isabelle list lifter and compression

From two sets in Isabelle a third list needs to be created with element of the form (a, b) where a is from the first set and b is in the second set. in addition the elements in the last set must be filtered by some condition.
The code:
theory Scratch
imports Main Nat
begin
value "let a = {(1::int), 2, 3, 4} in (let b = {(6::int),7,8,9} in
((1::int), 6) ∈ set (filter (λ el . (snd el) < 8) [(n,m). n ∈ a ∧ m ∈ b]))"
end
The result I expected was True or False. the results was:
"(1, 6)
∈ set [u←if (1 = n ∨ 2 = n ∨ 3 = n ∨ 4 = n) ∧
(6 = m ∨ 7 = m ∨ 8 = m ∨ 9 = m)
then [(n, m)] else [] . snd u < 8]"
:: "bool"
Why does the result not evaluate to a True/False value?
Is it possible to write code where the filter functions is evaluated on a set and not list?
First of all, you cannot convert sets to lists. Lists have a specific order of elements; sets do not.
Question 1
This is because you have free variables in there: n and m. The expression [(n,m). n ∈ a ∧ m ∈ b] basically means if n ∈ a ∧ m ∈ b then [(n,m)] else []. This is not what you want.
If a and b were lists, you could use the list comprehension syntax [(n,m). n ← a, m ← b]. However, since a and b are sets, this cannot possibly work, since the result would be a list with a specific order, and that order has to come from somewhere – but a and b, as sets, have no such order.
Question 2
In formalisation, the best approach is to first define things abstractly, without using data structures that are too concrete. If you don't need to maintain a specific ordering of your values, use a set, not a list. You can then later refine this from sets to lists in order to obtain executable (and efficient) code.
There is a section on refinement in the Isabelle code generation manual. I recommend you have a look at it.
That said, there is some limited support for code generation with sets. Sets are then internally represented as lists and most basic operations work, but code generation may sometimes fail – not all operations on sets are computable in general. There is the function Set.filter, which is executable and basically does the same on sets as the regular filter function does for lists.
However, the following will fail due to a wellsortedness error:
value "let a = {(1::int), 2, 3, 4} in (let b = {(6::int),7,8,9} in
((1::int), (6 :: int)) ∈ Set.filter (λ el . (snd el) < 8) {x. fst x ∈ a ∧ snd x ∈ b})"
This is because set comprehensions (i.e. {x. … }) are, in general, not computable. You have to replace this {x. fst x ∈ a ∧ snd x ∈ b} with something the code generator can generate code for. In this case, it's easy, because this operation is just the cartesian product. You can write:
value "let a = {(1::int), 2, 3, 4} in (let b = {(6::int),7,8,9} in
((1::int), (6 :: int)) ∈ Set.filter (λ el . (snd el) < 8) (a × b))"
And you get the result you'd expect.

Why can I prove ⟦ ( ∃ x. P ) ∧ ( ∃ x. Q ) ⟧ ⟹ ∃ x. (P ∧ Q)?

I'm an Isabelle beginner, learning the basics. To my surprise, I just proved
lemma "⟦ ( ∃ x. P ) ∧ ( ∃ x. Q ) ⟧ ⟹ ∃ x. (P ∧ Q)"
apply ( auto )
done
in Isabelle/HOL. Now assuming that P and Q range over arbitrary predicates, this is false, just instantiate P to x = 1 and Q to x = 2.
Of course the mistake must be on my side, but where is my misconception?
As was already indicated in the comment, P and Q in your example are not predicates, they are simply Boolean variables. If you type term P, you will get simply bool. Since HOL types are nonempty, ∃x. P is equivalent to P and similarly for Q, so your assumptions force P and Q to be True, which obviously implies the statement you proved.
What you meant is
lemma "⟦(∃x. P x) ∧ (∃x. Q x)⟧ ⟹ ∃x. P x ∧ Q x"
This is wrong, and simply by writing down the lemma, quickcheck will already provide you with a counterexample automatically.
Also note that the brackets ⟦…⟧ are not required for a single assumption (like in your case). Furthermore, it is uncommon to use the HOL conjunction operator ∧ to combine assumptions. You would more commonly state this lemma as
lemma "⟦∃x. P x; ∃x. Q x⟧ ⟹ ∃x. P x ∧ Q x"
or
lemma "∃x. P x ⟹ ∃x. Q x ⟹ ∃x. P x ∧ Q x"
This form is easier to handle than the one with the HOL ∧, since you can instantiate particular assumptions.

Resources