Tactic to prove a boolean implication - coq

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.

Related

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

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.

Paramcoq: Free theorems in Coq

How can I prove the following free theorem with the plugin Paramcoq?
Lemma id_free (f : forall A : Type, A -> A) (X : Type) (x : X), f X x = x.
If it is not possible, then what is the purpose of this plugin?
The plugin can generate the statement of parametricity for any type. You will still need to then declare it as an axiom or an assumption to actually use it:
Declare ML Module "paramcoq".
Definition idt := forall A:Type, A -> A.
Parametricity idt arity 1.
(* ^^^ This command defines the constant idt_P. *)
Axiom param_idt : forall f, idt_P f.
Lemma id_free (f : forall A : Type, A -> A) (X : Type) (x : X) : f X x = x.
Proof.
intros.
apply (param_idt f X (fun y => y = x) x).
reflexivity.
Qed.

Is there any thing like apply lem in *?

Is there any way to call apply lem in H for every possible H in premises, like rewrite lem in *?
Axiom P Q : nat -> Prop.
Axiom lem : forall (n : nat), P n -> Q n.
Goal P O -> P (S O) -> True.
intros. apply lem in H. apply lem in H0.
I couldn't find anything built in, but it's possible to write such a tactic with Ltac.
First, the special case.
Axiom P Q : nat -> Prop.
Axiom lem : forall (n : nat), P n -> Q n.
Goal P O -> P (S O) -> True.
intros.
repeat match goal with
x : _ |- _ => apply lem in x
end.
Abort.
Now we can generalize this
Ltac apply_in_premises t :=
repeat match goal with
x : _ |- _ => apply t in x
end.
and use it like this:
Goal P O -> P (S O) -> True.
intros.
apply_in_premises lem.
Abort.
Unfortunately, this way of doing it can cause an infinite loop if applying lem produces something else that lem can be applied to.
Axiom P : nat -> Prop.
Axiom lem : forall (n : nat), P n -> P (S n).
Ltac apply_in_premises t :=
repeat match goal with
x : _ |- _ => apply t in x
end.
Goal P O -> P (S O) -> nat -> True.
intros.
apply_in_premises lem. (* infinite loop *)
Abort.
If this is a concern for you, you can use a variant suggested by Yves in the comments. Simply changing apply t in x to apply t in x; revert x will ensure that that hypothesis won't be matched again. However, the end result will have all the hypotheses in the goal, like P -> G, instead of p: P as a premise and G as the goal.
To automatically reintroduce these hypotheses, we can keep track of how many times a hypothesis was reverted, then introduce them again.
Ltac intro_n n :=
match n with
| 0 => idtac
| S ?n' => intro; intro_n n'
end.
Ltac apply_in_premises_n t n :=
match goal with
| x : _ |- _ => apply t in x; revert x;
apply_in_premises_n t (S n)
| _ => intro_n n (* now intro all the premises that were reverted *)
end.
Tactic Notation "apply_in_premises" uconstr(t) := apply_in_premises_n t 0.
Axiom P : nat -> Prop.
Axiom lem : forall (n : nat), P n -> P (S n).
Goal P O -> P (S O) -> nat -> True.
intros.
apply_in_premises lem. (* only applies `lem` once in each of the premises *)
Abort.
Here, the tactic intro_n n applies intro n times.
I haven't tested this in general, but it works well in the case above. It might fail if a hypothesis can't be reverted (for example, if some other hypothesis depends on it). It also may reorder the hypotheses, since when a reverted hypothesis is reintroduced, it's put on the end of the hypothesis list.

How to use a custom induction principle in Coq?

I read that the induction principle for a type is just a theorem about a proposition P. So I constructed an induction principle for List based on the right (or reverse) list constructor .
Definition rcons {X:Type} (l:list X) (x:X) : list X :=
l ++ x::nil.
The induction principle itself is:
Definition true_for_nil {X:Type}(P:list X -> Prop) : Prop :=
P nil.
Definition true_for_list {X:Type} (P:list X -> Prop) : Prop :=
forall xs, P xs.
Definition preserved_by_rcons {X:Type} (P: list X -> Prop): Prop :=
forall xs' x, P xs' -> P (rcons xs' x).
Theorem list_ind_rcons:
forall {X:Type} (P:list X -> Prop),
true_for_nil P ->
preserved_by_rcons P ->
true_for_list P.
Proof. Admitted.
But now, I am having trouble using the theorem. I don't how to invoke it to achieve the same as the induction tactic.
For example, I tried:
Theorem rev_app_dist: forall {X} (l1 l2:list X), rev (l1 ++ l2) = rev l2 ++ rev l1.
Proof. intros X l1 l2.
induction l2 using list_ind_rcons.
But in the last line, I got:
Error: Cannot recognize an induction scheme.
What are the correct steps to define and apply a custom induction principle like list_ind_rcons?
Thanks
If one would like to preserve the intermediate definitions, then one could use the Section mechanism, like so:
Require Import Coq.Lists.List. Import ListNotations.
Definition rcons {X:Type} (l:list X) (x:X) : list X :=
l ++ [x].
Section custom_induction_principle.
Variable X : Type.
Variable P : list X -> Prop.
Hypothesis true_for_nil : P nil.
Hypothesis true_for_list : forall xs, P xs.
Hypothesis preserved_by_rcons : forall xs' x, P xs' -> P (rcons xs' x).
Fixpoint list_ind_rcons (xs : list X) : P xs. Admitted.
End custom_induction_principle.
Coq substitutes the definitions and list_ind_rcons has the needed type and induction ... using ... works:
Theorem rev_app_dist: forall {X} (l1 l2:list X),
rev (l1 ++ l2) = rev l2 ++ rev l1.
Proof. intros X l1 l2.
induction l2 using list_ind_rcons.
Abort.
By the way, this induction principle is present in the standard library (List module):
Coq < Check rev_ind.
rev_ind
: forall (A : Type) (P : list A -> Prop),
P [] ->
(forall (x : A) (l : list A), P l -> P (l ++ [x])) ->
forall l : list A, P l
What you did was mostly correct. The problem is that Coq has some trouble recognizing that what you wrote is an induction principle, because of the intermediate definitions. This, for instance, works just fine:
Theorem list_ind_rcons:
forall {X:Type} (P:list X -> Prop),
P nil ->
(forall x l, P l -> P (rcons l x)) ->
forall l, P l.
Proof. Admitted.
Theorem rev_app_dist: forall {X} (l1 l2:list X), rev (l1 ++ l2) = rev l2 ++ rev l1.
Proof. intros X l1 l2.
induction l2 using #list_ind_rcons.
I don't know if Coq not being able to automatically unfold the intermediate definitions should be considered a bug or not, but at least there is a workaround.

Implementing safe element retrieval by index from list in Coq

I'm trying to demonstrate the difference in code generation between Coq Extraction mechanism and MAlonzo compiler in Agda. I came up with this simple example in Agda:
data Nat : Set where
zero : Nat
succ : Nat → Nat
data List (A : Set) : Set where
nil : List A
cons : A → List A → List A
length : ∀ {A} → List A → Nat
length nil = zero
length (cons _ xs) = succ (length xs)
data Fin : Nat → Set where
finzero : ∀ {n} → Fin (succ n)
finsucc : ∀ {n} → Fin n → Fin (succ n)
elemAt : ∀ {A} (xs : List A) → Fin (length xs) → A
elemAt nil ()
elemAt (cons x _) finzero = x
elemAt (cons _ xs) (finsucc n) = elemAt xs n
Direct translation to Coq (with absurd pattern emulation) yields:
Inductive Nat : Set :=
| zero : Nat
| succ : Nat -> Nat.
Inductive List (A : Type) : Type :=
| nil : List A
| cons : A -> List A -> List A.
Fixpoint length (A : Type) (xs : List A) {struct xs} : Nat :=
match xs with
| nil => zero
| cons _ xs' => succ (length _ xs')
end.
Inductive Fin : Nat -> Set :=
| finzero : forall n : Nat, Fin (succ n)
| finsucc : forall n : Nat, Fin n -> Fin (succ n).
Lemma finofzero : forall f : Fin zero, False.
Proof. intros a; inversion a. Qed.
Fixpoint elemAt (A : Type) (xs : List A) (n : Fin (length _ xs)) : A :=
match xs, n with
| nil, _ => match finofzero n with end
| cons x _, finzero _ => x
| cons _ xs', finsucc m n' => elemAt _ xs' n' (* fails *)
end.
But the last case in elemAt fails with:
File "./Main.v", line 26, characters 46-48:
Error:
In environment
elemAt : forall (A : Type) (xs : List A), Fin (length A xs) -> A
A : Type
xs : List A
n : Fin (length A xs)
a : A
xs' : List A
n0 : Fin (length A (cons A a xs'))
m : Nat
n' : Fin m
The term "n'" has type "Fin m" while it is expected to have type
"Fin (length A xs')".
It seems that Coq does not infer succ m = length A (cons A a xs'). What should I
tell Coq so it would use this information? Or am I doing something completely senseless?
Doing pattern matching is the equivalent of using the destruct tactic.
You won't be able to prove finofzero directly using destruct.
The inversion tactic automatically generates some equations before doing what destruct does.
Then it tries to do what discriminate does. The result is really messy.
Print finofzero.
To prove something like fin zero -> P you should change it to fin n -> n = zero -> P first.
To prove something like list nat -> P (more usually forall l : list nat, P l) you don't need to change it to list A -> A = nat -> P, because list's only argument is a parameter in its definition.
To prove something like S n <= 0 -> False you should change it to S n1 <= n2 -> n2 = 0 -> False first, because the first argument of <= is a parameter while the second one isn't.
In a goal f x = f y -> P (f y), to rewrite with the hypothesis you first need to change the goal to f x = z -> f y = z -> P z, and only then will you be able to rewrite with the hypothesis using induction, because the first argument of = (actually the second) is a parameter in the definition of =.
Try defining <= without parameters to see how the induction principle changes.
In general, before using induction on a predicate you should make sure it's arguments are variables. Otherwise information might be lost.
Conjecture zero_succ : forall n1, zero = succ n1 -> False.
Conjecture succ_succ : forall n1 n2, succ n1 = succ n2 -> n1 = n2.
Lemma finofzero : forall n1, Fin n1 -> n1 = zero -> False.
Proof.
intros n1 f1.
destruct f1.
intros e1.
eapply zero_succ.
eapply eq_sym.
eapply e1.
admit.
Qed.
(* Use the Show Proof command to see how the tactics manipulate the proof term. *)
Definition elemAt' : forall (A : Type) (xs : List A) (n : Nat), Fin n -> n = length A xs -> A.
Proof.
fix elemAt 2.
intros A xs.
destruct xs as [| x xs'].
intros n f e.
destruct (finofzero f e).
destruct 1.
intros e.
eapply x.
intros e.
eapply elemAt.
eapply H.
eapply succ_succ.
eapply e.
Defined.
Print elemAt'.
Definition elemAt : forall (A : Type) (xs : List A), Fin (length A xs) -> A :=
fun A xs f => elemAt' A xs (length A xs) f eq_refl.
CPDT has more about this.
Maybe things would be clearer if at the end of a proof Coq performed eta reduction and beta/zeta reduction (wherever variables occur at most once in scope).
I think your problem is similar to Dependent pattern matching in coq . Coq's match does not infer much, so you have to help it by providing the equality by hand.