-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Series.Unboxed
-- Copyright   :  (c) Laurent P. René de Cotret
-- License     :  MIT
-- Maintainer  :  laurent.decotret@outlook.com
-- Portability :  portable
--
-- This module contains data structures and functions to work with 'Series' capable of holding unboxed values,
-- i.e. values of types which are instances of `Unbox`.
--
-- = Why use unboxed series?
--
-- Unboxed series can have much better performance, at the cost of less flexibility. For example,
-- an unboxed series cannot contain values of type @`Maybe` a@. Moreover, unboxed series aren't instances of 
-- `Functor` or `Foldable`.
--
-- If you are hesitating, you should prefer the series implementation in the "Data.Series" module.
--
-- = Introduction to series
--
-- A 'Series' of type @Series k a@ is a labeled array of values of type @a@,
-- indexed by keys of type @k@.
--
-- Like `Data.Map.Strict.Map` from the @containers@ package, 'Series' support efficient:
--
--      * random access by key ( \(O(\log n)\) );
--      * slice by key ( \(O(\log n)\) ).
--
-- Like `Data.Vector.Vector`, they support efficient:
--
--      * random access by index ( \(O(1)\) );
--      * slice by index ( \(O(1)\) );
--      * numerical operations.
--
-- This module re-exports most of the content of "Data.Series.Generic", with type signatures 
-- specialized to the unboxed vector type `Data.Vector.Unboxed.Vector`.
 
module Data.Series.Unboxed (
    Series, index, values,

    -- * Building/converting 'Series'
    singleton, fromIndex,
    -- ** Lists
    fromList, toList,
    -- ** Vectors
    fromVector, toVector,
    -- ** Handling duplicates
    Occurrence, fromListDuplicates, fromVectorDuplicates,
    -- ** Strict Maps
    fromStrictMap, toStrictMap,
    -- ** Lazy Maps
    fromLazyMap, toLazyMap,
    -- ** Ad-hoc conversion with other data structures
    IsSeries(..),
    -- ** Conversion between 'Series' types
    G.convert,

    -- * Mapping and filtering
    map, mapWithKey, mapIndex, concatMap,
    take, takeWhile, drop, dropWhile, filter, filterWithKey,
    -- ** Mapping with effects
    mapWithKeyM, mapWithKeyM_, forWithKeyM, forWithKeyM_,

    -- * Combining series
    zipWithMatched, zipWithKey,
    zipWithMatched3, zipWithKey3,
    ZipStrategy, skipStrategy, mapStrategy, constStrategy, zipWithStrategy, zipWithStrategy3,
    zipWithMonoid, esum, eproduct, unzip, unzip3,

    -- * Index manipulation
    require, dropIndex,

    -- * Accessors
    -- ** Bulk access
    select, selectWhere, Range, to, from, upto, Selection, 
    -- ** Single-element access
    at, iat,

    -- * Replacement
    replace, (|->), (<-|),

    -- * Grouping and windowing operations
    groupBy, Grouping, aggregateWith, foldWith, 
    windowing, expanding,

    -- * Folds
    -- ** General folds
    fold, foldM, foldWithKey, foldMWithKey, foldMap, foldMap', foldMapWithKey,
    -- ** Specialized folds
    G.mean, G.variance, G.std,
    null, length, all, any, and, or, sum, product, maximum, maximumOn, minimum, minimumOn,
    argmin, argmax,

    -- * Scans
    postscanl, prescanl,

    -- * Displaying 'Series'
    display, displayWith,
    noLongerThan,
    DisplayOptions(..), G.defaultDisplayOptions
) where

import           Control.Foldl       ( Fold, FoldM )
import qualified Data.Map.Lazy       as ML
import qualified Data.Map.Strict     as MS
import           Data.Series.Index   ( Index )
import           Data.Series.Generic.View 
                                     ( Range, Selection, to, from, upto )
import           Data.Series.Generic ( IsSeries(..), ZipStrategy, Occurrence, DisplayOptions(..), skipStrategy, mapStrategy, constStrategy
                                     , noLongerThan 
                                     )
import qualified Data.Series.Generic as G
import           Data.Vector.Unboxed ( Vector, Unbox )
import qualified Data.Vector.Unboxed as Vector

import           Prelude             hiding ( map, concatMap, zipWith, filter, foldMap, null, length, all, any, and, or
                                            , sum, product, maximum, minimum, take, takeWhile, drop, dropWhile
                                            , last, unzip, unzip3
                                            )

-- $setup
-- >>> import qualified Data.Series.Unboxed as Series
-- >>> import qualified Data.Series.Index as Index

infixl 1 `select` 
infix 6 |->, <-|

-- | A series is a labeled array of values of type @a@,
-- indexed by keys of type @k@.
--
-- Like @Data.Map@ and @Data.HashMap@, they support efficient:
--
--      * random access by key ( \(O(\log n)\) );
--      * slice by key ( \(O(\log n)\) ).
--
-- Like @Data.Vector.Vector@, they support efficient:
--
--      * random access by index ( \(O(1)\) );
--      * slice by index ( \(O(1)\) );
--      * numerical operations.
type Series = G.Series Vector


index :: Series k a -> Index k
{-# INLINE index #-}
index :: forall k a. Series k a -> Index k
index = Series Vector k a -> Index k
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> Index k2
G.index


values :: Series k a -> Vector a
{-# INLINE values #-}
values :: forall k a. Series k a -> Vector a
values = Series Vector k a -> Vector a
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
G.values


-- | Create a 'Series' with a single element.
singleton :: Unbox a => k -> a -> Series k a
{-# INLINE singleton #-}
singleton :: forall a k. Unbox a => k -> a -> Series k a
singleton = k -> a -> Series Vector k a
forall (v :: * -> *) a k. Vector v a => k -> a -> Series v k a
G.singleton


-- | \(O(n)\) Generate a 'Series' by mapping every element of its index.
--
-- >>> fromIndex (const (0::Int)) $ Index.fromList ['a','b','c','d']
-- index | values
-- ----- | ------
--   'a' |      0
--   'b' |      0
--   'c' |      0
--   'd' |      0
fromIndex :: Unbox a
          => (k -> a) -> Index k -> Series k a
{-# INLINE fromIndex #-}
fromIndex :: forall a k. Unbox a => (k -> a) -> Index k -> Series k a
fromIndex = (k -> a) -> Index k -> Series Vector k a
forall (v :: * -> *) a k.
Vector v a =>
(k -> a) -> Index k -> Series v k a
G.fromIndex


-- | Construct a series from a list of key-value pairs. There is no
-- condition on the order of pairs.
--
-- >>> let xs = fromList [('b', 0::Int), ('a', 5), ('d', 1) ]
-- >>> xs
-- index | values
-- ----- | ------
--   'a' |      5
--   'b' |      0
--   'd' |      1
--
-- If you need to handle duplicate keys, take a look at `fromListDuplicates`.
fromList :: (Ord k, Unbox a) => [(k, a)] -> Series k a
{-# INLINE fromList #-}
fromList :: forall k a. (Ord k, Unbox a) => [(k, a)] -> Series k a
fromList = [(k, a)] -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Ord k) =>
[(k, a)] -> Series v k a
G.fromList


-- | Construct a series from a list of key-value pairs.
-- Contrary to `fromList`, values at duplicate keys are preserved. To keep each
-- key unique, an `Occurrence` number counts up.
--
-- >>> let xs = fromListDuplicates [('b', 0::Int), ('a', 5), ('d', 1), ('d', -4), ('d', 7) ]
-- >>> xs
--   index | values
--   ----- | ------
-- ('a',0) |      5
-- ('b',0) |      0
-- ('d',0) |      1
-- ('d',1) |     -4
-- ('d',2) |      7
fromListDuplicates :: (Ord k, Unbox a) => [(k, a)] -> Series (k, Occurrence) a
{-# INLINE fromListDuplicates #-}
fromListDuplicates :: forall k a.
(Ord k, Unbox a) =>
[(k, a)] -> Series (k, Occurrence) a
fromListDuplicates = [(k, a)] -> Series Vector (k, Occurrence) a
forall (v :: * -> *) a k.
(Vector v a, Ord k) =>
[(k, a)] -> Series v (k, Occurrence) a
G.fromListDuplicates


-- | Construct a list from key-value pairs. The elements are in order sorted by key:
--
-- >>> let xs = Series.fromList [ ('b', 0::Int), ('a', 5), ('d', 1) ]
-- >>> xs
-- index | values
-- ----- | ------
--   'a' |      5
--   'b' |      0
--   'd' |      1
-- >>> toList xs
-- [('a',5),('b',0),('d',1)]
toList :: Unbox a => Series k a -> [(k, a)]
{-# INLINE toList #-}
toList :: forall a k. Unbox a => Series k a -> [(k, a)]
toList = Series Vector k a -> [(k, a)]
forall (v :: * -> *) a k. Vector v a => Series v k a -> [(k, a)]
G.toList


-- | Construct a 'Vector' of key-value pairs. The elements are in order sorted by key. 
toVector :: (Unbox a, Unbox k) => Series k a -> Vector (k, a)
{-# INLINE toVector #-}
toVector :: forall a k. (Unbox a, Unbox k) => Series k a -> Vector (k, a)
toVector = Series Vector k a -> Vector (k, a)
forall (v :: * -> *) a k.
(Vector v a, Vector v k, Vector v (k, a)) =>
Series v k a -> v (k, a)
G.toVector


-- | Construct a 'Series' from a 'Vector' of key-value pairs. There is no
-- condition on the order of pairs. Duplicate keys are silently dropped. If you
-- need to handle duplicate keys, see 'fromVectorDuplicates'.
--
-- Note that due to differences in sorting,
-- @Series.fromList@ and @Series.fromVector . Vector.fromList@ 
-- may not be equivalent if the input list contains duplicate keys.
fromVector :: (Ord k, Unbox k, Unbox a)
           => Vector (k, a) -> Series k a
{-# INLINE fromVector #-}
fromVector :: forall k a.
(Ord k, Unbox k, Unbox a) =>
Vector (k, a) -> Series k a
fromVector = Vector (k, a) -> Series Vector k a
forall k (v :: * -> *) a.
(Ord k, Vector v k, Vector v a, Vector v (k, a)) =>
v (k, a) -> Series v k a
G.fromVector


-- | Construct a series from a 'Vector' of key-value pairs.
-- Contrary to 'fromVector', values at duplicate keys are preserved. To keep each
-- key unique, an 'Occurrence' number counts up.
--
-- >>> import qualified Data.Vector.Unboxed as Unboxed
-- >>> let xs = fromVectorDuplicates $ Unboxed.fromList [('b', 0::Int), ('a', 5), ('d', 1), ('d', -4), ('d', 7) ]
-- >>> xs
--   index | values
--   ----- | ------
-- ('a',0) |      5
-- ('b',0) |      0
-- ('d',0) |      1
-- ('d',1) |     -4
-- ('d',2) |      7
fromVectorDuplicates :: (Unbox k, Unbox a, Ord k) => Vector (k, a) -> Series (k, Occurrence) a
{-# INLINE fromVectorDuplicates #-}
fromVectorDuplicates :: forall k a.
(Unbox k, Unbox a, Ord k) =>
Vector (k, a) -> Series (k, Occurrence) a
fromVectorDuplicates = Vector (k, a) -> Series Vector (k, Occurrence) a
forall k (v :: * -> *) a.
(Ord k, Vector v k, Vector v a, Vector v (k, a),
 Vector v (k, Occurrence)) =>
v (k, a) -> Series v (k, Occurrence) a
G.fromVectorDuplicates


-- | Convert a series into a lazy @Map@.
toLazyMap :: (Unbox a) => Series k a -> ML.Map k a
{-# INLINE toLazyMap #-}
toLazyMap :: forall a k. Unbox a => Series k a -> Map k a
toLazyMap = Series Vector k a -> Map k a
forall (v :: * -> *) a k. Vector v a => Series v k a -> Map k a
G.toLazyMap


-- | Construct a series from a lazy @Map@.
fromLazyMap :: (Unbox a) => ML.Map k a -> Series k a
{-# INLINE fromLazyMap #-}
fromLazyMap :: forall a k. Unbox a => Map k a -> Series k a
fromLazyMap = Map k a -> Series Vector k a
forall (v :: * -> *) a k. Vector v a => Map k a -> Series v k a
G.fromLazyMap


-- | Convert a series into a strict @Map@.
toStrictMap :: (Unbox a) => Series k a -> MS.Map k a
{-# INLINE toStrictMap #-}
toStrictMap :: forall a k. Unbox a => Series k a -> Map k a
toStrictMap = Series Vector k a -> Map k a
forall (v :: * -> *) a k. Vector v a => Series v k a -> Map k a
G.toStrictMap

-- | Construct a series from a strict @Map@.
fromStrictMap :: (Unbox a) => MS.Map k a -> Series k a
{-# INLINE fromStrictMap #-}
fromStrictMap :: forall a k. Unbox a => Map k a -> Series k a
fromStrictMap = Map k a -> Series Vector k a
forall (v :: * -> *) a k. Vector v a => Map k a -> Series v k a
G.fromStrictMap


-- | \(O(n)\) Map every element of a 'Series'.
map :: (Unbox a, Unbox b) => (a -> b) -> Series k a -> Series k b
{-# INLINE map #-}
map :: forall a b k.
(Unbox a, Unbox b) =>
(a -> b) -> Series k a -> Series k b
map = (a -> b) -> Series Vector k a -> Series Vector k b
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
(a -> b) -> Series v k a -> Series v k b
G.map


-- | \(O(n)\) Map every element of a 'Series', possibly using the key as well.
mapWithKey :: (Unbox a, Unbox b) => (k -> a -> b) -> Series k a -> Series k b
{-# INLINE mapWithKey #-}
mapWithKey :: forall a b k.
(Unbox a, Unbox b) =>
(k -> a -> b) -> Series k a -> Series k b
mapWithKey = (k -> a -> b) -> Series Vector k a -> Series Vector k b
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
(k -> a -> b) -> Series v k a -> Series v k b
G.mapWithKey


-- | \(O(n \log n)\).
-- Map each key in the index to another value. Note that the resulting series
-- may have less elements, because each key must be unique.
--
-- In case new keys are conflicting, the first element is kept.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- >>> import qualified Data.List
-- >>> xs `mapIndex` (Data.List.take 1)
-- index | values
-- ----- | ------
--   "L" |      4
--   "P" |      1
mapIndex :: (Unbox a, Ord k, Ord g) => Series k a -> (k -> g) -> Series g a
{-# INLINE mapIndex #-}
mapIndex :: forall a k g.
(Unbox a, Ord k, Ord g) =>
Series k a -> (k -> g) -> Series g a
mapIndex = Series Vector k a -> (k -> g) -> Series Vector g a
forall (v :: * -> *) a k g.
(Vector v a, Ord k, Ord g) =>
Series v k a -> (k -> g) -> Series v g a
G.mapIndex


-- | Map a function over all the elements of a 'Series' and concatenate the result into a single 'Series'.
concatMap :: (Unbox a, Unbox k, Unbox b, Ord k) 
          => (a -> Series k b) 
          -> Series k a 
          -> Series k b
{-# INLINE concatMap #-}
concatMap :: forall a k b.
(Unbox a, Unbox k, Unbox b, Ord k) =>
(a -> Series k b) -> Series k a -> Series k b
concatMap = (a -> Series Vector k b) -> Series Vector k a -> Series Vector k b
forall (v :: * -> *) a k b.
(Vector v a, Vector v k, Vector v b, Vector v (k, a),
 Vector v (k, b), Ord k) =>
(a -> Series v k b) -> Series v k a -> Series v k b
G.concatMap


-- | \(O(n)\) Apply the monadic action to every element of a series and its
-- index, yielding a series of results.
mapWithKeyM :: (Unbox a, Unbox b, Monad m, Ord k) => (k -> a -> m b) -> Series k a -> m (Series k b)
{-# INLINE mapWithKeyM #-}
mapWithKeyM :: forall a b (m :: * -> *) k.
(Unbox a, Unbox b, Monad m, Ord k) =>
(k -> a -> m b) -> Series k a -> m (Series k b)
mapWithKeyM = (k -> a -> m b) -> Series Vector k a -> m (Series Vector k b)
forall (v :: * -> *) a b (m :: * -> *) k.
(Vector v a, Vector v b, Monad m, Ord k) =>
(k -> a -> m b) -> Series v k a -> m (Series v k b)
G.mapWithKeyM


-- | \(O(n)\) Apply the monadic action to every element of a series and its
-- index, discarding the results.
mapWithKeyM_ :: (Unbox a, Monad m) => (k -> a -> m b) -> Series k a -> m ()
{-# INLINE mapWithKeyM_ #-}
mapWithKeyM_ :: forall a (m :: * -> *) k b.
(Unbox a, Monad m) =>
(k -> a -> m b) -> Series k a -> m ()
mapWithKeyM_ = (k -> a -> m b) -> Series Vector k a -> m ()
forall (v :: * -> *) a (m :: * -> *) k b.
(Vector v a, Monad m) =>
(k -> a -> m b) -> Series v k a -> m ()
G.mapWithKeyM_


-- | \(O(n)\) Apply the monadic action to all elements of the series and their associated keys, 
-- yielding a series of results.
forWithKeyM :: (Unbox a, Unbox b, Monad m, Ord k) => Series k a -> (k -> a -> m b) -> m (Series k b)
{-# INLINE forWithKeyM #-}
forWithKeyM :: forall a b (m :: * -> *) k.
(Unbox a, Unbox b, Monad m, Ord k) =>
Series k a -> (k -> a -> m b) -> m (Series k b)
forWithKeyM = Series Vector k a -> (k -> a -> m b) -> m (Series Vector k b)
forall (v :: * -> *) a b (m :: * -> *) k.
(Vector v a, Vector v b, Monad m, Ord k) =>
Series v k a -> (k -> a -> m b) -> m (Series v k b)
G.forWithKeyM


-- | \(O(n)\) Apply the monadic action to all elements of the series and their associated keys, 
-- discarding the results.
forWithKeyM_ :: (Unbox a, Monad m) => Series k a -> (k -> a -> m b) -> m ()
{-# INLINE forWithKeyM_ #-}
forWithKeyM_ :: forall a (m :: * -> *) k b.
(Unbox a, Monad m) =>
Series k a -> (k -> a -> m b) -> m ()
forWithKeyM_ = Series Vector k a -> (k -> a -> m b) -> m ()
forall (v :: * -> *) a (m :: * -> *) k b.
(Vector v a, Monad m) =>
Series v k a -> (k -> a -> m b) -> m ()
G.forWithKeyM_


-- | \(O(\log n)\) @'take' n xs@ returns at most @n@ elements of the 'Series' @xs@.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4), ("Vienna", 5)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- "Vienna" |      5
-- >>> take 2 xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
take :: Unbox a => Int -> Series k a -> Series k a
{-# INLINE take #-}
take :: forall a k. Unbox a => Int -> Series k a -> Series k a
take = Int -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
Vector v a =>
Int -> Series v k a -> Series v k a
G.take


-- | \(O(n)\) Returns the longest prefix (possibly empty) of the input 'Series' that satisfy a predicate.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4), ("Vienna", 5)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- "Vienna" |      5

-- >>> takeWhile (>1) xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
takeWhile :: Unbox a => (a -> Bool) -> Series k a -> Series k a
takeWhile :: forall a k. Unbox a => (a -> Bool) -> Series k a -> Series k a
takeWhile = (a -> Bool) -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
Vector v a =>
(a -> Bool) -> Series v k a -> Series v k a
G.takeWhile


-- | \(O(\log n)\) @'drop' n xs@ drops at most @n@ elements from the 'Series' @xs@.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4), ("Vienna", 5)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- "Vienna" |      5
-- >>> drop 2 xs
--    index | values
--    ----- | ------
--  "Paris" |      1
-- "Vienna" |      5
drop :: Unbox a => Int -> Series k a -> Series k a
{-# INLINE drop #-}
drop :: forall a k. Unbox a => Int -> Series k a -> Series k a
drop = Int -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
Vector v a =>
Int -> Series v k a -> Series v k a
G.drop


-- | \(O(n)\) Returns the complement of `takeWhile`.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4), ("Vienna", 5)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- "Vienna" |      5

-- >>> dropWhile (>1) xs
--    index | values
--    ----- | ------
--  "Paris" |      1
-- "Vienna" |      5
dropWhile :: Unbox a => (a -> Bool) -> Series k a -> Series k a
dropWhile :: forall a k. Unbox a => (a -> Bool) -> Series k a -> Series k a
dropWhile = (a -> Bool) -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
Vector v a =>
(a -> Bool) -> Series v k a -> Series v k a
G.dropWhile


-- | Apply a function elementwise to two series, matching elements
-- based on their keys. Keys present only in the left or right series are dropped.
--
-- >>> let xs = Series.fromList [ ('a', 0::Int),  ('b', 1),  ('g', 2) ]
-- >>> let ys = Series.fromList [ ('a', 10::Int), ('b', 11), ('d', 13) ]
-- >>> zipWithMatched (+) xs ys
-- index | values
-- ----- | ------
--   'a' |     10
--   'b' |     12
zipWithMatched :: (Unbox a, Unbox b, Unbox c, Ord k) 
               => (a -> b -> c) -> Series k a -> Series k b -> Series k c
{-# INLINE zipWithMatched #-}
zipWithMatched :: forall a b c k.
(Unbox a, Unbox b, Unbox c, Ord k) =>
(a -> b -> c) -> Series k a -> Series k b -> Series k c
zipWithMatched = (a -> b -> c)
-> Series Vector k a -> Series Vector k b -> Series Vector k c
forall (v :: * -> *) a b c k.
(Vector v a, Vector v b, Vector v c, Ord k) =>
(a -> b -> c) -> Series v k a -> Series v k b -> Series v k c
G.zipWithMatched


-- | Apply a function elementwise to three series, matching elements
-- based on their keys. Keys not present in all three series are dropped.
--
-- >>> let xs = Series.fromList [ ('a', 0::Int),  ('b', 1),   ('g', 2) ]
-- >>> let ys = Series.fromList [ ('a', 10::Int), ('b', 11),  ('d', 13) ]
-- >>> let zs = Series.fromList [ ('a', 20::Int), ('d', 13), ('e', 6) ]
-- >>> zipWithMatched3 (\x y z -> x + y + z) xs ys zs
-- index | values
-- ----- | ------
--   'a' |     30
zipWithMatched3 :: (Unbox a, Unbox b, Unbox c, Unbox d, Ord k) 
                => (a -> b -> c -> d) 
                -> Series k a 
                -> Series k b 
                -> Series k c
                -> Series k d
{-# INLINE zipWithMatched3 #-}
zipWithMatched3 :: forall a b c d k.
(Unbox a, Unbox b, Unbox c, Unbox d, Ord k) =>
(a -> b -> c -> d)
-> Series k a -> Series k b -> Series k c -> Series k d
zipWithMatched3 = (a -> b -> c -> d)
-> Series Vector k a
-> Series Vector k b
-> Series Vector k c
-> Series Vector k d
forall (v :: * -> *) a b c d k.
(Vector v a, Vector v b, Vector v c, Vector v d, Ord k) =>
(a -> b -> c -> d)
-> Series v k a -> Series v k b -> Series v k c -> Series v k d
G.zipWithMatched3


-- | Apply a function elementwise to two series, matching elements
-- based on their keys. Keys present only in the left or right series are dropped.
-- 
--
-- >>> import Data.Char ( ord )
-- >>> let xs = Series.fromList [ ('a', 0::Int), ('b', 1), ('c', 2) ]
-- >>> let ys = Series.fromList [ ('a', 10::Int), ('b', 11), ('d', 13) ]
-- >>> zipWithKey (\k x y -> ord k + x + y) xs ys
-- index | values
-- ----- | ------
--   'a' |    107
--   'b' |    110
zipWithKey :: (Unbox a, Unbox b, Unbox c, Unbox k, Ord k)  
           => (k -> a -> b -> c) -> Series k a -> Series k b -> Series k c
{-# INLINE zipWithKey #-}
zipWithKey :: forall a b c k.
(Unbox a, Unbox b, Unbox c, Unbox k, Ord k) =>
(k -> a -> b -> c) -> Series k a -> Series k b -> Series k c
zipWithKey = (k -> a -> b -> c)
-> Series Vector k a -> Series Vector k b -> Series Vector k c
forall (v :: * -> *) a b c k.
(Vector v a, Vector v b, Vector v c, Vector v k, Ord k) =>
(k -> a -> b -> c) -> Series v k a -> Series v k b -> Series v k c
G.zipWithKey


-- | Apply a function elementwise to three series, matching elements
-- based on their keys. Keys present only in the left or right series are dropped.
-- 
-- >>> import Data.Char ( ord )
-- >>> let xs = Series.fromList [ ('a', 0::Int), ('b', 1), ('g', 2) ]
-- >>> let ys = Series.fromList [ ('a', 10::Int), ('b', 11), ('d', 13) ]
-- >>> let zs = Series.fromList [ ('a', 20::Int), ('b', 7), ('d', 5) ]
-- >>> zipWithKey3 (\k x y z -> ord k + x + y + z) xs ys zs
-- index | values
-- ----- | ------
--   'a' |    127
--   'b' |    117
zipWithKey3 :: (Unbox a, Unbox b, Unbox c, Unbox d, Unbox k, Ord k) 
            => (k -> a -> b -> c -> d) 
            -> Series k a 
            -> Series k b 
            -> Series k c
            -> Series k d
{-# INLINE zipWithKey3 #-}
zipWithKey3 :: forall a b c d k.
(Unbox a, Unbox b, Unbox c, Unbox d, Unbox k, Ord k) =>
(k -> a -> b -> c -> d)
-> Series k a -> Series k b -> Series k c -> Series k d
zipWithKey3 = (k -> a -> b -> c -> d)
-> Series Vector k a
-> Series Vector k b
-> Series Vector k c
-> Series Vector k d
forall (v :: * -> *) a b c d k.
(Vector v a, Vector v b, Vector v c, Vector v d, Vector v k,
 Ord k) =>
(k -> a -> b -> c -> d)
-> Series v k a -> Series v k b -> Series v k c -> Series v k d
G.zipWithKey3


-- | Zip two 'Series' with a combining function, applying a 'ZipStrategy' when one key is present in one of the 'Series' but not both.
--
-- In the example below, we want to set the value to @-100@ (via @'constStrategy' (-100)@) for keys which are only present 
-- in the left 'Series', and drop keys (via 'skipStrategy') which are only present in the `right 'Series'  
--
-- >>> let xs = Series.fromList [ ('a', 0::Int),  ('b', 1),  ('g', 2) ]
-- >>> let ys = Series.fromList [ ('a', 10::Int), ('b', 11), ('d', 13) ]
-- >>> zipWithStrategy (+) (constStrategy (-100)) skipStrategy  xs ys
-- index | values
-- ----- | ------
--   'a' |     10
--   'b' |     12
--   'g' |   -100
--
-- Note that if you want to drop keys missing in either 'Series', it is faster to use @'zipWithMatched' f@ 
-- than using @'zipWithStrategy' f 'skipStrategy' 'skipStrategy'@.
zipWithStrategy :: (Ord k, Unbox a, Unbox b, Unbox c) 
                => (a -> b -> c)     -- ^ Function to combine values when present in both series
                -> ZipStrategy k a c -- ^ Strategy for when the key is in the left series but not the right
                -> ZipStrategy k b c -- ^ Strategy for when the key is in the right series but not the left
                -> Series k a
                -> Series k b 
                -> Series k c
{-# INLINE zipWithStrategy #-}
zipWithStrategy :: forall k a b c.
(Ord k, Unbox a, Unbox b, Unbox c) =>
(a -> b -> c)
-> ZipStrategy k a c
-> ZipStrategy k b c
-> Series k a
-> Series k b
-> Series k c
zipWithStrategy = (a -> b -> c)
-> ZipStrategy k a c
-> ZipStrategy k b c
-> Series Vector k a
-> Series Vector k b
-> Series Vector k c
forall (v :: * -> *) a b c k.
(Vector v a, Vector v b, Vector v c, Ord k) =>
(a -> b -> c)
-> ZipStrategy k a c
-> ZipStrategy k b c
-> Series v k a
-> Series v k b
-> Series v k c
G.zipWithStrategy


-- | Zip three 'Series' with a combining function, applying a 'ZipStrategy' when one key is 
-- present in one of the 'Series' but not all of the others.
--
-- Note that if you want to drop keys missing in either 'Series', it is faster to use @'zipWithMatched3' f@ 
-- than using @'zipWithStrategy3' f skipStrategy skipStrategy skipStrategy@.
zipWithStrategy3 :: (Ord k, Unbox a, Unbox b, Unbox c, Unbox d) 
                => (a -> b -> c -> d) -- ^ Function to combine values when present in all series
                -> ZipStrategy k a d  -- ^ Strategy for when the key is in the left series but not in all the others
                -> ZipStrategy k b d  -- ^ Strategy for when the key is in the center series but not in all the others
                -> ZipStrategy k c d  -- ^ Strategy for when the key is in the right series but not in all the others
                -> Series k a
                -> Series k b 
                -> Series k c
                -> Series k d
zipWithStrategy3 :: forall k a b c d.
(Ord k, Unbox a, Unbox b, Unbox c, Unbox d) =>
(a -> b -> c -> d)
-> ZipStrategy k a d
-> ZipStrategy k b d
-> ZipStrategy k c d
-> Series k a
-> Series k b
-> Series k c
-> Series k d
zipWithStrategy3 = (a -> b -> c -> d)
-> ZipStrategy k a d
-> ZipStrategy k b d
-> ZipStrategy k c d
-> Series Vector k a
-> Series Vector k b
-> Series Vector k c
-> Series Vector k d
forall (v :: * -> *) a b c d k.
(Vector v a, Vector v b, Vector v c, Vector v d, Ord k) =>
(a -> b -> c -> d)
-> ZipStrategy k a d
-> ZipStrategy k b d
-> ZipStrategy k c d
-> Series v k a
-> Series v k b
-> Series v k c
-> Series v k d
G.zipWithStrategy3
{-# INLINE zipWithStrategy3 #-}


-- | Zip two 'Series' with a combining function. The value for keys which are missing from
-- either 'Series' is replaced with the appropriate `mempty` value.
--
-- >>> import Data.Monoid ( Sum(..) )
-- >>> let xs = Series.fromList [ ("2023-01-01", Sum (1::Int)), ("2023-01-02", Sum 2) ]
-- >>> let ys = Series.fromList [ ("2023-01-01", Sum (5::Int)), ("2023-01-03", Sum 7) ]
-- >>> zipWithMonoid (<>) xs ys
--        index |           values
--        ----- |           ------
-- "2023-01-01" | Sum {getSum = 6}
-- "2023-01-02" | Sum {getSum = 2}
-- "2023-01-03" | Sum {getSum = 7}
zipWithMonoid :: ( Monoid a, Monoid b
                 , Unbox a, Unbox b, Unbox c
                 , Ord k
                 ) 
              => (a -> b -> c)
              -> Series k a
              -> Series k b 
              -> Series k c
zipWithMonoid :: forall a b c k.
(Monoid a, Monoid b, Unbox a, Unbox b, Unbox c, Ord k) =>
(a -> b -> c) -> Series k a -> Series k b -> Series k c
zipWithMonoid = (a -> b -> c)
-> Series Vector k a -> Series Vector k b -> Series Vector k c
forall a b (v :: * -> *) c k.
(Monoid a, Monoid b, Vector v a, Vector v b, Vector v c, Ord k) =>
(a -> b -> c) -> Series v k a -> Series v k b -> Series v k c
G.zipWithMonoid
{-# INLINE zipWithMonoid #-}


-- | Elementwise sum of two 'Series'. Elements missing in one or the other 'Series' is considered 0. 
--
-- >>> let xs = Series.fromList [ ("2023-01-01", (1::Int)), ("2023-01-02", 2) ]
-- >>> let ys = Series.fromList [ ("2023-01-01", (5::Int)), ("2023-01-03", 7) ]
-- >>> xs `esum` ys
--        index | values
--        ----- | ------
-- "2023-01-01" |      6
-- "2023-01-02" |      2
-- "2023-01-03" |      7
esum :: (Ord k, Num a, Unbox a) 
     => Series k a 
     -> Series k a
     -> Series k a
esum :: forall k a.
(Ord k, Num a, Unbox a) =>
Series k a -> Series k a -> Series k a
esum = Series Vector k a -> Series Vector k a -> Series Vector k a
forall k a (v :: * -> *).
(Ord k, Num a, Vector v a, Vector v (Sum a)) =>
Series v k a -> Series v k a -> Series v k a
G.esum
{-# INLINE esum #-}


-- | Elementwise product of two 'Series'. Elements missing in one or the other 'Series' is considered 1. 
--
-- >>> let xs = Series.fromList [ ("2023-01-01", (2::Int)), ("2023-01-02", 3) ]
-- >>> let ys = Series.fromList [ ("2023-01-01", (5::Int)), ("2023-01-03", 7) ]
-- >>> xs `eproduct` ys
--        index | values
--        ----- | ------
-- "2023-01-01" |     10
-- "2023-01-02" |      3
-- "2023-01-03" |      7
eproduct :: (Ord k, Num a, Unbox a) 
         => Series k a 
         -> Series k a
         -> Series k a
eproduct :: forall k a.
(Ord k, Num a, Unbox a) =>
Series k a -> Series k a -> Series k a
eproduct = Series Vector k a -> Series Vector k a -> Series Vector k a
forall k a (v :: * -> *).
(Ord k, Num a, Vector v a, Vector v (Product a)) =>
Series v k a -> Series v k a -> Series v k a
G.eproduct
{-# INLINE eproduct #-}


-- | \(O(n)\) Unzip a 'Series' of 2-tuples.
unzip :: (Unbox a, Unbox b) 
      => Series k (a, b)
      -> ( Series k a
         , Series k b
         )
unzip :: forall a b k.
(Unbox a, Unbox b) =>
Series k (a, b) -> (Series k a, Series k b)
unzip = Series Vector k (a, b) -> (Series Vector k a, Series Vector k b)
forall (v :: * -> *) a b k.
(Vector v a, Vector v b, Vector v (a, b)) =>
Series v k (a, b) -> (Series v k a, Series v k b)
G.unzip
{-# INLINE unzip #-}


-- | \(O(n)\) Unzip a 'Series' of 3-tuples.
unzip3 :: (Unbox a, Unbox b, Unbox c) 
       => Series k (a, b, c)
       -> ( Series k a
          , Series k b
          , Series k c
          )
unzip3 :: forall a b c k.
(Unbox a, Unbox b, Unbox c) =>
Series k (a, b, c) -> (Series k a, Series k b, Series k c)
unzip3 = Series Vector k (a, b, c)
-> (Series Vector k a, Series Vector k b, Series Vector k c)
forall (v :: * -> *) a b c k.
(Vector v a, Vector v b, Vector v c, Vector v (a, b, c)) =>
Series v k (a, b, c) -> (Series v k a, Series v k b, Series v k c)
G.unzip3
{-# INLINE unzip3 #-}


-- | Require a series to have a specific `Index`. 
-- Contrary to @select@, all keys in the `Index` will be present in the resulting series.
--
-- Note that unlike the implementation for boxed series (`Data.Series.require`), missing keys need to be mapped to some values because unboxed
-- series cannot contain values of type @`Maybe` a@. 
--
-- In the example below, the missing value for key @\"Taipei\"@ is mapped to 0:
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- >>> require (const 0) xs (Index.fromList ["Paris", "Lisbon", "Taipei"])
--    index | values
--    ----- | ------
-- "Lisbon" |      4
--  "Paris" |      1
-- "Taipei" |      0
require :: (Unbox a, Ord k) 
        => (k -> a) -> Series k a -> Index k -> Series k a
{-# INLINE require #-}
require :: forall a k.
(Unbox a, Ord k) =>
(k -> a) -> Series k a -> Index k -> Series k a
require k -> a
f = (k -> a)
-> (a -> a) -> Series Vector k a -> Index k -> Series Vector k a
forall (v :: * -> *) a b k.
(Vector v a, Vector v b, Ord k) =>
(k -> b) -> (a -> b) -> Series v k a -> Index k -> Series v k b
G.requireWith k -> a
f a -> a
forall a. a -> a
id


-- | Drop the index of a series by replacing it with an `Int`-based index. Values will
-- be indexed from 0.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- >>> dropIndex xs
-- index | values
-- ----- | ------
--     0 |      4
--     1 |      2
--     2 |      1
dropIndex :: Series k a -> Series Int a
{-# INLINE dropIndex #-}
dropIndex :: forall k a. Series k a -> Series Int a
dropIndex = Series Vector k a -> Series Vector Int a
forall {k1} (v :: k1 -> *) k2 (a :: k1).
Series v k2 a -> Series v Int a
G.dropIndex


-- | Filter elements. Only elements for which the predicate is @True@ are kept. 
-- Notice that the filtering is done on the values, not on the keys.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- >>> filter (>2) xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
--
-- See also 'filterWithKey'.
filter :: (Unbox a, Ord k) => (a -> Bool) -> Series k a -> Series k a
{-# INLINE filter #-}
filter :: forall a k.
(Unbox a, Ord k) =>
(a -> Bool) -> Series k a -> Series k a
filter = (a -> Bool) -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Ord k) =>
(a -> Bool) -> Series v k a -> Series v k a
G.filter


-- | Filter elements, taking into account the corresponding key. Only elements for which 
-- the predicate is @True@ are kept. 
filterWithKey :: (Unbox a, Ord k) 
              => (k -> a -> Bool) 
              -> Series k a 
              -> Series k a
{-# INLINE filterWithKey #-}
filterWithKey :: forall a k.
(Unbox a, Ord k) =>
(k -> a -> Bool) -> Series k a -> Series k a
filterWithKey = (k -> a -> Bool) -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Vector v Bool, Ord k) =>
(k -> a -> Bool) -> Series v k a -> Series v k a
G.filterWithKey


-- | Select a subseries. There are a few ways to do this.
--
-- The first way to do this is to select a sub-series based on random keys. For example,
-- selecting a subseries from an `Index`:
--
-- >>> let xs = Series.fromList [('a', 10::Int), ('b', 20), ('c', 30), ('d', 40)]
-- >>> xs `select` Index.fromList ['a', 'd']
-- index | values
-- ----- | ------
--   'a' |     10
--   'd' |     40
--
-- The second way to select a sub-series is to select all keys in a range:
--
-- >>> xs `select` 'b' `to` 'c'
-- index | values
-- ----- | ------
--   'b' |     20
--   'c' |     30
--
-- Note that with `select`, you'll always get a sub-series; if you ask for a key which is not
-- in the series, it'll be ignored:
--
-- >>> xs `select` Index.fromList ['a', 'd', 'e']
-- index | values
-- ----- | ------
--   'a' |     10
--   'd' |     40
--
-- See `require` if you want to ensure that all keys are present.
select :: (Unbox a, Selection s, Ord k) => Series k a -> s k -> Series k a
select :: forall a (s :: * -> *) k.
(Unbox a, Selection s, Ord k) =>
Series k a -> s k -> Series k a
select = Series Vector k a -> s k -> Series Vector k a
forall (s :: * -> *) (v :: * -> *) a k.
(Selection s, Vector v a, Ord k) =>
Series v k a -> s k -> Series v k a
forall (v :: * -> *) a k.
(Vector v a, Ord k) =>
Series v k a -> s k -> Series v k a
G.select


-- | Select a sub-series from a series matching a condition.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- >>> xs `selectWhere` (Series.map (>1) xs)
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
selectWhere :: (Unbox a, Ord k) => Series k a -> Series k Bool -> Series k a
{-# INLINE selectWhere #-}
selectWhere :: forall a k.
(Unbox a, Ord k) =>
Series k a -> Series k Bool -> Series k a
selectWhere = Series Vector k a -> Series Vector k Bool -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Vector v Bool, Ord k) =>
Series v k a -> Series v k Bool -> Series v k a
G.selectWhere


-- | \(O(\log n)\). Extract a single value from a series, by key.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]
-- >>> xs `at` "Paris"
-- Just 1
-- >>> xs `at` "Sydney"
-- Nothing
at :: (Unbox a, Ord k) => Series k a -> k -> Maybe a
{-# INLINE at #-}
at :: forall a k. (Unbox a, Ord k) => Series k a -> k -> Maybe a
at = Series Vector k a -> k -> Maybe a
forall (v :: * -> *) a k.
(Vector v a, Ord k) =>
Series v k a -> k -> Maybe a
G.at


-- | \(O(1)\). Extract a single value from a series, by index.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- >>> xs `iat` 0
-- Just 4
-- >>> xs `iat` 3
-- Nothing
iat :: Unbox a => Series k a -> Int -> Maybe a
{-# INLINE iat #-}
iat :: forall a k. Unbox a => Series k a -> Int -> Maybe a
iat = Series Vector k a -> Int -> Maybe a
forall (v :: * -> *) a k.
Vector v a =>
Series v k a -> Int -> Maybe a
G.iat


-- | Replace values in the right series from values in the left series at matching keys.
-- Keys not in the right series are unaffected.
-- 
-- See `(|->)` and `(<-|)`, which might be more readable.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- >>> let ys = Series.singleton "Paris" (99::Int)
-- >>> ys `replace` xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |     99
replace :: (Unbox a, Ord k) => Series k a -> Series k a -> Series k a
{-# INLINE replace #-}
replace :: forall a k.
(Unbox a, Ord k) =>
Series k a -> Series k a -> Series k a
replace = Series Vector k a -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Ord k) =>
Series v k a -> Series v k a -> Series v k a
G.replace


-- | Replace values in the right series from values in the left series at matching keys.
-- Keys not in the right series are unaffected.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- >>> let ys = Series.singleton "Paris" (99::Int)
-- >>> ys |-> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |     99
(|->) :: (Unbox a, Ord k) => Series k a -> Series k a -> Series k a
{-# INLINE (|->) #-}
|-> :: forall a k.
(Unbox a, Ord k) =>
Series k a -> Series k a -> Series k a
(|->) = Series Vector k a -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Ord k) =>
Series v k a -> Series v k a -> Series v k a
(G.|->)


-- | Replace values in the left series from values in the right series at matching keys.
-- Keys not in the left series are unaffected.
--
-- >>> let xs = Series.fromList [("Paris", 1 :: Int), ("London", 2), ("Lisbon", 4)]
-- >>> xs
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |      1
-- >>> let ys = Series.singleton "Paris" (99::Int)
-- >>> xs <-| ys
--    index | values
--    ----- | ------
-- "Lisbon" |      4
-- "London" |      2
--  "Paris" |     99
(<-|) :: (Unbox a, Ord k) => Series k a -> Series k a -> Series k a
{-# INLINE (<-|) #-}
<-| :: forall a k.
(Unbox a, Ord k) =>
Series k a -> Series k a -> Series k a
(<-|) = Series Vector k a -> Series Vector k a -> Series Vector k a
forall (v :: * -> *) a k.
(Vector v a, Vector v Int, Ord k) =>
Series v k a -> Series v k a -> Series v k a
(G.<-|)


-- | \(O(n)\) Execute a 'Fold' over a 'Series'.
--
-- >>> let xs = Series.fromList (zip [0..] [1,2,3,4]) :: Series Int Double
-- >>> xs
-- index | values
-- ----- | ------
--     0 |    1.0
--     1 |    2.0
--     2 |    3.0
--     3 |    4.0
-- >>> import Control.Foldl (variance)
-- >>> fold variance xs
-- 1.25
--
-- See also 'foldM' for monadic folds, and 'foldWithKey' to take keys into
-- account while folding.
fold :: Unbox a 
     => Fold a b -> Series k a -> b
fold :: forall a b k. Unbox a => Fold a b -> Series k a -> b
fold = Fold a b -> Series Vector k a -> b
forall (v :: * -> *) a b k.
Vector v a =>
Fold a b -> Series v k a -> b
G.fold
{-# INLINE fold #-}


-- | \(O(n)\) Execute a monadic 'FoldM' over a 'Series'.
--
-- See also 'fold' for pure folds, and 'foldMWithKey' to take keys into
-- account while folding.
foldM :: (Monad m, Unbox a) 
      => FoldM m a b  
      -> Series k a 
      -> m b
foldM :: forall (m :: * -> *) a b k.
(Monad m, Unbox a) =>
FoldM m a b -> Series k a -> m b
foldM = FoldM m a b -> Series Vector k a -> m b
forall (m :: * -> *) (v :: * -> *) a b k.
(Monad m, Vector v a) =>
FoldM m a b -> Series v k a -> m b
G.foldM
{-# INLINE foldM #-}


-- | \(O(n)\) Execute a 'Fold' over a 'Series', taking keys into account.
foldWithKey :: (Unbox k, Unbox a) 
            => Fold (k, a) b -> Series k a -> b
foldWithKey :: forall k a b.
(Unbox k, Unbox a) =>
Fold (k, a) b -> Series k a -> b
foldWithKey = Fold (k, a) b -> Series Vector k a -> b
forall (v :: * -> *) a k b.
(Vector v a, Vector v k, Vector v (k, a)) =>
Fold (k, a) b -> Series v k a -> b
G.foldWithKey
{-# INLINE foldWithKey #-}


-- | \(O(n)\) Execute a monadic 'FoldM' over a 'Series', where the 'FoldM' takes keys into account.
foldMWithKey :: (Monad m, Unbox a, Unbox k) 
             => FoldM m (k, a) b  
             -> Series k a 
             -> m b
foldMWithKey :: forall (m :: * -> *) a k b.
(Monad m, Unbox a, Unbox k) =>
FoldM m (k, a) b -> Series k a -> m b
foldMWithKey = FoldM m (k, a) b -> Series Vector k a -> m b
forall (m :: * -> *) (v :: * -> *) a k b.
(Monad m, Vector v a, Vector v k, Vector v (k, a)) =>
FoldM m (k, a) b -> Series v k a -> m b
G.foldMWithKey
{-# INLINE foldMWithKey #-}


-- | \(O(n)\) Map each element of the structure to a monoid and combine
-- the results.
foldMap :: (Monoid m, Unbox a) => (a -> m) -> Series k a -> m
{-# INLINE foldMap #-}
foldMap :: forall m a k. (Monoid m, Unbox a) => (a -> m) -> Series k a -> m
foldMap = (a -> m) -> Series Vector k a -> m
forall m (v :: * -> *) a k.
(Monoid m, Vector v a) =>
(a -> m) -> Series v k a -> m
G.foldMap


-- | \(O(n)\) Like 'foldMap', but strict in the accumulator. It uses the same
-- implementation as the corresponding method of the 'Foldable' type class.
foldMap' :: (Monoid m, Unbox a) => (a -> m) -> Series k a -> m
{-# INLINE foldMap' #-}
foldMap' :: forall m a k. (Monoid m, Unbox a) => (a -> m) -> Series k a -> m
foldMap' a -> m
f = (a -> m) -> Vector a -> m
forall m a. (Monoid m, Unbox a) => (a -> m) -> Vector a -> m
Vector.foldMap' a -> m
f (Vector a -> m) -> (Series k a -> Vector a) -> Series k a -> m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series k a -> Vector a
forall k a. Series k a -> Vector a
values


-- | \(O(n)\) Map each element and associated key of the structure to a monoid and combine
-- the results.
foldMapWithKey :: (Monoid m, Unbox a, Unbox k) => (k -> a -> m) -> Series k a -> m
{-# INLINE foldMapWithKey #-}
foldMapWithKey :: forall m a k.
(Monoid m, Unbox a, Unbox k) =>
(k -> a -> m) -> Series k a -> m
foldMapWithKey = (k -> a -> m) -> Series Vector k a -> m
forall m (v :: * -> *) a k.
(Monoid m, Vector v a, Vector v k, Vector v (k, a)) =>
(k -> a -> m) -> Series v k a -> m
G.foldMapWithKey


-- | Group values in a 'Series' by some grouping function (@k -> g@).
-- The provided grouping function is guaranteed to operate on a non-empty 'Series'.
--
-- This function is expected to be used in conjunction with @aggregate@:
-- 
-- >>> import Data.Maybe ( fromMaybe )
-- >>> type Date = (Int, String)
-- >>> month :: (Date -> String) = snd
-- >>> :{ 
--     let xs = Series.fromList [ ((2020, "January") :: Date,  0 :: Int)
--                              , ((2021, "January"), -5)
--                              , ((2020, "June")   , 20)
--                              , ((2021, "June")   , 25) 
--                              ]
--      in xs `groupBy` month `aggregateWith` (fromMaybe 0 . minimum)
-- :}
--     index | values
--     ----- | ------
-- "January" |     -5
--    "June" |     20
groupBy :: Series k a      -- ^ Grouping function
        -> (k -> g)        -- ^ Input series
        -> Grouping k g a  -- ^ Grouped series
{-# INLINE groupBy #-}
groupBy :: forall k a g. Series k a -> (k -> g) -> Grouping k g a
groupBy = Series Vector k a -> (k -> g) -> Grouping k g Vector a
forall {k1} (v :: k1 -> *) k2 (a :: k1) g.
Series v k2 a -> (k2 -> g) -> Grouping k2 g v a
G.groupBy


-- | Representation of a 'Series' being grouped.
type Grouping k g a = G.Grouping k g Vector a


-- | Aggregate groups resulting from a call to 'groupBy':
-- 
-- >>> import Data.Maybe ( fromMaybe )
-- >>> type Date = (Int, String)
-- >>> month :: (Date -> String) = snd
-- >>> :{ 
--     let xs = Series.fromList [ ((2020, "January") :: Date,  0 :: Int)
--                              , ((2021, "January"), -5)
--                              , ((2020, "June")   , 20)
--                              , ((2021, "June")   , 25) 
--                              ]
--      in xs `groupBy` month `aggregateWith` (fromMaybe 0 . minimum)
-- :}
--     index | values
--     ----- | ------
-- "January" |     -5
--    "June" |     20
--
-- If you want to aggregate groups using a binary function, see 'foldWith' which
-- may be much faster.
aggregateWith :: (Ord g, Unbox a, Unbox b) 
              => Grouping k g a 
              -> (Series k a -> b) 
              -> Series g b
{-# INLINE aggregateWith #-}
aggregateWith :: forall g a b k.
(Ord g, Unbox a, Unbox b) =>
Grouping k g a -> (Series k a -> b) -> Series g b
aggregateWith = Grouping k g Vector a
-> (Series Vector k a -> b) -> Series Vector g b
forall g (v :: * -> *) a b k.
(Ord g, Vector v a, Vector v b) =>
Grouping k g v a -> (Series v k a -> b) -> Series v g b
G.aggregateWith


-- | Aggregate each group in a 'Grouping' using a binary function.
-- While this is not as expressive as 'aggregateWith', users looking for maximum
-- performance should use 'foldWith' as much as possible.
foldWith :: (Ord g, Unbox a) 
         => Grouping k g a
         -> (a -> a -> a)
         -> Series g a
{-# INLINE foldWith #-}
foldWith :: forall g a k.
(Ord g, Unbox a) =>
Grouping k g a -> (a -> a -> a) -> Series g a
foldWith = Grouping k g Vector a -> (a -> a -> a) -> Series Vector g a
forall g (v :: * -> *) a k.
(Ord g, Vector v a) =>
Grouping k g v a -> (a -> a -> a) -> Series v g a
G.foldWith


-- | Expanding window aggregation.
--
-- >>> :{ 
--     let (xs :: Series Int Int) 
--          = fromList [ (1, 0)
--                     , (2, 1)
--                     , (3, 2)
--                     , (4, 3)
--                     , (5, 4)
--                     , (6, 5)
--                     ]
--     in (xs `expanding` sum) :: Series Int Int 
-- :}
-- index | values
-- ----- | ------
--     1 |      0
--     2 |      1
--     3 |      3
--     4 |      6
--     5 |     10
--     6 |     15
expanding :: (Unbox a, Unbox b) 
          => Series k a        -- ^ Series vector
          -> (Series k a -> b) -- ^ Aggregation function
          -> Series k b        -- ^ Resulting vector
{-# INLINE expanding #-}
expanding :: forall a b k.
(Unbox a, Unbox b) =>
Series k a -> (Series k a -> b) -> Series k b
expanding = Series Vector k a -> (Series Vector k a -> b) -> Series Vector k b
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
Series v k a -> (Series v k a -> b) -> Series v k b
G.expanding


-- | General-purpose window aggregation.
--
-- >>> :{ 
--     let (xs :: Series.Series Int Int) 
--          = Series.fromList [ (1, 0)
--                            , (2, 1)
--                            , (3, 2)
--                            , (4, 3)
--                            , (5, 4)
--                            , (6, 5)
--                            ]
--     in windowing (\k -> k `to` (k+2)) sum xs
-- :}
-- index | values
-- ----- | ------
--     1 |      3
--     2 |      6
--     3 |      9
--     4 |     12
--     5 |      9
--     6 |      5
windowing :: (Ord k, Unbox a, Unbox b)
          => (k -> Range k)
          -> (Series k a -> b)
          -> Series k a
          -> Series k b
{-# INLINE windowing #-}
windowing :: forall k a b.
(Ord k, Unbox a, Unbox b) =>
(k -> Range k) -> (Series k a -> b) -> Series k a -> Series k b
windowing = (k -> Range k)
-> (Series Vector k a -> b)
-> Series Vector k a
-> Series Vector k b
forall k (v :: * -> *) a b.
(Ord k, Vector v a, Vector v b) =>
(k -> Range k)
-> (Series v k a -> b) -> Series v k a -> Series v k b
G.windowing 


-- | \(O(1)\) Test whether a 'Series' is empty.
null :: Unbox a => Series k a -> Bool
{-# INLINE null #-}
null :: forall a k. Unbox a => Series k a -> Bool
null = Series Vector k a -> Bool
forall (v :: * -> *) a k. Vector v a => Series v k a -> Bool
G.null


-- |\(O(1)\) Extract the length of a 'Series'.
length :: Unbox a => Series k a -> Int
{-# INLINE length #-}
length :: forall a k. Unbox a => Series k a -> Int
length = Series Vector k a -> Int
forall (v :: * -> *) a k. Vector v a => Series v k a -> Int
G.length


-- | \(O(n)\) Check if all elements satisfy the predicate.
all :: Unbox a => (a -> Bool) -> Series k a -> Bool
{-# INLINE all #-}
all :: forall a k. Unbox a => (a -> Bool) -> Series k a -> Bool
all = (a -> Bool) -> Series Vector k a -> Bool
forall (v :: * -> *) a k.
Vector v a =>
(a -> Bool) -> Series v k a -> Bool
G.all


-- | \(O(n)\) Check if any element satisfies the predicate.
any :: Unbox a => (a -> Bool) -> Series k a -> Bool
{-# INLINE any #-}
any :: forall a k. Unbox a => (a -> Bool) -> Series k a -> Bool
any = (a -> Bool) -> Series Vector k a -> Bool
forall (v :: * -> *) a k.
Vector v a =>
(a -> Bool) -> Series v k a -> Bool
G.any


-- | \(O(n)\) Check if all elements are 'True'.
and :: Series k Bool -> Bool
{-# INLINE and #-}
and :: forall k. Series k Bool -> Bool
and = Series Vector k Bool -> Bool
forall (v :: * -> *) k. Vector v Bool => Series v k Bool -> Bool
G.and


-- | \(O(n)\) Check if any element is 'True'.
or :: Series k Bool -> Bool
{-# INLINE or #-}
or :: forall k. Series k Bool -> Bool
or = Series Vector k Bool -> Bool
forall (v :: * -> *) k. Vector v Bool => Series v k Bool -> Bool
G.or


-- | \(O(n)\) Compute the sum of the elements.
sum :: (Unbox a, Num a) => Series k a -> a
{-# INLINE sum #-}
sum :: forall a k. (Unbox a, Num a) => Series k a -> a
sum = Series Vector k a -> a
forall a (v :: * -> *) k. (Num a, Vector v a) => Series v k a -> a
G.sum


-- | \(O(n)\) Compute the product of the elements.
product :: (Unbox a, Num a) => Series k a -> a
{-# INLINE product #-}
product :: forall a k. (Unbox a, Num a) => Series k a -> a
product = Series Vector k a -> a
forall a (v :: * -> *) k. (Num a, Vector v a) => Series v k a -> a
G.product


-- | \(O(n)\) Yield the maximum element of the series. In case of a tie, the first occurrence wins.
-- If the 'Series' is empty, @Nothing@ is returned.
--
-- See also 'argmax'.
maximum :: (Ord a, Unbox a) => Series k a -> Maybe a
{-# INLINE maximum #-}
maximum :: forall a k. (Ord a, Unbox a) => Series k a -> Maybe a
maximum = Series Vector k a -> Maybe a
forall a (v :: * -> *) k.
(Ord a, Vector v a) =>
Series v k a -> Maybe a
G.maximum


-- | \(O(n)\) @'maximumOn' f xs@ teturns the maximum element of the series @xs@, as determined by the function @f@.
-- In case of a tie, the first occurrence wins. If the 'Series' is empty, @Nothing@ is returned.
maximumOn :: (Ord b, Unbox a) => (a -> b) -> Series k a -> Maybe a
{-# INLINE maximumOn #-}
maximumOn :: forall b a k. (Ord b, Unbox a) => (a -> b) -> Series k a -> Maybe a
maximumOn = (a -> b) -> Series Vector k a -> Maybe a
forall b (v :: * -> *) a k.
(Ord b, Vector v a) =>
(a -> b) -> Series v k a -> Maybe a
G.maximumOn


-- | \(O(n)\) Yield the minimum element of the series. In case of a tie, the first occurrence wins.
-- If the 'Series' is empty, @Nothing@ is returned.
--
-- See also 'argmin'.
minimum :: (Ord a, Unbox a) => Series k a -> Maybe a
{-# INLINE minimum #-}
minimum :: forall a k. (Ord a, Unbox a) => Series k a -> Maybe a
minimum = Series Vector k a -> Maybe a
forall a (v :: * -> *) k.
(Ord a, Vector v a) =>
Series v k a -> Maybe a
G.minimum


-- | \(O(n)\) @'minimumOn' f xs@ teturns the minimum element of the series @xs@, as determined by the function @f@.
-- In case of a tie, the first occurrence wins. If the 'Series' is empty, @Nothing@ is returned.
minimumOn :: (Ord b, Unbox a) => (a -> b) -> Series k a -> Maybe a
{-# INLINE minimumOn #-}
minimumOn :: forall b a k. (Ord b, Unbox a) => (a -> b) -> Series k a -> Maybe a
minimumOn = (a -> b) -> Series Vector k a -> Maybe a
forall b (v :: * -> *) a k.
(Ord b, Vector v a) =>
(a -> b) -> Series v k a -> Maybe a
G.minimumOn


-- | \(O(n)\) Find the index of the maximum element in the input series.
-- If the input series is empty, 'Nothing' is returned.
--
-- The index of the first occurrence of the maximum element is returned.
--
-- >>> import qualified Data.Series.Unboxed as Series 
-- >>> :{ 
--     let (xs :: Series.Series Int Int) 
--          = Series.fromList [ (1, 0)
--                            , (2, 1)
--                            , (3, 2)
--                            , (4, 7)
--                            , (5, 4)
--                            , (6, 5)
--                            ]
--     in argmax xs 
-- :}
-- Just 4
argmax :: (Ord a, Unbox a)
       => Series k a
       -> Maybe k
argmax :: forall a k. (Ord a, Unbox a) => Series k a -> Maybe k
argmax = Series Vector k a -> Maybe k
forall a (v :: * -> *) k.
(Ord a, Vector v a) =>
Series v k a -> Maybe k
G.argmax
{-# INLINE argmax #-}


-- | \(O(n)\) Find the index of the minimum element in the input series.
-- If the input series is empty, 'Nothing' is returned.
--
-- The index of the first occurrence of the minimum element is returned.
-- >>> import qualified Data.Series.Unboxed as Series 
-- >>> :{ 
--     let (xs :: Series.Series Int Int) 
--          = Series.fromList [ (1, 1)
--                            , (2, 1)
--                            , (3, 2)
--                            , (4, 0)
--                            , (5, 4)
--                            , (6, 5)
--                            ]
--     in argmin xs 
-- :}
-- Just 4
argmin :: (Ord a, Unbox a)
       => Series k a
       -> Maybe k
argmin :: forall a k. (Ord a, Unbox a) => Series k a -> Maybe k
argmin = Series Vector k a -> Maybe k
forall a (v :: * -> *) k.
(Ord a, Vector v a, Vector v (Down a)) =>
Series v k a -> Maybe k
G.argmin
{-# INLINE argmin #-}


-- | \(O(n)\) Left-to-right postscan.
--
-- >>> let xs = Series.fromList (zip [0..] [1,2,3,4]) :: Series Int Int
-- >>> xs
-- index | values
-- ----- | ------
--     0 |      1
--     1 |      2
--     2 |      3
--     3 |      4
-- >>> postscanl (+) 0 xs
-- index | values
-- ----- | ------
--     0 |      1
--     1 |      3
--     2 |      6
--     3 |     10
postscanl :: (Unbox a, Unbox b) 
          => (a -> b -> a) -> a -> Series k b -> Series k a
{-# INLINE postscanl #-}
postscanl :: forall a b k.
(Unbox a, Unbox b) =>
(a -> b -> a) -> a -> Series k b -> Series k a
postscanl = (a -> b -> a) -> a -> Series Vector k b -> Series Vector k a
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
(a -> b -> a) -> a -> Series v k b -> Series v k a
G.postscanl


-- | \(O(n)\) Left-to-right prescan.
--
-- >>> let xs = Series.fromList (zip [0..] [1,2,3,4]) :: Series Int Int
-- >>> xs
-- index | values
-- ----- | ------
--     0 |      1
--     1 |      2
--     2 |      3
--     3 |      4
-- >>> prescanl (+) 0 xs
-- index | values
-- ----- | ------
--     0 |      0
--     1 |      1
--     2 |      3
--     3 |      6
prescanl :: (Unbox a, Unbox b) 
         => (a -> b -> a) -> a -> Series k b -> Series k a
{-# INLINE prescanl #-}
prescanl :: forall a b k.
(Unbox a, Unbox b) =>
(a -> b -> a) -> a -> Series k b -> Series k a
prescanl = (a -> b -> a) -> a -> Series Vector k b -> Series Vector k a
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
(a -> b -> a) -> a -> Series v k b -> Series v k a
G.prescanl


-- | Display a 'Series' using default 'DisplayOptions'.
--
-- >>> let xs = Series.fromList (zip [0..] [1,2,3,4,5,6,7]) :: Series Int Int
-- >>> putStrLn $ display xs
-- index | values
-- ----- | ------
--     0 |      1
--     1 |      2
--     2 |      3
--   ... |    ...
--     4 |      5
--     5 |      6
--     6 |      7
display :: (Unbox a, Show k, Show a) 
        => Series k a 
        -> String
display :: forall a k. (Unbox a, Show k, Show a) => Series k a -> String
display = Series Vector k a -> String
forall (v :: * -> *) a k.
(Vector v a, Show k, Show a) =>
Series v k a -> String
G.display


-- | Display a 'Series' using customizable 'DisplayOptions'.
--
-- >>> let xs = Series.fromList (zip [0..] [1,2,3,4,5,6,7]) :: Series Int Int
-- >>> import Data.List (replicate)
-- >>> :{
--     let opts = DisplayOptions { maximumNumberOfRows  = 4
--                               , indexHeader = "keys"
--                               , valuesHeader = "vals"
--                               , keyDisplayFunction   = (\i -> replicate i 'x') `noLongerThan` 5
--                               , valueDisplayFunction = (\i -> replicate i 'o') 
--                               }
--      in putStrLn $ displayWith opts xs
-- :}
--   keys |    vals
--  ----- |  ------
--        |       o
--      x |      oo
--    ... |     ...
--  xxxxx |  oooooo
-- xxx... | ooooooo
displayWith :: (Unbox a) 
            => DisplayOptions k a
            -> Series k a 
            -> String
displayWith :: forall a k. Unbox a => DisplayOptions k a -> Series k a -> String
displayWith = DisplayOptions k a -> Series Vector k a -> String
forall (v :: * -> *) a k.
Vector v a =>
DisplayOptions k a -> Series v k a -> String
G.displayWith