Calculating transitive closures - isabelle

I have the following definition:
definition someRel :: "nat rel"
where
"someRel = {(1, 2), (2, 3), (3, 4), (4, 5)}"
I want to prove the following lemma:
lemma "someRel^*``{1}={1, 2, 3, 4, 5}"
I have devised the following proof:
proof
show "someRel^*``{1} ⊆ {1, 2, 3, 4, 5}"
proof
fix x
assume "x ∈ someRel⇧* `` {1}"
then show "x ∈ {1, 2, 3, 4, 5}"
using assms someRel_def by (auto elim: rtranclE)
qed
next
show "{1, 2, 3, 4, 5} ⊆ someRel^*``{1}"
proof
fix x
assume "x ∈ {1::nat, 2, 3, 4, 5}"
then show "x ∈ someRel⇧* `` {1}"
using assms someRel_def Image_singleton by (induction) blast+
qed
qed
This proof has the following issues:
The first part (show "someRel^*``{1} ⊆ {1, 2, 3, 4, 5}") is proved using the rule
rtranclE. This does not work if I add one more pair to the someRel relation (say the pair (6, 7))
The proof of the second part (show "{1, 2, 3, 4, 5} ⊆ someRel^*``{1}") does not terminate.
Can anyone suggest a better proof? That (a) allows for more pairs in the someRel relation and (b) that terminates.

It turns out that for your specific instance (and some slightly bigger ones I tried), the following suffices (found by first applying auto and then running sledgehammer on the remaining goals to identify useful facts, like converse_rtrancl_into_rtrancl here):
by (auto simp: someRel_def converse_rtrancl_into_rtrancl elim: rtranclE)
However, in general it might be a better idea to do one of the following:
device a tactic to prove such goals (by actually computing the involved transitive closure)
compute the transitive closure inside Isabelle/HOL (either via simp -- which might be slow -- or via eval -- which, as far as I know is kind of an oracle).
For the latter the AFP entry
Executable Transitive Closures might be of interest.
Update: I added an example of a simproc that computes images of finite transitive closures over finite sets by evaluation to the development version of the AFP. Instead of Executable Transitive Closures however, I based the example on
Executable Transitive Closures of Finite Relations. Your example can be found at the end of theory
Finite_Transitive_Closure_Simprocs (as soon as the AFP website is synchronized with the underlying mercurial repository).
Update: Note that the above mentioned simproc is specifically aimed at patterns of the form r^* `` x where the sets r and x are finite in the sense that they are given in finite set notation {x1, x2, ..., xN}. Thus, in order to fire on a specific goal you might have to add additional facts / simp rules / simprocs / ... in order to normalize an expression into this form.
Example: If you had the goal
"(converse someRel)^* `` {1} = {1}"
you would have to add rules that actually "apply" the converse operation on the given finite set. The following would do:
lemma [simp]:
"converse (insert (x, y) A) = insert (y, x) (converse A)"
by auto
Now the goal could be solved via
by (auto simp: someRel_def)

Adding to Chris' answer, here is a full version which uses the AFP-entry for transitive closures, and which does use code-simp instead of eval. code-simp is a bit slower than eval, but does not rely upon oracles.
theory Test
imports "$AFP/Transitive-Closure/Transitive_Closure_List_Impl"
begin
lemma to_memo_list: "(set xs)^* `` {a} = set (memo_list_rtrancl xs a)"
unfolding memo_list_rtrancl Image_def by auto
definition someRel :: "nat rel"
where
"someRel = {(1, 2), (2, 3), (3, 4), (4, 5), (5,3)}"
definition someRel_list :: "(nat × nat)list"
where
"someRel_list = [(1, 2), (2, 3), (3, 4), (4, 5), (5,3)]"
lemma someRel_list: "someRel = set someRel_list" by code_simp
lemma "someRel^*``{4}={3, 4, 5}"
unfolding someRel_list to_memo_list by code_simp
end

Related

Isabelle termination of function on datatypes containing maps to themselves

Is it possible in Isabelle to define a terminating recursive function f where
f has a single parameter of type t such that values of type t may contain maps to values of type t, and
f performs its recursive calls on all elements in the range of such a map?
For example consider the datatype trie defined in theory Trie_Fun:
datatype 'a trie = Nd bool "'a ⇒ 'a trie option"
and my attempt at a simple function height intended to compute the height of tries (with finitely many outgoing edges):
theory Scratch
imports "HOL-Data_Structures.Trie_Fun"
begin
function height :: "'a trie ⇒ nat" where
"height (Nd _ edges) = (if dom edges = Set.empty ∨ ¬ finite (dom edges)
then 0
else 1 + Max (height ` ran edges))"
by pat_completeness auto
termination (* ??? *)
end
Here lexicographic_order does not suffice to prove the function to be terminating, but so far I have also not been able to formulate any measure on trie (for termination) that does not itself require a similar recursion.
I must admit here that I am not sure whether I have understood datatypes in Isabelle/HOL correctly (i.e., whether a trie of the above definition is actually always of finite height).
Is it possible to show that height terminates?
Based to the comment by Peter Zeller, I was able to prove termination of height by adding (domintros) to the definition and then performing induction on the trie, using the fact height.domintros, resulting in the following termination proof:
function (domintros) height :: "'a trie ⇒ nat" where
"height (Nd _ edges) = (if dom edges = Set.empty ∨ ¬ finite (dom edges)
then 0
else 1 + Max (height ` ran edges))"
by pat_completeness auto
termination apply auto
proof -
fix x :: "'a trie"
show "height_dom x"
proof (induction)
case (Nd b edges)
have "(⋀x. x ∈ ran edges ⟹ height_dom x)"
proof -
fix x assume "x ∈ ran edges"
then have "∃a. edges a = Some x"
unfolding ran_def by blast
then have "∃a. Some x = edges a"
by (metis (no_types))
then have "Some x ∈ range edges"
by blast
then show "height_dom x"
using Nd by auto
qed
then show ?case
using height.domintros by blast
qed
qed

Shorten proposition with abbreviations in Isabelle

Imagine the following theorem:
assumes d: "distinct (map fst zs_ws)"
assumes e: "(p :: complex poly) = lagrange_interpolation_poly zs_ws"
shows "degree p ≤ (length zs_ws)-1 ∧
(∀ x y. (x,y) ∈ set zs_ws ⟶ poly p x = y)"
I would like to eliminate the second assumption, without having to substitute the value of p on each occurrence. I did this in proofs with the let command:
let ?p = lagrange_interpolation_poly zs_ws
But it doesn't work in the theorem statement. Ideas?
You can make a local definition in the lemma statement like this:
lemma l:
fixes zs_ws
defines "p == lagrange_interpolation_poly zs_ws"
assumes d: "distinct (map fst zs_ws)"
shows "degree p ≤ (length zs_ws)-1 ∧ (∀(x,y) ∈ set zs_ws. poly p x = y)"
The definition gets unfolded when the proof is finished. So when you look at thm l later, all occurrences of p have been substituted by the right-hand side. Inside the proof, p_def refers to the definining equation for p (what you call e). The defines clause is most useful when you want to control in the proof when Isabelle's proof tools just see p and when they see the expanded right-hand side.

Proving a basic identity in Isabelle

Consider the following following definition definition phi :: "nat ⇒ nat" where "phi n = card {k∈{0<..n}. coprime n k}" (see also this answer)
How can I then prove a very basic fact, like phi(p)=p-1 for a prime p ? Here is one possible formalization of this lemma, though I'm not sure it's the best one:
lemma basic:
assumes "prime_elem (p::nat) = true"
shows "phi p = p-1"
(prime_elem is defined in Factorial_Ring.thy)
Using try resp. try0 doesn't lead anywhere. (A proof by hand is immediate though, since the GCD between any m less than p and p is 1. But poking around various file didn't turn out to be very helpful, I imagine I have to guess some clever lemma that I have to give auto for the proof to succeed.)
First of all, true doesn't exist. Isabelle interprets this as a free Boolean variable (as you can see by the fact that it is printed blue). You mean True. Also, writing prime_elem p = True is somewhat unidiomatic; just write prime_elem p.
Next, I would suggest using prime p. It's equivalent to prime_elem on the naturals; for other types, the difference is that prime also requires the element to be ‘canonical’, i.e. 2 :: int is prime, but -2 :: int is not.
So your lemma looks like this:
lemma basic:
assumes "prime_elem (p::nat)"
shows "phi p = p - 1"
proof -
Next, you should prove the following:
from assms have "{k∈{0<..p}. coprime p k} = {0<..<p}"
If you throw auto at this, you'll get two subgoals, and sledgehammer can solve them both, so you're done. However, the resulting proof is a bit ugly:
apply auto
apply (metis One_nat_def gcd_nat.idem le_less not_prime_1)
by (simp add: prime_nat_iff'')
You can then simply prove your overall goal with this:
thus ?thesis by (simp add: phi_def)
A more reasonable and robust way would be this Isar proof:
lemma basic:
assumes "prime (p::nat)"
shows "phi p = p - 1"
proof -
have "{k∈{0<..p}. coprime p k} = {0<..<p}"
proof safe
fix x assume "x ∈ {0<..p}" "coprime p x"
with assms show "x ∈ {0<..<p}" by (cases "x = p") auto
next
fix x assume "x ∈ {0<..<p}"
with assms show "coprime p x" by (simp add: prime_nat_iff'')
qed auto
thus ?thesis by (simp add: phi_def)
qed
By the way, I would recommend restructuring your definitions in the following way:
definition rel_primes :: "nat ⇒ nat set" where
"rel_primes n = {k ∈ {0<..n}. coprime k n}"
definition phi :: "nat ⇒ nat" where
"phi n = card (rel_primes n)"
Then you can prove nice auxiliary lemmas for rel_primes. (You'll need them for more complicated properties of the totient function)

isabelle - Choose an arbitrary but fixed element

How can an arbitrary but fixed element be selected from a set in Isabelle? The element selected will be used as random element from the set for further processing, but no other element must be used further.
My first attempt was:
theory Scratch
imports Main Orderings
begin
value "(let el ∈ {3::int, 4, 5} in el)"
end
But gives a syntax error.
My second attempt was:
theory Scratch
imports Main Orderings
begin
value "(let el = (SOME x . x ∈ {{3::int, 4},
{5::int, 6} ,
{7::int, 8}})
in el)"
end
giving a type int set and not the expected type int.
Edit 1
A new example:
theory Scratch
imports Main Orderings
begin
fun add :: "int set ⇒ int" where
"add st = (let el = (SOME x . x ∈ st) in el + (10::int))"
value "add {3::int, 4, 5, 6}"
end
The result of the code is:
"(SOME u. 3 = u ∨ 4 = u ∨ 5 = u ∨ 6 = u) + 10"
:: "int"
instead of an integer value. How do I write add so that the results is either 13, 14, 15 or 16? The exact value does not matter, it must just be different each time the function is executed.
The reason you got an int set as result is that you select an element from an int set set. In your second attempt, instead of using a "flat" set, you have used a nested set.
Apart from your specific question, I would recommend you look at the folding locale in the Finite_Set theory. It provides a combinator for folding over sets (given that the operator commutes).
You can define
definition "el = (SOME x. x ∈ {(3::int), 4, 5})"
You can then prove e.g.
lemma "el ∈ {3,4,5}"
unfolding el_def by (rule someI_ex) auto
Logically, el is some fixed element of {3, 4, 5} (as we just proved), and it is always the same element – but you don't know which one. You can think of it as ‘When the universe came into existence, it chose a value for SOME x. x ∈ {3,4,5}, either 3, 4, or 5, but it will never tell you which one it is.’
I don't know what it is exactly that you are trying to do, but I do not think that this is what you really want to do. Perhaps you can go into a bit more detail as to what you want to do with this element?

Isabelle: adjusting lemma to form required for `rule` method

I define an inductive relation called step_g. Here is one of the inference rules:
G_No_Op:
"∀j ∈ the (T i). ¬ (eval_bool p (the (γ ⇩t⇩s j)))
⟹ step_g a i T (γ, (Barrier, p)) (Some γ)"
I want to invoke this rule in a proof, so I type
apply (rule step_g.G_No_Op)
but the rule cannot be applied, because its conclusion must be of a particular form already (the two γ's must match). So I adapt the rule like so:
lemma G_No_Op_helper:
"⟦ ∀j ∈ the (T i). ¬ (eval_bool p (the (γ ⇩t⇩s j))) ; γ = γ' ⟧
⟹ step_g a i T (γ, (Barrier, p)) (Some γ')"
by (simp add: step_g.G_No_Op)
Now, when I invoke rule G_No_Op_helper, the requirement that "the two γ's must match" becomes a subgoal to be proven.
The transformation of G_No_Op into G_No_Op_helper looks rather mechanical. My question is: is there a way to make Isabelle do this automatically?
Edit. I came up with a "minimal working example". In the following, lemma A is equivalent to A2, but rule A doesn't help to prove the theorem, only rule A2 works.
consts foo :: "nat ⇒ nat ⇒ nat ⇒ bool"
lemma A: "x < y ⟹ foo y x x"
sorry
lemma A2: "⟦ x < y ; x = z ⟧ ⟹ foo y x z"
sorry
theorem "foo y x z"
apply (rule A)
To my knowledge, nothing exists to automate these things. One could probably implement this as an attribute, i.e.
thm A[generalised x]
to obtain something like A2. The attribute would replace every occurence of the variable it is given (i.e. x here) but the first in the conclusion of the theorem with a fresh variable x' and add the premise x' = x to the theorem.
This shouldn't be very hard to implement for someone more skilled in Isabelle/ML than me – maybe some of the advanced Isabelle/ML hackers who read this could comment on the idea.
There is a well-known principle "proof-by-definition", i.e. you write your initial specifications in a way such the the resulting rules are easy to apply. This might occasionally look unexpected to informal readers, but is normal for formalists.
I had similar problems and wrote a method named fuzzy_rule, which can be used like this:
theorem "foo y x z"
apply (fuzzy_rule A)
subgoal "x < y"
sorry
subgoal "x = z"
sorry
The code is available at https://github.com/peterzeller/isabelle_fuzzy_rule

Resources