feat: add Lean.Rat for implementing decision procedures
This commit is contained in:
parent
34853bcbd8
commit
db583550fd
4 changed files with 162 additions and 0 deletions
|
|
@ -21,3 +21,4 @@ import Lean.Data.SMap
|
|||
import Lean.Data.Trie
|
||||
import Lean.Data.PrefixTree
|
||||
import Lean.Data.NameTrie
|
||||
import Lean.Data.Rat
|
||||
|
|
|
|||
125
src/Lean/Data/Rat.lean
Normal file
125
src/Lean/Data/Rat.lean
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/-
|
||||
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
|
||||
|
||||
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 lt (a b : Rat) : Bool :=
|
||||
if a.num < 0 && b.num >= 0 then
|
||||
return true
|
||||
else if a.num == 0 then
|
||||
return b.num > 0
|
||||
else if a.num > 0 && b.num <= 0 then
|
||||
return 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 }
|
||||
|
||||
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
|
||||
20
tests/lean/rat1.lean
Normal file
20
tests/lean/rat1.lean
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import Lean.Data.Rat
|
||||
open Lean
|
||||
|
||||
#eval (15 : Rat) / 10
|
||||
#eval (15 : Rat) / 10 + 2
|
||||
#eval (15 : Rat) / 10 - 2
|
||||
#eval (-2 : Rat).inv
|
||||
#eval (2 : Rat).inv == (1 : Rat) / 2
|
||||
#eval (-2 : Rat).inv == (-1 : Rat) / 2
|
||||
#eval (4 : Rat)/9 * (3 : Rat)/10
|
||||
#eval (4 : Rat)/9 * (-3 : Rat)/10
|
||||
#eval (1 : Rat) < (-1 : Rat)
|
||||
#eval (-1 : Rat) < (1 : Rat)
|
||||
#eval (-1 : Rat)/2 < (1 : Rat)
|
||||
#eval (-1 : Rat) < 0
|
||||
#eval (-1 : Rat)/2 < 0
|
||||
#eval 0 < (-1 : Rat)/2
|
||||
#eval (1 : Rat)/3 < (1 : Rat)/2
|
||||
#eval (1 : Rat)/2 < (1 : Rat)/3
|
||||
-- TODO: add more tests
|
||||
16
tests/lean/rat1.lean.expected.out
Normal file
16
tests/lean/rat1.lean.expected.out
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
(3 : Rat)/2
|
||||
(7 : Rat)/2
|
||||
(-1 : Rat)/2
|
||||
(-1 : Rat)/2
|
||||
true
|
||||
true
|
||||
(2 : Rat)/15
|
||||
(-2 : Rat)/15
|
||||
false
|
||||
true
|
||||
true
|
||||
true
|
||||
true
|
||||
false
|
||||
true
|
||||
false
|
||||
Loading…
Add table
Reference in a new issue