packages feed

ac-library-hs-1.5.1.0: benchmarks/BenchLib/Vector/MapAccumL.hs

-- | Fast modular multiplication by barrett reduction.
module BenchLib.Vector.MapAccumL
  ( mapAccumL1,
    mapAccumL2,
    mapAccumL3,
    mapAccumL4,
  )
where

import Control.Monad.Primitive (PrimMonad)
import Control.Monad.ST (ST, runST)
import Control.Monad.Trans.State.Strict (StateT, runState, runStateT, state)
import Data.Vector.Fusion.Bundle qualified as Bundle
import Data.Vector.Fusion.Bundle.Monadic qualified as BundleM
import Data.Vector.Fusion.Bundle.Size qualified as Bundle
import Data.Vector.Fusion.Stream.Monadic qualified as MS
import Data.Vector.Generic qualified as VG
import Data.Vector.Generic.Mutable qualified as VGM

{-# INLINE mapAccumL1 #-}
mapAccumL1 ::
  (VG.Vector v a, VG.Vector v b) =>
  (s -> a -> (s, b)) ->
  s ->
  v a ->
  (s, v b)
mapAccumL1 f s0 xs = (\(!x, !s) -> (s, x)) $ runState (VG.mapM g xs) s0
  where
    g a =
      state
        ( \s ->
            let (!s', !b) = f s a
             in (b, s')
        )

{-# INLINE mapAccumL2 #-}
mapAccumL2 ::
  (VG.Vector v a, VG.Vector v b) =>
  (s -> a -> (s, b)) ->
  s ->
  v a ->
  (s, v b)
mapAccumL2 f s0 xs = runST $ do
  vec <- VGM.unsafeNew (VG.length xs)
  !res <-
    VG.ifoldM'
      ( \ !s i x -> do
          let (!s', !x') = f s x
          VGM.write vec i x'
          pure s'
      )
      s0
      xs
  vec' <- VG.unsafeFreeze vec
  pure (res, vec')

{-# INLINE mapAccumL3 #-}
mapAccumL3 ::
  forall v s a b.
  (VG.Vector v a, VG.Vector v b) =>
  (s -> a -> (s, b)) ->
  s ->
  v a ->
  (s, v b)
mapAccumL3 f s0 xs = (\(!x, !s) -> (s, x)) $ runST $ (`runStateT` s0) $ do
  unstreamPrimM
    . BundleM.mapM g
    $ BundleM.fromVector xs
  where
    g :: forall st. a -> StateT s (ST st) b
    g a =
      state
        ( \s ->
            let (!s', !b) = f s a
             in (b, s')
        )

-- | https://github.com/haskell/vector/issues/416
unstreamPrimM :: (PrimMonad m, VG.Vector v a) => BundleM.Bundle m u a -> m (v a)
{-# INLINE [1] unstreamPrimM #-}
unstreamPrimM s = VGM.munstream s >>= VG.unsafeFreeze

-- @cojna/iota. Note that it does not return state value.
{-# INLINE mapAccumL4 #-}
mapAccumL4 ::
  (VG.Vector v a, VG.Vector v b) =>
  (s -> a -> (s, b)) ->
  s ->
  v a ->
  v b
mapAccumL4 f x =
  VG.unstream
    . Bundle.inplace
      (streamAccumM (\s a -> pure (f s a)) x)
      Bundle.toMax
    . VG.stream

-- @cojna/iota
streamAccumM :: (Monad m) => (s -> a -> m (s, b)) -> s -> MS.Stream m a -> MS.Stream m b
streamAccumM f s0 (MS.Stream step x0) = MS.Stream step' (s0, x0)
  where
    step' (!s, x) = do
      r <- step x
      case r of
        MS.Yield a x' -> do
          (s', b) <- f s a
          return $ MS.Yield b (s', x')
        MS.Skip x' -> return $ MS.Skip (s, x')
        MS.Done -> return MS.Done
    {-# INLINE [0] step' #-}
{-# INLINE [1] streamAccumM #-}