Skip to Content.
Sympa Menu

coq-club - Re: [Coq-Club] Simplify proofs with nested pattern matching (cases explosion)

coq-club AT inria.fr

Subject: The Coq mailing list

List archive

Re: [Coq-Club] Simplify proofs with nested pattern matching (cases explosion)


Chronological Thread 
  • From: Gaëtan Gilbert <gaetan.gilbert AT skyskimmer.net>
  • To: coq-club AT inria.fr
  • Subject: Re: [Coq-Club] Simplify proofs with nested pattern matching (cases explosion)
  • Date: Mon, 29 Jun 2020 17:39:23 +0200
  • Authentication-results: mail3-smtp-sop.national.inria.fr; spf=None smtp.pra=gaetan.gilbert AT skyskimmer.net; spf=Pass smtp.mailfrom=gaetan.gilbert AT skyskimmer.net; spf=None smtp.helo=postmaster AT relay2-d.mail.gandi.net
  • Ironport-phdr: 9a23:l6EzORVfvooa9fIvGOfFRj9fB1PV8LGtZVwlr6E/grcLSJyIuqrYbByFt8tkgFKBZ4jH8fUM07OQ7/m9HzVRsN3Y4DgrS99lb1c9k8IYnggtUoauKHbQC7rUVRE8B9lIT1R//nu2YgB/Ecf6YEDO8DXptWZBUhrwOhBoKevrB4Xck9q41/yo+53Ufg5EmCexbal9IRmrrQjdrNQajI9mJ6o+1xfEoWZDdvhLy29vOV+dhQv36N2q/J5k/SRQuvYh+NBFXK7nYak2TqFWASo/PWwt68LlqRfMTQ2U5nsBSWoWiQZHAxLE7B7hQJj8tDbxu/dn1ymbOc32Sq00WSin4qx2RhLklDsLOjgk+2zRl8d+jr9UoAi5qhJi3YDUboGbOvlwcKzTctwVR3ZOU91UVyBdGI6xdZcDAuQDMOtesoLzp0EOrRy7BQS0Be3g0CNPhmPs0q08y+svEADG3Ag7EN0QqnTUsMj+OaAdUe+v0qbI0S/Mb/VM1Tfy6YjIdgsuru+WXbJsasfR0kovFgPejlWTqIzlOjaV2foXs2SB6epvS/6vhnchpgpsrTeh2t0ihZPVhoIJ1F/E7yN5zZ4oKdGkVUJ2bt+pHZpOuyybOIV7QM0sT3xqtSs6ybAIuZC2cTYJxZg5yBPSauGKfomW7x//VOidPCt1iX1ldry/gRu57EuuyvXkW8WqzVpHrDBJn9vQunwXyhDe6caKRuFg8kql1juDzx7f5vxKLEwuiKbWK4AtzqQtmpcSr0jPBDL6lUrygaKQa04q4PKn6/79bbXjvpKcN5F7igX5Mqk2gMywH+A4PRIOXmSF4Oizyafv/UjjT7VLiv06iKbZv4rcJcsGp661GQlV3Zg/6xqnDjem1soXnWUfIV5bZR6KjZLlNlPSLPziEPuygFqhnC12y/3CMbDtGpDNIWLCkLflc7Z98UlcyA8rwNBQ/Z1bFK0BL+j1WkPru9zYDxs5PBeqzOb9FNVwzZgeWWGPA6+CM6PSsFqI5ucxLOmWfoMVvijyK+Q96/70kXA5gUMdfbWu3ZYPdH+4Ge1mL1yFbnron9cOCnwHvhE+TezvkF2NSyRfZ3e0X6Im5zE0EpiqDYnZRtPlvLvU1yCiW5ZSe2puC1aWEH6ueZ/Xde0LbXe9K0x9mzozermlQYI7yVn6uwb317NhaOXV/icVr47Lz9tk/O7SkBQ/73pyAtjLgDLFdH19gm5dH2x+56t4u0Eokg7fg5g9uORREJlo390MSh0zbMCO1O9rENPzXwfMZJGPRUr0Goz3UwF0dco4xpo1W2g4Htyjih7Z2C/zXe0OlK2QB50x96/GmX78O5QkkiuU5Owal1AjB/B3Gyimi6p4rVWBHYPNmlTD0qrscK0d2GjC/WGPzCyIsV0KCAM=

You may convert is_valid to an inductive type, that way it only has
constructors for the cases you want and you can destruct it directly.
see attached file for an example

Gaëtan Gilbert

On 29/06/2020 16:46, Blaudeau Clément wrote:
Hi Everyone,
I'm currently working to prove results on a fonction that uses several levels
of nested pattern matching and it generates *a lot* of trivial subgoals, to
the point that every proof takes several minutes to go through.

##### High level view of the problem

I have an inductive type with ~ 50 constructors, and nested pattern matching
on lists of that type. The nested pattern matching is translated into several
levels of normal pattern matching with one case that is interesting and 49
useless cases. To build proofs on my function, I would like to be able to
extract easily the interesting cases, and quickly drop all useless cases. Is
there automated ways of doing that ? Just destruct the match expressions and
using `congruence` is too slow.

##### More details

I have a function  `is_valid : A -> bool`, and I want to prove results of the
form `is_valid a = true -> P`, where `A` is an inductive type of the form
```Coq
Inductive A := | N : B -> (list A) -> A . % N is the only constructor
```
And `B` is also an inductive type **with around 50 constructors**.
The problem is that, in the `is_valid` function, I have nested pattern
matching (on the list) like
```Coq
| N b1 (N b2 [])::(N b3 [])::_ => (f b1 b2 b3) % some property computed using
b1 b2 b3
```
generates huge patterns, because the internal translation of nested patterns
is to create several levels of patterns. As my type `B` has 50 constructors,
each level of pattern matching generates **a lot** of subgoals and slows down
the proofs.

Is there a simple way to say that if `is_valid a = true` then all the possible
cases are only the ones of the main pattern matching, without having to break all
sub-levels of matching using `congruence` everywhere ? Just doing an `unfold` of
the `is_valid` function takes ~2 min on my computer. The dream would be that
`is_valid a = true -> P` could be split into the few subgoals of the form `.. /\
(f b1 b2 b3) -> P /\ ...`

Thank you for your help !
Clément

PS: I could write a big theorem saying that for any property P, but I'm
looking for an automated way of doing it

Require Import Init.Byte.

Definition is_valid b :=
  match b with
  | x00 | xff => true
  | _ => false (* 254 cases hidden in this _ *)
  end.

Lemma some_lemma : forall b, is_valid b = true -> b = x00 \/ b = xff.
Proof.
  intros b v;destruct b;try discriminate v. (* 254 cases discriminated away *)
  - left;reflexivity.
  - right;reflexivity.
Qed.

Inductive is_valid' : byte -> Prop :=
| valid00 : is_valid' x00
| validff : is_valid' xff
.

Lemma some_lemma' : forall b, is_valid' b -> b = x00 \/ b = xff.
Proof.
  intros b v;destruct v.
  - left;reflexivity.
  - right;reflexivity.
Qed.

(* If you want to recover decidability of validity you still can
   (here by hand, or you can use some ssr stuff for decidable properties) *)
Definition valid'_checker (b:byte) : { v:bool | v=true <-> is_valid' b}.
Proof.
  destruct b;try (exists true; split; intros _;constructor).
  (* 254 remaining cases *)
  all: exists false;split;[discriminate|intros v;inversion v].
 (* note that each inversion builds a 2-cases match *)
Defined.



Archive powered by MHonArc 2.6.19+.

Top of Page