{-# OPTIONS_HADDOCK prune #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE RecordWildCards #-}
module Censor (
Hypothesis(..)
, fixVsRandom
, fixVsRandomCtx
, Config(..)
, defaultConfig
, Result(..)
, resPeakCdf
, Advisory(..)
, ClipRates(..)
, LeakShape(..)
, diagnose
, leakShape
, CensorError(..)
, runCT
, runCTWith
, Frame(..)
, runCTAttributed
, Split(..)
, runSplit
, runSplitWith
, attributeSplit
, calibrateBatch
, CalibReport(..)
, calibrateBatchReport
, Noise(..)
, baselineReading
, toAA
, runAA
, toBB
, runBB
, Attribution(..)
, ControlVerdict(..)
, attribute
, Meter(..)
, wallClock
, Counter(..)
, MeterError(..)
, withCounter
, SplitMeter(..)
, withSplitMeter
, Rng
, mkRng
, nextWord
, reseed
, randomBytes
) where
import Control.Exception (Exception, IOException, throwIO, try)
import Control.Monad (unless)
import qualified Data.Bits as B
import qualified Data.ByteString as BS
import Data.IORef (newIORef, readIORef, writeIORef)
import Data.List (sort, sortBy)
import Data.Primitive.SmallArray
(SmallArray, indexSmallArray, smallArrayFromListN)
import Data.Word (Word64)
import GHC.Clock (getMonotonicTimeNSec)
import System.IO (IOMode(ReadMode), withBinaryFile)
import qualified Numeric.Eproc.Bernoulli.TwoSided as EPSign
import qualified Numeric.Eproc.Bounded as EPMagn
import qualified Numeric.Eproc.ConfSeq as EPCS
import qualified Numeric.Eproc.Mixture as EPMix
import Numeric.Eproc.Bounded (Bettor(Newton), ConfigError)
import Censor.Meter
import Censor.Rng
(Rng, mkRng, nextWord, randomBytes, reseed, splitMix)
data Hypothesis a = Hypothesis
{ forall a. Hypothesis a -> a -> IO ()
target :: !(a -> IO ())
, forall a. Hypothesis a -> IO ()
prepare :: !(IO ())
, forall a. Hypothesis a -> IO a
sampleA :: !(IO a)
, forall a. Hypothesis a -> IO a
sampleB :: !(IO a)
}
fixVsRandom
:: (a -> IO ())
-> IO s
-> (s -> IO s)
-> (s -> IO a)
-> IO (Hypothesis a)
fixVsRandom :: forall a s.
(a -> IO ())
-> IO s -> (s -> IO s) -> (s -> IO a) -> IO (Hypothesis a)
fixVsRandom a -> IO ()
tgt IO s
sec s -> IO s
dup s -> IO a
embed = do
!fix <- IO s
sec
pure Hypothesis
{ target = tgt
, prepare = pure ()
, sampleA = do
!_ <- sec
!s <- dup fix
embed s
, sampleB = do
!s <- sec
!_ <- dup fix
embed s
}
fixVsRandomCtx
:: (a -> IO ())
-> IO s
-> (s -> IO s)
-> IO c
-> (c -> s -> IO a)
-> IO (Hypothesis a)
fixVsRandomCtx :: forall a s c.
(a -> IO ())
-> IO s
-> (s -> IO s)
-> IO c
-> (c -> s -> IO a)
-> IO (Hypothesis a)
fixVsRandomCtx a -> IO ()
tgt IO s
sec s -> IO s
dup IO c
ctx c -> s -> IO a
embed = do
!fix <- IO s
sec
!c0 <- ctx
ref <- newIORef c0
pure Hypothesis
{ target = tgt
, prepare = do
!c <- ctx
writeIORef ref c
, sampleA = do
!_ <- sec
!s <- dup fix
!c <- readIORef ref
embed c s
, sampleB = do
!s <- sec
!_ <- dup fix
!c <- readIORef ref
embed c s
}
data Config = Config
{ Config -> Double
cfgAlpha :: !Double
, Config -> Int
cfgBudget :: !Int
, Config -> Int
cfgBatch :: !Int
, Config -> Int
cfgWarmup :: !Int
, Config -> Maybe Word64
cfgSeed :: !(Maybe Word64)
, Config -> Maybe Double
cfgMargin :: !(Maybe Double)
} deriving Int -> Config -> ShowS
[Config] -> ShowS
Config -> String
(Int -> Config -> ShowS)
-> (Config -> String) -> ([Config] -> ShowS) -> Show Config
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Config -> ShowS
showsPrec :: Int -> Config -> ShowS
$cshow :: Config -> String
show :: Config -> String
$cshowList :: [Config] -> ShowS
showList :: [Config] -> ShowS
Show
defaultConfig :: Config
defaultConfig :: Config
defaultConfig = Config
{ cfgAlpha :: Double
cfgAlpha = Double
1.0e-6
, cfgBudget :: Int
cfgBudget = Int
100000
, cfgBatch :: Int
cfgBatch = Int
1
, cfgWarmup :: Int
cfgWarmup = Int
200
, cfgSeed :: Maybe Word64
cfgSeed = Maybe Word64
forall a. Maybe a
Nothing
, cfgMargin :: Maybe Double
cfgMargin = Maybe Double
forall a. Maybe a
Nothing
}
data Result
= Reject
{ Result -> Int
resPairs :: {-# UNPACK #-} !Int
, Result -> Double
resPeakLogW :: {-# UNPACK #-} !Double
, Result -> Double
resPValue :: {-# UNPACK #-} !Double
, Result -> (Double, Double)
resEffect :: !(Double, Double)
, Result -> Int
resClipped :: {-# UNPACK #-} !Int
, Result -> Int
resClipped4 :: {-# UNPACK #-} !Int
, Result -> Int
resClipped16 :: {-# UNPACK #-} !Int
, Result -> Double
resBound :: {-# UNPACK #-} !Double
, Result -> Double
resPeakSign :: {-# UNPACK #-} !Double
, Result -> Double
resPeakMagn :: {-# UNPACK #-} !Double
, Result -> Double
resPeakMagn4 :: {-# UNPACK #-} !Double
, Result -> Double
resPeakMagn16 :: {-# UNPACK #-} !Double
, Result -> [(Double, Double)]
resCdf :: ![(Double, Double)]
, Result -> Word64
resSeed :: {-# UNPACK #-} !Word64
, Result -> Maybe Double
resMargin :: !(Maybe Double)
}
| Pass
{ resPairs :: {-# UNPACK #-} !Int
, resPeakLogW :: {-# UNPACK #-} !Double
, resPValue :: {-# UNPACK #-} !Double
, resEffect :: !(Double, Double)
, resClipped :: {-# UNPACK #-} !Int
, resClipped4 :: {-# UNPACK #-} !Int
, resClipped16 :: {-# UNPACK #-} !Int
, resBound :: {-# UNPACK #-} !Double
, resPeakSign :: {-# UNPACK #-} !Double
, resPeakMagn :: {-# UNPACK #-} !Double
, resPeakMagn4 :: {-# UNPACK #-} !Double
, resPeakMagn16 :: {-# UNPACK #-} !Double
, resCdf :: ![(Double, Double)]
, resSeed :: {-# UNPACK #-} !Word64
, resMargin :: !(Maybe Double)
}
deriving Int -> Result -> ShowS
[Result] -> ShowS
Result -> String
(Int -> Result -> ShowS)
-> (Result -> String) -> ([Result] -> ShowS) -> Show Result
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Result -> ShowS
showsPrec :: Int -> Result -> ShowS
$cshow :: Result -> String
show :: Result -> String
$cshowList :: [Result] -> ShowS
showList :: [Result] -> ShowS
Show
resPeakCdf :: Result -> Double
resPeakCdf :: Result -> Double
resPeakCdf = ((Double, Double) -> Double -> Double)
-> Double -> [(Double, Double)] -> Double
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\(Double
_, Double
p) Double
acc -> Double -> Double -> Double
forall a. Ord a => a -> a -> a
max Double
p Double
acc) Double
0 ([(Double, Double)] -> Double)
-> (Result -> [(Double, Double)]) -> Result -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Result -> [(Double, Double)]
resCdf
data Advisory
= HighClipRate !ClipRates
| LowPower !Double
| RejectionDriver !LeakShape
deriving (Advisory -> Advisory -> Bool
(Advisory -> Advisory -> Bool)
-> (Advisory -> Advisory -> Bool) -> Eq Advisory
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Advisory -> Advisory -> Bool
== :: Advisory -> Advisory -> Bool
$c/= :: Advisory -> Advisory -> Bool
/= :: Advisory -> Advisory -> Bool
Eq, Int -> Advisory -> ShowS
[Advisory] -> ShowS
Advisory -> String
(Int -> Advisory -> ShowS)
-> (Advisory -> String) -> ([Advisory] -> ShowS) -> Show Advisory
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Advisory -> ShowS
showsPrec :: Int -> Advisory -> ShowS
$cshow :: Advisory -> String
show :: Advisory -> String
$cshowList :: [Advisory] -> ShowS
showList :: [Advisory] -> ShowS
Show)
data ClipRates = ClipRates
{ ClipRates -> Double
clipTight :: {-# UNPACK #-} !Double
, ClipRates -> Double
clipWide :: {-# UNPACK #-} !Double
, ClipRates -> Double
clipWidest :: {-# UNPACK #-} !Double
} deriving (ClipRates -> ClipRates -> Bool
(ClipRates -> ClipRates -> Bool)
-> (ClipRates -> ClipRates -> Bool) -> Eq ClipRates
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ClipRates -> ClipRates -> Bool
== :: ClipRates -> ClipRates -> Bool
$c/= :: ClipRates -> ClipRates -> Bool
/= :: ClipRates -> ClipRates -> Bool
Eq, Int -> ClipRates -> ShowS
[ClipRates] -> ShowS
ClipRates -> String
(Int -> ClipRates -> ShowS)
-> (ClipRates -> String)
-> ([ClipRates] -> ShowS)
-> Show ClipRates
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ClipRates -> ShowS
showsPrec :: Int -> ClipRates -> ShowS
$cshow :: ClipRates -> String
show :: ClipRates -> String
$cshowList :: [ClipRates] -> ShowS
showList :: [ClipRates] -> ShowS
Show)
data LeakShape
= BulkShift
| ShapeLeak
| RareOutlier
| CdfShift
| MixedShape
deriving (LeakShape -> LeakShape -> Bool
(LeakShape -> LeakShape -> Bool)
-> (LeakShape -> LeakShape -> Bool) -> Eq LeakShape
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LeakShape -> LeakShape -> Bool
== :: LeakShape -> LeakShape -> Bool
$c/= :: LeakShape -> LeakShape -> Bool
/= :: LeakShape -> LeakShape -> Bool
Eq, Int -> LeakShape -> ShowS
[LeakShape] -> ShowS
LeakShape -> String
(Int -> LeakShape -> ShowS)
-> (LeakShape -> String)
-> ([LeakShape] -> ShowS)
-> Show LeakShape
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LeakShape -> ShowS
showsPrec :: Int -> LeakShape -> ShowS
$cshow :: LeakShape -> String
show :: LeakShape -> String
$cshowList :: [LeakShape] -> ShowS
showList :: [LeakShape] -> ShowS
Show)
diagnose :: Result -> [Advisory]
diagnose :: Result -> [Advisory]
diagnose Result
r =
let rate :: a -> Double
rate a
n = if Result -> Int
resPairs Result
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
then Double
0
else a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ (Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Result -> Int
resPairs Result
r) :: Double)
!rates :: ClipRates
rates = Double -> Double -> Double -> ClipRates
ClipRates (Int -> Double
forall {a}. Integral a => a -> Double
rate (Result -> Int
resClipped Result
r)) (Int -> Double
forall {a}. Integral a => a -> Double
rate (Result -> Int
resClipped4 Result
r))
(Int -> Double
forall {a}. Integral a => a -> Double
rate (Result -> Int
resClipped16 Result
r))
clipA :: [Advisory]
clipA = [ClipRates -> Advisory
HighClipRate ClipRates
rates | ClipRates -> Double
clipTight ClipRates
rates Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0.05]
powerA :: [Advisory]
powerA = case Result
r of
Pass{} ->
let !hw :: Double
hw = ((Double, Double) -> Double
forall a b. (a, b) -> b
snd (Result -> (Double, Double)
resEffect Result
r) Double -> Double -> Double
forall a. Num a => a -> a -> a
- (Double, Double) -> Double
forall a b. (a, b) -> a
fst (Result -> (Double, Double)
resEffect Result
r)) Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
2
!c :: Double
c = Result -> Double
resBound Result
r
in [Double -> Advisory
LowPower (Double
hw Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
c) | Double
c Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0 Bool -> Bool -> Bool
&& Double
hw Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
c]
Reject{} -> []
drvA :: [Advisory]
drvA = case Result
r of
Reject{} -> [LeakShape -> Advisory
RejectionDriver (Result -> LeakShape
leakShape Result
r)]
Pass{} -> []
in [Advisory]
clipA [Advisory] -> [Advisory] -> [Advisory]
forall a. [a] -> [a] -> [a]
++ [Advisory]
powerA [Advisory] -> [Advisory] -> [Advisory]
forall a. [a] -> [a] -> [a]
++ [Advisory]
drvA
leakShape :: Result -> LeakShape
leakShape :: Result -> LeakShape
leakShape Result
r =
let !sig :: Double
sig = Result -> Double
resPeakSign Result
r
!mag :: Double
mag = Result -> Double
resPeakMagn Result
r
!tl :: Double
tl = Double -> Double -> Double
forall a. Ord a => a -> a -> a
max (Result -> Double
resPeakMagn4 Result
r) (Result -> Double
resPeakMagn16 Result
r)
!cdf :: Double
cdf = Result -> Double
resPeakCdf Result
r
candidates :: [(Double, LeakShape)]
candidates = case Result -> Maybe Double
resMargin Result
r of
Just Double
_ -> [ (Double
mag, LeakShape
BulkShift)
, (Double
tl, LeakShape
RareOutlier)
]
Maybe Double
Nothing -> [ (Double
sig, LeakShape
ShapeLeak)
, (Double
mag, LeakShape
BulkShift)
, (Double
tl, LeakShape
RareOutlier)
, (Double
cdf, LeakShape
CdfShift)
]
ranked :: [(Double, LeakShape)]
ranked = ((Double, LeakShape) -> (Double, LeakShape) -> Ordering)
-> [(Double, LeakShape)] -> [(Double, LeakShape)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (\(Double, LeakShape)
a (Double, LeakShape)
b -> Double -> Double -> Ordering
forall a. Ord a => a -> a -> Ordering
compare ((Double, LeakShape) -> Double
forall a b. (a, b) -> a
fst (Double, LeakShape)
b) ((Double, LeakShape) -> Double
forall a b. (a, b) -> a
fst (Double, LeakShape)
a)) [(Double, LeakShape)]
candidates
in case [(Double, LeakShape)]
ranked of
(Double
p1, LeakShape
s1) : (Double
p2, LeakShape
_) : [(Double, LeakShape)]
_
| Double
p1 Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
1.5 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double -> Double -> Double
forall a. Ord a => a -> a -> a
max Double
0 Double
p2 -> LeakShape
s1
| Bool
otherwise -> LeakShape
MixedShape
[(Double, LeakShape)]
_ -> LeakShape
MixedShape
data CensorError =
WarmupZeroDuration
| InvalidConfig !String
| InvalidEprocConfig !ConfigError
deriving (CensorError -> CensorError -> Bool
(CensorError -> CensorError -> Bool)
-> (CensorError -> CensorError -> Bool) -> Eq CensorError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CensorError -> CensorError -> Bool
== :: CensorError -> CensorError -> Bool
$c/= :: CensorError -> CensorError -> Bool
/= :: CensorError -> CensorError -> Bool
Eq, Int -> CensorError -> ShowS
[CensorError] -> ShowS
CensorError -> String
(Int -> CensorError -> ShowS)
-> (CensorError -> String)
-> ([CensorError] -> ShowS)
-> Show CensorError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CensorError -> ShowS
showsPrec :: Int -> CensorError -> ShowS
$cshow :: CensorError -> String
show :: CensorError -> String
$cshowList :: [CensorError] -> ShowS
showList :: [CensorError] -> ShowS
Show)
instance Exception CensorError
data Frame = Frame
{ Frame -> Int
frPair :: {-# UNPACK #-} !Int
, Frame -> Double
frDiff :: {-# UNPACK #-} !Double
, Frame -> Double
frLogW :: {-# UNPACK #-} !Double
, Frame -> Double
frLogWSup :: {-# UNPACK #-} !Double
, Frame -> Double
frLo :: {-# UNPACK #-} !Double
, Frame -> Double
frHi :: {-# UNPACK #-} !Double
, Frame -> Bool
frClipped :: !Bool
} deriving Int -> Frame -> ShowS
[Frame] -> ShowS
Frame -> String
(Int -> Frame -> ShowS)
-> (Frame -> String) -> ([Frame] -> ShowS) -> Show Frame
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Frame -> ShowS
showsPrec :: Int -> Frame -> ShowS
$cshow :: Frame -> String
show :: Frame -> String
$cshowList :: [Frame] -> ShowS
showList :: [Frame] -> ShowS
Show
runCTWith
:: Meter -> Config -> Hypothesis a -> (Frame -> IO ()) -> IO Result
runCTWith :: forall a.
Meter -> Config -> Hypothesis a -> (Frame -> IO ()) -> IO Result
runCTWith Meter
meter Config
cfg Hypothesis a
hyp Frame -> IO ()
observe = do
Config -> IO ()
validateConfig Config
cfg
(!root, !wSeed, !mSeed) <- Maybe Word64 -> IO (Word64, Word64, Word64)
resolveSeeds (Config -> Maybe Word64
cfgSeed Config
cfg)
let !samplers = Hypothesis a -> SmallArray (IO a)
forall a. Hypothesis a -> SmallArray (IO a)
orderedSamplers Hypothesis a
hyp
pair = Meter
-> Config
-> Hypothesis a
-> SmallArray (IO a)
-> Word64
-> IO (Word64, Word64)
forall a.
Meter
-> Config
-> Hypothesis a
-> SmallArray (IO a)
-> Word64
-> IO (Word64, Word64)
runPair Meter
meter Config
cfg Hypothesis a
hyp SmallArray (IO a)
samplers
ws <- warmup cfg pair wSeed
!ch <- channel cfg [ (fromIntegral x, fromIntegral y) | (x, y) <- ws ]
let go !Int
n !ChanState
st !Word64
rng
| Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Config -> Int
cfgBudget Config
cfg = Result -> IO Result
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Result -> IO Result) -> Result -> IO Result
forall a b. (a -> b) -> a -> b
$! Chan -> Word64 -> Int -> ChanState -> Result
chanResult Chan
ch Word64
root Int
n ChanState
st
| Bool
otherwise = do
let (!Word64
rng', !Word64
bit) = Word64 -> (Word64, Word64)
nextOrderBit Word64
rng
(!ta, !tb) <- Word64 -> IO (Word64, Word64)
pair Word64
bit
let !xa = Word64 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
ta :: Double
!xb = Word64 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
tb :: Double
!st' = Chan -> ChanState -> Double -> Double -> ChanState
stepChan Chan
ch ChanState
st Double
xa Double
xb
!n' = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
observe (chanFrame ch n' (xa - xb) st')
if chanRejects ch st'
then pure $! chanResult ch root n' st'
else go n' st' rng'
go 0 (chanInitial ch) mSeed
runCT :: Meter -> Config -> Hypothesis a -> IO Result
runCT :: forall a. Meter -> Config -> Hypothesis a -> IO Result
runCT Meter
meter Config
cfg Hypothesis a
hyp = Meter -> Config -> Hypothesis a -> (Frame -> IO ()) -> IO Result
forall a.
Meter -> Config -> Hypothesis a -> (Frame -> IO ()) -> IO Result
runCTWith Meter
meter Config
cfg Hypothesis a
hyp (\Frame
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ())
runCTAttributed
:: Meter -> Config -> Hypothesis a -> IO (Result, Maybe Attribution)
runCTAttributed :: forall a.
Meter -> Config -> Hypothesis a -> IO (Result, Maybe Attribution)
runCTAttributed Meter
meter Config
cfg Hypothesis a
hyp = do
r <- Meter -> Config -> Hypothesis a -> IO Result
forall a. Meter -> Config -> Hypothesis a -> IO Result
runCT Meter
meter Config
cfg Hypothesis a
hyp
case r of
Reject{} -> do
att <- Meter -> Config -> Hypothesis a -> IO Attribution
forall a. Meter -> Config -> Hypothesis a -> IO Attribution
attribute Meter
meter Config
cfg Hypothesis a
hyp
pure (r, Just att)
Pass{} -> (Result, Maybe Attribution) -> IO (Result, Maybe Attribution)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Result
r, Maybe Attribution
forall a. Maybe a
Nothing)
data Split a = Split
{ forall a. Split a -> a
splitCycles :: !a
, forall a. Split a -> a
splitPeriod :: !a
, forall a. Split a -> a
splitWall :: !a
} deriving (Split a -> Split a -> Bool
(Split a -> Split a -> Bool)
-> (Split a -> Split a -> Bool) -> Eq (Split a)
forall a. Eq a => Split a -> Split a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => Split a -> Split a -> Bool
== :: Split a -> Split a -> Bool
$c/= :: forall a. Eq a => Split a -> Split a -> Bool
/= :: Split a -> Split a -> Bool
Eq, Int -> Split a -> ShowS
[Split a] -> ShowS
Split a -> String
(Int -> Split a -> ShowS)
-> (Split a -> String) -> ([Split a] -> ShowS) -> Show (Split a)
forall a. Show a => Int -> Split a -> ShowS
forall a. Show a => [Split a] -> ShowS
forall a. Show a => Split a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> Split a -> ShowS
showsPrec :: Int -> Split a -> ShowS
$cshow :: forall a. Show a => Split a -> String
show :: Split a -> String
$cshowList :: forall a. Show a => [Split a] -> ShowS
showList :: [Split a] -> ShowS
Show)
instance Functor Split where
fmap :: forall a b. (a -> b) -> Split a -> Split b
fmap a -> b
f (Split a
c a
p a
w) = b -> b -> b -> Split b
forall a. a -> a -> a -> Split a
Split (a -> b
f a
c) (a -> b
f a
p) (a -> b
f a
w)
runSplitWith
:: SplitMeter -> Config -> Hypothesis a -> (Frame -> IO ())
-> IO (Split Result)
runSplitWith :: forall a.
SplitMeter
-> Config -> Hypothesis a -> (Frame -> IO ()) -> IO (Split Result)
runSplitWith SplitMeter
meter Config
cfg Hypothesis a
hyp Frame -> IO ()
observe = do
Config -> IO ()
validateConfig Config
cfg
(!root, !wSeed, !mSeed) <- Maybe Word64 -> IO (Word64, Word64, Word64)
resolveSeeds (Config -> Maybe Word64
cfgSeed Config
cfg)
let !samplers = Hypothesis a -> SmallArray (IO a)
forall a. Hypothesis a -> SmallArray (IO a)
orderedSamplers Hypothesis a
hyp
pair = SplitMeter
-> Config
-> Hypothesis a
-> SmallArray (IO a)
-> Word64
-> IO (Word64, Word64, Word64, Word64)
forall a.
SplitMeter
-> Config
-> Hypothesis a
-> SmallArray (IO a)
-> Word64
-> IO (Word64, Word64, Word64, Word64)
runSplitPair SplitMeter
meter Config
cfg Hypothesis a
hyp SmallArray (IO a)
samplers
ws <- warmup cfg pair wSeed
let rs = ((Word64, Word64, Word64, Word64) -> Split (Double, Double))
-> [(Word64, Word64, Word64, Word64)] -> [Split (Double, Double)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Word64, Word64, Word64, Word64) -> Split (Double, Double)
splitReadings [(Word64, Word64, Word64, Word64)]
ws
!cc <- channel cfg (fmap splitCycles rs)
!cp <- channel cfg (fmap splitPeriod rs)
!cw <- channel cfg (fmap splitWall rs)
let finish !Int
n !ChanState
sc !ChanState
sp !ChanState
sw = Result -> Result -> Result -> Split Result
forall a. a -> a -> a -> Split a
Split
(Chan -> Word64 -> Int -> ChanState -> Result
chanResult Chan
cc Word64
root Int
n ChanState
sc)
(Chan -> Word64 -> Int -> ChanState -> Result
chanResult Chan
cp Word64
root Int
n ChanState
sp)
(Chan -> Word64 -> Int -> ChanState -> Result
chanResult Chan
cw Word64
root Int
n ChanState
sw)
go !Int
n !ChanState
sc !ChanState
sp !ChanState
sw !Word64
rng
| Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Config -> Int
cfgBudget Config
cfg = Split Result -> IO (Split Result)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Split Result -> IO (Split Result))
-> Split Result -> IO (Split Result)
forall a b. (a -> b) -> a -> b
$! Int -> ChanState -> ChanState -> ChanState -> Split Result
finish Int
n ChanState
sc ChanState
sp ChanState
sw
| Bool
otherwise = do
let (!Word64
rng', !Word64
bit) = Word64 -> (Word64, Word64)
nextOrderBit Word64
rng
!r <- Word64 -> IO (Word64, Word64, Word64, Word64)
pair Word64
bit
case splitReadings r of
Split (!Double
ca, !Double
cb) (!Double
pa, !Double
pb) (!Double
wa, !Double
wb) -> do
let !sc' :: ChanState
sc' = Chan -> ChanState -> Double -> Double -> ChanState
stepChan Chan
cc ChanState
sc Double
ca Double
cb
!sp' :: ChanState
sp' = Chan -> ChanState -> Double -> Double -> ChanState
stepChan Chan
cp ChanState
sp Double
pa Double
pb
!sw' :: ChanState
sw' = Chan -> ChanState -> Double -> Double -> ChanState
stepChan Chan
cw ChanState
sw Double
wa Double
wb
!n' :: Int
n' = Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
Frame -> IO ()
observe (Chan -> Int -> Double -> ChanState -> Frame
chanFrame Chan
cc Int
n' (Double
ca Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
cb) ChanState
sc')
if Chan -> ChanState -> Bool
chanRejects Chan
cc ChanState
sc'
then Split Result -> IO (Split Result)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Split Result -> IO (Split Result))
-> Split Result -> IO (Split Result)
forall a b. (a -> b) -> a -> b
$! Int -> ChanState -> ChanState -> ChanState -> Split Result
finish Int
n' ChanState
sc' ChanState
sp' ChanState
sw'
else Int
-> ChanState
-> ChanState
-> ChanState
-> Word64
-> IO (Split Result)
go Int
n' ChanState
sc' ChanState
sp' ChanState
sw' Word64
rng'
go 0 (chanInitial cc) (chanInitial cp) (chanInitial cw) mSeed
runSplit :: SplitMeter -> Config -> Hypothesis a -> IO (Split Result)
runSplit :: forall a. SplitMeter -> Config -> Hypothesis a -> IO (Split Result)
runSplit SplitMeter
meter Config
cfg Hypothesis a
hyp = SplitMeter
-> Config -> Hypothesis a -> (Frame -> IO ()) -> IO (Split Result)
forall a.
SplitMeter
-> Config -> Hypothesis a -> (Frame -> IO ()) -> IO (Split Result)
runSplitWith SplitMeter
meter Config
cfg Hypothesis a
hyp (\Frame
_ -> () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ())
attributeSplit
:: SplitMeter -> Config -> Hypothesis a -> IO (Split Attribution)
attributeSplit :: forall a.
SplitMeter -> Config -> Hypothesis a -> IO (Split Attribution)
attributeSplit SplitMeter
meter Config
cfg Hypothesis a
hyp = do
Split ac ap aw <- SplitMeter -> Config -> Hypothesis a -> IO (Split Result)
forall a. SplitMeter -> Config -> Hypothesis a -> IO (Split Result)
runSplit SplitMeter
meter Config
cfg (Hypothesis a -> Hypothesis a
forall a. Hypothesis a -> Hypothesis a
toAA Hypothesis a
hyp)
Split bc bp bw <- runSplit meter cfg (toBB hyp)
pure $! Split (attribution ac bc) (attribution ap bp)
(attribution aw bw)
calibrateBatch :: Meter -> Hypothesis a -> IO Int
calibrateBatch :: forall a. Meter -> Hypothesis a -> IO Int
calibrateBatch Meter
meter Hypothesis a
hyp = (CalibReport -> Int) -> IO CalibReport -> IO Int
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap CalibReport -> Int
crBatch (Meter -> Hypothesis a -> IO CalibReport
forall a. Meter -> Hypothesis a -> IO CalibReport
calibrateBatchReport Meter
meter Hypothesis a
hyp)
data CalibReport = CalibReport
{ CalibReport -> Int
crBatch :: {-# UNPACK #-} !Int
, CalibReport -> [(Int, Word64)]
crProbes :: ![(Int, Word64)]
, CalibReport -> Bool
crCapHit :: !Bool
, CalibReport -> Double
crTargetMag :: {-# UNPACK #-} !Double
, CalibReport -> Maybe Noise
crNoise :: !(Maybe Noise)
} deriving Int -> CalibReport -> ShowS
[CalibReport] -> ShowS
CalibReport -> String
(Int -> CalibReport -> ShowS)
-> (CalibReport -> String)
-> ([CalibReport] -> ShowS)
-> Show CalibReport
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CalibReport -> ShowS
showsPrec :: Int -> CalibReport -> ShowS
$cshow :: CalibReport -> String
show :: CalibReport -> String
$cshowList :: [CalibReport] -> ShowS
showList :: [CalibReport] -> ShowS
Show
data Noise = Noise
{ Noise -> Word64
nsMedian :: {-# UNPACK #-} !Word64
, Noise -> Word64
nsIqr :: {-# UNPACK #-} !Word64
} deriving (Noise -> Noise -> Bool
(Noise -> Noise -> Bool) -> (Noise -> Noise -> Bool) -> Eq Noise
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Noise -> Noise -> Bool
== :: Noise -> Noise -> Bool
$c/= :: Noise -> Noise -> Bool
/= :: Noise -> Noise -> Bool
Eq, Int -> Noise -> ShowS
[Noise] -> ShowS
Noise -> String
(Int -> Noise -> ShowS)
-> (Noise -> String) -> ([Noise] -> ShowS) -> Show Noise
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Noise -> ShowS
showsPrec :: Int -> Noise -> ShowS
$cshow :: Noise -> String
show :: Noise -> String
$cshowList :: [Noise] -> ShowS
showList :: [Noise] -> ShowS
Show)
calibrateBatchReport :: Meter -> Hypothesis a -> IO CalibReport
calibrateBatchReport :: forall a. Meter -> Hypothesis a -> IO CalibReport
calibrateBatchReport Meter
meter Hypothesis a
hyp = do
Hypothesis a -> IO ()
forall a. Hypothesis a -> IO ()
prepare Hypothesis a
hyp
!x <- Hypothesis a -> IO a
forall a. Hypothesis a -> IO a
sampleA Hypothesis a
hyp
let !act = Hypothesis a -> a -> IO ()
forall a. Hypothesis a -> a -> IO ()
target Hypothesis a
hyp a
x
probe !Int
b ![(Int, Word64)]
ps
| Int
b Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
calibCap =
CalibReport -> IO CalibReport
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CalibReport -> IO CalibReport) -> CalibReport -> IO CalibReport
forall a b. (a -> b) -> a -> b
$! Int -> Bool -> Maybe Noise -> [(Int, Word64)] -> CalibReport
finish Int
1 Bool
True Maybe Noise
forall a. Maybe a
Nothing [(Int, Word64)]
ps
| Bool
otherwise = do
!r <- Meter -> IO () -> Int -> IO Word64
probeReading Meter
meter IO ()
act Int
b
let !ps' = (Int
b, Word64
r) (Int, Word64) -> [(Int, Word64)] -> [(Int, Word64)]
forall a. a -> [a] -> [a]
: [(Int, Word64)]
ps
if fromIntegral r < calibTarget
then probe (b * 4) ps'
else do
let !b' = Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
ceiling
(Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
b Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
calibTarget Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Word64 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
r)
!bf = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
calibCap Int
b')
!ns <- noiseReading meter act bf
pure $! finish bf False (Just ns) ps'
finish !Int
bf !Bool
cap !Maybe Noise
ns ![(Int, Word64)]
ps = CalibReport
{ crBatch :: Int
crBatch = Int
bf
, crProbes :: [(Int, Word64)]
crProbes = [(Int, Word64)] -> [(Int, Word64)]
forall a. [a] -> [a]
reverse [(Int, Word64)]
ps
, crCapHit :: Bool
crCapHit = Bool
cap
, crTargetMag :: Double
crTargetMag = Double
calibTarget
, crNoise :: Maybe Noise
crNoise = Maybe Noise
ns
}
probe 1 []
probeReading :: Meter -> IO () -> Int -> IO Word64
probeReading :: Meter -> IO () -> Int -> IO Word64
probeReading Meter
meter IO ()
act Int
b =
([Word64] -> Word64) -> IO [Word64] -> IO Word64
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Noise -> Word64
nsMedian (Noise -> Word64) -> ([Word64] -> Noise) -> [Word64] -> Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Word64] -> Noise
dispersion) (Int -> IO Word64 -> IO [Word64]
samples Int
calibProbes (Meter -> Int -> IO () -> IO Word64
measure Meter
meter Int
b IO ()
act))
noiseReading :: Meter -> IO () -> Int -> IO Noise
noiseReading :: Meter -> IO () -> Int -> IO Noise
noiseReading Meter
meter IO ()
act Int
b =
([Word64] -> Noise) -> IO [Word64] -> IO Noise
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Word64] -> Noise
dispersion (Int -> IO Word64 -> IO [Word64]
samples Int
noiseSamples (Meter -> Int -> IO () -> IO Word64
measure Meter
meter Int
b IO ()
act))
samples :: Int -> IO Word64 -> IO [Word64]
samples :: Int -> IO Word64 -> IO [Word64]
samples Int
n IO Word64
act = Int -> IO [Word64]
forall {t}. (Eq t, Num t) => t -> IO [Word64]
go Int
n
where
go :: t -> IO [Word64]
go t
0 = [Word64] -> IO [Word64]
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
go t
i = do
!r <- IO Word64
act
fmap (r :) (go (i - 1))
dispersion :: [Word64] -> Noise
dispersion :: [Word64] -> Noise
dispersion [Word64]
rs =
let !srt :: [Word64]
srt = [Word64] -> [Word64]
forall a. Ord a => [a] -> [a]
sort [Word64]
rs
!n :: Int
n = [Word64] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Word64]
srt
!med :: Word64
med = Int -> [Word64] -> Word64
forall a. Num a => Int -> [a] -> a
nth (Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2) [Word64]
srt
!q1 :: Word64
q1 = Int -> [Word64] -> Word64
forall a. Num a => Int -> [a] -> a
nth (Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
4) [Word64]
srt
!q3 :: Word64
q3 = Int -> [Word64] -> Word64
forall a. Num a => Int -> [a] -> a
nth (Int
3 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
4) [Word64]
srt
in Noise { nsMedian :: Word64
nsMedian = Word64
med, nsIqr :: Word64
nsIqr = Word64
q3 Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
- Word64
q1 }
baselineReading :: Meter -> Config -> Hypothesis a -> IO Noise
baselineReading :: forall a. Meter -> Config -> Hypothesis a -> IO Noise
baselineReading Meter
meter Config
cfg Hypothesis a
hyp =
([Word64] -> Noise) -> IO [Word64] -> IO Noise
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Word64] -> Noise
dispersion (Int -> IO Word64 -> IO [Word64]
samples Int
baselineSamples IO Word64
fresh)
where
fresh :: IO Word64
fresh = do
Hypothesis a -> IO ()
forall a. Hypothesis a -> IO ()
prepare Hypothesis a
hyp
!x <- Hypothesis a -> IO a
forall a. Hypothesis a -> IO a
sampleA Hypothesis a
hyp
measure meter (cfgBatch cfg) (target hyp x)
baselineSamples :: Int
baselineSamples :: Int
baselineSamples = Int
15
nth :: Num a => Int -> [a] -> a
nth :: forall a. Num a => Int -> [a] -> a
nth Int
k [a]
xs = case Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
drop Int
k [a]
xs of
(a
v : [a]
_) -> a
v
[] -> a
0
noiseSamples :: Int
noiseSamples :: Int
noiseSamples = Int
15
calibTarget :: Double
calibTarget :: Double
calibTarget = Double
65536
calibCap :: Int
calibCap :: Int
calibCap = Int
1000000
calibProbes :: Int
calibProbes :: Int
calibProbes = Int
5
toAA :: Hypothesis a -> Hypothesis a
toAA :: forall a. Hypothesis a -> Hypothesis a
toAA Hypothesis a
h = Hypothesis a
h { sampleB = sampleA h }
{-# INLINE toAA #-}
runAA :: Meter -> Config -> Hypothesis a -> IO Result
runAA :: forall a. Meter -> Config -> Hypothesis a -> IO Result
runAA Meter
meter Config
cfg Hypothesis a
hyp = Meter -> Config -> Hypothesis a -> IO Result
forall a. Meter -> Config -> Hypothesis a -> IO Result
runCT Meter
meter Config
cfg (Hypothesis a -> Hypothesis a
forall a. Hypothesis a -> Hypothesis a
toAA Hypothesis a
hyp)
toBB :: Hypothesis a -> Hypothesis a
toBB :: forall a. Hypothesis a -> Hypothesis a
toBB Hypothesis a
h = Hypothesis a
h { sampleA = sampleB h }
{-# INLINE toBB #-}
runBB :: Meter -> Config -> Hypothesis a -> IO Result
runBB :: forall a. Meter -> Config -> Hypothesis a -> IO Result
runBB Meter
meter Config
cfg Hypothesis a
hyp = Meter -> Config -> Hypothesis a -> IO Result
forall a. Meter -> Config -> Hypothesis a -> IO Result
runCT Meter
meter Config
cfg (Hypothesis a -> Hypothesis a
forall a. Hypothesis a -> Hypothesis a
toBB Hypothesis a
hyp)
data ControlVerdict
= ControlsPass
| SampleAAsymmetry
| SampleBAsymmetry
| PervasiveAsymmetry
deriving (ControlVerdict -> ControlVerdict -> Bool
(ControlVerdict -> ControlVerdict -> Bool)
-> (ControlVerdict -> ControlVerdict -> Bool) -> Eq ControlVerdict
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ControlVerdict -> ControlVerdict -> Bool
== :: ControlVerdict -> ControlVerdict -> Bool
$c/= :: ControlVerdict -> ControlVerdict -> Bool
/= :: ControlVerdict -> ControlVerdict -> Bool
Eq, Int -> ControlVerdict -> ShowS
[ControlVerdict] -> ShowS
ControlVerdict -> String
(Int -> ControlVerdict -> ShowS)
-> (ControlVerdict -> String)
-> ([ControlVerdict] -> ShowS)
-> Show ControlVerdict
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ControlVerdict -> ShowS
showsPrec :: Int -> ControlVerdict -> ShowS
$cshow :: ControlVerdict -> String
show :: ControlVerdict -> String
$cshowList :: [ControlVerdict] -> ShowS
showList :: [ControlVerdict] -> ShowS
Show)
data Attribution = Attribution
{ Attribution -> ControlVerdict
attVerdict :: !ControlVerdict
, Attribution -> Result
attAA :: !Result
, Attribution -> Result
attBB :: !Result
} deriving Int -> Attribution -> ShowS
[Attribution] -> ShowS
Attribution -> String
(Int -> Attribution -> ShowS)
-> (Attribution -> String)
-> ([Attribution] -> ShowS)
-> Show Attribution
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Attribution -> ShowS
showsPrec :: Int -> Attribution -> ShowS
$cshow :: Attribution -> String
show :: Attribution -> String
$cshowList :: [Attribution] -> ShowS
showList :: [Attribution] -> ShowS
Show
attribute :: Meter -> Config -> Hypothesis a -> IO Attribution
attribute :: forall a. Meter -> Config -> Hypothesis a -> IO Attribution
attribute Meter
meter Config
cfg Hypothesis a
hyp = do
raa <- Meter -> Config -> Hypothesis a -> IO Result
forall a. Meter -> Config -> Hypothesis a -> IO Result
runAA Meter
meter Config
cfg Hypothesis a
hyp
rbb <- runBB meter cfg hyp
pure $! attribution raa rbb
attribution :: Result -> Result -> Attribution
attribution :: Result -> Result -> Attribution
attribution Result
raa Result
rbb =
let !v :: ControlVerdict
v = case (Result
raa, Result
rbb) of
(Pass{}, Pass{}) -> ControlVerdict
ControlsPass
(Reject{}, Pass{}) -> ControlVerdict
SampleAAsymmetry
(Pass{}, Reject{}) -> ControlVerdict
SampleBAsymmetry
(Reject{}, Reject{}) -> ControlVerdict
PervasiveAsymmetry
in Attribution
{ attVerdict :: ControlVerdict
attVerdict = ControlVerdict
v
, attAA :: Result
attAA = Result
raa
, attBB :: Result
attBB = Result
rbb
}
validateConfig :: Config -> IO ()
validateConfig :: Config -> IO ()
validateConfig Config{Double
Int
Maybe Double
Maybe Word64
cfgAlpha :: Config -> Double
cfgBudget :: Config -> Int
cfgBatch :: Config -> Int
cfgWarmup :: Config -> Int
cfgSeed :: Config -> Maybe Word64
cfgMargin :: Config -> Maybe Double
cfgAlpha :: Double
cfgBudget :: Int
cfgBatch :: Int
cfgWarmup :: Int
cfgSeed :: Maybe Word64
cfgMargin :: Maybe Double
..}
| Int
cfgBatch Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = CensorError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (CensorError -> IO ()) -> CensorError -> IO ()
forall a b. (a -> b) -> a -> b
$! String -> CensorError
InvalidConfig
String
"cfgBatch must be positive"
| Int
cfgWarmup Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = CensorError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (CensorError -> IO ()) -> CensorError -> IO ()
forall a b. (a -> b) -> a -> b
$! String -> CensorError
InvalidConfig
String
"cfgWarmup must be positive"
| Int
cfgBudget Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = CensorError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (CensorError -> IO ()) -> CensorError -> IO ()
forall a b. (a -> b) -> a -> b
$! String -> CensorError
InvalidConfig
String
"cfgBudget must be nonnegative"
| Just Double
m <- Maybe Double
cfgMargin
, Bool -> Bool
not (Double
m Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0 Bool -> Bool -> Bool
&& Bool -> Bool
not (Double -> Bool
forall a. RealFloat a => a -> Bool
isNaN Double
m) Bool -> Bool -> Bool
&& Bool -> Bool
not (Double -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Double
m)) =
CensorError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (CensorError -> IO ()) -> CensorError -> IO ()
forall a b. (a -> b) -> a -> b
$! String -> CensorError
InvalidConfig
String
"cfgMargin must be a positive finite fraction"
| Bool
otherwise = () -> IO ()
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
orderedSamplers :: Hypothesis a -> SmallArray (IO a)
orderedSamplers :: forall a. Hypothesis a -> SmallArray (IO a)
orderedSamplers Hypothesis a
hyp =
let !sa :: IO a
sa = Hypothesis a -> IO a
forall a. Hypothesis a -> IO a
sampleA Hypothesis a
hyp
!sb :: IO a
sb = Hypothesis a -> IO a
forall a. Hypothesis a -> IO a
sampleB Hypothesis a
hyp
in Int -> [IO a] -> SmallArray (IO a)
forall a. Int -> [a] -> SmallArray a
smallArrayFromListN Int
2 [IO a
sa, IO a
sb]
runPair
:: Meter -> Config -> Hypothesis a -> SmallArray (IO a) -> Word64
-> IO (Word64, Word64)
runPair :: forall a.
Meter
-> Config
-> Hypothesis a
-> SmallArray (IO a)
-> Word64
-> IO (Word64, Word64)
runPair Meter
meter Config
cfg Hypothesis a
hyp SmallArray (IO a)
samplers !Word64
bit = do
Hypothesis a -> IO ()
forall a. Hypothesis a -> IO ()
prepare Hypothesis a
hyp
let !iFst :: Int
iFst = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
bit :: Int
!iSnd :: Int
iSnd = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
iFst
!u <- SmallArray (IO a) -> Int -> IO a
forall a. SmallArray a -> Int -> a
indexSmallArray SmallArray (IO a)
samplers Int
iFst
!t1 <- measure meter (cfgBatch cfg) (target hyp u)
!v <- indexSmallArray samplers iSnd
!t2 <- measure meter (cfgBatch cfg) (target hyp v)
let (!x, !y) = unscramble bit t1 t2
pure (x, y)
{-# INLINE runPair #-}
runSplitPair
:: SplitMeter -> Config -> Hypothesis a -> SmallArray (IO a) -> Word64
-> IO (Word64, Word64, Word64, Word64)
runSplitPair :: forall a.
SplitMeter
-> Config
-> Hypothesis a
-> SmallArray (IO a)
-> Word64
-> IO (Word64, Word64, Word64, Word64)
runSplitPair SplitMeter
meter Config
cfg Hypothesis a
hyp SmallArray (IO a)
samplers !Word64
bit = do
Hypothesis a -> IO ()
forall a. Hypothesis a -> IO ()
prepare Hypothesis a
hyp
let !iFst :: Int
iFst = Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
bit :: Int
!iSnd :: Int
iSnd = Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
iFst
!u <- SmallArray (IO a) -> Int -> IO a
forall a. SmallArray a -> Int -> a
indexSmallArray SmallArray (IO a)
samplers Int
iFst
(!c1, !w1) <- measureSplit meter (cfgBatch cfg) (target hyp u)
!v <- indexSmallArray samplers iSnd
(!c2, !w2) <- measureSplit meter (cfgBatch cfg) (target hyp v)
let (!ca, !cb) = unscramble bit c1 c2
(!wa, !wb) = unscramble bit w1 w2
pure (ca, wa, cb, wb)
{-# INLINE runSplitPair #-}
unscramble :: Word64 -> Word64 -> Word64 -> (Word64, Word64)
unscramble :: Word64 -> Word64 -> Word64 -> (Word64, Word64)
unscramble !Word64
bit !Word64
t1 !Word64
t2 =
let !m :: Word64
m = Word64 -> Word64
forall a. Num a => a -> a
negate Word64
bit
!s :: Word64
s = (Word64
t1 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`B.xor` Word64
t2) Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
B..&. Word64
m
in (Word64
t1 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`B.xor` Word64
s, Word64
t2 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
`B.xor` Word64
s)
{-# INLINE unscramble #-}
splitReadings :: (Word64, Word64, Word64, Word64) -> Split (Double, Double)
splitReadings :: (Word64, Word64, Word64, Word64) -> Split (Double, Double)
splitReadings (!Word64
ca, !Word64
wa, !Word64
cb, !Word64
wb) = (Double, Double)
-> (Double, Double) -> (Double, Double) -> Split (Double, Double)
forall a. a -> a -> a -> Split a
Split
(Word64 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
ca, Word64 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
cb)
(Word64 -> Word64 -> Double
forall {a} {a} {a}.
(Fractional a, Integral a, Integral a) =>
a -> a -> a
period Word64
wa Word64
ca, Word64 -> Word64 -> Double
forall {a} {a} {a}.
(Fractional a, Integral a, Integral a) =>
a -> a -> a
period Word64
wb Word64
cb)
(Word64 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
wa, Word64 -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
wb)
where
period :: a -> a -> a
period !a
w !a
c = a -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
w a -> a -> a
forall a. Num a => a -> a -> a
* a
1.0e6 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> a -> a
forall a. Ord a => a -> a -> a
max a
1 a
c)
data HedgeCfg = HedgeCfg
{ HedgeCfg -> Config
hcSign :: !EPSign.Config
, HedgeCfg -> Config
hcMagn1 :: !EPMagn.Config
, HedgeCfg -> Config
hcMagn2 :: !EPMagn.Config
, HedgeCfg -> Config
hcMagn3 :: !EPMagn.Config
, HedgeCfg -> Config
hcCdf :: !EPMagn.Config
, HedgeCfg -> [Double]
hcQs :: ![Double]
, HedgeCfg -> Config
hcMix :: !EPMix.Config
, HedgeCfg -> Double
hcC1 :: {-# UNPACK #-} !Double
, HedgeCfg -> Double
hcC2 :: {-# UNPACK #-} !Double
, HedgeCfg -> Double
hcC3 :: {-# UNPACK #-} !Double
, HedgeCfg -> Maybe Double
hcMargin :: !(Maybe Double)
}
data HedgeState = HedgeState
{ HedgeState -> State
hsSign :: !EPSign.State
, HedgeState -> State
hsMagn1 :: !EPMagn.State
, HedgeState -> State
hsMagn2 :: !EPMagn.State
, HedgeState -> State
hsMagn3 :: !EPMagn.State
, HedgeState -> [State]
hsCdf :: ![EPMagn.State]
, HedgeState -> State
hsMix :: !EPMix.State
}
mkHedgeCfg
:: Double -> Double -> [Double] -> Maybe Double
-> Either ConfigError HedgeCfg
mkHedgeCfg :: Double
-> Double
-> [Double]
-> Maybe Double
-> Either ConfigError HedgeCfg
mkHedgeCfg !Double
alpha !Double
c [Double]
qs Maybe Double
mmargin = do
let !c2 :: Double
c2 = Double
4 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
c
!c3 :: Double
c3 = Double
16 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
c
magn :: Double -> Either ConfigError Config
magn !Double
b = case Maybe Double
mmargin of
Maybe Double
Nothing -> Double
-> Double
-> Double
-> Double
-> Bettor
-> Either ConfigError Config
EPMagn.config Double
0 (Double -> Double
forall a. Num a => a -> a
negate Double
b) Double
b Double
alpha Bettor
Newton
Just Double
d ->
Double
-> Double
-> Double
-> Double
-> Double
-> Bettor
-> Either ConfigError Config
EPMagn.configInterval (Double -> Double
forall a. Num a => a -> a
negate Double
d) Double
d (Double -> Double
forall a. Num a => a -> a
negate Double
b) Double
b Double
alpha Bettor
Newton
!k :: Int
k = case Maybe Double
mmargin of
Maybe Double
Nothing -> Int
4 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
qs
Just Double
_ -> Int
3
!sc <- Double -> Double -> Bettor -> Either ConfigError Config
EPSign.config Double
0.5 Double
alpha Bettor
Newton
!m1 <- magn c
!m2 <- magn c2
!m3 <- magn c3
!cd <- EPMagn.config 0 (negate 1) 1 alpha Newton
!mx <- EPMix.config k alpha
pure HedgeCfg
{ hcSign = sc
, hcMagn1 = m1
, hcMagn2 = m2
, hcMagn3 = m3
, hcCdf = cd
, hcQs = qs
, hcMix = mx
, hcC1 = c
, hcC2 = c2
, hcC3 = c3
, hcMargin = mmargin
}
data Chan = Chan
{ Chan -> HedgeCfg
chHedge :: !HedgeCfg
, Chan -> Config
chSeq :: !EPCS.Config
}
data ChanState = ChanState
{ ChanState -> HedgeState
csHedge :: !HedgeState
, ChanState -> State
csSeq :: !EPCS.State
, ChanState -> (Double, Double)
csIv :: !(Double, Double)
, ChanState -> Clips
csClips :: !Clips
}
channel :: Config -> [(Double, Double)] -> IO Chan
channel :: Config -> [(Double, Double)] -> IO Chan
channel Config
cfg [(Double, Double)]
ws = do
let (!Double
c, ![Double]
qs, !Bool
meterResolves, !Double
medR) = [(Double, Double)] -> (Double, [Double], Bool, Double)
calibrate [(Double, Double)]
ws
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
meterResolves (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ CensorError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO CensorError
WarmupZeroDuration
!mdelta <- case Config -> Maybe Double
cfgMargin Config
cfg of
Maybe Double
Nothing -> Maybe Double -> IO (Maybe Double)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe Double
forall a. Maybe a
Nothing
Just Double
rel -> do
let !delta :: Double
delta = Double
rel Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
medR
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Double
delta Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ CensorError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (CensorError -> IO ()) -> CensorError -> IO ()
forall a b. (a -> b) -> a -> b
$! String -> CensorError
InvalidConfig
String
"cfgMargin resolves to a zero absolute margin (warmup \
\median reading is 0); raise cfgBatch"
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Double
delta Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
c) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ CensorError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (CensorError -> IO ()) -> CensorError -> IO ()
forall a b. (a -> b) -> a -> b
$! String -> CensorError
InvalidConfig
String
"cfgMargin resolves to an absolute margin at or above the \
\warmup clip bound; lower cfgMargin (the tolerance exceeds \
\the pair-noise scale the test bets against)"
Maybe Double -> IO (Maybe Double)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Double -> Maybe Double
forall a. a -> Maybe a
Just Double
delta)
!hcfg <- case mkHedgeCfg (cfgAlpha cfg) c qs mdelta of
Left ConfigError
e -> CensorError -> IO HedgeCfg
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (ConfigError -> CensorError
InvalidEprocConfig ConfigError
e)
Right HedgeCfg
x -> HedgeCfg -> IO HedgeCfg
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure HedgeCfg
x
!cscfg <- case EPCS.config (negate (hcC3 hcfg)) (hcC3 hcfg)
(cfgAlpha cfg) effectGrid of
Left ConfigError
e -> CensorError -> IO Config
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO (ConfigError -> CensorError
InvalidEprocConfig ConfigError
e)
Right Config
x -> Config -> IO Config
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Config
x
pure (Chan hcfg cscfg)
chanInitial :: Chan -> ChanState
chanInitial :: Chan -> ChanState
chanInitial Chan{Config
HedgeCfg
chHedge :: Chan -> HedgeCfg
chSeq :: Chan -> Config
chHedge :: HedgeCfg
chSeq :: Config
..} = ChanState
{ csHedge :: HedgeState
csHedge = HedgeCfg -> HedgeState
initialHedge HedgeCfg
chHedge
, csSeq :: State
csSeq = Config -> State
EPCS.initial Config
chSeq
, csIv :: (Double, Double)
csIv = (Double -> Double
forall a. Num a => a -> a
negate (HedgeCfg -> Double
hcC3 HedgeCfg
chHedge), HedgeCfg -> Double
hcC3 HedgeCfg
chHedge)
, csClips :: Clips
csClips = Clips
noClips
}
stepChan :: Chan -> ChanState -> Double -> Double -> ChanState
stepChan :: Chan -> ChanState -> Double -> Double -> ChanState
stepChan Chan{Config
HedgeCfg
chHedge :: Chan -> HedgeCfg
chSeq :: Chan -> Config
chHedge :: HedgeCfg
chSeq :: Config
..} ChanState{(Double, Double)
State
Clips
HedgeState
csHedge :: ChanState -> HedgeState
csSeq :: ChanState -> State
csIv :: ChanState -> (Double, Double)
csClips :: ChanState -> Clips
csHedge :: HedgeState
csSeq :: State
csIv :: (Double, Double)
csClips :: Clips
..} !Double
xa !Double
xb =
let !d :: Double
d = Double
xa Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
xb
!h' :: HedgeState
h' = HedgeCfg -> HedgeState -> Double -> Double -> Double -> HedgeState
updateHedge HedgeCfg
chHedge HedgeState
csHedge Double
d Double
xa Double
xb
!s' :: State
s' = Config -> State -> Double -> State
EPCS.update Config
chSeq State
csSeq (Double -> Double -> Double
clipD (HedgeCfg -> Double
hcC3 HedgeCfg
chHedge) Double
d)
!iv' :: (Double, Double)
iv' = case Config -> State -> Maybe (Double, Double)
EPCS.interval Config
chSeq State
s' of
Just (Double, Double)
x -> (Double, Double)
x
Maybe (Double, Double)
Nothing -> (Double, Double)
csIv
!cl' :: Clips
cl' = HedgeCfg -> Clips -> Double -> Clips
bumpClips HedgeCfg
chHedge Clips
csClips Double
d
in HedgeState -> State -> (Double, Double) -> Clips -> ChanState
ChanState HedgeState
h' State
s' (Double, Double)
iv' Clips
cl'
chanRejects :: Chan -> ChanState -> Bool
chanRejects :: Chan -> ChanState -> Bool
chanRejects Chan{Config
HedgeCfg
chHedge :: Chan -> HedgeCfg
chSeq :: Chan -> Config
chHedge :: HedgeCfg
chSeq :: Config
..} ChanState{(Double, Double)
State
Clips
HedgeState
csHedge :: ChanState -> HedgeState
csSeq :: ChanState -> State
csIv :: ChanState -> (Double, Double)
csClips :: ChanState -> Clips
csHedge :: HedgeState
csSeq :: State
csIv :: (Double, Double)
csClips :: Clips
..} =
case Config -> State -> Verdict
EPMix.decide (HedgeCfg -> Config
hcMix HedgeCfg
chHedge) (HedgeState -> State
hsMix HedgeState
csHedge) of
Verdict
EPMix.Reject -> Bool
True
Verdict
_ -> Bool
False
chanFrame :: Chan -> Int -> Double -> ChanState -> Frame
chanFrame :: Chan -> Int -> Double -> ChanState -> Frame
chanFrame Chan{Config
HedgeCfg
chHedge :: Chan -> HedgeCfg
chSeq :: Chan -> Config
chHedge :: HedgeCfg
chSeq :: Config
..} !Int
n !Double
d ChanState{(Double, Double)
State
Clips
HedgeState
csHedge :: ChanState -> HedgeState
csSeq :: ChanState -> State
csIv :: ChanState -> (Double, Double)
csClips :: ChanState -> Clips
csHedge :: HedgeState
csSeq :: State
csIv :: (Double, Double)
csClips :: Clips
..} = Int
-> Double -> Double -> Double -> Double -> Double -> Bool -> Frame
Frame Int
n Double
d
(Config -> State -> Double
EPMix.log_evalue Config
mixc (HedgeState -> State
hsMix HedgeState
csHedge))
(Config -> State -> Double
EPMix.log_evalue_sup Config
mixc (HedgeState -> State
hsMix HedgeState
csHedge))
((Double, Double) -> Double
forall a b. (a, b) -> a
fst (Double, Double)
csIv) ((Double, Double) -> Double
forall a b. (a, b) -> b
snd (Double, Double)
csIv)
(Double -> Double
forall a. Num a => a -> a
abs Double
d Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> HedgeCfg -> Double
hcC1 HedgeCfg
chHedge)
where
mixc :: Config
mixc = HedgeCfg -> Config
hcMix HedgeCfg
chHedge
chanResult :: Chan -> Word64 -> Int -> ChanState -> Result
chanResult :: Chan -> Word64 -> Int -> ChanState -> Result
chanResult ch :: Chan
ch@Chan{Config
HedgeCfg
chHedge :: Chan -> HedgeCfg
chSeq :: Chan -> Config
chHedge :: HedgeCfg
chSeq :: Config
..} !Word64
root !Int
n st :: ChanState
st@ChanState{(Double, Double)
State
Clips
HedgeState
csHedge :: ChanState -> HedgeState
csSeq :: ChanState -> State
csIv :: ChanState -> (Double, Double)
csClips :: ChanState -> Clips
csHedge :: HedgeState
csSeq :: State
csIv :: (Double, Double)
csClips :: Clips
..} = Int
-> Double
-> Double
-> (Double, Double)
-> Int
-> Int
-> Int
-> Double
-> Double
-> Double
-> Double
-> Double
-> [(Double, Double)]
-> Word64
-> Maybe Double
-> Result
ctor
Int
n (Config -> State -> Double
EPMix.log_evalue_sup Config
mixc (HedgeState -> State
hsMix HedgeState
csHedge))
(Config -> State -> Double
EPMix.p_value Config
mixc (HedgeState -> State
hsMix HedgeState
csHedge))
(Double, Double)
csIv
(Clips -> Int
clAtC Clips
csClips) (Clips -> Int
clAt4C Clips
csClips) (Clips -> Int
clAt16C Clips
csClips) (HedgeCfg -> Double
hcC1 HedgeCfg
chHedge)
(State -> Double
EPSign.log_evalue_sup (HedgeState -> State
hsSign HedgeState
csHedge))
(State -> Double
EPMagn.log_evalue_sup (HedgeState -> State
hsMagn1 HedgeState
csHedge))
(State -> Double
EPMagn.log_evalue_sup (HedgeState -> State
hsMagn2 HedgeState
csHedge))
(State -> Double
EPMagn.log_evalue_sup (HedgeState -> State
hsMagn3 HedgeState
csHedge))
([Double] -> [State] -> [(Double, Double)]
cdfPeaks (HedgeCfg -> [Double]
hcQs HedgeCfg
chHedge) (HedgeState -> [State]
hsCdf HedgeState
csHedge))
Word64
root
(HedgeCfg -> Maybe Double
hcMargin HedgeCfg
chHedge)
where
mixc :: Config
mixc = HedgeCfg -> Config
hcMix HedgeCfg
chHedge
ctor :: Int
-> Double
-> Double
-> (Double, Double)
-> Int
-> Int
-> Int
-> Double
-> Double
-> Double
-> Double
-> Double
-> [(Double, Double)]
-> Word64
-> Maybe Double
-> Result
ctor | Chan -> ChanState -> Bool
chanRejects Chan
ch ChanState
st = Int
-> Double
-> Double
-> (Double, Double)
-> Int
-> Int
-> Int
-> Double
-> Double
-> Double
-> Double
-> Double
-> [(Double, Double)]
-> Word64
-> Maybe Double
-> Result
Reject
| Bool
otherwise = Int
-> Double
-> Double
-> (Double, Double)
-> Int
-> Int
-> Int
-> Double
-> Double
-> Double
-> Double
-> Double
-> [(Double, Double)]
-> Word64
-> Maybe Double
-> Result
Pass
data Clips = Clips
{ Clips -> Int
clAtC :: {-# UNPACK #-} !Int
, Clips -> Int
clAt4C :: {-# UNPACK #-} !Int
, Clips -> Int
clAt16C :: {-# UNPACK #-} !Int
}
noClips :: Clips
noClips :: Clips
noClips = Int -> Int -> Int -> Clips
Clips Int
0 Int
0 Int
0
bumpClips :: HedgeCfg -> Clips -> Double -> Clips
bumpClips :: HedgeCfg -> Clips -> Double -> Clips
bumpClips HedgeCfg{Double
[Double]
Maybe Double
Config
Config
Config
hcSign :: HedgeCfg -> Config
hcMagn1 :: HedgeCfg -> Config
hcMagn2 :: HedgeCfg -> Config
hcMagn3 :: HedgeCfg -> Config
hcCdf :: HedgeCfg -> Config
hcQs :: HedgeCfg -> [Double]
hcMix :: HedgeCfg -> Config
hcC1 :: HedgeCfg -> Double
hcC2 :: HedgeCfg -> Double
hcC3 :: HedgeCfg -> Double
hcMargin :: HedgeCfg -> Maybe Double
hcSign :: Config
hcMagn1 :: Config
hcMagn2 :: Config
hcMagn3 :: Config
hcCdf :: Config
hcQs :: [Double]
hcMix :: Config
hcC1 :: Double
hcC2 :: Double
hcC3 :: Double
hcMargin :: Maybe Double
..} (Clips !Int
a !Int
b !Int
c) !Double
d = Int -> Int -> Int -> Clips
Clips
(Double -> Int -> Int
forall {a}. Num a => Double -> a -> a
bump Double
hcC1 Int
a) (Double -> Int -> Int
forall {a}. Num a => Double -> a -> a
bump Double
hcC2 Int
b) (Double -> Int -> Int
forall {a}. Num a => Double -> a -> a
bump Double
hcC3 Int
c)
where
!m :: Double
m = Double -> Double
forall a. Num a => a -> a
abs Double
d
bump :: Double -> a -> a
bump !Double
lim !a
n = if Double
m Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
lim then a
n a -> a -> a
forall a. Num a => a -> a -> a
+ a
1 else a
n
{-# INLINE bumpClips #-}
initialHedge :: HedgeCfg -> HedgeState
initialHedge :: HedgeCfg -> HedgeState
initialHedge HedgeCfg{Double
[Double]
Maybe Double
Config
Config
Config
hcSign :: HedgeCfg -> Config
hcMagn1 :: HedgeCfg -> Config
hcMagn2 :: HedgeCfg -> Config
hcMagn3 :: HedgeCfg -> Config
hcCdf :: HedgeCfg -> Config
hcQs :: HedgeCfg -> [Double]
hcMix :: HedgeCfg -> Config
hcC1 :: HedgeCfg -> Double
hcC2 :: HedgeCfg -> Double
hcC3 :: HedgeCfg -> Double
hcMargin :: HedgeCfg -> Maybe Double
hcSign :: Config
hcMagn1 :: Config
hcMagn2 :: Config
hcMagn3 :: Config
hcCdf :: Config
hcQs :: [Double]
hcMix :: Config
hcC1 :: Double
hcC2 :: Double
hcC3 :: Double
hcMargin :: Maybe Double
..} = HedgeState
{ hsSign :: State
hsSign = Config -> State
EPSign.initial Config
hcSign
, hsMagn1 :: State
hsMagn1 = Config -> State
EPMagn.initial Config
hcMagn1
, hsMagn2 :: State
hsMagn2 = Config -> State
EPMagn.initial Config
hcMagn2
, hsMagn3 :: State
hsMagn3 = Config -> State
EPMagn.initial Config
hcMagn3
, hsCdf :: [State]
hsCdf = (Double -> State) -> [Double] -> [State]
forall a b. (a -> b) -> [a] -> [b]
map (State -> Double -> State
forall a b. a -> b -> a
const (Config -> State
EPMagn.initial Config
hcCdf)) [Double]
hcQs
, hsMix :: State
hsMix = Config -> State
EPMix.initial Config
hcMix
}
updateHedge
:: HedgeCfg -> HedgeState -> Double -> Double -> Double -> HedgeState
updateHedge :: HedgeCfg -> HedgeState -> Double -> Double -> Double -> HedgeState
updateHedge HedgeCfg{Double
[Double]
Maybe Double
Config
Config
Config
hcSign :: HedgeCfg -> Config
hcMagn1 :: HedgeCfg -> Config
hcMagn2 :: HedgeCfg -> Config
hcMagn3 :: HedgeCfg -> Config
hcCdf :: HedgeCfg -> Config
hcQs :: HedgeCfg -> [Double]
hcMix :: HedgeCfg -> Config
hcC1 :: HedgeCfg -> Double
hcC2 :: HedgeCfg -> Double
hcC3 :: HedgeCfg -> Double
hcMargin :: HedgeCfg -> Maybe Double
hcSign :: Config
hcMagn1 :: Config
hcMagn2 :: Config
hcMagn3 :: Config
hcCdf :: Config
hcQs :: [Double]
hcMix :: Config
hcC1 :: Double
hcC2 :: Double
hcC3 :: Double
hcMargin :: Maybe Double
..} HedgeState{[State]
State
State
State
hsSign :: HedgeState -> State
hsMagn1 :: HedgeState -> State
hsMagn2 :: HedgeState -> State
hsMagn3 :: HedgeState -> State
hsCdf :: HedgeState -> [State]
hsMix :: HedgeState -> State
hsSign :: State
hsMagn1 :: State
hsMagn2 :: State
hsMagn3 :: State
hsCdf :: [State]
hsMix :: State
..} !Double
d !Double
ta !Double
tb =
let !s' :: State
s' = if Double
d Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0
then State
hsSign
else Config -> State -> Bool -> State
EPSign.update Config
hcSign State
hsSign (Double
d Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0)
!m1' :: State
m1' = Config -> State -> Double -> State
EPMagn.update Config
hcMagn1 State
hsMagn1 (Double -> Double -> Double
clipD Double
hcC1 Double
d)
!m2' :: State
m2' = Config -> State -> Double -> State
EPMagn.update Config
hcMagn2 State
hsMagn2 (Double -> Double -> Double
clipD Double
hcC2 Double
d)
!m3' :: State
m3' = Config -> State -> Double -> State
EPMagn.update Config
hcMagn3 State
hsMagn3 (Double -> Double -> Double
clipD Double
hcC3 Double
d)
!cd' :: [State]
cd' = Config -> [Double] -> [State] -> Double -> Double -> [State]
stepCdf Config
hcCdf [Double]
hcQs [State]
hsCdf Double
ta Double
tb
!evs :: [Double]
evs = case Maybe Double
hcMargin of
Just Double
_ ->
[ State -> Double
EPMagn.log_evalue State
m1'
, State -> Double
EPMagn.log_evalue State
m2'
, State -> Double
EPMagn.log_evalue State
m3'
]
Maybe Double
Nothing ->
( State -> Double
EPSign.log_evalue State
s'
Double -> [Double] -> [Double]
forall a. a -> [a] -> [a]
: State -> Double
EPMagn.log_evalue State
m1'
Double -> [Double] -> [Double]
forall a. a -> [a] -> [a]
: State -> Double
EPMagn.log_evalue State
m2'
Double -> [Double] -> [Double]
forall a. a -> [a] -> [a]
: State -> Double
EPMagn.log_evalue State
m3'
Double -> [Double] -> [Double]
forall a. a -> [a] -> [a]
: (State -> Double) -> [State] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map State -> Double
EPMagn.log_evalue [State]
cd'
)
!x' :: State
x' = Config -> State -> [Double] -> State
EPMix.update Config
hcMix State
hsMix [Double]
evs
in HedgeState
{ hsSign :: State
hsSign = State
s'
, hsMagn1 :: State
hsMagn1 = State
m1'
, hsMagn2 :: State
hsMagn2 = State
m2'
, hsMagn3 :: State
hsMagn3 = State
m3'
, hsCdf :: [State]
hsCdf = [State]
cd'
, hsMix :: State
hsMix = State
x'
}
stepCdf
:: EPMagn.Config -> [Double] -> [EPMagn.State] -> Double -> Double
-> [EPMagn.State]
stepCdf :: Config -> [Double] -> [State] -> Double -> Double -> [State]
stepCdf !Config
cfg = [Double] -> [State] -> Double -> Double -> [State]
go
where
go :: [Double] -> [State] -> Double -> Double -> [State]
go (Double
q : [Double]
qs) (State
s : [State]
ss) !Double
ta !Double
tb =
let !s' :: State
s' = Config -> State -> Double -> State
EPMagn.update Config
cfg State
s (Double -> Double -> Double -> Double
cdfDiff Double
q Double
ta Double
tb)
!ss' :: [State]
ss' = [Double] -> [State] -> Double -> Double -> [State]
go [Double]
qs [State]
ss Double
ta Double
tb
in State
s' State -> [State] -> [State]
forall a. a -> [a] -> [a]
: [State]
ss'
go [Double]
_ [State]
_ Double
_ Double
_ = []
cdfDiff :: Double -> Double -> Double -> Double
cdfDiff :: Double -> Double -> Double -> Double
cdfDiff !Double
q !Double
ta !Double
tb = Double -> Double
forall {a}. Num a => Double -> a
ind Double
ta Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double -> Double
forall {a}. Num a => Double -> a
ind Double
tb
where
ind :: Double -> a
ind !Double
t | Double
t Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
q = a
1
| Bool
otherwise = a
0
{-# INLINE cdfDiff #-}
cdfPeaks :: [Double] -> [EPMagn.State] -> [(Double, Double)]
cdfPeaks :: [Double] -> [State] -> [(Double, Double)]
cdfPeaks [Double]
qs = [Double] -> [Double] -> [(Double, Double)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Double]
qs ([Double] -> [(Double, Double)])
-> ([State] -> [Double]) -> [State] -> [(Double, Double)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (State -> Double) -> [State] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map State -> Double
EPMagn.log_evalue_sup
clipD :: Double -> Double -> Double
clipD :: Double -> Double -> Double
clipD !Double
lim !Double
x
| Double -> Double
forall a. Num a => a -> a
abs Double
x Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
lim = if Double
x Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0 then Double
lim else Double -> Double
forall a. Num a => a -> a
negate Double
lim
| Bool
otherwise = Double
x
{-# INLINE clipD #-}
effectGrid :: Int
effectGrid :: Int
effectGrid = Int
300
nextOrderBit :: Word64 -> (Word64, Word64)
nextOrderBit :: Word64 -> (Word64, Word64)
nextOrderBit !Word64
s =
let (!Word64
s', !Word64
w) = Word64 -> (Word64, Word64)
splitMix Word64
s
in (Word64
s', Word64
w Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
B..&. Word64
1)
{-# INLINE nextOrderBit #-}
resolveSeeds :: Maybe Word64 -> IO (Word64, Word64, Word64)
resolveSeeds :: Maybe Word64 -> IO (Word64, Word64, Word64)
resolveSeeds Maybe Word64
mseed = do
!base <- case Maybe Word64
mseed of
Just Word64
s -> Word64 -> IO Word64
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Word64
s
Maybe Word64
Nothing -> do
mw <- IO (Maybe Word64)
osEntropy
case mw of
Just Word64
w -> Word64 -> IO Word64
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Word64
w
Maybe Word64
Nothing -> IO Word64
getMonotonicTimeNSec
let (!s1, !w1) = splitMix base
(_ , !w2) = splitMix s1
pure (base, w1, w2)
osEntropy :: IO (Maybe Word64)
osEntropy :: IO (Maybe Word64)
osEntropy = (Either IOException ByteString -> Maybe Word64)
-> IO (Either IOException ByteString) -> IO (Maybe Word64)
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Either IOException ByteString -> Maybe Word64
forall {a}. Num a => Either IOException ByteString -> Maybe a
toWord (IO ByteString -> IO (Either IOException ByteString)
forall e a. Exception e => IO a -> IO (Either e a)
try (String -> IOMode -> (Handle -> IO ByteString) -> IO ByteString
forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile String
urandom IOMode
ReadMode Handle -> IO ByteString
grab))
where
urandom :: String
urandom = String
"/dev/urandom"
grab :: Handle -> IO ByteString
grab Handle
h = Handle -> Int -> IO ByteString
BS.hGet Handle
h Int
8
toWord :: Either IOException ByteString -> Maybe a
toWord (Left IOException
e) = Maybe a -> IOException -> Maybe a
forall a b. a -> b -> a
const Maybe a
forall a. Maybe a
Nothing (IOException
e :: IOException)
toWord (Right ByteString
bs)
| ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
8 = a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$! (a -> Word8 -> a) -> a -> ByteString -> a
forall a. (a -> Word8 -> a) -> a -> ByteString -> a
BS.foldl' a -> Word8 -> a
forall {a} {a}. (Integral a, Num a) => a -> a -> a
step a
0 ByteString
bs
| Bool
otherwise = Maybe a
forall a. Maybe a
Nothing
step :: a -> a -> a
step !a
acc !a
w = a
acc a -> a -> a
forall a. Num a => a -> a -> a
* a
256 a -> a -> a
forall a. Num a => a -> a -> a
+ a -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
w
warmup :: Config -> (Word64 -> IO r) -> Word64 -> IO [r]
warmup :: forall r. Config -> (Word64 -> IO r) -> Word64 -> IO [r]
warmup Config
cfg Word64 -> IO r
pair = Int -> [r] -> Word64 -> IO [r]
go Int
0 []
where
go :: Int -> [r] -> Word64 -> IO [r]
go !Int
i ![r]
acc !Word64
rng
| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Config -> Int
cfgWarmup Config
cfg = [r] -> IO [r]
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [r]
acc
| Bool
otherwise = do
let (!Word64
rng', !Word64
bit) = Word64 -> (Word64, Word64)
nextOrderBit Word64
rng
!r <- Word64 -> IO r
pair Word64
bit
go (i + 1) (r : acc) rng'
calibrate :: [(Double, Double)] -> (Double, [Double], Bool, Double)
calibrate :: [(Double, Double)] -> (Double, [Double], Bool, Double)
calibrate [(Double, Double)]
ws =
let !readings :: [Double]
readings = [[Double]] -> [Double]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ [Double
x, Double
y] | (Double
x, Double
y) <- [(Double, Double)]
ws ]
!sortedR :: [Double]
sortedR = [Double] -> [Double]
forall a. Ord a => [a] -> [a]
sort [Double]
readings
!p99d :: Double
p99d = [Double] -> Double
forall a. (Ord a, Num a) => [a] -> a
orderStat99 [ Double -> Double
forall a. Num a => a -> a
abs (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
y) | (Double
x, Double
y) <- [(Double, Double)]
ws ]
!p99r :: Double
p99r = [Double] -> Double
forall a. (Ord a, Num a) => [a] -> a
orderStat99 [Double]
readings
!qs :: [Double]
qs = [Double] -> [Double]
cutPoints [Double]
sortedR
!medR :: Double
medR = Int -> [Double] -> Double
forall a. Num a => Int -> [a] -> a
nth ([Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
sortedR Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2) [Double]
sortedR
in (Double -> Double -> Double
forall a. Ord a => a -> a -> a
max Double
1 (Double
2 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
p99d), [Double]
qs, Double
p99r Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0, Double
medR)
orderStat99 :: Ord a => Num a => [a] -> a
orderStat99 :: forall a. (Ord a, Num a) => [a] -> a
orderStat99 [a]
xs =
let !sorted :: [a]
sorted = [a] -> [a]
forall a. Ord a => [a] -> [a]
sort [a]
xs
in Int -> [a] -> a
forall a. Num a => Int -> [a] -> a
nth (([a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
sorted Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
99) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
100) [a]
sorted
{-# INLINE orderStat99 #-}
cdfLevels :: [Double]
cdfLevels :: [Double]
cdfLevels = [Double
0.10, Double
0.25, Double
0.50, Double
0.75, Double
0.90]
cutPoints :: [Double] -> [Double]
cutPoints :: [Double] -> [Double]
cutPoints [Double]
sorted
| Int
m Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 = []
| Bool
otherwise = [Double] -> [Double]
dedupAsc ((Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map Double -> Double
forall {a}. RealFrac a => a -> Double
pick [Double]
cdfLevels)
where
!m :: Int
m = [Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
sorted
pick :: a -> Double
pick !a
p = Int -> [Double] -> Double
forall a. Num a => Int -> [a] -> a
nth (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int -> Int -> Int
forall a. Ord a => a -> a -> a
min (Int
m Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (a -> Int
forall b. Integral b => a -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (a
p a -> a -> a
forall a. Num a => a -> a -> a
* Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
m)))) [Double]
sorted
dedupAsc :: [Double] -> [Double]
dedupAsc :: [Double] -> [Double]
dedupAsc (Double
x : Double
y : [Double]
rest)
| Double
x Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
y = [Double] -> [Double]
dedupAsc (Double
y Double -> [Double] -> [Double]
forall a. a -> [a] -> [a]
: [Double]
rest)
| Bool
otherwise = Double
x Double -> [Double] -> [Double]
forall a. a -> [a] -> [a]
: [Double] -> [Double]
dedupAsc (Double
y Double -> [Double] -> [Double]
forall a. a -> [a] -> [a]
: [Double]
rest)
dedupAsc [Double]
xs = [Double]
xs