From Coq Require Import Init.Nat Lia List.
From QuickChick Require Import QuickChick.
From mathcomp Require Import ssreflect eqtype ssrnat.
Import QcNotation. Import QcDefaultNotation.
Import ListNotations.
Set SsrOldRewriteGoalsOrder.  (* change Set to Unset when porting the file, then remove the line when requiring MathComp >= 2.6 *)

Require Import QuickChick.TacticsUtil ExtLib.Structures.Monads.
Open Scope monad_scope.
Open Scope qc_scope.
Open Scope nat_scope.

From Ltac2 Require Import Ltac2.

(* Inductive not_In {A: Type} : A -> list A -> Prop := *)
(* | In_nil: forall x, not_In x [] *)
(* | In_cons : forall x y l, *)
(*     x <> y -> not_In x l -> not_In x (y :: l).  *)

(* XXX Leo DEBUG params *)

(* This gives an unsound enum *)

(* Inductive not_In : nat -> list nat -> Prop := *)
(* | In_nil: forall x, not_In x [] *)
(* | In_cons : forall x y l, *)
(*     x <> y -> not_In x l -> not_In x (y :: l). *)

(* XXX Leo DEBUG *)

Inductive not_In : nat -> list nat -> Prop :=
| In_nil: forall x, not_In x []
| In_cons : forall x y l,
    not_In x l -> x <> y -> not_In x (y :: l).

QCDerive DecOpt for (not_In x l).


Instance not_In_SizeMonotonic x l : DecOptSizeMonotonic (not_In x l).
Proof. derive_mon (). Qed.

Instance not_In__sound x l : DecOptSoundPos (not_In x l).
Proof. derive_sound (). Qed.

Instance not_In_complete x l : DecOptCompletePos (not_In x l).
Proof. derive_complete (). Qed.
       

QCDerive EnumSizedSuchThat for (fun x => eq x n).

Instance EnumSizedSuchThateq_SizedMonotonic X {_ : Enum X} (n : X) :
  SizedMonotonicOpt (@enumSizeST _ _ (EnumSizedSuchThateq n)).
Proof. derive_enumST_SizedMonotonic (). Qed.

Instance EnumSizedSuchThateq_SizeMonotonic X `{_ : EnumMonotonic X} (n : X) :
  forall s, SizeMonotonicOpt (@enumSizeST _ _ (EnumSizedSuchThateq n) s).
Proof. derive_enumST_SizeMonotonic (). Qed.

Instance EnumSizedSuchThateq_Correct X `{_ : EnumMonotonicCorrect X} (n : X) :
  CorrectSizedST (fun m => eq n m) (@enumSizeST _ _ (EnumSizedSuchThateq n)).
Proof. derive_enumST_Correct (). Qed.

QCDerive EnumSizedSuchThat for (fun n => not_In n l).

Instance EnumSizedSuchThatnot_In_SizedMonotonic l :
  SizedMonotonicOpt (@enumSizeST _ _ (EnumSizedSuchThatnot_In l)).
Proof. derive_enumST_SizedMonotonic (). Qed.

Instance EnumSizedSuchThatnot_In_SizeMonotonic l :
    forall s, SizeMonotonicOpt (@enumSizeST _ _ (EnumSizedSuchThatnot_In l) s).
Proof. derive_enumST_SizeMonotonic (). Qed.


Instance EnumSizedSuchThatnot_In_Correct l :
    CorrectSizedST (fun n => not_In n l) (@enumSizeST _ _ (EnumSizedSuchThatnot_In l)).
Proof. derive_enumST_Correct (). Qed.
