Solving a mergesort split proof in Coq - coq

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

Related

Solving a split proof in Coq

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.

How to find difference between two lists in coq

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.

how to use hypothesis which includes universal quantifier in Coq?

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.

How to do induction differently?

I am doing an exercise in Coq and trying to prove if a list equals to its reverse, it's a palindrome. Here is how I define palindromes:
Inductive pal {X : Type} : list X -> Prop :=
| emptypal : pal []
| singlpal : forall x, pal [x]
| inducpal : forall x l, pal l -> pal (x :: l ++ [x]).
Here is the theorem:
Theorem palindrome3 : forall {X : Type} (l : list X),
l = rev l -> pal l.
According to my definition, I will need to do the induction my extracting the front and tail element but apparently coq won't let me do it, and if I force it to do so, it gives an induction result that definitely doesn't make any sense:
Proof.
intros X l H. remember (rev l) as rl. induction l, rl.
- apply emptypal.
- inversion H.
- inversion H.
- (* stuck *)
context:
1 subgoals
X : Type
x : X
l : list X
x0 : X
rl : list X
Heqrl : x0 :: rl = rev (x :: l)
H : x :: l = x0 :: rl
IHl : x0 :: rl = rev l -> l = x0 :: rl -> pal l
______________________________________(1/1)
pal (x :: l)
aparently the inductive context is terribly wrong. is there any way I can fix the induction?
The solution I propose here is probably not the shortest one, but I think it is rather natural.
My solution consists in defining an induction principle on list specialized to your problem.
Consider natural numbers. There is not only the standard induction nat_ind where you prove P 0 and forall n, P n -> P (S n). But there are other induction schemes, e.g., the strong induction lt_wf_ind, or the two-step induction where you prove P 0, P 1 and forall n, P n -> P (S (S n)). If the standard induction scheme is not strong enough to prove the property you want, you can try another one.
We can do the same for lists. If the standard induction scheme list_ind is not enough, we can write another one that works. In this idea, we define for lists an induction principle similar to the two-step induction on nat (and we will prove the validity of this induction scheme using the two-step induction on nat), where we need to prove three cases: P [], forall x, P [x] and forall x l x', P l -> P (x :: l ++ [x']). The proof of this scheme is the difficult part. Applying it to deduce your theorem is quite straightforward.
I don't know if the two-step induction scheme is part of the standard library, so I introduce it as an axiom.
Axiom nat_ind2 : forall P : nat -> Prop, P 0 -> P 1 ->
(forall n : nat, P n -> P (S (S n))) -> forall n : nat, P n.
Then we prove the induction scheme we want.
Lemma list_ind2 : forall {A} (P : list A -> Prop) (P_nil : P [])
(P_single : forall x, P [x])
(P_cons_snoc : forall x l x', P l -> P (x :: l ++ [x'])),
forall l, P l.
Proof.
intros. remember (length l) as n. symmetry in Heqn. revert dependent l.
induction n using nat_ind2; intros.
- apply length_zero_iff_nil in Heqn. subst l. apply P_nil.
- destruct l; [discriminate|]. simpl in Heqn. inversion Heqn; subst.
apply length_zero_iff_nil in H0. subst l. apply P_single.
- destruct l; [discriminate|]. simpl in Heqn.
inversion Heqn; subst. pose proof (rev_involutive l) as Hinv.
destruct (rev l). destruct l; discriminate. simpl in Hinv. subst l.
rewrite app_length in H0.
rewrite PeanoNat.Nat.add_comm in H0. simpl in H0. inversion H0.
apply P_cons_snoc. apply IHn. assumption.
Qed.
You should be able to conclude quite easily using this induction principle.
Theorem palindrome3 : forall {X : Type} (l : list X),
l = rev l -> pal l.

Coq: Problems with List In inductive

I'm new to Coq, but with some effort I was able to prove various inductive lemmas. However I get stuck on all exercises that uses the following inductive definition:
Inductive In (A:Type) (y:A) : list A -> Prop :=
| InHead : forall xs:list A, In y (cons y xs)
| InTail : forall (x:A) (xs:list A), In y xs -> In y (cons x xs).
The furthest i got was with the following lemma:
Lemma my_In_rev : forall (A:Type) (x:A) (l:list A), In x l -> In x (rev l).
Proof.
induction l.
simpl.
trivial.
simpl.
intros.
The following two lemmas I cant get past the first steps, because I get stuck on the exists goal right after using intros.
Lemma my_In_map : forall (A B:Type) (y:B) (f:A->B) (l:list A), In y (map f l) -> exists x : A, In x l /\ y = f x.
Lemma my_In_split : forall (A:Type) (x:A) (l : list A), In x l -> exists l1, exists l2, l = l1 ++ (x::l2).
Proof.
Any help would be appreciated!
For your first lemma, I added two simple sublemmas (that you can find in the list library).
The two others are more straightforward.
Require Import List.
Lemma In_concat_l: forall (A: Type) (l1 l2: list A) (x:A),
In x l1 -> In x (l1 ++ l2).
Proof.
intros A.
induction l1 as [ | hd tl hi ]; intros l2 x hIn; simpl in *.
- contradiction.
- destruct hIn.
+ left; assumption.
+ right; now apply hi.
Qed.
Lemma In_concat_r: forall (A: Type) (l1 l2: list A) (x:A),
In x l2 -> In x (l1 ++ l2).
intros A.
induction l1 as [ | hd tl hi ]; intros l2 x hIn; simpl in *.
- assumption.
- right; now apply hi.
Qed.
Lemma my_In_rev : forall (A:Type) (x:A) (l:list A), In x l -> In x (rev l).
Proof.
intros A x l.
induction l as [ | hd tl hi ]; intros hIn; simpl in *.
- contradiction.
- destruct hIn.
+ apply In_concat_r.
rewrite H.
now constructor.
+ apply In_concat_l.
now apply hi.
Qed.
Lemma my_In_map : forall (A B:Type) (y:B) (f:A->B) (l:list A), In y (map f l) -> exists x : A, In x l /\ y = f x.
Proof.
intros A B y f l.
induction l as [ | hd tl hi]; intros hIn; simpl in *.
- contradiction.
- destruct hIn.
+ exists hd; split.
left; reflexivity.
symmetry; assumption.
+ destruct (hi H) as [x0 [ h1 h2]].
exists x0; split.
right; assumption.
assumption.
Qed.
Lemma my_In_split : forall (A:Type) (x:A) (l : list A), In x l -> exists l1, exists l2, l = l1 ++ (x::l2).
Proof.
intros A x l.
induction l as [ | hd tl hi]; intros hIn; simpl in *.
- contradiction.
- destruct hIn.
rewrite H.
exists nil; exists tl; simpl; reflexivity.
destruct (hi H) as [ l1 [ l2 h ]].
exists (hd :: l1); exists l2.
rewrite <- app_comm_cons; rewrite h.
reflexivity.
Qed.
I won't say it's less complex than Rui's answer, but I find this solution a little bit easier to understand. But in the end, they are relatively close.
Cheers,
V.
When the goal is existentially quantified, you have to give a concrete example of an object with the stated property, and when a hypothesis is existentially quantified, you're allowed to assume one such object exists and introduce it. See FAQs 47, 53, and 54. By the way, an In predicate is already defined in Coq.Lists.List. Check it out here. A reference for Coq tactics is here.
A proof of the first lemma:
Require Import Coq.Lists.List.
Require Import Coq.Setoids.Setoid.
Inductive In {A : Type} (y : A) : list A -> Prop :=
| InHead : forall xs : list A, In y (cons y xs)
| InTail : forall (x : A) (xs : list A), In y xs -> In y (cons x xs).
Lemma L1 : forall (t1 : Type) (l1 : list t1) (o1 o2 : t1),
In o1 (o2 :: l1) <-> o1 = o2 \/ In o1 l1.
Proof.
intros t1 l1 o1 o2. split.
intros H1. inversion H1 as [l2 [H3 H4] | o3 l2 H2 [H3 H4]].
left. reflexivity.
right. apply H2.
intros H1. inversion H1 as [H2 | H2].
rewrite H2. apply InHead.
apply InTail. apply H2.
Qed.
Lemma my_In_map : forall (A B : Type) (l : list A) (y : B) (f : A -> B),
In y (map f l) -> exists x : A, In x l /\ y = f x.
Proof.
intros A B. induction l as [| z l H1].
intros y f H2. simpl in *. inversion H2.
intros y f H2. simpl in *. rewrite L1 in H2. inversion H2 as [H3 | H3].
exists z. split.
apply InHead.
apply H3.
assert (H4 := H1 _ _ H3). inversion H4 as [x [H5 H6]]. exists x. split.
rewrite L1. right. apply H5.
apply H6.
Qed.