0

Consider the following code:

Require Import List.

Set Implicit Arguments.

Inductive even_length {A : Type} : list A -> Prop:=
| e_nil : even_length nil
| e_cons : forall e l, odd_length l -> even_length (e::l)
with
  odd_length {A : Type} : list A -> Prop :=
  | o_cons : forall e l, even_length l -> odd_length (e::l). 

Lemma map_even : forall A B (f : A -> B) (l : list A),
    even_length l -> even_length (map f l).
Proof.
  induction l.
  (** nil *)
  - intros. simpl. econstructor.
  (** cons *)
  - intros. simpl.
    inversion_clear H.
    econstructor.
    Abort. (** odd_length l -> odd_length (map f l) would help *)

Notice that I wish to prove it with induction over the list l.

As explained in here, Coq by default only generates non-mutual induction principles and to get the mutual induction principles the Scheme command is necessary. So this is what I did:

Scheme even_length_mut := Induction for even_length Sort Prop
with odd_length_mut := Induction for odd_length Sort Prop.

Check even_length_mut.
(**   
even_length_mut
     : forall (A : Type) (P : forall l : list A, even_length l -> Prop) (P0 : forall l : list A, odd_length l -> Prop),
       P nil e_nil ->
       (forall (e : A) (l : list A) (o : odd_length l), P0 l o -> P (e :: l) (e_cons e o)) ->
       (forall (e : A) (l : list A) (e0 : even_length l), P l e0 -> P0 (e :: l) (o_cons e e0)) -> forall (l : list A) (e : even_length l), P l e 
*)

From this type above and the examples that I saw, I managed to complete this proof like so:

Lemma map_even : forall A B (f : A -> B) (l : list A),
    even_length l -> even_length (map f l).
Proof.
  intros.
  apply (even_length_mut (fun l (h : even_length l) => even_length (map f l) )
                         (fun l (h : odd_length l) => odd_length (map f l) )
        ); 
    try econstructor; auto.
Qed.

However, this induction wasn't over l, it was the so called "induction over evidence".

My question is what should be the predicates in even_length_mut so the induction is over l?

Edit: Also, would be possible to get the odd_length l -> odd_length (map f l) hypothesis?

Rafael Castro
  • 579
  • 5
  • 14
  • For inductive predicates, it is usually preferable to use `Minimality` rather than `Induction` in the definition of `even_lenth_mut` and `odd_length_mut`. See for instance [this question](https://stackoverflow.com/questions/55196816/induction-principle-for-le). – eponier May 15 '19 at 08:21

1 Answers1

1

To prove this by induction we need either to generalize the lemma to get a stronger induction hypothesis or to use a custom induction scheme which adds two elements at once to the list instead of just one (which will also require such a generalization).

Since the default induction scheme (induction l) only adds one element at a time, we need an intermediate predicate to record the "state" of the list inbetween states where it is of even length, namely, we also need to remember the case where l is of odd length.

Lemma map_odd_even {A B} (f : A -> B) : forall l : list A,
  (even_length l -> even_length (map f l)) /\
  (odd_length l -> odd_length (map f l)).
Proof.
  induction l.

You can apply the same idea to prove a more general induction scheme for even-length lists, from which your map_even theorem would follow quite easily via apply even_list_ind. (EDIT: another candidate, induction l using even_list_ind fails, I don't know why.)

Theorem even_list_ind {A} (P : list A -> Prop) :
  P [] ->
  (forall x y l, even_length l -> P l -> P (x :: y :: l)) ->
  forall l, even_length l -> P l.
Li-yao Xia
  • 31,896
  • 2
  • 33
  • 56
  • I managed to prove `map_odd_even`, but not `even_list_ind` so far. Any tips on how to do it? Also, when I try `induction l using even_list_ind` Coq complains about "Not the right number of induction arguments (expected 2 arguments)". – Rafael Castro May 11 '19 at 23:28
  • 2
    @RafaelCastro The more direct solution is to use `even_length_mut` (or a style similar to the first lemma in the answer) with `P0 l` (the property implied by `odd_length l`) simply stating that the tail of `l` satisfies `P`. A solution that I find more elegant is to write the theorem and its proof as a `Fixpoint`, which allows you to use two nested `match` and thus completely skip the "odd" case. – eponier May 15 '19 at 12:08
  • @Li-yao Xia Any information for the fix of "Not the right number of induction arguments (expected 2 arguments)"? What does this error mean? – Dole Sep 20 '20 at 01:19
  • I'm not sure what that means or how to fix this use of `induction`, but an alternative is to use `apply`. I could do the proof with `intros A B f; apply even_list_ind.` – Li-yao Xia Sep 20 '20 at 15:13