I am new to Coq, and my primary interest is in using it to do simple real analysis problems. For a first exercise, I managed to bash through a proof that x^2+2x tends to 0 as x tends to 0. See code below.
This seems pretty clunky, and I would be interested in any general feedback on how to shorten this proof, or good practice for improving its readability. However, my main question is whether there are any Coq tactics for automating simple tasks involving the real numbers, along the lines of field and lra but better.
possible example 1: are there any tactics to prove identities for the functions from Rbasic_fun, such as the absolute value? For example, half my proof is dedicated to showing that |x*x|+|2*x|=|x||x|+2|x| !
possible example 2: are there any tactics to automate the use of the lemmas from Rineq, such as Rlt_le, Rle_trans, Rplus_le_compat_r and Rmult_le_compat_r? That is, lemmas that a human proof-creator would use to "chain together" a sequence of inequalities.
Require Import Rbase.
Require Import Rbasic_fun.
Require Import Lra.
Local Open Scope R_scope.
Definition limit (f:R -> R)
(D:R -> Prop) (l:R) (x0:R) :=
forall eps:R,
eps > 0 ->
exists delta : R,
delta > 0 /\
(forall x:R, D x /\ Rabs (x - x0) < delta -> Rabs ((f x) - l) < eps).
Lemma limitf : limit (fun (x:R) => x*x + 2 *x) (fun x => True) 0 0.
Proof.
unfold limit; intros.
split with (Rmin (eps/3) 1); split.
assert (eps / 3 > 0) by lra; clear H.
assert (1>0) by lra.
apply (Rmin_Rgt_r (eps/3) 1). apply (conj H0 H).
intros. destruct H0. clear H0. replace (x-0) with x in H1 by field.
apply (Rmin_Rgt_l (eps/3) 1) in H1. destruct H1.
assert (Rabs (x*x+2*x -0) <= Rabs(x*x)+Rabs(2*x)).
replace (x*x+2*x-0) with (x*x+2*x) by field.
apply Rabs_triang.
assert (Rabs(2*x) = 2 * Rabs(x)).
assert (Rabs(2*x) = Rabs(2) * Rabs(x)).
apply (Rabs_mult _ _).
assert (Rabs 2 = 2).
apply (Rabs_right _). lra.
replace (Rabs 2) with 2 in H3 by H4. apply H3.
replace (Rabs (2 * x)) with (2 * Rabs x) in H2 by H3. clear H3.
assert (Rabs(x*x) = Rabs(x)*Rabs(x)).
apply Rabs_mult.
replace (Rabs(x*x)) with (Rabs(x)*Rabs(x)) in H2 by H3. clear H3.
assert (Rabs x * Rabs x <= 1 * Rabs x).
apply Rmult_le_compat_r. apply Rabs_pos. apply Rlt_le. auto.
apply (Rplus_le_compat_r (2 * Rabs x) _ _) in H3.
apply (Rle_trans _ _ _ H2) in H3. clear H2.
replace (1 * Rabs x + 2 * Rabs x) with (3 * Rabs x) in H3 by field.
assert (3 * Rabs x < eps) by lra.
apply (Rle_lt_trans _ _ _ H3). auto.
Qed.
Here is the proof using coquelicot, it can probably be made nicer with some of the tactics, but this was quite straight forward. Whenever I wondered what lemma to use, I did Search to find a lemma with the term in its conclusion...
Require Import Reals.
From Coquelicot Require Import Coquelicot.
Open Scope R.
Lemma limitf : is_lim (fun x => x*x + 2 * x) 0 0.
eapply is_lim_plus.
eapply is_lim_mult.
eapply is_lim_id.
eapply is_lim_id.
compute. apply I.
eapply is_lim_mult.
eapply is_lim_const.
eapply is_lim_id.
compute. apply I.
compute. f_equal. f_equal.
ring.
Qed.
Edit:
Here is the proof of your lemma above using lemmas from Coq's standard library instead. I found them by relying heavily on Search. Perhaps this approach makes it less heavy to do similar proofs for you.
Require Import Reals Lra.
Local Open Scope R_scope.
Definition limit (f:R -> R)
(D:R -> Prop) (l:R) (x0:R) :=
forall eps:R,
eps > 0 ->
exists delta : R,
delta > 0 /\
(forall x:R, D x /\ Rabs (x - x0) < delta -> Rabs ((f x) - l) < eps).
Lemma limitf : limit (fun (x:R) => x*x + 2 *x) (fun x => True) 0 0.
intros eps Heps.
exists (Rmin (eps/3) 1).
split. apply Rmin_Rgt. lra.
intros x [_ H].
destruct (Rmin_Rgt_l _ _ _ H); clear H.
rewrite Rminus_0_r in *.
eapply Rle_lt_trans.
apply Rabs_triang.
do 2 erewrite Rabs_mult.
pose proof (Rabs_pos x).
remember (Rabs x) as a; clear Heqa.
rewrite (Rabs_right 2) by lra.
replace eps with (((eps/3)*1) + (2*eps/3)) by lra.
apply Rplus_lt_compat; try lra.
apply Rmult_le_0_lt_compat; lra.
Qed.
A partial answer to my own question: I realised that the tactic nra from micromega does exactly what I had asked for in my "possible example 2". So here is a version of my previous code in which reasoning about inequalities is done automatically by nra. I am still interested to know whether there is a tactic for reasoning about the absolute-value and min/max, corresponding to my "possible example 1".
Update: code below improved by some idioms (pose proof, exists) learned from the answer of #larsr.
Require Import Psatz.
.....
Lemma limitf : limit (fun (x:R) => x*x + 2 *x) (fun x => True) 0 0.
Proof.
unfold limit; intros.
exists (Rmin (eps/3) 1); split.
apply Rmin_Rgt; lra.
intros; destruct H0.
replace (x-0) with x in H1 by field; replace (x*x+2*x-0) with (x*x+2*x) by field.
apply Rmin_Rgt_l in H1; destruct H1.
pose proof (Rabs_triang (x*x) (2*x)).
pose proof (Rabs_mult 2 x).
pose proof (Rabs_mult x x).
pose proof (Rabs_pos x).
epose proof (Rabs_right 2).
nra.
Qed.
Related
I am proving theorem about finding in a list. I got stuck at proving that if you actually found something then it is true. What kind of lemmas or strategy may help for proving such kind of theorems? I mean it looks like induction on the list is not enough in this case. But still the theorem is surely true.
(*FIND P = OPTION_MAP (SND :num # α -> α ) ∘ INDEX_FIND (0 :num) P*)
Require Import List.
Require Import Nat.
Fixpoint INDEX_FIND {a:Type} (i:nat) (P:a->bool) (l:list a) :=
match l with
| nil => None
| (h::t) => if P h then Some (i,h) else INDEX_FIND (S i) P t
end.
Definition FIND {a:Type} (P:a->bool) (l:list a)
:= (option_map snd) (INDEX_FIND 0 P l).
Theorem find_prop {a:Type} P l (x:a):
(FIND P l) = Some x
->
(P x)=true.
Proof.
unfold FIND.
unfold option_map.
induction l.
+ simpl.
intro H. inversion H.
+ simpl.
destruct (P a0).
- admit.
- admit.
Admitted.
(this is a translation of definition from HOL4 which also lacks such kind of theorem)
HOL version of the theorem:
Theorem find_prop:
FIND (P:α->bool) (l:α list) = SOME x ⇒ P x
Proof
cheat
QED
It looks like what you are missing is an equation relating P a0 and its destructed value. This can be obtained with the variant of destruct documented there destruct (P a0) eqn:H.
You may want to try to strengthen the property before proving your theorem. Using the SSReflect proof language, you can try the following route.
Lemma index_find_prop {a:Type} P (x:a) l :
forall i j, (INDEX_FIND i P l) = Some (j, x) -> P x = true.
Proof.
elim: l => [//=|x' l' IH i j].
rewrite /INDEX_FIND.
case Px': (P x').
- by case=> _ <-.
- exact: IH.
Qed.
Lemma opt_snd_inv A B X x :
option_map (#snd A B) X = Some x -> exists j, X = Some (j, x).
Proof.
case: X => ab; last by [].
rewrite (surjective_pairing ab) /=.
case=> <-.
by exists ab.1.
Qed.
Theorem find_prop {a:Type} P l (x:a):
(FIND P l) = Some x -> (P x)=true.
Proof.
rewrite /FIND => /(#opt_snd_inv _ _ (INDEX_FIND 0 P l) x) [j].
exact: index_find_prop.
Qed.
I'm confident there are shorter proofs ;)
I'm looking for this lemma about nats. I'm hoping it already exists in one of the Coq libraries so I don't have to prove it.
forall m n : nat, (S m < n)%nat -> (n - (S m) < n)%nat
Please point me to the library if it exists. Thanks!
You are almost looking for Nat.sub_lt. I recommend using the Search command to find lemmas. It's quite powerful.
Require Import Arith.
Goal forall m n, (S m < n)%nat -> (n - (S m) < n)%nat.
intros.
Search (_ - _ < _).
apply Nat.sub_lt.
Search (_ < _ -> _ <= _).
apply Nat.lt_le_incl, H.
Search (0 < S _).
apply Nat.lt_0_succ.
Qed.
or auto using Nat.sub_lt, Nat.lt_le_incl, Nat.lt_0_succ. or auto with arith.
This statement does not hold: substituting m = 0, the conclusion becomes n < n, a clear contradiction.
As far as I know, there is no Coq library to prove your statement. So you can come up with your own proof as:
Require Import PeanoNat List.
Import Nat.
Goal(forall m n : nat, (S m < n)%nat -> (n - (S m) < n)%nat).
Proof.
induction m.
destruct n.
intros.
inversion H.
intros. simpl.
rewrite Nat.sub_0_r.
apply lt_succ_diag_r.
intros.
intuition.
Qed.
I'm trying to learn to use the ListMap module in Coq. I'm really not sure about proving properties about the keys or values in a ListMap, when the ListMap is created by a recursive function. I feel like I do not know what tactics to use.
(* Me proving statements about maps to understand how to use maps in Coq *)
Require Import FunInd.
Require Import Coq.Lists.List.
Require Import Coq.FSets.FMapInterface.
Require Import
Coq.FSets.FMapList
Coq.Structures.OrderedTypeEx.
Module Import MNat := FMapList.Make(Nat_as_OT).
Require Import
Coq.FSets.FMapFacts.
Definition NatToNat := MNat.t nat.
Definition NatToNatEmpty : NatToNat := MNat.empty nat.
(* We wish to show that map will have only positive values *)
Function insertNats (n: nat) (mm: NatToNat) {struct n}: NatToNat :=
match n with
| O => mm
| S (next) => insertNats next (MNat.add n n mm)
end.
Definition keys (mm: NatToNat) : list nat :=
List.map fst (elements mm).
(* vvvvv How do I prove this? Intuitively it is true *)
Example keys_nonnegative: forall (n: nat),
forall (k: nat),
List.In k (keys (insertNats n NatToNatEmpty)) -> k >= 0.
Proof.
intros n k in_proof.
induction n.
simpl in in_proof. tauto.
(* ??? NOW WHAT *)
Admitted.
Informally, the argument I would use for the below program is that because n >= 0 because it is a nat, the keys inserted into the map by idMapsGo will also always be non-negative.
I need to induct on n for keys_nonnegative. On the nth step, we add a key n, which will be non-negative (due to being a nat). The base case is trivial.
However, I am unable to convert this intuition into a Coq proof :)
You want to look at elements_in_iff and elements_mapsto_iff from Coq.FSets.FMapFacts.
Useful properties on keys:
Here are two useful properties on your definition of keys that might help you simplify your proofs. The code is taken from my own project Aniceto that includes helper properties on maps.
Definition keys {elt:Type} (m:t elt) : list key := fst (split (elements m)).
Fixpoint split_alt {A:Type} {B:Type} (l:list (A*B) %type) : (list A * list B) % type:=
match l with
| nil => (nil, nil)
| (x, y) :: l => (x :: (fst (split_alt l)), y :: (snd (split_alt l)))
end.
Lemma split_alt_spec:
forall {A:Type} {B:Type} (l:list (A*B) %type),
split l = split_alt l.
Proof.
intros.
induction l.
- auto.
- simpl. intuition.
rewrite IHl.
remember (split_alt l) as l'.
destruct l' as (lhs, rhs).
auto.
Qed.
Lemma in_fst_split:
forall {A:Type} {B:Type} (l:list (A*B)%type) (lhs:A),
List.In lhs (fst (split l)) ->
exists rhs, List.In (lhs, rhs) l.
Proof.
intros.
induction l.
{ inversion H. (* absurd *) }
destruct a.
rewrite split_alt_spec in H.
simpl in H.
destruct H.
+ subst.
eauto using in_eq.
+ rewrite <- split_alt_spec in H.
apply IHl in H; clear IHl.
destruct H as (r, Hin).
eauto using in_cons.
Qed.
Lemma in_elements_to_in:
forall {elt:Type} k e (m: t elt),
List.In (k, e) (elements m) ->
In k m.
Proof.
intros.
rewrite elements_in_iff.
exists e.
apply InA_altdef.
apply Exists_exists.
exists (k,e).
intuition.
unfold eq_key_elt.
intuition.
Qed.
Lemma keys_spec_1:
forall {elt:Type} (m:t elt) (k:key),
List.In k (keys m) -> In k m.
Proof.
intros.
unfold keys in *.
apply in_fst_split in H.
destruct H as (e, H).
apply in_elements_to_in with (e0:=e).
assumption.
Qed.
Lemma keys_spec_2:
forall {elt:Type} (m:t elt) (k:key),
In k m ->
exists k', E.eq k k' /\ List.In k' (keys m).
Proof.
intros.
unfold keys in *.
destruct H as (e, H).
apply maps_to_impl_in_elements in H.
destruct H as (k', (Heq, Hin)).
apply in_split_l in Hin.
exists k'.
intuition.
Qed.
When reasoning on paper, I often use arguments by induction on the length of some list. I want to formalized these arguments in Coq, but there doesn't seem to be any built in way to do induction on the length of a list.
How should I perform such an induction?
More concretely, I am trying to prove this theorem. On paper, I proved it by induction on the length of w. My goal is to formalize this proof in Coq.
There are many general patterns of induction like this one that can be covered
by the existing library on well founded induction. In this case, you can prove
any property P by induction on length of lists by using well_founded_induction, wf_inverse_image, and PeanoNat.Nat.lt_wf_0, as in the following comand:
induction l using (well_founded_induction
(wf_inverse_image _ nat _ (#length _)
PeanoNat.Nat.lt_wf_0)).
if you are working with lists of type T and proving a goal P l, this generates an
hypothesis of the form
H : forall y : list T, length y < length l -> P y
This will apply to any other datatype (like trees for instance) as long as you can map that other datatype to nat using any size function from that datatype to nat instead of length.
Note that you need to add Require Import Wellfounded. at the head of your development for this to work.
Here is how to prove a general list-length induction principle.
Require Import List Omega.
Section list_length_ind.
Variable A : Type.
Variable P : list A -> Prop.
Hypothesis H : forall xs, (forall l, length l < length xs -> P l) -> P xs.
Theorem list_length_ind : forall xs, P xs.
Proof.
assert (forall xs l : list A, length l <= length xs -> P l) as H_ind.
{ induction xs; intros l Hlen; apply H; intros l0 H0.
- inversion Hlen. omega.
- apply IHxs. simpl in Hlen. omega.
}
intros xs.
apply H_ind with (xs := xs).
omega.
Qed.
End list_length_ind.
You can use it like this
Theorem foo : forall l : list nat, ...
Proof.
induction l using list_length_ind.
...
That said, your concrete example example does not necessarily need induction on the length. You just need a sufficiently general induction hypothesis.
Import ListNotations.
(* ... some definitions elided here ... *)
Definition flip_state (s : state) :=
match s with
| A => B
| B => A
end.
Definition delta (s : state) (n : input) : state :=
match n with
| zero => s
| one => flip_state s
end.
(* ...some more definitions elided here ...*)
Theorem automata221: forall (w : list input),
extend_delta A w = B <-> Nat.odd (one_num w) = true.
Proof.
assert (forall w s, extend_delta s w = if Nat.odd (one_num w) then flip_state s else s).
{ induction w as [|i w]; intros s; simpl.
- reflexivity.
- rewrite IHw.
destruct i; simpl.
+ reflexivity.
+ rewrite <- Nat.negb_even, Nat.odd_succ.
destruct (Nat.even (one_num w)), s; reflexivity.
}
intros w.
rewrite H; simpl.
destruct (Nat.odd (one_num w)); intuition congruence.
Qed.
In case like this, it is often faster to generalize your lemma directly:
From mathcomp Require Import all_ssreflect.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Section SO.
Variable T : Type.
Implicit Types (s : seq T) (P : seq T -> Prop).
Lemma test P s : P s.
Proof.
move: {2}(size _) (leqnn (size s)) => ss; elim: ss s => [|ss ihss] s hs.
Just introduce a fresh nat for the size of the list, and regular induction will work.
I am trying to write an induction hypothesis specifically for proving properties of even numbers. I formulated and proved the following:
Theorem ind_hyp_on_evens:
forall (p : nat -> Prop),
(p 0 -> (forall n, p n -> p (S (S n))) ->
forall n, p (n + n)).
Proof.
intros p P0 P1.
intro n.
assert(p (n + n) /\ p (S (S (n + n)))).
induction n as [| n'].
split. unfold plus. assumption.
unfold plus.
apply (P1 0).
assumption.
destruct IHn' as [A B].
split.
rewrite <- plus_Snm_nSm.
rewrite -> ? plus_Sn_m.
assumption.
rewrite <- plus_Snm_nSm.
rewrite -> ? plus_Sn_m.
apply (P1 (S (S (n' + n')))).
assumption.
destruct H as [H1 H2].
assumption. Qed.
Despite the fact that it's proved, any attempt to use it results in the error message: "Error: Not the right number of induction arguments."
Can someone please tell me what is the problem with the induction hypothesis, or otherwise, how to apply it??
Thanks,
Mayer
I believe induction assumes that any induction principle that will be used has the
fixed form
forall ... (P : SomeType -> Type) ..., (* or ->Set or ->Prop *)
... ->
forall (v : SomeType), P v
Your ind_hyp_on_evens matches only P (plus n n) which seems to confuse induction.
If you have a suitable goal, say forall n, is_even (n+n), you can manually do the
steps that induction normally does and extend that to handle the special form.
intro n0; (* temp. var *)
pattern (n0 + n0); (* restructure as (fun x => (is_even x)) (n0+n0) *)
refine (ind_hyp_on_evens _ _ _ n0); (* apply ind. scheme *)
clear n0; [| intros n IHn ]. (* clear temp., do one 'intros' per branch *)
I don't know if it's possible to pack that up as a general helper tactic for any induction scheme, packing these steps up as a per-scheme Ltac tactic should work however.
You could consider writing an inductive predicate that describes even numbers (code not tested):
Inductive even : nat -> Prop :=
| evenO : even O
| evenSSn : forall n, even n -> even (S (S n))
.
Coq will generate the induction principle automatically.
You would have to prove that even n holds before being able to perform induction on the "evenness" of n.