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.
Related
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
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.
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.
In Programming and Proving in Isabelle/HOL there is Exercise 2.4 which suggests to use 'algebra_simps' on simple arithmetic expressions, represented as 'datatype exp'. Could somebody give an example how some simple properties of such expressions could be proven using algebra_simps? For example 'Mult a b = Mult b a'?
In general I am trying to prove equivalence of simple arithmetic expressions represented in similar form (with limited set of operators).
If you have defined your eval function appropriately, you can prove the property you gave in your example like this:
lemma Mult_comm: "eval (Mult a b) x = eval (Mult b a) x"
by simp
algebra_simps is just a collection of basic simplification rules for groups and rings (such as the integers, in this case). They have nothing to do with this particular example. You can look at the lemmas contained by typing thm algebra_simps.
For this particular proof, you don't actually need algebra_simps, because commutativity of integer multiplication is already a default simplifier rule anyway.
So, to show how to use algebra_simps, consider an example where you actually do need them: right distributivity of multiplication:
lemma Mult_distrib_right: "eval (Mult (Add a b) c) x = eval (Add (Mult a c) (Mult b c)) x"
If you just try apply simp on this, you will get stuck with the goal
(eval a x + eval b x) * eval c x =
eval a x * eval c x + eval b x * eval c x
Luckily, the rule algebra_simps(4) is a rule that says just that: thm algebra_simps(4) will show you that this rule is (?a + ?b) * ?c = ?a * ?c + ?b * ?c. Isabelle's simplifier will apply it automatically if you tell it to use the algebra_simps rules, by doing:
apply (simp add: algebra_simps)
instead of
apply simp
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