packages feed

hw-rankselect-0.13.4.0: app/App/Commands/Validate.hs

{-# LANGUAGE BangPatterns        #-}
{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications    #-}

module App.Commands.Validate
  ( cmdValidate
  ) where

import Control.Lens
import Control.Monad
import Control.Monad.State
import Data.Generics.Product.Any
import Data.Word
import HaskellWorks.Data.AtIndex
import HaskellWorks.Data.Bits.PopCount.PopCount1
import HaskellWorks.Data.RankSelect.Base.Rank1
import HaskellWorks.Data.RankSelect.Base.Select1
import Options.Applicative

import qualified App.Commands.Options.Type            as Z
import qualified Data.Vector.Storable                 as DVS
import qualified HaskellWorks.Data.FromForeignRegion  as IO
import qualified HaskellWorks.Data.RankSelect.CsPoppy as CS
import qualified System.IO                            as IO

{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}
{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
{-# ANN module ("HLint: ignore Redundant return"    :: String) #-}

runValidate :: Z.ValidateOptions -> IO ()
runValidate opts = case opts ^. the @"indexType" of
  Z.CsPoppy  -> do
    !(v :: DVS.Vector Word64) <- IO.mmapFromForeignRegion (opts ^. the @"file")

    let !csIndex = CS.makeCsPoppy v

    (_, final) <- flip runStateT Z.emptyValidateState $
      forM_ [0 .. fromIntegral (DVS.length v - 1)] $ \i -> do
        let w = v !!! i
        let wPopCount = popCount1 w
        lastPopCount <- use (the @"cumulativePopCount")

        forM_ [0 .. 64] $ \pw -> do
          let r = rank1 w pw + lastPopCount
          let p = fromIntegral (i * 64) + pw
          let actualR = rank1 csIndex p
          when (actualR /= r) $ do
            liftIO $ IO.putStrLn $ "Corrupt bit-index.  Expected: rank1 " <> show p <> " == " <> show r <> ", but: rank1 " <> show p <> " == " <> show actualR

        forM_ [0 .. 63] $ \pw -> do
          let r0 = rank1 w  pw      + lastPopCount
          let r1 = rank1 w (pw + 1) + lastPopCount
          let p = fromIntegral (i * 64) + pw
          when (r0 == r1) $ do
            let actualP = select1 csIndex r0
            when (actualP > p) $ do
              liftIO $ IO.putStrLn $ "Corrupt bit-index.  Expected: select1 " <> show r0 <> " <= " <> show p <> ", but: select1 " <> show r0 <> " == " <> show actualP

        forM_ [lastPopCount + 1 .. lastPopCount + wPopCount] $ \r -> do
          let p = select1 csIndex r
          when (rank1 csIndex p /= r) $ do
            liftIO $ IO.putStrLn $ "Corrupt bit-index at (p, r) = (" <> show p <> ", " <> show r <> ")"
            return ()
          return ()

        the @"cumulativePopCount" += wPopCount

        return ()

    IO.putStrLn $ "PopCounts validated: " <> show (final ^. the @"cumulativePopCount")

    return ()
  Z.Poppy512 -> do
    putStrLn "Not implemented"
    return ()

optsValidate :: Parser Z.ValidateOptions
optsValidate = Z.ValidateOptions
  <$> option auto
      (   long "index-type"
      <>  help "Index type"
      <>  metavar "INDEX_TYPE"
      )
  <*> strOption
      (   long "file"
      <>  help "Input file"
      <>  metavar "FILE"
      )

cmdValidate :: Mod CommandFields (IO ())
cmdValidate = command "validate"  $ flip info idm $ runValidate <$> optsValidate