-- | Internal 'Range' API
module Test.Falsify.Internal.Range (
    -- * Definition
    Range(..)
  , ProperFraction(ProperFraction)
  , Precision(..)
  ) where

import Data.List.NonEmpty (NonEmpty)
import Data.Word
import GHC.Show
import GHC.Stack

{-------------------------------------------------------------------------------
  Proper fractions
-------------------------------------------------------------------------------}

-- | Value @x@ such that @0 <= x < 1@
newtype ProperFraction = UnsafeProperFraction { ProperFraction -> Double
getProperFraction :: Double }
  deriving stock (ProperFraction -> ProperFraction -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ProperFraction -> ProperFraction -> Bool
$c/= :: ProperFraction -> ProperFraction -> Bool
== :: ProperFraction -> ProperFraction -> Bool
$c== :: ProperFraction -> ProperFraction -> Bool
Eq, Eq ProperFraction
ProperFraction -> ProperFraction -> Bool
ProperFraction -> ProperFraction -> Ordering
ProperFraction -> ProperFraction -> ProperFraction
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: ProperFraction -> ProperFraction -> ProperFraction
$cmin :: ProperFraction -> ProperFraction -> ProperFraction
max :: ProperFraction -> ProperFraction -> ProperFraction
$cmax :: ProperFraction -> ProperFraction -> ProperFraction
>= :: ProperFraction -> ProperFraction -> Bool
$c>= :: ProperFraction -> ProperFraction -> Bool
> :: ProperFraction -> ProperFraction -> Bool
$c> :: ProperFraction -> ProperFraction -> Bool
<= :: ProperFraction -> ProperFraction -> Bool
$c<= :: ProperFraction -> ProperFraction -> Bool
< :: ProperFraction -> ProperFraction -> Bool
$c< :: ProperFraction -> ProperFraction -> Bool
compare :: ProperFraction -> ProperFraction -> Ordering
$ccompare :: ProperFraction -> ProperFraction -> Ordering
Ord)
  deriving newtype (Integer -> ProperFraction
ProperFraction -> ProperFraction
ProperFraction -> ProperFraction -> ProperFraction
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> ProperFraction
$cfromInteger :: Integer -> ProperFraction
signum :: ProperFraction -> ProperFraction
$csignum :: ProperFraction -> ProperFraction
abs :: ProperFraction -> ProperFraction
$cabs :: ProperFraction -> ProperFraction
negate :: ProperFraction -> ProperFraction
$cnegate :: ProperFraction -> ProperFraction
* :: ProperFraction -> ProperFraction -> ProperFraction
$c* :: ProperFraction -> ProperFraction -> ProperFraction
- :: ProperFraction -> ProperFraction -> ProperFraction
$c- :: ProperFraction -> ProperFraction -> ProperFraction
+ :: ProperFraction -> ProperFraction -> ProperFraction
$c+ :: ProperFraction -> ProperFraction -> ProperFraction
Num, Num ProperFraction
Rational -> ProperFraction
ProperFraction -> ProperFraction
ProperFraction -> ProperFraction -> ProperFraction
forall a.
Num a
-> (a -> a -> a) -> (a -> a) -> (Rational -> a) -> Fractional a
fromRational :: Rational -> ProperFraction
$cfromRational :: Rational -> ProperFraction
recip :: ProperFraction -> ProperFraction
$crecip :: ProperFraction -> ProperFraction
/ :: ProperFraction -> ProperFraction -> ProperFraction
$c/ :: ProperFraction -> ProperFraction -> ProperFraction
Fractional)

-- | Show instance relies on the 'ProperFraction' pattern synonym
instance Show ProperFraction where
  showsPrec :: Int -> ProperFraction -> ShowS
showsPrec Int
p (UnsafeProperFraction Double
f) = Bool -> ShowS -> ShowS
showParen (Int
p forall a. Ord a => a -> a -> Bool
>= Int
appPrec1) forall a b. (a -> b) -> a -> b
$
        String -> ShowS
showString String
"ProperFraction "
      forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => Int -> a -> ShowS
showsPrec Int
appPrec1 Double
f

mkProperFraction :: HasCallStack => Double -> ProperFraction
mkProperFraction :: HasCallStack => Double -> ProperFraction
mkProperFraction Double
f
  | Double
0 forall a. Ord a => a -> a -> Bool
<= Double
f Bool -> Bool -> Bool
&& Double
f forall a. Ord a => a -> a -> Bool
< Double
1 = Double -> ProperFraction
UnsafeProperFraction Double
f
  | Bool
otherwise = forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"mkProperFraction: not a proper fraction: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Double
f

pattern ProperFraction :: Double -> ProperFraction
pattern $bProperFraction :: Double -> ProperFraction
$mProperFraction :: forall {r}. ProperFraction -> (Double -> r) -> ((# #) -> r) -> r
ProperFraction f <- (getProperFraction -> f)
  where
    ProperFraction = HasCallStack => Double -> ProperFraction
mkProperFraction

{-# COMPLETE ProperFraction #-}

{-------------------------------------------------------------------------------
  Precision
-------------------------------------------------------------------------------}

-- | Precision (in bits)
newtype Precision = Precision Word8
  deriving stock (Int -> Precision -> ShowS
[Precision] -> ShowS
Precision -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Precision] -> ShowS
$cshowList :: [Precision] -> ShowS
show :: Precision -> String
$cshow :: Precision -> String
showsPrec :: Int -> Precision -> ShowS
$cshowsPrec :: Int -> Precision -> ShowS
Show, Precision -> Precision -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Precision -> Precision -> Bool
$c/= :: Precision -> Precision -> Bool
== :: Precision -> Precision -> Bool
$c== :: Precision -> Precision -> Bool
Eq, Eq Precision
Precision -> Precision -> Bool
Precision -> Precision -> Ordering
Precision -> Precision -> Precision
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Precision -> Precision -> Precision
$cmin :: Precision -> Precision -> Precision
max :: Precision -> Precision -> Precision
$cmax :: Precision -> Precision -> Precision
>= :: Precision -> Precision -> Bool
$c>= :: Precision -> Precision -> Bool
> :: Precision -> Precision -> Bool
$c> :: Precision -> Precision -> Bool
<= :: Precision -> Precision -> Bool
$c<= :: Precision -> Precision -> Bool
< :: Precision -> Precision -> Bool
$c< :: Precision -> Precision -> Bool
compare :: Precision -> Precision -> Ordering
$ccompare :: Precision -> Precision -> Ordering
Ord)
  deriving newtype (Integer -> Precision
Precision -> Precision
Precision -> Precision -> Precision
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> Precision
$cfromInteger :: Integer -> Precision
signum :: Precision -> Precision
$csignum :: Precision -> Precision
abs :: Precision -> Precision
$cabs :: Precision -> Precision
negate :: Precision -> Precision
$cnegate :: Precision -> Precision
* :: Precision -> Precision -> Precision
$c* :: Precision -> Precision -> Precision
- :: Precision -> Precision -> Precision
$c- :: Precision -> Precision -> Precision
+ :: Precision -> Precision -> Precision
$c+ :: Precision -> Precision -> Precision
Num, Int -> Precision
Precision -> Int
Precision -> [Precision]
Precision -> Precision
Precision -> Precision -> [Precision]
Precision -> Precision -> Precision -> [Precision]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Precision -> Precision -> Precision -> [Precision]
$cenumFromThenTo :: Precision -> Precision -> Precision -> [Precision]
enumFromTo :: Precision -> Precision -> [Precision]
$cenumFromTo :: Precision -> Precision -> [Precision]
enumFromThen :: Precision -> Precision -> [Precision]
$cenumFromThen :: Precision -> Precision -> [Precision]
enumFrom :: Precision -> [Precision]
$cenumFrom :: Precision -> [Precision]
fromEnum :: Precision -> Int
$cfromEnum :: Precision -> Int
toEnum :: Int -> Precision
$ctoEnum :: Int -> Precision
pred :: Precision -> Precision
$cpred :: Precision -> Precision
succ :: Precision -> Precision
$csucc :: Precision -> Precision
Enum)

{-------------------------------------------------------------------------------
  Range
-------------------------------------------------------------------------------}

-- | Range of values
data Range a where
  -- | Constant (point) range
  Constant :: a -> Range a

  -- | Construct values in the range from a 'ProperFraction'
  --
  -- This is the main constructor for 'Range'.
  FromProperFraction :: Precision -> (ProperFraction -> a) -> Range a

  -- | Evaluate each range and choose the \"smallest\"
  --
  -- Each value in the range is annotated with some distance metric; for
  -- example, this could be the distance to some predefined point (e.g. as in
  -- 'Test.Falsify.Range.towards')
  Smallest :: Ord b => NonEmpty (Range (a, b)) -> Range a

deriving stock instance Functor Range