src/Codec/Goat/Story.hs
{- |
Module : Codec.Goat.Story
Description : High-level time series API
Copyright : (c) Daniel Lovasko, 2016-2017
License : BSD3
Maintainer : Daniel Lovasko <daniel.lovasko@gmail.com>
Stability : stable
Portability : portable
The Story type provides an easy-to-use high-level interface to a time
series object. This module implements the building of the time series
structure and enables interval queries that return value points.
-}
module Codec.Goat.Story
( Story(..)
, storyAppend
, storyDump
, storyNew
, storyQuery
) where
import Data.Word
import Codec.Goat.Fluid
import Codec.Goat.TimeFrame
import Codec.Goat.Util
import Codec.Goat.ValueFrame
-- | Representation of a time series object. The constructor arguments are
-- as follows:
-- * time window size
-- * current time window number
-- * times fluid
-- * values fluid
data Story = Story Word32 Word32 (Fluid Word32 TimeFrame) (Fluid Float ValueFrame)
-- | Pretty-printing for the Story type.
instance Show Story where
show (Story wsz win ft fv) = unwords
[ "Story"
, "wsz=" ++ show wsz
, "win=" ++ show win
, "times=" ++ show ft
, "values=" ++ show fv ]
-- | Create a new empty story. The ratio of raw/compressed sections is
-- 12/74. These fields will be configurable in the future versions of the
-- module.
storyNew :: Word32 -- ^ time window size
-> Word32 -- ^ current time window number
-> Story -- ^ new story
storyNew wsz win = Story wsz win (fluidNew (12, 74)) (fluidNew (12, 74))
-- | Add new time/value pair to the story. The function will return
-- Nothing in case that the value was invalid (NaN or Infinity) or when
-- the time was invalid with respect to previously added times (breaking
-- the series monotonicity).
storyAppend :: Story -- ^ old story
-> (Word32, Float) -- ^ time & value
-> Maybe Story -- ^ new story
storyAppend (Story wsz win ft fv) (newTime, newValue)
| invalid = Nothing
| otherwise = Just $ Story wsz win2 newFt newFv
where
valueInv = isNaN newValue || isInfinite newValue
timeInv = maybe True (newTime>) (fluidFirst ft)
invalid = valueInv || timeInv
newWin = mod newTime wsz
win2 = bool win newWin (win == newWin)
newFt = fluidAppend (bool ft (fluidShift ft) (newWin == win)) newTime
newFv = fluidAppend (bool fv (fluidShift fv) (newWin == win)) newValue
-- | Query the story for time/value pairs within the specified time limit.
storyQuery :: Story -- ^ story
-> (Word32, Word32) -- ^ interval
-> [(Word32, Float)] -- ^ times & values
storyQuery (Story _ _ ft fv) ival
| all (==False) heads = []
| otherwise = zip times values
where
times = fluidSelect ft heads
values = fluidSelect fv heads
heads = map (maybe False (inBounds ival)) (fluidHeads ft)
-- | Output a list of all time/value pairs stored in the story.
storyDump :: Story -- ^ story
-> [(Word32, Float)] -- ^ times & values
storyDump (Story _ _ ft fv) = zip (fluidDump ft) (fluidDump fv)