module Data.Rational.Base where

Rational numbers🔗

The ring of rational numbers, is the localisation of the ring of integers inverting every positive element. We’ve already done most of the work while implementing localisations:

PositiveΩ : Int  Ω
PositiveΩ x .∣_∣ = Positive x
PositiveΩ x .is-tr = hlevel 1

private
  module L = Loc ℤ-comm PositiveΩ record { has-1 = pos 0 ; has-* = *ℤ-positive }

Strictly speaking, we are done: we could simply define to be the ring we just constructed. However, for the sake of implementation hiding, we wrap it as a distinct type constructor. This lets consumers of the type forget that it’s implemented as a localisation.

data  : Type where
  inc :  L.S⁻¹R   

toℚ : Fraction  
toℚ x = inc (inc x)

_+ℚ_ :     
_+ℚ_ (inc x) (inc y) = inc (x L.+ₗ y)

_*ℚ_ :     
_*ℚ_ (inc x) (inc y) = inc (x L.*ₗ y)

-ℚ_ :   
-ℚ_ (inc x) = inc (L.-ₗ x)

However, clients of this module will need the fact that is a quotient of the type of integer fractions. Therefore, we expose an elimination principle, saying that to show a proposition everywhere over it suffices to do so at the fractions.

ℚ-elim-prop
  :  {} {P :   Type } (pprop :  x  is-prop (P x))
   (f :  x  P (toℚ x))
    x  P x
ℚ-elim-prop pprop f (inc (inc x)) = f x
ℚ-elim-prop pprop f (inc (glue r@(x , y , _) i)) = is-prop→pathp  i  pprop (inc (glue r i))) (f x) (f y) i
ℚ-elim-prop pprop f (inc (squash x y p q i j)) =
  is-prop→squarep
     i j  pprop (inc (squash x y p q i j)))
     i  go (inc x))  i  go (inc (p i)))  i  go (inc (q i)))  i  go (inc y))
    i j
  where go = ℚ-elim-prop pprop f

Next, we show that sameness of fractions implies identity in and the converse is true as well:

abstract
  quotℚ :  {x y}  x  y  toℚ x  toℚ y
  quotℚ p = ap ℚ.inc (quot p)

  unquotℚ :  {x y}  toℚ x  toℚ y  x  y
  unquotℚ p = ≈.effective (ap unℚ p)

Finally, we want to show that the type of rational numbers is discrete. To do this, we have to show that sameness of integer fractions is decidable, i.e. that, given fractions and we can decide whether there exists a with This is not automatic since can range over all integers! However, recall that this is equivalent to Since we know that has no zerodivisors, if this is true, then either or by assumption, it can not be But if then Conversely, if then we can take Therefore, checking sameness of fractions boils down to checking whether they “cross-multiply” to the same thing.

from-same-rational : {x y : Fraction}  x  y  x . *ℤ y .  y . *ℤ x .
from-same-rational {x / s [ s≠0 ]} {y / t [ t≠0 ]} p = case L.≈→≈' p of λ where
  u@(possuc u') (pos u') p  case *ℤ-is-zero u _ p of λ where
    (inl u=0)      absurd (suc≠zero (pos-injective u=0))
    (inr xt-ys=0)  ℤ.zero-diff xt-ys=0

to-same-rational : {x y : Fraction}  x . *ℤ y .  y . *ℤ x .  x  y
to-same-rational {x / s [ s≠0 ]} {y / t [ t≠0 ]} p = L.inc 1 (pos 0) (recover (sym (*ℤ-associative 1 x t) ·· ap (1 *ℤ_) p ·· *ℤ-associative 1 y s))

Dec-same-rational : (x y : Fraction)  Dec (x  y)
Dec-same-rational f@(x / s [ _ ]) f'@(y / t [ _ ]) with x *ℤ t ≡? y *ℤ s
... | yes p = yes (to-same-rational p)
... | no xt≠ys = no λ p  xt≠ys (from-same-rational p)
There are a number of other properties of that we can export as properties of however, these are all trivial as above, so we do not remark on them any further.
_-ℚ_ :     
(inc x) -ℚ (inc y) = inc (x L.+ₗ L.-ₗ y)

infixl 8 _+ℚ_ _-ℚ_
infixl 9 _*ℚ_
infix 10 -ℚ_

_/_ : (x y : Int)  _ : Positive y   
_/_ x y  p  = toℚ (x / y [ p ])

infix 11 _/_

{-# DISPLAY ℚ.inc (Coeq.inc (_/_[_] x y _)) = x / y #-}
{-# DISPLAY _/_ x (Int.pos 1) = x #-}

_/1 : Int  
x /1 = x / 1

instance
  H-Level-ℚ :  {n}  H-Level  (2 + n)
  H-Level-ℚ = basic-instance 2 (Discrete→is-set auto)

  Number-ℚ : Number 
  Number-ℚ .Number.Constraint _ = 
  Number-ℚ .Number.fromNat x = pos x /1

  Negative-ℚ : Negative 
  Negative-ℚ .Negative.Constraint _ = 
  Negative-ℚ .Negative.fromNeg 0 = 0
  Negative-ℚ .Negative.fromNeg (suc x) = negsuc x /1

  Inductive-ℚ
    :  { ℓm} {P :   Type }
      _ : Inductive ((x : Fraction)  P (toℚ x)) ℓm 
      _ :  {x}  H-Level (P x) 1 
     Inductive (∀ x  P x) ℓm
  Inductive-ℚ  r  .Inductive.methods = r .Inductive.methods
  Inductive-ℚ  r  .Inductive.from f = ℚ-elim-prop  x  hlevel 1) (r .Inductive.from f)

abstract
  +ℚ-idl :  x  0 +ℚ x  x
  +ℚ-idl (inc x) = ap inc (L.+ₗ-idl x)

  +ℚ-idr :  x  x +ℚ 0  x
  +ℚ-idr (inc x) = ap ℚ.inc (CRing.+-idr L.S⁻¹R)

  +ℚ-invl :  x  (-ℚ x) +ℚ x  0
  +ℚ-invl (inc x) = ap ℚ.inc (CRing.+-invl L.S⁻¹R {x})

  +ℚ-invr :  x  x +ℚ (-ℚ x)  0
  +ℚ-invr (inc x) = ap ℚ.inc (L.+ₗ-invr x)

  +ℚ-associative :  x y z  x +ℚ (y +ℚ z)  (x +ℚ y) +ℚ z
  +ℚ-associative (inc x) (inc y) (inc z) = ap inc (L.+ₗ-assoc x y z)

  +ℚ-commutative :  x y  x +ℚ y  y +ℚ x
  +ℚ-commutative (inc x) (inc y) = ap inc (L.+ₗ-comm x y)

  *ℚ-idl :  x  1 *ℚ x  x
  *ℚ-idl (inc x) = ap inc (L.*ₗ-idl x)

  *ℚ-idr :  x  x *ℚ 1  x
  *ℚ-idr (inc x) = ap ℚ.inc (CRing.*-idr L.S⁻¹R)

  *ℚ-associative :  x y z  x *ℚ (y *ℚ z)  (x *ℚ y) *ℚ z
  *ℚ-associative (inc x) (inc y) (inc z) = ap inc (L.*ₗ-assoc x y z)

  *ℚ-commutative :  x y  x *ℚ y  y *ℚ x
  *ℚ-commutative (inc x) (inc y) = ap inc (L.*ₗ-comm x y)

  *ℚ-zerol :  x  0 *ℚ x  0
  *ℚ-zerol (inc x) = ap ℚ.inc (CRing.*-zerol L.S⁻¹R {x})

  *ℚ-zeror :  x  x *ℚ 0  0
  *ℚ-zeror (inc x) = ap ℚ.inc (CRing.*-zeror L.S⁻¹R {x})

  *ℚ-distribl :  x y z  x *ℚ (y +ℚ z)  x *ℚ y +ℚ x *ℚ z
  *ℚ-distribl (inc x) (inc y) (inc z) = ap ℚ.inc (L.*ₗ-distribl x y z)

  *ℚ-distribr :  x y z  (y +ℚ z) *ℚ x  y *ℚ x +ℚ z *ℚ x
  *ℚ-distribr x y z = *ℚ-commutative (y +ℚ z) x  *ℚ-distribl x y z  ap₂ _+ℚ_ (*ℚ-commutative x y) (*ℚ-commutative x z)

+ℚ-monoid : is-monoid 0 _+ℚ_
+ℚ-monoid = record { has-is-semigroup = record { has-is-magma = record { has-is-set = hlevel 2 } ; associative = λ {x} {y} {z}  +ℚ-associative x y z } ; idl = +ℚ-idl _ ; idr = +ℚ-idr _ }

*ℚ-monoid : is-monoid 1 _*ℚ_
*ℚ-monoid = record { has-is-semigroup = record { has-is-magma = record { has-is-set = hlevel 2 } ; associative = λ {x} {y} {z}  *ℚ-associative x y z } ; idl = *ℚ-idl _ ; idr = *ℚ-idr _ }

ℚ-ring : CRing lzero
 ℚ-ring .fst  = 
ℚ-ring .fst .is-tr = hlevel 2
ℚ-ring .snd .CRing-on.has-ring-on = to-ring-on mk where
  open make-ring
  mk : make-ring 
  mk .ring-is-set = hlevel 2
  mk .0R = 0
  mk .make-ring._+_ = _+ℚ_
  - mk = -ℚ_
  mk .+-idl = +ℚ-idl
  mk .+-invr = +ℚ-invr
  mk .+-assoc = +ℚ-associative
  mk .+-comm = +ℚ-commutative
  mk .1R = 1
  mk .make-ring._*_ = _*ℚ_
  mk .*-idl = *ℚ-idl
  mk .*-idr = *ℚ-idr
  mk .*-assoc = *ℚ-associative
  mk .*-distribl = *ℚ-distribl
  mk .*-distribr = *ℚ-distribr
ℚ-ring .snd .CRing-on.*-commutes = *ℚ-commutative _ _

As a field🔗

An important property of the ring is that any nonzero rational number is invertible. Since inverses are unique when they exist — the type of inverses is a proposition — it suffices to show this at the more concrete level of integer fractions.

inverseℚ : (x : )  x  0  Σ[ y   ] (x *ℚ y  1)
inverseℚ = ℚ-elim-prop is-p go where
  abstract
    is-p : (x : )  is-prop (x  0  Σ[ y   ] (x *ℚ y  1))
    is-p x = Π-is-hlevel 1 λ _ (y , p) (z , q)  Σ-prop-path! (monoid-inverse-unique *ℚ-monoid x y z (*ℚ-commutative y x  p) q)

    rem₁ :  x y  1 *ℤ (x *ℤ y) *ℤ 1  1 *ℤ (y *ℤ x)
    rem₁ x y = ap (_*ℤ 1) (*ℤ-onel (x *ℤ y))
       *ℤ-oner (x *ℤ y)  *ℤ-commutative x y  sym (*ℤ-onel (y *ℤ x))

This leaves us with three cases: either the fraction had a denominator of zero, contradicting our assumption, or its numerator is also nonzero (either positive or negative), so that we can form the fraction It’s then routine to show that holds in

  go : (x : Fraction)  toℚ x  0  Σ[ y   ] (toℚ x *ℚ y  1)
  go (posz / y [ _ ]) nz = absurd (nz (quotℚ (L.inc 1 decide! refl)))
  go (x@(possuc x') / y [ _ ]) nz = y / x , quotℚ (L.inc 1 decide! (rem₁ x y))
  go (x@(negsuc x') / y [ p ]) nz with y | p
  ... | possuc y | _ = negsuc y / possuc x' , quotℚ (L.inc 1 decide! (rem₁ (negsuc x') (negsuc y)))
  ... | negsuc y | _ = possuc y / possuc x' , quotℚ (L.inc 1 decide! (rem₁ x (possuc y)))

Reduced fractions🔗

We now show that the quotient defining is split: integer fractions have a well-defined notion of normal form, and similarity of fractions is equivalent to equality under normalisation. The procedure we formalise is the familiar one, sending a fraction to

What remains is proving that this is actually a normalisation procedure, which takes up the remainder of this module.

reduce-fraction : Fraction  Fraction
reduce-fraction (x / y [ p ]) = reduced module reduce where
  gcd[x,y] : GCD (abs x) (abs y)
  gcd[x,y] = Euclid.euclid (abs x) (abs y)

Our first obligation, to form the reduced fraction at all, is showing that the denominator is non-zero. This is pretty easy: we know that is nonzero, so if were zero, we would have which is a contradiction. A similar argument shows that is itself nonzero, a fact we’ll need later.

  rem₁ : y/g  0
  rem₁ y/g=0 with y/g | y/g=0 | y/g*g=y
  ... | zero  | y/g=0 | q = positive→nonzero p (abs-positive y (sym q))
  ... | suc n | y/g=0 | q = absurd (suc≠zero y/g=0)

  rem₂ : g  0
  rem₂ g=0 = positive→nonzero p (abs-positive y (sym (sym (*-zeror y/g)  ap (y/g *_) (sym g=0)  y/g*g=y)))

Finally, we must quickly mention the issue of signs. Since gcd produces a natural number, we have to multiply it by the sign of to make sure signs are preserved. Note that the denominator must be positive.

  reduced : Fraction
  reduced = assign (sign x) x/g / pos y/g [ pos-positive rem₁ ]

Finally, we can calculate that these fractions are similar.

  related : (x / y [ p ])  reduced
  related = L.inc (pos g) (pos-positive rem₂) $
    pos g *ℤ x *ℤ pos y/g               ≡⟨ solve 3  x y z  x :* y :* z  (z :* x) :* y) (pos g) x (pos y/g) refl 
    (pos y/g *ℤ pos g) *ℤ x             ≡⟨ ap (_*ℤ x) (ap (assign pos) y/g*g=y) 
    assign pos (abs y) *ℤ x             ≡⟨ ap₂ _*ℤ_ (assign-pos-positive y p) (sym (divides-*ℤ {n = x/g} {g} {x} (*-commutative g x/g  x/g*g=x))) 
    y *ℤ (pos g *ℤ assign (sign x) x/g) ≡⟨ solve 3  y g x  y :* (g :* x)  g :* x :* y) y (pos g) (assign (sign x) x/g) refl 
    pos g ℤ.* assign (sign x) x/g ℤ.* y 

We’ll now show that reduce-fraction respects similarity of fractions. We show this by an intermediate lemma, which says that, given a non-zero and a fraction we have as integer fractions (rather than rational numbers).

reduce-*r
  :  x y s (p : Positive y) (q : Positive s)
   reduce-fraction ((x *ℤ s) / (y *ℤ s) [ *ℤ-positive p q ])
   reduce-fraction (x / y [ p ])
reduce-*r x y s p q = Fraction-path (ap₂ assign sgn num) (ap Int.pos denom) where

The first observation is that even when absolute values are involved.1

  p1 : gcdℤ (x *ℤ s) (y *ℤ s)  gcdℤ x y * abs s
  p1 = ap₂ gcd (abs-*ℤ x s) (abs-*ℤ y s)  gcd-factor (abs x) (abs y) (abs s)

This implies that and, because multiplication by is injective, this in turn implies that is also We conclude since both sides multiply with to and this multiplication is also injective. Therefore, our numerators have the same absolute value.

  num' : xs/gcd * gcdℤ x y  abs x
  num' = *-injr (abs s) (xs/gcd * m.g) (abs x) $
    xs/gcd * gcdℤ x y * abs s       ≡⟨ *-associative xs/gcd m.g (abs s) 
    xs/gcd * (gcdℤ x y * abs s)     ≡˘⟨ ap (xs/gcd *_) p1 ≡˘
    xs/gcd * gcdℤ (x *ℤ s) (y *ℤ s) ≡⟨ n.x/g*g=x 
    abs (x *ℤ s)                    ≡⟨ abs-*ℤ x s 
    abs x * abs s                   

  num : xs/gcd  x/gcd
  num = *-injr (gcdℤ x y) xs/gcd x/gcd (num'  sym m.x/g*g=x)

We must still show that the resulting numerators have the same sign. Fortunately, this boils down to a bit of algebra, plus the hyper-specific fact that whenever is nonzero.2

  sgn : sign (x *ℤ s)  sign x
  sgn = sign-*ℤ-positive x s q

A symmetric calculation shows that the denominators also have the same absolute value, and, since they’re both positive in the resulting fraction, we’re done.

  denom' : ys/gcd * gcdℤ x y  abs y
  denom' = *-injr (abs s) (ys/gcd * m.g) (abs y) (*-associative ys/gcd m.g (abs s)  sym (ap (ys/gcd *_) p1)  n.y/g*g=y  abs-*ℤ y s)

  denom : ys/gcd  y/gcd
  denom = *-injr (gcdℤ x y) ys/gcd y/gcd (denom'  sym m.y/g*g=y)

We can use this to show that reduce-fraction sends similar fractions to equal normal forms: If we have and we can calculate using the previous lemma. Thus, by the general logic of split quotients, we conclude that is equivalent to the set of reduced integer fractions.

reduce-resp : (x y : Fraction)  x  y  reduce-fraction x  reduce-fraction y
reduce-resp f@(x / s [ s≠0 ]) f'@(y / t [ t≠0 ]) p =
  reduce-fraction (x / s [ s≠0 ])             ≡⟨ sym (reduce-*r x s t s≠0 t≠0) 
  reduce-fraction ((x *ℤ t) / (s *ℤ t) [ _ ]) ≡⟨ ap reduce-fraction (Fraction-path {x = _ / _ [ *ℤ-positive s≠0 t≠0 ]} {_ / _ [ *ℤ-positive t≠0 s≠0 ]} (from-same-rational p) (*ℤ-commutative s t)) 
  reduce-fraction ((y *ℤ s) / (t *ℤ s) [ _ ]) ≡⟨ reduce-*r y t s t≠0 s≠0 
  reduce-fraction (y / t [ t≠0 ])             

integer-frac-splits : is-split-congruence L.Fraction-congruence
integer-frac-splits = record
  { has-is-set = hlevel 2
  ; normalise  = reduce-fraction
  ; represents = elim! reduce.related
  ; respects   = reduce-resp
  }
private module split = is-split-congruence integer-frac-splits

reduceℚ :   Fraction
reduceℚ (inc x) = split.choose x

splitℚ : (x : )  fibre toℚ x
splitℚ (inc x) = record
  { fst = split.choose x
  -- The use of 'recover' here replaces the calculated proof that
  -- is-split-congruence returns by an invocation of Discrete-ℚ. This
  -- has much shorter normal forms when applied to concrete values.
  ; snd = recover (ap inc (split.splitting x .snd))
  }

abstract
  reduce-injective :  x y  reduceℚ x  reduceℚ y  x  y
  reduce-injective = elim!  x s s≠0 y t t≠0 p  quotℚ (split.reflects _ _ p))

common-denominator
  :  n (fs : Fin n  Fraction)  Σ[ c  Int ] Σ[ p  Positive c ] Σ[ n  (Fin n  Int) ] (∀ j  fs j  (n j / c [ p ]))
common-denominator 0 _ = 1 , pos 0 ,  ()) ,  ())
common-denominator (suc sz) fs with (c , c≠0 , nums , prfs)common-denominator sz (fs  fsuc) | inspect (fs fzero)
... | n / d [ d≠0 ] , prf = c' , c'≠0 , nums' , prfs' where
  c'   = d *ℤ c
  c'≠0 = *ℤ-positive d≠0 c≠0

  nums' : Fin (suc sz)  Int
  nums' fzero = n *ℤ c
  nums' (fsuc n) = nums n *ℤ d

  abstract
    prfs' : (n : Fin (suc sz))  fs n  (nums' n / c' [ c'≠0 ])
    prfs' fzero    = ≈.reflᶜ' prf ≈.∙ᶜ L.inc c c≠0 (solve 3  c n d  c :* n :* (d :* c)  c :* (n :* c) :* d) c n d refl)
    prfs' (fsuc n) = prfs n ≈.∙ᶜ L.inc d d≠0 (solve 3  c n d  d :* n :* (d :* c)  d :* (n :* d) :* c) c (nums n) d refl)

-- Induction principle for n-tuples of rational numbers which reduces to
-- the case of n fractions /with the same denominator/. The type is
-- pretty noisy since it uses the combinators for finite products, but
-- it specialises at concrete n to what you would expect, e.g.
--
--    ℚ-elim-propⁿ 2
--      : ∀ {P : ℚ → ℚ → Prop}
--      → (∀ d (p : Positive d) a b → P (a / d) (b / d))
--      → ∀ a b → P a b
--
-- This is useful primarily when dealing with the order, since
-- a / d ≤ b / d is just a ≤ b. Algebraic properties of the rationals
-- don't generally get any easier by assuming a common denominator.

ℚ-elim-propⁿ
  :  (n : Nat) {} {P : Arrᶠ {n = n}  _  ) (Type )}
    _ : {as : Πᶠ  i  )}  H-Level (applyᶠ P as) 1 
   ( (d : Int)  p : Positive d 
     ∀ᶠ n  i  Int)  as  applyᶠ P (mapₚ  i n  toℚ (n / d [ p ])) as)))
   ∀ᶠ n  _  ) λ as  applyᶠ P as

ℚ-elim-propⁿ n {P = P} work = curry-∀ᶠ go where abstract
  reps :  n  (qs : Fin n  )   ((i : Fin n)  fibre toℚ (qs i)) 
  reps n qs = finite-choice n  i  ℚ-elim-prop {P = λ x   fibre toℚ x }  _  squash)  x  inc (x , refl)) (qs i))

  go : (as : Πᶠ  i  ))  applyᶠ P as
  go as = ∥-∥-out! do
    fracs'  reps _ (indexₚ as)

    let
      fracs : Fin n  Fraction
      fracs i = fracs' i .fst

      same : (i : Fin n)  toℚ (fracs i)  indexₚ as i
      same i = fracs' i .snd

    (d , d≠0 , nums , same')  pure (common-denominator _ fracs)

    let
      rats : Πᶠ  i  )
      rats = mapₚ  i n  toℚ (n / d [ d≠0 ])) (tabulateₚ nums)

      p₀ : applyᶠ P rats
      p₀ = apply-∀ᶠ (work d  d≠0 ⦄) (tabulateₚ nums)

      rats=as : rats  as
      rats=as = extₚ λ i 
        indexₚ-mapₚ  i n  toℚ (n / d [ d≠0 ])) (tabulateₚ nums) i
        ·· ap  e  toℚ (e / d [ d≠0 ])) (indexₚ-tabulateₚ nums i)
        ·· sym (quotℚ (same' i))  same i

    pure (subst (applyᶠ P) rats=as p₀)

same-frac : Fraction  Fraction  Prop lzero
same-frac f@record{} g@record{} = el! (f . *ℤ g .  g . *ℤ f .)

private
  eqℚ :     Prop lzero
  eqℚ (inc x) (inc y) = Coeq-rec₂ (hlevel 2) same-frac
     { f@(x / s [ p ]) (g@(y / t [ q ]) , h@(z / u [ r ]) , α)  n-ua (prop-ext!
       β  from-same-rational {h} {f} (≈.symᶜ α ≈.∙ᶜ to-same-rational β))
       β  from-same-rational {g} {f} (α ≈.∙ᶜ to-same-rational β))) })
     { f@(x / s [ p ]) (g@(y / t [ q ]) , h@(z / u [ r ]) , α)  n-ua (prop-ext!
       β  from-same-rational {f} {h} (to-same-rational β ≈.∙ᶜ α))
       β  from-same-rational {f} {g} (to-same-rational β ≈.∙ᶜ ≈.symᶜ α))) })
    x y

open Extensional

instance
  Extensional-ℚ : Extensional  lzero
  Extensional-ℚ .Pathᵉ x y =  eqℚ x y 
  Extensional-ℚ .reflᵉ = ℚ-elim-prop  _  hlevel 1) λ { record{}  refl }
  Extensional-ℚ .idsᵉ .to-path {a} {b} = go a b where
    go :  a b   eqℚ a b   a  b
    go = ℚ-elim-propⁿ 2  d a b p  quotℚ (to-same-rational p))
  Extensional-ℚ .idsᵉ .to-path-over p = prop!

record Nonzero (x : ) : Type where
  constructor inc
  -- It's important that Nonzero is a strict proposition, living in
  -- Type, so that it doesn't matter what instance gets selected when we
  -- use it in invℚ etc.
  --
  -- The alternative is to always use it as an irrelevant instance (or
  -- to, god forbid, have it in Agda's Prop), but that doesn't play well
  -- with the overlap pragmas; and we need those if we're gonna have
  -- e.g. Nonzero (p * q) as an instance.
  field
    .lower : x  0

instance
  H-Level-Nonzero :  {x n}  H-Level (Nonzero x) (suc n)
  H-Level-Nonzero = prop-instance λ _ _  refl

open Nonzero

abstract
  from-nonzero :  {x}  p : Nonzero x   x  0
  from-nonzero  inc α  p = absurd (α p)

  from-nonzero-frac :  {x y} {p : Positive y}  Nonzero (toℚ (x / y [ p ]))  x  0
  from-nonzero-frac (inc α) p = absurd (α (quotℚ (to-same-rational (*ℤ-oner _  p))))

  to-nonzero-frac :  {x y} {p : Positive y}  x  0  Nonzero (toℚ (x / y [ p ]))
  to-nonzero-frac p = inc λ α  p (sym (*ℤ-oner _)  from-same-rational (unquotℚ α))

instance
  Nonzero-neg :  {x d} {p : Positive d}  Nonzero (toℚ (negsuc x / d [ p ]))
  Nonzero-neg = inc  p  absurd (negsuc≠pos (from-same-rational (unquotℚ p))))

  Nonzero-pos :  {x d} {p : Positive d}  _ : Positive x   Nonzero (toℚ (x / d [ p ]))
  Nonzero-pos {.(possuc x)}  pos x  = inc  p  absurd (suc≠zero (pos-injective (from-same-rational (unquotℚ p)))))
  {-# OVERLAPPABLE Nonzero-pos #-}

-- Since we want invℚ to be injective as well, we re-wrap the result on
-- the RHS, to make sure the clause is headed by a constructor.
invℚ : (x : )  p : Nonzero x   
invℚ (inc x)  inc α  = inc (unℚ (inverseℚ (inc x)  p  absurd (α p)) .fst))

*ℚ-invr : {x : } {p : Nonzero x}  x *ℚ invℚ x  p   1
*ℚ-invr {inc x} {inc α} with inverseℚ (inc x)  p  absurd (α p))
... | (inc x , p) = p

-ℚ-def :  x y  x +ℚ (-ℚ y)  x -ℚ y
-ℚ-def (inc x) (inc y) = refl

_/ℚ_ : (x y : )  p : Nonzero y   
inc x /ℚ inc y = inc x *ℚ invℚ (inc y)

abstract
  from-same-denom :  {x y d}  p : Positive d   x / d  y / d  x  y
  from-same-denom {x} {y} {d} p = *ℤ-injectiver d x y (positive→nonzero auto) (from-same-rational (unquotℚ p))

  1. Keep in mind that the gcd function is defined over the naturals, and we’re extending it to integers by ↩︎

  2. Here, we’re applying this lemma with and and we have assumed nonzero. The function is not fun.↩︎