Can someone help me with this proof about the pumping lemma using coq? - coq

This is an exercise from software foundation.
I have proved weak pumping lemma, but I don't know how the prove the strong one.
When I try proving the third case 'App', I can't deal with length (s1 ++ s3) + length s4 <= pumping_constant re1 + pumping_constant re2.
These are my previous proof.
Lemma pumping: forall T (re: reg_exp T) s,
s =~ re ->
pumping_constant re <= length s ->
exists s1 s2 s3,
s = s1 ++ s2 ++ s3 /\
s2 <> [] /\
length s1 + length s2 <= pumping_constant re /\
forall m, s1 ++ napp m s2 ++ s3 =~ re.
Proof.
intros T re s Hmatch.
induction Hmatch.
- simpl. intros contra. inversion contra.
- simpl. intros contra. inversion contra. inversion H0.
- simpl. intros H. rewrite app_length in H. apply add_le_cases in H. destruct H.
+ destruct (IHHmatch1 H) as [s3 [s4 [s5 [H1 [H2 [H3 H4]]]]]].
exists s3. exists s4. exists (s5 ++ s2). split.
{
rewrite H1. rewrite (app_assoc _ s3 s4 s5).
rewrite <- (app_assoc _ (s3 ++ s4) s5 s2). rewrite <- (app_assoc _ s3 s4 (s5 ++ s2)).
reflexivity.
} split.
{ apply H2. } split.
{ apply le_trans with (n := pumping_constant re1). apply H3. apply le_plus_l. }
{
intros m.
rewrite app_assoc. rewrite app_assoc. rewrite <- (app_assoc _ s3 _ s5).
apply MApp. apply H4. apply Hmatch2.
}
+ destruct (IHHmatch2 H) as [s3 [s4 [s5 [H1 [H2 [H3 H4]]]]]].
exists (s1 ++ s3). exists s4. exists s5. split.
{
rewrite H1. rewrite (app_assoc _ s3 s4 s5).
rewrite app_assoc. rewrite (app_assoc _ s1 s3 s4). rewrite <- app_assoc.
reflexivity.
} split.
{ apply H2. } split.
{ }

Related

Can't find a way to 'reverse' a constructor

I try to prove the following simple Lemma :
Lemma wayBack :
forall (a b n:nat) (input:list nat), a <> n -> implist n (a::b::input) -> implist n input.
were implist is as follows :
Inductive implist : nat -> list nat -> Prop :=
| GSSingle : forall (n:nat), implist n [n]
| GSPairLeft : forall (a b n:nat) (l:list nat), implist n l -> implist n ([a]++[b]++l)
| GSPairRight : forall (a b n:nat) (l:list nat), implist n l -> implist n (l++[a]++[b]).
Any idea how to do this ?
Thank you !!
Here it is:
Require Import Program.Equality.
Lemma wayBack :
forall (a b n:nat) (input:list nat), a <> n -> implist n (a::b::input) -> implist n input.
Proof.
intros.
dependent induction H0.
1: eassumption.
assert (exists l', l = a :: b :: l' /\ input = l' ++ [a0 ; b0]) as [l' [-> ->]].
{
clear - x H0 H.
change (l ++ [a0] ++ [b0]) with (l ++ [a0; b0]) in x.
remember [a0; b0] as t in *.
clear Heqt.
induction H0 in input, t, x, H |- *.
+ cbn in *.
inversion x ; subst.
now destruct H.
+ cbn in *.
inversion x ; subst ; clear x.
eexists ; split.
1: reflexivity.
reflexivity.
+ cbn in x.
rewrite <- app_assoc in x.
edestruct IHimplist as [? []] ; try eassumption.
subst.
eexists ; split.
cbn.
2: rewrite app_assoc.
all: reflexivity.
}
econstructor.
eapply IHimplist ; try eassumption.
reflexivity.
Qed.
There are two main difficulties here: the first is that you want to do an induction on you hypothesis implist n (a::b::input), but since a::b::input is not just a variable, there is a need for some fiddling, that standard induction cannot do, but dependent induction from Program can.
The second difficulty, which actually takes up most of my proof, is to be able to decompose the equality you get in the last case, that where you add values at the beginning rather than at the end of the list.

IndProp: re_not_empty_correct

Lemma re_not_empty_correct : forall T (re : #reg_exp T),
(exists s, s =~ re) <-> re_not_empty re = true.
Proof.
split.
- admit. (* I proved it myself *)
- intros. induction re.
+ simpl in H. discriminate H.
+ exists []. apply MEmpty.
+ exists [t]. apply MChar.
+ simpl in H. rewrite -> andb_true_iff in H. destruct H as [H1 H2].
apply IHre1 in H1. apply IHre2 in H2.
Here is what we've got so far:
1 subgoal (ID 505)
T : Type
re1, re2 : reg_exp
H1 : exists s : list T, s =~ re1
H2 : exists s : list T, s =~ re2
IHre1 : re_not_empty re1 = true -> exists s : list T, s =~ re1
IHre2 : re_not_empty re2 = true -> exists s : list T, s =~ re2
============================
exists s : list T, s =~ App re1 re2
Now I need either to combine H1 and H2 into exists s : list T, s =~ App re1 re2 or destruct the goal into 2 subgoals and prove them separately using H1 and H2. But I don't know, how to do it.
You can think of exists as a pair type which includes a value and its property. Just like an ordinary pair type, you can destruct it.
For example, destruct H1 as [s1 H1]. at that point gives
s1 : list T
H1 : s1 =~ re1
Given this, think about how to construct an s in the goal that satisfies s =~ App re1 re2. Then use the tactic exists (your answer). (which will change the goal to (your answer) =~ App re1 re2) and fill in the rest of the proof (it should be trivial if your s is correct).

Proving another property of finding same elements in lists

Following my question here, I have a function findshare which finds the same elements in two lists. Actually, keepnotEmpty is the lemma I need in my program after applying some changes to the initial version of lemma sameElements. Lemma keepnotEmpty proves if the result of function findshare on the concatenation of two lists is not empty then the concatenation of the results of the function applied to each one of them is not empty as well. I'm confused how to prove lemma keepnotEmpty. Thank you.
Require Import List .
Import ListNotations.
Fixpoint findshare(s1 s2: list nat): list nat:=
match s1 with
| nil => nil
| v :: tl =>
if ( existsb (Nat.eqb v) s2)
then v :: findshare tl s2
else findshare tl s2
end.
Lemma sameElements l1 l2 tl :
(findshare(l1++l2) tl) =
(findshare l1 tl) ++ (findshare l2 tl ).
Proof.
Admitted.
Lemma keepnotEmpty l1 l2 tl :
(findshare tl (l1++l2)) <> nil -> (findshare tl (l1) ++ (findshare tl (l2))<>nil).
Proof.
You need induction on tl and the property oneNotEmpty of lists to prove lemmakeepnotEmpty.
Lemma oneNotEmpty (l1 l2:list nat):
l1<>nil -> (l2++l1)<>nil.
Proof.
Admitted.
Lemma keepnotEmpty l1 l2 tl :
(findshare tl (l1++l2))<> nil -> (findshare tl (l1) ++ (findshare tl (l2))<>nil).
Proof.
induction tl. simpl; intro. congruence.
simpl.
rewrite existsb_app.
destruct_with_eqn(existsb (Nat.eqb a) l1).
destruct_with_eqn(existsb (Nat.eqb a) l2);
simpl; intros H1 H2; congruence.
destruct_with_eqn(existsb (Nat.eqb a) l2).
simpl. intros. apply (oneNotEmpty);
intro. inversion H0.
simpl; assumption.
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.

Stuck on a simple proof about regular expressions

I'm trying to formalize some properties on regular expressions (REs) using Coq. But, I've got some troubles to prove a rather simple property:
For all strings s, if s is in the language of (epsilon)* RE, then s =
"", where epsilon and * denotes the empty string RE and Kleene star
operation.
This seems to be an obvious application of induction / inversion tactics, but I couldn't make it work.
The minimal working code with the problematic lemma is in the following gist.
Any tip on how should I proceed will be appreciated.
EDIT:
One of my tries was something like:
Lemma star_lemma : forall s, s <<- (#1 ^*) -> s = "".
Proof.
intros s H.
inverts* H.
inverts* H2.
inverts* H1.
inverts* H1.
inverts* H2.
simpl in *.
-- stuck here
that leave me with the following goal:
s' : string
H4 : s' <<- (#1 ^*)
============================
s' = ""
At least to me, it appears that using induction would finish the proof, since I could use H4 in induction hypothesis to finish the proof, but when I start the proof using
induction H
instead of
inverts* H
I got some (at least for me) senseless goals. In Idris / Agda, such proof just follows by pattern matching and recursion over the structure of s <<- (#1 ^*). My point is how to do such recursion in Coq.
Here is one possible solution of the original problem:
Lemma star_lemma : forall s,
s <<- (#1 ^*) -> s = "".
Proof.
refine (fix star_lemma s prf {struct prf} : s = "" := _).
inversion_clear prf; subst.
inversion_clear H; subst.
- now inversion H0.
- inversion_clear H0; subst. inversion_clear H; subst.
rewrite (star_lemma s' H1).
reflexivity.
Qed.
The main idea is to introduce a term in the context which will resemble the recursive call in a typical Idris proof. The approaches with remember and dependent induction don't work well (without modifications of in_regex) because they introduce impossible to satisfy equations as induction hypotheses' premises.
Note: it can take a while to check this lemma (around 40 seconds on my machine under Coq 8.5pl3). I think it's due to the fact that the inversion tactic tends to generate big proof terms.
This problem has obsessed me for a week, and I have finally found a solution that I find elegant.
I had already read that when an induction principle does not fit your needs, you can write and prove another one, more adapted to your problem. That is what I have done in this case. What we would want is the one obtained when using the more natural definition given in this answer. By doing this, we can keep the same definition (if changing it implies too many changes, for example) and reason about it more easily.
Here is the proof of the induction principle (I use a section to specify precisely the implicit arguments, since otherwise I observe strange behaviours with them, but the section mechanism is not necessary at all here).
Section induction_principle.
Context (P : string -> regex -> Prop)
(H_InEps : P "" #1)
(H_InChr : forall c, P (String c "") ($ c))
(H_InCat : forall {e e' s s' s1}, s <<- e -> P s e -> s' <<- e' ->
P s' e' -> s1 = s ++ s' -> P s1 (e # e'))
(H_InLeft : forall {s e e'}, s <<- e -> P s e -> P s (e :+: e'))
(H_InRight : forall {s' e e'}, s' <<- e' -> P s' e' -> P s' (e :+: e'))
(H_InStar_Eps : forall e, P "" (e ^*))
(H_InStar_Cat : forall {s1 s2 e}, s1 <<- e -> s2 <<- (e ^*) ->
P s1 e -> P s2 (e ^*) -> P (s1++s2) (e ^*)).
Arguments H_InCat {_ _ _ _ _} _ _ _ _ _.
Arguments H_InLeft {_ _ _} _ _.
Arguments H_InRight {_ _ _} _ _.
Arguments H_InStar_Cat {_ _ _} _ _ _ _.
Definition in_regex_ind2 : forall (s : string) (r : regex), s <<- r -> P s r.
Proof.
refine (fix in_regex_ind2 {s r} prf {struct prf} : P s r :=
match prf with
| InEps => H_InEps
| InChr c => H_InChr c
| InCat prf1 prf2 eq1 =>
H_InCat prf1 (in_regex_ind2 prf1) prf2 (in_regex_ind2 prf2) eq1
| InLeft _ prf => H_InLeft prf (in_regex_ind2 prf)
| InRight _ prf => H_InRight prf (in_regex_ind2 prf)
| InStar prf => _
end).
inversion prf; subst.
- inversion H1. apply H_InStar_Eps.
- inversion H1; subst.
apply H_InStar_Cat; try assumption; apply in_regex_ind2; assumption.
Qed.
End induction_principle.
And it turned out that the Qed of this proof was not instantaneous (probably due to inversion producing large terms as in this answer), but took less than 1s (maybe because the lemma is more abstract).
The star_lemma becomes nearly trivial to prove (as soon as we know the remember trick), as with the natural definition.
Lemma star_lemma : forall s, s <<- (#1 ^*) -> s = "".
Proof.
intros s H. remember (#1 ^*) as r.
induction H using in_regex_ind2; try discriminate.
- reflexivity.
- inversion Heqr; subst.
inversion H. rewrite IHin_regex2 by reflexivity. reflexivity.
Qed.
I modified a bit the definition of your in_regex predicate:
Inductive in_regex : string -> regex -> Prop :=
| InEps
: "" <<- #1
| InChr
: forall c
, (String c EmptyString) <<- ($ c)
| InCat
: forall e e' s s' s1
, s <<- e
-> s' <<- e'
-> s1 = s ++ s'
-> s1 <<- (e # e')
| InLeft
: forall s e e'
, s <<- e
-> s <<- (e :+: e')
| InRight
: forall s' e e'
, s' <<- e'
-> s' <<- (e :+: e')
| InStarLeft
: forall e
, "" <<- (e ^*)
| InStarRight
: forall s s' e
, s <<- e
-> s' <<- (e ^*)
-> (s ++ s') <<- (e ^*)
where "s '<<-' e" := (in_regex s e).
and could prove your lemma:
Lemma star_lemma : forall s, s <<- (#1 ^*) -> s = "".
Proof.
intros s H.
remember (#1 ^*) as r.
induction H; inversion Heqr; clear Heqr; trivial.
subst e.
rewrite IHin_regex2; trivial.
inversion H; trivial.
Qed.
Some explanations are necessary.
I did an induction on H. The reasoning is: if I have a proof of s <<- (#1 ^*) then this proof must have the following form...
The tactic remember create a new hypothesis Heqr which, combined with inversion will help get rid of cases which cannot possibly give this proof (in fact all the cases minus the ones where ^* is in the conclusion).
Unfortunately, this path of reasoning does not work with the definition you had for the in_regex predicate because it will create an unsatisfiable condition to the induction hypothesis. That's why I modified your inductive predicate as well.
The modified inductive tries to give a more basic definition of being in (e ^*). Semantically, I think this is equivalent.
I would be interested to read a proof on the original problem.