module HaskellWorks.Data.RankSelect.CsPoppy
( CsPoppy(..)
, Nice(..)
, Rank1(..)
, makeCsPoppy
) where
import Control.DeepSeq
import Data.Monoid ((<>))
import Data.Word
import GHC.Generics
import HaskellWorks.Data.AtIndex
import HaskellWorks.Data.BalancedParens.BalancedParens
import HaskellWorks.Data.BalancedParens.CloseAt
import HaskellWorks.Data.BalancedParens.Enclose
import HaskellWorks.Data.BalancedParens.FindClose
import HaskellWorks.Data.BalancedParens.FindCloseN
import HaskellWorks.Data.BalancedParens.FindOpen
import HaskellWorks.Data.BalancedParens.FindOpenN
import HaskellWorks.Data.BalancedParens.NewCloseAt
import HaskellWorks.Data.BalancedParens.OpenAt
import HaskellWorks.Data.Bits.BitLength
import HaskellWorks.Data.Bits.BitRead
import HaskellWorks.Data.Bits.BitShow
import HaskellWorks.Data.Bits.BitWise
import HaskellWorks.Data.Bits.PopCount.PopCount1
import HaskellWorks.Data.Drop
import HaskellWorks.Data.Positioning
import HaskellWorks.Data.RankSelect.Base.Rank0
import HaskellWorks.Data.RankSelect.Base.Rank1
import HaskellWorks.Data.RankSelect.Base.Select1
import HaskellWorks.Data.RankSelect.CsPoppy.Internal
import HaskellWorks.Data.Take
import HaskellWorks.Data.Vector.AsVector64
import Prelude hiding (drop, length, pi, take)
import qualified Data.Vector.Storable as DVS
newtype Nice a = Nice a deriving Eq
data CsPoppy = CsPoppy
{ csPoppyBits :: !(DVS.Vector Word64)
, csPoppyLayerM :: !(DVS.Vector Word64)
, csPoppyLayerS :: !(DVS.Vector Word32)
} deriving (Eq, Show, NFData, Generic)
instance Show (Nice CsPoppy) where
showsPrec _ (Nice rsbs) = showString "CsPoppy "
<> showString "{ csPoppyBits = " <> shows (bitShow <$> DVS.toList (csPoppyBits rsbs))
<> showString ", csPoppyLayer0 = " <> shows (CsInterleaved <$> DVS.toList (csPoppyLayerM rsbs))
<> showString ", csPoppyLayerS = " <> shows (csPoppyLayerS rsbs)
<> showString " }"
instance AsVector64 CsPoppy where
asVector64 = asVector64 . csPoppyBits
instance BitLength CsPoppy where
bitLength = bitLength . csPoppyBits
instance PopCount1 CsPoppy where
popCount1 v = getCsiTotal (CsInterleaved (lastOrZero (csPoppyLayerM v)))
indexOrZero :: DVS.Vector Word64 -> Position -> Word64
indexOrZero _ i | i < 0 = 0
indexOrZero v i | i < end v = v !!! i
indexOrZero _ _ = 0
lastOrZero :: DVS.Vector Word64 -> Word64
lastOrZero v | 0 < end v = DVS.last v
lastOrZero _ = 0
makeCsPoppy :: DVS.Vector Word64 -> CsPoppy
makeCsPoppy v = CsPoppy
{ csPoppyBits = v
, csPoppyLayerM = layerM
, csPoppyLayerS = layerS
}
where blocks = DVS.constructN (((DVS.length v + 8 1) `div` 8) + 1) genBlocks
layerM = DVS.constructN (((DVS.length blocks + 4 1) `div` 4) + 1) genLayer1
layerMPopCount = getCsiTotal (CsInterleaved (lastOrZero layerM))
layerS = DVS.unfoldrN (fromIntegral layerMPopCount) genSample (0, 1)
genBlocks u = let i = length u in popCount1 (take 8 (drop (i * 8) v))
genLayer1 :: DVS.Vector Word64 -> Word64
genLayer1 u =
let i = end u in
let lx = lastOrZero u in
let la = indexOrZero blocks (i * 4 4) in
let lb = indexOrZero blocks (i * 4 3) in
let lc = indexOrZero blocks (i * 4 2) in
let ld = indexOrZero blocks (i * 4 1) in
let nx = lx + (la + lb + lc + ld) in
let na = indexOrZero blocks (i * 4 + 0) in
let nb = indexOrZero blocks (i * 4 + 1) in
let nc = indexOrZero blocks (i * 4 + 2) in
( ( nx .&. 0x00000000ffffffff)
.|. ((na .<. 32) .&. 0x000003ff00000000)
.|. ((nb .<. 42) .&. 0x000ffc0000000000)
.|. ((nc .<. 52) .&. 0x3ff0000000000000))
mLookup :: Position -> Word64
mLookup i = getCsiX (CsInterleaved (layerM !!! i))
genSample :: (Position, Position) -> Maybe (Word32, (Position, Position))
genSample (mi, _) | mi == maxBound = Nothing
genSample (mi, _) | mi >= end layerM = Just (fromIntegral (DVS.length layerM 1), (maxBound, maxBound))
genSample (mi, s) | s < toPosition (getCsiTotal (CsInterleaved (mLookup mi))) = Just (fromIntegral mi 1, (mi, s + 512 ))
genSample (mi, s) = genSample (fromIntegral mi + 1, s)
instance TestBit CsPoppy where
(.?.) = (.?.) . csPoppyBits
instance BitRead CsPoppy where
bitRead = fmap makeCsPoppy . bitRead
instance Rank1 CsPoppy where
rank1 (CsPoppy !v !layerM !_) p = rankPrior + rankInBasicBlock
where mw = layerM !!! toPosition (p `div` 2048)
mx = mw .&. 0x00000000ffffffff
ma = (mw .&. 0x000003ff00000000) .>. 32
mb = (mw .&. 0x000ffc0000000000) .>. 42
mc = (mw .&. 0x3ff0000000000000) .>. 52
q = (p `div` 512) `mod` 4
mi | q == 0 = mx
| q == 1 = mx + ma
| q == 2 = mx + ma + mb
| q == 3 = mx + ma + mb + mc
| otherwise = error "Invalid interleaved entry index"
rankPrior = mi :: Count
rankInBasicBlock = rank1 (DVS.drop (fromIntegral (p `div` 512) * 8) v) (p `mod` 512)
mBinarySearch :: Word64 -> DVS.Vector Word64 -> Position -> Position -> Position
mBinarySearch !w !m !p !q = if p + 1 >= q
then p
else let !o = (p + q) `div` 2 in
if w <= getCsiX (CsInterleaved (m !!! o))
then mBinarySearch w m p o
else mBinarySearch w m o q
instance Select1 CsPoppy where
select1 _ p | p == 0 = 0
select1 (CsPoppy !v !layerM !layerS) p =
let !pi = toPosition $ (p 1) `div` 512 in
let !pj = (pi + 1) `min` (end layerS 1) in
let !si = fromIntegral (layerS !!! pi) in
let !sj = fromIntegral $ (layerS !!! pj) + 1 in
let !mIndex = mBinarySearch (fromIntegral p) layerM si sj in
let !me = CsInterleaved (layerM !!! fromIntegral mIndex) in
let !mx = getCsiX me in
let !ma = getCsiA me + mx in
let !mb = getCsiB me + ma in
let !mc = getCsiC me + mb in
let !bo | p <= ma = 0
| p <= mb = 1
| p <= mc = 2
| otherwise = 3 in
let !bp | p <= ma = mx
| p <= mb = ma
| p <= mc = mb
| otherwise = mc in
let !blockStart = toCount (mIndex * 4 + bo) * 8 in
let !block = DVS.take 8 (drop blockStart v) in
let !q = p bp in
select1 block q + blockStart * 64
instance OpenAt CsPoppy where
openAt = openAt . csPoppyBits
instance CloseAt CsPoppy where
closeAt = closeAt . csPoppyBits
instance NewCloseAt CsPoppy where
newCloseAt = newCloseAt . csPoppyBits
instance FindOpenN CsPoppy where
findOpenN = findOpenN . csPoppyBits
instance FindOpen CsPoppy where
findOpen = findOpen . csPoppyBits
instance FindClose CsPoppy where
findClose = findClose . csPoppyBits
instance FindCloseN CsPoppy where
findCloseN = findCloseN . csPoppyBits
instance Enclose CsPoppy where
enclose = enclose . csPoppyBits
instance Rank0 CsPoppy where
rank0 rsbs p = p rank0 rsbs p
instance BalancedParens CsPoppy where
firstChild = firstChild . csPoppyBits
nextSibling = nextSibling . csPoppyBits
parent = parent . csPoppyBits