How to define an inductive predicate on fset? - isabelle

I defined 2 kinds of values and a cast function:
theory FSetIndTest
imports Main "~~/src/HOL/Library/FSet"
begin
datatype val1 = A | B
datatype val2 = C | D
inductive cast_val :: "val1 ⇒ val2 ⇒ bool" where
"cast_val A C"
| "cast_val B D"
Also, I defined cast function for a list of values:
inductive cast_list :: "val1 list ⇒ val2 list ⇒ bool" where
"cast_list [] []"
| "cast_val x y ⟹ cast_list xs ys ⟹ cast_list (x#xs) (y#ys)"
code_pred [show_modes] cast_list .
values "{x. cast_list [A, B] x}"
values "{x. cast_list x [C, D]}"
I need to define a similar function for fset.
Here is a 1st attempt. It seems that the generated implementation is non-terminating:
inductive cast_fset1 :: "val1 fset ⇒ val2 fset ⇒ bool" where
"cast_fset1 {||} {||}"
| "cast_val x y ⟹ cast_fset1 xs ys ⟹
cast_fset1 (finsert x xs) (finsert y ys)"
code_pred [show_modes] cast_fset1 .
(*values "{x. cast_fset1 {|A, B|} x}"*)
Here is another attempt. It doesn't allow to calculate second argument given the 1st argument:
inductive cast_fset2 :: "val1 fset ⇒ val2 fset ⇒ bool" where
"⋀x y. x |∈| xs ⟹ y |∈| ys ⟹ cast_val x y ⟹
cast_fset2 xs ys"
code_pred [show_modes] cast_fset2 .
The following version works fine, but it use a functional cast_val_fun instead of inductive cast_val. And also it works only in one direction:
fun cast_val_fun :: "val1 ⇒ val2" where
"cast_val_fun A = C"
| "cast_val_fun B = D"
inductive cast_fset3 :: "val1 fset ⇒ val2 fset ⇒ bool" where
"cast_fset3 x (fimage cast_val_fun x)"
code_pred [show_modes] cast_fset3 .
values "{x. cast_fset3 {|A, B|} x}"
Here is one more non-terminating implementation:
inductive cast_fset4 :: "val1 fset ⇒ val2 fset ⇒ bool" where
"cast_list xs ys ⟹
cast_fset4 (fset_of_list xs) (fset_of_list ys)"
code_pred [show_modes] cast_fset4 .
(*values "{x. cast_fset4 {|A, B|} x}"*)
Could you suggest how to define an inductive version of the cast function for fsets with terminating implementation?
UPDATE:
The following code is generated for cast_fset1:
cast_fset1_o_o =
sup (Predicate.bind (Predicate.single ()) (λx. case x of () ⇒ Predicate.single ({||}, {||})))
(Predicate.bind (Predicate.single ())
(λx. case x of
() ⇒
Predicate.bind cast_fset1_o_o
(λx. case x of
(xs_, ys_) ⇒
Predicate.bind cast_val_o_o
(λxa. case xa of
(x_, y_) ⇒ Predicate.single (finsert x_ xs_, finsert y_ ys_)))))
cast_fset1_i_o ?xa =
sup (Predicate.bind (Predicate.single ?xa)
(λx. if x = {||} then Predicate.single {||} else bot))
(Predicate.bind (Predicate.single ?xa)
(λx. Predicate.bind cast_fset1_o_o
(λxa. case xa of
(xs_, ys_) ⇒
Predicate.bind cast_val_o_o
(λxb. case xb of
(xa_, y_) ⇒
if x = finsert xa_ xs_ then Predicate.single (finsert y_ ys_)
else bot))))
cast_fset1_i_o invokes cast_fset1_o_o. The later one is non-terminating. I think it's because fset doesn't have any constructors. But I don't understand how to fix it. How to generate code for datatypes without constructors?
UPDATE 2:
The same behavior for multisets:
code_pred [show_modes] rel_mset' .
values 2 "{x. (rel_mset' cast_val) {#A, B#} x}"
returns {mset [D, C], mset [C, D]} ∪ ...
mset [D, C] and mset [C, D] are equal. Abs_fset {D, C} and Abs_fset {C, D} returned by the following expression are equal too:
values 2 "{x. cast_fset1 {|A, B|} x}"
How to define an inductive predicate for fset, multiset, ... so it calculates sets with some canonicial list representation and doesn't return duplicate values?

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.

Proving a type classed theorem in Isabelle

I am to prove a triviality using type classes:
class order =
fixes lesseq :: " 'a ⇒ 'a ⇒ bool" (infix "≼" 50)
assumes refl: "x ≼ x"
and trans: "x ≼ y ⟹ y ≼ z ⟹ x ≼ z"
and antisym: "x ≼ y ⟹ y ≼ x ⟹ x = y"
begin
theorem "(myle:: ('b::order) ⇒ 'b ⇒ bool) x x"
proof -
show ?thesis by (rule refl)
qed
end
Here, Isabelle/jEdit highlights by (rule refl) in pink and says
Failed to apply initial proof method⌂:
goal (1 subgoal):
1. myle x x
What is the problem here? Otherwise the proof seems to go through.
myle and ≼ are not the same function.
The type annotation (myle:: ('b::order) ⇒ 'b ⇒ bool) just states that myle is a function that takes two elements of type 'b and returns a boolean and that 'b is a type belonging to the order typeclass.
If you want to prove something about ≼ just use the same symbol or the name lesseq.

How to use different code lemmas for different modes of inductive predicate?

(The question is related to How to define an inductive predicate on fset? but a more concrete)
Here is a simple theory with 2 kinds of values and a casting predicate:
theory FSetIndTest
imports Main "~~/src/HOL/Library/FSet"
begin
datatype val1 = A | B
datatype val2 = C | D
inductive cast_val :: "val1 ⇒ val2 ⇒ bool" where
"cast_val A C"
| "cast_val B D"
code_pred [show_modes] cast_val .
fun cast_val_fun :: "val1 ⇒ val2" where
"cast_val_fun A = C"
| "cast_val_fun B = D"
fun cast_val_fun_inv :: "val2 ⇒ val1" where
"cast_val_fun_inv C = A"
| "cast_val_fun_inv D = B"
I'm trying to define a cast predicate for fsets. It works fine in i ⇒ o ⇒ bool mode, but doesn't support o ⇒ i ⇒ bool mode:
inductive cast_fset1 :: "val1 fset ⇒ val2 fset ⇒ bool" where
"cast_fset1 {||} {||}"
| "cast_val x y ⟹ cast_fset1 xs ys ⟹
cast_fset1 (finsert x xs) (finsert y ys)"
lemma cast_fset1_left [code_pred_intro]:
"fimage cast_val_fun xs = ys ⟹ cast_fset1 xs ys"
apply (induct xs arbitrary: ys)
apply (simp add: cast_fset1.intros(1))
by (metis (full_types) cast_fset1.intros(2) cast_val.intros(1) cast_val.intros(2) cast_val_fun.simps(1) cast_val_fun.simps(2) fimage_finsert val1.exhaust)
lemma cast_fset1_left_inv:
"cast_fset1 xs ys ⟹
fimage cast_val_fun xs = ys"
apply (induct rule: cast_fset1.induct)
apply simp
using cast_val.simps by auto
code_pred [show_modes] cast_fset1
by (simp add: cast_fset1_left_inv)
values "{x. cast_fset1 {|A, B|} x}"
So I try to define a code lemma for both arguments. And as result only i ⇒ i ⇒ bool mode is supported:
inductive cast_fset2 :: "val1 fset ⇒ val2 fset ⇒ bool" where
"cast_fset2 {||} {||}"
| "cast_val x y ⟹ cast_fset2 xs ys ⟹
cast_fset2 (finsert x xs) (finsert y ys)"
lemma cast_fset2_code [code_pred_intro]:
"fimage cast_val_fun xs = ys ⟹ cast_fset2 xs ys"
"fimage cast_val_fun_inv ys = xs ⟹ cast_fset2 xs ys"
apply (auto)
apply (induct xs arbitrary: ys)
apply (simp add: cast_fset2.intros(1))
apply (metis (full_types) cast_fset2.intros(2) cast_val.intros(1) cast_val.intros(2) cast_val_fun.simps(1) cast_val_fun.simps(2) fimage_finsert val1.exhaust)
apply (induct ys arbitrary: xs)
apply (simp add: cast_fset2.intros(1))
by (smt cast_fset2.intros(2) cast_val.intros(1) cast_val.intros(2) cast_val_fun_inv.elims cast_val_fun_inv.simps(1) fimage_finsert)
lemma cast_fset2_code_inv:
"cast_fset2 xs ys ⟹ fimage cast_val_fun xs = ys"
"cast_fset2 xs ys ⟹ fimage cast_val_fun_inv ys = xs"
apply (induct rule: cast_fset2.induct)
apply simp
apply simp
using cast_val.simps cast_val_fun.simps(1) apply auto[1]
using cast_val.simps by auto
code_pred [show_modes] cast_fset2
by (simp add: cast_fset2_code_inv(1))
I'm trying to use [code] annotation instead of [code_pred_intro]:
inductive cast_fset3 :: "val1 fset ⇒ val2 fset ⇒ bool" where
"cast_fset3 {||} {||}"
| "cast_val x y ⟹ cast_fset3 xs ys ⟹
cast_fset3 (finsert x xs) (finsert y ys)"
lemma cast_fset3_left:
"fimage cast_val_fun xs = ys ⟹ cast_fset3 xs ys"
apply (induct xs arbitrary: ys)
apply (simp add: cast_fset3.intros(1))
by (metis (full_types) cast_fset3.intros(2) cast_val.intros(1) cast_val.intros(2) cast_val_fun.simps(1) cast_val_fun.simps(2) fimage_finsert val1.exhaust)
lemma cast_fset3_left_inv:
"cast_fset3 xs ys ⟹
fimage cast_val_fun xs = ys"
apply (induct rule: cast_fset3.induct)
apply simp
using cast_val.simps by auto
lemma cast_fset3_left_code [code]:
"fimage cast_val_fun xs = ys ⟷
cast_fset3 xs ys"
using cast_fset3_left cast_fset3_left_inv by blast
But I get the following warning and the lemma is ignored at all:
Partially applied constant "FSetIndTest.cast_val_fun" on left hand side of equation, in theorem:
cast_val_fun |`| ?xs = ?ys ≡ cast_fset3 ?xs ?ys
Is it possible to use different code lemmas for different modes (i ⇒ o ⇒ bool, o ⇒ i ⇒ bool) of an inductive predicate? How to fix last lemma? Why I get this warning?
Code generation for an inductive predicate always operates on the same set of introduction rules; however you are always free to introduce a copy of an existing inductive predicate and equip that with a different set of introduction rules.
The attribute [code] is just for equations, not for introduction rules.

How to define a map of mappings?

There are 2 kinds of values in the theory - val1 and val2:
type_synonym bool3 = "bool option"
datatype val1 = BVal1 bool3 | IVal1 int | SVal1 string
datatype val2 = BVal2 bool | IVal2 int
I can map them using either the following inductive predicate:
inductive map_val_ind :: "val1 ⇒ val2 ⇒ bool" where
"map_val_ind (BVal1 (Some v)) (BVal2 v)"
| "map_val_ind (IVal1 v) (IVal2 v)"
code_pred [show_modes] map_val_ind .
values "{t. map_val_ind (BVal1 (Some True)) t}"
or the following function:
fun map_val :: "val1 ⇒ val2 option" where
"map_val (BVal1 (Some v)) = Some (BVal2 v)"
| "map_val (IVal1 v) = Some (IVal2 v)"
| "map_val _ = None"
value "map_val (BVal1 (Some True))"
I prefer inductive predicate, because it's bidirectional.
Also I need to map environments of variables:
type_synonym vname = "string"
type_synonym 'a env = "vname ⇒ 'a option"
1) Here is a first attempt to define the mapping:
definition map_env :: "val1 env ⇒ val2 env ⇒ bool" where
"map_env env1 env2 ≡ ∀x. ∃y z.
env1 x = Some y ∧
env2 x = Some z ∧
map_val_ind y z"
The problem is that it's not constructive, and I don't understand how to map an environment using this definition.
2) Here is a functional definition:
definition map_env_fun :: "val1 env ⇒ (val2 env) option" where
"map_env_fun env = (if ∀x. ∃y z. env x = Some y ∧ map_val y = Some z
then Some (λx. map_val (the (env x)))
else None)"
value "map_env_fun [''x'' ↦ BVal1 (Some True)]"
But I get the following error:
Wellsortedness error
(in code equation map_env_fun ?env ≡
if ∀x. ∃y z. equal_option_inst.equal_option (?env x) (Some y) ∧
equal_option_inst.equal_option (map_val y) (Some z)
then Some (λx. map_val (the (?env x))) else None,
with dependency "Pure.dummy_pattern" -> "map_env_fun"):
Type char list not of sort enum
No type arity list :: enum
3) And here is an inductive version:
inductive map_env_ind :: "val1 env ⇒ val2 env ⇒ bool" where
"env1 x = Some y ⟹
env2 x = Some z ⟹
map_val_ind y z ⟹
map_env_ind env1 env2"
code_pred [show_modes] map_env_ind .
The problem is that code_pred can't infer any execution modes.
How to define such an environment mapping? I prefer an inductive version, because it's bidirectional and it's easier to prove lemmas for inductive predicates.

What happens during function proofs

I am trying to proof a property of the icmp6 checksum function (sum 16bit integers, add carry, invert 16bit integer).
I defined the functions in isabelle. (I know my proofs are terrible)
But for some reason, isabelle can't proof something about the icmp_csum function, it wants to have.
When I replace the oops in the paste with done it produces thousands of lines that just says:
"linarith_split_limit exceeded (current value is 9)"
theory Scratch
imports Main Int List
begin
fun norm_helper :: "nat ⇒ nat" where
"norm_helper x = (let y = divide x 65536 in (y + x - y * 65536))"
lemma "x ≥ 65536 ⟹ norm_helper x < x" by simp
lemma h: "norm_helper x ≤ x" by simp
fun normalize :: "nat ⇒ nat" where
"normalize x = (if x ≥ 65536
then normalize (norm_helper x)
else x)"
inductive norm_to :: "nat ⇒ nat ⇒ bool" where
"(x < 65536) ⟹ norm_to x x"
| "norm_to y z ⟹ y = norm_helper x ⟹ norm_to x z"
lemma ne: "norm_to x y ⟹ y = normalize x"
apply (induct x y rule: norm_to.induct) by simp+
lemma i: "norm_to x y ⟹ x ≥ y"
apply (induct x y rule: norm_to.induct) by simp+
lemma l: "norm_to x y ⟹ y < 65536"
apply (induct x y rule: norm_to.induct) by simp+
lemma en: "y = normalize x ⟹ norm_to x y"
apply (induct x rule: normalize.induct)
proof -
fix x :: nat
assume 1: "(x ≥ 65536 ⟹ y = Scratch.normalize (norm_helper x) ⟹ norm_to (norm_helper x) y)"
assume 2: "y = Scratch.normalize x"
show "norm_to x y"
proof (cases "x ≥ 65536")
show "¬ 65536 ≤ x ⟹ norm_to x y"
using norm_to.intros(1)[of x] 2 by simp
{
assume s: "65536 ≤ x"
have d: "y = normalize (norm_helper x)" using 2 s by simp
show "65536 ≤ x ⟹ norm_to x y"
using 1 d norm_to.intros(2)[of "norm_helper x" y x]
by blast
}
qed
qed
lemma "normalize x ≤ x" using en i by simp
lemma n[simp]: "normalize x < 65536" using en l by blast
fun sum :: "nat list ⇒ nat" where
"sum [] = 0"
| "sum (x#xs) = x + sum xs"
fun csum :: "nat list ⇒ nat" where
"csum xs = normalize (sum xs)"
fun invert :: "nat ⇒ nat" where
"invert x = 65535 - x"
lemma c: "csum xs ≤ 65535" using n[of "sum xs"] by simp
lemma ic: "invert (csum xs) ≥ 0" using c[of xs] by blast
lemma asdf:
assumes "xs = ys"
shows "invert (csum xs) = invert (csum ys)"
using HOL.arg_cong[of "csum xs" "csum ys" invert,
OF HOL.arg_cong[of xs ys csum]] assms(1)
by blast
function icmp_csum :: "nat list ⇒ nat" where
"icmp_csum xs = invert (csum xs)"
apply simp
apply (rule asdf)
apply simp
oops
end
I have no idea why there is tracing output from linarith there, but given that your definition is neither recursive nor performs pattern matching, you can write it as a definition:
definition icmp_csum :: "nat list ⇒ nat" where
"icmp_csum xs = invert (csum xs)"
Another possibility is to change invert to a definition instead of a fun. (In general, if it's neither recursive nor performs pattern matching, definition is preferable because it has much less overhead than fun.)
NB, just import Main, not Main Int List.
Edit: An explanation from Tobias Nipkow on the mailing list:
This is a known issue. In the outdated LNCS 2283 you can find a discussion what to do about it in Section 3.5.3 Simplification and Recursive Functions. The gist: don't use "if", use pattern matching or "case". Or disable if_split.

Resources