Isabelle labeled graph definition - functional-programming

I am trying to define some vertex labels in Isabelle HOL and have a problem with the successor definition:
record ('v,'w) graph =
nodes :: "('v×'w) set"
edges :: "(('v×'w) × ('v×'w)) set"
definition succ :: "('v,'w) graph ⇒'v ⇒ ('v,'w) set"
where "succ G v ≡ {(v',w). ((v,w),(v',w))∈edges G}"
It says "Bad number of arguments for type constructor: "Set.set"", does anyone know how to fix this?

succ shall probably return a set of vertex-label pairs 'v × 'w, so want to write
definition succ :: "('v,'w) graph ⇒'v ⇒ ('v × 'w) set"

Related

Preimage of a function in Isabelle

I made this:
abbreviation "preimage f y ≡ { x . f x = y }"
Isn't there a built-in definition I could be using instead? How would I find that?
f -` {a}
aka
vimage f {a}
I found by searching for theorems with the name image in it and hoping to find the right one with the symbol:
find_theorems name:image
I was lucky enough that it appeared in the first theorems... In general, a better approach is have an idea of the type and use find_consts:
find_consts "('a ⇒ 'b) ⇒ 'b set ⇒ 'a set"

Isabelle unification error

I am new to Isabelle and this is a simplification of my first program
theory Scratch
imports Main
begin
record flow =
Src :: "nat"
Dest :: "nat"
record diagram =
DataFlows :: "flow set"
Transitions :: "nat set"
Markings :: "flow set"
fun consume :: "diagram × (nat set) ⇒ (flow set)"
where
"(consume dia trans) = {n . n ∈ (Markings dia) ∧ (∃ t ∈ trans . (Dest n) = t)}"
end
The function give the error:
Type unification failed: Clash of types "_ ⇒ " and " set"
Type error in application: operator not of function type
Operator: consume dia :: flow set
Operand: trans :: (??'a × ??'a) set ⇒ bool
What should I do for the the code to compile?
First of all, you give two parameters to your consume function, but the way you defined its type, it takes a single tuple. This is unusual and often inconvenient – defined curried functions instead, like this:
fun consume :: "diagram ⇒ (nat set) ⇒ (flow set)"
Also, trans is a constant; it is the property that a relation is transitive. You can see that by observing that trans is black to indicate that it is a constant and the other variable is blue, indicating that it is a free variable.
I therefore recommend using another name, like ts:
where
"consume dia ts = {n . n ∈ (Markings dia) ∧ (∃ t ∈ ts . (Dest n) = t)}"

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).

Establishing that a record type belongs to a given class

I have made a record type called graph, and I have defined a suitable "is a subgraph of" relation. I would like to show that the set of graphs together with the subgraph relation forms an order, i.e. is an instance of the ord class. But I can't get it to work. Here is my minimal working example:
theory John imports
Main
begin
typedecl node
record graph =
nodes :: "node set"
edges :: "(node × node) set"
definition subgraph :: "graph ⇒ graph ⇒ bool"
(infix "⊑" 50)
where
"G ⊑ H ≡
nodes G ⊆ nodes H ∧ edges G ⊆ edges H"
lemma "(GREATEST H. H ⊑ G) = G"
oops
end
I get the error:
Type unification failed: No type arity graph_ext :: ord"
I tried typing things like instantiation graph :: ord and instantiation graph_ext :: ord, but nothing seems to work. Any ideas?
When a record graph is defined, behind the scenes a new type 'a graph_ext is actually created. This type is the same as your record type, but with an extra field that allows extra data to be tacked in (i.e., a new field with type 'a is added to your record definition, which can be used to add additional data into your records later on). The type graph is simply an abbreviation for unit graph_ext.
This means that when you want to instantiate a graph into a type class, you actually need to instantiate the underlying type 'a graph_ext. This could be done as follows:
instantiation graph_ext :: (type) ord
begin
instance ..
end
Although you probably also want to provide some definitions for the ord type, perhaps as follows:
instantiation graph_ext :: (type) ord
begin
definition "less_eq_graph_ext (G :: 'a graph_ext) (H :: 'a graph_ext) ≡
nodes G ⊆ nodes H ∧ edges G ⊆ edges H"
definition "less_graph_ext (G :: 'a graph_ext) (H :: 'a graph_ext)
≡ (nodes G ⊆ nodes H ∧ edges G ⊆ edges H) ∧
¬ (nodes H ⊆ nodes G ∧ edges H ⊆ edges G)"
instance ..
end
Once 'a graph_ext has been instantiated into the class ord, your final lemma type-checks (although to actually carry out the proof, you likely need to do a bit more work, such as instantiating 'a graph_ext into the preorder or order classes.)

Using tuples in definitions

I want to create a definition which has a tuple as its argument.
definition my_def :: "('a × 'a) ⇒ bool" where
"my_def (a, b) ⟷ a = b"
However, this is not accepted. The error message is
Bad arguments on lhs: "(a, b)"
The error(s) above occurred in definition:
"my_def (a, b) ≡ a = b"
Using fun instead of definition works but this is not what I want. The following notation also works but is somewhat ugly:
definition my_def :: "('a × 'a) ⇒ bool" where
"my_def t ⟷ fst t = snd t"
What is the best way to use tuples as arguments in a definition?
Using fun is probably the least painful way to do this, the definition package doesn't recognise patterns on the left hand side.
Another option is to use tuple patterns for lambda expressions:
my_def ≡ %(a,b). a = b

Resources