(**
 Resolution tactic for blindly weeding out common terms from boolean
 equalities. When faced with a goal of the form (andb/orb/addb b1 b2) = b3
 they will try to locate b1 in b3 and remove it. This can fail!             **)

Ltac bool_congr :=
  match goal with
  | |- (?X1 && ?X2 = ?X3) => first
  [ symmetry; rewrite -1?(andbC X1) -?(andbCA X1); congr 1 (andb X1); symmetry
  | case: (X1); [ rewrite ?andTb ?andbT // | by rewrite ?andbF /= ] ]
  | |- (?X1 || ?X2 = ?X3) => first
  [ symmetry; rewrite -1?(orbC X1) -?(orbCA X1); congr 1 (orb X1); symmetry
  | case: (X1); [ by rewrite ?orbT //= | rewrite ?orFb ?orbF ] ]
  | |- (?X1 (+) ?X2 = ?X3) =>
    symmetry; rewrite -1?(addbC X1) -?(addbCA X1); congr 1 (addb X1); symmetry
  | |- (~~ ?X1 = ?X2) => congr 1 negb
  end.(**
 Predicates, i.e., packaged functions to bool.
 - pred T, the basic type for predicates over a type T, is simply an alias
 for T -> bool.
 We actually distinguish two kinds of predicates, which we call applicative
 and collective, based on the syntax used to test them at some x in T:
 - For an applicative predicate P, one uses prefix syntax:
     P x
   Also, most operations on applicative predicates use prefix syntax as
   well (e.g., predI P Q).
 - For a collective predicate A, one uses infix syntax:
     x \in A
   and all operations on collective predicates use infix syntax as well
   (e.g., #[#predI A & B#]#).
 There are only two kinds of applicative predicates:
 - pred T, the alias for T -> bool mentioned above
 - simpl_pred T, an alias for simpl_fun T bool with a coercion to pred T
   that auto-simplifies on application (see ssrfun).
 On the other hand, the set of collective predicate types is open-ended via
 - predType T, a Structure that can be used to put Canonical collective
   predicate interpretation on other types, such as lists, tuples,
   finite sets, etc.
 Indeed, we define such interpretations for applicative predicate types,
 which can therefore also be used with the infix syntax, e.g.,
     x \in predI P Q
 Moreover these infix forms are convertible to their prefix counterpart
 (e.g., predI P Q x which in turn simplifies to P x && Q x). The converse
 is not true, however; collective predicate types cannot, in general, be
 used applicatively, because of restrictions on implicit coercions.
   However, we do define an explicit generic coercion
 - mem : forall (pT : predType), pT -> mem_pred T
   where mem_pred T is a variant of simpl_pred T that preserves the infix
   syntax, i.e., mem A x auto-simplifies to x \in A.
 Indeed, the infix "collective" operators are notation for a prefix
 operator with arguments of type mem_pred T or pred T, applied to coerced
 collective predicates, e.g.,
      Notation "x \in A" := (in_mem x (mem A)).
 This prevents the variability in the predicate type from interfering with
 the application of generic lemmas. Moreover this also makes it much easier
 to define generic lemmas, because the simplest type -- pred T -- can be
 used as the type of generic collective predicates, provided one takes care
 not to use it applicatively; this avoids the burden of having to declare a
 different predicate type for each predicate parameter of each section or
 lemma.
   In detail, we ensure that the head normal form of mem A is always of the
 eta-long MemPred (fun x => pA x) form, where pA is the pred interpretation of
 A following its predType pT, i.e., the _expansion_ of topred A. For a pred T
 evar ?P, (mem ?P) converts MemPred (fun x => ?P x), whose argument is a Miller
 pattern and therefore always unify: unifying (mem A) with (mem ?P) always
 yields ?P = pA, because the rigid constant MemPred aligns the unification.
 Furthermore, we ensure pA is always either A or toP .... A where toP ... is
 the expansion of @topred T pT, and toP is declared as a Coercion, so pA will
 _display_ as A in either case, and the instances of @mem T (predPredType T) pA
 appearing in the premises or right-hand side of a generic lemma parameterized
 by ?P will be indistinguishable from @mem T pT A.
   Users should take care not to inadvertently "strip" (mem A) down to the
 coerced A, since this will expose the internal toP coercion: Coq could then
 display terms A x that cannot be typed as such. The topredE lemma can be used
 to restore the x \in A syntax in this case. While -topredE can conversely be
 used to change x \in P into P x for an applicative P, it is safer to use the
 inE, unfold_in or and memE lemmas instead, as they do not run the risk of
 exposing internal coercions. As a consequence it is better to explicitly
 cast a generic applicative predicate to simpl_pred using the SimplPred
 constructor when it is used as a collective predicate (see, e.g.,
 Lemma eq_big in bigop).
   We also sometimes "instantiate" the predType structure by defining a
 coercion to the sort of the predPredType structure, conveniently denoted
 {pred T}. This works better for types such as {set T} that have subtypes that
 coerce to them, since the same coercion will be inserted by the application
 of mem, or of any lemma that expects a generic collective predicates with
 type {pred T} := pred_sort (predPredType T) = pred T; thus {pred T} should be
 the preferred type for generic collective predicate parameters.
   This device also lets us turn any Type aT : predArgType into the total
 predicate over that type, i.e., fun _: aT => true. This allows us to write,
 e.g., ##|'I_n| for the cardinal of the (finite) type of integers less than n.
 **)

(** Boolean predicates. *)

Definition pred T := T -> bool.Identity Coercion fun_of_pred : pred >-> Funclass.Definition subpred T (p1 p2 : pred T) := forall x : T, p1 x -> p2 x.(* Notation for some manifest predicates. *)

Notation xpred0 := (fun=> false).Notation xpredT := (fun=> true).Notation xpredI := (fun (p1 p2 : pred _) x => p1 x && p2 x).Notation xpredU := (fun (p1 p2 : pred _) x => p1 x || p2 x).Notation xpredC := (fun (p : pred _) x => ~~ p x).Notation xpredD := (fun (p1 p2 : pred _) x => ~~ p2 x && p1 x).Notation xpreim := (fun f (p : pred _) x => p (f x)).(** The packed class interface for pred-like types. **)

Structure predType T :=
   PredType {pred_sort :> Type; topred : pred_sort -> pred T}.(** The packed class interface for pred-like types. **)

Structure predType T :=
   PredType {pred_sort :> Type; topred : pred_sort -> pred T}.(** The packed class interface for pred-like types. **)

Structure predType T :=
   PredType {pred_sort :> Type; topred : pred_sort -> pred T}.(** The packed class interface for pred-like types. **)

Structure predType T :=
   PredType {pred_sort :> Type; topred : pred_sort -> pred T}.Definition clone_pred T U :=
  fun pT & @pred_sort T pT -> U =>
  fun toP (pT' := @PredType T U toP) & phant_id pT' pT => pT'.Notation "[ 'predType' 'of' T ]" := (@clone_pred _ T _ id _ id) : form_scope.Canonical predPredType T := PredType (@id (pred T)).Canonical boolfunPredType T := PredType (@id (T -> bool)).(** The type of abstract collective predicates.
 While {pred T} is convertible to pred T, it presents the pred_sort coercion
 class, which crucially does _not_ coerce to Funclass. Term whose type P coerces
 to {pred T} cannot be applied to arguments, but they _can_ be used as if P
 had a canonical predType instance, as the coercion will be inserted if the
 unification P =~= pred_sort ?pT fails, changing the problem into the trivial
 {pred T} =~= pred_sort ?pT (solution ?pT := predPredType P).
   Additional benefits of this approach are that any type coercing to P will
 also inherit this behaviour, and that the coercion will be apparent in the
 elaborated expression. The latter may be important if the coercion is also
 a canonical structure projector - see mathcomp/fingroup/fingroup.v. The
 main drawback of implementing predType by coercion in this way is that the
 type of the value must be known when the unification constraint is imposed:
 if we only register the constraint and then later discover later that the
 expression had type P it will be too late to insert a coercion, whereas a
 canonical instance of predType for P would have solved the deferred constraint.
   Finally, definitions, lemmas and sections should use type {pred T} for
 their generic collective type parameters, as this will make it possible to
 apply such definitions and lemmas directly to values of types that implement
 predType by coercion to {pred T} (values of types that implement predType
 without coercing to {pred T} will have to be coerced explicitly using topred).
**)
Notation "{ 'pred' T }" := (pred_sort (predPredType T)) : type_scope.(** The type of self-simplifying collective predicates. **)
Definition simpl_pred T := simpl_fun T bool.Definition SimplPred {T} (p : pred T) : simpl_pred T := SimplFun p.(** Some simpl_pred constructors. **)

Definition pred0 {T} := @SimplPred T xpred0.Definition predT {T} := @SimplPred T xpredT.Definition predI {T} (p1 p2 : pred T) := SimplPred (xpredI p1 p2).Definition predU {T} (p1 p2 : pred T) := SimplPred (xpredU p1 p2).Definition predC {T} (p : pred T) := SimplPred (xpredC p).Definition predD {T} (p1 p2 : pred T) := SimplPred (xpredD p1 p2).Definition preim {aT rT} (f : aT -> rT) (d : pred rT) := SimplPred (xpreim f d).Notation "[ 'pred' : T | E ]" := (SimplPred (fun _ : T => E%B)) :
  function_scope.Notation "[ 'pred' x | E ]" := (SimplPred (fun x => E%B)) : function_scope.Notation "[ 'pred' x | E1 & E2 ]" := [pred x | E1 && E2 ] : function_scope.Notation "[ 'pred' x : T | E ]" :=
  (SimplPred (fun x : T => E%B)) (only parsing) : function_scope.Notation "[ 'pred' x : T | E1 & E2 ]" :=
  [pred x : T | E1 && E2 ] (only parsing) : function_scope.Definition coerce T (sp : simpl_pred T) : pred T := fun_of_simpl sp.Notation pred_of_simpl := PredOfSimpl.coerce.Canonical simplPredType T := PredType (@pred_of_simpl T).Module Export PredSortOfSimplCoercion := DeclarePredSortOfSimpl PredOfSimpl.(** Type to pred coercion.
   This lets us use types of sort predArgType as a synonym for their universal
 predicate. We define this predicate as a simpl_pred T rather than a pred T or
 a {pred T} so that /= and inE reduce (T x) and x \in T to true, respectively.
   Unfortunately, this can't be used for existing types like bool whose sort
 is already fixed (at least, not without redefining bool, true, false and
 all bool operations and lemmas); we provide syntax to recast a given type
 in predArgType as a workaround. **)
Definition predArgType := Type.Identity Coercion sort_of_predArgType : predArgType >-> Sortclass.Coercion pred_of_argType (T : predArgType) : simpl_pred T := predT.Notation "{ : T }" := (T%type : predArgType) : type_scope.(** Boolean relations.
 Simplifying relations follow the coding pattern of 2-argument simplifying
 functions: the simplifying type constructor is applied to the _last_
 argument. This design choice will let the in_simpl component of inE expand
 membership in simpl_rel as well. We provide an explicit coercion to rel T
 to avoid eta-expansion during coercion; this coercion self-simplifies so it
 should be invisible.
 **)

Definition rel T := T -> pred T.Identity Coercion fun_of_rel : rel >-> Funclass.Definition subrel T (r1 r2 : rel T) := forall x y : T, r1 x y -> r2 x y.Definition simpl_rel T := T -> simpl_pred T.Coercion rel_of_simpl T (sr : simpl_rel T) : rel T := fun x : T => sr x.Notation xrelU := (fun (r1 r2 : rel _) x y => r1 x y || r2 x y).Notation xrelpre := (fun f (r : rel _) x y => r (f x) (f y)).Definition SimplRel {T} (r : rel T) : simpl_rel T := fun x => SimplPred (r x).Definition relU {T} (r1 r2 : rel T) := SimplRel (xrelU r1 r2).Definition relpre {aT rT} (f : aT -> rT) (r : rel rT) := SimplRel (xrelpre f r).Notation "[ 'rel' x y | E ]" := (SimplRel (fun x y => E%B))
  (only parsing) : function_scope.Notation "[ 'rel' x y : T | E ]" :=
  (SimplRel (fun x y : T => E%B)) (only parsing) : function_scope.

(* Specifications: *)
Lemma subrelUl T (r1 r2 : rel T) : subrel r1 (relU r1 r2).
Lemma subrelUr T (r1 r2 : rel T) : subrel r2 (relU r1 r2).