module TimeSeries.Correlation where
import Data.Array.Base
import Data.List (sort)
import TimeSeries.PRG64
import TimeSeries.Window (Window(..))
import qualified TimeSeries.Window as W
direct :: Window -> Window -> Double
direct (Window x) (Window y) = sigma_x_y_minus_means / sqrt_sigma_x_y_squared
  where
    sigma_x_y_minus_means =
      sum [ (xix_mean)*(yiy_mean)
          | (xi,yi) <- zip (elems x) (elems y)]
    sqrt_sigma_x_y_squared = sqrt (sum xs' * sum ys') where
      xs' = [square (xix_mean) | xi <- elems x]
      ys' = [square (yiy_mean) | yi <- elems y]
    x_mean = mean (elems x)
    y_mean = mean (elems y)
sketch_naive ::
  [Window]
  
  
  -> Int    
  -> Window 
  -> Window 
  -> Double
sketch_naive rs sz (Window wx) (Window wy) = 1  (d'/len')
  where
    d' = sqrt $ sum ds
    ds = [ square (xjyj)
         | (xi,yi) <- zip skX skY
         , let xj = (xiavg_x) / var_x
         , let yj = (yiavg_y) / var_y
         ]
    skX = [dotp (elems r) (elems wx)|Window r <- rs]
    skY = [dotp (elems r) (elems wy)|Window r <- rs]
    len' = 2 * (len x1)
    avg_x = mean x
    avg_y = mean y
    var_x = (sum [square (xi  avg_x)|xi<-x]) / sz'
    var_y = (sum [square (yi  avg_y)|yi<-y]) / sz'
    x = elems wx
    y = elems wy
    sz' = fromIntegral sz
sketch ::
  Window
  
  -> Window
  
  -> Double
sketch wx wy = 1  (d'/len') where
  d' = sum [square (xy)|(x,y)<-zip (W.toList wx) (W.toList wy)]
  len' = 2 * fromIntegral (W.length wx)
sketch_distance ::
  Int         
  -> [Double] 
  -> [Double] 
  -> Double
sketch_distance d x w = median norms / sqrt (fromIntegral d) where
  norms = map norm $ zipWith (zipWith ()) ys zs
  median xs = sort xs !! (length xs `div` 2)
  
  
  
  
  
  
  
  
  b = 8
  m = length x
  prg64s = chunks m $ concat $ prg64Bits (prg64Init 0x9834219)
  (ys,zs) = foldr f ([],[]) [0..2*b] where
    f n (yacc,zacc) =
      let y = [dotp x r | r <- rs]
          z = [dotp w r | r <- rs]
          rs = take d $ drop (n*d) prg64s
      in  (y:yacc,z:zacc)
norm :: Floating a => [a] -> a
norm as = sqrt $ sum [square a|a <- as]
mean :: Fractional a => [a] -> a
mean zs = sum zs / len zs
stddev :: [Double] -> Double
stddev zs = sqrt (mean [square zi|zi<-zs]  (square (mean zs)))
stddev' :: Window -> Double
stddev' (Window x) = stddev $ elems x
len :: Num b => [a] -> b
len zs = fromIntegral (length zs)
dotp :: Num a => [a] -> [a] -> a
dotp a b = sum $ zipWith (*) a b
chunks :: Int -> [a] -> [[a]]
chunks sz ys
  | null ys   = []
  | otherwise = let (pre,post) = splitAt sz ys in pre : chunks sz post
square :: Fractional a => a -> a
square = (^ (2::Int))