module TimeSeries.Window where
import Data.Array.Unboxed
import Data.List (intersperse)
import Data.Word
import Text.Printf (printf)
import Prelude hiding (length)
import qualified Prelude
import TimeSeries.PRG64
newtype Window = Window (UArray Word64 Double) deriving (Eq, Show)
type Size = Word64
data RandomVector = RandomVector
  { 
    unitRV :: Window
    
  , controlRV :: Window
  } deriving (Eq, Show)
fromList :: [Double] -> Window
fromList xs = Window $ array (0,sz) $ zip [0..] xs where
  sz = fromIntegral (Prelude.length xs  1)
toList :: Window -> [Double]
toList (Window xs) = elems xs
empty :: Size -> Window
empty sz = Window $ array (0,sz1) [(i,0)|i <- [0..sz1]]
push :: Double -> Window -> Window
push v (Window arr) = Window (arr' // [(0,v)]) where
  arr' = ixmap (bounds arr) f arr
  f idx | idx == 0  = 0 
        | otherwise = idx  1
singleton :: Double -> Window
singleton v = Window $ array (0,0) [(0,v)]
norm :: Window -> Window -> Double
norm (Window x) (Window y) =
  sqrt $ sum [(xiyi)^(2::Int)|(xi,yi)<-zip (elems x) (elems y)]
append :: Window -> Window -> Window
append w@(Window wina) (Window winb) = Window (winc // assocs wina) where
  winc = ixmap (bounds winb) f winb
  f idx | idx < lengthA = 0
        | otherwise     = idx  lengthA
  lengthA = fromIntegral $ length w
sumWindow :: Window -> Double
sumWindow (Window arr) = sum $ elems arr
sumSqWindow :: Window -> Double
sumSqWindow (Window arr) = sum $ [x^(2::Int)|x<-elems arr]
dotp :: Window -> Window -> Double
dotp (Window wx) (Window wy) = sum $ zipWith (*) (elems wx) (elems wy)
dotps :: [Window] -> Window -> Window
dotps xss ys = fromList [dotp xs ys|xs <- xss]
copyContents ::
  Window    
  -> Window 
  -> Window
copyContents (Window to) (Window from) =
  Window $ ixmap (bounds to) id from
randomVector ::
  Integer    
  -> Size    
  -> Size    
  -> RandomVector
randomVector seed bw nb = RandomVector (fromList r) (fromList b) where
  (r,b) = rnd bw nb (fromIntegral seed)
wholeRandomVector ::
  RandomVector
  
  -> Window
  
wholeRandomVector (RandomVector (Window u) (Window c)) =
  let bw = rangeSize $ bounds u
      nb = rangeSize $ bounds c
      u' = concat $ replicate (fromIntegral nb) (elems u)
      c' = concatMap (replicate (fromIntegral bw)) (elems c)
  in  fromList $ zipWith (*) u' c'
pretty :: Window -> String
pretty (Window w) =
  concat . intersperse ", " $  map (printf "%.12f") (elems w)
average :: Window -> Double
average win@(Window w) = sum w' / fromIntegral (length win) where
  w' = elems w
variance :: Window -> Double
variance win@(Window w) = sqrt (mean [sq wi|wi<-w']  sq (mean w')) where
  w' = elems w
  mean xs = sum xs / fromIntegral (length win)
  sq x = x ^ (2::Int)
length :: Window -> Int
length (Window w) = rangeSize $ bounds w