Given the next theorem.
Theorem rev_injective_helper : forall (l : natlist) (n : nat),
[] = l ++ [n] -> False.
Proof.
intros l n H.
unfold app in H.
induction l. all: inversion H.
Qed.
How to prove the next goal?
1 subgoal
n : nat
l2 : natlist
H : [ ] = rev l2 ++ [n]
IHl2 : [ ] = rev l2 -> [ ] = l2
______________________________________(1/1)
[ ] = n :: l2
As I understand an assumption in this case is wrong H : [ ] = rev l2 ++ [n] how to finis the proof? Thanks in advance!
Update.
Missing definitions:
Fixpoint app (l1 l2 : natlist) : natlist :=
match l1 with
| nil ⇒ l2
| h :: t ⇒ h :: (app t l2)
end.
Notation "x ++ y" := (app x y)
(right associativity, at level 60).
Fixpoint rev (l:natlist) : natlist :=
match l with
| nil ⇒ nil
| h :: t ⇒ rev t ++ [h]
end.
I'm trying to prove this theorem:
Theorem rev_injective : forall (l1 l2 : natlist),
rev l1 = rev l2 -> l1 = l2.
As you say you have a false hypothesis in your context, so it doesn't matter what your are trying to prove, it will follow from falsehood.
To exploit this you can use the exfalso tactic which replaces your current goal by False. Then you should be able to conclude from rev_injective_helper and H no?
Related
Inductive bar {X : Type} : list X -> Prop :=
| bar_nil : bar []
| bar_fst : forall x l, bar (rev l ++ l) -> bar (rev l ++ [x] ++ l)
| bar_snd : forall x l, bar (rev l ++ [x] ++ l) -> bar (rev l ++ [x; x] ++ l).
Axiom bar_surround :
forall X x (l : list X),
bar l -> bar ([x] ++ l ++ [x]).
Inductive list_last {X : Type} : list X -> Prop :=
| ll_nil : list_last []
| ll_snoc : forall l x, list_last l -> list_last (l ++ [x]).
Axiom ll_app :
forall X (a b : list X),
list_last a -> list_last b -> list_last (a ++ b).
Axiom ll_from_list :
forall {X} (l : list X),
list_last l.
Axiom app_head_eq :
forall X (a b c : list X),
a ++ c = b ++ c -> a = b.
Theorem foo :
forall X (l: list X), l = rev l -> bar l.
Proof.
intros.
induction l.
- constructor.
- assert (Hll := ll_from_list l).
inversion Hll.
+ apply (bar_fst x []). apply bar_nil.
+ rewrite <- H1 in H.
simpl in H.
rewrite rev_app_distr in H.
rewrite <- app_assoc in H.
simpl in H.
inversion H.
apply app_head_eq in H4.
apply bar_surround.
1 subgoal
X : Type
x : X
l, l0 : list X
x0 : X
H : x :: l0 ++ [x0] = x0 :: rev l0 ++ [x]
IHl : l = rev l -> bar l
Hll : list_last l
H0 : list_last l0
H1 : l0 ++ [x0] = l
H3 : x = x0
H4 : l0 = rev l0
______________________________________(1/1)
bar l0
I am only a step away from getting this exercise solved, but I do not know how to do the induction step. Note that IHl is useless here and replacing induction on l with induction on Hll would have a similar problem. In both cases, the inductive hypothesis would expect a call with a one step decrease while I need two - one with the item taken from both the start and the end of the list on both sides of the equality.
Consider that the type of the function I am trying to prove is forall X (l: list X), l = rev l -> bar l and I have l0 = rev l0 -> bar l0 in the goal here. l0 is a decreased argument thereby making the recursive call safe.
What should I do here?
You can prove the following inductive predicate:
Inductive delist {A : Type} : list A -> Prop :=
| delist_nil : delist []
| delist_one x : delist [x]
| delist_cons x y l : delist l -> delist (x :: l ++ [y])
.
Theorem all_delist {A} : forall xs : list A, delist xs.
Then in your final theorem, induction on delist xs will split into the cases you need.
Another solution is by strong induction on the length of the list:
Lemma foo_len X : forall (n : nat) (l: list X), length l <= n -> l = rev l -> bar l.
Proof.
induction n.
(* Nat.le_succ_r from the Arith module is useful here *)
...
Qed.
(* Final theorem *)
Theorem foo X : forall (l : list X), l = rev l -> bar l.
Proof.
intros; apply foo_len; auto.
Qed.
This is a more common and systematic principle than delist, but you will need to work more than the ad-hoc inductive type above to use the induction hypothesis in the main proof.
Here is how to implement the first part of what was suggested in the other answer. I can confirm that with this, solving the exercise is quite simple. That having said, I am interested how to solve the above using straightforward induction. Having to implement delist and its functions is more complicated than I'd prefer.
Inductive delist {A : Type} : list A -> Prop :=
| delist_nil : delist []
| delist_one x : delist [x]
| delist_wrap x y l : delist l -> delist (x :: l ++ [y]).
Theorem delist_cons {A} :
forall x (l : list A),
delist l -> delist (x :: l).
Proof.
intros.
generalize dependent x.
induction H; intros.
- constructor.
- replace [x; x0] with (x :: [] ++ [x0]).
2 : { reflexivity. }
+ apply delist_wrap with (l := []). constructor.
- replace (x0 :: x :: l ++ [y]) with (x0 :: (x :: l) ++ [y]).
2 : { reflexivity. }
constructor.
apply IHdelist.
Qed.
Theorem delist_from_list {A} :
forall l : list A,
delist l.
Proof.
induction l.
- constructor.
- assert (ll := ll_from_list l).
destruct ll.
+ constructor.
+ apply delist_cons. assumption.
Qed.
I made an environment to try to proof what I want/need
I have a posfijo function that says if a list (l1) contains another list (l2) at the end.
So if I add an element to the first list and I use the result as the second list, like l2 = x :: l1, I want to proof that is not possible.
I did this...
Variable G:Set.
Inductive posfijo : list _ -> list _ -> Prop :=
| posfijoB : forall l: list _, posfijo l l
| posfijoI : forall (l1 l2: list _) (a : G), posfijo l1 l2 -> posfijo l1 (cons a l2).
Infix "<<" := (posfijo) (at level 70, right associativity).
Lemma Pref4_a : forall (X:Set)(l: list G)(x:G), ~ (cons x l << l).
Proof.
intros X l x H.
So then my goal is
You should proceed with induction l.
I'm trying to prove something in coq and the same problem keeps coming up;
I want to unfold the definition of a Fixpoint inside the recursive (not nil) step of induction. Unfold works as expected, here's an example:
Before unfolding the list reverse (rev) definition:
n : nat
l' : natlist
IHl' : rev (rev l') = l'
============================
rev (rev (n :: l')) = n :: l'
After:
n : nat
l' : natlist
IHl' : rev (rev l') = l'
============================
(fix rev (l : natlist) : natlist := match l with
| [ ] => [ ]
| h :: t => rev t ++ [h]
end)
((fix rev (l : natlist) : natlist := match l with
| [ ] => [ ]
| h :: t => rev t ++ [h]
end) l' ++ [n]) = n :: l'
So far so good. Now I would expect simpl to figure out I'm on the non-nil case of the induction since n :: l' can never be nil,
and simplify away the nil case of the match ([ ] => [ ]), keeping only the non-nil part of the definition.
Unfortunately it does not do that implicitly. How can I make unfold of a recursive Fixpoint definition play well with induction? How do I get:
n : nat
l' : natlist
IHl' : rev (rev l') = l'
============================
rev (rev l' ++ [n]) = n :: l'
According to the rev definition for the inner rev.
Note: The use of Lists is irrelevant here, the same technique can be used for any inductively defined types.
Edit: Definition of rev and proof that leads to the After state.
Fixpoint rev (l:natlist) : natlist :=
match l with
| nil => nil
| h :: t => rev t ++ [h]
end.
Theorem rev_involutive : forall l : natlist,
rev (rev l) = l.
Proof.
intros l. induction l as [| n l'].
- reflexivity.
- unfold rev.
Your After: is basically rev (rev l' ++ [n]) (with rev unfolded) which means that the reduction you want to see happening has already happened. Now you probably want to prove an auxiliary lemma akin to rev (xs ++ ys) = rev ys ++ rev xs.
I am trying to prove the following theorem by induction over l. It's an easy theorem on paper, however when I try to prove it in Coq I am not getting the induction goal I would expect.
Theorem nodup_app__disjoint: forall {X: Type} (l: list X),
(forall l1 l2 : list X, l = l1 ++ l2 -> Disjoint l1 l2) -> NoDup l.
Proof.
intros X l. induction l.
- intros F. apply nodup_nil.
- (* ??? *)
The state at this point:
1 subgoal
X : Type
x : X
l : list X
IHl : (forall l1 l2 : list X, l = l1 ++ l2 -> Disjoint l1 l2) -> NoDup l
______________________________________(1/1)
(forall l1 l2 : list X, x :: l = l1 ++ l2 -> Disjoint l1 l2) ->
NoDup (x :: l)
But that is not at all the goal I would expect! Shouldn't x :: l = l1 ++ l2 be replaced by l = l1 ++ l2?
Here are the propositions I'm working with, in case you'd like to reproduce the problem and see for yourself:
Inductive Disjoint {X : Type}: list X -> list X -> Prop :=
| disjoint_nil: Disjoint [] []
| disjoint_left: forall x l1 l2, Disjoint l1 l2 -> ~(In x l2) -> Disjoint (x :: l1) l2
| disjoint_right: forall x l1 l2, Disjoint l1 l2 -> ~(In x l1) -> Disjoint l1 (x :: l2).
Inductive NoDup {X: Type}: list X -> Prop :=
| nodup_nil: NoDup []
| nodup_cons: forall hd tl, NoDup tl -> ~(In hd tl) -> NoDup (hd :: tl).
But that is not at all the goal I would expect! Shouldn't x :: l = l1 ++ l2 be replaced by l = l1 ++ l2?
Short answer: It should not!
Induction principle for lists
Let's recall the induction principle for lists:
Check list_ind.
(*
list_ind
: forall (A : Type) (P : list A -> Prop),
P [] ->
(forall (a : A) (l : list A), P l -> P (a :: l)) ->
forall l : list A, P l
*)
It means that in order to prove that a predicate P holds for all lists (forall l : list A, P l), one needs to prove that
P holds for the empty list -- P [];
P holds for all non-empty lists, given that it holds for their tails -- (forall (a : A) (l : list A), P l -> P (a :: l)).
Applying the list induction principle to the goal
Now, we have the following goal:
(forall l1 l2, l = l1 ++ l2 -> Disjoint l1 l2) -> NoDup l.
To see what goals we should get when trying to prove the statement by induction on l, let's mechanically substitute l in the above with [] in one case and h :: tl the other.
[] case:
(forall l1 l2, [] = l1 ++ l2 -> Disjoint l1 l2) -> NoDup [].
h :: tl case:
(forall l1 l2, h :: tl = l1 ++ l2 -> Disjoint l1 l2) -> NoDup (h :: tl).
This is what you've got above (modulo the renaming). For the second case you are also getting the induction hypothesis, which we get from the original statement substituting tl for l:
(forall l1 l2, tl = l1 ++ l2 -> Disjoint l1 l2) -> NoDup tl.
Incidentally, the theorem is provable and you might find the following helper lemmas useful:
Lemma disjoint_cons_l {X} (h : X) l1 l2 :
Disjoint (h :: l1) l2 -> Disjoint l1 l2.
Admitted.
Lemma disjoint_singleton {X} h (l : list X) :
Disjoint [h] l -> ~ In h l.
Admitted.
I am going over Software Foundations. There are two definitions of list reverse function given.
Fixpoint rev (l:natlist) : natlist :=
match l with
| nil => nil
| h :: t => rev t ++ [h]
end.
and a tail-recursive one:
Fixpoint rev_append {X} (l1 l2 : list X) : list X :=
match l1 with
| [] => l2
| x :: l1' => rev_append l1' (x :: l2)
end.
Definition tr_rev {X} (l : list X) : list X :=
rev_append l [].
Here is where the problem arrives. I am asked to prove their equality, with the following theorem stated: Lemma tr_rev_correct : ∀X, #tr_rev X = #rev X.
This generates the following proof state:
1 subgoal
______________________________________(1/1)
forall X : Type, tr_rev = rev
However, even if I do unfold tr_rev (and / or the other two definitions), I end up with something along the lines of:
1 subgoal
______________________________________(1/1)
forall X : Type, (fun l : list X => rev_append l [ ]) = rev
But I can't do anything with this formulation (other than intro X).
What I would like to have is this:
Lemma tr_rev_correct : forall (X : Type) (l : list X), tr_rev l = rev l.
Is there a way to replace the former with the latter without involving functional extensionality? (If I didn't want to restate the lemma that is given by the book.)