(** The termination argument is [before_witness n], which says that
any number before any witness (not necessarily the [x] of [exists x :A, P x])
makes the search eventually stops. *)

Inductive before_witness (n:nat) : Prop :=
  | stop : P n -> before_witness n
  | next : before_witness (S n) -> before_witness n.(** The termination argument is [before_witness n], which says that
any number before any witness (not necessarily the [x] of [exists x :A, P x])
makes the search eventually stops. *)

Inductive before_witness (n:nat) : Prop :=
  | stop : P n -> before_witness n
  | next : before_witness (S n) -> before_witness n.(** The termination argument is [before_witness n], which says that
any number before any witness (not necessarily the [x] of [exists x :A, P x])
makes the search eventually stops. *)

Inductive before_witness (n:nat) : Prop :=
  | stop : P n -> before_witness n
  | next : before_witness (S n) -> before_witness n.(* Computation of the initial termination certificate *)
Fixpoint O_witness (n : nat) : before_witness n -> before_witness 0 :=
  match n return (before_witness n -> before_witness 0) with
    | 0 => fun b => b
    | S n => fun b => O_witness n (next n b)
  end.(* Inversion of [inv_before_witness n] in a way such that the result
is structurally smaller even in the [stop] case. *)
Definition inv_before_witness :
  forall n, before_witness n -> ~(P n) -> before_witness (S n) :=
  fun n b not_p =>
    match b with
      | stop _ p => match not_p p with end
      | next _ b => b
    end.(** Basic program *)
Fixpoint prog_linear_search start (b : before_witness start) : nat :=
  match P_dec start with
    | left yes => start
    | right no => prog_linear_search (S start) (inv_before_witness start b no)
  end.(** rel_ls = relational version of linear search *)
Inductive rel_ls : nat -> nat -> Prop :=
| Rstop : forall {found}, P found -> rel_ls found found
| Rnext : forall {start found}, ~(P start) -> rel_ls (S start) found -> rel_ls start found.(** rel_ls = relational version of linear search *)
Inductive rel_ls : nat -> nat -> Prop :=
| Rstop : forall {found}, P found -> rel_ls found found
| Rnext : forall {start found}, ~(P start) -> rel_ls (S start) found -> rel_ls start found.(** rel_ls = relational version of linear search *)
Inductive rel_ls : nat -> nat -> Prop :=
| Rstop : forall {found}, P found -> rel_ls found found
| Rnext : forall {start found}, ~(P start) -> rel_ls (S start) found -> rel_ls start found.(** Following the Braga method, the output is packed with a proof of its conformity wrt rel_ls *)
Definition linear_search_conform start (b : before_witness start) : {n : nat | rel_ls start n}.(** A variant where the computational contents is closer to [prog_linear_search]
    (no deconstruction/reconstruction of the result), using a suitable
    abstraction of the postcondition.
    The predicate [rel_ls start] is abstracted into [Q], with an additional
    implication [rq] they are equivalent (but only one direction is needed);
    and as linear search is tail recursive, [Q] can be fixed (but [rq] varies,
    behaving like a logical continuation). *)
Definition linear_search_conform_alt start (b : before_witness start) : {n : nat | rel_ls start n}.(** Start at 0 *)
Definition linear_search_from_0_conform (e : exists n, P n) : {n:nat | rel_ls 0 n} :=
    let b := let (n, p) := e in O_witness n (stop n p) in
    linear_search_conform 0 b.

(* Specifications: *)
Theorem rel_ls_post : forall {start found}, rel_ls start found -> P found.
Lemma rel_ls_lower_bound {found start} : rel_ls start found -> forall {k}, P k -> start <= k -> found <= k.