142 lines
3.3 KiB
Text
142 lines
3.3 KiB
Text
/-
|
|
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Authors: Leonardo de Moura
|
|
-/
|
|
namespace Lean
|
|
|
|
/-!
|
|
Rational numbers for implementing decision procedures.
|
|
We should not confuse them with the Mathlib rational numbers.
|
|
-/
|
|
|
|
structure Rat where
|
|
private mk ::
|
|
num : Int
|
|
den : Nat := 1
|
|
deriving Inhabited, BEq, DecidableEq
|
|
|
|
instance : ToString Rat where
|
|
toString a := if a.den == 1 then toString a.num else s!"{a.num}/{a.den}"
|
|
|
|
instance : Repr Rat where
|
|
reprPrec a _ := if a.den == 1 then repr a.num else s!"({a.num} : Rat)/{a.den}"
|
|
|
|
@[inline] def Rat.normalize (a : Rat) : Rat :=
|
|
let n := Nat.gcd a.num.natAbs a.den
|
|
if n == 1 then a else { num := a.num / n, den := a.den / n }
|
|
|
|
def mkRat (num : Int) (den : Nat) : Rat :=
|
|
if den == 0 then { num := 0 } else Rat.normalize { num, den }
|
|
|
|
namespace Rat
|
|
|
|
protected def isInt (a : Rat) : Bool :=
|
|
a.den == 1
|
|
|
|
protected def lt (a b : Rat) : Bool :=
|
|
if a.num < 0 && b.num >= 0 then
|
|
true
|
|
else if a.num == 0 then
|
|
b.num > 0
|
|
else if a.num > 0 && b.num <= 0 then
|
|
false
|
|
else
|
|
-- `a` and `b` must have the same sign
|
|
a.num * b.den < b.num * a.den
|
|
|
|
protected def mul (a b : Rat) : Rat :=
|
|
let g1 := Nat.gcd a.den b.num.natAbs
|
|
let g2 := Nat.gcd a.num.natAbs b.den
|
|
{ num := (a.num / g2)*(b.num / g1)
|
|
den := (b.den / g2)*(a.den / g1) }
|
|
|
|
protected def inv (a : Rat) : Rat :=
|
|
if a.num < 0 then
|
|
{ num := - a.den, den := a.num.natAbs }
|
|
else if a.num == 0 then
|
|
a
|
|
else
|
|
{ num := a.den, den := a.num.natAbs }
|
|
|
|
protected def div (a b : Rat) : Rat :=
|
|
Rat.mul a b.inv
|
|
|
|
protected def add (a b : Rat) : Rat :=
|
|
let g := Nat.gcd a.den b.den
|
|
if g == 1 then
|
|
{ num := a.num * b.den + b.num * a.den, den := a.den * b.den }
|
|
else
|
|
let den := (a.den / g) * b.den
|
|
let num := (b.den / g) * a.num + (a.den / g) * b.num
|
|
let g1 := Nat.gcd num.natAbs g
|
|
if g1 == 1 then
|
|
{ num, den }
|
|
else
|
|
{ num := num / g1, den := den / g1 }
|
|
|
|
protected def sub (a b : Rat) : Rat :=
|
|
let g := Nat.gcd a.den b.den
|
|
if g == 1 then
|
|
{ num := a.num * b.den - b.num * a.den, den := a.den * b.den }
|
|
else
|
|
let den := (a.den / g) * b.den
|
|
let num := (b.den / g) * a.num - (a.den / g) * b.num
|
|
let g1 := Nat.gcd num.natAbs g
|
|
if g1 == 1 then
|
|
{ num, den }
|
|
else
|
|
{ num := num / g1, den := den / g1 }
|
|
|
|
protected def neg (a : Rat) : Rat :=
|
|
{ a with num := - a.num }
|
|
|
|
protected def floor (a : Rat) : Int :=
|
|
if a.den == 1 then
|
|
a.num
|
|
else
|
|
let r := a.num / a.den
|
|
if a.num < 0 then r - 1 else r
|
|
|
|
protected def ceil (a : Rat) : Int :=
|
|
if a.den == 1 then
|
|
a.num
|
|
else
|
|
let r := a.num / a.den
|
|
if a.num > 0 then r + 1 else r
|
|
|
|
instance : LT Rat where
|
|
lt a b := (Rat.lt a b) = true
|
|
|
|
instance (a b : Rat) : Decidable (a < b) :=
|
|
inferInstanceAs (Decidable (_ = true))
|
|
|
|
instance : LE Rat where
|
|
le a b := ¬(b < a)
|
|
|
|
instance (a b : Rat) : Decidable (a ≤ b) :=
|
|
inferInstanceAs (Decidable (¬ _))
|
|
|
|
instance : Add Rat where
|
|
add := Rat.add
|
|
|
|
instance : Sub Rat where
|
|
sub := Rat.sub
|
|
|
|
instance : Neg Rat where
|
|
neg := Rat.neg
|
|
|
|
instance : Mul Rat where
|
|
mul := Rat.mul
|
|
|
|
instance : Div Rat where
|
|
div a b := a * b.inv
|
|
|
|
instance : OfNat Rat n where
|
|
ofNat := { num := n }
|
|
|
|
instance : Coe Int Rat where
|
|
coe num := { num }
|
|
|
|
end Rat
|
|
end Lean
|