What is the right proof term so that the ssreflect tutorial work with the exact: hAiB example? - coq

I was going through the tutorial https://hal.inria.fr/inria-00407778/document for ssreflect and they have the proof:
Variables A B C : Prop.
Hypotheses (hAiBiC : A -> B -> C) (hAiB : A -> B) (hA : A).
Lemma HilbertS2 :
C.
Proof.
apply: hAiBiC; first by apply: hA.
exact: hAiB.
Qed.
but it doesn't actually work since the goal is
B
which puzzled me...what is this not working because the coq version changed? Or perhaps something else? What was the exact argument supposed to be anyway?
I think I do understand what the exact argument does. It completes the current subgoal by making sure the proof term (program) given has the type of the current goal. e.g.
Theorem add_easy_induct_1_exact:
forall n:nat,
n + 0 = n.
Proof.
exact (fun n : nat =>
nat_ind (fun n0 : nat => n0 + 0 = n0) eq_refl
(fun (n' : nat) (IH : n' + 0 = n') =>
eq_ind_r (fun n0 : nat => S n0 = S n') eq_refl IH) n).
Qed.
for the proof of addition's commutativity.
Module ssreflect1.
(* Require Import ssreflect ssrbool eqtype ssrnat. *)
From Coq Require Import ssreflect ssrfun ssrbool.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Theorem three_is_three:
3 = 3.
Proof. by []. Qed.
(*
https://stackoverflow.com/questions/71388591/what-does-apply-tactic-on-its-own-do-in-coq-i-e-without-specifying-a-rul
*)
Lemma HilbertS :
forall A B C : Prop,
(A -> B -> C) -> (A -> B) -> A -> C.
(* A ->(B -> C)*)
Proof.
move=> A B C. (* since props A B C are the 1st things in the assumption stack, this pops them and puts them in the local context, note using the same name as the proposition name.*)
move=> hAiBiC hAiB hA. (* pops the first 3 premises from the hypothesis stack with those names into the local context *)
move: hAiBiC. (* put hAiBiC tactic back *)
apply.
by [].
(* move: hAiB.
apply. *)
by apply: hAiB.
(* apply: hAiB.
by [].dd *)
Qed.
Variables A B C : Prop.
Hypotheses (hAiBiC : A -> B -> C) (hAiB : A -> B) (hA : A).
Lemma HilbertS2 :
C.
Proof.
apply: hAiBiC; first by apply: hA.
exact: hAiB.
Qed.
Lemma HilbertS2 :
C.
Proof.
(* apply: hAiBiC; first by apply: hA. *)
apply: hAiBiC. (* usually we think of : as pushing to the goal stack, so match c with conclusion in
selected hypothesis hAiBiC and push the replacement, so put A & B in local context. *)
by apply: hA. (* discharges A *)
exact: hAiB.
End ssreflect1.
full script I was using. Why does that not put the hypothesis in the local context?

The reason why your example fails is probably that you did not open a section. The various hypotheses that you declare are then treated as "axioms" and not in the context of the goal.
On the other hand, if you start a section before the fragment of text that you posted, everything works, because then the goal before the exact: hAiB. tactic also contains hypothesis hA, which is necessary for exact: to succeed.
Here is the full script (tested on coq 8.15.0)
From mathcomp Require Import all_ssreflect.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Section sandbox.
Variables A B C : Prop.
Hypotheses (hAiBiC : A -> B -> C) (hAiB : A -> B) (hA : A).
Lemma HilbertS2 :
C.
Proof.
apply: hAiBiC; first by apply: hA.
exact: hAiB.
Qed.
End sandbox.

Related

The missing De Morgan's law

Coq uses constructive logic, which means that if you try to fill out
De Morgan's laws, you'll end up missing 2.
Namely, you can't prove:
Theorem deMorgan_nand P Q (andPQ : ~(P /\ Q)) : P \/ Q.
Abort.
Theorem deMorgan_nall {A} (P : A -> Prop) (allPa : ~forall a, P a) : exists a, ~P a.
Abort.
This makes sense, because you've have to compute whether it was
the left or right item of the or, which you can't do in general.
Looking at
"Classical Mathematics for a Constructive World"
(https://arxiv.org/pdf/1008.1213.pdf)
has the definitions
Definition orW P Q := ~(~P /\ ~Q).
Definition exW {A} (P : A -> Prop) := ~forall a, ~P a.
similar to De Morgan's law. This suggests an alternative formulation.
Theorem deMorgan_nand P Q (andPQ : ~(P /\ Q)) : orW (~P) (~Q).
hnf; intros nnPQ; destruct nnPQ as [ nnP nnQ ].
apply nnP; clear nnP; hnf; intros p.
apply nnQ; clear nnQ; hnf; intros q.
apply (andPQ (conj p q)).
Qed.
Theorem deMorgan_nall {A} (P : A -> Prop) (allPa : ~forall a, P a) : exW (fun a => ~P a).
Abort.
But, it doesn't work with negating forall. In particular, it gets stuck on
trying to convert ~~P a into P a. So, despite in the nand case
converting ~~P into P, it doesn't seem to work with forall.
You can also show that there is some element of a that has
P a.
Similarly, you could try to show
Theorem deMorgan_nexn {A} (P : A -> Prop) (exPa : ~exists a, ~P a) : ~~forall a, P a.
Abort.
but that gets stuck in that once you have the argument a,
the conclusion is no longer False, so you can't use ~~P -> P.
So, if you can't prove deMorgan_nall, is there any theorem like it?
Or is ~forall a, P a already as simplified as it can get?
More generally, when the conclusion is False, that allows for using
the law of excluded middle (P \/ ~P). Is there any counterpart
to that that works when the proposition takes an argument, that is
P : A -> Prop instead of P : Prop ?
The principle you are looking for is known as double negation shift. It is not valid in intuitionistic logic in general. Despite looking fairly innocuous at first, as its conclusion is a doubly-negated formula, it is actually quite potent. Indeed, DNS is essentially what is needed in order to interpret the axiom of choice through the double-negation translation.
Edit by scubed:
So, that means I have to add an axiom to handle this case. Using the axiom,
Axiom deMorgan_allnn : forall {A} (P : A -> Prop) (allPa : forall a, ~~P a), ~~forall a, P a.
Theorem deMorgan_nall {A} (P : A -> Prop) (allPa : ~forall a, P a) : exW (fun a => ~P a).
hnf; intros ex1; apply deMorgan_allnn in ex1.
apply ex1; clear ex1; hnf; intros all2.
apply (allPa all2).
Qed.

Understanding specialize tactic

Trying to comprehend the answer of #keep_learning I walked through this code step by step:
Inductive nostutter {X:Type} : list X -> Prop :=
| ns_nil : nostutter []
| ns_one : forall (x : X), nostutter [x]
| ns_cons: forall (x : X) (h : X) (t : list X), nostutter (h::t) -> x <> h -> nostutter (x::h::t).
Example test_nostutter_4: not (nostutter [3;1;1;4]).
Proof.
intro.
inversion_clear H.
inversion_clear H0.
unfold not in H2.
(* We are here *)
specialize (H2 eq_refl).
apply H2.
Qed.
Here is what we have before excuting specialize
H1 : 3 <> 1
H : nostutter [1; 4]
H2 : 1 = 1 -> False
============================
False
Here is eq Prop whose constructor eq_refl is used in specialize:
Inductive eq (A:Type) (x:A) : A -> Prop :=
eq_refl : x = x :>A
where "x = y :> A" := (#eq A x y) : type_scope.
I can't explain, how this command works:
specialize (H2 eq_refl).
I read about specialize in reference manual, but the explanation there is too broad. As far as I understand it sees that "1 = 1" expression in H2 satisfies eq_refl constructor and therefore eq proposition is True. Then it simplifies the expression:
True -> False => False
And we get
H1 : 3 <> 1
H : nostutter [1; 4]
H2 : False
============================
False
Can somebody provide me a minimal example with explanation of what is specialize doing, so I could freely use it?
Update
Trying to imitate how specialize works using apply I did the following:
Example specialize {A B: Type} (H: A -> B) (a: A): B.
Proof.
apply H in a.
This gives:
A : Type
B : Type
H : A -> B
a : B
============================
B
Almost the same as specialize, only different hypothesis name.
In test_nostutter_4 theorem I tried this and it worked:
remember (#eq_refl nat 1) as Heq.
apply H2 in Heq as H3.
It gives us:
H1 : 3 <> 1
H : nostutter [1; 4]
H2 : 1 = 1 -> False
Heq : 1 = 1
H3 : False
HeqHeq : Heq = eq_refl
============================
False
This one was more complex, we had to introduce a new hypothesis Heq. But we got what we need - H3 at the end.
Does specialize internally use something like remember? Or is it possible to solve it with apply but without remember?
specialize, in its simplest form, simply replaces a given hypothesis with that hypothesis applied to some other term.
In this proof,
Example specialize {A B: Type} (H: A -> B) (a: A): B.
Proof.
specialize (H a).
exact H.
Qed.
we initially have the hypothesis H: A -> B. When we call specialize (H a), we apply H to a (apply as in function application). This gives us something of type B. specialize then gets rid of the old H for us and replaces it with the result of the application. It gives the new hypothesis the same name: H.
In your case, we have H2: 1 = 1 -> False, which is a function from the type 1 = 1 to the type False. That means that H2 applied to eq_refl is of type False, i.e. H2 eq_refl: False. When we use the tactic specialize (H2 eq_refl)., the old H2 is cleared and replaced by a new term (H2 eq_refl) whose type is False. It keeps the old name H2, though.
specialize is useful when you're sure that you're only going to use a hypothesis once, since it automatically gets rid of the old hypothesis. One disadvantage is that the old name may not fit the meaning of the new hypothesis. However, in your case and in my example, H is a generic enough name that it works either way.
To your update...
specialize is a core tactic defined directly in the ltac plugin. It doesn't use any other tactic internally, since it is its internals.
If you want to keep a hypothesis, you can use the as modifier, which works for both specialize and apply. In the proof
Example specialize {A B: Type} (H: A -> B) (a: A): B.
Proof.
if you do specialize (H a) as H0., instead of clearing H, it'll introduce a new hypothesis H0: B. apply H in a as H0. has the same effect.

Tactic to prove a boolean implication

Is there a tactic similar to intros to prove a boolean implication such as
f : nat -> bool
g : nat -> bool
Lemma f_implies_g : forall n : nat, eq_true(implb (f n) (g n)).
This tactic would pull eq_true(f n) into the context and require to prove eq_true(g n).
Let me suggest to use SSReflect in this case. Because it already has the machinery you need. It does not use eq_true to embed bool into Prop, but rather is_true, which is an alternate way to do it.
From Coq Require Import ssreflect ssrbool.
Variables f g : nat -> bool.
Lemma f_implies_g n : (f n) ==> (g n).
Proof.
apply/implyP => Hfn.
Abort.
The snippet above does what you want, implicitly coercing f n and g n into Prop. Having executed the snippet you see this
n : nat
Hfn : f n
============================
g n
but Set Printing Coercions. reveals that it's really
n : nat
Hfn : is_true (f n)
============================
is_true (g n)
that you have.

Typeclass resolution and autorewrite

I have a base of rewrite lemmas. Some of them are parameterized by typeclasses. When applying a lemma, it is important that the rewrite fails when the typeclass cannot be automatically resolved by Coq. The only way I have found to get this behaviour is to declare most of the parameters implicit.
Class T (t:Type) : Type.
Instance T1 : T nat.
Instance T2 : forall {A1 A2:Type} {t1:T A1} {t2:T A2}, T (A1*A2).
Definition f {A:Type} (x:A) := x.
Lemma f_eq : forall {A:Type} (t:T A) (x:A), f x = x.
Proof.
reflexivity.
Qed.
Lemma test1 : f (0,1) = (0,1).
Proof.
rewrite f_eq.
(* a subgoal T (nat * nat) is generated,
which should have been resolved directly *)
Abort.
Lemma test2 : f (0,true) = (0,true).
Proof.
rewrite f_eq.
(* a subgoal T (nat * bool) is generated,
while it should have failed *)
Abort.
Arguments f_eq {_ _} _.
Lemma test1 : f (0,1) = (0,1).
Proof.
rewrite f_eq.
reflexivity. (* OK *)
Qed.
Lemma test2 : f (0,true) = (0,true).
Proof.
Fail rewrite f_eq. (* fails as expected *)
Abort.
Then I want to add my lemmas to a rewrite database, but the lemma added to the database is already specialized.
Hint Rewrite f_eq : my_db.
Print Rewrite HintDb my_db.
(* Database my_db
rewrite -> f_eq of type forall x : nat, f x = x *)
How can I add my lemmas to a rewrite database and get the proper behaviour in terms of typeclass resolution of their arguments ?
EDIT: there is an option Set Typeclass Resolution After Apply. that seems to enable the behaviour that I expect, but only for apply, not rewrite.
The corresponding commit gives the following description:
Add an option to solve typeclass goals generated by apply which can't
be catched otherwise due to the discrepancy between evars and metas.
One possible solution is to use ssreflect's rewrite (this will fix the first part of the problem) and replace the hint db by multi-rewrite rules. That is to say:
From mathcomp Require Import ssreflect.
Class T (t:Type) : Type.
Instance T1 : T nat.
Instance T2 : forall {A1 A2:Type} {t1:T A1} {t2:T A2}, T (A1*A2).
Definition f {A:Type} (x:A) := x.
Lemma f_eq : forall {A:Type} (t : T A) (x:A), f x = x.
Proof. by []. Qed.
(* Add more lemmas as needed *)
Definition my_db A := (#f_eq A, #f_eq A).
Lemma test1 : f (0,1) = (0,1).
Proof. by rewrite my_db. Qed.
Lemma test2 : f (0,true) = (0,true).
Proof.
Fail rewrite f_eq.
Abort.
Here is a workaround. First, we add the generalized lemma, but we tell the autorewrite tactic to use the tactic exact _ to solve the secondary goal of resolving the necessary typeclass instance.
Hint Rewrite #f_eq using (exact _): my_db.
Print Rewrite HintDb my_db.
(*
Database my_db
rewrite -> #f_eq of type forall A : Type, T A -> forall x : A, f x = x
then use tactic exact _
*)
Then you can keep rewriting with rewrite as you've shown in the body of your question, or you can use your database:
Lemma test1' : f (0,1) = (0,1).
Proof.
autorewrite with my_db.
reflexivity.
Qed.
Lemma test2 : f (0,true) = (0,true).
Proof.
autorewrite with my_db.
(* does nothing: no rewrites, no error messages *)
Abort.
Notice that when we use exact _ Coq does not generate new instances of the form Build_T (nat * bool) in the last case, as it would do if we used reflexivity instead.
Here is an example of what I mean by that. If we started with this hint
Hint Rewrite #f_eq using reflexivity: my_db.
we could prove test2 this way
Lemma test2 : f (0,true) = (0,true).
Proof.
autorewrite with my_db.
reflexivity.
Qed.
But if we look at it using Set Printing All. Print test2. we will see that Coq constructed a new instance of T: (Build_T (prod nat bool)) which I think goes against your goal -- it seems you'd prefer Coq to infer an already existing instance of T if it's possible at all or fail in some way.
We can repeat the same thing manually:
Lemma test2' : f (0,true) = (0,true).
Proof.
rewrite #f_eq. reflexivity.
exact (Build_T (nat * bool)). (* `exact _` won't work *)
Qed.

Proving Gauss' theorem for nat in Coq

I'd like to prove Gauss' theorem for nat.
In plain (non-precise) language it says: if a divides b*c and none of a's factors are in b then they must all be in c.
Require Import NPeano.
Theorem Gauss_nat: forall (a b c:nat), gcd a b = 1 -> (a | (b*c)) -> (a | c).
The theorem is already defined for integers Z, see here in the Coq manual. But I need it for nat. The recommendations I have gotten so far is to use Bezout's lemma which states that
Lemma Bezout: forall (a b c:Z), Z.gcd a b = c -> exists u v, u*a+v*b=c.
However, I can't use it directly for nats since the coefficients u and v might be negative and thus it doesn't hold for nat.
Is there another proof that does not use integers in the proof?
EDIT:
As was pointed out in a comment by Mark Dickinson, the theorem and lemma are already in Coq's library. They are in NPeano, named Nat.gcd_bezout and Nat.gauss.
If you just want to obtain the result for nat, and not really avoid the use of Z, you can just reuse the proof in the standard library. Here's a sketch of how you could proceed, relying on two auxiliary lemmas:
Require Import NPeano.
Require Import ZArith.
Require Import ZArith.Znumtheory.
Require Import Omega.
Close Scope Z_scope.
Lemma Zdiv_Ndiv a b : (a | b) <-> (Z.of_nat a | Z.of_nat b)%Z.
Proof. Admitted.
Lemma Zgcd_Ngcd a b : Z.of_nat (gcd a b) = Z.gcd (Z.of_nat a) (Z.of_nat b).
Proof. Admitted.
Theorem Gauss_nat a b c : gcd a b = 1 -> (a | (b*c)) -> (a | c).
Proof.
rewrite Zdiv_Ndiv, Zdiv_Ndiv, Nat2Z.inj_mul.
intros H1 H2.
assert (H3 : Z.of_nat (gcd a b) = 1%Z) by (rewrite H1; reflexivity).
rewrite Zgcd_Ngcd in H3.
apply (Gauss _ _ _ H2).
now rewrite <- Zgcd_1_rel_prime.
Qed.