How to define functions with overlapping patterns? - isabelle

I'm trying to define a conjunction function for 4-valued logic (false, true, null, and error):
datatype 'a maybe = Just "'a" | Nothing | Error
type_synonym bool4 = "bool maybe"
abbreviation JF :: "bool4" where "JF ≡ Just False"
abbreviation JT :: "bool4" where "JT ≡ Just True"
abbreviation BN :: "bool4" where "BN ≡ Nothing"
abbreviation BE :: "bool4" where "BE ≡ Error"
fun and4 :: "bool4 ⇒ bool4 ⇒ bool4" where
"and4 JF b = JF"
| "and4 a JF = JF"
| "and4 BE b = BE"
| "and4 a BE = BE"
| "and4 BN b = BN"
| "and4 a BN = BN"
| "and4 a b = JT"
I expect that the first patterns have a priority over the last patterns.
It seems that the definition is wrong. I'm trying to evaluate the following expressions:
value "and4 JF b"
value "and4 a JF"
The first one returns JF as expected. But the second one can't be simplified.
As result I can't prove commutativity of the conjunction:
lemma and4_commut:
"and4 a b = and4 b a"
It's recomended to use function instead of fun in "Defining Recursive Functions in Isabelle/HOL" by Alexander Krauss. But I get 12 false subgoals:
function and4 :: "bool4 ⇒ bool4 ⇒ bool4" where
"and4 JF b = JF"
| "and4 a JF = JF"
| "and4 BE b = BE"
| "and4 a BE = BE"
| "and4 BN b = BN"
| "and4 a BN = BN"
| "and4 a b = JT"
apply pat_completeness
apply auto
I guess it's because the function has conflicting patterns. For example, and4 JF BE are matched by the 1st and 4th patterns. And the result of conjuction could be either JF or BE.
What is a right way to define such a functions? And how to prove its commutativity? I can use a case of construction but it complicates the function definition.

The value command can usually not handle free variables (like a) very well.
You can, however, prove the theorem FooAndValue a JF = JF by case distinction:
lemma and4_JF_right [simp]: "and4 a JF = JF"
proof (cases a)
case (Just b)
thus ?thesis by (cases b) simp_all
qed simp_all
Or, a bit less verbose, with a custom case rule:
lemma bool4_cases [case_names JF JT BN BE]:
"(a = JF ⟹ P) ⟹ (a = JT ⟹ P) ⟹ (a = BN ⟹ P) ⟹ (a = BE ⟹ P) ⟹ P"
by (cases a) auto
lemma and4_JF_right [simp]: "and4 a JF = JF"
by (cases a rule: bool4_cases) simp_all
With this, proving commutativity can be done by a simply induction in a single line.
The reason why the fun command does not give you and4 a JF = JF as a theorem even though you literally wrote that in the definition is that indeed that you have overlapping patterns and use sequential pattern matching, i.e. the second ‘equation’ in the function definition only applies if the first one does not.
fun has to resolve the overlapping patterns in order to accomodate this sequential matching, and after this, it's not obvious (in general) that and4 a JF = JF holds. You can look at and4.simps to see exactly what fun did.
If I remember correctly, you can also use plain function to have overlapping patterns without sequential matching, but then you have to prove that the overlapping equations are compatible. In your case, I don't think that would make things any easier.
Another thing that you could do (and that may be easier to use, depending on your use case) would be not to use bool maybe, but define a 4-constructor datatype and define a linear ordering on that type, where JF < BE < BN < JT, and then and4 is equivalent to min.

Related

How to include statement about type of the variable in the Isabelle/HOL term

I have following simple Isabelle/HOL theory:
theory Max_Of_Two_Integers_Real
imports Main
"HOL-Library.Multiset"
"HOL-Library.Code_Target_Numeral"
"HOL-Library.Code_Target_Nat"
"HOL-Library.Code_Abstract_Nat"
begin
definition two_integer_max_case_def :: "nat ⇒ nat ⇒ nat" where
"two_integer_max_case_def a b = (case a > b of True ⇒ a | False ⇒ b)"
lemma spec_final:
fixes a :: nat and b :: nat
assumes "a > b" (* and "b < a" *)
shows "two_integer_max_case_def a b = a"
using assms by (simp add: two_integer_max_case_def_def)
lemma spec_1:
fixes a :: nat and b :: nat
shows "a > b ⟹ two_integer_max_case_def a b = a"
by (simp add: two_integer_max_case_def_def)
lemma spec_2:
shows " (a ∈ nat set) ∧ (b ∈ nat set) ∧ (a > b) ⟹ two_integer_max_case_def a b = a"
by (simp add: two_integer_max_case_def_def)
end
Three lemmas try to express and prove that same statement, but progressively I am trying to move information from assumes and fixes towards the term. First 2 lemmas are correct, but the third (last) lemma is failing syntactically with the error message:
Type unification failed: Clash of types "_ ⇒ _" and "int"
Type error in application: incompatible operand type
Operator: nat :: int ⇒ nat
Operand: set :: ??'a list ⇒ ??'a set
My aim in this lemma is to move type information from the fixes towards the term/statement? How I make statements about the type of variable in the term (of inner syntax)?
Maybe I should use, if I am trying to avoid fixes clause (in which the variables may be declared), the full ForAll expression like:
lemma spec_final_3:
shows "∀ a :: nat . ∀ b :: nat . ( (a > b) ⟹ two_integer_max_case_def a b = a)"
by (simp add: two_integer_max_case_def_def)
But it is failing syntactically as well with the error message:
Inner syntax error: unexpected end of input⌂
Failed to parse prop
So - is it possible to include type statements in the term directly (without fixes clause) and is there any difference between fixes clause and type statement in the term? Maybe such differences start to appear during (semi)automatic proofs, e.g., when simplification tactics are applied or some other tactics?
nat set is interpreted as a function (that does not type correctly). The set of natural numbers can be expressed as UNIV :: nat set. Then, spec_2 reads
lemma spec_2:
shows "a ∈ (UNIV :: nat set) ∧ b ∈ (UNIV :: nat set) ∧ a > b ⟹
two_integer_max_case_def a b = a"
by (simp add: two_integer_max_case_def_def)
However, more natural way would be to include the type information in spec_1 without fixes clause:
lemma spec_1':
shows "(a :: nat) > (b :: nat) ⟹ two_integer_max_case_def a b = a"
by (simp add: two_integer_max_case_def_def)
∀ belongs to HOL, so the HOL implication should be used in spec_final_3:
lemma spec_final_3:
shows "∀ a :: nat. ∀ b :: nat. a > b ⟶ two_integer_max_case_def a b = a"
by (simp add: two_integer_max_case_def_def)
spec_1 can also be rewritten using an explicit meta-logic qualification (and implication) to look similar to spec_final_3:
lemma spec_1'':
shows "⋀ a :: nat. ⋀ b :: nat. a > b ⟹ two_integer_max_case_def a b = a"
by (simp add: two_integer_max_case_def_def)

What does "case _ of _" mean in Isabelle

While reading this answer on quotient types, I stumbled upon the construct "case _ of _ ⇒ _". Upon checking the manual, there's no such definition, but there are separate definitions for "case _" (§6.5.1) and "of _" (§6.4.3). Nonetheless, reading these definitions only confused me more about the meaning of this construct.
Consequently, I decided to come up with a simpler version of the lemma that I might be able to prove, which was this one:
lemma test: "(case n of (0::nat,0::nat) ⇒ (a,b) = n) ⟹ a = 0 ∧ b = 0"
In my head, after analyzing the context of the mentioned question, this statement should be equivalent to "(a,b) = (0,0) ⟹ a = 0 ∧ b = 0", which should be trivial to prove. Well, sledgehammer begs to differ:
"cvc4": Timed out
"z3": Timed out
"e": Timed out
"spass": Timed out
"remote_vampire": The prover gave up
So it seems like I'm misunderstanding what this construct is meant to represent.
In light of that, what is the meaning of the statement "case _ of _ ⇒ _" in Isabelle?
In Isabelle, a statement of the type case _ of _ ⇒ _ | _ ⇒ _ | _ ⇒ _ | ... is a form of pattern matching.
You might want to take a look at §2.5.4 of Isabelle's tutorial (§2.5.5 and §2.5.6 are also useful). This question on pattern matching and the Wikipedia article may provide more information about pattern matching in general.
What you are missing is that there not guarantee that the patterns are exhaustive. If no pattern matches, the result is undefined.
Nitpick actually finds a counter-example automatically on your lemma:
Nitpicking formula...
Kodkod warning: Interrupt
Nitpick found a counterexample:
Free variables:
a = 1
b = 0
n = (0, 1)
Let's plugin back the value of n:
lemma ‹(case (0,1) of (0::nat,0::nat) ⇒ (a,b) = n)⟹ a = 0 ∧ b = 0›
apply simp
(*
proof (prove)
goal (1 subgoal):
1. undefined ⟹ a = 0 ∧ b = 0
*)
EDIT, to answer the question below:
(case (0,1) of (0::nat,0::nat) ⇒ (a,b) = n) means roughly [1]:
(case_prod (0,1) of
(0::nat,0::nat) ⇒ (a,b) = n
| _ ⇒ undefined)
where case_prod is the destructor for pairs. Hence, if you don't match any of the patterns, the result is undefined.
[1] full output:
ML ‹#{term ‹(case (0,1) of (0::nat,0::nat) ⇒ (a,b) = n)›}›
As mentioned, nitpick is helpful here. Luckily the fix is simple.
lemma test: "(case n of (0::nat,0::nat) ⇒ (a,b) = n | _ ⇒ False) ⟹ a = 0 ∧ b = 0"
Because you don't bind any variables, rewriting your hypothesis into a conditional statement is trivial. Finally, you might want to look into the concept of pattern matching, specifically in the context of functional programming.
lemma test': "(case n of (0::nat,0::nat) ⇒ (a,b) = n | _ ⇒ (a,b) = (0,0)) = ((a,b) = (0,0))"
lemma test'': "(case n of (0::nat,0::nat) ⇒ (a,b) = n) = (if n = (0,0) then (a,b) = n else undefined)"

How do I convert a predicate to a function in Isabelle?

In Isabelle HOL, I have a predicate on two numbers like this:
definition f :: "nat ⇒ nat ⇒ bool"
where
...
I can prove that this predicate is morally a function:
lemma f_function:
fixes x :: nat
shows "∃! y . f x y""
...
Intuitively, this should be enough for me to construct a function f' :: nat ⇒ nat that is provably equivalent to f', i.e.:
lemma f'_correct:
"f x y = (f' x = y)"
But how do I do that?
definition f' :: "nat ⇒ nat"
where
"f' x ≡ ?"
What do I put in for the question mark?
The typical approach is to use the definite description operator THE:
definition f' :: "nat ⇒ nat" where "f' x = (THE y. f x y)"
If you have already proven that this y is unique, you can then use e.g. the theorem theI' to show that f x (f' x) holds and theI_unique to show that if f x y holds, then y = f' x.
For more information about THE, SOME, etc. see the following:
Isabelle/HOL: What does the THE construct denote?
Proving intuitive statements about THE in Isabelle

How to generate code for the existential quantifier

Here is a sample theory:
datatype ty = A | B | C
inductive test where
"test A B"
| "test B C"
inductive test2 where
"¬(∃z. test x z) ⟹ test2 x"
code_pred [show_modes] test .
code_pred [show_modes] test2 .
values "{x. test2 A}"
The generated code tries to enumerate over ty. And so it fails.
I'm tring to define an executable version of test predicate:
definition "test_ex x ≡ ∃y. test x y"
definition "test_ex_fun x ≡
Predicate.singleton (λ_. False)
(Predicate.map (λ_. True) (test_i_o x))"
lemma test_ex_code [code_abbrev, simp]:
"test_ex_fun = test_ex"
apply (intro ext)
unfolding test_ex_def test_ex_fun_def Predicate.singleton_def
apply (simp split: if_split)
But I can't prove the lemma. Could you suggest a better approach?
Existential quantifiers over an argument to an inductive predicate can be made executable by introducing another inductive predicate. For example:
inductive test2_aux where "test x z ==> test2_aux x"
inductive test2 where "~ test2_aux x ==> test2 x"
with appropriate code_pred statements. The free variable z in the premise of test2_aux acts like an existential. Since this transformation is canonical, code_pred has a preprocessor to do so:
code_pred [inductify] test2 .
does the job.
Well, values complains about the fact that ty is not of sort enum. So, in this particular case it is easiest to perform this instantiation.
instantiation ty :: enum
begin
definition enum_ty :: "ty list" where
"enum_ty = [A,B,C]"
definition "enum_all_ty f = list_all f [A,B,C]"
definition "enum_ex_ty f = list_ex f [A,B,C]"
instance
proof (intro_classes)
let ?U = "UNIV :: ty set"
show id: "?U = set enum_class.enum"
unfolding enum_ty_def
using ty.exhaust by auto
fix P
show "enum_class.enum_all P = Ball ?U P"
"enum_class.enum_ex P = Bex ?U P"
unfolding id enum_all_ty_def enum_ex_ty_def enum_ty_def by auto
show "distinct (enum_class.enum :: ty list)" unfolding enum_ty_def by auto
qed
Afterwards, your values-command evaluates without problems.
I thought that the lemma is unprovable, and I should find another approach. But it can be proven as follows:
lemma test_ex_code [code_abbrev, simp]:
"Predicate.singleton (λ_. False)
(Predicate.map (λ_. True) (test_i_o x)) = (∃y. test x y)"
apply (intro ext iffI)
unfolding Predicate.singleton_def
apply (simp_all split: if_split)
apply (metis SUP1_E mem_Collect_eq pred.sel test_i_o_def)
apply (intro conjI impI)
apply (smt SUP1_E the_equality)
apply (metis (full_types) SUP1_E SUP1_I mem_Collect_eq pred.sel test_i_o_def)
done
The interesting thing is that the lemma structure and the proof structure seems to be independent of the concrete predicate. I guess there could be a general solution for any predicate.

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.

Resources