2

I'm trying to prove (n : ℕ) → ∃[ m ] n * n ≡ 3 * m + 2 → ⊥. Typically I would prove this by rewriting it in terms of congruence, and then splitting on each case. There doesn't seem to be a modular arithmetic module in agda-stdlib. How should I implement modular arithmetic or approach this kind of problem without modular arithmetic?

Edit: there has been discussion in the comments that is not quite precise enough to lead me to an answer, so in the hopes of clarifying what cannot fit in the word count I am dumping my various attempts at this problem, some of which inspired by things in the comments.

open Data.Nat.Divisibility.Core
open Data.Nat.Base
open Relation.Binary.Core
open Level using (0ℓ)
open Relation.Binary.PropositionalEquality
open Data.Empty
open Relation.Nullary
open Data.Product using (Σ; _,_; ∃; Σ-syntax; ∃-syntax)
open Relation.Binary.PropositionalEquality.≡-Reasoning
open Data.Nat.Solver
open +-*-Solver

data Z/3 : (n : ℕ) → Set where
  Z/3₀ : (n : ℕ) → ∃[ m ] n ≡ 3 * m → Z/3 n
  Z/3₁ : (n : ℕ) → ∃[ m ] n ≡ 3 * m + 1 → Z/3 n
  Z/3₂ : (n : ℕ) → ∃[ m ] n ≡ 3 * m + 2 → Z/3 n

data _≋_ : Rel ℕ 0ℓ where
  3∣|a-b| : ∀ {a b : ℕ} → 3 ∣ ∣ a - b ∣ → a ≋ b

q' : {a : ℕ} → (2 ≋ ((a + 3) * (a + 3))) → (∃[ a' ] 2 ≋ (a' * a'))
q' = {!!}

qq : (n : ℕ) → Z/3 (n * n)
qq zero = Z/3₀ zero (zero , refl)
qq (suc zero) = Z/3₁ 1 (zero , refl)
qq (suc (suc zero)) = Z/3₁ 4 (1 , refl)
qq (suc (suc (suc n))) = Z/3₁ ((3 + n) * (3 + n)) ({!!} , {!!})

q'' : (n : ℕ) → ∃[ m ] n * n ≡ 3 * m + 2 → ⊥
q'' zero (zero , ())
q'' zero (suc fst , ())
q'' (suc zero) (suc zero , ())
q'' (suc zero) (suc (suc fst) , ())
q'' (suc (suc zero)) (suc (suc (suc (suc zero))) , ())
q'' (suc (suc zero)) (suc (suc (suc (suc (suc fst)))) , ())
q'' (suc (suc (suc n))) (suc fst , snd) = q'' n ({!!} , {!!})

sq : {a : ℕ} → Z/3 a →  Z/3 (a * a)
sq (Z/3₀ n (m , p)) = Z/3₀ (n * n) (3 * m * m , q) where
  q =
    begin
      n * n
    ≡⟨ cong (λ e → e * n) p ⟩
      (3 * m) * n
    ≡⟨ cong (λ e → (3 * m) * e) p ⟩
      (3 * m) * (3 * m)
    ≡⟨ solve 1 (λ m' → (con 3 :* m') :* (con 3 :* m') := con 3 :* m' :* m' :+ (con 3 :* m' :* m' :+ (con 3 :* m' :* m' :+ con zero))) refl m ⟩
      3 * m * m + (3 * m * m + (3 * m * m + zero))
    ∎
    -- (3 * b + 1) * (3 * b + 1)
    -- 9b^2 + 6b + 1
    -- 3(3b^2 + 2b) +1
    -- (3 * b + 2) * (3 * b + 2)
    -- 9b^2 + 12b + 4
    -- 3(3b^2+4b+1) + 1
sq (Z/3₁ n (m , p)) = Z/3₁ (n * n) (3 * m * m + 2 * m , q) where
  q =
    begin
      n * n
    ≡⟨ cong (λ e → e * n) p ⟩
      (3 * m + 1) * n
    ≡⟨ cong (λ e → (3 * m + 1) * e) p ⟩
      (3 * m + 1) * (3 * m + 1)
    ≡⟨ solve 1 (λ m' → (con 3 :* m' :+ con 1) :* (con 3 :* m' :+ con 1) := (m' :+ (m' :+ (m' :+ con 0))) :* m' :+ (m' :+ (m' :+ con 0)) :+ ((m' :+ (m' :+ (m' :+ con 0))) :* m' :+ (m' :+ (m' :+ con 0)) :+ ((m' :+ (m' :+ (m' :+ con 0))) :* m' :+ (m' :+ (m' :+ con 0)) :+ con 0)) :+ con 1 ) refl m ⟩
      (m + (m + (m + 0))) * m + (m + (m + 0)) + ((m + (m + (m + 0))) * m + (m + (m + 0)) + ((m + (m + (m + 0))) * m + (m + (m + 0)) + 0)) + 1
    ∎
sq (Z/3₂ n (m , p)) = Z/3₁ (n * n) (3 * m * m + 4 * m + 1 , {!!})

q : {a : ℕ} → ¬(2 ≋ (a * a))
q {zero} (3∣|a-b| (divides zero ()))
q {zero} (3∣|a-b| (divides (suc quotient) ()))
q {suc zero} (3∣|a-b| (divides zero ()))
q {suc zero} (3∣|a-b| (divides (suc quotient) ()))
q {suc (suc zero)} (3∣|a-b| (divides zero ()))
q {suc (suc zero)} (3∣|a-b| (divides (suc quotient) ()))
q {suc (suc (suc a))} (3∣|a-b| (divides (suc quotient) equality)) = {!!}
Ace shinigami
  • 1,374
  • 2
  • 12
  • 25
  • 1
    Can you start by showing `(n : ℕ) → (∃[ m ] n ≡ 3 * m) ∨ (∃[ m ] n ≡ 3 * m + 1) ∨ (∃[ m ] n ≡ 3 * m + 2)` (which should be provable by induction on `n`) and then split on cases? (I'm not familiar with Agda, so I probably have the syntax wrong here, but I hope the idea is clear.) – Mark Dickinson Oct 10 '22 at 14:57
  • @MarkDickinson I'm not sure how this would help me assuming `v` is a coproduct – Ace shinigami Oct 10 '22 at 15:22
  • 1
    `∨` was supposed to indicate disjunction, and is what I'm used to from other tools (Lean, Coq). I'm not sure of the right way to indicate disjunction in Agda. The statement I wanted to convey is roughly "for any natural number n, either n is a multiple of 3, or it's of the form 3m + 1, or it's of the form 3m + 2". That statement is easily proved by induction, and then you can split on those three cases: if `n = 3m` then `n * n = 9*m*m`; if `n = 3m+1` then `n*n = 9*m*m + 6*m + 1`; etc. – Mark Dickinson Oct 10 '22 at 15:33
  • @MarkDickinson disjunction and coproduct are the same thing – Ace shinigami Oct 10 '22 at 15:35
  • @MarkDickinson this makes sense from a high level, but it gets less clear once you try and implement it. I can see how you get to (n : ℕ) → (∃[ m ] n * n ≡ 3 * m) ∨ (∃[ m ] n * n ≡ 3 * m + 1) ∨ (∃[ m ] n * n ≡ 3 * m + 2), but where you go from there isn't clear – Ace shinigami Oct 10 '22 at 16:03
  • 1
    That's not what I'm suggesting. Note that I have `n`, not `n * n`, in my statement. We have three cases: either `n = 3k` for some natural `k`, or `n = 3k+1`, or `n = 3k+2`. [I'm switching from `m` to `k` to avoid confusion with the `m` in your goal.] If `n = 3k` and `n² = 3m+2` then `9k² = 3m + 2`. Now if you have some basic results about divisibility available, you can deduce that since `3` divides `9k²` and `3` divides `3m` then `3` divides `2`, a contradiction. Similary if `n = 3k+1` and `n² = 3m+2` then `9k² + 6k + 1 = 3m + 2`, so `9k² + 6k = 3m + 1` and we can deduce that `3` divides `1`. – Mark Dickinson Oct 10 '22 at 16:15
  • ... again a contradiction. The last case is similar. – Mark Dickinson Oct 10 '22 at 16:19
  • Wouldn't `Data.Nat.DivMod` qualify as a "modular arithmetic module"? – 123omnomnom Oct 21 '22 at 01:33

1 Answers1

3

Building on Mark's proof outline:

module SOMod where

open import Data.Empty
open import Data.Nat
open import Data.Nat.Properties
open import Data.Nat.DivMod
open import Data.Product
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary.Negation

open ≡-Reasoning

lemma : ∀ m n → (n * n) % 3 ≢ (3 * m + 2) % 3
lemma m n p = contradiction ≡2 (≢2 n)
  where
  ≡2 : ((n % 3) * (n % 3)) % 3 ≡ 2
  ≡2 = begin
    ((n % 3) * (n % 3)) % 3 ≡˘⟨ %-distribˡ-* n n 3 ⟩
    (n * n) % 3             ≡⟨ p ⟩
    (3 * m + 2) % 3         ≡⟨ cong (_% 3) (+-comm (3 * m) 2) ⟩
    (2 + 3 * m) % 3         ≡⟨ cong (λ # → (2 + #) % 3) (*-comm 3 m) ⟩
    (2 + m * 3) % 3         ≡⟨ [m+kn]%n≡m%n 2 m 3 ⟩
    2 % 3                   ≡⟨⟩
    2                       ∎

  ≢2 : ∀ n → ((n % 3) * (n % 3)) % 3 ≢ 2
  ≢2 zero                = λ ()
  ≢2 (suc zero)          = λ ()
  ≢2 (suc (suc zero))    = λ ()
  ≢2 (suc (suc (suc n))) = ≢2 n

proof : ∀ n → ∃[ m ] n * n ≡ 3 * m + 2 → ⊥
proof n (m , p) = contradiction (cong (_% 3) p) (lemma m n)
123omnomnom
  • 294
  • 1
  • 10
  • "Building on Mark's proof outline:" <- Nah, this proof is much cleaner and simpler than the one I was suggesting. Have an upvote. – Mark Dickinson Oct 21 '22 at 17:29