Set Implicit Arguments.
Unset Strict Implicit.
From Undecidability.HOU Require Import std.decidable std.lists.basics std.lists.advanced std.tactics.
Notation "( A × B × .. × C )" :=
(list_prod .. (list_prod A B) .. C) (at level 0, left associativity).
Notation "[ s | p ∈ A ',' P ]" :=
(map (fun p => s) (filter (fun p => decb P) A)) (p pattern).
Notation "[ s | p ∈ A ]" :=
(map (fun p => s) A) (p pattern).
Notation "[ s 'where' H ':' P ]" := (match dec P with
| left H => s :: nil
| right _ => nil
end) (H pattern).
Notation "[ s | p ∈ A 'where' H ':' P ]" :=
(flat_map (fun p => [s where H : P]) A) (p pattern, H pattern).
Notation "[ s | p ∈ A '&' q ∈ B ]" :=
(flat_map (fun q => map (fun p => s) A) B) (p pattern, q pattern).
Notation "[ s | p ∈ A '&' q ∈ B 'where' H ':' P ]" :=
(flat_map (fun q => map (fun p => [s where H : P]) A) B) (p pattern, q pattern).
Ltac in_collect a :=
eapply in_map_iff; exists a; split; [ eauto | match goal with [ |- _ ∈ filter _ _ ] =>  eapply filter_In; split; [ try (rewrite !in_prod_iff; repeat split) | repeat split; eauto ] | _ => try (rewrite !in_prod_iff; repeat split) end ].
Ltac in_app n :=
(match goal with
| [ |- _ ∈ _ ++ _ ] =>
match n with
| 0 => idtac
| 1 => eapply in_app_iff; left
| S ?n => eapply in_app_iff; right; in_app n
end
| [ |- _ ∈  _ :: _ ] => match n with 0 => idtac | 1 => left | S ?n => right; in_app n end
end) || (repeat (try right; eapply in_app_iff; right)).
Ltac inv_collect :=
repeat
(match goal with
| [ H : ?x ∈ concat _ |- _ ] => eapply in_concat_iff in H as (? & ? & ?)
| [ H : ?x ∈ map _ _ |- _ ] => let x := fresh "x" in eapply in_map_iff in H as (x & ? & ?)
| [ x : ?A * ?B |- _ ] => destruct x; subst
| [ H : ?x ∈ filter _ _ |- _ ] => let H' := fresh "H" in eapply filter_In in H as (? & H')
| [ H : ?x ∈ list_prod _ _ |- _ ] => eapply in_prod_iff in H
| [ H : _ ∈ _ ++ _ |- _ ] => try eapply in_app_iff in H as []
| [H : _ ∈ _ :: _ |- _ ] => destruct H
end; intuition; subst).
Hint Extern 4 =>
match goal with
|[ H: False |- _ ] => destruct H
|[ H: true=false |- _ ] => discriminate H
|[ H: false=true |- _ ] => discriminate H
end : core.
Definition enumerable {X} (p : X -> Prop) := exists f, forall x, p x <-> exists n : nat, f n = Some x.
Definition enumerable__T X := exists f : nat -> option X, forall x, exists n, f n = Some x.
Definition cumulative {X} (L: nat -> list X) :=
forall n, exists A, L (S n) = L n ++ A.
Hint Extern 0 (cumulative _) => intros ?; cbn; eauto : core.

Lemma cum_ge {X} (L: nat -> list X) n m :
cumulative L -> m >= n -> exists A, L m = L n ++ A.