6
votes

When reasoning on paper, I often use arguments by induction on the length of some list. I want to formalized these arguments in Coq, but there doesn't seem to be any built in way to do induction on the length of a list.

How should I perform such an induction?

More concretely, I am trying to prove this theorem. On paper, I proved it by induction on the length of w. My goal is to formalize this proof in Coq.

3
For concreteness, is there any particular property of lists that you would like to prove?Arthur Azevedo De Amorim
@arthur-azevedo-de-amorim Thank you for replying. It is an automat as here: ibb.co/nNUXe5 I want to prove some theorems about it. The coq code can be seen here: pastebin.ubuntu.com/25386445 I failed to continue. I manage to prove it by induction on list length in paper using informal langauge. Just don't know how to use coq to prove it.kainwen

3 Answers

8
votes

There are many general patterns of induction like this one that can be covered by the existing library on well founded induction. In this case, you can prove any property P by induction on length of lists by using well_founded_induction, wf_inverse_image, and PeanoNat.Nat.lt_wf_0, as in the following comand:

induction l using (well_founded_induction
                     (wf_inverse_image _ nat _ (@length _)
                        PeanoNat.Nat.lt_wf_0)).

if you are working with lists of type T and proving a goal P l, this generates an hypothesis of the form

H : forall y : list T, length y < length l -> P y

This will apply to any other datatype (like trees for instance) as long as you can map that other datatype to nat using any size function from that datatype to nat instead of length.

Note that you need to add Require Import Wellfounded. at the head of your development for this to work.

6
votes

Here is how to prove a general list-length induction principle.

Require Import List Omega.

Section list_length_ind.  
  Variable A : Type.
  Variable P : list A -> Prop.

  Hypothesis H : forall xs, (forall l, length l < length xs -> P l) -> P xs.

  Theorem list_length_ind : forall xs, P xs.
  Proof.
    assert (forall xs l : list A, length l <= length xs -> P l) as H_ind.
    { induction xs; intros l Hlen; apply H; intros l0 H0.
      - inversion Hlen. omega.
      - apply IHxs. simpl in Hlen. omega.
    }
    intros xs.
    apply H_ind with (xs := xs).
    omega.
  Qed.
End list_length_ind.

You can use it like this

Theorem foo : forall l : list nat, ...
Proof. 
    induction l using list_length_ind.
    ...

That said, your concrete example example does not necessarily need induction on the length. You just need a sufficiently general induction hypothesis.

Import ListNotations.

(* ... some definitions elided here ... *)    

Definition flip_state (s : state) :=
  match s with
  | A => B
  | B => A
  end.

Definition delta (s : state) (n : input) : state :=
  match n with
  | zero => s
  | one => flip_state s
  end.

(* ...some more definitions elided here ...*)

Theorem automata221: forall (w : list input),
    extend_delta A w = B <-> Nat.odd (one_num w) = true.
Proof.
  assert (forall w s, extend_delta s w = if Nat.odd (one_num w) then flip_state s else s).
  { induction w as [|i w]; intros s; simpl.
    - reflexivity.
    - rewrite IHw.
      destruct i; simpl.
      + reflexivity.
      + rewrite <- Nat.negb_even, Nat.odd_succ.
        destruct (Nat.even (one_num w)), s; reflexivity.
  }

  intros w.
  rewrite H; simpl.
  destruct (Nat.odd (one_num w)); intuition congruence.
Qed.
4
votes

In case like this, it is often faster to generalize your lemma directly:

From mathcomp Require Import all_ssreflect.

Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.

Section SO.

Variable T : Type.
Implicit Types (s : seq T) (P : seq T -> Prop).

Lemma test P s : P s.
Proof.
move: {2}(size _) (leqnn (size s)) => ss; elim: ss s => [|ss ihss] s hs.

Just introduce a fresh nat for the size of the list, and regular induction will work.