Top

Module mathcomp.classical.contra

From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq.
From mathcomp Require Import boolp.

Set SsrOldRewriteGoalsOrder.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.

# Contraposition This file provides tactics to reason by contraposition and contradiction. ## Tactics ``` assume_not == add a goal negation assumption. The tactic also works for goals in Type, simplifies the added assumption, and exposes its top-level constructive content. absurd_not == proof by contradiction. Same as assume_not, but the goal is erased and replaced by False. Caveat: absurd_not cannot be used as a move/ view because its conclusion is indeterminate. The more general notP can be used instead. contra == proof by contraposition. Change a goal of the form assumption -> conclusion to ~ conclusion -> ~ assumption. As with assume_not, contra allows both assumption and conclusion to be in Type, simplifies the negation of both assumption and conclusion, and exposes the constructive contents of the negated conclusion. The contra tactic also supports a limited form of the ':' discharge pseudo tactical, whereby contra: <d-items> means move: <d-items>; contra. The only <d-items> allowed are one term, possibly preceded by a clear switch. absurd == proof by contradiction. The defective form of the tactic simply replaces the entire goal with False (just as the Ltac exfalso), leaving the user to derive a contradiction from the assumptions. The ':' form absurd: <d-items> replaces the goal with the negation of the (single) <d-item> (as with contra:, a clear switch is also allowed. Finally the Ltac absurd term form is also supported. ```

Hiding module for the internal definitions and lemmas used by the tactics defined here.
Module Internals.

A wrapper for view lemmas with an indeterminate conclusion (of the form forall ... T ..., pattern -> T), and for which the intended view pattern may fail to match some assumptions. This wrapper ensures that such views are only used in the forward direction (as in move/), and only with the appropriate move_viewP hint, preventing its application to an arbitrary assumption A by the instatiation to A -> T' of its indeterminate conclusion T. This is similar to the implies wrapper, except move_viewP is *NOT* declared as a coercion---it must be used explicitly to apply the view manually to an assumption (as in, move_viewP my_view some_assumption).

Variant move_view S T := MoveView of S -> T.
Definition
move_viewP

Internals.move_viewP : forall {S T : Type}, Internals.move_view S T -> S -> T Internals.move_viewP is not universe polymorphic Arguments Internals.move_viewP {S T}%_type_scope mv _ Internals.move_viewP is transparent Expands to: Constant mathcomp.classical.contra.Internals.move_viewP Declared in library mathcomp.classical.contra, line 64, characters 11-21

{S T} mv : S -> T := let: MoveView v := mv in v.
Hint View for move/ move_viewP|2.

## Type-level equivalence

Variant equivT S T := EquivT of S -> T & T -> S.

Definition
equivT_refl

Internals.equivT_refl : forall S : Type, Internals.equivT S S Internals.equivT_refl is not universe polymorphic Arguments Internals.equivT_refl S%_type_scope Internals.equivT_refl is transparent Expands to: Constant mathcomp.classical.contra.Internals.equivT_refl Declared in library mathcomp.classical.contra, line 73, characters 11-22

S : equivT S S := EquivT id id.
Definition
equivT_transl

Internals.equivT_transl : forall {S T U : Type}, Internals.equivT S T -> Internals.equivT S U -> Internals.equivT T U Internals.equivT_transl is not universe polymorphic Arguments Internals.equivT_transl {S T U}%_type_scope _ _ Internals.equivT_transl is transparent Expands to: Constant mathcomp.classical.contra.Internals.equivT_transl Declared in library mathcomp.classical.contra, line 74, characters 11-24

{S T U} : equivT S T -> equivT S U -> equivT T U :=
  fun (st : equivT S T) (su : equivT S U) =>
    let: EquivT S_T T_S := st in
    let: EquivT S_U U_S := su in
    EquivT (S_U \o T_S) (S_T \o U_S).
Definition
equivT_sym

Internals.equivT_sym : forall {S T : Type}, Internals.equivT S T -> Internals.equivT T S Internals.equivT_sym is not universe polymorphic Arguments Internals.equivT_sym {S T}%_type_scope _ Internals.equivT_sym is transparent Expands to: Constant mathcomp.classical.contra.Internals.equivT_sym Declared in library mathcomp.classical.contra, line 79, characters 11-21

{S T} : equivT S T -> equivT T S :=
   equivT_transl^~ (equivT_refl S).
Definition
equivT_trans

Internals.equivT_trans : forall {S T U : Type}, Internals.equivT S T -> Internals.equivT T U -> Internals.equivT S U Internals.equivT_trans is not universe polymorphic Arguments Internals.equivT_trans {S T U}%_type_scope _ _ Internals.equivT_trans is transparent Expands to: Constant mathcomp.classical.contra.Internals.equivT_trans Declared in library mathcomp.classical.contra, line 81, characters 11-23

{S T U} : equivT S T -> equivT T U -> equivT S U :=
   equivT_transl \o equivT_sym.
Definition
equivT_transr

Internals.equivT_transr : forall {S T U : Type}, Internals.equivT S T -> Internals.equivT U S -> Internals.equivT U T Internals.equivT_transr is not universe polymorphic Arguments Internals.equivT_transr {S T U}%_type_scope eqST _ Internals.equivT_transr is transparent Expands to: Constant mathcomp.classical.contra.Internals.equivT_transr Declared in library mathcomp.classical.contra, line 83, characters 11-24

{S T U} eqST : equivT U S -> equivT U T :=
   equivT_trans^~ eqST.
Definition
equivT_Prop

Internals.equivT_Prop : forall P Q : Prop, Internals.equivT P Q <-> Internals.equivT P Q Internals.equivT_Prop is not universe polymorphic Arguments Internals.equivT_Prop (P Q)%_type_scope Internals.equivT_Prop is transparent Expands to: Constant mathcomp.classical.contra.Internals.equivT_Prop Declared in library mathcomp.classical.contra, line 85, characters 11-22

(P Q : Prop) : (equivT P Q) <-> (equivT P Q).
Proof.
split; destruct 1; split; assumption. Defined.
Definition
equivT_LR

Internals.equivT_LR : forall {S T : Type}, Internals.equivT S T -> S -> T Internals.equivT_LR is not universe polymorphic Arguments Internals.equivT_LR {S T}%_type_scope eq _ Internals.equivT_LR is transparent Expands to: Constant mathcomp.classical.contra.Internals.equivT_LR Declared in library mathcomp.classical.contra, line 87, characters 11-20

{S T} (eq : equivT S T) : S -> T :=
  let: EquivT S_T _ := eq in S_T.
Definition
equivT_RL

Internals.equivT_RL : forall {S T : Type}, Internals.equivT S T -> T -> S Internals.equivT_RL is not universe polymorphic Arguments Internals.equivT_RL {S T}%_type_scope eq _ Internals.equivT_RL is transparent Expands to: Constant mathcomp.classical.contra.Internals.equivT_RL Declared in library mathcomp.classical.contra, line 89, characters 11-20

{S T} (eq : equivT S T) : T -> S :=
  let: EquivT _ T_S := eq in T_S.

Hint View for move/ equivT_LR|2 equivT_RL|2.
Hint View for apply/ equivT_RL|2 equivT_LR|2.

A generic Forall "constructor" for the Gallina forall quantifier, i.e., ``` \Forall x, P := Forall (fun x => P) := forall x, P. ``` The main use of Forall is to apply congruence to a forall equality: ``` congr1 Forall : forall P Q, P = Q -> Forall P = Forall Q. ``` in particular in a classical setting with function extensionality, where we can have (forall x, P x = Q x) -> (forall x, P x) = (forall x, Q x). We use a forallSort structure to factor the ad hoc PTS product formation rules; forallSort is keyed on the type of the entire forall expression, or (up to subsumption) the type of the forall body---this is always a sort. This implementation has two important limitations: 1. It cannot handle the SProp sort and its typing rules. However, its main application is extensionality, which is not compatible with SProp because an (A : SProp) -> B "function" is not a generic (A : Type) -> B function as SProp is not included in Type. 2. The Forall constructor can't be inserted by a straightforward unfold (as in, rewrite -[forall x, _]/(Forall _)) because of the way Coq unification handles Type constraints. The ForallI tactic mitigates this issue, but there are additional issues with its implementation---see below.

Structure forallSort A :=
  ForallSort {forall_sort :> Type; _ : (A -> forall_sort) -> forall_sort}.

Notation mkForallSort A S := (@ForallSort A S (fun T => forall x, T x)).
Polymorphic Definition
TypeForall

Internals.TypeForall@{u u0} : forall A : Type, Internals.forallSort A Internals.TypeForall is universe polymorphic Arguments Internals.TypeForall A%_type_scope Internals.TypeForall is transparent Expands to: Constant mathcomp.classical.contra.Internals.TypeForall Declared in library mathcomp.classical.contra, line 127, characters 23-33

(S := Type) (A : S) := mkForallSort A S.
Canonical TypeForall.

Canonical
PropForall

Internals.PropForall : forall A : Type, Internals.forallSort A Internals.PropForall is not universe polymorphic Arguments Internals.PropForall A%_type_scope Internals.PropForall is transparent Expands to: Constant mathcomp.classical.contra.Internals.PropForall Declared in library mathcomp.classical.contra, line 130, characters 10-20

A := mkForallSort A Prop.

Canonical
SetForall

Internals.SetForall : forall A : Set, Internals.forallSort A Internals.SetForall is not universe polymorphic Arguments Internals.SetForall A%_type_scope Internals.SetForall is transparent Expands to: Constant mathcomp.classical.contra.Internals.SetForall Declared in library mathcomp.classical.contra, line 134, characters 10-19

(A : Set) := mkForallSort A Set.

Definition
Forall

Internals.Forall : forall {A : Type} {S : Internals.forallSort A}, (A -> Internals.forall_sort S) -> Internals.forall_sort S Internals.Forall is not universe polymorphic Arguments Internals.Forall {A}%_type_scope {S} _%_function_scope Internals.Forall is transparent Expands to: Constant mathcomp.classical.contra.Internals.Forall Declared in library mathcomp.classical.contra, line 136, characters 11-17

{A} {S : forallSort A} :=
  let: ForallSort _ F := S return (A -> S) -> S in F.

Notation "\Forall x .. z , T" :=
   (Forall (fun x => .. (Forall (fun z => T)) ..))
  (at level 200, x binder, z binder, T at level 200,
   format "'[hv' '\Forall' '[' x .. z , ']' '/ ' T ']'") : type_scope.

Tactic Notation "ForallI" ssrpatternarg(pat) :=
  let F := fresh "F" in ssrmatching.ssrpattern pat => F;
  case: F / (@erefl _ F : Forall _ = _).
Tactic Notation "ForallI" := ForallI (forall x, _).

We define specialized copies of the wrapped structure of ssrfun for Prop and Type, as we need more than two alternative rules (indeed, 3 for Prop and 4 for Type). We need separate copies for Prop and Type as universe polymorphism cannot instantiate Type with Prop.

Structure wrappedProp := WrapProp {unwrap_Prop :> Prop}.
Definition
wrap4Prop

Internals.wrap4Prop : Prop -> Internals.wrappedProp Internals.wrap4Prop is not universe polymorphic Arguments Internals.wrap4Prop unwrap_Prop%_type_scope Internals.wrap4Prop is transparent Expands to: Constant mathcomp.classical.contra.Internals.wrap4Prop Declared in library mathcomp.classical.contra, line 172, characters 11-20

:= WrapProp.
Definition
wrap3Prop

Internals.wrap3Prop : Prop -> Internals.wrappedProp Internals.wrap3Prop is not universe polymorphic Arguments Internals.wrap3Prop unwrap_Prop%_type_scope Internals.wrap3Prop is transparent Expands to: Constant mathcomp.classical.contra.Internals.wrap3Prop Declared in library mathcomp.classical.contra, line 173, characters 11-20

:= wrap4Prop.
Definition
wrap2Prop

Internals.wrap2Prop : Prop -> Internals.wrappedProp Internals.wrap2Prop is not universe polymorphic Arguments Internals.wrap2Prop unwrap_Prop%_type_scope Internals.wrap2Prop is transparent Expands to: Constant mathcomp.classical.contra.Internals.wrap2Prop Declared in library mathcomp.classical.contra, line 174, characters 11-20

:= wrap3Prop.
Canonical
wrap1Prop

Internals.wrap1Prop : Prop -> Internals.wrappedProp Internals.wrap1Prop is not universe polymorphic Arguments Internals.wrap1Prop P%_type_scope Internals.wrap1Prop is transparent Expands to: Constant mathcomp.classical.contra.Internals.wrap1Prop Declared in library mathcomp.classical.contra, line 175, characters 10-19

P := wrap2Prop P.

Polymorphic Structure wrappedType@{i} := WrapType {unwrap_Type :> Type@{i}}.
Polymorphic Definition
wrap4Type

Internals.wrap4Type@{i} : Type -> Internals.wrappedType Internals.wrap4Type is universe polymorphic Arguments Internals.wrap4Type unwrap_Type%_type_scope Internals.wrap4Type is transparent Expands to: Constant mathcomp.classical.contra.Internals.wrap4Type Declared in library mathcomp.classical.contra, line 178, characters 23-32

@{i} := WrapType@{i}.
Polymorphic Definition
wrap3Type

Internals.wrap3Type@{i} : Type -> Internals.wrappedType Internals.wrap3Type is universe polymorphic Arguments Internals.wrap3Type unwrap_Type%_type_scope Internals.wrap3Type is transparent Expands to: Constant mathcomp.classical.contra.Internals.wrap3Type Declared in library mathcomp.classical.contra, line 179, characters 23-32

@{i} := wrap4Type@{i}.
Polymorphic Definition
wrap2Type

Internals.wrap2Type@{i} : Type -> Internals.wrappedType Internals.wrap2Type is universe polymorphic Arguments Internals.wrap2Type unwrap_Type%_type_scope Internals.wrap2Type is transparent Expands to: Constant mathcomp.classical.contra.Internals.wrap2Type Declared in library mathcomp.classical.contra, line 180, characters 23-32

@{i} := wrap3Type@{i}.
Polymorphic Definition
wrap1Type

Internals.wrap1Type@{i} : Type -> Internals.wrappedType Internals.wrap1Type is universe polymorphic Arguments Internals.wrap1Type T%_type_scope Internals.wrap1Type is transparent Expands to: Constant mathcomp.classical.contra.Internals.wrap1Type Declared in library mathcomp.classical.contra, line 181, characters 23-32

@{i} (T : Type@{i}) := wrap2Type T.
Canonical wrap1Type.

Lemma generic_forall_extensionality {A} {S : forallSort A} {P Q : A -> S} :
  P =1 Q -> Forall P = Forall Q.
Proof.
by move/funext->. Qed.

A set of tools (tactics, views, and rewrite rules) to facilitate the handling of classical negation. The core functionality of these tools is implemented by three sets of canonical structures that provide for the simplification of negation statements (e.g., using de Morgan laws), the conversion from constructive statements in Type to purely logical ones in Prop (equivalently, expansion rules for the statement inhabited T), and conversely extraction of constructive contents from logical statements. Except for bool predicates and operators, all definitions are treated transparently when matching statements for either simplification or conversion; this is achieved by using the wrapper telescope pattern, first delegating the matching of specific logical connectives, predicates, or type constructors to an auxiliary structure that *FAILS* to match unknown operators, thus triggers the expansion of defined constants. If this ultimately fails then the wrapper is expanded, and the primary structure instance for the expanded wrapper provides an alternative default rule: not simplifying ~ P, not expanding inhabited T, or not extracting any contents from a proposition P, respectively. Additional rules, for intermediate wrapper instances, are used to handle forall statements (for which canonical instances are not yet supported), as well as addiitonal simplifications, such as inhabited P = P :> Prop. Finally various tertiary structures are used to match deeper patterns, such as bounded forall statements of the form forall x, P x -> Q x, or inequalites x != y (i.e., is_true (~~ (x == y))). As mentioned above, tertiary rules for bool subexpressions do not try to expand definitions, as this would lead to the undesirable expansion of some standard definitions. This is simply achieved by *NOT* using the wrapper telescope pattern, and just having a default instance alongside those for specific predicates and connectives.

The negatedProp structure provides simplification of the Prop negation (~ _) for standard connectives and predicates. The instances below cover the pervasive and ssrbool Prop connectives, decidable equality, as well as bool propositions (i.e., the is_true predicate), together with a few bool connectives and predicates: negation ~~, equality ==, and nat <= and <. Others can be added (e.g., Order.le/lt) by declaring appropriate instances of bool_negation and bool_affirmation, while other Prop connectives and predicates can be added by declaring instances of proper_negatedProp.

The implementation follows the wrapper telescope pattern outlined above: negatedProp instances match on the wrappedProp wrapper to try three generic matching rules, in succession: - Rule 1: match a specific connective or predicate with an instance of the properNegatedProp secondary structure, expanding definitions if needed, but failing if no proper match is found. - Rule 2: match a forall statement (including (T : Type) -> P statements). - Rule 3: match any Prop but return the trivial simplification. The simplified proposition is returned as a projection parameter nP rather than a Structure member, so that applying the corresponding views or rewrite rules doesn't expose the inferred structures; properNegatedProp does similarly. Also, negatedProp similarly returns a 'trivial' bool flag that is set when Rule 3 is used, but this is actually used in the reverse direction: views notP and rewrite rule notE force trivial := false, thus excluding trivial instances.

Structure negatedProp (trivial : bool) nP :=
  NegatedProp {negated_Prop :> wrappedProp; _ : (~ negated_Prop) = nP}.

Structure properNegatedProp nP := ProperNegatedProp {
  proper_negated_Prop :> Prop; _ : (~ proper_negated_Prop) = nP}.

Local Notation nProp t nP P := (unwrap_Prop (@negated_Prop t nP P)).
Local Notation nPred t nP P x := (nProp t (nP x) (P x)).
Local Notation pnProp nP P := (@proper_negated_Prop nP P).

User views and rewrite rules. The plain versions (notP, notE and notI) do not match trivial instances; lax_XXX versions allow them. In addition, the negation introduction rewrite rule notI does not match forall or -> statements---lax_notI must be used for these.

Lemma lax_notE {t nP} P : (~ nProp t nP P) = nP
Proof.
by case: P. Qed.
Lemma lax_notP {t nP P} : ~ nProp t nP P -> nP
Proof.
by rewrite lax_notE. Qed.
Definition
lax_notI

Internals.lax_notI : forall {t : bool} {nP : Prop} (P : Internals.negatedProp t nP), Internals.unwrap_Prop (Internals.negated_Prop P) = (~ nP) Internals.lax_notI is not universe polymorphic Arguments Internals.lax_notI {t}%_bool_scope {nP}%_type_scope P Internals.lax_notI is transparent Expands to: Constant mathcomp.classical.contra.Internals.lax_notI Declared in library mathcomp.classical.contra, line 270, characters 11-19

{t nP} P : nProp t nP P = (~ nP) := canRL notK (lax_notE P).

#[warn(note="A different `notE` used to be provided by `boolp.v` before MathComp-Analysis 1.15.0.")]
Definition
notE

Internals.notE : forall {nP : Prop} (P : Internals.negatedProp false nP), (~ Internals.unwrap_Prop (Internals.negated_Prop P)) = nP Internals.notE is not universe polymorphic Arguments Internals.notE {nP}%_type_scope P Internals.notE is transparent Expands to: Constant mathcomp.classical.contra.Internals.notE Declared in library mathcomp.classical.contra, line 273, characters 11-15

{nP} P : (~ nProp false nP P) = nP := lax_notE P.
#[warn(note="A different `notP` used to be provided by `boolp.v` before MathComp-Analysis 1.15.0.")]
Definition
notP

Internals.notP : forall {nP : Prop} {P : Internals.negatedProp false nP}, Internals.move_view (~ Internals.unwrap_Prop (Internals.negated_Prop P)) nP Internals.notP is not universe polymorphic Arguments Internals.notP {nP}%_type_scope {P} Internals.notP is transparent Expands to: Constant mathcomp.classical.contra.Internals.notP Declared in library mathcomp.classical.contra, line 275, characters 11-15

{nP P} := MoveView (@lax_notP false nP P).

Fact proper_nPropP nP P : (~ pnProp nP P) = nP
Proof.
by case: P. Qed.
Definition
notI

Internals.notI : forall {nP : Prop} (P : Internals.properNegatedProp nP), Internals.proper_negated_Prop P = (~ nP) Internals.notI is not universe polymorphic Arguments Internals.notI {nP}%_type_scope P Internals.notI is transparent Expands to: Constant mathcomp.classical.contra.Internals.notI Declared in library mathcomp.classical.contra, line 278, characters 11-15

{nP} P : pnProp nP P = (~ nP) := canRL notK (proper_nPropP P).

Rule 1: proper negation simplification, delegated to properNegatedProp.
Canonical
proper_nProp

Internals.proper_nProp : forall [nP : Prop], Internals.properNegatedProp nP -> Internals.negatedProp false nP Internals.proper_nProp is not universe polymorphic Arguments Internals.proper_nProp [nP]%_type_scope P Internals.proper_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.proper_nProp Declared in library mathcomp.classical.contra, line 281, characters 10-22

nP P :=
  @NegatedProp false nP (wrap1Prop (pnProp nP P)) (proper_nPropP P).

Rule 2: forall_nProp is defined below as it uses exists_nProp.

Rule 3: trivial negation.
Canonical
trivial_nProp

Internals.trivial_nProp : forall P : Prop, Internals.negatedProp true (~ P) Internals.trivial_nProp is not universe polymorphic Arguments Internals.trivial_nProp P%_type_scope Internals.trivial_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.trivial_nProp Declared in library mathcomp.classical.contra, line 287, characters 10-23

P := @NegatedProp true (~ P) (wrap3Prop P) erefl.

properNegatedProp instances.

Canonical
True_nProp

Internals.True_nProp : Internals.properNegatedProp False Internals.True_nProp is not universe polymorphic Internals.True_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.True_nProp Declared in library mathcomp.classical.contra, line 291, characters 10-20

:= @ProperNegatedProp False True notB.1.
Canonical
False_nProp

Internals.False_nProp : Internals.properNegatedProp True Internals.False_nProp is not universe polymorphic Internals.False_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.False_nProp Declared in library mathcomp.classical.contra, line 292, characters 10-21

:= @ProperNegatedProp True False notB.2.
Canonical
not_nProp

Internals.not_nProp : forall P : Prop, Internals.properNegatedProp P Internals.not_nProp is not universe polymorphic Arguments Internals.not_nProp P%_type_scope Internals.not_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.not_nProp Declared in library mathcomp.classical.contra, line 293, characters 10-19

P := @ProperNegatedProp P (~ P) (notK P).

Fact and_nPropP P tQ nQ Q : (~ (P /\ nProp tQ nQ Q)) = (P -> nQ).
Proof.
by rewrite -implypN lax_notE. Qed.
Canonical
and_nProp

Internals.and_nProp : forall (P : Prop) [tQ : bool] [nQ : Prop], Internals.negatedProp tQ nQ -> Internals.properNegatedProp (P -> nQ) Internals.and_nProp is not universe polymorphic Arguments Internals.and_nProp P%_type_scope [tQ]%_bool_scope [nQ]%_type_scope Q Internals.and_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.and_nProp Declared in library mathcomp.classical.contra, line 297, characters 10-19

P tQ nQ Q :=
  ProperNegatedProp (@and_nPropP P tQ nQ Q).

Fact and3_nPropP P Q tR nR R : (~ [/\ P, Q & nProp tR nR R]) = (P -> Q -> nR).
Proof.
#[warnings="-user-warn"] by hnf; rewrite and3E notE. Qed.
Canonical
and3_nProp

Internals.and3_nProp : forall (P Q : Prop) [tR : bool] [nR : Prop], Internals.negatedProp tR nR -> Internals.properNegatedProp (P -> Q -> nR) Internals.and3_nProp is not universe polymorphic Arguments Internals.and3_nProp (P Q)%_type_scope [tR]%_bool_scope [nR]%_type_scope R Internals.and3_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.and3_nProp Declared in library mathcomp.classical.contra, line 302, characters 10-20

P Q tR nR R :=
  ProperNegatedProp (@and3_nPropP P Q tR nR R).

Fact and4_nPropP P Q R tS nS S :
  (~ [/\ P, Q, R & nProp tS nS S]) = (P -> Q -> R -> nS).
Proof.
#[warnings="-user-warn"] by hnf; rewrite and4E notE. Qed.
Canonical
and4_nProp

Internals.and4_nProp : forall (P Q R : Prop) [tS : bool] [nS : Prop], Internals.negatedProp tS nS -> Internals.properNegatedProp (P -> Q -> R -> nS) Internals.and4_nProp is not universe polymorphic Arguments Internals.and4_nProp (P Q R)%_type_scope [tS]%_bool_scope [nS]%_type_scope S Internals.and4_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.and4_nProp Declared in library mathcomp.classical.contra, line 308, characters 10-20

P Q R tS nS S :=
  ProperNegatedProp (@and4_nPropP P Q R tS nS S).

Fact and5_nPropP P Q R S tT nT T :
  (~ [/\ P, Q, R, S & nProp tT nT T]) = (P -> Q -> R -> S -> nT).
Proof.
#[warnings="-user-warn"] by hnf; rewrite and5E notE. Qed.
Canonical
and5_nProp

Internals.and5_nProp : forall (P Q R S : Prop) [tT : bool] [nT : Prop], Internals.negatedProp tT nT -> Internals.properNegatedProp (P -> Q -> R -> S -> nT) Internals.and5_nProp is not universe polymorphic Arguments Internals.and5_nProp (P Q R S)%_type_scope [tT]%_bool_scope [nT]%_type_scope T Internals.and5_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.and5_nProp Declared in library mathcomp.classical.contra, line 314, characters 10-20

P Q R S tT nT T :=
  ProperNegatedProp (@and5_nPropP P Q R S tT nT T).

Fact or_nPropP tP nP P tQ nQ Q :
  (~ (nProp tP nP P \/ nProp tQ nQ Q)) = (nP /\ nQ).
Proof.
by rewrite not_orE !lax_notE. Qed.
Canonical
or_nProp

Internals.or_nProp : forall [tP : bool] [nP : Prop], Internals.negatedProp tP nP -> forall [tQ : bool] [nQ : Prop], Internals.negatedProp tQ nQ -> Internals.properNegatedProp (nP /\ nQ) Internals.or_nProp is not universe polymorphic Arguments Internals.or_nProp [tP]%_bool_scope [nP]%_type_scope P [tQ]%_bool_scope [nQ]%_type_scope Q Internals.or_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.or_nProp Declared in library mathcomp.classical.contra, line 320, characters 10-18

tP nP P tQ nQ Q :=
  ProperNegatedProp (@or_nPropP tP nP P tQ nQ Q).

Fact or3_nPropP tP nP P tQ nQ Q tR nR R :
  (~ [\/ nProp tP nP P, nProp tQ nQ Q | nProp tR nR R]) = [/\ nP, nQ & nR].
Proof.
#[warnings="-user-warn"] by rewrite or3E notE and3E. Qed.
Canonical
or3_nProp

Internals.or3_nProp : forall [tP : bool] [nP : Prop], Internals.negatedProp tP nP -> forall [tQ : bool] [nQ : Prop], Internals.negatedProp tQ nQ -> forall [tR : bool] [nR : Prop], Internals.negatedProp tR nR -> Internals.properNegatedProp [/\ nP, nQ & nR] Internals.or3_nProp is not universe polymorphic Arguments Internals.or3_nProp [tP]%_bool_scope [nP]%_type_scope P [tQ]%_bool_scope [nQ]%_type_scope Q [tR]%_bool_scope [nR]%_type_scope R Internals.or3_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.or3_nProp Declared in library mathcomp.classical.contra, line 326, characters 10-19

tP nP P tQ nQ Q tR nR R :=
  ProperNegatedProp (@or3_nPropP tP nP P tQ nQ Q tR nR R).

Fact or4_nPropP tP nP P tQ nQ Q tR nR R tS nS S :
  (~ [\/ nProp tP nP P, nProp tQ nQ Q, nProp tR nR R | nProp tS nS S])
     = [/\ nP, nQ, nR & nS].
Proof.
#[warnings="-user-warn"] by rewrite or4E notE and4E. Qed.
Canonical
or4_nProp

Internals.or4_nProp : forall [tP : bool] [nP : Prop], Internals.negatedProp tP nP -> forall [tQ : bool] [nQ : Prop], Internals.negatedProp tQ nQ -> forall [tR : bool] [nR : Prop], Internals.negatedProp tR nR -> forall [tS : bool] [nS : Prop], Internals.negatedProp tS nS -> Internals.properNegatedProp [/\ nP, nQ, nR & nS] Internals.or4_nProp is not universe polymorphic Arguments Internals.or4_nProp [tP]%_bool_scope [nP]%_type_scope P [tQ]%_bool_scope [nQ]%_type_scope Q [tR]%_bool_scope [nR]%_type_scope R [tS]%_bool_scope [nS]%_type_scope S Internals.or4_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.or4_nProp Declared in library mathcomp.classical.contra, line 333, characters 10-19

tP nP P tQ nQ Q tR nR R tS nS S :=
  ProperNegatedProp (@or4_nPropP tP nP P tQ nQ Q tR nR R tS nS S).

The andRHS tertiary structure used to simplify (~ (P -> False)) to P, both here for the imply_nProp instance and for bounded_forall_nProp below. Because the andRHS instances match the Prop RETURNED by negatedProp they do not need to expand definitions, hence do not need to use the wrapper telescope pattern.

Notation and_def binary P Q PQ := (PQ = if binary then P /\ Q else Q)%type.
Structure andRHS binary P Q PQ :=
  AndRHS {and_RHS :> Prop; _ : (P /\ and_RHS) = PQ; _ : and_def binary P Q PQ}.
Canonical
unary_and_rhs

Internals.unary_and_rhs : forall P : Prop, Internals.andRHS false P P P Internals.unary_and_rhs is not universe polymorphic Arguments Internals.unary_and_rhs P%_type_scope Internals.unary_and_rhs is transparent Expands to: Constant mathcomp.classical.contra.Internals.unary_and_rhs Declared in library mathcomp.classical.contra, line 347, characters 10-23

P := @AndRHS false P P P True (andB.1.2 P) erefl.
Canonical
binary_and_rhs

Internals.binary_and_rhs : forall P Q : Prop, Internals.andRHS true P Q (P /\ Q) Internals.binary_and_rhs is not universe polymorphic Arguments Internals.binary_and_rhs (P Q)%_type_scope Internals.binary_and_rhs is transparent Expands to: Constant mathcomp.classical.contra.Internals.binary_and_rhs Declared in library mathcomp.classical.contra, line 348, characters 10-24

P Q := @AndRHS true P Q (P /\ Q) Q erefl erefl.

Fact imply_nPropP b P nQ PnQ tR (nR : andRHS b P nQ PnQ) R :
  (~ (P -> nProp tR nR R)) = PnQ.
Proof.
by rewrite -orNp {R}lax_notE; case: nR. Qed.
Canonical
imply_nProp

Internals.imply_nProp : forall [b : bool] [P nQ PnQ : Prop] [tR : bool] [nR : Internals.andRHS b P nQ PnQ], Internals.negatedProp tR (Internals.and_RHS nR) -> Internals.properNegatedProp PnQ Internals.imply_nProp is not universe polymorphic Arguments Internals.imply_nProp [b]%_bool_scope [P nQ PnQ]%_type_scope [tR]%_bool_scope [nR] R Internals.imply_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.imply_nProp Declared in library mathcomp.classical.contra, line 353, characters 10-21

b P nQ PnQ tR nR R :=
  ProperNegatedProp (@imply_nPropP b P nQ PnQ tR nR R).

Fact exists_nPropP A tP nP P :
  (~ exists x : A, nPred tP nP P x) = (forall x : A, nP x).
Proof.
eqProp=> [nEP x | AnP [x]]; last by rewrite -/(~ _) lax_notE.
by rewrite -(lax_notE (P x)) => Px; case: nEP; exists x.
Qed.
Canonical
exists_nProp

Internals.exists_nProp : forall [A : Type] [tP : bool] [nP : A -> Prop], (forall x : A, Internals.negatedProp tP (nP x)) -> Internals.properNegatedProp (forall x : A, nP x) Internals.exists_nProp is not universe polymorphic Arguments Internals.exists_nProp [A]%_type_scope [tP]%_bool_scope [nP]%_function_scope P%_function_scope Internals.exists_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.exists_nProp Declared in library mathcomp.classical.contra, line 362, characters 10-22

A tP nP P :=
  ProperNegatedProp (@exists_nPropP A tP nP P).

Fact exists2_nPropP A P tQ nQ Q :
  (~ exists2 x : A, P x & nPred tQ nQ Q x) = (forall x : A, P x -> nQ x).
Proof.
#[warnings="-user-warn"] by rewrite exists2E notE. Qed.
Canonical
exists2_nProp

Internals.exists2_nProp : forall [A : Type] (P : A -> Prop) [tQ : bool] [nQ : A -> Prop], (forall x : A, Internals.negatedProp tQ (nQ x)) -> Internals.properNegatedProp (forall x : A, P x -> nQ x) Internals.exists2_nProp is not universe polymorphic Arguments Internals.exists2_nProp [A]%_type_scope P%_function_scope [tQ]%_bool_scope [nQ]%_function_scope Q%_function_scope Internals.exists2_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.exists2_nProp Declared in library mathcomp.classical.contra, line 368, characters 10-23

A P tQ nQ Q :=
  ProperNegatedProp (@exists2_nPropP A P tQ nQ Q).

Fact inhabited_nPropP T : (~ inhabited T) = (T -> False).
Proof.
#[warnings="-user-warn"] by rewrite inhabitedE notE. Qed.
Canonical
inhabited_nProp

Internals.inhabited_nProp : forall T : Type, Internals.properNegatedProp (T -> False) Internals.inhabited_nProp is not universe polymorphic Arguments Internals.inhabited_nProp T%_type_scope Internals.inhabited_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.inhabited_nProp Declared in library mathcomp.classical.contra, line 373, characters 10-25

T := ProperNegatedProp (inhabited_nPropP T).

Rule 2: forall negation, including (T : Type) -> P statements. We use tertiary structures to recognize bounded foralls and simplify, e.g., ~ forall x, P -> Q to exists2 x, P & ~ Q, or even exists x, P when Q := False (as above for imply). As forall_body_nProp and forall_body_proper_nProp are telescopes over negatedProp and properNegatedProp, respectively, their instances match instances declared above without the need to expand definitions, hence do not need to use the wrapper telescope idiom.

Structure negatedForallBody bounded P nQ tR nR := NegatedForallBody {
  negated_forall_body :> negatedProp tR nR; _ : and_def bounded P nQ nR}.
Structure properNegatedForallBody b P nQ nR := ProperNegatedForallBody {
  proper_negated_forall_body :> properNegatedProp nR; _ : and_def b P nQ nR}.
Notation nBody b P nQ t nR x := (negatedForallBody b (P x) (nQ x) t (nR x)).

The explicit argument to fun_if is a workaround for a bug in the Coq unification code that prevents default instances from ever matching match constructs. Furthermore rewriting with ifE would not work here, because the if_expr definition would be expanded by the eta expansion needed to match the exists_nProp rule.

Fact forall_nPropP A b P nQ tR nR (R : forall x, nBody b P nQ tR nR x) :
  (~ forall x : A, R x) = if b then exists2 x, P x & nQ x else exists x, nQ x.
Proof.
rewrite exists2E -(fun_if (fun P => exists x, idfun P x)) notI /=; congr not.
apply/generic_forall_extensionality=> x; rewrite if_arg lax_notI.
by case: (R x) => _ <-.
Qed.
Canonical
forall_nProp

Internals.forall_nProp : forall [A : Type] [b : bool] [P nQ : A -> Prop] [tR : bool] [nR : A -> Prop], (forall x : A, Internals.nBody b P nQ tR nR x) -> Internals.negatedProp false (if b then exists2 x : A, P x & nQ x else exists x : A, nQ x) Internals.forall_nProp is not universe polymorphic Arguments Internals.forall_nProp [A]%_type_scope [b]%_bool_scope [P nQ]%_function_scope [tR]%_bool_scope [nR]%_function_scope R%_function_scope Internals.forall_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.forall_nProp Declared in library mathcomp.classical.contra, line 409, characters 10-22

A b P nQ tR nR (R : forall x, nBody b P nQ tR nR x) :=
  @NegatedProp false _ (wrap2Prop (forall x : A, R x)) (forall_nPropP R).

Fact proper_nBodyP b P nQ nR :
  properNegatedForallBody b P nQ nR -> and_def b P nQ nR.
Proof.
by case. Qed.
Canonical
proper_nBody

Internals.proper_nBody : forall [b : bool] [P nQ nR : Prop], Internals.properNegatedForallBody b P nQ nR -> Internals.negatedForallBody b P nQ false nR Internals.proper_nBody is not universe polymorphic Arguments Internals.proper_nBody [b]%_bool_scope [P nQ nR]%_type_scope R Internals.proper_nBody is transparent Expands to: Constant mathcomp.classical.contra.Internals.proper_nBody Declared in library mathcomp.classical.contra, line 415, characters 10-22

b P nQ nR R :=
  let def_nR := @proper_nBodyP b P nQ nR R in
  @NegatedForallBody b P nQ false nR (proper_nProp R) def_nR.
Canonical
nonproper_nBody

Internals.nonproper_nBody : forall [tP : bool] [nP : Prop], Internals.negatedProp tP nP -> Internals.negatedForallBody false True nP tP nP Internals.nonproper_nBody is not universe polymorphic Arguments Internals.nonproper_nBody [tP]%_bool_scope [nP]%_type_scope P Internals.nonproper_nBody is transparent Expands to: Constant mathcomp.classical.contra.Internals.nonproper_nBody Declared in library mathcomp.classical.contra, line 418, characters 10-25

tP nP P :=
  @NegatedForallBody false True nP tP nP P erefl.

Fact andRHS_def b P Q PQ : andRHS b P Q PQ -> and_def b P Q PQ.
Proof.
by case. Qed.
Canonical
bounded_nBody

Internals.bounded_nBody : forall [b : bool] [P nQ PnQ : Prop] [tR : bool] [nR : Internals.andRHS b P nQ PnQ], Internals.negatedProp tR (Internals.and_RHS nR) -> Internals.properNegatedForallBody b P nQ PnQ Internals.bounded_nBody is not universe polymorphic Arguments Internals.bounded_nBody [b]%_bool_scope [P nQ PnQ]%_type_scope [tR]%_bool_scope [nR] R Internals.bounded_nBody is transparent Expands to: Constant mathcomp.classical.contra.Internals.bounded_nBody Declared in library mathcomp.classical.contra, line 423, characters 10-23

b P nQ PnQ tR nR R :=
  ProperNegatedForallBody (@imply_nProp b P nQ PnQ tR nR R) (andRHS_def nR).
Canonical
unbounded_nBody

Internals.unbounded_nBody : forall [nQ : Prop], Internals.properNegatedProp nQ -> Internals.properNegatedForallBody false True nQ nQ Internals.unbounded_nBody is not universe polymorphic Arguments Internals.unbounded_nBody [nQ]%_type_scope Q Internals.unbounded_nBody is transparent Expands to: Constant mathcomp.classical.contra.Internals.unbounded_nBody Declared in library mathcomp.classical.contra, line 425, characters 10-25

nQ Q :=
  @ProperNegatedForallBody false True nQ nQ Q erefl.

The properNegatedProp instance that handles boolean statements. We use two tertiary structures to handle positive and negative boolean statements so that the contra tactic below will mostly subsume the collection of contraXX lemmas in ssrbool and eqtype. We only match manifest ~~ connectives, the true and false constants, and the ==, <=%N, and <%N predicates. In particular we do not use de Morgan laws to push boolean negation into connectives, as we did above for Prop connectives. It will be up to the user to use rewriting to put the negated statement in its desired shape.

Structure negatedBool nP :=
  NegatedBool {negated_bool :> bool; _ : (~ negated_bool) = nP}.
Structure positedBool P :=
  PositedBool {posited_bool :> bool; _ : is_true posited_bool = P}.

Local Fact is_true_nPropP nP (b : negatedBool nP) : (~ b) = nP.
Proof.
by case: b. Qed.
Canonical
is_true_nProp

Internals.is_true_nProp : forall [nP : Prop], Internals.negatedBool nP -> Internals.properNegatedProp nP Internals.is_true_nProp is not universe polymorphic Arguments Internals.is_true_nProp [nP]%_type_scope b Internals.is_true_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.is_true_nProp Declared in library mathcomp.classical.contra, line 448, characters 10-23

nP b := ProperNegatedProp (@is_true_nPropP nP b).

Local Fact true_negP : (~ true) = False
Proof.
by eqProp. Qed.
Local Fact true_posP : (true : Prop) = True
Proof.
by eqProp. Qed.
Local Fact false_negP : (~ false) = True
Proof.
by eqProp. Qed.
Local Fact false_posP : (false : Prop) = False
Proof.
by eqProp. Qed.
Canonical
true_neg

Internals.true_neg : Internals.negatedBool False Internals.true_neg is not universe polymorphic Internals.true_neg is transparent Expands to: Constant mathcomp.classical.contra.Internals.true_neg Declared in library mathcomp.classical.contra, line 454, characters 10-18

:= NegatedBool true_negP.
Canonical
true_pos

Internals.true_pos : Internals.positedBool True Internals.true_pos is not universe polymorphic Internals.true_pos is transparent Expands to: Constant mathcomp.classical.contra.Internals.true_pos Declared in library mathcomp.classical.contra, line 455, characters 10-18

:= PositedBool true_posP.
Canonical
false_neg

Internals.false_neg : Internals.negatedBool True Internals.false_neg is not universe polymorphic Internals.false_neg is transparent Expands to: Constant mathcomp.classical.contra.Internals.false_neg Declared in library mathcomp.classical.contra, line 456, characters 10-19

:= NegatedBool false_negP.
Canonical
false_pos

Internals.false_pos : Internals.positedBool False Internals.false_pos is not universe polymorphic Internals.false_pos is transparent Expands to: Constant mathcomp.classical.contra.Internals.false_pos Declared in library mathcomp.classical.contra, line 457, characters 10-19

:= PositedBool false_posP.

Local Fact id_negP (b : bool) : (~ b) = ~~ b
Proof.
exact/reflect_eq/negP. Qed.
Canonical
id_neg

Internals.id_neg : forall b : bool, Internals.negatedBool (~~ b) Internals.id_neg is not universe polymorphic Arguments Internals.id_neg b%_bool_scope Internals.id_neg is transparent Expands to: Constant mathcomp.classical.contra.Internals.id_neg Declared in library mathcomp.classical.contra, line 460, characters 10-16

b := NegatedBool (id_negP b).
Canonical
id_pos

Internals.id_pos : forall b : bool, Internals.positedBool b Internals.id_pos is not universe polymorphic Arguments Internals.id_pos b%_bool_scope Internals.id_pos is transparent Expands to: Constant mathcomp.classical.contra.Internals.id_pos Declared in library mathcomp.classical.contra, line 461, characters 10-16

(b : bool) := @PositedBool b b erefl.

Local Fact negb_negP P (b : positedBool P) : (~ ~~ b) = P.
Proof.
by rewrite (reflect_eq negP) negbK; case: b. Qed.
Canonical
negb_neg

Internals.negb_neg : forall [P : Prop], Internals.positedBool P -> Internals.negatedBool P Internals.negb_neg is not universe polymorphic Arguments Internals.negb_neg [P]%_type_scope b Internals.negb_neg is transparent Expands to: Constant mathcomp.classical.contra.Internals.negb_neg Declared in library mathcomp.classical.contra, line 465, characters 10-18

P b := NegatedBool (@negb_negP P b).
Local Fact negb_posP nP (b : negatedBool nP) : (~~ b = nP :> Prop).
Proof.
#[warnings="-user-warn"] by rewrite -(reflect_eq negP) notE. Qed.
Canonical
negb_pos

Internals.negb_pos : forall [nP : Prop], Internals.negatedBool nP -> Internals.positedBool nP Internals.negb_pos is not universe polymorphic Arguments Internals.negb_pos [nP]%_type_scope b Internals.negb_pos is transparent Expands to: Constant mathcomp.classical.contra.Internals.negb_pos Declared in library mathcomp.classical.contra, line 468, characters 10-18

nP b := PositedBool (@negb_posP nP b).

We use a tertiary structure to handle the negation of nat comparisons, and simplify ~ m <= n to n < m, and ~ m < n to n <= m. As m < n is merely notation for m.+1 <= n, we need to dispatch on the left hand side of the comparison to perform the latter simplification.

Structure negatedLeqLHS n lt_nm :=
  NegatedLeqLHS {negated_leq_LHS :> nat; _ : (n < negated_leq_LHS) = lt_nm}.
Canonical
neg_ltn_LHS

Internals.neg_ltn_LHS : forall n m : nat, Internals.negatedLeqLHS n (n <= m) Internals.neg_ltn_LHS is not universe polymorphic Arguments Internals.neg_ltn_LHS (n m)%_nat_scope Internals.neg_ltn_LHS is transparent Expands to: Constant mathcomp.classical.contra.Internals.neg_ltn_LHS Declared in library mathcomp.classical.contra, line 479, characters 10-21

n m := @NegatedLeqLHS n (n <= m) m.+1 erefl.
Canonical
neg_leq_LHS

Internals.neg_leq_LHS : forall n m : nat, Internals.negatedLeqLHS n (n < m) Internals.neg_leq_LHS is not universe polymorphic Arguments Internals.neg_leq_LHS (n m)%_nat_scope Internals.neg_leq_LHS is transparent Expands to: Constant mathcomp.classical.contra.Internals.neg_leq_LHS Declared in library mathcomp.classical.contra, line 480, characters 10-21

n m := @NegatedLeqLHS n (n < m) m erefl.

Local Fact leq_negP n lt_nm (m : negatedLeqLHS n lt_nm) : (~ m <= n) = lt_nm.
Proof.
#[warnings="-user-warn"] by rewrite notE -ltnNge; case: m => /= m ->. Qed.
Canonical
leq_neg

Internals.leq_neg : forall [n : nat] [lt_nm : bool], Internals.negatedLeqLHS n lt_nm -> Internals.negatedBool lt_nm Internals.leq_neg is not universe polymorphic Arguments Internals.leq_neg [n]%_nat_scope [lt_nm]%_bool_scope m Internals.leq_neg is transparent Expands to: Constant mathcomp.classical.contra.Internals.leq_neg Declared in library mathcomp.classical.contra, line 484, characters 10-17

n lt_nm m := NegatedBool (@leq_negP n lt_nm m).

We use two tertiary structures to simplify negation of boolean constant and decidable equalities, simplifying b <> true to ~~ b, b <> false to b, x <> y to x != y, and ~ x != y to x = y. We do need to use the wrapper telescope pattern here, as we want to simplify instances of x <> y when y evaluates to true or false. Since we only need two rules (true/false RHS or generic eqType RHS) we can use the generic wrapped type from ssrfun. The actual matching of the true and false RHS is delegated to a fourth level bool_eq_negation_rhs structure. Finally observe that the ~ x != y to x = y simplification can be handled by a bool_affirmation instance.

Structure neqRHS nP T x :=
  NeqRHS {neq_RHS :> wrapped T; _ : (x <> unwrap neq_RHS) = nP}.
Structure boolNeqRHS nP (x : bool) :=
  BoolNeqRHS {bool_neq_RHS; _ : (x <> bool_neq_RHS) = nP}.

Local Fact eq_nPropP nP T x (y : neqRHS nP x) : (x <> unwrap y :> T) = nP.
Proof.
by case: y. Qed.
Canonical
eq_nProp

Internals.eq_nProp : forall [nP : Prop] [T : Type] [x : T], Internals.neqRHS nP x -> Internals.properNegatedProp nP Internals.eq_nProp is not universe polymorphic Arguments Internals.eq_nProp [nP T]%_type_scope [x] y Internals.eq_nProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.eq_nProp Declared in library mathcomp.classical.contra, line 505, characters 10-18

nP T x y := ProperNegatedProp (@eq_nPropP nP T x y).

Local Fact bool_neqP nP x y : (x <> @bool_neq_RHS nP x y) = nP.
Proof.
by case: y. Qed.
Canonical
bool_neq

Internals.bool_neq : forall [nP : Prop] [x : bool], Internals.boolNeqRHS nP x -> Internals.neqRHS nP x Internals.bool_neq is not universe polymorphic Arguments Internals.bool_neq [nP]%_type_scope [x]%_bool_scope y Internals.bool_neq is transparent Expands to: Constant mathcomp.classical.contra.Internals.bool_neq Declared in library mathcomp.classical.contra, line 509, characters 10-18

nP x y := @NeqRHS nP bool x (wrap _) (@bool_neqP nP x y).
Canonical
true_neq

Internals.true_neq : forall [nP : Prop] (b : Internals.negatedBool nP), Internals.boolNeqRHS nP (Internals.negated_bool b) Internals.true_neq is not universe polymorphic Arguments Internals.true_neq [nP]%_type_scope b Internals.true_neq is transparent Expands to: Constant mathcomp.classical.contra.Internals.true_neq Declared in library mathcomp.classical.contra, line 510, characters 10-18

nP b := BoolNeqRHS (@is_true_nPropP nP b).
Local Fact false_neqP P (b : positedBool P) : (b <> false :> bool) = P.
Proof.
by move: b => [] [] /= <-; exact/propext. Qed.
Canonical
false_neq

Internals.false_neq : forall [P : Prop] (b : Internals.positedBool P), Internals.boolNeqRHS P (Internals.posited_bool b) Internals.false_neq is not universe polymorphic Arguments Internals.false_neq [P]%_type_scope b Internals.false_neq is transparent Expands to: Constant mathcomp.classical.contra.Internals.false_neq Declared in library mathcomp.classical.contra, line 513, characters 10-19

P b := BoolNeqRHS (@false_neqP P b).

Local Fact eqType_neqP (T : eqType) (x y : T) : (x <> y) = (x != y).
Proof.
by rewrite [in LHS](reflect_eq eqP) (reflect_eq negP). Qed.
Canonical
eqType_neq

Internals.eqType_neq : forall [T : eqType] (x y : T), Internals.neqRHS (x != y) x Internals.eqType_neq is not universe polymorphic Arguments Internals.eqType_neq [T] x y Internals.eqType_neq is transparent Expands to: Constant mathcomp.classical.contra.Internals.eqType_neq Declared in library mathcomp.classical.contra, line 517, characters 10-20

(T : eqType) x y :=
  @NeqRHS (x != y) T x (Wrap y) (eqType_neqP x y).
Local Fact eq_op_posP (T : eqType) x y : (x == y :> T : Prop) = (x = y).
Proof.
exact/esym/reflect_eq/eqP. Qed.
Canonical
eq_op_pos

Internals.eq_op_pos : forall [T : eqType] (x y : T), Internals.positedBool (x = y) Internals.eq_op_pos is not universe polymorphic Arguments Internals.eq_op_pos [T] x y Internals.eq_op_pos is transparent Expands to: Constant mathcomp.classical.contra.Internals.eq_op_pos Declared in library mathcomp.classical.contra, line 521, characters 10-19

T x y := PositedBool (@eq_op_posP T x y).

The witnessedType structure provides conversion between Type and Prop in goals; the conversion is mostly used in the Type-to-Prop direction, e.g., as a preprocessing step preceding proof by contradiction (see absurd_not below), but the Prop-to-Type direction is required for contraposition. Thus witnessedType associates to a type T a "witness" proposition P equivalent to the existence of an x of type T. As in a `{classical_logic} context inhabited T is such a proposition, witnessedType can be understood as providing simplification for inhabited T, much like negatedProp provides simplification for ~ P for standard connectives and predicates.

Similarly to negatedProp, witnessedType returns the witness proposition via a projection argument P, but does not need to signal "trivial" instances as the default value for P is nontrivial (namely, inhabited T), while the "trivial" case where P = T is actually desireable and handled by an extra top-priority rule.

Structure witnessedType P := WitnessedType {
 witnessed_Type :> wrappedType; _ : inhabited witnessed_Type = P}.
Structure properWitnessedType P := ProperWitnessedType {
  proper_witnessed_Type :> Type; _ : inhabited proper_witnessed_Type = P}.
Local Notation wType P T := (unwrap_Type (@witnessed_Type P T)).
Local Notation wTycon P T x := (wType (P x) (T x)).


Lemma witnessedType_intro {P : Prop} T : P -> wType P T.
Proof.
by case: T => /= T <- /inhabited_witness. Qed.
Local Coercion witnessedType_intro : witnessedType >-> Funclass.

Lemma witnessedType_elim {P} T : wType P T -> P.
Proof.
by case: T => /= T <-. Qed.
Local Notation wTypeP := witnessedType_elim.


Local Fact eq_inhabited T (P : Prop) : (T -> P) -> (P -> T) -> inhabited T = P.
Proof.
by move=> T_P P_T; eqProp=> [[/T_P] | /P_T]. Qed.
Ltac eqInh := apply: eq_inhabited.

Rule 1: Prop goals are left as is.
Canonical
Prop_wType

Internals.Prop_wType : forall P : Prop, Internals.witnessedType P Internals.Prop_wType is not universe polymorphic Arguments Internals.Prop_wType P%_type_scope Internals.Prop_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.Prop_wType Declared in library mathcomp.classical.contra, line 568, characters 10-20

P :=
  @WitnessedType P (wrap1Type P) (eq_inhabited (@id P) id).

Rule 2: Specific type constructors (sigs, sums, and pairs) are delegated to the secondary properWitnessedType structure.
Lemma proper_wTypeP P (T : properWitnessedType P) : inhabited T = P.
Proof.
by case: T. Qed.
Canonical
proper_wType

Internals.proper_wType : forall [P : Prop], Internals.properWitnessedType P -> Internals.witnessedType P Internals.proper_wType is not universe polymorphic Arguments Internals.proper_wType [P]%_type_scope T Internals.proper_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.proper_wType Declared in library mathcomp.classical.contra, line 575, characters 10-22

P T :=
  @WitnessedType P (wrap2Type _) (@proper_wTypeP P T).

Rule 3: Forall (and -> as a special case).
Local Fact forall_wTypeP A P T :
  inhabited (forall x : A, wTycon P T x) = (forall x : A, P x) .
Proof.
by do [eqInh=> allP x; have:= allP x] => [/wTypeP | /T]. Qed.
Canonical
forall_wType

Internals.forall_wType : forall [A : Type] [P : A -> Prop], (forall x : A, Internals.witnessedType (P x)) -> Internals.witnessedType (forall x : A, P x) Internals.forall_wType is not universe polymorphic Arguments Internals.forall_wType [A]%_type_scope [P]%_function_scope T%_function_scope Internals.forall_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.forall_wType Declared in library mathcomp.classical.contra, line 582, characters 10-22

A P T :=
  @WitnessedType _ (wrap3Type _) (@forall_wTypeP A P T).

Rule 4: Default to inhabited if all else fails.
Canonical
inhabited_wType

Internals.inhabited_wType : forall T : Type, Internals.witnessedType (inhabited T) Internals.inhabited_wType is not universe polymorphic Arguments Internals.inhabited_wType T%_type_scope Internals.inhabited_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.inhabited_wType Declared in library mathcomp.classical.contra, line 586, characters 10-25

T := @WitnessedType (inhabited T) (wrap4Type T) erefl.

Specific proper_witnessedType instances.

Local Fact void_wTypeP : inhabited void = False
Proof.
by eqInh. Qed.
Canonical
void_wType

Internals.void_wType : Internals.properWitnessedType False Internals.void_wType is not universe polymorphic Internals.void_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.void_wType Declared in library mathcomp.classical.contra, line 591, characters 10-20

:= ProperWitnessedType void_wTypeP.

Local Fact unit_wTypeP : inhabited unit = True
Proof.
by eqInh. Qed.
Canonical
unit_wType

Internals.unit_wType : Internals.properWitnessedType True Internals.unit_wType is not universe polymorphic Internals.unit_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.unit_wType Declared in library mathcomp.classical.contra, line 594, characters 10-20

:= ProperWitnessedType unit_wTypeP.

Local Fact pair_wTypeP P Q S T : inhabited (wType P S * wType Q T) = (P /\ Q).
Proof.
by eqInh=> [[/wTypeP-isP /wTypeP] | [/S-x /T]]. Qed.
Canonical
pair_wType

Internals.pair_wType : forall [P Q : Prop], Internals.witnessedType P -> Internals.witnessedType Q -> Internals.properWitnessedType (P /\ Q) Internals.pair_wType is not universe polymorphic Arguments Internals.pair_wType [P Q]%_type_scope S T Internals.pair_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.pair_wType Declared in library mathcomp.classical.contra, line 598, characters 10-20

P Q S T := ProperWitnessedType (@pair_wTypeP P Q S T).

Local Fact sum_wTypeP P Q S T : inhabited (wType P S + wType Q T) = (P \/ Q).
Proof.
by eqInh=> [[] /wTypeP | /decide_or[/S | /T]]; by [left | right]. Qed.
Canonical
sum_wType

Internals.sum_wType : forall [P Q : Prop], Internals.witnessedType P -> Internals.witnessedType Q -> Internals.properWitnessedType (P \/ Q) Internals.sum_wType is not universe polymorphic Arguments Internals.sum_wType [P Q]%_type_scope S T Internals.sum_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.sum_wType Declared in library mathcomp.classical.contra, line 602, characters 10-19

P Q S T := ProperWitnessedType (@sum_wTypeP P Q S T).

Local Fact sumbool_wTypeP P Q : inhabited ({P} + {Q}) = (P \/ Q).
Proof.
by eqInh=> [[] | /decide_or[]]; by [left | right]. Qed.
Canonical
sumbool_wType

Internals.sumbool_wType : forall P Q : Prop, Internals.properWitnessedType (P \/ Q) Internals.sumbool_wType is not universe polymorphic Arguments Internals.sumbool_wType (P Q)%_type_scope Internals.sumbool_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.sumbool_wType Declared in library mathcomp.classical.contra, line 606, characters 10-23

P Q := ProperWitnessedType (@sumbool_wTypeP P Q).

Local Fact sumor_wTypeP P Q T : inhabited (wType P T + {Q}) = (P \/ Q).
Proof.
by eqInh=> [[/wTypeP|] | /decide_or[/T|]]; by [left | right]. Qed.
Canonical
sumor_wType

Internals.sumor_wType : forall [P : Prop] (Q : Prop), Internals.witnessedType P -> Internals.properWitnessedType (P \/ Q) Internals.sumor_wType is not universe polymorphic Arguments Internals.sumor_wType [P]%_type_scope Q%_type_scope T Internals.sumor_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.sumor_wType Declared in library mathcomp.classical.contra, line 610, characters 10-21

P Q T := ProperWitnessedType (@sumor_wTypeP P Q T).

Local Fact sig1_wTypeP T P : inhabited {x : T | P x} = (exists x : T, P x).
Proof.
by eqInh=> [[x Px] | /cid//]; exists x. Qed.
Canonical
sig1_wType

Internals.sig1_wType : forall [T : Type] (P : T -> Prop), Internals.properWitnessedType (exists x : T, P x) Internals.sig1_wType is not universe polymorphic Arguments Internals.sig1_wType [T]%_type_scope P%_function_scope Internals.sig1_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.sig1_wType Declared in library mathcomp.classical.contra, line 614, characters 10-20

T P := ProperWitnessedType (@sig1_wTypeP T P).

Local Fact sig2_wTypeP T P Q :
  inhabited {x : T | P x & Q x} = exists2 x : T, P x & Q x.
Proof.
by eqInh=> [[x Px Qx] | /cid2//]; exists x. Qed.
Canonical
sig2_wType

Internals.sig2_wType : forall [T : Type] (P Q : T -> Prop), Internals.properWitnessedType (exists2 x : T, P x & Q x) Internals.sig2_wType is not universe polymorphic Arguments Internals.sig2_wType [T]%_type_scope (P Q)%_function_scope Internals.sig2_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.sig2_wType Declared in library mathcomp.classical.contra, line 619, characters 10-20

T P Q := ProperWitnessedType (@sig2_wTypeP T P Q).

Local Fact sigT_wTypeP A P T :
  inhabited {x : A & wTycon P T x} = (exists x : A, P x).
Proof.
by eqInh=> [[x /wTypeP] | /cid[x /T]]; exists x. Qed.
Canonical
sigT_wType

Internals.sigT_wType : forall [A : Type] [P : A -> Prop], (forall x : A, Internals.witnessedType (P x)) -> Internals.properWitnessedType (exists x : A, P x) Internals.sigT_wType is not universe polymorphic Arguments Internals.sigT_wType [A]%_type_scope [P]%_function_scope T%_function_scope Internals.sigT_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.sigT_wType Declared in library mathcomp.classical.contra, line 624, characters 10-20

A P T := ProperWitnessedType (@sigT_wTypeP A P T).

Local Fact sigT2_wTypeP A P Q S T :
  inhabited {x : A & wTycon P S x & wTycon Q T x} = (exists2 x : A, P x & Q x).
Proof.
by eqInh=> [[x /wTypeP-Px /wTypeP] | /cid2[x /S-y /T]]; exists x. Qed.
Canonical
sigT2_wType

Internals.sigT2_wType : forall [A : Type] [P Q : A -> Prop], (forall x : A, Internals.witnessedType (P x)) -> (forall x : A, Internals.witnessedType (Q x)) -> Internals.properWitnessedType (exists2 x : A, P x & Q x) Internals.sigT2_wType is not universe polymorphic Arguments Internals.sigT2_wType [A]%_type_scope [P Q]%_function_scope (S T)%_function_scope Internals.sigT2_wType is transparent Expands to: Constant mathcomp.classical.contra.Internals.sigT2_wType Declared in library mathcomp.classical.contra, line 629, characters 10-21

A P Q S T :=
  ProperWitnessedType (@sigT2_wTypeP A P Q S T).

The witnessProp structure provides for conversion of some Prop assumptions to Type values with some constructive contents, e.g., convert a P \/ Q assumption to a {P} + {Q} sumbool value. This is not the same as the forward direction of witnessedType, because instances here match the Prop statement: witness_Prop find a T such that P -> T while witnessedType finds a P such that P -> T (and T -> P for the converse direction).

The implementation follows the wrapper telescope pattern similarly to negatedProp, with three rules, one for Prop constructors with proper constructive contents, one for forall propositions (also with proper constructive contents) and one default rule that just returns P : Prop as is (thus, with no other contents except the provability of P). The witnessProp structure also uses projection parameters to return the inferred Type T together with a bool 'trivial' flag that is set when the trivial rule is used. Here, however, this flag is used in both directions: the 'witness' view forces it to false to prevent trivial instances, but the flag is also used to fine tune the choice of T, selecting between sum, sumor, and sumbool, between sig and sigT, and sig2 and sigT2. This relies on the fact that the tactic engine will eagerly iota reduce the returned type, so that the user will never see the conditionals specified in the proper_witness_Prop instances. However, it would not be possible to construct the specialised types for trivial witnesses (e.g., {P} + {Q}) using the types returned by witnessProp instances, since thes are in Type, and the information that they are actully in Prop has been lost. This is solved by returning an additional Prop P0 that is a copy of the matched Prop P when trivial = true. (We put P0 = True when trivial = false, as we only need to ensure P -> P0.) Caveat: although P0 should in principle be the last parameter of witness_Prop, and we use this order for the wProp and wPred projector local notation, it is important to put P0 _BEFORE_ T, to circumvent an incompleteness in Coq's implementation of higher-order pattern unification that would cause the trivial rule to fail for the body of an exists. In such a case the rule needs to unify (1) ?P0 x ~ ?P and (2) ?T x ~ ?P for some type A some x : A in the context of ?P, but not ?P0 nor ?T. This succeeds easily if (1) is performed before (2), setting ?P := ?P0 x and ?T := ?P0, but if (2) is attempted first Coq tries to perform ?P := ?T x, which fails Type/Prop universe constraints, and then fails outright, instead of using pattern unification to solve (2) as ?P := ?Q x, ?T := ?Q for a fresh ?Q : A -> Prop.

Structure witnessProp (trivial : bool) (P0 : Prop) (T : Type) :=
  WitnessProp {witness_Prop :> wrappedProp; _ : witness_Prop -> T * P0}.
Structure properWitnessProp T :=
  ProperWitnessProp {proper_witness_Prop :> Prop; _ : proper_witness_Prop -> T}.

Local Notation wProp t T P0 P := (unwrap_Prop (@witness_Prop t P0 T P)).
Local Notation wPred t T P0 P x := (wProp t (T x) (P0 x) (P x)).

Local Fact wPropP t T P0 P : wProp t T P0 P -> T * P0
Proof.
by case: P. Qed.
Lemma lax_witness {t T P0 P} : move_view (wProp t T P0 P) T.
Proof.
by split=> /wPropP[]. Qed.
Definition
witness

Internals.witness : forall {T : Type} {P0 : Prop} {P : Internals.witnessProp false P0 T}, Internals.move_view (Internals.unwrap_Prop (Internals.witness_Prop P)) T Internals.witness is not universe polymorphic Arguments Internals.witness {T P0}%_type_scope {P} Internals.witness is transparent Expands to: Constant mathcomp.classical.contra.Internals.witness Declared in library mathcomp.classical.contra, line 691, characters 11-18

{T P0 P} := @lax_witness false T P0 P.

Rule 1: proper instances (except forall), delegated to an auxiliary structures.
Local Fact proper_wPropP T P : wrap1Prop (@proper_witness_Prop T P) -> T * True.
Proof.
by case: P => _ P_T {}/P_T. Qed.
Canonical
proper_wProp

Internals.proper_wProp : forall [T : Type], Internals.properWitnessProp T -> Internals.witnessProp false True T Internals.proper_wProp is not universe polymorphic Arguments Internals.proper_wProp [T]%_type_scope P Internals.proper_wProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.proper_wProp Declared in library mathcomp.classical.contra, line 697, characters 10-22

T P := WitnessProp false (@proper_wPropP T P).

Rule 2: forall types (including implication); as only proper instances are allowed, we set trivial = false for the recursive body instance.
Local Fact forall_wPropP A T P0 P :
  wrap2Prop (forall x : A, wPred false T P0 P x) -> (forall x, T x) * True.
Proof.
by move=> P_A; split=> // x; have /witness := P_A x. Qed.
Canonical
forall_wProp

Internals.forall_wProp : forall [A : Type] [T : A -> Type] [P0 : A -> Prop], (forall x : A, Internals.witnessProp false (P0 x) (T x)) -> Internals.witnessProp false True (forall x : A, T x) Internals.forall_wProp is not universe polymorphic Arguments Internals.forall_wProp [A]%_type_scope [T P0]%_function_scope P%_function_scope Internals.forall_wProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.forall_wProp Declared in library mathcomp.classical.contra, line 704, characters 10-22

A T P0 P := WitnessProp false (@forall_wPropP A T P0 P).

Rule 3: trivial (proof) self-witness.
Canonical
trivial_wProp

Internals.trivial_wProp : forall P : Prop, Internals.witnessProp true P P Internals.trivial_wProp is not universe polymorphic Arguments Internals.trivial_wProp P%_type_scope Internals.trivial_wProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.trivial_wProp Declared in library mathcomp.classical.contra, line 707, characters 10-23

P :=
  WitnessProp true (fun p : wrap3Prop P => (p, p) : P * P).

Specific proper_witnesss_Prop instances.

Canonical
inhabited_wProp

Internals.inhabited_wProp : forall T : Type, Internals.properWitnessProp T Internals.inhabited_wProp is not universe polymorphic Arguments Internals.inhabited_wProp T%_type_scope Internals.inhabited_wProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.inhabited_wProp Declared in library mathcomp.classical.contra, line 712, characters 10-25

T := ProperWitnessProp (@inhabited_witness T).

Conjunctions P /\ Q are a little delicate to handle, as we should not produce a proper instance (and thus fail) if neither P nor Q is proper. We use a tertiary structure for this : nand_bool b, which has instances only for booleans b0 such that ~~ (b0 && b). We allow the witness_Prop instance for P to return an arbitrary 'trivial' flag s, but then force the 'trivial' flag for Q to be an instance of nand_bool s.

Structure nandBool b := NandBool {nand_bool :> bool; _ : ~~ (nand_bool && b)}.
Canonical
nand_false_bool

Internals.nand_false_bool : forall b : bool, Internals.nandBool b Internals.nand_false_bool is not universe polymorphic Arguments Internals.nand_false_bool b%_bool_scope Internals.nand_false_bool is transparent Expands to: Constant mathcomp.classical.contra.Internals.nand_false_bool Declared in library mathcomp.classical.contra, line 724, characters 10-25

b := @NandBool b false isT.
Canonical
nand_true_bool

Internals.nand_true_bool : Internals.nandBool false Internals.nand_true_bool is not universe polymorphic Internals.nand_true_bool is transparent Expands to: Constant mathcomp.classical.contra.Internals.nand_true_bool Declared in library mathcomp.classical.contra, line 725, characters 10-24

:= @NandBool false true isT.

Local Fact and_wPropP s S P0 P (t : nandBool s) T Q0 Q :
  wProp s S P0 P /\ wProp t T Q0 Q -> S * T.
Proof.
by case=> /lax_witness-x /lax_witness. Qed.
Canonical
and_wProp

Internals.and_wProp : forall [s : bool] [S : Type] [P0 : Prop], Internals.witnessProp s P0 S -> forall [t : Internals.nandBool s] [T : Type] [Q0 : Prop], Internals.witnessProp (Internals.nand_bool t) Q0 T -> Internals.properWitnessProp (S * T) Internals.and_wProp is not universe polymorphic Arguments Internals.and_wProp [s]%_bool_scope [S P0]%_type_scope P [t] [T Q0]%_type_scope Q Internals.and_wProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.and_wProp Declared in library mathcomp.classical.contra, line 730, characters 10-19

s S P0 P t T Q0 Q :=
  ProperWitnessProp (@and_wPropP s S P0 P t T Q0 Q).

Local Fact or_wPropP s S P0 P t T Q0 Q :
    wProp s S P0 P \/ wProp t T Q0 Q ->
  if t then if s then {P0} + {Q0} : Type else S + {Q0} else S + T : Type.
Proof.
by case: s t => -[] in P Q *; (case/decide_or=> /wPropP[]; [left | right]).
Qed.
Canonical
or_wProp

Internals.or_wProp : forall [s : bool] [S : Type] [P0 : Prop], Internals.witnessProp s P0 S -> forall [t : bool] [T : Type] [Q0 : Prop], Internals.witnessProp t Q0 T -> Internals.properWitnessProp (if t then if s then {P0} + {Q0} : Type else S + {Q0} else S + T : Type) Internals.or_wProp is not universe polymorphic Arguments Internals.or_wProp [s]%_bool_scope [S P0]%_type_scope P [t]%_bool_scope [T Q0]%_type_scope Q Internals.or_wProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.or_wProp Declared in library mathcomp.classical.contra, line 742, characters 10-18

s S P0 P t T Q0 Q :=
  ProperWitnessProp (@or_wPropP s S P0 P t T Q0 Q).

Local Fact exists_wPropP A t T P0 P :
  (exists x : A, wPred t T P0 P x) -> if t then {x | P0 x} else {x & T x}.
Proof.
by case/cid => x /wPropP[]; case t; exists x. Qed.
Canonical
exists_wProp

Internals.exists_wProp : forall [A : Type] [t : bool] [T : A -> Type] [P0 : A -> Prop], (forall x : A, Internals.witnessProp t (P0 x) (T x)) -> Internals.properWitnessProp (if t then {x : A | P0 x} else {x : A & T x}) Internals.exists_wProp is not universe polymorphic Arguments Internals.exists_wProp [A]%_type_scope [t]%_bool_scope [T P0]%_function_scope P%_function_scope Internals.exists_wProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.exists_wProp Declared in library mathcomp.classical.contra, line 748, characters 10-22

A t T P0 P :=
  ProperWitnessProp (@exists_wPropP A t T P0 P).

Local Fact exists2_wPropP A s S P0 P t T Q0 Q (st := if s then t else false) :
    (exists2 x : A, wPred s S P0 P x & wPred t T Q0 Q x) ->
  if st then {x | P0 x & Q0 x} else {x : A & S x & T x}.
Proof.
by case/cid2=> x /wPropP[P0x y] /wPropP[]; case: ifP; exists x. Qed.
Canonical
exists2_wProp

Internals.exists2_wProp : forall [A : Type] [s : bool] [S : A -> Type] [P0 : A -> Prop], (forall x : A, Internals.witnessProp s (P0 x) (S x)) -> forall [t : bool] [T : A -> Type] [Q0 : A -> Prop], (forall x : A, Internals.witnessProp t (Q0 x) (T x)) -> Internals.properWitnessProp (if if s then t else false then {x : A | P0 x & Q0 x} else {x : A & S x & T x}) Internals.exists2_wProp is not universe polymorphic Arguments Internals.exists2_wProp [A]%_type_scope [s]%_bool_scope [S P0]%_function_scope P%_function_scope [t]%_bool_scope [T Q0]%_function_scope Q%_function_scope Internals.exists2_wProp is transparent Expands to: Constant mathcomp.classical.contra.Internals.exists2_wProp Declared in library mathcomp.classical.contra, line 757, characters 10-23

A s S P0 P t T Q0 Q :=
  ProperWitnessProp (@exists2_wPropP A s S P0 P t T Q0 Q).

## User lemmas and tactics for proof by contradiction and contraposition.

Helper lemmas: - push_goal_copy makes a copy of the goal that can then be matched with witnessedType and negatedProp instances to generate a contradiction assuption, without disturbing the original form of the goal. - assume_not_with turns the copy generated by push_identity into an equivalent negative assumption, which can then be simplified using the lax_notP and lax_witness views. - absurd and absurdW replace the goal with False; absurdW does this under an assumption, and is used to weaken proof-by-assuming-negation to proof-by-contradiction. - contra_Type converts an arbitrary function goal (with assumption and conclusion in Type) to an equivalent contrapositive Prop implication. - contra_notP simplifies a contrapositive ~ Q -> ~ P goal using negatedProp instances.

Local Fact push_goal_copy {T} : ((T -> T) -> T) -> T
Proof.
exact. Qed.
Local Fact assume_not_with {R P T} : (~ P -> R) -> (wType P T -> R) -> R.
Proof.
by move=> nP_T T_R; have [/T|] := asboolP P. Qed.

Local Fact absurdW {S T} : (S -> False) -> S -> T
Proof.
by []. Qed.

Local Fact contra_Type {P Q S T} : (~ Q -> ~ P) -> wType P S -> wType Q T.
Proof.
by rewrite implyNN => P_Q /wTypeP/P_Q/T. Qed.

Local Fact contra_notP tP tQ (nP nQ : Prop) P Q :
  (nP -> nQ) -> (~ nProp tP nP P -> ~ nProp tQ nQ Q).
Proof.
by rewrite 2!lax_notE. Qed.

End Internals.
Import Internals.
#[warnings="-user-warn"] Definition
notP

notP : forall {nP : Prop} {P : negatedProp false nP}, move_view (~ P) nP notP is not universe polymorphic Arguments notP {nP}%_type_scope {P} notP is transparent Expands to: Constant mathcomp.classical.contra.Internals.notP Declared in library mathcomp.classical.contra, line 275, characters 11-15

:= @Internals.notP.
Hint View for move/ move_viewP|2.
Hint View for move/ Internals.equivT_LR|2 Internals.equivT_RL|2.
Hint View for apply/ Internals.equivT_RL|2 Internals.equivT_LR|2.
Export (canonicals) Internals.

Lemma and tactic assume_not: add a goal negation assumption. The tactic also works for goals in Type, simplifies the added assumption, and exposes its top-level constructive content.

Lemma assume_not {P} : (~ P -> P) -> P
Proof.
by rewrite implyNp orB. Qed.
Ltac assume_not :=
  apply: Internals.push_goal_copy; apply: Internals.assume_not_with
    => /Internals.lax_notP-/Internals.lax_witness.

Lemma and tactic absurd_not: proof by contradiction. Same as assume_not, but the goal is erased and replaced by False. Caveat: absurd_not cannot be used as a move/ view because its conclusion is indeterminate. The more general notP defined above can be used instead.
Lemma absurd_not {P} : (~ P -> False) -> P
Proof.
#[warnings="-user-warn"] by move/Internals.notP. Qed.
Ltac absurd_not := assume_not; apply: Internals.absurdW.

Tactic contra: proof by contraposition. Assume the negation of the goal conclusion, and prove the negation of a given assumption. The defective form contra (which can also be written contrapose) expects the assumption to be pushed on the goal which thus has the form assumption -> conclusion. As with assume_not, contra allows both assumption and conclusion to be in Type, simplifies the negation of both assumption and conclusion, and exposes the constructive contents of the negated conclusion. The contra tactic also supports a limited form of the ':' discharge pseudo tactical, whereby contra: <d-items> means move: <d-items>; contra. The only <d-items> allowed are one term, possibly preceded by a clear switch.

Ltac contrapose :=
  apply: Internals.contra_Type;
  apply: Internals.contra_notP => /Internals.lax_witness.
Tactic Notation "contra" := contrapose.
Tactic Notation "contra" ":" constr(H) := move: (H); contra.
Tactic Notation "contra" ":" ident(H) := move: H; contra.
Tactic Notation "contra" ":" "{" hyp_list(Hs) "}" constr(H) :=
  contra: (H); clear Hs.
Tactic Notation "contra" ":" "{" hyp_list(Hs) "}" ident(H) :=
  contra: H; clear Hs.
Tactic Notation "contra" ":" "{" "-" "}" constr(H) := contra: (H).

Lemma and tactic absurd: proof by contradiction. The defective form of the lemma simply replaces the entire goal with False (just as the Ltac exfalso), leaving the user to derive a contradiction from the assumptions. The ':' form absurd: <d-items> replaces the goal with the negation of the (single) <d-item> (as with contra:, a clear switch is also allowed. Finally the Ltac absurd term form is also supported.

Lemma absurd T : False -> T
Proof.
by []. Qed.
Tactic Notation (at level 0) "absurd" := apply absurd.
Tactic Notation (at level 0) "absurd" constr(P) := have []: ~ P.
Tactic Notation "absurd" ":" constr(H) := absurd; contra: (H) => _.
Tactic Notation "absurd" ":" ident(H) := absurd; contra: H => _.
Tactic Notation "absurd" ":" "{" hyp_list(Hs) "}" constr(H) :=
  absurd: (H) => _; clear Hs.
Tactic Notation "absurd" ":" "{" hyp_list(Hs) "}" ident(H) :=
  absurd: H => _; clear Hs.