open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl; cong; sym; module ≡-Reasoning) open import Data.Nat using (ℕ; zero; suc; _+_; _*_) open import Data.Nat.Properties using (+-comm; *-comm) open ≡-Reasoning -- Context infix 4 _≤_ data _≤_ : ℕ → ℕ → Set where z≤n : ∀ {n} → zero ≤ n s≤s : ∀ {m n} → m ≤ n → suc m ≤ suc n -- Exercise orderings (practice) ----------------------------------------------- -- Preorder which is not a partial order: -- Consider a directed graph, where n ≤ n' holds if node n' can be reached -- from node n by walking along a path of zero or more edges. -- This relation is -- - reflexive, because each node is reachable from itself by walking along zero -- edges. -- - transitive, because paths can be joined to longer paths. -- - not anti-symmetric: We can have two distinct nodes n and n', where there's -- an edge both from n to n' and from n' to n, i.e. -- n ≤ n' ∧ n' ≤ n does not imply n ≡ n'. -- Partial order which is not a total order: -- The subset-relation ⊆ satisfies this criterion. It is -- - reflexive: ∀ A. A ⊆ A -- - transitive: ∀ A B C. A ⊆ B ∧ B ⊆ C → A ⊆ C -- - anti-symmetric: ∀ A B. A ⊆ B ∧ B ⊆ A → A = B -- but not total: {0} ⊈ {1} and {1} ⊈ {0} -- -- Alternatively, we can obtain such an order by lifting ≤ on ℕ over pairs, i.e. -- (m₁, m₂) ≤' (n₁, n₂) iff m₁ ≤ n₁ ∧ m₂ ≤ n₂. -- This relation is -- - reflexive -- - transitive -- - antisymmetric, because if (m₁, m₂) ≤' (n₁, n₂) and (n₁, n₂) ≤' (m₁, m₂), -- then by definition of ≤' we have m₁ ≤ n₁, n₁ ≤ m₁, m₂ ≤ n₂, n₂ ≤ n₂, -- so by antisymmetry of ≤, we have m₁ = n₁ and m₂ = n₂, which implies -- (m₁, m₂) = (n₁, n₂) -- - not total, because for example neither (1, 2) ≤' (2, 1) nor (2, 1) ≤' (1, 2) -- is true. ≤-refl : ∀ {n} → n ≤ n ≤-refl {zero} = z≤n ≤-refl {suc n} = s≤s ≤-refl ≤-trans : ∀ {m n p} → m ≤ n → n ≤ p → m ≤ p ≤-trans z≤n n≤p = z≤n ≤-trans (s≤s m≤n) (s≤s n≤p) = s≤s (≤-trans m≤n n≤p) -- Exercise ≤-antisym-cases (practice) ----------------------------------------- ≤-antisym : ∀ {m n : ℕ} → m ≤ n → n ≤ m ----- → m ≡ n ≤-antisym z≤n z≤n = refl ≤-antisym (s≤s m≤n) (s≤s n≤m) = cong suc (≤-antisym m≤n n≤m) -- Question: Why can the following cases be omitted? -- -- ≤-antisym z≤n (s≤s n≤m) = ? -- ≤-antisym (s≤s m≤n) z≤n = ? -- -- By looking at the constructors of _≤_ we can see that z≤n requires that -- the left side of the inequality is 0, while s≤s requires that the right side -- of the inequality is the successor of something: -- -- data _≤_ : ℕ → ℕ → Set where -- z≤n : ∀ {n} → zero ≤ n -- s≤s : ∀ {m n} → m ≤ n → suc m ≤ suc n -- -- If we look at ≤-antisym, then we can see that the parameters `m ≤ n` and -- `n ≤ m` share the variable `m`. -- Hence, if we know that the first parameter of type `m ≤ n` is constructed via -- `z≤n`, then `m` must be 0, so the second paramter of type `n ≤ m` is actually -- of type `n ≤ 0`, which can not be constructed by `s≤s`, since `0` is not -- the successor of something. -- -- The second case can be omitted for the same reason. -- Note: Here we can use parameters (and not indices) -- because m and n are constant across the constructors. data Total (m n : ℕ) : Set where forward : m ≤ n --------- → Total m n flipped : n ≤ m --------- → Total m n ≤-total : ∀ (m n : ℕ) → Total m n ≤-total zero n = forward z≤n ≤-total (suc m) zero = flipped z≤n ≤-total (suc m) (suc n) with ≤-total m n ... | forward m≤n = forward (s≤s m≤n) ... | flipped n≤m = flipped (s≤s n≤m) +-monoʳ-≤ : ∀ {n p q} → p ≤ q → n + p ≤ n + q +-monoʳ-≤ {zero} p≤q = p≤q +-monoʳ-≤ {suc n} p≤q = s≤s (+-monoʳ-≤ p≤q) +-monoˡ-≤ : ∀ {m n p} → m ≤ n → m + p ≤ n + p -- +-monoˡ-≤ {m} {n} {p} m≤n rewrite +-comm m p | +-comm n p = +-monoʳ-≤ m≤n +-monoˡ-≤ {m} {n} {p} m≤n = subst-≤ (+-comm p m) (+-comm p n) (+-monoʳ-≤ m≤n) where subst-≤ : ∀ {m n p q} → m ≡ n → p ≡ q → m ≤ p → n ≤ q subst-≤ refl refl m≤p = m≤p +-mono-≤ : ∀ {m n p q} → m ≤ n → p ≤ q → m + p ≤ n + q +-mono-≤ m≤n p≤q = ≤-trans (+-monoˡ-≤ m≤n) (+-monoʳ-≤ p≤q) -- Exercise *-mono-≤ (stretch) ------------------------------------------------- *-mono-≤ : ∀ {m n p q : ℕ} → m ≤ n → p ≤ q ------------- → m * p ≤ n * q *-mono-≤ z≤n p≤q = z≤n *-mono-≤ (s≤s m≤n) p≤q = +-mono-≤ p≤q (*-mono-≤ m≤n p≤q) infix 4 _<_ data _<_ : ℕ → ℕ → Set where z_ _>_ : ℕ → ℕ → Set m > n = n < m module Variant1 where data <-Trichotomy (m n : ℕ) : Set where tri-< : m < n → <-Trichotomy m n tri-≡ : m ≡ n → <-Trichotomy m n tri-> : m > n → <-Trichotomy m n <-trichotomy : ∀ (m n : ℕ) → <-Trichotomy m n <-trichotomy zero zero = tri-≡ refl <-trichotomy zero (suc n) = tri-< z z m>n = tri-> (sn) module Variant2 where -- This type describes the disjunction of two propositions A ∨ B, and will -- be covered in Chapter 'Connectives'. A proof of A ∨ B is either a proof -- of A (via constructor inj₁) or a proof of B (via constructor inj₂). infixr 1 _∨_ data _∨_ (A : Set) (B : Set) : Set where inj₁ : A → A ∨ B inj₂ : B → A ∨ B -- This type describes the trichotomy property for an arbitrary binary -- relation R. -- `Trichotomy _<_` is equivalent to -- `∀ (m n : ℕ) → <-Trichotomy m n` from `Variant1`. Trichotomy : ∀ {A : Set} → (A → A → Set) → Set Trichotomy {A} R = ∀ (x y : A) → R x y ∨ x ≡ y ∨ R y x -- The actual proof is the same as in `Variant1`, except that we now -- use combinations of `inₗ` and `inᵣ` instead of `tri-<`, `tri-≡`, and `tri->`, -- which makes it less readable on first sight. <-trichotomy : Trichotomy _>_ <-trichotomy zero zero = inj₂ (inj₁ refl) <-trichotomy zero (suc n) = inj₂ (inj₂ zm) = inj₂ (inj₂ (sm)) -- Exercise +-mono-< (practice) ------------------------------------------------ +-monoʳ-< : ∀ {m p q : ℕ} → p < q → m + p < m + q +-monoʳ-< {zero} p