What's the difference between revert and generalize tactics in Coq? - coq

From the Coq reference manual (8.5p1), my impression is that revert is the inverse of intro, but so is generalize to a certain extent. For example, revert and generalize dependent below seem to be the same.
Goal forall x y: nat, 1 + x = 2 + y -> 1 + x + 5 = 7 + y.
intros x y. revert x y.
intros x y. generalize dependent y. generalize dependent x.
Is it just that generalize is more powerful than revert?
Also, the documentation is a bit circular in explaining things about generalize:
This tactic applies to any goal. It generalizes the conclusion with
respect to some term.
Is generalize similar to the abstraction operator in lambda calculus?

Yes, generalize is more powerful. You've demonstrated it has at least the same power as revert by simulating revert with generalize.
Notice that generalize works on any terms, revert -- only on identifiers.
For example, revert cannot do the example from the manual:
x, y : nat
============================
0 <= x + y + y
Coq < generalize (x + y + y).
1 subgoal
x, y : nat
============================
forall n : nat, 0 <= n
As for "circularity" of the definition, the real explanation is right below the example:
If the goal is G and t is a subterm of type T in the goal, then generalize t replaces the goal by forall x:T, G0 where G0 is obtained from G by replacing all occurrences of t by x.
Essentially, this says generalize wraps your goal in forall, replacing some term with a fresh variable (x).
Of course, generalize should be used with some thought and caution, since one can get a false statement to prove after using it:
Goal forall x y, x > 0 -> 0 < x + y + y.
intros x y H.
generalize dependent (x + y + y).
(* results in this proof state: *)
x, y : nat
H : x > 0
============================
forall n : nat, 0 < n

From what I recall, revert is just a simpler form of generalize, which is usually easier to use for newcomers: it is the opposite of intro. Using a flavor of generalize, you can do much more (especially with dependency between terms and types).

Related

Coq syntax for defining lemmas

I can see the different syntax of Coq for defining lemmas. For example, Lemma plus_n_O: forall n:nat, n = n + 0. and Lemma plus_n_O n: n = n + 0. both define that the sum of zero by any number is equal to the number. How these definitions differ? Or this is a new feature of Coq to remove forall quantifier from definitions.
These two definitions are essentially equivalent. Generally speaking, any statement of the form
Lemma foo x y z : P.
Proof.
(* ... *)
is equivalent to
Lemma foo : forall x y z, P.
Proof.
intros x y z.
(* ... *)

What does the tactic `Induction` followed by a number do?

What effect does the following tactic have on the goal and the assumptions?
I know what induction on variables and named hypothesis do, but am unclear about induction on a number.
Induction 1
From the Coq Reference Manual: https://coq.inria.fr/distrib/current/refman/proof-engine/tactics.html#coq:tacn.induction
(...) induction num behaves as intros until num followed by induction applied to the last introduced hypothesis.
And for intros until num: https://coq.inria.fr/distrib/current/refman/proof-engine/tactics.html#coq:tacv.intros
intros until num: This repeats intro until the num-th non-dependent product.
Example
On the subgoal forall x y : nat, x = y -> y = x the tactic intros until 1 is equivalent to intros x y H, as x = y -> y = x is the first non-dependent product.
On the subgoal forall x y z : nat, x = y -> y = x the tactic intros until 1 is equivalent to intros x y z as the product on z can be rewritten as a non-dependent product: forall x y : nat, nat -> x = y -> y = x.
For reference, there is an index of standard tactics in the Manual where those can easily be looked up: https://coq.inria.fr/distrib/current/refman/coq-tacindex.html
(There are other indices in there that you may find interesting as well.)

How to build a function implicitly in Coq?

I am trying to prove that every group has an inverse function.
I have defined a group as follows:
Record Group:Type := {
G:Set;
mult:G->G->G;
e:G;
assoc:forall x y z:G, mult x (mult y z)=mult (mult x y) z;
neut:forall x:G, mult e x=x /\ mult x e=x;
inverse:forall x:G,exists y:G, mult x y = e
}.
I am aware that it is better to just replace the inverse axiom by inverse:forall x:G, {y: mult x y = e}., or even inverse:G->G. is_inverse:forall x:G, mult x (inverse x)=e., but I prefer my definition, mainly because I want the definition to be identical to the one given in a classroom.
So I have included a suitable version of the axiom of choice:
Axiom indefinite_description : forall (A : Type) (P: A->Prop), ex P -> sig P.
Axiom functional_choice : forall A B (R:A->B->Prop), (forall x, exists y, R x y) -> (exists f, forall x, R x (f x)).
Now I can prove my claim:
Lemma inv_func_exists(H:Group):exists inv_func:G H->G H, (forall x:G H, mult H x (inv_func(x))=e H).
generalize (inverse H).
apply functional_choice.
Qed.
Now that I have proved the existence, I would like to define an actual function. Here I feel that things start to go messy. The following definition creates an actual function, but seems to ugly and complicated:
Definition inv_func(H:Group):G H->G H.
pose (inv_func_exists H).
pose indefinite_description.
generalize e0 s.
trivial.
Qed.
Lastly, I would like to prove that inv_func is actually an inverse function:
Lemma inv_func_is_inverse:forall (H:Group), forall x:(G H), mult H x (inv_func H x)=e H.
I can see that Coq knows how inv_func was defined (e.g. Print inv_func), but I have no idea how to formally prove the lemma.
To conclude, I would appreciate suggestions as to how to prove the last lemma, and of better ways to define inv_func (but under my definition of group, without including the existence of such a function in the group definition. I believe the question could be relevant in many other situations when one can prove some correspondence for each element and needs to build this correspondence as a function).
There are quite a few questions inside your question. I'll try to address all of them:
First, there is no reason to prefer exists x, P + description over {x | P}, indeed, it seems weird you do so. {x | P} is perfectly valid as "there exists a x that can be computed" and I would rather use that definition with your groups.
Secondly, when creating definitions using tactics, you should end the proof with the command Defined. Using Qed will declare the definition "Opaque", which means it cannot be expanded, then preventing you proof.
The way to extract the witness from your definition is by using a projection. In this case, proj1_sig.
Using all the above we arrive at:
Definition inv_func' (H:Group) (x : G H) : G H.
Proof.
destruct (inverse H x) as [y _].
exact y.
Defined.
Definition inv_func (H:Group) (x : G H) : G H := proj1_sig (inverse H x).
Lemma inv_func_is_inverse (H:Group) (x: G H) : mult H x (inv_func H x) = e H.
Proof. now unfold inv_func; destruct (inverse H x). Qed.

Proving st X + st Y = st Y + (st X - 1) + 1 using Coq

Just like the title says, I'm looking for a way to prove st X + st Y = st Y + (st X - 1) + 1 in Coq. I've been trying applying various combinations of plus_comm, plus_assoc and plus_permute but I haven't been able to make it go through. Any suggestions?
Here is the goal window:
3 subgoal
n : nat
m : nat
st : state
H : st Y + st X = n + m /\ beval st (BNot (BEq (AId X) (ANum 0))) = true
______________________________________(1/3)
st Y + 1 + (st X - 1) = n + m
For integers, either ring or omega should be able to solve such a goal. It can also be done manually. It helps to disable notations so that function names appear (in order use SearchAbout to find useful lemmas). The following is probably not the shortest possible proof, just the first I found:
Require Import ZArith.
Lemma simple: forall x y, (x + y)%Z = (y + (x - 1) + 1)%Z.
intros.
rewrite Z.add_sub_assoc.
replace ((y + x)%Z) with ((x + y)%Z).
Focus 2.
rewrite Z.add_comm.
reflexivity.
set (t := ((x + y)%Z)).
replace (1%Z) with (Z.succ 0).
Focus 2.
symmetry.
apply Z.one_succ.
rewrite Zminus_succ_r.
rewrite Z.add_succ_r.
rewrite <- Zminus_0_l_reverse.
rewrite <- Zplus_0_r_reverse.
rewrite Z.succ_pred.
reflexivity.
Qed.
For those looking to use omega as a quick-fix, here's one way to get the goal into a form where it can be applied:
inversion H.
inversion H1.
rewrite negb_true_iff in H3.
apply beq_nat_false in H3.
omega.
For why omega works after we do this and not when the goal was in the original state, here is a great answer by Github user jaewooklee93:
"You don't need to think about plus_comm or similar lemmas here, because omega can solve those easy problems. Your goals are almost trivial, but the reason why omega hesistates to clear the goals is just because the minus between nat is not the same as the one we already know; 2-5=0, since there is no notion of negative in nat. So if you don't provide the fact that st X is greater than zero, omega cannot clear the goal for you. But you already have that condition in H1. Therefore, the only thing you should do is to simplify H1 and apply lemmas to H1 to make it st X<>0 .Then omega can properly work."

How to "flip" an equality proposition in Coq?

If I'm in Coq and I find myself in a situation with a goal like so:
==================
x = y -> y = x
Is there a tactic that can can take care of this in one swoop? As it is, I'm writing
intros H. rewrite -> H. reflexivity.
But it's a bit clunky.
To "flip" an equality H: x = y you can use symmetry in H. If you want to flip the goal, simply use symmetry.
If you're looking for a single tactic, then the easy tactic handles this one immediately:
Coq < Parameter x y : nat.
x is assumed
y is assumed
Coq < Lemma sym : x = y -> y = x.
1 subgoal
============================
x = y -> y = x
sym < easy.
No more subgoals.
If you take a look at the proof that the easy tactic found, the key part is an application of eq_sym:
sym < Show Proof.
(fun H : x = y => eq_sym H)
The heavier-weight auto tactic will also handle this goal in a single step. For a slightly lower-level proof that produces exactly the same proof term, you can use the symmetry tactic (which also automatically does the necessary intro for you):
sym < Restart.
1 subgoal
============================
x = y -> y = x
sym < symmetry.
1 subgoal
H : x = y
============================
x = y
sym < assumption.
No more subgoals.
sym < Show Proof.
(fun H : x = y => eq_sym H)