1

I have two lists, one constructed directly by recursion and the other constructed using a map operation. I'm trying to show they are equal, and surprisingly I got stuck.

Require Import Coq.Lists.List.
Import ListNotations.

Fixpoint ls_zeroes n :=
  match n with
  | 0 => nil
  | S n' => 0 :: ls_zeroes n'
  end.

Fixpoint ls_ones n := map S (ls_zeroes n).
Fixpoint ls_ones' n :=
  match n with
  | 0 => nil
  | S n' => 1 :: ls_ones' n'
  end.

Goal forall n, ls_ones n = ls_ones' n.
Proof.
  intros.
  induction n.
  - reflexivity.
  - simpl. f_equal. (* ??? *)
Abort.

This is what the context looks like:

1 subgoal
n : nat
IHn : ls_ones n = ls_ones' n
______________________________________(1/1)
map S (ls_zeroes n) = ls_ones' n

I thought fold ls_ones would map S (ls_zeroes n) into ls_ones n since that's literally the definition of ls_ones but it does nothing. If I try to unfold ls_ones in IHn I get a nasty recursive expression instead of the verbatim definition of ls_ones.

What is the cleanest way to complete this proof?

Carl Patenaude Poulin
  • 6,238
  • 5
  • 24
  • 46

3 Answers3

2

Notice that when you define ls_one and unfold the definition you gets :

(fix ls_ones (n0 : nat) : list nat := map S (ls_zeroes n0)) n = ls_ones' n

The problem is that ls_one isn't a fixpoint. Indeed, it's doesn't make a recursion. Once coq automatically defines the point {struct n0} (in that case the n argument), your proof gets stuck because n is never destructed in P k -> P (k + 1), 'cause k is not destructed. Using :

Definition ls_ones n := map S (ls_zeroes n). 

The proof becomes trivial :

Goal forall n, ls_ones n = ls_ones' n.
Proof.
  intros.
  induction n.
  trivial.
  unfold ls_ones in *.
  simpl.
  rewrite IHn.
  trivial.
Qed.
Tiago Campos
  • 503
  • 3
  • 14
1

I thought fold ls_ones would map S (ls_zeroes n) into ls_ones n since that's literally the definition of ls_ones

Is it? You said Fixpoint ls_ones, not Definition. Just like any Fixpoint, this means that the given definition of ls_ones is transformed into a fix. There's no recursive structure in the definition given, so this is pointless, but you said to do it, so Coq does it. Issue Print ls_ones. to see the actual definition. The true solution is to make ls_ones a Definition.

If you don't fix that, Coq will only reduce a Fixpoint if the recursive argument(s) start with constructors. Then, in order to complete this proof, you need to destruct n to show those constructors:

Goal forall n, ls_ones n = ls_ones' n.
Proof.
  intros.
  induction n.
  - reflexivity.
  - simpl. f_equal. destruct n; assumption.
Qed.
HTNW
  • 27,182
  • 1
  • 32
  • 60
  • Nice catch. I changed `Fixpoint` to `Definition` and `fold` still does nothing. `unfold ls_ones. simpl. f_equal. Fail progress fold ls_ones.` – Carl Patenaude Poulin Mar 25 '20 at 01:53
  • 1
    @CarlPatenaudePoulin The `fold` is unnecessary. At that point, the type of `IHn` and the goal are already convertible. Just finish the proof with `exact IHn.`/etc. If you really want it, `fold (ls_ones n).`. As stated in the [documentation](https://coq.inria.fr/refman/proof-engine/tactics.html#coq:tacn.fold), `fold expr` first `red`uces `expr`, then searches for exact matches of that pattern in the goal. `fold ls_ones` therefore recognizes only the actual abstraction `fun m => map S (ls_zeroes m)`, not the reduction of its application `map S (ls_zeroes n)`. – HTNW Mar 25 '20 at 02:14
1

Unfortunately, due to the value being fixed in your definitions you must use induction to do the proof:

From mathcomp Require Import all_ssreflect.

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

Fixpoint seq0 n :=
  match n with
  | 0 => nil
  | S n' => 0 :: seq0 n'
  end.

Fixpoint seq1 n :=
  match n with
  | 0 => nil
  | S n' => 1 :: seq1 n'
  end.

Lemma eq_F n : seq1 n = [seq n.+1 | n <- seq0 n].
Proof. by elim: n => //= n ->. Qed.

There is not a lot to proof tho. I'd recommend tho using the more general nseq count elem function instead of definition your own duplicate structures, then the proof follows pretty quickly from the general lemma about map:

Lemma eq_G n : nseq n 1 = [seq n.+1 | n <- nseq n 0].
Proof. by rewrite map_nseq. Qed.
ejgallego
  • 6,709
  • 1
  • 14
  • 29