Preimage of a function in Isabelle - 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"

Related

How do I convert a predicate to a function in Isabelle?

In Isabelle HOL, I have a predicate on two numbers like this:
definition f :: "nat ⇒ nat ⇒ bool"
where
...
I can prove that this predicate is morally a function:
lemma f_function:
fixes x :: nat
shows "∃! y . f x y""
...
Intuitively, this should be enough for me to construct a function f' :: nat ⇒ nat that is provably equivalent to f', i.e.:
lemma f'_correct:
"f x y = (f' x = y)"
But how do I do that?
definition f' :: "nat ⇒ nat"
where
"f' x ≡ ?"
What do I put in for the question mark?
The typical approach is to use the definite description operator THE:
definition f' :: "nat ⇒ nat" where "f' x = (THE y. f x y)"
If you have already proven that this y is unique, you can then use e.g. the theorem theI' to show that f x (f' x) holds and theI_unique to show that if f x y holds, then y = f' x.
For more information about THE, SOME, etc. see the following:
Isabelle/HOL: What does the THE construct denote?
Proving intuitive statements about THE in Isabelle

How to use a definition written on locale parameters in the assumptions of the locale?

If there is some definition on the parameters of a locale which would make the assumptions of the locale easier to write and/or read and/or understand (either because the function is quite complicated so would simplify the statement of the assumptions, or its name makes the assumptions easier to read and understand), what is the best way to define that function?
As a contrived example, say we want to incorporate the function fg into the statement of the assumptions (not actually useful here of course):
locale defined_after =
fixes f :: "'a ⇒ 'b ⇒ 'c"
and g :: "'b ⇒ 'a"
assumes "∀a. ∃b. f a b = f (g b) b"
and univ: "(UNIV::'b set) = {b}"
begin
definition fg :: "'b ⇒ 'c" where
"fg b ≡ f (g b) b"
lemma "∀b b'. fg b = fg b'" using univ the_elem_eq by (metis (full_types))
(* etc *)
end
One might think to use defines:
locale defined_during =
fixes f :: "'a ⇒ 'b ⇒ 'c"
and g :: "'b ⇒ 'a"
and fg :: "'b ⇒ 'c"
defines fg_def: "fg b ≡ f (g b) b"
assumes "∀a. ∃b. f a b = fg b"
and univ: "(UNIV::'b set) = {b}"
begin
lemma "∀b b'. fg b = fg b'" using univ the_elem_eq by (metis (full_types))
end
but the locales.pdf document seems to suggest it is deprecated (but by what I'm not sure):
The grammar is complete with the exception of the context elements constrains and defines, which are provided for backward compatibility.
Ctrl-hovering over fg in the lemma in the locale defined_after names it as constant "local.fg" whereas in defined_during it is fixed fg\nfree variable. It does however achieve defined_after_def being equal to defined_during_def (i.e. there are no additional parameters or assumptions in the latter), which the third option does not:
locale extra_defined_during =
fixes f :: "'a ⇒ 'b ⇒ 'c"
and g :: "'b ⇒ 'a"
and fg :: "'b ⇒ 'c"
assumes fg_def: "fg b ≡ f (g b) b"
and "∀a. ∃b. f a b = fg b"
and univ: "(UNIV::'b set) = {b}"
begin
lemma "∀b b'. fg b = fg b'" using univ the_elem_eq by (metis (full_types))
end
which also has the same Ctrl-hover text for fg in the lemma as the defined_during locale does.
Maybe there's something about it in one of the PDFs on the website, or in the NEWS file, but I can't find anything obvious. isar-ref.pdf makes a comment:
Both assumes and defines elements contribute to the locale specification. When defining an operation derived from the parameters, definition (§5.4) is usually more appropriate.
But I'm not sure how to use this information. Presumably it is saying that when one doesn't gain much by doing what I am asking about, one should proceed as in the locale defined_after (unless the quote means one can use definition inside a locale definition), which is not what I want. (As an aside: the first sentence of this quote would have suggested to me that defines is somehow equivalent to the third option which introduces an extra parameter and assumption, but that isn't the case. Maybe understanding what the possibly-subtler-than-it-appears-Isabelle-jargon "locale specification" means would explain what is causing the Ctrl-hover text to differ between the first and second option, I don't know.)
The specification element defines is indeed nothing that I would recommend to use. It goes back to a time when definition was not available inside a locale context and all definitions had to be done in the locale declaration itself.
Nowadays, the standard approach to your problem is to split the locale into two parts: First define a locale l1 without the complicated assumption, but with the relevant parameters. (If you need some assumptions to justify the definition, e.g. for the termination proof of function, include those assumptions.) Then define your function fg inside l1 as usual. Finally, define your actual locale l that extends l1. You can then use the definition of fg in the assumptions of l.
locale l = l1 + assumes "... fg ..."

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

How can I remove all elements in a list with a certain property?

I want to match and remove those elements in l :: 'a list that match the predicate P :: ('a => bool)
What is the best way to accomplish such a task? How can I find out about existing functions that might help me?
One way to find functions you expect to exist is the document What's in Main from the Isabelle documentation. It gives a quick overview of the main types, functions and syntax provided by the theory Main of Isabelle/HOL.
If you look at the List section in ths document, you find the function filter which seems to have the correct type.
Short Story: Use find_consts
Long Story:
This a How-To to conquer such problems.
In Main, there is List.dropWhile
List.dropWhile :: "('a => bool) => 'a list => 'a list"
However, it only removes from the beginning. This may not be the intended function.
value "List.dropWhile (λ x. x = ''c'') [''c'', ''c'', ''d'']"
"[''d'']"
value "List.dropWhile (λ x. x = ''c'') [''d'', ''c'', ''c'']"
"[''d'', ''c'', ''c'']"
Manual Approach
We can write a function ourselves which removes all occurrences
fun dropAll :: "('a => bool) => 'a list => 'a list" where
"dropAll P [] = []"
| "dropAll P (x # xs) = (if P x then dropAll P xs else x # (dropAll P xs))"
Searching the Library
However, this function is equivalent to filtering with ¬ P
How can we find such library functions?
If we know the signature of what we want to do, we can use find_consts
find_consts "('a ⇒ bool) ⇒ 'a list ⇒ 'a list"
It returns 3 functions from Main, with that signature: List.dropWhile, List.filter, List.takeWhile
Now, let's show that we don't need dropAll but can do the same with filter.
lemma "dropAll P l = filter (λ x. ¬ P x) l"
apply(induction l)
by simp_all
It is advisable not to implement things like dropAllyourself but rather use filter. Thus, all lemmata proven for filter are usable.
Hints
Hint: we can use the convenient list comprehension syntax to write e.g. filter expressions
lemma "filter (λ x. ¬ P x) l = [x ← l. ¬ P x]" by simp

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