induction hypothesis for even numbers - coq

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.

Related

How to prove forall (p q:Prop), ~p->~((p ->q) ->p). using coq

I am completely new to coq programming and unable to prove below theorem. I need help on steps how to solve below construct?
Theorem PeirceContra: forall (p q:Prop), ~p->~((p ->q) ->p).
I tried the proof below way.
Given axiom as Axiom classic : forall P:Prop, P \/ ~ P.
Theorem PeirceContra: forall (p q:Prop), ~ p -> ~((p -> q) -> p).
Proof.
unfold not.
intros.
apply H.
destruct (classic p) as [ p_true | p_not_true].
- apply p_true.
- elimtype False. apply H.
Qed.
Getting subgoal after using elimtype and apply H as
1 subgoal
p, q : Prop
H : p -> False
H0 : (p -> q) -> p
p_not_true : ~ p
______________________________________(1/1)
p
But now I am stuck here because I am unable to prove P using p_not_true construct of given axiom......Please suggest some help......
I am not clear how to use the given axiom to prove logic................
This lemma can be proved constructively. If you think about what can be done at each step to make progress the lemma proves itself:
Lemma PeirceContra :
forall P Q, ~P -> ~((P -> Q) -> P).
Proof.
intros P Q np.
unfold "~".
intros pq_p.
apply np. (* this is pretty much the only thing we can do at this point *)
apply pq_p. (* this is almost inevitable too *)
(* the rest should be easy *)
(* Qed. *)

I'm looking for this lemma about the nat type

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.

How to prove theorems about recursive functions of ListMap in coq?

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.

How to do induction on the length of a list in Coq?

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.

Why can't inversion be used on a universally qualified hypothesis in Coq?

I've been going through the Software Foundations course and found the following proof (source link).
Theorem not_exists_dist :
excluded_middle ->
forall (X:Type) (P : X -> Prop),
~ (exists x, ~ P x) -> (forall x, P x).
Proof.
unfold not. intros.
unfold excluded_middle in H.
assert ((P x) \/ ((P x) -> False)) as HP.
apply H with (P:=(P x)).
inversion HP.
apply H1.
apply ex_falso_quodlibet. apply H0. exists x. apply H1.
Qed.
I'm curious, why is there an assertion saying (P x) \/ ((P x) -> False), when if I unfold excluded_middle in H and unfold not in H, I'll get the exact same H : forall P : Prop, P \/ (P -> False) as the assertion, only that there's a universal quantifier.
This is even more obvious as the assertion can be proved just by doing apply H, and the whole reason for this step is to do inversion HP on the newly asserted hypothsesis.
The question is, why isn't it possible to do inversion H at the beginning directly, and spare the extra step of defining an assertion, which just copies one of the assumptions? Is there a better way to do this?
inversion only works on things of inductive type, such as or. forall is not an inductive type constructor, hence one cannot perform inversion on it. One could maybe extend inversion to behave like (e)destruct: if you give it something that is universally quantified, it'll generate additional existentials and proof obligations that you need to fulfill to fill in the missing spots, as well as destructing the conclusion. However, this is not how it works right now...
One could do a more direct proof by just applying H and destructing it directly:
Theorem not_exists_dist :
excluded_middle ->
forall (X:Type) (P : X -> Prop),
~ (exists x, ~ P x) -> (forall x, P x).
Proof.
intros.
destruct (H (P x)).
apply H1.
exfalso. apply H0. exists x. apply H1.
Qed.