module Data.Series.Generic.Aggregation ( 
    -- * Grouping

    Grouping,
    groupBy,
    aggregateWith,
    foldWith,

    -- * Windowing

    expanding,
    windowing,

    -- * Folding

    all, any, and, or, sum, product, maximum, maximumOn, minimum, minimumOn,
    argmax, argmin,
) where

import qualified Data.List 
import qualified Data.Map.Strict                as Map
import           Data.Ord                       ( Down(..) )
import           Data.Series.Generic.Definition ( Series(..) )
import qualified Data.Series.Generic.Definition as GSeries
import           Data.Series.Generic.View       ( Range, slice, select )
import qualified Data.Vector                    as Boxed
import           Data.Vector.Generic            ( Vector )
import qualified Data.Vector.Generic            as Vector
import           Prelude                        hiding ( last, null, length, all, any, and, or, sum, product, maximum, minimum )

-- $setup

-- >>> import qualified Data.Series as Series

-- >>> import qualified Data.Set as Set


-- | 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 v k a       -- ^ Input series

        -> (k -> g)           -- ^ Grouping function

        -> Grouping k g v a   -- ^ Grouped series

{-# INLINABLE groupBy #-}
groupBy :: forall {k} (v :: k -> *) k (a :: k) g.
Series v k a -> (k -> g) -> Grouping k g v a
groupBy = Series v k a -> (k -> g) -> Grouping k g v a
forall {k} k g (v :: k -> *) (a :: k).
Series v k a -> (k -> g) -> Grouping k g v a
MkGrouping


-- | Representation of a 'Series' being grouped.

data Grouping k g v a 
    = MkGrouping (Series v k a)  (k -> g)


-- | 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, Vector v a, Vector v b) 
              => Grouping k g v a 
              -> (Series v k a -> b) 
              -> Series v g b
{-# INLINABLE aggregateWith #-}
aggregateWith :: 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
aggregateWith (MkGrouping Series v k a
xs k -> g
by) Series v k a -> b
f
    = Map g b -> Series v g b
forall (v :: * -> *) a k. Vector v a => Map k a -> Series v k a
GSeries.fromStrictMap 
    (Map g b -> Series v g b) -> Map g b -> Series v g b
forall a b. (a -> b) -> a -> b
$ ([(k, a)] -> b) -> Map g [(k, a)] -> Map g b
forall a b. (a -> b) -> Map g a -> Map g b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Series v k a -> b
f (Series v k a -> b) -> ([(k, a)] -> Series v k a) -> [(k, a)] -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(k, a)] -> Series v k a
forall (v :: * -> *) a k. Vector v a => [(k, a)] -> Series v k a
GSeries.fromDistinctAscList)
    -- We're using a list fold to limit the number of 

    -- type constraints. This is about as fast as it is 

    -- with a Vector fold

    (Map g [(k, a)] -> Map g b) -> Map g [(k, a)] -> Map g b
forall a b. (a -> b) -> a -> b
$ (Map g [(k, a)] -> (k, a) -> Map g [(k, a)])
-> Map g [(k, a)] -> [(k, a)] -> Map g [(k, a)]
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Data.List.foldl' Map g [(k, a)] -> (k, a) -> Map g [(k, a)]
forall {b}. Map g [(k, b)] -> (k, b) -> Map g [(k, b)]
acc Map g [(k, a)]
forall a. Monoid a => a
mempty 
    ([(k, a)] -> Map g [(k, a)]) -> [(k, a)] -> Map g [(k, a)]
forall a b. (a -> b) -> a -> b
$ Series v k a -> [(k, a)]
forall (v :: * -> *) a k. Vector v a => Series v k a -> [(k, a)]
GSeries.toList Series v k a
xs
    where
        acc :: Map g [(k, b)] -> (k, b) -> Map g [(k, b)]
acc !Map g [(k, b)]
m (k
key, b
val) = ([(k, b)] -> [(k, b)] -> [(k, b)])
-> g -> [(k, b)] -> Map g [(k, b)] -> Map g [(k, b)]
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
Map.insertWith [(k, b)] -> [(k, b)] -> [(k, b)]
forall a. Semigroup a => a -> a -> a
(<>) (k -> g
by k
key) ((k, b) -> [(k, b)]
forall a. a -> [a]
Data.List.singleton (k
key, b
val)) Map g [(k, b)]
m


-- | Fold over 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.

--

-- >>> 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 `foldWith` min

-- :}

--     index | values

--     ----- | ------

-- "January" |     -5

--    "June" |     20

foldWith :: (Ord g, Vector v a) 
         => Grouping k g v a
         -> (a -> a -> a)
         -> Series v g a
{-# INLINABLE foldWith #-}
foldWith :: forall g (v :: * -> *) a k.
(Ord g, Vector v a) =>
Grouping k g v a -> (a -> a -> a) -> Series v g a
foldWith (MkGrouping Series v k a
xs k -> g
by) a -> a -> a
f 
    = Map g a -> Series v g a
forall (v :: * -> *) a k. Vector v a => Map k a -> Series v k a
GSeries.fromStrictMap 
    -- We're using a list fold to limit the number of 

    -- type constraints. This is about as fast as it is 

    -- with a Vector fold

    (Map g a -> Series v g a) -> Map g a -> Series v g a
forall a b. (a -> b) -> a -> b
$ (Map g a -> (k, a) -> Map g a) -> Map g a -> [(k, a)] -> Map g a
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Data.List.foldl' Map g a -> (k, a) -> Map g a
acc Map g a
forall a. Monoid a => a
mempty 
    ([(k, a)] -> Map g a) -> [(k, a)] -> Map g a
forall a b. (a -> b) -> a -> b
$ Series v k a -> [(k, a)]
forall (v :: * -> *) a k. Vector v a => Series v k a -> [(k, a)]
GSeries.toList Series v k a
xs
    where
        acc :: Map g a -> (k, a) -> Map g a
acc !Map g a
m (k
key, a
val) = (a -> a -> a) -> g -> a -> Map g a -> Map g a
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
Map.insertWith a -> a -> a
f (k -> g
by k
key) a
val Map g a
m


-- | Expanding window aggregation.

--

-- >>> import qualified Data.Series as Series 

-- >>> :{ 

--     let (xs :: Series.Series Int Int) 

--          = Series.fromList [ (1, 0)

--                            , (2, 1)

--                            , (3, 2)

--                            , (4, 3)

--                            , (5, 4)

--                            , (6, 5)

--                            ]

--     in (xs `expanding` sum) :: Series.Series Int Int 

-- :}

-- index | values

-- ----- | ------

--     1 |      0

--     2 |      1

--     3 |      3

--     4 |      6

--     5 |     10

--     6 |     15

expanding :: (Vector v a, Vector v b) 
          => Series v k a        -- ^ Series vector

          -> (Series v k a -> b) -- ^ Aggregation function

          -> Series v k b        -- ^ Resulting vector

{-# INLINABLE expanding #-}
expanding :: forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
Series v k a -> (Series v k a -> b) -> Series v k b
expanding Series v k a
vs Series v k a -> b
f = Index k -> v b -> Series v k b
forall {k} (v :: k -> *) k1 (a :: k).
Index k1 -> v a -> Series v k1 a
MkSeries (Series v k a -> Index k
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> Index k2
index Series v k a
vs) (v b -> Series v k b) -> v b -> Series v k b
forall a b. (a -> b) -> a -> b
$ Int -> (Int -> (b, Int)) -> Int -> v b
forall (v :: * -> *) a b.
Vector v a =>
Int -> (b -> (a, b)) -> b -> v a
Vector.unfoldrExactN (Series v k a -> Int
forall (v :: * -> *) a k. Vector v a => Series v k a -> Int
GSeries.length Series v k a
vs) Int -> (b, Int)
go Int
0
    where
        -- Recall that `slice` does NOT include the right index

        go :: Int -> (b, Int)
go Int
ix = (Series v k a -> b
f (Series v k a -> b) -> Series v k a -> b
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Series v k a -> Series v k a
forall (v :: * -> *) a k.
Vector v a =>
Int -> Int -> Series v k a -> Series v k a
slice Int
0 (Int
ix Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Series v k a
vs, Int
ix Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)


-- | General-purpose window aggregation.

--

-- >>> import qualified Data.Series as Series 

-- >>> import           Data.Series ( to )

-- >>> :{ 

--     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, Vector v a, Vector v b)
          => (k -> Range k)
          -> (Series v k a -> b)
          -> Series v k a
          -> Series v k b
{-# INLINABLE windowing #-}
windowing :: 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
windowing k -> Range k
range Series v k a -> b
agg Series v k a
series 
    = (k -> a -> b) -> Series v k a -> Series v k b
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
(k -> a -> b) -> Series v k a -> Series v k b
GSeries.mapWithKey (\k
k a
_ -> Series v k a -> b
agg (Series v k a -> b) -> Series v k a -> b
forall a b. (a -> b) -> a -> b
$ Series v k a
series Series v k a -> Range k -> Series v 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 -> Range k -> Series v k a
`select` k -> Range k
range k
k) Series v k a
series


-- | \(O(n)\) Check if all elements satisfy the predicate.

all :: Vector v a => (a -> Bool) -> Series v k a -> Bool
{-# INLINABLE all #-}
all :: forall (v :: * -> *) a k.
Vector v a =>
(a -> Bool) -> Series v k a -> Bool
all a -> Bool
f = (a -> Bool) -> v a -> Bool
forall (v :: * -> *) a. Vector v a => (a -> Bool) -> v a -> Bool
Vector.all a -> Bool
f (v a -> Bool) -> (Series v k a -> v a) -> Series v k a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series v k a -> v a
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
values


-- | \(O(n)\) Check if any element satisfies the predicate.

any :: Vector v a => (a -> Bool) -> Series v k a -> Bool
{-# INLINABLE any #-}
any :: forall (v :: * -> *) a k.
Vector v a =>
(a -> Bool) -> Series v k a -> Bool
any a -> Bool
f = (a -> Bool) -> v a -> Bool
forall (v :: * -> *) a. Vector v a => (a -> Bool) -> v a -> Bool
Vector.any a -> Bool
f (v a -> Bool) -> (Series v k a -> v a) -> Series v k a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series v k a -> v a
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
values


-- | \(O(n)\) Check if all elements are 'True'.

and :: Vector v Bool => Series v k Bool -> Bool
{-# INLINABLE and #-}
and :: forall (v :: * -> *) k. Vector v Bool => Series v k Bool -> Bool
and = v Bool -> Bool
forall (v :: * -> *). Vector v Bool => v Bool -> Bool
Vector.and (v Bool -> Bool)
-> (Series v k Bool -> v Bool) -> Series v k Bool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series v k Bool -> v Bool
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
values


-- | \(O(n)\) Check if any element is 'True'.

or :: Vector v Bool => Series v k Bool -> Bool
{-# INLINABLE or #-}
or :: forall (v :: * -> *) k. Vector v Bool => Series v k Bool -> Bool
or = v Bool -> Bool
forall (v :: * -> *). Vector v Bool => v Bool -> Bool
Vector.or (v Bool -> Bool)
-> (Series v k Bool -> v Bool) -> Series v k Bool -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series v k Bool -> v Bool
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
values


-- | \(O(n)\) Compute the sum of the elements.

sum :: (Num a, Vector v a) => Series v k a -> a
{-# INLINABLE sum #-}
sum :: forall a (v :: * -> *) k. (Num a, Vector v a) => Series v k a -> a
sum = v a -> a
forall (v :: * -> *) a. (Vector v a, Num a) => v a -> a
Vector.sum (v a -> a) -> (Series v k a -> v a) -> Series v k a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series v k a -> v a
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
values


-- | \(O(n)\) Compute the product of the elements.

product :: (Num a, Vector v a) => Series v k a -> a
{-# INLINABLE product #-}
product :: forall a (v :: * -> *) k. (Num a, Vector v a) => Series v k a -> a
product = v a -> a
forall (v :: * -> *) a. (Vector v a, Num a) => v a -> a
Vector.product (v a -> a) -> (Series v k a -> v a) -> Series v k a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series v k a -> v a
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
values


nothingIfEmpty :: Vector v a 
               => (Series v k a -> b) -> (Series v k a -> Maybe b)
nothingIfEmpty :: forall (v :: * -> *) a k b.
Vector v a =>
(Series v k a -> b) -> Series v k a -> Maybe b
nothingIfEmpty Series v k a -> b
f Series v k a
xs = if Series v k a -> Bool
forall (v :: * -> *) a k. Vector v a => Series v k a -> Bool
GSeries.null Series v k a
xs then Maybe b
forall a. Maybe a
Nothing else b -> Maybe b
forall a. a -> Maybe a
Just (Series v k a -> b
f Series v k a
xs) 


-- | \(O(n)\) Yield the maximum element of the series. In case of a tie, the first occurrence wins.

maximum :: (Ord a, Vector v a) => Series v k a -> Maybe a
{-# INLINABLE maximum #-}
maximum :: forall a (v :: * -> *) k.
(Ord a, Vector v a) =>
Series v k a -> Maybe a
maximum = (Series v k a -> a) -> Series v k a -> Maybe a
forall (v :: * -> *) a k b.
Vector v a =>
(Series v k a -> b) -> Series v k a -> Maybe b
nothingIfEmpty ((Series v k a -> a) -> Series v k a -> Maybe a)
-> (Series v k a -> a) -> Series v k a -> Maybe a
forall a b. (a -> b) -> a -> b
$ v a -> a
forall (v :: * -> *) a. (Vector v a, Ord a) => v a -> a
Vector.maximum (v a -> a) -> (Series v k a -> v a) -> Series v k a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series v k a -> v a
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
values


-- | \(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, Vector v a) => (a -> b) -> Series v k a -> Maybe a
{-# INLINABLE maximumOn #-}
maximumOn :: forall b (v :: * -> *) a k.
(Ord b, Vector v a) =>
(a -> b) -> Series v k a -> Maybe a
maximumOn a -> b
f = (Series v k a -> a) -> Series v k a -> Maybe a
forall (v :: * -> *) a k b.
Vector v a =>
(Series v k a -> b) -> Series v k a -> Maybe b
nothingIfEmpty ((Series v k a -> a) -> Series v k a -> Maybe a)
-> (Series v k a -> a) -> Series v k a -> Maybe a
forall a b. (a -> b) -> a -> b
$ (a -> b) -> v a -> a
forall b (v :: * -> *) a.
(Ord b, Vector v a) =>
(a -> b) -> v a -> a
Vector.maximumOn a -> b
f (v a -> a) -> (Series v k a -> v a) -> Series v k a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series v k a -> v a
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
values


-- | \(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.

minimum :: (Ord a, Vector v a) => Series v k a -> Maybe a
{-# INLINABLE minimum #-}
minimum :: forall a (v :: * -> *) k.
(Ord a, Vector v a) =>
Series v k a -> Maybe a
minimum = (Series v k a -> a) -> Series v k a -> Maybe a
forall (v :: * -> *) a k b.
Vector v a =>
(Series v k a -> b) -> Series v k a -> Maybe b
nothingIfEmpty ((Series v k a -> a) -> Series v k a -> Maybe a)
-> (Series v k a -> a) -> Series v k a -> Maybe a
forall a b. (a -> b) -> a -> b
$ v a -> a
forall (v :: * -> *) a. (Vector v a, Ord a) => v a -> a
Vector.minimum (v a -> a) -> (Series v k a -> v a) -> Series v k a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series v k a -> v a
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
values


-- | \(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, Vector v a) => (a -> b) -> Series v k a -> Maybe a
{-# INLINABLE minimumOn #-}
minimumOn :: forall b (v :: * -> *) a k.
(Ord b, Vector v a) =>
(a -> b) -> Series v k a -> Maybe a
minimumOn a -> b
f = (Series v k a -> a) -> Series v k a -> Maybe a
forall (v :: * -> *) a k b.
Vector v a =>
(Series v k a -> b) -> Series v k a -> Maybe b
nothingIfEmpty ((Series v k a -> a) -> Series v k a -> Maybe a)
-> (Series v k a -> a) -> Series v k a -> Maybe a
forall a b. (a -> b) -> a -> b
$ (a -> b) -> v a -> a
forall b (v :: * -> *) a.
(Ord b, Vector v a) =>
(a -> b) -> v a -> a
Vector.minimumOn a -> b
f (v a -> a) -> (Series v k a -> v a) -> Series v k a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series v k a -> v a
forall {k1} (v :: k1 -> *) k2 (a :: k1). Series v k2 a -> v a
values


-- | \(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 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, Vector v a)
       => Series v k a
       -> Maybe k
{-# INLINABLE argmax #-}
argmax :: forall a (v :: * -> *) k.
(Ord a, Vector v a) =>
Series v k a -> Maybe k
argmax Series v k a
xs | Series v k a -> Bool
forall (v :: * -> *) a k. Vector v a => Series v k a -> Bool
GSeries.null Series v k a
xs = Maybe k
forall a. Maybe a
Nothing
          | Bool
otherwise = k -> Maybe k
forall a. a -> Maybe a
Just 
                      (k -> Maybe k) -> (Series v k a -> k) -> Series v k a -> Maybe k
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (k, a) -> k
forall a b. (a, b) -> a
fst 
                      -- We're forcing the use of boxed vectors in order to

                      -- reduce the constraints on the vector instance

                      ((k, a) -> k) -> (Series v k a -> (k, a)) -> Series v k a -> k
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((k, a) -> a) -> Vector (k, a) -> (k, a)
forall b a. Ord b => (a -> b) -> Vector a -> a
Boxed.maximumOn (k, a) -> a
forall a b. (a, b) -> b
snd 
                      (Vector (k, a) -> (k, a))
-> (Series v k a -> Vector (k, a)) -> Series v k a -> (k, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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)
GSeries.toVector
                      (Series Vector k a -> Vector (k, a))
-> (Series v k a -> Series Vector k a)
-> Series v k a
-> Vector (k, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Series v k a -> Series Vector k a
forall (v1 :: * -> *) a (v2 :: * -> *) k.
(Vector v1 a, Vector v2 a) =>
Series v1 k a -> Series v2 k a
GSeries.convert
                      (Series v k a -> Maybe k) -> Series v k a -> Maybe k
forall a b. (a -> b) -> a -> b
$ Series v k a
xs


-- | \(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 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, Vector v a, Vector v (Down a))
       => Series v k a
       -> Maybe k
{-# INLINABLE argmin #-}
argmin :: forall a (v :: * -> *) k.
(Ord a, Vector v a, Vector v (Down a)) =>
Series v k a -> Maybe k
argmin = Series v k (Down a) -> Maybe k
forall a (v :: * -> *) k.
(Ord a, Vector v a) =>
Series v k a -> Maybe k
argmax (Series v k (Down a) -> Maybe k)
-> (Series v k a -> Series v k (Down a)) -> Series v k a -> Maybe k
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Down a) -> Series v k a -> Series v k (Down a)
forall (v :: * -> *) a b k.
(Vector v a, Vector v b) =>
(a -> b) -> Series v k a -> Series v k b
GSeries.map a -> Down a
forall a. a -> Down a
Down