What is INF in Isabelle - 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" .

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

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 abstract collection data type?

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.

Using a definition to produce an specific example of a locale in Isabelle

I'm working on a theory that requires usage of rings, so I imported the following theories: https://www.isa-afp.org/browser_info/devel/AFP/Group-Ring-Module/
Right now, I have defined a set X of a certain type and I'd like to define operations on it to make it a ring, as in the locale "Ring" of the imported theory.
How do I define a ring with carrier X and have it recognized as an instance of the locale "Ring"?
The locale "Ring" is declared by extending "aGroup", which in turn is declared by extending "Group", which is in the theory "Algebra2.thy":
record 'a Group = "'a carrier" +
top :: "['a, 'a ] ⇒ 'a" (infixl "⋅ı" 70)
iop :: "'a ⇒ 'a" ("ρı _" [81] 80)
one :: "'a" ("𝟭ı")
locale Group =
fixes G (structure)
assumes top_closed: "top G ∈ carrier G → carrier G → carrier G"
and tassoc : "⟦a ∈ carrier G; b ∈ carrier G; c ∈ carrier G⟧ ⟹
(a ⋅ b) ⋅ c = a ⋅ (b ⋅ c)"
and iop_closed:"iop G ∈ carrier G → carrier G"
and l_i :"a ∈ carrier G ⟹ (ρ a) ⋅ a = 𝟭"
and unit_closed: "𝟭 ∈ carrier G"
and l_unit:"a ∈ carrier G ⟹ 𝟭 ⋅ a = a"
Another possible problem I antecipate: if I'm not mistaken, the carrier must be of type 'a set, but my set X is of type ('a set \times 'a) set set. Is there a workaround?
EDIT: In order to better formulate the sequential question in the comments, here are some pieces of what I did. All that follows is within the context of a locale presheaf, that fixes (among other things):
T :: 'a set set and
objectsmap :: "'a set ⇒ ('a, 'm) Ring_scheme" and
restrictionsmap:: "('a set ×'a set) ⇒ ('a ⇒ 'a)"
I then introduced the following:
definition prestalk :: "'a ⇒('a set × 'a) set" where
"prestalk x = { (U,s). (U ∈ T) ∧ x ∈U ∧ (s ∈ carrier (objectsmap U))}"
definition stalkrel :: "'a ⇒ ( ('a set × 'a) × ('a set × 'a) ) set" where
"stalkrel x = {( (U,s), (V,t) ). (U,s) ∈ prestalk x ∧ (V,t) ∈ prestalk x ∧ (∃W. W ⊆ U∩V ∧ x∈W ∧
restrictionsmap (V,W) t = restrictionsmap (U,W)) s} "
I then proved that for each x, stalkrel x is an equivalence relation, and defined:
definition germ:: "'a ⇒ 'a set ⇒ 'a ⇒ ('a set × 'a) set" where
"germ x U s = {(V,t). ((U,s),(V,t)) ∈ stalkrel x}"
definition stalk:: "'a ⇒( ('a set × 'a) set) set" where
"stalk x = {w. (∃ U s. w = germ x U s ∧ (U,s) ∈ prestalk x) }"
I'm trying to show that for each x this stalk x is a ring, and the ring operation is "built" out of the ring operations of rings objectsmap (U∩V) , i.e, I'd like germ x U s + germ x V t to be germ x (U∩V) (restrictionsmap (U, (U∩V)) s + restrictionsmap (V, (U∩V)) t), where this last sum is the sum of ring objectsmap (U∩V).
A multiplicative Group in the AFP entry mentioned is a record with four fields: a set carrier for the carrier, the binary group operation top, the inverse operation iop and the neutral element one. Similarly, a Ring is a record which extends an additive group (record aGroup with fields carrier, pop, mop, zero) with the binary multiplicative operation tp and the multiplicative unit un. If you want to define an instance of a group or record, you must define something of the appropriate record type. For example,
definition my_ring :: "<el> Ring" where
"my_ring =
(|carrier = <c>,
pop = <plus>,
mop = <minus>,
zero = <0>,
tp = <times>,
un = <unit>|)"
where you have to replace all the <...> by the types and terms for your ring. That is, <el> is the type of the ring elements, <c> is the carrier set, etc. Note that you can specialise the type of ring elements as needed.
In order to prove that my_ring is indeed a ring, you must show that it satisfies the assumptions of the corresponding locale Ring:
lemma "Ring my_ring"
proof unfold_locales
...
qed
If you want to use the theorems that have been proven abstractly for arbitrary rings, you may want to interpret the locale using interpretation.

How to generate code for reverse sorting

What is the easiest way to generate code for a sorting algorithm that sorts its argument in reverse order, while building on top of the existing List.sort?
I came up with two solutions that are shown below in my answer. But both of them are not really satisfactory.
Any other ideas how this could be done?
I came up with two possible solutions. But both have (severe) drawbacks. (I would have liked to obtain the result almost automatically.)
Introduce a Haskell-style newtype. E.g., if we wanted to sort lists of nats, something like
datatype 'a new = New (old : 'a)
instantiation new :: (linorder) linorder
begin
definition "less_eq_new x y ⟷ old x ≥ old y"
definition "less_new x y ⟷ old x > old y"
instance by (default, case_tac [!] x) (auto simp: less_eq_new_def less_new_def)
end
At this point
value [code] "sort_key New [0::nat, 1, 0, 0, 1, 2]"
yields the desired reverse sorting. While this is comparatively easy, it is not as automatic as I would like the solution to be and in addition has a small runtime overhead (since Isabelle doesn't have Haskell's newtype).
Via a locale for the dual of a linear order. First we more or less copy the existing code for insertion sort (but instead of relying on a type class, we make the parameter that represents the comparison explicit).
fun insort_by_key :: "('b ⇒ 'b ⇒ bool) ⇒ ('a ⇒ 'b) ⇒ 'a ⇒ 'a list ⇒ 'a list"
where
"insort_by_key P f x [] = [x]"
| "insort_by_key P f x (y # ys) =
(if P (f x) (f y) then x # y # ys else y # insort_by_key P f x ys)"
definition "revsort_key f xs = foldr (insort_by_key (op ≥) f) xs []"
at this point we have code for revsort_key.
value [code] "revsort_key id [0::nat, 1, 0, 0, 1, 2]"
but we also want all the nice results that have already been proved in the linorder locale (that derives from the linorder class). To this end, we introduce the dual of a linear order and use a "mixin" (not sure if I'm using the correct naming here) to replace all occurrences of linorder.sort_key (which does not allow for code generation) by our new "code constant" revsort_key.
interpretation dual_linorder!: linorder "op ≥ :: 'a::linorder ⇒ 'a ⇒ bool" "op >"
where
"linorder.sort_key (op ≥ :: 'a ⇒ 'a ⇒ bool) f xs = revsort_key f xs"
proof -
show "class.linorder (op ≥ :: 'a ⇒ 'a ⇒ bool) (op >)" by (rule dual_linorder)
then interpret rev_order: linorder "op ≥ :: 'a ⇒ 'a ⇒ bool" "op >" .
have "rev_order.insort_key f = insort_by_key (op ≥) f"
by (intro ext) (induct_tac xa; simp)
then show "rev_order.sort_key f xs = revsort_key f xs"
by (simp add: rev_order.sort_key_def revsort_key_def)
qed
While with this solution we do not have any runtime penalty, it is far too verbose for my taste and is not easily adaptable to changes in the standard code setup (e.g., if we wanted to use the mergesort implementation from the Archive of Formal Proofs for all of our sorting operations).

Resources