MathClasses.misc.decision

Require Import
  canonical_names util.

Class Decision P := decide: sumbool P (¬P).
Arguments decide _ {Decision}.

Instance: P, Decision P Stable P.
Proof. firstorder. Qed.

Ltac case_decide := match goal with
  | H : context [@decide ?P ?dec] |- _case (@decide P dec) in ×
  | |- context [@decide ?P ?dec] ⇒ case (@decide P dec) in ×
  end.

Ltac solve_trivial_decision :=
  match goal with
  | [ |- Decision (?P) ] ⇒ apply _
  | [ |- sumbool ?P (¬?P) ] ⇒ change (Decision P); apply _
  end.

Ltac solve_decision :=
  first [solve_trivial_decision | unfold Decision; decide equality; solve_trivial_decision].

Program Instance decision_proper (P Q : Prop) (PiffQ : P Q) (P_dec : Decision P) : Decision Q :=
  match P_dec with
  | left _left _
  | right _right _
  end.
Solve Obligations using (program_simpl; tauto).

Definition bool_decide (P : Prop) `{dec : !Decision P} : bool := if dec then true else false.

Lemma bool_decide_true `{dec : Decision P} : bool_decide P true P.
Proof. unfold bool_decide. split; intro; destruct dec; firstorder. Qed.

Lemma bool_decide_false `{dec : !Decision P} : bool_decide P false ¬P.
Proof. unfold bool_decide. split; intro; destruct dec; firstorder. Qed.


Definition decide_rel `(R : A B Prop) {dec : x y, Decision (R x y)} (x : A) (y : B) : Decision (R x y)
  := dec x y.

Definition bool_decide_rel `(R : relation A) {dec : x y, Decision (R x y)} : A A bool
  := λ x y, if dec x y then true else false.

Lemma bool_decide_rel_true `(R : relation A) {dec : x y, Decision (R x y)} :
   x y, bool_decide_rel R x y true R x y.
Proof. unfold bool_decide_rel. split; intro; destruct dec; firstorder. Qed.

Lemma bool_decide_rel_false `(R : relation A)`{dec : x y, Decision (R x y)} :
   x y, bool_decide_rel R x y false ¬R x y.
Proof. unfold bool_decide_rel. split; intro; destruct dec; firstorder. Qed.

Program Definition decision_from_bool_decide {P b} (prf : b true P) :
  Decision P := match b with trueleft _ | falseright _ end.
Next Obligation. now apply prf. Qed.
Next Obligation. rewrite <-prf. discriminate. Qed.

Program Instance prod_eq_dec `(A_dec : x y : A, Decision (x y))
     `(B_dec : x y : B, Decision (x y)) : x y : A × B, Decision (x y) := λ x y,
  match A_dec (fst x) (fst y) with
  | left _match B_dec (snd x) (snd y) with left _left _ | right _right _ end
  | right _right _
  end.
Solve Obligations using (program_simpl; f_equal; firstorder).

Program Instance and_dec `(P_dec : Decision P) `(Q_dec : Decision Q) : Decision (P Q) :=
  match P_dec with
  | left _match Q_dec with left _left _ | right _right _ end
  | right _right _
  end.
Solve Obligations using (program_simpl; tauto).

Program Instance or_dec `(P_dec : Decision P) `(Q_dec : Decision Q) : Decision (P Q) :=
  match P_dec with
  | left _left _
  | right _match Q_dec with left _left _ | right _right _ end
  end.
Solve Obligations using (program_simpl; firstorder).

Program Instance is_Some_dec `(x : option A) : Decision (is_Some x) :=
  match x with
  | Noneright _
  | Some _left _
  end.

Program Instance is_None_dec `(x : option A) : Decision (is_None x) :=
  match x with
  | Noneleft _
  | Some _right _
  end.

Program Instance option_eq_dec `(A_dec : x y : A, Decision (x y))
     : x y : option A, Decision (x y) := λ x y,
  match x with
  | Some r
    match y with
    | Some smatch A_dec r s with left _left _ | right _right _ end
    | Noneright _
    end
  | None
    match y with
    | Some sright _
    | Noneleft _
    end
  end.

Program Instance True_dec: Decision True := left _.
Program Instance False_dec: Decision False := right _.