module Poseidon.MathHelpers where

import           Data.List   (foldl')
import           Text.Printf (PrintfArg, printf)

-- | A helper function to calculate the mean of a list of doubles
avg :: [Double] -> Double
avg :: [Double] -> Double
avg [Double]
xs = let sum_ :: Double
sum_ = (Double -> Double -> Double) -> Double -> [Double] -> Double
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Double -> Double -> Double
forall a. Num a => a -> a -> a
(+) Double
0 [Double]
xs
         in Double
sum_ Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([Double] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Double]
xs)

-- | A helper function to round doubles
roundTo :: Int -> Double -> Double
roundTo :: Int -> Double -> Double
roundTo Int
n Double
x = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
val Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
t
  where
    val :: Int
val = Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
t) :: Int
    t :: Double
t = Double
10Double -> Int -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^Int
n

-- | A helper function to print rounded doubles
roundToStr :: (PrintfArg a, Floating a) => Int -> a -> String
roundToStr :: forall a. (PrintfArg a, Floating a) => Int -> a -> String
roundToStr = String -> Int -> a -> String
forall r. PrintfType r => String -> r
printf String
"%0.*f"

-- | A helper function to calculate the standard deviation of a list of doubles
stdev :: [Double] -> Double
stdev :: [Double] -> Double
stdev [Double]
xs = Double -> Double
forall a. Floating a => a -> a
sqrt (Double -> Double) -> ([Double] -> Double) -> [Double] -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Double] -> Double
avg ([Double] -> Double)
-> ([Double] -> [Double]) -> [Double] -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map (Double -> Double
forall {a}. Num a => a -> a
sq (Double -> Double) -> (Double -> Double) -> Double -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (-) ([Double] -> Double
avg [Double]
xs)) ([Double] -> Double) -> [Double] -> Double
forall a b. (a -> b) -> a -> b
$ [Double]
xs
  where
    sq :: a -> a
sq a
x = a
x a -> a -> a
forall a. Num a => a -> a -> a
* a
x
-- | A helper function to get a nice string with mean and sd for a list of doubles
meanAndSdRoundTo :: Int -> [Double] -> String
meanAndSdRoundTo :: Int -> [Double] -> String
meanAndSdRoundTo Int
_ [] = String
"no values"
meanAndSdRoundTo Int
n [Double]
xs = Double -> String
forall a. Show a => a -> String
show (Int -> Double -> Double
roundTo Int
n (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ [Double] -> Double
avg [Double]
xs) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" ± " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Double -> String
forall a. Show a => a -> String
show (Int -> Double -> Double
roundTo Int
n (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ [Double] -> Double
stdev [Double]
xs)

-- | A helper function to get a nice string with mean and sd for a list of doubles
-- (here rounded to integer)
meanAndSdInteger :: [Double] -> String
meanAndSdInteger :: [Double] -> String
meanAndSdInteger [] = String
"no values"
meanAndSdInteger [Double]
xs = Int -> String
forall a. Show a => a -> String
show Int
a String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" ± " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
s
  where
    a :: Int
a = (Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (Double -> Int) -> Double -> Int
forall a b. (a -> b) -> a -> b
$ [Double] -> Double
avg [Double]
xs) :: Int
    s :: Int
s = (Double -> Int
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (Double -> Int) -> Double -> Int
forall a b. (a -> b) -> a -> b
$ [Double] -> Double
stdev [Double]
xs) :: Int