How to automatically introduce symmetries into Coq hypotheses? - coq

I have some equalities (=) and unequalities (<>) in the hypotheses such as:
e : x2 = x1
n : x3 <> x1
I want to use tactics like assumption, but sometimes the expected (un)equality in the goal is in the other direction like:
x1 = x2
x1 <> x3
My question is:
Is it possible to automatically introduce the symmetric forms of (un)equality above into the hypotheses?
If not, is it possible to use Notation to write a tactical to do this.
So far, I can do this manually like this:
assert (x1 = x2) by (symmetry in e; assumption).
assert (x1 <> x3) by (unfold not; intro Hnot;
symmetry in Hnot; unfold not in n; apply n in Hnot; inversion Hnot).
But it is really tedious and noisy. I don't know enough about how to automate this or if there is a better way.

Perhaps this tactic can help:
Ltac maybe_intro_sym A B :=
match goal with
|[H:B=A|-_] => fail 1
|[H:A=B|-_] => assert (B=A) by auto
end.
Ltac maybe_intro_sym_neg A B :=
match goal with
|[H:B<>A|-_] => fail 1
|[H:A<>B|-_] => assert (B<>A) by auto
end.
Ltac intro_sym :=
repeat match goal with
|[H:?A=?B|-_] => maybe_intro_sym A B
|[H:?A<>?B|-_] => maybe_intro_sym_neg A B
end.
Here's an example:
Parameters a b c d:nat.
Goal a=b -> c=d -> c<>d -> True.
intros.
intro_sym.
Now the context is
H : a = b
H0 : c = d
H1 : c <> d
H2 : d = c
H3 : b = a
H4 : d <> c
============================
True

Related

Why can I not apply f_equal to a hypothesis?

In my list of hypothesis, I have:
X : Type
l' : list X
n' : nat
H : S (length l') = S n'
My goal is length l' = n'.
So I tried f_equal in H. But I get the following error:
Syntax error: [tactic:ltac_use_default] expected after [tactic:tactic] (in [vernac:tactic_command]).
Am I wrong in thinking I should be able to apply f_equal to H in order to remove the S on both sides?
f_equal is about congruence of equality. It can be used to prove f x = f y from x = y. However, it cannot be used to deduce x = y from f x = f y because that is not true in general, only when f is injective.
Here it is a particular case as S is a constructor of an inductive type, and constructors are indeed injective. You could for instance use tactics like inversion H to obtain the desired equality.
Another solution involving f_equal would be to apply a function that removes the S like
Definition removeS n :=
match n with
| S m => m
| 0 => 0
end.
and then use
apply (f_equal removeS) in H.
f_equal tells you that if x = y, then f x = f y. In other words, when you have x = y and need f x = f y, you can use f_equal.
Your situation is the reverse. You have f x = f y and you need x = y, so you can't use f_equal.
If you think about your conclusion, it is only true when S is an injection. You need a different tactic.

How does the "intro ->" in Coq work on context?

I am interested in how does dependent-typed theorem provers do substitution on the context. I find a thing called "intro ->" in Coq, as described in:
https://coq.inria.fr/refman/proof-engine/tactics.html#intropattern-rarrow-ex
In the example, it says the goal:
x, y, z : nat
H : x = y
y = z -> x = z
will become
x, z : nat
H : x = z
x = z
after an application of "intros ->".
I am not sure how is the step of substituting H:x = y into H:x = z be done, what is the rule of the logic of Coq is this step according to? It seems like a step of rewriting, and according to my current knowledge most of these rewriting are according to equalities, so the replacement from H:x = y into H:x = z should come from an equality like (H:x = y) = (H:x= z) ($\diamond$), but such an equality is ill-formed because, in principle, we require the LHS and RHS of an equality to have the same type, so the well-formedness of such equality ($\diamond$) depends on the assumption that y = z.
Could someone please help explaining how does "intro ->" work here? Do we need to get "equalities" like ($\diamond$) involved?
In Coq, rewriting on the context is a derived notion. The tactic intros -> in this case is roughly equivalent to the following tactics:
intros H'. rewrite H' in H. clear y H'.
The tactic rewrite H' in H., in turn, is roughly equivalent to
revert H. rewrite H'. intros H.
In words, to rewrite on the context, Coq first transfers all the relevant hypotheses to the goal, rewrites the goal and then brings the hypotheses back to the context.
Rewriting the goal uses the following elimination principle for the equality type:
forall [A : Type] [a : A] (P : A -> Prop), P a -> forall b : A, b = a -> P b
For rewriting H' above, we would have:
A := T
a := z
P := fun c => x = c -> x = z
b := y
so,
P b == x = y -> x = z
P a == x = z -> x = z
Indeed, ignoring the move steps to and from the context, Coq went from P b to P a when you performed the rewrite.

Coq forward reasoning: apply with multiple hypotheses

I have two hypothesis, and I would like to use forward reasoning to apply a theorem that uses both of them.
My specific I have the hypothes
H0 : a + b = c + d
H1 : e + f = g + h
and I want to apply the theorem from the standard library:
f_equal2_mult
: forall x1 y1 x2 y2 : nat, x1 = y1 -> x2 = y2 -> x1 * x2 = y1 * y2
Now I know I could manually give the values for x1, y1, x2, y2, but I would like Coq to automatically determine those values when it unified with H0 and H1. I have figured out that I can get it to work like so:
eapply f_equal2_mult in H0; try exact H1.
But this feels like a hack, with the broken symmetry and the try. I really would like to be able to say apply f_equals2_mult in H0, H1 or something similarly clear. Is there a way like this?
You could use pose proof to introduce the lemma in the context, and specialize to apply it to other hypotheses.
Lemma f (a b c d : nat) : a = b -> c = d -> False.
intros H1 H2.
pose proof f_equal2_mult as pp.
specialize pp with (1 := H1).
specialize pp with (1 := H2).
(* or *)
specialize pp with (1 := H1) (2 := H2).

Equality of proof-carrying dependent functions in Coq

Suppose we have:
Require Import ZArith Program Omega.
Open Scope Z_scope.
Definition Z_to_nat (z : Z) (p : 0 <= z) : nat.
Proof.
dependent destruction z.
- exact (0%nat).
- exact (Pos.to_nat p).
- assert (Z.neg p < 0) by apply Zlt_neg_0.
contradiction.
Qed.
Now I would like to formulate something like this:
Lemma Z_to_nat_pred : forall x y p p', (Z_to_nat x p <= Z_to_nat y p')%nat <-> x <= y.
This doesn't seem quite right to me, because in x <= y, I can have negative x, y, and then I won't have proofs about their positivity. All in all, the dependent Z_to_nat seems extremely difficult to use. How does one formulate that it suffices to show x <= y to conclude (Z_to_nat x p <= Z_to_nat y p')%nat and the other way around?
I've given it a bash to inspect the way I could formulate the proof (although I am fairly sure it can't be proven with this formulation).
I've tried:
Lemma Z_to_nat_pred : forall x y p p',
(Z_to_nat x p <= Z_to_nat y p')%nat <-> x <= y.
Proof.
intros.
split; intros.
- dependent destruction x;
dependent destruction y; try easy; try omega.
Which leads me to the following goal:
p : positive
p0 : 0 <= Z.pos p
p' : 0 <= 0
H : (Z_to_nat (Z.pos p) p0 <= Z_to_nat 0 p')%nat
______________________________________(1/1)
Z.pos p <= 0
Could I here, for example, solve the goal by deriving contradiction from H, as Z.pos p cannot be <= 0? I can't really do much with the Z_to_nat definition.
here are several remarks that are related to your question:
In Coq when one defines functions using tactics and especially when we want to compute with, it is preferable to end the corresponding proof script with Defined., not Qed. (the notion at stake is "transparent definition" vs. "opaque definition", cf. the Coq ref man)
so if you replace Qed with Defined, the tactic simpl in H. will be applicable in your proof of Z_to_nat_pred
EDIT: another tactic that would have been useful in your goal is exfalso.
your function Z_to_nat is a partial function that takes a proof as argument. But in many practical cases, it is simpler to avoid dependent types, and just use a default value (making thus the function "total")
this latter strategy is already that of the two functions below that are available in the the standard library (that you have already imported with Require Import ZArith). These two functions can be viewed as two ways to define your function Z_to_nat in a non-dependently-typed way:
Print Z.abs_nat.
Z.abs_nat =
fun z : Z => match z with
| 0 => 0%nat
| Z.pos p => Pos.to_nat p
| Z.neg p => Pos.to_nat p
end
: Z -> nat
Print Z.to_nat.
Z.to_nat =
fun z : Z => match z with
| 0 => 0%nat
| Z.pos p => Pos.to_nat p
| Z.neg _ => 0%nat
end
: Z -> nat
Finally it appears that for each of these two functions, lemmas similar to yours are available in ZArith:
SearchAbout Z.abs_nat Z.le iff.
Zabs2Nat.inj_le: forall n m : Z, 0 <= n -> 0 <= m -> n <= m <-> (Z.abs_nat n <= Z.abs_nat m)%nat
Zabs2Nat.inj_lt: forall n m : Z, 0 <= n -> 0 <= m -> n < m <-> (Z.abs_nat n < Z.abs_nat m)%nat
SearchAbout Z.to_nat Z.le iff.
Z2Nat.inj_iff: forall n m : Z, 0 <= n -> 0 <= m -> Z.to_nat n = Z.to_nat m <-> n = m
Z2Nat.inj_le: forall n m : Z, 0 <= n -> 0 <= m -> n <= m <-> (Z.to_nat n <= Z.to_nat m)%nat
Z2Nat.inj_lt: forall n m : Z, 0 <= n -> 0 <= m -> n < m <-> (Z.to_nat n < Z.to_nat m)%nat
Best regards

How to add to both sides of an equality in Coq

This seems like a really simple question, but I wasn't able to find anything useful.
I have the statement
n - x = n
and would like to prove
(n - x) + x = n + x
I haven't been able to find what theorem allows for this.
You should have a look at the rewrite tactic (and then maybe reflexivity).
EDIT: more info about rewrite:
You can rewrite H rewrite -> H to rewrite from left to right
You can rewrite <- H to rewrite from right to left
You can use the pattern tactic to only select specific instances of the goal to rewrite. For example, to only rewrite the second n, you can perform the following steps
pattern n at 2.
rewrite <- H.
In your case, the solution is much simpler.
Building on #gallais' suggestion on using f_equal. We start in the following state:
n : nat
x : nat
H : n - x = n
============================
n - x + x = n + x
(1) First variant via "forward" reasoning (where one applies theorems to hypotheses) using the f_equal lemma.
Check f_equal.
f_equal
: forall (A B : Type) (f : A -> B) (x y : A), x = y -> f x = f y
It needs the function f, so
apply f_equal with (f := fun t => t + x) in H.
This will give you:
H : n - x + x = n + x
This can be solved via apply H. or exact H. or assumption. or auto. ... or some other way which suits you the most.
(2) Or you can use "backward" reasoning (where one applies theorems to the goal).
There is also the f_equal2 lemma:
Check f_equal2.
f_equal2
: forall (A1 A2 B : Type) (f : A1 -> A2 -> B)
(x1 y1 : A1) (x2 y2 : A2),
x1 = y1 -> x2 = y2 -> f x1 x2 = f y1 y2
We just apply it to the goal, which results in two trivial subgoals.
apply f_equal2. assumption. reflexivity.
or just
apply f_equal2; trivial.
(3) There is also the more specialized lemma f_equal2_plus:
Check f_equal2_plus.
(*
f_equal2_plus
: forall x1 y1 x2 y2 : nat,
x1 = y1 -> x2 = y2 -> x1 + x2 = y1 + y2
*)
Using this lemma we are able to solve the goal with the following one-liner:
apply (f_equal2_plus _ _ _ _ H eq_refl).
There is a powerful search engine in Coq using patterns. You can try for example:
Search (_=_ -> _+_=_+_).