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

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)

Related

Topological filters in Isabelle

I'm studying topological filters in Filter.thy
theory Filter
imports Set_Interval Lifting_Set
begin
subsection ‹Filters›
text ‹
This definition also allows non-proper filters.
›
locale is_filter =
fixes F :: "('a ⇒ bool) ⇒ bool"
assumes True: "F (λx. True)"
assumes conj: "F (λx. P x) ⟹ F (λx. Q x) ⟹ F (λx. P x ∧ Q x)"
assumes mono: "∀x. P x ⟶ Q x ⟹ F (λx. P x) ⟹ F (λx. Q x)"
typedef 'a filter = "{F :: ('a ⇒ bool) ⇒ bool. is_filter F}"
proof
show "(λx. True) ∈ ?filter" by (auto intro: is_filter.intro)
qed
I don't get this definition. It's quite convoluted so I'll simplify it first
The expression
F (λx. P x) could be simplified to F P (using eta reduction of lambda calculus). The predicate 'a ⇒ bool is really just a set 'a set. Similarly ('a ⇒ bool) ⇒ bool should be 'a set set. Then we could rewrite the axioms as
assumes conj: "P ∈ F ∧ Q ∈ F ⟹ Q ∩ P ∈ F"
assumes mono: "P ⊆ Q ∧ P ∈ F ⟹ Q ∈ F"
Now my question is about the True axiom. It is equivalent to
assumes True: "UNIV ∈ F"
This does not match with the definitions of filters that I ever saw.
The axiom should be instead
assumes True: "{} ∉ F" (* the name True is not very fitting anymore *)
The statement UNIV ∈ F is unnecessary because it follows from axiom mono.
So what's up with this definition that Isabelle provides?
The link provided by Javier Diaz has lots of explanations.
Turns out this is a definition of improper filter. The axiom True is necessary and does not follow from mono. If this axiom was missing then F could be defined as
F P = False
or in set-theory notation, F could be an empty set and mono and conj would then be satisfied vacuously.

Are there Isabelle/Isar proof strategies to prove lemmas about non-inductive definitions?

I have Isabelle theory with non-inductive definition (I would like to model algorithms avoiding induction as usually is done by industrial developers) and lemma that is stated for this definition:
theory Maximum
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_1:
fixes a :: nat and b :: nat
assumes "a > b"
shows "two_integer_max_case_def a b = a"
apply (induction b)
apply (induction a)
apply simp_all
done
end
Current proof state has generated 3 goals all of them are connected with induction (direct application of simp fails with Failed to apply proof method):
proof (prove)
goal (3 subgoals):
1. two_integer_max_case_def 0 0 = 0
2. ⋀a. two_integer_max_case_def a 0 = a ⟹
two_integer_max_case_def (Suc a) 0 =
Suc a
3. ⋀b. two_integer_max_case_def a b = a ⟹
two_integer_max_case_def a (Suc b) = a
My question is - are there proof methods, strategies that avoid induction and that can be applied in this simple case? Maybe somehow related with simp family of tactics?

How to setup code for finite set operations?

The following expression is evaluated fine:
value "foldr plus [1::nat, 2] 0"
But the following expressions:
value "Finite_Set.fold plus 0 (set [1::nat, 2])"
value "ffold plus 0 {|1::nat, 2|}"
raise error:
Wellsortedness error:
Type nat not of sort finite
No type arity nat :: finite
I understand that nat is not finite. So nat set is not finite too.
But is it possible to define code equations for these functions? I'm trying to prove one. But I'm stuck:
lemma finite_set_fold_code [code]:
"comp_fun_commute f ⟹
Finite_Set.fold f x (set xs) = foldr f xs x"
apply (rule Finite_Set.comp_fun_commute.fold_equality)
apply simp
apply (induct xs arbitrary: x)
apply (simp add: Finite_Set.fold_graph.emptyI)
apply auto
apply (rule Finite_Set.fold_graph.insertI)
UPDATE:
The lemma doesn't hold and can't be proven. Duplicates must be removed from a list.
interpretation nat_plus_commute: comp_fun_commute "plus :: nat ⇒ nat ⇒ nat"
by standard auto
lemma finite_set_nat_plus [code]:
"Finite_Set.fold plus (y :: nat) (set xs) = fold plus (remdups xs) y"
by (simp add: nat_plus_commute.fold_set_fold_remdups)
But I get the following warning:
Partially applied constant "Groups.plus_class.plus" on left hand side of equation, in theorem:
Finite_Set.fold op + ?y (set ?xs) ≡ fold op + (remdups ?xs) ?y
And still can't evaluate the expression.
UPDATE 2:
Actually I can evaluate it using schematic_goal:
schematic_goal g1:
"Finite_Set.fold plus 0 (set [1::nat, 2]) = ?x"
by (simp add: nat_plus_commute.fold_set_fold_remdups)
thm g1
What should I do to evaluate it using value?

Lifting a partial definition to a quotient type

I have a partially-defined operator (disj_union below) on sets that I would like to lift to a quotient type (natq). Morally, I think this should be ok, because it is always possible to find in the equivalence class some representative for which the operator is defined [*]. However, I cannot complete the proof that the lifted definition preserves the equivalence, because disj_union is only partially defined. In my theory file below, I propose one way I have found to define my disj_union operator, but I don't like it because it features lots of abs and Rep functions, and I think it would be hard to work with (right?).
What is a good way to define this kind of thing using quotients in Isabelle?
theory My_Theory imports
"~~/src/HOL/Library/Quotient_Set"
begin
(* A ∪-operator that is defined only on disjoint operands. *)
definition "X ∩ Y = {} ⟹ disj_union X Y ≡ X ∪ Y"
(* Two sets are equivalent if they have the same cardinality. *)
definition "card_eq X Y ≡ finite X ∧ finite Y ∧ card X = card Y"
(* Quotient sets of naturals by this equivalence. *)
quotient_type natq = "nat set" / partial: card_eq
proof (intro part_equivpI)
show "∃x. card_eq x x" by (metis card_eq_def finite.emptyI)
show "symp card_eq" by (metis card_eq_def symp_def)
show "transp card_eq" by (metis card_eq_def transp_def)
qed
(* I want to lift my disj_union operator to the natq type.
But I cannot complete the proof, because disj_union is
only partially defined. *)
lift_definition natq_add :: "natq ⇒ natq ⇒ natq"
is "disj_union"
oops
(* Here is another attempt to define natq_add. I think it
is correct, but it looks hard to prove things about,
because it uses abstraction and representation functions
explicitly. *)
definition natq_add :: "natq ⇒ natq ⇒ natq"
where "natq_add X Y ≡
let (X',Y') = SOME (X',Y').
X' ∈ Rep_natq X ∧ Y' ∈ Rep_natq Y ∧ X' ∩ Y' = {}
in abs_natq (disj_union X' Y')"
end
[*] This is a little bit like how capture-avoiding substitution is only defined on the condition that bound variables do not clash; a condition that can always be satisfied by renaming to another representative in the alpha-equivalence class.
What about something like this (just an idea):
definition disj_union' :: "nat set ⇒ nat set ⇒ nat set"
where "disj_union' X Y ≡
let (X',Y') = SOME (X',Y').
card_eq X' X ∧ card_eq Y' Y ∧ X' ∩ Y' = {}
in disj_union X' Y'"
lift_definition natq_add :: "natq ⇒ natq ⇒ natq"
is "disj_union'" oops
For the record, here is Ondřej's suggestion (well, a slight amendment thereof, in which only one of the operands is renamed, not both) carried out to completion...
(* A version of disj_union that is always defined. *)
definition disj_union' :: "nat set ⇒ nat set ⇒ nat set"
where "disj_union' X Y ≡
let Y' = SOME Y'.
card_eq Y' Y ∧ X ∩ Y' = {}
in disj_union X Y'"
(* Can always choose a natural that is not in a given finite subset of ℕ. *)
lemma nats_infinite:
fixes A :: "nat set"
assumes "finite A"
shows "∃x. x ∉ A"
proof (rule ccontr, simp)
assume "∀x. x ∈ A"
hence "A = UNIV" by fast
hence "finite UNIV" using assms by fast
thus False by fast
qed
(* Can always choose n naturals that are not in a given finite subset of ℕ. *)
lemma nat_renaming:
fixes x :: "nat set" and n :: nat
assumes "finite x"
shows "∃z'. finite z' ∧ card z' = n ∧ x ∩ z' = {}"
using assms
apply (induct n)
apply (intro exI[of _ "{}"], simp)
apply (clarsimp)
apply (rule_tac x="insert (SOME y. y ∉ x ∪ z') z'" in exI)
apply (intro conjI, simp)
apply (rule someI2_ex, rule nats_infinite, simp, simp)+
done
lift_definition natq_add :: "natq ⇒ natq ⇒ natq"
is "disj_union'"
apply (unfold disj_union'_def card_eq_def)
apply (rule someI2_ex, simp add: nat_renaming)
apply (rule someI2_ex, simp add: nat_renaming)
apply (metis card.union_inter_neutral disj_union_def empty_iff finite_Un)
done

code_pred in locales

I want to create an executable inductive within a locale. Without the locale everything works fine:
definition "P a b = True"
inductive test :: "'a ⇒ 'a ⇒ bool" where
"test a a" |
"test a b ⟹ P b c ⟹ test a c"
code_pred test .
However, when I try the same in a locale, it does not work:
locale localTest
begin
definition "P' a b = True"
inductive test' :: "'a ⇒ 'a ⇒ bool" where
"test' a a" |
"test' a b ⟹ P' b c ⟹ test' a c"
code_pred test'
end
The code_pred line in the locale returns the following error:
Not a constant: test'
You can give alternative introduction rules (see isabelle doc codegen section 4.2: Alternative introduction rules) and thereby avoid an interpretation. This also works for locales with parameters (and even for constants that are not defined inductively). A variant of your example having a parameter:
locale l =
fixes A :: "'a set"
begin
definition "P a b = True"
inductive test :: "'a ⇒ 'a ⇒ bool" where
"a ∈ A ⟹ test a a" |
"test a b ⟹ P b c ⟹ test a c"
end
We introduce a new constant
definition "foo A = l.test A"
And prove its introduction rules (thus the new constant is sound w.r.t. the old one).
lemma [code_pred_intro]:
"a ∈ A ⟹ foo A a a"
"foo A a b ⟹ l.P b c ⟹ foo A a c"
unfolding foo_def by (fact l.test.intros)+
Finally, we have to show that the new constant is also complete w.r.t. the old one:
code_pred foo by (unfold foo_def) (metis l.test.simps)
Expressed sloppily, locales are an abstraction mechanism that allows to introduce new constants relative to some hypothetical constants satisfying hypothetical properties, whereas code generation is more concrete (you need all the information that is required to implement a function, not just its abstract specification).
For that reason you first need to interpret a locale, before you can generate code. Of course, in your example there are no hypothetical constants and properties, thus an interpretation is trivial
interpretation test: localTest .
After that, you can use
code_pred test.test' .
Complete guess here, but I'm wondering if renaming test to test' has messed things up for you. (Consider changing code_pred test' to code_pred "test'".)

Resources