Shorten proposition with abbreviations in Isabelle - 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.

Related

Isabelle `subst` but replace right side with left side

Suppose the goal is P l, then I can use apply(subst X) where X is of the form l=r
and as a result I obtain P r. Now my question is whether there exists some other tactic like subst but which could use X to change P r into P l.
Here is an example
theorem mul_1_I : "(x::nat) = 1 * x" by (rule sym, rule Nat.nat_mult_1)
theorem "(λ x::nat . x) ≤ (λ x::nat . 2*x)"
using [[simp_trace]]
apply(rule le_funI)
apply(subst mul_1_I)
apply(rule mult_le_mono1)
apply(simp)
done
where
lemma nat_mult_1: "1 * n = n"
Right now I have to first prove this auxiliary lemma mul_1_I which applies sym to nat_mult_1 and only then I can use subst. Would be ideal if I didn't have to create new lemma specifically for this.
You can use the symmetric attribute to derive the swapped fact. For example, if x is of the form l = r, then x [symmetric] is the fact r = l (which is also valid due to the symmetry of =). Therefore, in your particular case you can use subst nat_mult_1 [symmetric] directly and avoid creating your auxiliary lemma.

How does one insert values into unknowns in isabelle theorem prover?

I have the following subgoals:
proof (prove)
goal (2 subgoals):
1. ⋀y. ∃x. P x ⟹ P (?x6 y)
2. ⋀y. ∃x. P x ⟹ Q (?y8 y) ⟹ Q y
I want to conclude the proof or continue trying stuff but I don't know how to introduce things into the unknowns (schematic variables) i.e variables with ?.
How does one do that?
Firstly, it is necessary to understand how schematic variables appeared in your subgoals. Normally, unless you are using schematic_goal, schematic variables appear in the subgoals after some form of rule application, whether implicit or explicit.
If the rule application was explicit (e.g. apply (rule conjunct1)), then a reasonably standard methodology for dealing with the problem that you described is to substitute the variables that you wish to 'try' directly into the rule, e.g. apply (rule conjunct1[of A]). In this case, there will be no schematic variables in your goals and, therefore, the problem implicitly disappears.
If the rule application was implicit (e.g. via one of the tools for classical reasoning), then your options depend on whether the subgoals were generated in an apply script or within the body of an Isar proof. Nonetheless, before I proceed, I would like to mention that the proofs where you have to interact with subgoals generated after the application of any 'black-box' methods are not considered to be a very good style (at least, in my opinion).
In the case of the former, there is nothing that you need to do to "try stuff". Once the variable that you wish to substitute (e.g. z) is defined, you can use show "∃x. P x ⟹ P (z y)" in the body of the Isar proof. Similarly, in an apply script, you can resolve with pre-substituted variables.
I demonstrate all these methods in the context of a simplified example below:
context
fixes A B :: bool
assumes AB: "A ∧ B"
begin
lemma A by (rule conjunct1[of _ B]) (rule AB)
lemma A
by (rule conjunct1) (rule AB)
lemma A
proof(rule conjunct1)
show "A ∧ B" by (rule AB)
qed
end
The important parts are already explained by user9716869. I just wanted to add:
You current subgoal is probably not solvable if you don't have additional information available. If you need the x from ∃x. P x to instantiate the schematic variable ?x6 then you need to obtain the value of x before the schematic variable is created.
Schematic variables are instantiated automatically by matching.
This works well if the schematic variable is not a function, so you can just continue to write your proof as if the correct value was already there.
If you want to fix the value in an apply style proof (other cases are already given in the other answer), you could use subgoal_tac followed by assumption:
lemma "⋀y. ∃x. P x ⟹ ∃x::nat. P x"
apply (rule exI)
― ‹⋀y. ∃x. P x ⟹ P (?x y)›
apply (subgoal_tac "P 42", assumption)
― ‹⋀y. ∃x. P x ⟹ P 42›
oops ― ‹Not possible to prove›
lemma "⋀y. ∃x. P x ⟹ ∃x::nat. P x"
apply (erule exE)
― ‹⋀y x. P x ⟹ ∃x. P x›
apply (rule exI)
― ‹⋀y x. P x ⟹ P (?x2 y x)›
apply (subgoal_tac "P x", assumption)
― ‹⋀y x. P x ⟹ P x›
by assumption

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 termination with distance of real numbers

maybe someone can help me with a termination proof in Isabelle. I am trying to construct from the list A a new sub-list B. For constructing B, I read again and again of the whole A. Take out elements and use the result for the search for the next element. I designed a simple example to illustrate that:
given is a list of random real numbers. And we say that a number P is on the list, if an item from the list is greater than P.
definition pointOnList :: "real list ⇒ real ⇒ bool" where
"pointOnList L P ≡ ∃ i. i < length L ∧ P < L!i"
I create a function that always take the next larger element.
fun nextPoint :: "real list ⇒ real ⇒ real" where
"nextPoint (X#Ls) P = (if (X > P)
then (X)
else (nextPoint Ls P))"
And now I'm trying to create a new sorted part-list by take out the next larger element than P but less than Q with nextPoint and continuing with this.
function listBetween :: "real list ⇒ real ⇒ real ⇒ real list" where
"pointOnList L P ⟹ pointOnList L Q ⟹ listBetween L P Q = (if(P ≤ Q)
then(P # (listBetween L (nextPoint L P) Q))
else([]))"
I have already demonstrated nextPoint always returns a growing number:
lemma foo: "pointOnList P A ⟹ A < (nextPoint P A)"
the termination proof with relation "measure (size o fst o snd)“ not working for real numbers…and now I don’t know how to continue.
To show termination in Isabelle, you have to show that the recursive calls follow a wellfounded relation. The easiest way to do that is to give a termination measure returning natural number that becomes smaller with every call. That does not work with real numbers because they are not wellfounded – you could have something like 1 → 1/2 → 1/4 → 1/8 → …
The termination measure to use in your case would be the number of list elements that fulfil the condition, i.e. length (filter (λx. P ≤ x ∧ x ≤ Q)) l. However, note that your definition fails to work if Q is larger than all numbers in the list.
Your definition is somewhat laborious and complicated. I recommend the following definition:
listBetween L P Q = sort (filter (λx. P ≤ x ∧ x ≤ Q) L)
or, equivalently,
listBetween L P Q = sort [x ← L. x ∈ {P..Q}]
Note, however, that this definition does not throw away multiple occurrences of the same number, i.e. listBetween L 0 10 [2,1,2] = [1,2,2]. If you want to throw them away, you can use remdups.
Also note that something like pointOnList L P ≡ ∃ i. i < length L ∧ P < L!i is pretty much never what you want – there is no need to work with explicit list indices here. Just do ∃x∈set L. P < x.
The termination argument relation "measure (size o fst o snd)" does not work for several reasons:
With your lemma foo you have just proven that the value increases. But for termination you need a decreasing measure. So you might want to use the difference
relation "measure (λ (L,P,Q). Q - P)"
Even then there is the problem that measure expects a mapping into the natural
numbers and Q - P is a real number, so this does not work. You used size before, but your lemma foo states nothing about the connection between size and <. Moreover, < is not a well-founded order over the real numbers.
Eventually, I would try to avoid the reasoning on reals in this simple example at all and take as measure something like
measure (λ (L,P,Q). length [ A . A <- L, P < A])"
and adapt the statement of foo accordingly.

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