sbv-12.2: Data/SBV/Rational.hs
-----------------------------------------------------------------------------
-- |
-- Module : Data.SBV.Rational
-- Copyright : (c) Levent Erkok
-- License : BSD3
-- Maintainer: erkokl@gmail.com
-- Stability : experimental
--
-- Symbolic rationals, corresponds to Haskell's 'Rational' type
-----------------------------------------------------------------------------
{-# LANGUAGE FlexibleInstances #-}
{-# OPTIONS_GHC -Wall -Werror -Wno-orphans #-}
module Data.SBV.Rational (
-- * Constructing rationals
(.%)
) where
import qualified Data.Ratio as R
import Data.SBV.Core.Data
import Data.SBV.Core.Model
infixl 7 .%
-- | Construct a symbolic rational from a given numerator and denominator. Note that
-- it is not possible to deconstruct a rational by taking numerator and denominator
-- fields, since we do not represent them canonically. (This is due to the fact that
-- SMTLib has no functions to compute the GCD. While we can define a recursive function
-- to do so, it would almost always imply non-decidability for even the simplest queries.)
(.%) :: SInteger -> SInteger -> SRational
top .% bot
| Just t <- unliteral top
, Just b <- unliteral bot
= literal $ t R.% b
| True
= SBV $ SVal KRational $ Right $ cache res
where res st = do t <- sbvToSV st top
b <- sbvToSV st bot
newExpr st KRational $ SBVApp RationalConstructor [t, b]
-- | Get the numerator. Note that this is always symbolic since we don't have a concrete representation.
-- Furthermore this is only used internally and is not exported to the user, since it is not canonical.
doNotExport_numerator :: SRational -> SInteger
doNotExport_numerator x = SBV $ SVal KUnbounded $ Right $ cache res
where res st = do xv <- sbvToSV st x
newExpr st KUnbounded $ SBVApp (Uninterpreted "sbv.rat.numerator") [xv]
-- | Get the numerator. Note that this is always symbolic since we don't have a concrete representation.
-- Furthermore this is only used internally and is not exported to the user, since it is not canonical.
doNotExport_denominator :: SRational -> SInteger
doNotExport_denominator x = SBV $ SVal KUnbounded $ Right $ cache res
where res st = do xv <- sbvToSV st x
newExpr st KUnbounded $ SBVApp (Uninterpreted "sbv.rat.denominator") [xv]
-- | Num instance for SRational. Note that denominators are always positive.
instance Num SRational where
fromInteger i = SBV $ SVal KRational $ Left $ mkConstCV KRational (fromIntegral i :: Integer)
(+) = lift2 (+) (\(t1, b1) (t2, b2) -> (t1 * b2 + t2 * b1) .% (b1 * b2))
(-) = lift2 (-) (\(t1, b1) (t2, b2) -> (t1 * b2 - t2 * b1) .% (b1 * b2))
(*) = lift2 (*) (\(t1, b1) (t2, b2) -> (t1 * t2 ) .% (b1 * b2))
abs = lift1 abs (\(t, b) -> abs t .% b)
negate = lift1 negate (\(t, b) -> negate t .% b)
signum a = ite (a .> 0) 1 $ ite (a .< 0) (-1) 0
-- | Symbolic ordering for SRational. Note that denominators are always positive.
instance OrdSymbolic SRational where
(.<) = lift2 (<) (\(t1, b1) (t2, b2) -> (t1 * b2) .< (b1 * t2))
(.<=) = lift2 (<=) (\(t1, b1) (t2, b2) -> (t1 * b2) .<= (b1 * t2))
(.>) = lift2 (>) (\(t1, b1) (t2, b2) -> (t1 * b2) .> (b1 * t2))
(.>=) = lift2 (>=) (\(t1, b1) (t2, b2) -> (t1 * b2) .>= (b1 * t2))
-- | Get the top and bottom parts. Internal only; do not export!
doNotExport_getTB :: SRational -> (SInteger, SInteger)
doNotExport_getTB a = (doNotExport_numerator a, doNotExport_denominator a)
-- | Lift a function over one rational
lift1 :: SymVal t => (Rational -> t) -> ((SInteger, SInteger) -> SBV t) -> SRational -> SBV t
lift1 cf f a
| Just va <- unliteral a
= literal (cf va)
| True
= f (doNotExport_getTB a)
-- | Lift a function over two rationals
lift2 :: SymVal t => (Rational -> Rational -> t) -> ((SInteger, SInteger) -> (SInteger, SInteger) -> SBV t) -> SRational -> SRational -> SBV t
lift2 cf f a b
| Just va <- unliteral a, Just vb <- unliteral b
= literal (va `cf` vb)
| True
= f (doNotExport_getTB a) (doNotExport_getTB b)
{- HLint ignore type doNotExport_numerator "Use camelCase" -}
{- HLint ignore type doNotExport_denominator "Use camelCase" -}
{- HLint ignore type doNotExport_getTB "Use camelCase" -}