How to define a map of mappings? - isabelle

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.

Related

How to define an inductive predicate on fset?

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?

How to replace existentially quantified variable?

Here is a simple type system:
datatype type =
VoidType
| IntegerType
| RealType
| StringType
datatype val =
VoidVal
| IntegerVal int
| RealVal real
| StringVal string
fun type_of :: "val ⇒ type" where
"type_of (VoidVal) = VoidType"
| "type_of (IntegerVal _) = IntegerType"
| "type_of (RealVal _) = RealType"
| "type_of (StringVal _) = StringType"
with type conformance relation:
inductive less_type :: "type ⇒ type ⇒ bool" (infix "<" 65) where
"IntegerType < RealType"
Integer values can be casted to corresponding real values:
inductive cast :: "val ⇒ val ⇒ bool" where
"cast (IntegerVal x) (RealVal x)"
I'm trying to prove the following lemma. If type of a variable x conforms to RealType, then there exists a value y with type RealType and x can be casted to y.
lemma is_castable_to_real:
"type_of x < RealType ⟹ ∃y. type_of y = RealType ∧ cast x y"
apply (rule exI[of _ "RealVal v"])
I can prove the generic lemma using cases tactics:
lemma is_castable:
"type_of x < τ ⟹ ∃y. type_of y = τ ∧ cast x y"
by (cases x; cases τ; auto simp add: less_type.simps cast.simps)
But I'm trying to understand how to treat existential quantifiers in lemmas. So I'm trying to provide a concrete example RealVal v for y:
type_of x < RealType ⟹ ∃v. type_of (RealVal v) = RealType ∧ cast x (RealVal v)
The problem is that I get the following proposition instead:
type_of x < RealType ⟹ type_of (RealVal v) = RealType ∧ cast x (RealVal v)
What is the kind of variable v? Is it universally quantified variable? How to make it existentially quantified one?
To prove an existential, you can give a concrete example.
In your case, this example can be derived from the assumption of the lemma.
lemma is_castable_to_real:
assumes subtype_of_real: "type_of x < RealType"
shows "∃y. type_of y = RealType ∧ cast x y"
proof -
have "type_of x = IntegerType"
using subtype_of_real less_type.cases by blast
from this obtain i where x_def: "x = IntegerVal i"
by (cases x, auto)
(* prove it for concrete example (RealVal i) *)
have "type_of (RealVal i) = RealType ∧ cast x (RealVal i)"
by (auto simp add: x_def cast.intros)
(* From the concrete example, the existential statement follows: *)
thus "∃y. type_of y = RealType ∧ cast x y" ..
qed
If you just use v before obtaining or defining it somehow, the value will be similar to undefined. It has the correct type, but you do not know anything about it.
If you start the proof without the dash (-) Isabelle will use the default tactic and you would get the subgoal type_of ?y = RealType ∧ cast x ?y. Here ?y is a schematic variable and you can later provide any value that was already available before starting the proof. Maybe this is the kind of variable you get for v, but it is still not clear how you got to the last line in your question.

How to define a supremum on a set?

I'm trying to describe a type system of a programming language. It has a common subtype for any types (VoidType) and a common supertype for any types (AnyType):
datatype type =
VoidType |
AnyType |
BooleanType |
EBooleanType |
RealType |
IntegerType |
UnlimNatType |
StringType
fun subtype_strict_fun :: "type ⇒ type ⇒ bool" (infix "<:sf" 55) where
"_ <:sf VoidType = False"
| "VoidType <:sf _ = True"
| "AnyType <:sf _ = False"
| "_ <:sf AnyType = True"
| "BooleanType <:sf EBooleanType = True"
| "IntegerType <:sf RealType = True"
| "UnlimNatType <:sf IntegerType = True"
| "UnlimNatType <:sf RealType = True"
| "_ <:sf _ = False"
definition subtype_fun :: "type ⇒ type ⇒ bool" (infix "<:f" 55) where
"x <:f y ≡ x = y ∨ x <:sf y"
I'm trying to instantinate type as ccpo:
instantiation type :: ccpo
begin
definition "less_eq = subtype_fun"
definition "less = subtype_strict_fun"
lemma subtype_strict_eq_subtype:
"(x <:sf y) = (x <:f y ∧ ¬ y <:f x)"
by (cases x; cases y; simp add: subtype_fun_def)
lemma subtype_refl:
"x <:f x"
by (simp add: subtype_fun_def)
lemma subtype_trans:
"x <:f y ⟹ y <:f z ⟹ x <:f z"
by (cases x; cases y; cases z; simp add: subtype_fun_def)
lemma subtype_antisym:
"x <:f y ⟹ y <:f x ⟹ x = y"
by (cases x; cases y; simp add: subtype_fun_def)
instance
apply intro_classes
apply (simp add: less_eq_type_def less_type_def subtype_strict_eq_subtype)
apply (simp add: less_eq_type_def less_type_def subtype_refl)
apply (metis less_eq_type_def subtype_trans)
apply (metis less_eq_type_def subtype_antisym)
end
Could you suggest how to define a supremum function Sup :: OCL.type set ⇒ OCL.type?
The type OCL.type is finite, so all sets of type OCL.type set are finite, too. Moreover, there is also a top element in your hierarchy. Therefore, you can define the Sup operation simply by folding sup over the given set. The locale comm_monoid_set provides the necessary infrastructure. First, instantiate the type classes semilattice_sup and order_top. Then interpret comm_monoid_set:
interpretation ocl': abel_semigroup sup "top :: OCL.type" <proof>
interpretation ocl: comm_monoid_set sup "top :: OCL.type" <proof>
This generates the folded sup operation over sets under the name ocl.F. So,
definition "Sup_ocl = ocl.F id"
gives you a definition for the Sup operation. This is a general construction that works for any finite upper semilattice with a top element. But it will not give you any dedicated setup for reasoning about the OCL.type hierarchy in particular. You'll have to derive appropriate rules yourself.

How to prove that addition of a new variable to the expression doesn't change its semantics?

Here is very simple language:
type_synonym vname = "string"
type_synonym bool3 = "bool option"
type_synonym env = "vname ⇒ bool3"
datatype exp = Let vname bool exp | Var vname | And exp exp
primrec val :: "exp ⇒ env ⇒ bool3" where
"val (Let var init body) e = val body (e(var ↦ init))"
| "val (Var var) e = e var"
| "val (And a b) e = (case (val a e, val b e) of
(Some x, Some y) ⇒ Some (x ∧ y) | _ ⇒ None)"
I'm trying to prove that if an expression doesn't have any free variables, then I can declare any new variable at the begining of the expression. I've tried 3 approaches to prove it.
1) defined function checks whether the expression's value is well defined (= all used variables are declared):
primrec defined :: "exp ⇒ env ⇒ bool" where
"defined (Let var init body) e = defined body (e(var ↦ init))"
| "defined (Var var) e = (var : dom e)"
| "defined (And a b) e = (defined a e ∧ defined b e)"
lemma var_intro: "defined exp env ⟹ defined exp (env(x ↦ init))"
apply (induct exp)
apply (simp_all split: if_splits)
2) The alternative approach is to collect all free variables from the expression. And if the expression doesn't contain any then we can add a new variable to the environment:
primrec freeVars :: "exp ⇒ vname set ⇒ vname set" where
"freeVars (Let var init body) e = freeVars body (insert var e)"
| "freeVars (Var var) e = (if var ∈ e then {} else {var})"
| "freeVars (And a b) e = freeVars a e ∪ freeVars b e"
lemma var_intro2: "freeVars exp {} = {} ⟹ freeVars exp {x} = {}"
apply (induct exp)
apply (simp_all split: if_splits)
3) And the last approach is to eliminate all bounded variables from the environment:
primrec isFree :: "vname ⇒ exp ⇒ bool" where
"isFree x (Let var init body) = (if var = x then False else isFree x body)"
| "isFree x (Var var) = (var = x)"
| "isFree x (And a b) = (isFree x a ∨ isFree x b)"
lemma var_elim: "¬ isFree x exp ⟹ val exp (env(x ↦ init)) = val exp (env)"
apply (induct exp)
apply (simp_all split: if_splits)
I can't prove any of the lemmas. Could you suggest a solution?
Your proofs will probably require you to set env to arbitrary in the induction or the proofs will not work. With that, you will probably be able to prove the properties you stated, but I think it'll be a bit ugly because both your definitions and your lemma statements are unnecessarily specific, which can make proofs more painful.
In particular, your notion of ‘free variable w.r.t. an environment’ seems a bit unnecessarily complicated to me. I think it's easier to use the following:
primrec freeVars :: "exp ⇒ vname set" where
"freeVars (Let var init body) = freeVars body - {var}"
| "freeVars (Var var) = {var}"
| "freeVars (And a b) = freeVars a ∪ freeVars b"
The statement ‘expression exp is well-defined w.r.t. an environment env’ is then simply freeVars exp ⊆ dom env.
Then it is obvious that any expression that is well-defined w.r.t. some environment is also well-defined with any bigger environment.
1) You have to lift the communicative property of element insertion on sets into that of state updates on maps, on which your lemma is based.
lemma defined_dom: "defined exp env ⟹ dom env = dom env' ⟹ defined exp env'"
by (induction exp arbitrary: env env'; auto)
lemma defined_comm: "defined exp (env(x↦a, y↦b)) ⟹ defined exp (env(y↦b, x↦a))"
by (auto elim!: defined_dom)
lemma var_intro: "defined exp env ⟹ defined exp (env(x ↦ init))"
by (induction exp arbitrary: env; simp add: defined_comm)
2) If your lemma is based on sets, you will also need the communicative lemma, which is already in the library:
lemma var_intro2': "freeVars exp s = {} ⟹ freeVars exp (insert x s) = {}"
by (induction exp arbitrary: s x; force simp: insert_commute)
lemma var_intro2: "freeVars exp {} = {} ⟹ freeVars exp {x} = {}"
using var_intro2' .
3) Similarly:
lemma var_elim: "¬ isFree x exp ⟹ val exp (env(x ↦ init)) = val exp (env)"
by (induction exp arbitrary: env; simp add: fun_upd_twist split: if_splits)

How to define a linear ordering on a type?

I'm trying to define a conjunction function for 4-valued logic (false, true, null, and error). In my case the conjunction is equivavlent to min function on linear order false < error < null < true.
datatype bool4 = JF | JT | BN | BE
instantiation bool4 :: linear_order
begin
fun leq_bool4 :: "bool4 ⇒ bool4 ⇒ bool" where
"leq_bool4 JF b = True"
| "leq_bool4 BE b = (b = BE ∨ b = BN ∨ b = JT)"
| "leq_bool4 BN b = (b = BN ∨ b = JT)"
| "leq_bool4 JT b = (b = JT)"
instance proof
fix x y z :: bool4
show "x ⊑ x"
by (induct x) simp_all
show "x ⊑ y ⟹ y ⊑ z ⟹ x ⊑ z"
by (induct x; induct y) simp_all
show "x ⊑ y ⟹ y ⊑ x ⟹ x = y"
by (induct x; induct y) simp_all
show "x ⊑ y ∨ y ⊑ x"
by (induct x; induct y) simp_all
qed
end
definition and4 :: "bool4 ⇒ bool4 ⇒ bool4" where
"and4 a b ≡ minimum a b"
I guess there must be an easier way to define a linear order in Isabelle HOL. Could you suggest a simplification of the theory?
You can use the "Datatype_Order_Generator" AFP entry.
Then it's as simple as importing "$AFP/Datatype_Order_Generator/Order_Generator" and declaring derive linorder "bool4". Note that the constructors must be declared in the order you want them when defining your datatype.
Details on how to download and use the AFP locally can be found here.

Resources