module Test.QuickCheck.DynamicLogic.CanGenerate (canGenerate) where

import System.IO.Unsafe
import Test.QuickCheck

-- | @canGenerate prob g p@
--   returns @False@ if we are sure @Prob(g generates x satisfying p) >= prob@
--   otherwise @True@ (and we know such an x can be generated).
canGenerate :: Double -> Gen a -> (a -> Bool) -> Bool
canGenerate :: forall a. Double -> Gen a -> (a -> Bool) -> Bool
canGenerate Double
prob Gen a
g a -> Bool
p = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ Double -> IO Bool
tryToGenerate Double
1
 where
  tryToGenerate :: Double -> IO Bool
tryToGenerate Double
luck
    | Double
luck forall a. Ord a => a -> a -> Bool
< Double
eps = forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
    | Bool
otherwise = do
        a
x <- forall a. Gen a -> IO a
generate Gen a
g
        if a -> Bool
p a
x
          then forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
          else Double -> IO Bool
tryToGenerate (Double
luck forall a. Num a => a -> a -> a
* (Double
1 forall a. Num a => a -> a -> a
- Double
prob))

  -- Our confidence level is 1-eps
  eps :: Double
eps = Double
1.0e-9