CSCI B629 Mechanized Proofs for PL Metatheory

module lecture-notes-Relations where
open import Data.Nat
open import Data.Nat.Properties
open import Relation.Binary.PropositionalEquality using (_≡_; refl; sym; cong; cong₂)

Predicates, Inductively Defined

Recall that a predicate is a statement involving a variable that can be true or false. In math, a predicate P is often represented as a Boolean-valued function, so P x ≡ true if the statement is true of the object x and P x ≡ false if it is false.

In Agda, we often uses datatypes to represent predicates. We define a datatype named P that is parameterized over the appropriate type, the below. We then say that P x is true if we can construct an object of type P x.

data Even : ℕ → Set where
  even-0 : Even 0
  even-+2 : (n : ℕ) → Even n → Even (2 + n)

The following constructs a value of type Even 2, so it’s true that 2 is even.

_ : Even 2
_ = even-+2 0 even-0

Similarly for the number 4.

_ : Even 4
_ = even-+2 2 (even-+2 0 even-0)

Taking this process to its logical conclusion, we prove that every number of the form 2 * n, or equivalently n + n, is even. We’ll do this by defining a recursive function even-dub that takes a number n and produces an object of type Even (n + n).

even-dub : (n : ℕ) → Even (n + n)
even-dub zero = even-0
even-dub (suc n) rewrite +-comm n (suc n) =
    let IH : Even (n + n)
        IH = even-dub n in
    even-+2 (n + n) IH 

If we know a number is Even, then it must have been generated by one of the two rules. We can use the pattern matching associated with function definitions to reason backwards about the rules. For example, if Even m and m is not zero, then there is a number n two less-than m that is also even.

open import Relation.Binary.PropositionalEquality using (_≢_)
open import Data.Empty using (⊥-elim)
inv-Even : (n m : ℕ) → Even m → m ≢ 0 → suc (suc n) ≡ m → Even n
inv-Even n .0 even-0 m≢0 n+2≡m = ⊥-elim (m≢0 refl)
inv-Even n .(suc (suc n')) (even-+2 n' even-m) m≢0 refl = even-m

Relations, Inductively Defined

Like predicates, relations can be represented in Agda with data types, they just have more parameters.

One of the most important relations in Number Theory is the divides (evenly) relation. We say that m divides n if some number of copies of m can be concatenated (added) to form n.

data _div_ : ℕ → ℕ → Set where
  div-refl : (m : ℕ) → m ≢ 0 → m div m
  div-step : (n m : ℕ) → m div n → m div (m + n)

For example, 3 div 3, 3 div 6, and 3 div 6.

3-div-3 : 3 div 3
3-div-3 = div-refl 3 λ ()

3-div-6 : 3 div 6
3-div-6 = div-step 3 3 3-div-3

3-div-9 : 3 div 9
3-div-9 = div-step 6 3 3-div-6

A common property of relations is transitivity. Indeed, the div relation is transitive. To prove this we need the following standard fact about divides and addition.

div-+ : ∀ l m n → l div m → l div n → l div (m + n)
div-+ l .l n (div-refl .l l≢0) ln = div-step n l ln
div-+ l .(l + m) n (div-step m .l lm) ln
   rewrite +-assoc l m n =
   let IH = div-+ l m n lm ln in
   div-step (m + n) l IH

We prove that div is transitive by induction on the derivation of m div n.

div-trans : ∀ l m n → l div m → m div n → l div n
div-trans l m .m lm (div-refl .m m≢0) = lm
div-trans l m .(m + n) lm (div-step n .m mn) =
  let IH:ln = div-trans l m n lm mn in
  div-+ l m n lm IH:ln