Using 'unfold' of a Fixpoint inside the recursive step of the induction - coq

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.

Related

Coq prove a false list assumption

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?

Can't prove trivial lemma about function with non-standard recursion

I'm having a great difficulty trying to prove even very simple lemmas about a function I defined. This is my definition:
Require Import List.
Require Export Omega.
Require Export FunInd.
Require Export Recdef.
Notation "A :: B" := (cons A B).
Notation "[]" := nil.
Notation "[[ A ]]" := (A :: nil).
Inductive tm :=
| E: nat -> tm
| L: list tm -> tm.
Definition T := list tm.
Fixpoint add_list (l: list nat) : nat :=
match l with
| [] => 0
| n :: l' => n + (add_list l')
end.
Fixpoint depth (t: tm) : nat :=
match t with
| E _ => 1
| L l => 1 + (add_list (map depth l))
end.
Definition sum_depth (l: T) := add_list (map depth l).
Function sum_total (l: T) {measure sum_depth l} : nat :=
match l with
| [] => 0
| [[E n]] => n
| [[L li]] => sum_total li
| E n :: l' => n + (sum_total l')
| L li :: l' => (sum_total li) + (sum_total l')
end.
Proof.
- auto.
- intros; unfold sum_depth; subst. simpl; omega.
- intros; subst; unfold sum_depth; simpl; omega.
- intros; subst; unfold sum_depth; simpl; omega.
Defined.
The inductive type can't be changed.
I can prove simple propositions like Lemma test : forall n, sum_total [[E n]] = n. using the compute tactic, but another trivial lemma like Lemma test2 : forall l, sum_total [[L l]] = sum_total l. hangs.
First, it seems OK that the compute tactic "hangs" on the goal you mention (because when using the Function … Proof. … Defined. definition methodology, your function sum_total incorporates some proof terms, which are not intended to be computed − all the more on an arbitrary argument l; maybe a tactic such as simpl or cbn would be more suitable in this context).
Independently of my comment on list notations, I had a closer look on your formalization and it seems the Function command is unneeded in your case, because sum_total is essentially structural, so you could use a mere Fixpoint, provided the inductive type you are looking at is slightly rephrased to be defined in one go as a mutually-defined inductive type (see the corresponding doc of the Inductive command in Coq's refman which gives a similar, typical example of "tree / forest").
To elaborate on your example, you may want to adapt your definition (if it is possible for your use case) like this:
Inductive tm :=
| E: nat -> tm
| L: T -> tm
with T :=
Nil : T
| Cons : forall (e : tm) (l : T), T.
Notation "[[ A ]]" := (Cons A Nil).
Fixpoint sum_total (l: T) {struct l} : nat :=
match l with
| Nil => 0
| [[E n]] => n
| [[L li]] => sum_total li
| Cons (E n) l' => n + (sum_total l')
| Cons (L li) l' => (sum_total li) + (sum_total l')
end.
(* and the lemma you were talking about is immediate *)
Lemma test2 : forall l, sum_total [[L l]] = sum_total l.
reflexivity.
Qed.
Otherwise (if you cannot rephrase your tm inductive like this), another solution would be to use another strategy than Function to define your sum_total function, e.g. Program Fixpoint, or the Equations plugin (which are much more flexible and robust than Function when dealing with non-structural recursion / dependently-typed pattern matching).
Edit: as the OP mentions the inductive type itself can't be changed, there is a direct solution, even when using the mere Function machinery: relying on the "equation lemma" that is automatically generated by the definition.
To be more precise, if you take your script as is, then you get the following lemma "for free":
Search sum_total "equation".
(*
sum_total_equation:
forall l : T,
sum_total l =
match l with
| [] => 0
| [[E n]] => n
| E n :: (_ :: _) as l' => n + sum_total l'
| [[L li]] => sum_total li
| L li :: (_ :: _) as l' => sum_total li + sum_total l'
end
*)
So you could easily state and prove the lemma you are interested in by doing:
Lemma test2 : forall l, sum_total [[L l]] = sum_total l.
intros l.
rewrite sum_total_equation.
reflexivity.
Qed.
Here is an answer that doesn't require changing the inductive type.
There is a simple definition of sum_total that is both comparatively easy to understand and gives (almost) the lemma you are looking for by compute.
Fixpoint sum_tm (t : tm) : nat :=
match t with
| E n => n
| L li => list_sum (map sum_tm li)
end.
Definition sum_total (l : T) : nat := list_sum (map sum_tm l).
Lemma test2 : forall l, sum_total [[L l]] = sum_total l + 0.
reflexivity.
Qed.
(list_sum comes from the List module.)
Notice how the definition of sum_tm and sum_total exactly follows the structure of the definition of term and T, with list_sum (composed with map) corresponding to the use of list. This pattern is in general effective for these problems with nested inductives.
If you want to get rid of the + 0, you can define a different version of list_sum that includes a case for the singleton list (and you can fuse this with map if you want, though it is not necessary).
That would look like replacing list_sum with list_sum_alt defined as
Fixpoint list_sum_alt (l : list nat) : nat :=
match l with
| [] => 0
| [[n]] => n
| n :: li => n + list_sum_alt li
end.
With this definition, test2 holds by compute.

How to make a recursive call with a decreasing argument?

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.

How can I split a list in half in coq?

It looks definitely simple task until I actually try to work on it. My method is to use twin pointers to avoid asking the length of the list ahead of time, but the difficulties come from the implication that I know for sure one list is "no emptier" than another. Specifically, in pseudo-coq:
Definition twin_ptr (heads, tail, rem : list nat) :=
match tail, rem with
| _, [] => (rev heads, tail)
| _, [_] => (rev heads, tail)
| t :: tl, _ :: _ :: rm => twin_ptr (t :: heads) tl rm
end.
Definition split (l : list nat) := twin_ptr [] l l
But definitely it's not going to compile because the match cases are incomplete. However, the missing case by construction doesn't exist.
What's your way of implementing it?
I you are not afraid of dependent types, you can add a proof that rem is shorter than tail as an argument of twin_ptr. Using Program to help manage these dependent types, this could give the following.
Require Import List. Import ListNotations.
Require Import Program.
Require Import Arith.
Require Import Omega.
Program Fixpoint twin_ptr
(heads tail rem : list nat)
(H:List.length rem <= List.length tail) :=
match tail, rem with
| a1, [] => (rev heads, tail)
| a2, [a3] => (rev heads, tail)
| t :: tl, _ :: _ :: rm => twin_ptr (t :: heads) tl rm _
| [], _::_::_ => !
end.
Next Obligation.
simpl in H. omega.
Qed.
Next Obligation.
simpl in H. omega.
Qed.
Definition split (l : list nat) := twin_ptr [] l l (le_n _).
The exclamation mark means that a branch is unreachable.
You can then prove lemmas about twin_ptr and deduce the properties of split from them. For example,
Lemma twin_ptr_correct : forall head tail rem H h t,
twin_ptr head tail rem H = (h, t) ->
h ++ t = rev head ++ tail.
Proof.
Admitted.
Lemma split_correct : forall l h t,
split l = (h, t) ->
h ++ t = l.
Proof.
intros. apply twin_ptr_correct in H. assumption.
Qed.
Personally, I dislike to use dependent types in functions, as resulting objects are more difficult to manipulate. Instead, I prefer defining total functions and give them the right hypotheses in the lemmas.
You do not need to maintain the invariant that the second list is bigger than the third. Here is a possible solution:
Require Import Coq.Arith.PeanoNat.
Require Import Coq.Arith.Div2.
Require Import Coq.Lists.List.
Import ListNotations.
Section Split.
Variable A : Type.
Fixpoint split_aux (hs ts l : list A) {struct l} : list A * list A :=
match l with
| [] => (rev hs, ts)
| [_] => (rev hs, ts)
| _ :: _ :: l' =>
match ts with
| [] => (rev hs, [])
| h :: ts => split_aux (h :: hs) ts l'
end
end.
Lemma split_aux_spec hs ts l n :
n = div2 (length l) ->
split_aux hs ts l = (rev (rev (firstn n ts) ++ hs), skipn n ts).
Proof.
revert hs ts l.
induction n as [|n IH].
- intros hs ts [|x [|y l]]; easy.
- intros hs ts [|x [|y l]]; simpl; try easy.
intros Hn.
destruct ts as [|h ts]; try easy.
rewrite IH; try congruence.
now simpl; rewrite <- app_assoc.
Qed.
Definition split l := split_aux [] l l.
Lemma split_spec l :
split l = (firstn (div2 (length l)) l, skipn (div2 (length l)) l).
Proof.
unfold split.
rewrite (split_aux_spec [] l l (div2 (length l))); trivial.
now rewrite app_nil_r, rev_involutive.
Qed.
End Split.
May I suggest going via a more precise type? The main idea is to define a function splitting a Vector.t whose nat index has the shape m + n into a Vector.t of size m and one of size n.
Require Import Vector.
Definition split_vector : forall a m n,
Vector.t a (m + n) -> (Vector.t a m * Vector.t a n).
Proof.
intros a m n; induction m; intro v.
- firstorder; constructor.
- destruct (IHm (tl v)) as [xs ys].
firstorder; constructor; [exact (hd v)|assumption].
Defined.
Once you have this, you've reduced your problem to defining the floor and ceil of n / 2 and proving that they sum to n.
Fixpoint div2_floor_ceil (n : nat) : (nat * nat) := match n with
| O => (O , O)
| S O => (O , S O)
| S (S n') => let (p , q) := div2_floor_ceil n'
in (S p, S q)
end.
Definition div2_floor (n : nat) := fst (div2_floor_ceil n).
Definition div2_ceil (n : nat) := snd (div2_floor_ceil n).
Lemma plus_div2_floor_ceil : forall n, div2_floor n + div2_ceil n = n.
Proof.
refine
(fix ih n := match n with
| O => _
| S O => _
| S (S n') => _
end); try reflexivity.
unfold div2_floor, div2_ceil in *; simpl.
destruct (div2_floor_ceil n') as [p q] eqn: eq.
simpl.
replace p with (div2_floor n') by (unfold div2_floor ; rewrite eq ; auto).
replace q with (div2_ceil n') by (unfold div2_ceil ; rewrite eq ; auto).
rewrite <- plus_n_Sm; do 2 f_equal.
apply ih.
Qed.
Indeed, you can then convert length xs into ceil (length xs / 2) + floor (length xs / 2) and use split_vector to get each part.
Definition split_list a (xs : list a) : (list a * list a).
Proof.
refine
(let v := of_list xs in
let (p , q) := split_vector a (div2_floor _) (div2_ceil _) _ in
(to_list p, to_list q)).
rewrite plus_div2_floor_ceil; exact v.
Defined.

Restating lambdas in Coq without extensional function equality?

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.)