Skip to content

[ refactor ] make contradiction and friends entirely definitionally proof-irrelevant #2802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
86 changes: 7 additions & 79 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Version 2.4-dev
Version 3.0-dev
===============

The library has been tested using Agda 2.8.0.
Expand All @@ -9,97 +9,25 @@ Highlights
Bug-fixes
---------

* Fix a type error in `README.Data.Fin.Relation.Unary.Top` within the definition of `>-weakInduction`.

Non-backwards compatible changes
--------------------------------

Minor improvements
------------------

* The type of `Relation.Nullary.Negation.Core.contradiction-irr` has been further
weakened so that the negated hypothesis `¬ A` is marked as irrelevant. This is
safe to do, in view of `Relation.Nullary.Recomputable.Properties.¬-recompute`.
* In `Relation.Nullary.Negation.Core`, all the various types of `contradiction`
have been weakened as far as possible to make their arguments definitionally
proof-irrelevant. As a consequence, there is no longer any need for the
separate v2.4 `contradiction-irr`.

* Refactored usages of `+-∸-assoc 1` to `∸-suc` in:
```agda
README.Data.Fin.Relation.Unary.Top
Algebra.Properties.Semiring.Binomial
Data.Fin.Subset.Properties
Data.Nat.Binary.Subtraction
Data.Nat.Combinatorics
```
Other major improvements
------------------------

Deprecated modules
------------------

Deprecated names
----------------

* In `Algebra.Properties.CommutativeSemigroup`:
```agda
interchange ↦ medial
```

New modules
-----------

* `Data.List.Relation.Binary.Permutation.Algorithmic{.Properties}` for the Choudhury and Fiore definition of permutation, and its equivalence with `Declarative` below.

* `Data.List.Relation.Binary.Permutation.Declarative{.Properties}` for the least congruence on `List` making `_++_` commutative, and its equivalence with the `Setoid` definition.

Additions to existing modules
-----------------------------

* In `Algebra.Properties.RingWithoutOne`:
```agda
[-x][-y]≈xy : ∀ x y → - x * - y ≈ x * y
```

* In `Data.Fin.Permutation.Components`:
```agda
transpose[i,i,j]≡j : (i j : Fin n) → transpose i i j ≡ j
transpose[i,j,j]≡i : (i j : Fin n) → transpose i j j ≡ i
transpose[i,j,i]≡j : (i j : Fin n) → transpose i j i ≡ j
transpose-transpose : transpose i j k ≡ l → transpose j i l ≡ k
```

* In `Data.Fin.Properties`:
```agda
≡-irrelevant : Irrelevant {A = Fin n} _≡_
≟-≡ : (eq : i ≡ j) → (i ≟ j) ≡ yes eq
≟-≡-refl : (i : Fin n) → (i ≟ i) ≡ yes refl
≟-≢ : (i≢j : i ≢ j) → (i ≟ j) ≡ no i≢j
```

* In `Data.Nat.Properties`:
```agda
≟-≢ : (m≢n : m ≢ n) → (m ≟ n) ≡ no m≢n
∸-suc : m ≤ n → suc n ∸ m ≡ suc (n ∸ m)
```

* In `Data.Vec.Properties`:
```agda
padRight-lookup : (m≤n : m ≤ n) (a : A) (xs : Vec A m) (i : Fin m) → lookup (padRight m≤n a xs) (inject≤ i m≤n) ≡ lookup xs i

padRight-map : (f : A → B) (m≤n : m ≤ n) (a : A) (xs : Vec A m) → map f (padRight m≤n a xs) ≡ padRight m≤n (f a) (map f xs)

padRight-zipWith : (f : A → B → C) (m≤n : m ≤ n) (a : A) (b : B) (xs : Vec A m) (ys : Vec B m) →
zipWith f (padRight m≤n a xs) (padRight m≤n b ys) ≡ padRight m≤n (f a b) (zipWith f xs ys)

padRight-zipWith₁ : (f : A → B → C) (o≤m : o ≤ m) (m≤n : m ≤ n) (a : A) (b : B) (xs : Vec A m) (ys : Vec B o) →
zipWith f (padRight m≤n a xs) (padRight (≤-trans o≤m m≤n) b ys) ≡
padRight m≤n (f a b) (zipWith f xs (padRight o≤m b ys))

padRight-take : (m≤n : m ≤ n) (a : A) (xs : Vec A m) .(n≡m+o : n ≡ m + o) → take m (cast n≡m+o (padRight m≤n a xs)) ≡ xs

padRight-drop : (m≤n : m ≤ n) (a : A) (xs : Vec A m) .(n≡m+o : n ≡ m + o) → drop m (cast n≡m+o (padRight m≤n a xs)) ≡ replicate o a

padRight-updateAt : (m≤n : m ≤ n) (x : A) (xs : Vec A m) (f : A → A) (i : Fin m) →
updateAt (padRight m≤n x xs) (inject≤ i m≤n) f ≡ padRight m≤n x (updateAt xs i f)
```

* In `Relation.Nullary.Negation.Core`
```agda
¬¬-η : A → ¬ ¬ A
```
6 changes: 6 additions & 0 deletions doc/style-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -717,3 +717,9 @@ used successfully in PR
systematic for `Nary` relations in PR
[#811](https://github.com/agda/agda-stdlib/pull/811)

## Prefer use of `Relation.Nullary.Negation.Core.contradiction`

Where possible use `contradiction` between two explicit arguments rather
than appealing to the lower-level `Data.Empty.⊥-elim`. This provides
clearer documentation for readers of the code, but also permits a wider
range of application, thanks to its arguments being made proof-irrelevant.
2 changes: 1 addition & 1 deletion src/Algebra/Module/Morphism/ModuleHomomorphism.agda
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ x≈0⇒fx≈0 {x} x≈0 = begin⟨ B.≈ᴹ-setoid ⟩
B.0ᴹ ∎

fx≉0⇒x≉0 : ∀ {x} → f x B.≉ᴹ B.0ᴹ → x A.≉ᴹ A.0ᴹ
fx≉0⇒x≉0 = contraposition x≈0⇒fx≈0
fx≉0⇒x≉0 x≈0 = contraposition x≈0⇒fx≈0 x≈0

-- Zero is a unique output of non-trivial (i.e. - ≉ `const 0`) linear map.
x≉0⇒f[x]≉0 : ∀ {x} → NonTrivial x → x A.≉ᴹ A.0ᴹ → f x B.≉ᴹ B.0ᴹ
Expand Down
9 changes: 6 additions & 3 deletions src/Algebra/Module/Properties/Semimodule.agda
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ module Algebra.Module.Properties.Semimodule
(semimod : Semimodule semiring m ℓm)
where

open import Relation.Nullary.Negation using (contraposition)

open CommutativeSemiring semiring
open Semimodule semimod
open import Relation.Binary.Reasoning.Setoid ≈ᴹ-setoid
open import Relation.Nullary.Negation using (contraposition)

------------------------------------------------------------------------

x≈0⇒x*y≈0 : ∀ {x y} → x ≈ 0# → x *ₗ y ≈ᴹ 0ᴹ
x≈0⇒x*y≈0 {x} {y} x≈0 = begin
Expand All @@ -34,7 +37,7 @@ y≈0⇒x*y≈0 {x} {y} y≈0 = begin
0ᴹ ∎

x*y≉0⇒x≉0 : ∀ {x y} → x *ₗ y ≉ᴹ 0ᴹ → x ≉ 0#
x*y≉0⇒x≉0 = contraposition x≈0⇒x*y≈0
x*y≉0⇒x≉0 x≈0 = contraposition x≈0⇒x*y≈0 x≈0

x*y≉0⇒y≉0 : ∀ {x y} → x *ₗ y ≉ᴹ 0ᴹ → y ≉ᴹ 0ᴹ
x*y≉0⇒y≉0 = contraposition y≈0⇒x*y≈0
x*y≉0⇒y≉0 y≈0 = contraposition y≈0⇒x*y≈0 y≈0
Original file line number Diff line number Diff line change
Expand Up @@ -409,17 +409,17 @@ module Antisymmetry
length (y ∷ ys₁) ≤⟨ length-mono-≤ ss ⟩
length zs ≤⟨ ℕ.n≤1+n (length zs) ⟩
length (z ∷ zs) ≤⟨ length-mono-≤ rs ⟩
length ys₁ ∎) $ ℕ.<-irrefl ≡.refl
length ys₁ ∎) (ℕ.<-irrefl ≡.refl)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps don't roll in such pure, non-breaking style changes in to something breaking and make a separate (if tiny) PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a style change; it's yet another 'feature' of irrelevant function spaces: _$_ is no longer well-typed!

antisym (_∷ʳ_ {xs} {ys₁} y rs) (_∷_ {y} {ys₂} {z} {zs} s ss) =
contradiction (begin
length (z ∷ zs) ≤⟨ length-mono-≤ rs ⟩
length ys₁ ≤⟨ length-mono-≤ ss ⟩
length zs ∎) $ ℕ.<-irrefl ≡.refl
length zs ∎) (ℕ.<-irrefl ≡.refl)
antisym (_∷_ {x} {xs} {y} {ys₁} r rs) (_∷ʳ_ {ys₂} {zs} z ss) =
contradiction (begin
length (y ∷ ys₁) ≤⟨ length-mono-≤ ss ⟩
length xs ≤⟨ length-mono-≤ rs ⟩
length ys₁ ∎) $ ℕ.<-irrefl ≡.refl
length ys₁ ∎) (ℕ.<-irrefl ≡.refl)

open Antisymmetry public

Expand Down
4 changes: 2 additions & 2 deletions src/Data/List/Relation/Unary/Unique/Setoid/Properties.agda
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ module _ (S : Setoid a ℓ₁) (R : Setoid b ℓ₂) where

map⁺ : ∀ {f} → (∀ {x y} → f x ≈₂ f y → x ≈₁ y) →
∀ {xs} → Unique S xs → Unique R (map f xs)
map⁺ inj xs! = AllPairs.map⁺ (AllPairs.map (contraposition inj) xs!)
map⁺ inj xs! = AllPairs.map⁺ (AllPairs.map (λ x≈y → contraposition inj x≈y) xs!)

map⁻ : ∀ {f} → Congruent _≈₁_ _≈₂_ f →
∀ {xs} → Unique R (map f xs) → Unique S xs
map⁻ cong fxs! = AllPairs.map (contraposition cong) (AllPairs.map⁻ fxs!)
map⁻ cong fxs! = AllPairs.map (λ fx≉fy → contraposition cong fx≉fy) (AllPairs.map⁻ fxs!)

------------------------------------------------------------------------
-- ++
Expand Down
8 changes: 5 additions & 3 deletions src/Data/Nat/Primality.agda
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ open import Function.Base using (flip; _∘_; _∘′_)
open import Function.Bundles using (_⇔_; mk⇔)
open import Relation.Nullary.Decidable as Dec
using (yes; no; from-yes; from-no; ¬?; _×-dec_; _⊎-dec_; _→-dec_; decidable-stable)
open import Relation.Nullary.Negation.Core using (¬_; contradiction; contradiction₂)
open import Relation.Nullary.Negation.Core
using (¬_; contradiction; contradiction′; contradiction₂)
open import Relation.Unary using (Pred; Decidable)
open import Relation.Binary.Core using (Rel)
open import Relation.Binary.PropositionalEquality.Core
Expand Down Expand Up @@ -347,8 +348,9 @@ irreducible[2] {suc _} d∣2 with ∣⇒≤ d∣2
... | s<s z<s = inj₂ refl

irreducible⇒nonZero : Irreducible n → NonZero n
irreducible⇒nonZero {zero} = flip contradiction ¬irreducible[0]
irreducible⇒nonZero {suc _} _ = _
irreducible⇒nonZero {zero} irreducible[0] =
contradiction′ ¬irreducible[0] irreducible[0]
irreducible⇒nonZero {suc _} _ = _

irreducible? : Decidable Irreducible
irreducible? zero = no ¬irreducible[0]
Expand Down
2 changes: 1 addition & 1 deletion src/Data/Vec/Relation/Unary/Unique/Setoid/Properties.agda
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module _ (S : Setoid a ℓ₁) (R : Setoid b ℓ₂) where

map⁺ : ∀ {f} → (∀ {x y} → f x ≈₂ f y → x ≈₁ y) →
∀ {n xs} → Unique S {n} xs → Unique R {n} (map f xs)
map⁺ inj xs! = AllPairs.map⁺ (AllPairs.map (contraposition inj) xs!)
map⁺ inj xs! = AllPairs.map⁺ (AllPairs.map (λ x≈y → contraposition inj x≈y) xs!)

------------------------------------------------------------------------
-- take & drop
Expand Down
10 changes: 5 additions & 5 deletions src/Relation/Nullary/Negation.agda
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ open import Relation.Nullary.Negation.Core public
-- ⊥).

call/cc : ((A → Whatever) → DoubleNegation A) → DoubleNegation A
call/cc hyp ¬a = hyp (flip contradiction ¬a) ¬a
call/cc hyp ¬a = hyp (λ a → contradiction a ¬a) ¬a

-- The "independence of premise" rule, in the double-negation monad.
-- It is assumed that the index set (A) is inhabited.
Expand All @@ -81,17 +81,17 @@ independence-of-premise : A → (B → Σ A P) → DoubleNegation (Σ[ x ∈ A ]
independence-of-premise {A = A} {B = B} {P = P} q f = ¬¬-map helper ¬¬-excluded-middle
where
helper : Dec B → Σ[ x ∈ A ] (B → P x)
helper (yes p) = Product.map₂ const (f p)
helper (no ¬p) = (q , flip contradiction ¬p)
helper (yes b) = Product.map₂ const (f b)
helper (no ¬b) = (q , λ b → contradiction b ¬b)

-- The independence of premise rule for binary sums.

independence-of-premise-⊎ : (A → B ⊎ C) → DoubleNegation ((A → B) ⊎ (A → C))
independence-of-premise-⊎ {A = A} {B = B} {C = C} f = ¬¬-map helper ¬¬-excluded-middle
where
helper : Dec A → (A → B) ⊎ (A → C)
helper (yes p) = Sum.map const const (f p)
helper (no ¬p) = inj₁ (flip contradiction ¬p)
helper (yes a) = Sum.map const const (f a)
helper (no ¬a) = inj₁ λ a → contradiction a ¬a

private

Expand Down
43 changes: 21 additions & 22 deletions src/Relation/Nullary/Negation/Core.agda
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ infix 3 ¬_
¬_ : Set a → Set a
¬ A = A → ⊥

-- Note the following use of flip:
private
note : (A → ¬ B) → B → ¬ A
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're going to bother to move this to the top of the file, maybe also document where the 'note' is useful in reading below?

Copy link
Contributor Author

@jamesmckinna jamesmckinna Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well... for starters, breaking, so code motion ought to be permissible?

Secondly, more importantly, some of the properties in this module (eg _¬-⊎_ and ¬¬-η) are consequences of the minimal logic interpretation of ¬_, and they are conceptually prior to the ones which make genuine use of ex falso ⊥-elim(-irr)... so it made sense to me that they occur first in the module. Cf. #2803

As to the best way to document this separation of concerns, suggestions welcome!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe one way to resolve this is to interpolate a v2.4 non-breaking PR which reorganises Negation.Core to distinguish

  • definition
  • consequences/properties per minimal logic: note, ¬¬-η, contra-diagonal...
  • consequences/properties per use of ex falso

rather than try to do this as part of this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And/or add some text to #2798 to emphasise the distinction?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See: #2805

note = flip

------------------------------------------------------------------------
-- Relationship to sum

infixr 1 _¬-⊎_
_¬-⊎_ : ¬ A → ¬ B → ¬ (A ⊎ B)
_¬-⊎_ = [_,_]

------------------------------------------------------------------------
-- Stability.

Expand All @@ -42,27 +54,20 @@ DoubleNegation A = ¬ ¬ A
Stable : Set a → Set a
Stable A = ¬ ¬ A → A

------------------------------------------------------------------------
-- Relationship to sum

infixr 1 _¬-⊎_
_¬-⊎_ : ¬ A → ¬ B → ¬ (A ⊎ B)
_¬-⊎_ = [_,_]

------------------------------------------------------------------------
-- Uses of negation

contradiction-irr : .A → .(¬ A) → Whatever
contradiction-irr a ¬a = ⊥-elim-irr (¬a a)
contradiction : .A → .(¬ A) → Whatever
contradiction a ¬a = ⊥-elim-irr (¬a a)

contradiction : A¬ A → Whatever
contradiction a ¬a = contradiction-irr a ¬a
contradiction : .(¬ A).A → Whatever
contradiction′ ¬a a = ⊥-elim-irr (¬a a)

contradiction₂ : A ⊎ B → ¬ A → ¬ B → Whatever
contradiction₂ : A ⊎ B → .(¬ A).(¬ B) → Whatever
contradiction₂ (inj₁ a) ¬a ¬b = contradiction a ¬a
contradiction₂ (inj₂ b) ¬a ¬b = contradiction b ¬b

contraposition : (A → B) → ¬ B → ¬ A
contraposition : (A → B) → .(¬ B) → ¬ A
contraposition f ¬b a = contradiction (f a) ¬b

-- Self-contradictory propositions are false by 'diagonalisation'
Expand All @@ -72,17 +77,11 @@ contra-diagonal self a = self a a

-- Everything is stable in the double-negation monad.
stable : ¬ ¬ Stable A
stable ¬[¬¬a→a] = ¬[¬¬a→a] (contradiction (¬[¬¬a→a] ∘ const))
stable ¬[¬¬a→a] = ¬[¬¬a→a] λ ¬¬a → contradiction (¬[¬¬a→a] ∘ const) ¬¬a

-- Negated predicates are stable.
negated-stable : Stable (¬ A)
negated-stable ¬¬¬a a = ¬¬¬a (contradiction a)
negated-stable ¬¬¬a a = ¬¬¬a λ ¬a → contradiction a ¬a

¬¬-map : (A → B) → ¬ ¬ A → ¬ ¬ B
¬¬-map f = contraposition (contraposition f)

-- Note also the following use of flip:
private
note : (A → ¬ B) → B → ¬ A
note = flip

¬¬-map f ¬¬a = contraposition (λ ¬b → contraposition f ¬b) ¬¬a
4 changes: 2 additions & 2 deletions src/Relation/Nullary/Reflects.agda
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ open import Data.Empty.Polymorphic using (⊥)
open import Level using (Level)
open import Function.Base using (_$_; _∘_; const; id)
open import Relation.Nullary.Negation.Core
using (¬_; contradiction-irr; contradiction; _¬-⊎_)
using (¬_; contradiction; _¬-⊎_)
open import Relation.Nullary.Recomputable as Recomputable using (Recomputable)

private
Expand Down Expand Up @@ -61,7 +61,7 @@ invert (ofⁿ ¬a) = ¬a

recompute : ∀ {b} → Reflects A b → Recomputable A
recompute (ofʸ a) _ = a
recompute (ofⁿ ¬a) a = contradiction-irr a ¬a
recompute (ofⁿ ¬a) a = contradiction a ¬a

recompute-constant : ∀ {b} (r : Reflects A b) (p q : A) →
recompute r p ≡ recompute r q
Expand Down