coq: Tactic to replace true hypothesis in 'and' statement - coq

Assumptions:
l: a < d
Goal: (s a /\ a < d) <-> s a
Here, I have an /\ with an assumed statement. The goal just needs l to be applied, but I cant seem to figure out the tactic. Apply, rewrite, and replace don't work.

rewrite would only work if a < d was a notation for an equality or an equivalence relation, but here I assume that is not the case.
tauto automatically solves your goal, as does easy, but I think you were asking for something less automatic.
It's a bit disappointing, but the best non-automatic proof I can come up with is to split your goal:
Goal forall a d s, a < d -> (s a /\ a < d) <-> s a.
Proof.
intros a d s l.
split.
- intros [sa _].
exact sa.
- intros sa.
split.
+ exact sa.
+ exact l.
Qed.
If you're interested in using rewrite for this kind of thing, the MathComp library defines things in ways that make rewrite the most useful tactic, and in particular it would work in a translated version of your goal. But probably the best short-term solution here is to make use of some automation tactics.

Using SSReflect/mathcomp, as mentioned by #ana-borges, one can indeed rewrite the Assumption l (which is what -> does); this can then be followed by a split, with a true in the conjunction.
From mathcomp Require Import all_ssreflect.
Goal forall a d s, a < d -> (s a /\ a < d) <-> s a.
Proof. move=> a d s ->; split=> [[sa _] //|sa]; exact: conj. Qed.
Maybe there is another shorter version, though.

I figured it out -- you just have to run propositional, which will evaluate such tautological logic automatically.

Related

Is it possible to turn unification errors into goals in Coq?

I've been working on a formalization for a process calculus in Coq (repository here), and constantly find myself trying to apply a function which fails because of equivalent, but syntactically different, subterms. This often happens because of manipulation of de Bruijn variables. As unification fails, I'll usually just replace misbehaving subterms explictly beforehand and then apply the function I need. A simple code as an example of what I mean:
Require Import Lia.
Goal
forall P: nat -> Prop,
(forall a b c, P (a + (b + c))) ->
forall a b c, P (b + c + a).
Proof.
intros.
(* Unification fails here. *)
Fail apply H.
(* Replace misbehaving subterms explictly. *)
replace (b + c + a) with (a + (b + c)).
- (* Now application succeeds. *)
apply H.
- (* Show now they were the same thing. *)
lia.
Qed.
So, my question is: is there a tactic, or is it possible to write one with ltac, which is similar to apply, but turning unification errors into additional equality goals instead of failing?
applys_eq from Programming Language Foundations' LibTactics will accomplish that. From the documentation (as of Version 6.1 of the book):
applys_eq H helps proving a goal of the form P x1 .. xN from an [sic] hypothesis H that concludes P y1 .. yN, where the arguments xi and yi may or may not be convertible. Equalities are produced for all arguments that don't unify.
The tactic invokes equates on all arguments, then calls applys K, and attempts reflexivity on the side equalities.

Coq auto tacitc fails

I have the following Coq program that tries to prove n <= 2^n with auto:
(***********)
(* imports *)
(***********)
Require Import Nat.
(************************)
(* exponential function *)
(************************)
Definition f (a : nat) : nat := 2^a.
Hint Resolve plus_n_O.
Hint Resolve plus_n_Sm.
(**********************)
(* inequality theorem *)
(**********************)
Theorem a_leq_pow_2_a: forall a, a <= f(a).
Proof.
auto with *.
Qed.
I expected Coq to either succeed or get stuck trying to. But it immediately returns. What am I doing wrong?
EDIT
I added the Hint Unfold f., and increased bound to 100
but I can't see any unfolding done with debug auto 100:
(* debug auto: *)
* assumption. (*fail*)
* intro. (*success*)
* assumption. (*fail*)
* intro. (*fail*)
* simple apply le_n (in core). (*fail*)
* simple apply le_S (in core). (*fail*)
EDIT 2
I'm adding the manual proof to demonstrate its complexity:
(**********************)
(* inequality theorem *)
(**********************)
Theorem a_leq_pow_2_a: forall a, a <= f(a).
Proof.
induction a as[|a' IHa].
- apply le_0_n.
- unfold f.
rewrite Nat.pow_succ_r.
* rewrite Nat.mul_comm.
rewrite Nat.mul_succ_r.
rewrite Nat.mul_1_r.
unfold f in IHa.
rewrite Nat.add_le_mono with (n:=1) (m:=2^a') (p:=a') (q:=2^a').
-- reflexivity.
-- apply Nat.pow_le_mono_r with (a:=2) (b:=0) (c:=a').
auto. apply le_0_n.
-- apply IHa.
* apply le_0_n.
Qed.
The manual proof that you performed explains why auto can't do it. You did a proof by induction and then a few rewrites. The auto tactic does not allow itself this kind of step.
The tactic auto is meant to find a proof if a manual proof only uses apply with a restricted set of theorems. Here the restrict set of theorems is taken from the core hint database. For the sake of brevity, let's assume this database only contains le_S, le_n, plus_n_O and plus_n_Sm.
To simplify, let's assume that we work with the goal a <= 2 ^ a. The head predicate of this statement is _ <= _ so the tactic will only look at theorems whose principal statement is expressed with _ <= _. This rules out
plus_n_O and plus_n_Sm. Your initiative of adding these goes down the drain.
If we look at le_n the statement is forall n : nat, n <= n. If we replace the universal quantification by a pattern variable, this pattern is ?1 < ?1. Does this unify with a <= 2 ^ a? The answer is no. so this theorem won't be used by auto. Now if we look at le_S, the pattern of the principal statement is ?1 <= S ?2. Unifying this pattern with a <= 2 ^ a, this would require ?1 to be a. Now what could be the value of ?2? We need to compare symbolically the expressions 2 ^ a and S ?2. On the left hand side the function symbol is either _ ^ _ or 2 ^ _ depending on how you wish to look at it, but anyway this is not S. So auto recognizes these functions are not the same, the lemma cannot apply. auto fails.
I repeat: when given a goal, auto first only looks at the head symbol of the goal, and it selects from its database the theorems that achieves proofs for this head symbol. In your example, the head symbol is _ <= _. Then it looks only at the conclusion of these theorems, and checks whether the conclusion matches syntactically with the goal at hand. If it does match, then this should provide values for the universally quantified variables of the theorem, and the premises of the theorem are new goals that should be solved at a lower depth. As was mentioned by #Elazar, the depth is limited to 5 by default.
The Hint unfold directive would be useful only if you had made a definition of the following shape:
Definition myle (x y : nat) := x <= y.
Then Hint Unfold myle : core. would be useful to make sure that the database theorems for _ <= _ are also used to proved instances of myle, as in the following example (it fails if we have 4 occurrences of S, because of the depth limitation).
Lemma myle3 (x : nat) : myle x (S (S (S x))).
Proof. auto with core. Qed.
Please note that the following statement is logically equivalent (according to the definition of addition) but not provable by auto. Even if you add Hint unfold plus : core. as a directive, this won't help because plus is not the head symbol of the goal.
Lemma myleplus3 (x : nat) : myle x (3 + x).
Proof.
auto. (* the goal is unchanged. *)
simpl. auto.
Qed.
I often use automatic tactics from Coq, for instance lia, but I always do so because I can predict if the goal is part of the intended scope of the tactic.
From the documentation:
This tactic implements a Prolog-like resolution procedure to solve the current goal. It first tries to solve the goal using the assumption tactic, then it reduces the goal to an atomic one using intros and introduces the newly generated hypotheses as hints. Then it looks at the list of tactics associated to the head symbol of the goal and tries to apply one of them (starting from the tactics with lower cost). This process is recursively applied to the generated subgoals.
Also, see the warning there:
auto uses a weaker version of apply that is closer to simple apply so it is expected that sometimes auto will fail even if applying manually one of the hints would succeed.
And finally, the search depth is limited to 5 by default; you can control it using auto num.
So if at any point, none of the "tactics associated to the head symbol" of the current goal makes any progress, auto will fail. And if auto reaches maximum depth, it will fail.
Note that auto it does not automatically apply the unfold tactic. There's no way to solve a <= f(a) when f is opaque, without further assumptions. If you want, you can use Hint Unfold f or Hint Transparent f.

Basic manipulation of algebraic expressions

I'm still missing the basic technique to manipulate algebraic expressions by adding the same value to both sides. For instance, if the present goal is a + b < a + 5, how do I transform it to b < 5 as one would do in a pen-paper proof? Thanks for any help.
For this kind of things, you need to use the lemmata that already prove this.
Most of these are proven in Arith.
If you type
From Coq Require Import Arith.
Search "+" "<".
Coq will tell you of lemmata that talk about both addition and the 'lower than' relation.
In particular you will find
plus_lt_compat_l: forall n m p : nat, n < m -> p + n < p + m
So that
Goal forall a b, a + b < a + 5.
intros a b.
apply plus_lt_compat_l.
will indeed leave you to prove b < 5.
More often than not, you do not really want to go through the search and instead use some automation. For this lia is recommended.
From Coq Require Import Lia.
Goal forall a b, a + b < a + 5.
intros a b.
cut (b < 5).
{ lia. }
(* The remaining goal is b < 5 *)
lia is a tactic that solves many arithmetic problems like those.
Ok, let's set up this goal. Although nat and < are predefined, you need Require Import Arith for many basic theorems about arithmetic.
Require Import Arith.
Goal forall a b : nat, b < 5 -> a + b < a + 5.
intros.
First let's see how to find the right lemma from the library manually. We can search the available lemmas whose conclusion has the right shape.
SearchPattern (_+_ < _+_).
This returns many lemmas, one of which happens to have the right shape (were the left-hand sides of the + operator are the same on both sides): plus_lt_compat_l. So we can apply this lemma.
apply plus_lt_compat_l.
assumption.
Qed.
Note that sometimes there might be a lemma with < but not one with <=, and SearchPattern won't find that. In such cases, unfold lt in *. to expand all uses of < to <= might help, possibly followed by additional rewriting to move the S around.
Of course finding the right lemma each time is tedious, so there are ways to automate this search. One of the ways is to use a hint database. There's a built-in database called arith, which includes this lemma. auto with arith tries to apply any combination of lemmas from the arith database up to a certain depth. The variant eauto with arith, not needed here, would also try to invent intermediate variables.
Require Import Arith.
Goal forall a b : nat, b < 5 -> a + b < a + 5.
intros.
auto with arith.
Qed.
For arithmetic specifically, there are “just solve this” targets, such as lia (or omega in older versions of Coq), which can solve any inequation involving additions of variables and constants.
Require Import Omega.
Goal forall a b : nat, b < 5 -> a + b < a + 5.
intros.
omega.
Qed.

Coq: working with inequalities (<>)

I'm trying to understand the logic about working with inequalities in Coq.
When <> is present in the goal, doing intros contra. changes the goal to False and moves the goal to an hypothesis but with <> switched to =. I think I understand how it is sound. If I have as goal a <> b, then a = b as hypothesis would generate a contradiction.
However, I can't do the opposite in Coq. If I have as goal a = b, I can't intros contra. in order to have False as goal and a <> b as hypothesis. Would this intros be logically sound? Is it not supported just because it is never needed to complete a proof?
When <> is in an hypothesis H, doing destruct H. will remove the hypothesis (I can't do destruct (H) eqn:H.) and it will switch any goal to the same that H but with <> switched for =. I don't understand the logic here. If I have an hypothesis which is an inequality, I don't see how not having it is the same as having the equality as goal.
How an inequality is inductive to be used by destruct?
If I have a contradictory hypothesis G 0 <> 0, in order to complete the proof and tell it is a contradiction, I need to do destruct G. (* now the goal is 0 = 0 *). reflexivity. Why is it not possible to just do something like inversion G., as you would do with an hypothesis S n = 0?.
So I have, in fact, 4 related questions marked in bold.
Would this intros [on a goal a = b] be logically sound?
If I understand your question, you want to know if it would be possible to
have a goal a = b, call intros contra, and transform that into the goal H : a <> b |- False. This would be sound, but not derivable in Coq's basic constructive logic for a and b of arbitrary type: it asserts that the proposition a = b supports double-negation elimination (~ (~ a = b) -> a = b). Coq does not support this because it would mean working in a different logical formalism.
How an inequality is inductive to be used by destruct?
As yeputons remarked, a <> b is defined as a = b -> False, and falsity is inductively defined as the proposition with no constructors; thus, destructing something of type False simply completes the proof. Furthermore, calling destruct on something of type A -> B has roughly the effect of generating a goal of type A, feeding that proof into the implication to obtain a proof of B, and then calling destruct on that proof of B. In your case, this means doing exactly what you described.
Why is it not possible to just do something like inversion G., as you would do with an hypothesis S n = 0?
My guess is that inversion is not as lenient as destruct, and is not extended to work on implications as I explained above.

How to return a (intro'd) hypothesis back to the goal formula?

For the proof:
Parameter A B : Prop.
Goal A->B.
intro A.
I get:
1 subgoals
A : A
______________________________________(1/1)
B
How do I return then A back to the goal section? To return to:
1 subgoals
______________________________________(1/1)
A -> B
Use the revert tactic:
revert A.
It is exactly the inverse of intro, cf. the reference manual.
You can use the revert tactic.
Given Coq's plethora of tactics, each with various corner cases and varying quality of documentation, it's quite common that you won't know which tactic to use.
In such cases, I find it useful to think of your proof as a program (see Curry-Howard Isomorphism) and to ask yourself what term you would have to write to solve your goal. The advantages of this approach is that Coq's term language is easier to learn (because there just aren't that many different kinds of terms) and expressive enough to solve all goals solvable with tactics (sometimes the proofs are more verbose though).
You can use the refine tactic to write your proofs in the term language. The argument of refine is a term with holes _. refine discharges the current goal using the term and generates a subgoal for every hole in the term. Once you know how refine works, all you have to do is to come up with a term that does what you want. For example:
revert a hypothesis h with refine (_ h).
introduce a hypothesis h with refine (fun h => _).
duplicate a hypothesis h with refine ((fun h' => _) h).
Note that Coq's tactics tend to do quite a bit of magic behind the scenes. For example, the revert tactic is "smarter" than the refine above when dealing with dependent variables:
Goal forall n:nat, n >= 0.
intro n; revert n. (* forall n : nat, n >= 0 *)
Restart.
intro n; refine (_ n). (* nat -> n >= 0 *)
Restart.
intro n'; refine ((_ : forall n, n >= 0) n'). (* forall n : nat, n >= 0 *)
Abort.