I have two lists in coq.I want to find the difference between these two lists.Plz guide me in writing code in coq
As Arthur says there are many versions of difference. If you mean subtraction here are two approaches:
Variable (T: eqType).
Definition dlist1 (l1 l2 : seq T) :=
foldr (fun x l => if x \in l2 then l else [:: x & l]) [::] l1.
Definition dlist2 (l1 l2 : seq T) :=
foldl (fun l x => filter (predC1 x) l) l1 l2.
YMMV. Proofs:
Lemma dlist2_nil l2 : dlist2 [::] l2 = [::].
Proof. by elim: l2. Qed.
Lemma dlist2_cons x1 l1 l2 :
dlist2 (x1 :: l1) l2 =
if x1 \in l2 then dlist2 l1 l2 else [:: x1 & dlist2 l1 l2].
Proof. by elim: l2 l1 => //= x2 l2 ih2 l1; rewrite inE; case: eqP => /=. Qed.
Lemma dlistP l1 l2 : dlist1 l1 l2 = dlist2 l1 l2.
Proof.
by elim: l1 l2 => [|x1 l1 ih1] /= l2; rewrite ?dlist2_nil // dlist2_cons ih1.
Qed.
What you are looking for is not the difference between the two lists, but their intersection. You can program this function by reusing parts of the standard library.
Require Import Coq.Arith.Arith.
Require Import Coq.Lists.List.
Definition intersection (l1 l2 : list nat) : list nat :=
List.filter (fun n => List.existsb (Nat.eqb n) l2) l1.
Lemma intersectionP l1 l2 n : In n (intersection l1 l2) <-> In n l1 /\ In n l2.
Proof.
unfold intersection.
rewrite filter_In, existsb_exists; split.
- intros [H1 [m [H2 e]]]; split; trivial.
rewrite Nat.eqb_eq in e; congruence.
- intros [H1 H2]; split; trivial.
now exists n; split; trivial; rewrite Nat.eqb_refl.
Qed.
Related
I have created this simple type :
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]).
and I try to prove this permutation lemma :
Lemma permutImplist :
forall (n a b c:nat) (input:list nat), implist n ((a::b::c::input)) <-> implist n ((c::b::a::input)).
I've tried various induction principles on the type itself or the list, but always end up in a dead end.
Can someone help me with this proof ?
Thanks !!
The induction principle of this predicate is not very useful for proving this directly. It is much better to find an alternative formulation of implist to make your proof go through:
From Coq Require Import List PeanoNat Lia.
Import ListNotations.
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]).
Lemma implist_alt n l :
implist n l <->
exists l1 l2,
l = l1 ++ n :: l2 /\
Nat.even (length l1) = true /\
Nat.even (length l2) = true.
Proof.
split.
- intros H. induction H as [n|a b n l _ IH|a b n l _ IH].
+ exists [], []; intuition.
+ destruct IH as (l1 & l2 & -> & Hl1 & Hl2).
exists (a :: b :: l1), l2; intuition.
+ destruct IH as (l1 & l2 & -> & Hl1 & Hl2).
exists l1, (l2 ++ [a; b]). simpl.
rewrite <- app_assoc, app_length, Nat.add_comm.
intuition.
- intros (l1 & l2 & -> & Hl1 & Hl2).
assert (Hb1 : exists b, length l1 < b) by (exists (S (length l1)); lia).
destruct Hb1 as (b1 & Hb1).
assert (Hb2 : exists b, length l2 < b) by (exists (S (length l2)); lia).
destruct Hb2 as (b2 & Hb2).
revert l1 b2 l2 Hl1 Hl2 Hb1 Hb2.
induction (Nat.lt_wf_0 b1) as [b1 _ IH1].
intros [| x1 [| y1 l1]]; simpl; try easy.
+ intros b2 l2 _ Hl2 _. revert l2 Hl2.
induction (Nat.lt_wf_0 b2) as [b2 _ IH2].
induction l2 as [|x2 l2 _] using rev_ind.
* intros _ _. apply GSSingle.
* induction l2 as [|y2 l2 _] using rev_ind; simpl; try easy.
rewrite !app_length. simpl. rewrite <- Nat.add_assoc, Nat.add_comm. simpl.
intros Hl2 Hb2. rewrite <- app_assoc.
change (n :: l2 ++ [y2] ++ [x2]) with ((n::l2) ++ [y2] ++ [x2]).
apply GSPairRight. apply (IH2 (S (S (length l2)))); eauto; lia.
+ intros b2 l2 Hl1 Hl2 Hb1 Hb2.
apply (GSPairLeft x1 y1). apply (IH1 (S (S (length l1))) Hb1 _ b2); eauto.
Qed.
Lemma permutImplist_aux :
forall (n a b c:nat) (input:list nat), implist n ((a::b::c::input)) -> implist n ((c::b::a::input)).
Proof.
intros n a b c l (l1 & l2 & e & Hl1 & Hl2)%implist_alt.
destruct l1 as [|x l1]; simpl in *.
{ injection e as <- <-; simpl in *.
apply implist_alt. exists [c; b], l; intuition. }
destruct l1 as [|y l1]; simpl in *; try easy.
injection e as <- <- e.
destruct l1 as [|z l1]; simpl in *.
{ injection e as <- <-.
apply implist_alt. exists [], (b :: a :: l); intuition. }
destruct l1 as [|w l1]; simpl in *; try easy.
injection e as <- ->.
apply implist_alt. exists (c :: b :: a :: w :: l1), l2.
intuition.
Qed.
Lemma permutImplist :
forall (n a b c:nat) (input:list nat), implist n ((a::b::c::input)) <-> implist n ((c::b::a::input)).
Proof.
intros n a b c l; split; apply permutImplist_aux.
Qed.
The tricky part, as you can see, is the reverse direction of implist_alt. The ideal way of proving this would be to have an induction principle for lists of even length. Since we do not have this, I have instead used strong induction on the length of the even lists, which works fine as well.
Following the advice about the induction principal for even lists, I've been able to produce a shorter proof for the reverse direction part :
Lemma implist_alt' :
forall (n:nat) (l:list nat), implist n l <-> exists l1 l2, l = l1 ++ n::l2 /\ Nat.Even (length l1) /\ Nat.Even (length l2).
Proof.
split.
- intros H. induction H as [n|a b n l _ IH|a b n l _ IH].
+ exists [], []; intuition; simpl; now exists 0.
+ destruct IH as (l1 & l2 & -> & Hl1 & Hl2).
exists (a :: b :: l1), l2. intuition. simpl. now rewrite Nat.Even_succ_succ.
+ destruct IH as (l1 & l2 & -> & Hl1 & Hl2).
exists l1, (l2 ++ [a; b]). simpl.
rewrite <- app_assoc, app_length, Nat.add_comm.
intuition. simpl. now rewrite Nat.Even_succ_succ.
- intros (l1 & l2 & -> & Hl1 & Hl2).
induction l1 using list_pair_induction.
simpl. now apply (EvenImplist n l2).
simpl in Hl1. rewrite Nat.Even_succ_succ in Hl1. apply IHl1 in Hl1. revert Hl1. now apply (GSPairLeft a b n (l1++n::l2)).
simpl in Hl1. exfalso. now apply Even_1.
Qed.
It uses the following induction principal on lists :
Section list_pair_induction.
Variable P : list nat -> Prop.
Hypothesis Hnil : P nil.
Hypothesis Hddn : forall (l:list nat) (a b:nat) , P l -> P (a::b::l).
Theorem allEven : forall (xs:list nat), even (length xs) = true -> P xs.
Proof.
intro.
remember (length xs) as n eqn : Heqn.
revert n xs Heqn.
induction n as [n IH] using (well_founded_induction lt_wf).
destruct n as [|n].
now destruct xs.
destruct n as [|n].
intros; discriminate.
destruct xs as [|a xs].
intros; discriminate.
destruct xs as [|b xs].
intros; discriminate.
simpl.
intros H1 H2.
apply Hddn.
apply IH with (y := n); auto.
now injection H1.
Qed.
Theorem allEven' : forall (xs:list nat), Nat.Even (length xs) -> P xs.
Proof.
intro.
rewrite <- Nat.even_spec.
apply allEven.
Qed.
Hypothesis Hsingle : forall (n:nat), P (n::nil).
Theorem Hsingle2Hsing : (forall n:nat, P(n::nil) ) -> forall (xs:list nat), (1 = length xs) -> P xs.
Proof.
induction xs.
intro.
exfalso.
simpl in H0.
congruence.
induction xs.
intro.
apply Hsingle.
intro.
exfalso.
simpl in H0.
congruence.
Qed.
Theorem allOdd : forall (xs:list nat), odd (length xs) = true -> P xs.
Proof.
intro.
remember (length xs) as n eqn : Heqn.
revert n xs Heqn.
induction n as [n IH] using (well_founded_induction lt_wf).
destruct n as [|n].
now destruct xs.
destruct n as [|n].
intros.
generalize Heqn.
generalize xs.
generalize Hsingle.
apply Hsingle2Hsing.
destruct xs as [|a xs].
intros; discriminate.
destruct xs as [|b xs].
intros; discriminate.
simpl.
intros H1 H2.
apply Hddn.
apply IH with (y := n); auto.
now injection H1.
Qed.
Hypothesis Hsing : forall (l:list nat) , (1 = length l) -> P (l).
Theorem allOddsing : forall (xs:list nat), odd (length xs) = true -> P xs.
Proof.
intro.
remember (length xs) as n eqn : Heqn.
revert n xs Heqn.
induction n as [n IH] using (well_founded_induction lt_wf).
destruct n as [|n].
now destruct xs.
destruct n as [|n].
intros.
apply Hsing.
assumption.
destruct xs as [|a xs].
intros; discriminate.
destruct xs as [|b xs].
intros; discriminate.
simpl.
intros H1 H2.
apply Hddn.
apply IH with (y := n); auto.
now injection H1.
Qed.
Theorem allOdd' : forall (xs:list nat), Nat.Odd (length xs) -> P xs.
Proof.
intro.
rewrite <- Nat.odd_spec.
apply allOdd.
Qed.
Theorem list_pair_induction : forall (xs:list nat), P xs.
Proof.
intro.
remember (length xs) as n eqn : Heqn.
destruct even_odd_dec with n.
apply allEven'.
rewrite <- Heqn.
assumption.
apply allOdd'.
rewrite <- Heqn.
assumption.
Qed.
End list_pair_induction.
I am currently working on the volume 3 of the Software Foundations' textbook Verified Functional Algorithm and I am stuck on the proof of one exercise.
You can find the chapter about Mergesort which I am dealing with at the moment here: https://softwarefoundations.cis.upenn.edu/vfa-current/Merge.html
This is where I am stuck so far:
Lemma split_perm : forall {X:Type} (l l1 l2: list X),
split l = (l1,l2) -> Permutation l (l1 ++ l2).
Proof.
induction l as [| x | x1 x2 l1' IHl'] using list_ind2; intros.
- inversion H. simpl. reflexivity.
- inversion H. simpl. reflexivity.
- inversion H. destruct (split l1'). inversion H1. simpl. apply perm_skip.
apply Permutation_cons_app.
And this is the result from my last tactic "apply Permutation_cons_app."
1 subgoal
X : Type
x1, x2 : X
l1', l, l0 : list X
IHl' : forall l1 l2 : list X,
(l, l0) = (l1, l2) -> Permutation l1' (l1 ++ l2)
l1, l2 : list X
H : split (x1 :: x2 :: l1') = (l1, l2)
H1 : (x1 :: l, x2 :: l0) = (l1, l2)
H2 : x1 :: l = l1
H3 : x2 :: l0 = l2
______________________________________(1/1)
Permutation (x2 :: l1') (l ++ x2 :: l0)
Any leads on how I should continue to prove my goal ?
Well, actually right now you have result from apply perm_skip. After you have applyed Permutations_cons_app, you need pay attention on your induction hypothises.
I am currently working on the volume 3 of the Software Foundations' textbook Verified Functional Algorithm and I am stuck on the proof of one exercise.
You can find the chapter about Mergesort which I am dealing with at the moment here: https://softwarefoundations.cis.upenn.edu/vfa-current/Merge.html
This is where I am stuck so far:
(** **** Exercise: 3 stars, standard (split_perm) *)
(** Here's another fact about [split] that we will find useful later on.
*)
Lemma split_perm : forall {X:Type} (l l1 l2: list X),
split l = (l1,l2) -> Permutation l (l1 ++ l2).
Proof.
induction l as [| x | x1 x2 l1' IHl'] using list_ind2; intros.
- inv H. simpl. reflexivity.
- inv H. simpl. reflexivity.
- inv H.
And this is the result from my last tactic "inv H."
1 subgoal
X : Type
x1, x2 : X
l1' : list X
IHl' : forall l1 l2 : list X, split l1' = (l1, l2) -> Permutation l1' (l1 ++ l2)
l1, l2 : list X
H1 : (let (l1, l2) := split l1' in (x1 :: l1, x2 :: l2)) = (l1, l2)
______________________________________(1/1)
Permutation (x1 :: x2 :: l1') (l1 ++ l2)
Any leads on how I should continue to prove my goal ? Permutation (x1 :: x2 :: l1') (l1 ++ l2)
I think a first step is to get rid of split l', so destruct (split l') and then an inversion on H1 should simplify your goal
I'm new to Coq. I'm confused about the proof below:
Lemma nth_eq : forall {A} (l1 l2 : list A),
length l1 = length l2 ->
(forall d k, nth k l1 d = nth k l2 d) ->l1 = l2.
Proof.
intros.
The result shows:
1 subgoal
A : Type
l1, l2 : list A
H : length l1 = length l2
H0 : forall (d : A) (k : nat), nth k l1 d = nth k l2 d
______________________________________(1/1)
l1 = l2
The inference is obvious by using H0 and H but I don't know how to use H0 to finish the proof. Thank you very much for your help!
Since it's been a while and the OP hasn't responded to the comment by gallais, I'll put a solution here which should hopefully be easy to follow stepping through the proof in an IDE.
Require Import List.
Lemma nth_eq : forall {A} (l1 l2 : list A),
length l1 = length l2 ->
(forall d k, nth k l1 d = nth k l2 d) ->l1 = l2.
Proof.
(* shortcut to the below:
induction l1; destruct l2; try discriminate 1.
will eliminate two of the cases for you *)
induction l1; destruct l2.
+ reflexivity.
+ discriminate 1.
+ discriminate 1.
+ intros. f_equal.
- specialize H0 with (d := a) (k := 0). simpl in H0. assumption.
- apply IHl1.
* simpl in H. injection H. trivial.
* intros. specialize H0 with (d := d) (k := S k). simpl in H0.
assumption.
Qed.
Working through CIS 500 Software Foundations courseCIS 500 Software Foundations course. Currently on MoreCoq. I don't understand the rewrite IHl1 part. How is it working? Why does this not work when used before simpl?
Definition split_combine_statement : Prop := forall X Y (l1 : list X) (l2 : list Y),
length l1 = length l2 -> split (combine l1 l2) = (l1,l2).
Theorem split_combine : split_combine_statement.
Proof. unfold split_combine_statement. intros. generalize dependent Y. induction l1.
Case "l = []". simpl. intros. destruct l2.
SCase "l2 = []". reflexivity.
SCase "l2 = y :: l2". inversion H.
Case "l = x :: l1". intros. destruct l2.
SCase "l2 = []". inversion H.
SCase "l2 = y :: l2". simpl. rewrite IHl1.
Your hypothesis IHl1 is:
IHl1 : forall (Y : Type) (l2 : list Y),
length l1 = length l2 -> split (combine l1 l2) = (l1, l2)
So in order to rewrite it, you need to instantiate the Y type and l2 list. Next, you need to provide the equality length l1 = length l2 to rewrite
split (combine l1 l2) = (l1,l2). The whole solution is:
Definition split_combine_statement : Prop := forall X Y (l1 : list X) (l2 : list Y),
length l1 = length l2 -> split (combine l1 l2) = (l1,l2).
Theorem split_combine : split_combine_statement.
Proof.
unfold split_combine_statement.
intros. generalize dependent Y. induction l1.
simpl. intros. destruct l2.
reflexivity.
inversion H.
intros. destruct l2.
inversion H.
simpl. inversion H. rewrite (IHl1 Y l2 H1). reflexivity.
Qed.
Note that to rewrite IHl1, we need to instantiate the universal quantifiers (passing adequate values for its variables) and to provide a left hand side for the implication. In Coq words: rewrite (IHl1 Y l2 H1) is passing the type Y to instantiate the forall (Y : Type) in IHl1. The same holds for l2.