(**
 List notations for wider connectives; the Prop connectives have a fixed
 width so as to avoid iterated destruction (we go up to width 5 for /\, and
 width 4 for or). The bool connectives have arbitrary widths, but denote
 expressions that associate to the RIGHT. This is consistent with the right
 associativity of list expressions and thus more convenient in most proofs.  **)

Inductive and3 (P1 P2 P3 : Prop) : Prop := And3 of P1 & P2 & P3.(**
 List notations for wider connectives; the Prop connectives have a fixed
 width so as to avoid iterated destruction (we go up to width 5 for /\, and
 width 4 for or). The bool connectives have arbitrary widths, but denote
 expressions that associate to the RIGHT. This is consistent with the right
 associativity of list expressions and thus more convenient in most proofs.  **)

Inductive and3 (P1 P2 P3 : Prop) : Prop := And3 of P1 & P2 & P3.Inductive and4 (P1 P2 P3 P4 : Prop) : Prop := And4 of P1 & P2 & P3 & P4.Inductive and4 (P1 P2 P3 P4 : Prop) : Prop := And4 of P1 & P2 & P3 & P4.Inductive and5 (P1 P2 P3 P4 P5 : Prop) : Prop :=
  And5 of P1 & P2 & P3 & P4 & P5.Inductive and5 (P1 P2 P3 P4 P5 : Prop) : Prop :=
  And5 of P1 & P2 & P3 & P4 & P5.Inductive or3 (P1 P2 P3 : Prop) : Prop := Or31 of P1 | Or32 of P2 | Or33 of P3.Inductive or3 (P1 P2 P3 : Prop) : Prop := Or31 of P1 | Or32 of P2 | Or33 of P3.Inductive or3 (P1 P2 P3 : Prop) : Prop := Or31 of P1 | Or32 of P2 | Or33 of P3.Inductive or3 (P1 P2 P3 : Prop) : Prop := Or31 of P1 | Or32 of P2 | Or33 of P3.Inductive or4 (P1 P2 P3 P4 : Prop) : Prop :=
  Or41 of P1 | Or42 of P2 | Or43 of P3 | Or44 of P4.Inductive or4 (P1 P2 P3 P4 : Prop) : Prop :=
  Or41 of P1 | Or42 of P2 | Or43 of P3 | Or44 of P4.Inductive or4 (P1 P2 P3 P4 : Prop) : Prop :=
  Or41 of P1 | Or42 of P2 | Or43 of P3 | Or44 of P4.Inductive or4 (P1 P2 P3 P4 : Prop) : Prop :=
  Or41 of P1 | Or42 of P2 | Or43 of P3 | Or44 of P4.Inductive or4 (P1 P2 P3 P4 : Prop) : Prop :=
  Or41 of P1 | Or42 of P2 | Or43 of P3 | Or44 of P4.Notation "[ /\ P1 & P2 ]" := (and P1 P2) (only parsing) : type_scope.Notation "[ /\ P1 , P2 & P3 ]" := (and3 P1 P2 P3) : type_scope.Notation "[ /\ P1 , P2 , P3 & P4 ]" := (and4 P1 P2 P3 P4) : type_scope.Notation "[ /\ P1 , P2 , P3 , P4 & P5 ]" := (and5 P1 P2 P3 P4 P5) : type_scope.Notation "[ \/ P1 | P2 ]" := (or P1 P2) (only parsing) : type_scope.Notation "[ \/ P1 , P2 | P3 ]" := (or3 P1 P2 P3) : type_scope.Notation "[ \/ P1 , P2 , P3 | P4 ]" := (or4 P1 P2 P3 P4) : type_scope.Notation "[ && b1 & c ]" := (b1 && c) (only parsing) : bool_scope.Notation "[ && b1 , b2 , .. , bn & c ]" := (b1 && (b2 && .. (bn && c) .. ))
  : bool_scope.Notation "[ || b1 | c ]" := (b1 || c) (only parsing) : bool_scope.Notation "[ || b1 , b2 , .. , bn | c ]" := (b1 || (b2 || .. (bn || c) .. ))
  : bool_scope.Notation "[ ==> b1 , b2 , .. , bn => c ]" :=
   (b1 ==> (b2 ==> .. (bn ==> c) .. )) : bool_scope.Notation "[ ==> b1 => c ]" := (b1 ==> c) (only parsing) : bool_scope.Local Notation a P := (forall x, P x).

(* Specifications: *)
Lemma all_and2 : implies (forall x, [/\ P1 x & P2 x]) [/\ a P1 & a P2].
Lemma all_and3 : implies (forall x, [/\ P1 x, P2 x & P3 x]) [/\ a P1, a P2 & a P3].
Lemma all_and4 : implies (forall x, [/\ P1 x, P2 x, P3 x & P4 x]) [/\ a P1, a P2, a P3 & a P4].
Lemma all_and5 : implies (forall x, [/\ P1 x, P2 x, P3 x, P4 x & P5 x]) [/\ a P1, a P2, a P3, a P4 & a P5].
Lemma pair_andP P Q : P /\ Q <-> P * Q.
Lemma idP : reflect b1 b1.
Lemma boolP : alt_spec b1 b1 b1.
Lemma idPn : reflect (~~ b1) (~~ b1).
Lemma negP : reflect (~ b1) (~~ b1).
Lemma negPn : reflect b1 (~~ ~~ b1).
Lemma negPf : reflect (b1 = false) (~~ b1).
Lemma andP : reflect (b1 /\ b2) (b1 && b2).
Lemma and3P : reflect [/\ b1, b2 & b3] [&& b1, b2 & b3].
Lemma and4P : reflect [/\ b1, b2, b3 & b4] [&& b1, b2, b3 & b4].
Lemma and5P : reflect [/\ b1, b2, b3, b4 & b5] [&& b1, b2, b3, b4 & b5].
Lemma orP : reflect (b1 \/ b2) (b1 || b2).
Lemma or3P : reflect [\/ b1, b2 | b3] [|| b1, b2 | b3].
Lemma or4P : reflect [\/ b1, b2, b3 | b4] [|| b1, b2, b3 | b4].
Lemma nandP : reflect (~~ b1 \/ ~~ b2) (~~ (b1 && b2)).
Lemma norP : reflect (~~ b1 /\ ~~ b2) (~~ (b1 || b2)).
Lemma implyP : reflect (b1 -> b2) (b1 ==> b2).
Lemma negPP : reflect (~ P) (~~ p).
Lemma andPP : reflect (P /\ Q) (p && q).
Lemma orPP : reflect (P \/ Q) (p || q).
Lemma implyPP : reflect (P -> Q) (p ==> q).
Lemma andTb : left_id true andb.
Lemma andFb : left_zero false andb.
Lemma andbT : right_id true andb.
Lemma andbF : right_zero false andb.
Lemma andbb : idempotent andb.
Lemma andbC : commutative andb.
Lemma andbA : associative andb.
Lemma andbCA : left_commutative andb.
Lemma andbAC : right_commutative andb.
Lemma andbACA : interchange andb andb.
Lemma orTb : forall b, true || b.
Lemma orFb : left_id false orb.
Lemma orbT : forall b, b || true.
Lemma orbF : right_id false orb.
Lemma orbb : idempotent orb.
Lemma orbC : commutative orb.
Lemma orbA : associative orb.
Lemma orbCA : left_commutative orb.
Lemma orbAC : right_commutative orb.
Lemma orbACA : interchange orb orb.
Lemma andbN b : b && ~~ b = false.
Lemma andNb b : ~~ b && b = false.
Lemma orbN b : b || ~~ b = true.
Lemma orNb b : ~~ b || b = true.
Lemma andb_orl : left_distributive andb orb.
Lemma andb_orr : right_distributive andb orb.
Lemma orb_andl : left_distributive orb andb.
Lemma orb_andr : right_distributive orb andb.
Lemma andb_idl (a b : bool) : (b -> a) -> a && b = b.
Lemma andb_idr (a b : bool) : (a -> b) -> a && b = a.
Lemma andb_id2l (a b c : bool) : (a -> b = c) -> a && b = a && c.
Lemma andb_id2r (a b c : bool) : (b -> a = c) -> a && b = c && b.
Lemma orb_idl (a b : bool) : (a -> b) -> a || b = b.
Lemma orb_idr (a b : bool) : (b -> a) -> a || b = a.
Lemma orb_id2l (a b c : bool) : (~~ a -> b = c) -> a || b = a || c.
Lemma orb_id2r (a b c : bool) : (~~ b -> a = c) -> a || b = c || b.
Lemma negb_and (a b : bool) : ~~ (a && b) = ~~ a || ~~ b.
Lemma negb_or (a b : bool) : ~~ (a || b) = ~~ a && ~~ b.
Lemma andbK a b : a && b || a = a.
Lemma andKb a b : a || b && a = a.
Lemma orbK a b : (a || b) && a = a.
Lemma orKb a b : a && (b || a) = a.
Lemma implybT b : b ==> true.
Lemma implybF b : (b ==> false) = ~~ b.
Lemma implyFb b : false ==> b.
Lemma implyTb b : (true ==> b) = b.
Lemma implybb b : b ==> b.
Lemma negb_imply a b : ~~ (a ==> b) = a && ~~ b.
Lemma implybE a b : (a ==> b) = ~~ a || b.
Lemma implyNb a b : (~~ a ==> b) = a || b.
Lemma implybN a b : (a ==> ~~ b) = (b ==> ~~ a).
Lemma implybNN a b : (~~ a ==> ~~ b) = b ==> a.
Lemma implyb_idl (a b : bool) : (~~ a -> b) -> (a ==> b) = b.
Lemma implyb_idr (a b : bool) : (b -> ~~ a) -> (a ==> b) = ~~ a.
Lemma implyb_id2l (a b c : bool) : (a -> b = c) -> (a ==> b) = (a ==> c).
Lemma addFb : left_id false addb.
Lemma addbF : right_id false addb.
Lemma addbb : self_inverse false addb.
Lemma addbC : commutative addb.
Lemma addbA : associative addb.
Lemma addbCA : left_commutative addb.
Lemma addbAC : right_commutative addb.
Lemma addbACA : interchange addb addb.
Lemma andb_addl : left_distributive andb addb.
Lemma andb_addr : right_distributive andb addb.
Lemma addKb : left_loop id addb.
Lemma addbK : right_loop id addb.
Lemma addIb : left_injective addb.
Lemma addbI : right_injective addb.
Lemma addTb b : true (+) b = ~~ b.
Lemma addbT b : b (+) true = ~~ b.
Lemma addbN a b : a (+) ~~ b = ~~ (a (+) b).
Lemma addNb a b : ~~ a (+) b = ~~ (a (+) b).
Lemma addbP a b : reflect (~~ a = b) (a (+) b).