packages feed

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

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

module HaskellWorks.Data.Succinct.BalancedParens.RangeMinMax.L3
  ( RangeMinMaxL3(..)
  , mkRangeMinMaxL3
  ) 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.L0
import           HaskellWorks.Data.Succinct.BalancedParens.RangeMinMax.L1
import           HaskellWorks.Data.Succinct.BalancedParens.RangeMinMax.L2
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 RangeMinMaxL3 = RangeMinMaxL3
  { rangeMinMaxL3Base     :: !RangeMinMaxL2
  , rangeMinMaxL3Min      :: !(DVS.Vector Int16)
  , rangeMinMaxL3Max      :: !(DVS.Vector Int16)
  , rangeMinMaxL3Excess   :: !(DVS.Vector Int16)
  }

instance RangeMinMaxLevel RangeMinMaxL3 where
  rmmFactor _ = 32
  rmmBinWords v = rmmFactor v * rmmBinWords (rmmBase v)
  rmmBins = DVS.length . rangeMinMaxL3Min
  {-# INLINE rmmFactor    #-}
  {-# INLINE rmmBinWords  #-}
  {-# INLINE rmmBins      #-}

class MkRangeMinMaxL3 a where
  mkRangeMinMaxL3 :: a -> RangeMinMaxL3

instance MkRangeMinMaxL3 RangeMinMaxL2 where
  mkRangeMinMaxL3 rmmL2 = result
    where bp            = rangeMinMaxSimpleBP (rangeMinMaxSimple (rangeMinMaxL1Base (rangeMinMaxL2Base rmmL2)))
          lenL3         = (DVS.length (rangeMinMaxL2Min rmmL2) `div` rmmFactor result) + 1 :: Int
          allMinMaxL3   = DV.constructN lenL3 genMinMaxL3
          genMinMaxL3 v = let len = DV.length v in minMaxExcess1 (DVS.take (rmmBinWords result) (DVS.drop (len * rmmBinWords result) bp))
          rangeMinMaxL3ExcessA = DVS.constructN lenL3 (\v -> let (_, e,    _) = allMinMaxL3 DV.! DVS.length v in fromIntegral e) :: DVS.Vector Int16
          result = RangeMinMaxL3
            { rangeMinMaxL3Base     = rmmL2
            , rangeMinMaxL3Min      = DVS.constructN lenL3 (\v -> let (minE, _, _) = allMinMaxL3 DV.! DVS.length v in fromIntegral minE)
            , rangeMinMaxL3Max      = DVS.constructN lenL3 (\v -> let (_, _, maxE) = allMinMaxL3 DV.! DVS.length v in fromIntegral maxE)
            , rangeMinMaxL3Excess   = rangeMinMaxL3ExcessA
            }

instance MkRangeMinMaxL3 RangeMinMaxSimple where
  mkRangeMinMaxL3 = mkRangeMinMaxL3 . mkRangeMinMaxL2

instance MkRangeMinMaxL3 (DVS.Vector Word64) where
  mkRangeMinMaxL3 = mkRangeMinMaxL3 . mkRangeMinMaxSimple
  {-# INLINE mkRangeMinMaxL3 #-}

instance TestBit RangeMinMaxL3 where
  (.?.) = (.?.) . rangeMinMaxL3Base
  {-# INLINE (.?.) #-}

instance Rank1 RangeMinMaxL3 where
  rank1 = rank1 . rangeMinMaxL3Base
  {-# INLINE rank1 #-}

instance Rank0 RangeMinMaxL3 where
  rank0 = rank0 . rangeMinMaxL3Base
  {-# INLINE rank0 #-}

instance BitLength RangeMinMaxL3 where
  bitLength = bitLength . rangeMinMaxL3Base
  {-# INLINE bitLength #-}

instance RangeMinMaxDerived RangeMinMaxL3 where
  type RangeMinMaxBase RangeMinMaxL3 = RangeMinMaxL2
  rmmBase = rangeMinMaxL3Base
  {-# INLINE rmmBase #-}

instance RangeMinMax RangeMinMaxL3 where
  rmmFindCloseDispatch v s p = if p `mod` rmmBinBits v == 0
    then rmmFindCloseN v s p
    else rmmFindCloseDispatch (rmmBase v) s p
  rmmFindCloseN v s p =
    let i = p `div` rmmBinBits v in
    let minE = fromIntegral (mins !!! fromIntegral i) :: Int in
    if fromIntegral s + minE <= 0
      then  rmmFindCloseN (rmmBase 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 + rmmBinBits v)
    where mins                  = rangeMinMaxL3Min v
          excesses              = rangeMinMaxL3Excess v
  {-# INLINE rmmFindCloseDispatch #-}
  {-# INLINE rmmFindCloseN        #-}

instance OpenAt RangeMinMaxL3 where
  openAt = openAt . rangeMinMaxL3Base
  {-# INLINE openAt #-}

instance CloseAt RangeMinMaxL3 where
  closeAt = closeAt . rangeMinMaxL3Base
  {-# INLINE closeAt #-}

instance NewCloseAt RangeMinMaxL3 where
  newCloseAt = newCloseAt . rangeMinMaxL3Base
  {-# INLINE newCloseAt #-}

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

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