Skip to content

Add more Data.Rational.Properties#2996

Open
kleinreact wants to merge 1 commit into
agda:masterfrom
kleinreact:more-rational-properties
Open

Add more Data.Rational.Properties#2996
kleinreact wants to merge 1 commit into
agda:masterfrom
kleinreact:more-rational-properties

Conversation

@kleinreact

@kleinreact kleinreact commented May 8, 2026

Copy link
Copy Markdown

I needed the following common properties over normalized rationals for some proofs, but found them to be missing in the library.

↥[i/1]≡i        : (i : ℤ)  ↥ (i / 1) ≡ i
↧ₙ[i/1]≡1       : (i : ℤ)  ↧ₙ (i / 1) ≡ 1
n/n≡1           :  (n : ℕ) .{{_ : ℕ.NonZero n}}  + n / n ≡ 1ℚ
-i/n≡-[i/n]     :  (i : ℤ) (n : ℕ) .{{_ : ℕ.NonZero n}} 
                  ℤ.- i / n ≡ - (i / n)
*-cancelˡ-/     :  p {q r} .{{_ : ℕ.NonZero r}} .{{_ : ℕ.NonZero (p ℕ.* r)}} 
                  (+ p ℤ.* q) / (p ℕ.* r) ≡ q / r
*-cancelʳ-/     :  p {q r} .{{_ : ℕ.NonZero r}} .{{_ : ℕ.NonZero (r ℕ.* p)}} 
                  (q ℤ.* + p) / (r ℕ.* p) ≡ q / r
i/n+j/n≡[i+j]/n :  (i j : ℤ) (n : ℕ) .{{_ : ℕ.NonZero n }} 
                  i / n + j / n ≡ (i ℤ.+ j) / n

Hence, my proposal to add them with this PR.

@kleinreact kleinreact force-pushed the more-rational-properties branch from 0ab7060 to e4da88b Compare May 8, 2026 12:40
↥p/↧p≡p (mkℚ -[1+ n ] d-1 prf) = cong (-_) (normalize-coprime prf)

↥[i/1]≡i : (i : ℤ) → ↥ (i / 1) ≡ i
↥[i/1]≡i i = begin

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This feels like an awfully complicated proof for something so simple. I wonder if a "first principles" proof, by matching on i, would be simpler?

where open ≡-Reasoning

↧ₙ[i/1]≡1 : (i : ℤ) → ↧ₙ (i / 1) ≡ 1
↧ₙ[i/1]≡1 i = ℤ.+-injective $ begin

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Possibly the same here.

n/g≢0 = ℕ.≢-nonZero (ℕ.n/gcd[m,n]≢0 n n {{gcd≢0 = g≢0}})

gcd[n,n]≡n : ∀ n → ℕ.gcd n n ≡ n
gcd[n,n]≡n n rewrite sym (ℕ.*-identityʳ n)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We tend not to use rewrite in stdlib. Also this lemma should go in to Data.Nat.GCD.

p*g≢0 = ℕ.m*n≢0 p (ℕ.gcd qₙ r)

lemma : ∀ n → (p ℕ.* n) ℕ./ ℕ.gcd (p ℕ.* qₙ) (p ℕ.* r) ≡ n ℕ./ ℕ.gcd qₙ r
lemma n = trans (ℕ./-congʳ $ sym $ ℕ.c*gcd[m,n]≡gcd[cm,cn] p qₙ r)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

an equational proof would be more readable here

(ℕ.m*n/m*o≡n/o p n $ ℕ.gcd qₙ r)

proof : ∀ q → (+ p ℤ.* q) / (p ℕ.* r) ≡ q / r
proof (+ qₙ) rewrite sym (ℤ.pos-* p qₙ) = *-cancelˡ-/-helper qₙ

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please make these explicit instead of using rewrite


↥≡ : (↥ pᵢ ℤ.* ↧ qⱼ ℤ.+ ↥ qⱼ ℤ.* ↧ pᵢ) ℤ.* gcd[j,n] ℤ.* gcd[i,n]
≡ (i ℤ.+ j) ℤ.* + n
↥≡ rewrite ℤ.*-distribʳ-+ gcd[j,n] (↥ pᵢ ℤ.* ↧ qⱼ) (↥ qⱼ ℤ.* ↧ pᵢ)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

most definitely needs to be done equationally!

------------------------------------------------------------------------
-- Properties of _*_ and _/_

*-cancelˡ-/ : ∀ p {q r} .{{_ : ℕ.NonZero r}} .{{_ : ℕ.NonZero (p ℕ.* r)}} →

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Others may disagree, but I find this kind of quantification annoying, especially when you will have to explicitly plumb in the derived instance p≢0 immediately below.

I know that it is to ensure that the typechecker is OK with the well-formedness of (+ p ℤ.* q) / (p ℕ.* r), but I would personally find it more mathematically plausible (even if more ugly/unwieldy) to write

Suggested change
*-cancelˡ-/ : p {q r} .{{_ : ℕ.NonZero r}} .{{_ : ℕ.NonZero (p ℕ.* r)}}
*-cancelˡ-/ : p {q r} .{{_ : ℕ.NonZero r}} .{{_ : ℕ.NonZero p}} (let instance _ = ℕ.m*n≢0 p r)

or even to lift all of this prefix out as part of a module _ ... declaration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants