| /- | |
| 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 |