content: module Main (main) where
  
  import           Control.Monad
  import           System.IO
  import           Text.Printf (printf)
  
  import           Data.Number.LogFloat (LogFloat)
  import qualified Data.Number.LogFloat as LF
  import           Statistics.Distribution
  import           Statistics.Distribution.Binomial
  
  -- | Compute the probability of seeing more than @k@ blocks in @n@ slots
  moreThanK ::
       Double  -- ^ Active slot coefficient
    -> Int     -- ^ Security parameter (@k@)
    -> Int     -- ^ Number of slots
    -> LogFloat
  moreThanK f k n =
      LF.sum [LF.logToLogFloat $ logProbability d i | i <- [k + 1 .. n]]
    where
      d :: BinomialDistribution
      d = binomial n f
  
  defaultS ::
       Double  -- ^ Active slot coefficient
    -> Int     -- ^ Security parameter (@k@)
    -> Int
  defaultS f k = floor (fromIntegral k / f) `div` 4
  
  main :: IO ()
  main = do
      forM_ [s .. 4 * s] $ \n -> do
        putStrLn $ show n ++ "\t" ++ showLogFloat (moreThanK f k n)
        hFlush stdout
    where
      f = 0.05
      k = 2160
      s = defaultS f k
  
  {-------------------------------------------------------------------------------
    LogFloat util
  -------------------------------------------------------------------------------}
  
  showLogFloat :: LogFloat -> String
  showLogFloat lf = printf "%6.4f * 10 ^ %d" m e
    where
      (m, e) = logFloatToScientific lf
  
  logFloatToScientific :: LogFloat -> (Double, Int)
  logFloatToScientific lf = (m, e)
    where
      l :: Double
      l = LF.logFromLogFloat lf
  
      e :: Int
      e = floor $ l / log10
  
      m :: Double
      m = exp $ l - log10 * fromIntegral e
  
      log10 :: Double
      log10 = log 10
  