packages feed

hw-rankselect-0.2.0.1: src/HaskellWorks/Data/Succinct/BalancedParens/RangeMinMax/L0.hs

{-# LANGUAGE FlexibleContexts   #-}
{-# LANGUAGE FlexibleInstances  #-}
{-# LANGUAGE InstanceSigs       #-}
{-# LANGUAGE TypeFamilies       #-}

module HaskellWorks.Data.Succinct.BalancedParens.RangeMinMax.L0
  ( RangeMinMaxL0(..)
  , mkRangeMinMaxL0
  ) where

import           Data.Int
import qualified Data.Vector                                                  as DV
import qualified Data.Vector.Storable                                         as DVS
import           Data.Word
import           HaskellWorks.Data.Bits.BitLength
import           HaskellWorks.Data.Bits.BitWise
import           HaskellWorks.Data.Succinct.BalancedParens.Internal
import           HaskellWorks.Data.Succinct.BalancedParens.NewCloseAt
import           HaskellWorks.Data.Succinct.BalancedParens.RangeMinMax.Internal
import           HaskellWorks.Data.Succinct.BalancedParens.RangeMinMax.Simple
import           HaskellWorks.Data.Succinct.RankSelect.Binary.Basic.Rank0
import           HaskellWorks.Data.Succinct.RankSelect.Binary.Basic.Rank1
import           HaskellWorks.Data.Succinct.Excess.MinMaxExcess1
import           HaskellWorks.Data.Vector.VectorLike

data RangeMinMaxL0 = RangeMinMaxL0
  { rangeMinMaxSimple   :: !RangeMinMaxSimple
  , rangeMinMaxL0Min    :: !(DVS.Vector Int8)
  , rangeMinMaxL0Max    :: !(DVS.Vector Int8)
  , rangeMinMaxL0Excess :: !(DVS.Vector Int8)
  }

instance RangeMinMaxLevel RangeMinMaxL0 where
  rmmFactor _ = 1
  rmmBinWords _ = 1
  rmmBins = DVS.length . rangeMinMaxL0Min
  {-# INLINE rmmFactor    #-}
  {-# INLINE rmmBinWords  #-}
  {-# INLINE rmmBins      #-}

class MkRangeMinMaxL0 a where
  mkRangeMinMaxL0 :: a -> RangeMinMaxL0

instance MkRangeMinMaxL0 RangeMinMaxSimple where
  mkRangeMinMaxL0 simple = RangeMinMaxL0
    { rangeMinMaxSimple   = simple
    , rangeMinMaxL0Min    = DVS.constructN (len0 + 1) (\v -> let (minE, _, _) = allMinMax DV.! DVS.length v in fromIntegral minE)
    , rangeMinMaxL0Max    = DVS.constructN (len0 + 1) (\v -> let (_, _, maxE) = allMinMax DV.! DVS.length v in fromIntegral maxE)
    , rangeMinMaxL0Excess = DVS.constructN (len0 + 1) (\v -> let (_, e,    _) = allMinMax DV.! DVS.length v in fromIntegral e)
    }
    where len0        = fromIntegral (vLength (rangeMinMaxSimpleBP simple)) :: Int
          allMinMax   = DV.constructN (len0 + 1) genMinMax
          genMinMax v = let len = DV.length v in
                        if len == len0
                          then (0, 0, 0)
                          else minMaxExcess1 (rangeMinMaxSimpleBP simple !!! fromIntegral len)
  {-# INLINE mkRangeMinMaxL0 #-}

instance MkRangeMinMaxL0 (DVS.Vector Word64) where
  mkRangeMinMaxL0 = mkRangeMinMaxL0 . mkRangeMinMaxSimple
  {-# INLINE mkRangeMinMaxL0 #-}

instance RangeMinMaxDerived RangeMinMaxL0 where
  type RangeMinMaxBase RangeMinMaxL0 = RangeMinMaxSimple
  rmmBase = rangeMinMaxSimple
  {-# INLINE rmmBase #-}

instance TestBit RangeMinMaxL0 where
  (.?.) = (.?.) . rangeMinMaxSimple
  {-# INLINE (.?.) #-}

instance Rank1 RangeMinMaxL0 where
  rank1 = rank1 . rangeMinMaxSimple
  {-# INLINE rank1 #-}

instance Rank0 RangeMinMaxL0 where
  rank0 = rank0 . rangeMinMaxSimple
  {-# INLINE rank0 #-}

instance BitLength RangeMinMaxL0 where
  bitLength = bitLength . rangeMinMaxSimple
  {-# INLINE bitLength #-}

instance OpenAt RangeMinMaxL0 where
  openAt = openAt . rangeMinMaxSimple
  {-# INLINE openAt #-}

instance CloseAt RangeMinMaxL0 where
  closeAt = closeAt . rangeMinMaxSimple
  {-# INLINE closeAt #-}

instance NewCloseAt RangeMinMaxL0 where
  newCloseAt = newCloseAt . rangeMinMaxSimple
  {-# INLINE newCloseAt #-}

instance RangeMinMax RangeMinMaxL0 where
  rmmFindCloseDispatch v s p = if p `mod` 64 == 0
    then rmmFindCloseN v s p
    else rmmFindCloseDispatch (rangeMinMaxSimple v) s p
  rmmFindCloseN v s p =
    let i = p `div` 64 in
    let minE = fromIntegral (mins !!! fromIntegral i) :: Int in
    if fromIntegral s + minE <= 0
      then  rmmFindCloseN (rangeMinMaxSimple v) s p
      else if v `newCloseAt` p && s <= 1
        then Just p
        else let excess  = fromIntegral (excesses !!! fromIntegral i)  :: Int in
              rmmFindClose v (fromIntegral (excess + fromIntegral s)) (p + 64)
    where mins                  = rangeMinMaxL0Min v
          excesses              = rangeMinMaxL0Excess v
  {-# INLINE rmmFindCloseDispatch #-}
  {-# INLINE rmmFindCloseN        #-}

instance BalancedParens RangeMinMaxL0 where
  findOpenN         = findOpenN . rangeMinMaxSimple
  findCloseN v s p  = (+ 1) `fmap` rmmFindClose v (fromIntegral s) (p - 1)

  {-# INLINE findOpenN   #-}
  {-# INLINE findCloseN  #-}