How to define an abstract collection data type? - isabelle

There are 4 kinds of collections in my theory. For each collection type I defined count and for_all operations:
theory MyCollections
imports Main
"~~/src/HOL/Library/Dlist"
"~~/src/HOL/Library/Multiset"
begin
typedef 'a mybag = "UNIV :: 'a multiset set" .. (* not unique, not ordered *)
typedef 'a myseq = "UNIV :: 'a list set" .. (* not unique, ordered *)
typedef 'a myset = "UNIV :: 'a set set" .. (* unique, not ordered *)
typedef 'a myord = "UNIV :: 'a dlist set" .. (* unique, ordered *)
setup_lifting type_definition_mybag
setup_lifting type_definition_myseq
setup_lifting type_definition_myset
setup_lifting type_definition_myord
lift_definition mybag_count :: "'a mybag ⇒ 'a ⇒ nat" is "Multiset.count" .
lift_definition myseq_count :: "'a myseq ⇒ 'a ⇒ nat" is "count_list" .
lift_definition myset_count :: "'a myset ⇒ 'a ⇒ nat" is "(λxs x. if x ∈ xs then 1 else 0)" .
lift_definition myord_count :: "'a myord ⇒ 'a ⇒ nat" is "(λxs x. if Dlist.member xs x then 1 else 0)" .
lift_definition mybag_for_all :: "'a mybag ⇒ ('a ⇒ bool) ⇒ bool" is "Multiset.Ball" .
lift_definition myseq_for_all :: "'a myseq ⇒ ('a ⇒ bool) ⇒ bool" is "(λxs f. list_all f xs)" .
lift_definition myset_for_all :: "'a myset ⇒ ('a ⇒ bool) ⇒ bool" is "Ball" .
lift_definition myord_for_all :: "'a myord ⇒ ('a ⇒ bool) ⇒ bool" is "(λxs f. list_all f (list_of_dlist xs))" .
I need to define polymorphic operations (includes and includes_all) for these collection types:
lift_definition mybag_includes :: "'a mybag ⇒ 'a ⇒ bool" is
"(λxs x. mybag_count xs x > 0)" .
lift_definition myseq_includes :: "'a myseq ⇒ 'a ⇒ bool" is
"(λxs x. myseq_count xs x > 0)" .
lift_definition myset_includes :: "'a myset ⇒ 'a ⇒ bool" is
"(λxs x. myset_count xs x > 0)" .
lift_definition myord_includes :: "'a myord ⇒ 'a ⇒ bool" is
"(λxs x. myord_count xs x > 0)" .
lift_definition mybag_mybag_includes_all :: "'a mybag ⇒ 'a mybag ⇒ bool" is
"(λxs ys. mybag_for_all ys (mybag_includes xs))" .
lift_definition mybag_myseq_includes_all :: "'a mybag ⇒ 'a myseq ⇒ bool" is
"(λxs ys. myseq_for_all ys (mybag_includes xs))" .
(* ... and 14 more similar operations for other type combinations *)
Some test cases:
value "mybag_myseq_includes_all (Abs_mybag {#1::nat,2,4,5,3,4#}) (Abs_myseq [1::nat,2])"
value "mybag_myseq_includes_all (Abs_mybag {#1::nat,2,4,5,3,4#}) (Abs_myseq [1::nat,7])"
The problem is that these operations are structurally identical and I don't want to duplicate them. I try to define an abstract collection type:
typedecl 'a mycol
consts
mycol_count :: "'a mycol ⇒ 'a ⇒ nat"
mycol_for_all :: "'a mycol ⇒ ('a ⇒ bool) ⇒ bool"
definition mycol_includes :: "'a mycol ⇒ 'a ⇒ bool" where
"mycol_includes xs x ≡ mycol_count xs x > 0"
definition mycol_includes_all :: "'a mycol ⇒ 'a mycol ⇒ bool" where
"mycol_includes_all xs ys ≡ mycol_for_all xs (mycol_includes ys)"
But I have no idea how to derive concrete collection types from the abstract one:
typedef 'a mybag = "{xs :: 'a mycol. ???}" ..
typedef 'a myseq = "{xs :: 'a mycol. ???}" ..
typedef 'a myset = "{xs :: 'a mycol. ???}" ..
typedef 'a myord = "{xs :: 'a mycol. ???}" ..

Once you have axiomatized the abstract collections type, you cannot refine it inside the logic any more. So the proposed approach does not work. But if you leave the container type abstract (as a type variable), then this is possible. I recommend to do that using locales:
locale container =
fixes count :: "'container => 'a => nat"
and for_all :: "'container => ('a => bool) => bool"
begin
definition "includes" where "includes C x <--> count C x > 0"
definition includes_all where "includes_all C C' <--> for_all C (includes C')"
end
Then, you can define your different collection types as usual and obtain the common operations by locale interpretation. For example,
interpretation mybag: container mybag_count mybag_forall .
generates the abbreviations mybag.includes and mybag.includes_all. Additionally, all theorems that are proven in the locale container are also specialized to mybag and prefixed with mybag.

Related

Isabelle instantiation with type parameter

I'm trying to get this to work
no_notation Nil ("[]") and Cons (infixr "#" 65) and append (infixr "#" 65) and plus (infixl "+" 65)
class plus =
fixes plus :: "'a ⇒ 'a ⇒ 'a" (infixl "+" 65)
datatype 'a list =
Nil ("[]")
| Cons 'a "'a list" (infixr "#" 65)
instantiation "'a list" :: plus
begin
primrec plus_list :: "'a list ⇒ 'a list ⇒ 'a list" where
"plus_list [] ys = ys" |
"plus_list (x#xs) ys = x # (plus_list xs ys)"
instance ..
end
essentially lists are free monoids under concatenation. How do I express this fact using type-classes?
At the moment I get
Undefined type name: "'a list"⌂
in this line
instantiation "'a list" :: plus
^^^^^^^^^
If I get rid of 'a I get
Bad number of arguments for type constructor: "Test.list"
Even if I try to specialize to nat list I get
Undefined type name: "nat list"⌂
I can see here
https://isabelle.in.tum.de/doc/classes.pdf
that it is possible. However, the notation used in this pdf is strange. I can't reproduce any of the examples provided. For instance this
class eq where
eq :: α ⇒ α ⇒ bool
I suppose it's meant to be something like
class eq where
eq :: "'a ⇒ 'a ⇒ bool"
but when I paste it to jEdit I get syntax error. Other Isabelle tutorials use a different notation, like
class eq =
fixes eq :: "'a ⇒ 'a ⇒ bool"
This pdf also provides example
instance (α::eq, β::eq) pair :: eq where
eq (x1, y1) (x2, y2) = eq x1 x2 ∧ eq y1 y2
which looks like what I am looking for. An instance of a higher-order type.
no_notation Nil ("[]") and Cons (infixr "#" 65) and append (infixr "#" 65) and plus (infixl "+" 65)
class plus =
fixes plus :: "'a ⇒ 'a ⇒ 'a" (infixl "+" 65)
datatype 'a list =
Nil ("[]")
| Cons 'a "'a list" (infixr "#" 65)
instantiation list :: (type) plus
begin
primrec plus_list :: "'a list ⇒ 'a list ⇒ 'a list" where
"plus_list [] ys = ys" |
"plus_list (x#xs) ys = x # (plus_list xs ys)"
instance ..
end

What is INF in Isabelle

I found this definition in Isabelle
definition (in topological_space) nhds :: "'a ⇒ 'a filter"
where "nhds a = (INF S∈{S. open S ∧ a ∈ S}. principal S)"
What is INF? I can't find anything in query tab nor can I jump to definition with Ctrl+Click.
You already answered the question yourself: INF x∈A. f x is simply the infimum of f(x) ranging over all x ∈ A.
But let me explain as well what it means in this particular context: principal S is the filter for which eventually P (principal S) simply means that P holds on all values in the set S.
We now take the infimum of that over all the open sets that contain a certain point x. This then gives us a filter where eventually P (nhds x) means that there exists an open set that contains x and on which this property holds. In other words: P holds for any point sufficiently close to x (including x itself).
It is infimum of complete lattice
class Inf =
fixes Inf :: "'a set ⇒ 'a" ("⨅ _" [900] 900)
This syntax is declared as
syntax
"_INF1" :: "pttrns ⇒ 'b ⇒ 'b" ("(3INF _./ _)" [0, 10] 10)
"_INF" :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b" ("(3INF _∈_./ _)" [0, 0, 10] 10)
"_SUP1" :: "pttrns ⇒ 'b ⇒ 'b" ("(3SUP _./ _)" [0, 10] 10)
"_SUP" :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b" ("(3SUP _∈_./ _)" [0, 0, 10] 10)
syntax
"_INF1" :: "pttrns ⇒ 'b ⇒ 'b" ("(3⨅_./ _)" [0, 10] 10)
"_INF" :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b" ("(3⨅_∈_./ _)" [0, 0, 10] 10)
"_SUP1" :: "pttrns ⇒ 'b ⇒ 'b" ("(3⨆_./ _)" [0, 10] 10)
"_SUP" :: "pttrn ⇒ 'a set ⇒ 'b ⇒ 'b" ("(3⨆_∈_./ _)" [0, 0, 10] 10)
It's in Complete_Lattices.thy (https://isabelle.in.tum.de/library/HOL/HOL/outline.pdf) under section "Syntactic infimum and supremum operations" .

Inductive predicates, transitive closure, and code generation

I am defining subclass and subtype relations as inductive predicates for a Java-like language and would like to generate code for these relations. Defining and generating code for the subtype relation was no problem:
type_synonym class_name = string
record class_def =
cname :: class_name
super :: "class_name option"
interfaces :: "class_name list"
type_synonym program = "class_def list"
(* Look up a class by its name *)
definition lookup_class :: "program ⇒ class_name ⇒ class_def option" where
"lookup_class P C ≡ find (λcl. (class_def.cname cl) = C) P"
(* Direct subclass relation *)
inductive is_subclass1 :: "program ⇒ class_name ⇒ class_name ⇒ bool" where
"⟦
Some cl = lookup_class P C;
(class_def.super cl) = Some C'
⟧ ⟹ is_subclass1 P C C'"
(* Reflexive transitive closure of `is_subclass1` *)
definition is_subclass :: "program ⇒ class_name ⇒ class_name ⇒ bool" where
"is_subclass P C C' ≡ (is_subclass1 P)⇧*⇧* C C'"
code_pred(modes: i ⇒ i ⇒ i ⇒ bool, i ⇒ i ⇒ o ⇒ bool) is_subclass1 .
code_pred
(modes: i ⇒ i ⇒ i ⇒ bool, i ⇒ i ⇒ o ⇒ bool)
[inductify]
is_subclass .
Here, is_subclass1 P C C' is true if C' is the name of the direct superclass of C. Then is_subclass is defined to be the transitive closure of is_subclass1.
For code generation to work, it is crucial that is_subclass1 has the mode i ⇒ i ⇒ o ⇒ bool, because otherwise the transitive closure cannot be computed. In the case of is_subclass1 this is easy, as a class has at most a single direct superclass, and the name of the superclass can thus be uniquely determined from the inputs.
However, for the subtype relation I also need to consider the interfaces that a class might implement:
inductive is_subtype1 :: "program ⇒ class_name ⇒ class_name ⇒ bool" for P :: program where
― ‹Same as subclass relation, no problem›
"⟦
Ok cl = lookup_class P C;
Some C' = (class_def.super cl)
⟧ ⟹ is_subtype1 P C C'" |
"⟦
Ok cl = lookup_class P C;
― ‹HERE IS THE PROBLEM: C' cannot be uniquely derived from the inputs and can thus not be marked as an output›
C' ∈ set (class_def.interfaces cl)
⟧ ⟹ is_subtype1 P C C'"
The problem is that there are multiple possible values for C' and that it cannot be marked as an output.
Intuitively, I think this should not be a problem for the code generator, as the generated code could just iterate over all the interfaces of a class. However, I don't know if this can be expressed in Isabelle/HOL.
Thus, the question is: Is there a way to generate code for is_subtype1 with mode i ⇒ i ⇒ o ⇒ bool?
You can solve your problem by importing HOL-Library.Predicate_Compile_Alternative_Defs and then using List.member _ _ instead of _ ∈ set _.

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?

Isabelle: How to unify type variables of current and imported locale?

Consider this following contrived example of locale declarations in Isabelle:
locale x =
fixes f :: "'a ⇒ 'a"
assumes "f ∘ f = f"
locale y = x +
fixes g :: "'a ⇒ 'b"
begin
abbreviation h :: "'a ⇒ 'b" where "h ≡ g ∘ f"
end
This fails, because the 'a in locale x is different from the 'a in locale y. How can I tell Isabelle that the argument of g should have the same type as the argument and the result of f? 

Resources