-- | Fixed precision generators
module Test.Falsify.Internal.Generator.Precision (
    wordN
  , properFraction
  ) where

import Prelude hiding (properFraction)

import GHC.Stack

import Data.Falsify.ProperFraction (ProperFraction)
import Data.Falsify.WordN (WordN)
import Test.Falsify.Internal.Generator
import Test.Falsify.Internal.Search

import qualified Data.Falsify.WordN      as WordN
import qualified Test.Falsify.SampleTree as SampleTree

{-------------------------------------------------------------------------------
  Generation
-------------------------------------------------------------------------------}

-- | Uniform selection of @n@-bit word of given precision, shrinking towards 0
wordN :: WordN.Precision -> Gen WordN
wordN :: Precision -> Gen WordN
wordN Precision
p =
    (Sample -> WordN) -> Gen Sample -> Gen WordN
forall a b. (a -> b) -> Gen a -> Gen b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Precision -> Word64 -> WordN
WordN.truncateAt Precision
p (Word64 -> WordN) -> (Sample -> Word64) -> Sample -> WordN
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Sample -> Word64
SampleTree.sampleValue) (Gen Sample -> Gen WordN)
-> ((Sample -> [Word64]) -> Gen Sample)
-> (Sample -> [Word64])
-> Gen WordN
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Sample -> [Word64]) -> Gen Sample
primWith ((Sample -> [Word64]) -> Gen WordN)
-> (Sample -> [Word64]) -> Gen WordN
forall a b. (a -> b) -> a -> b
$
        Word64 -> [Word64]
binarySearch
      (Word64 -> [Word64]) -> (Sample -> Word64) -> Sample -> [Word64]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WordN -> Word64
WordN.forgetPrecision
      (WordN -> Word64) -> (Sample -> WordN) -> Sample -> Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Precision -> Word64 -> WordN
WordN.truncateAt Precision
p
      (Word64 -> WordN) -> (Sample -> Word64) -> Sample -> WordN
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Sample -> Word64
SampleTree.sampleValue

-- | Uniform selection of fraction, shrinking towards 0
--
-- Precondition: precision must be at least 1 bit (a zero-bit number is constant
-- 0; it is meaningless to have a fraction in a point range).
properFraction :: HasCallStack => WordN.Precision -> Gen ProperFraction
properFraction :: HasCallStack => Precision -> Gen ProperFraction
properFraction (WordN.Precision Word8
0) = [Char] -> Gen ProperFraction
forall a. HasCallStack => [Char] -> a
error [Char]
"fraction: 0 precision"
properFraction Precision
p                   = WordN -> ProperFraction
WordN.toProperFraction (WordN -> ProperFraction) -> Gen WordN -> Gen ProperFraction
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Precision -> Gen WordN
wordN Precision
p