packages feed

hw-balancedparens-0.4.1.1: test/HaskellWorks/Data/BalancedParens/Internal/Broadword/FindClose/Vector8Spec.hs

{-# LANGUAGE TypeApplications #-}

module HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector8Spec
  ( spec
  ) where

import Control.Monad
import Data.Word
import HaskellWorks.Data.Bits.BitLength
import HaskellWorks.Data.Bits.BitShow
import HaskellWorks.Data.Bits.BitWise
import HaskellWorks.Data.Int.Widen
import HaskellWorks.Hspec.Hedgehog
import Hedgehog
import Test.Hspec

import qualified Data.List                                                             as L
import qualified Data.Vector.Storable                                                  as DVS
import qualified HaskellWorks.Data.BalancedParens.FindClose                            as CLS
import qualified HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector8 as V8
import qualified HaskellWorks.Data.BalancedParens.Internal.IO                          as IO
import qualified HaskellWorks.Data.BalancedParens.Internal.Slow.FindCloseN.Generic     as G
import qualified HaskellWorks.Data.BalancedParens.RangeMin2                            as RM2
import qualified HaskellWorks.Data.FromForeignRegion                                   as IO
import qualified Hedgehog.Gen                                                          as G
import qualified Hedgehog.Range                                                        as R
import qualified System.IO.Unsafe                                                      as IO

{- HLINT ignore "Evaluate"            -}
{- HLINT ignore "Redundant do"        -}
{- HLINT ignore "Redundant return"    -}
{- HLINT ignore "Reduce duplication"  -}

testFiles :: [FilePath]
testFiles = IO.unsafePerformIO $ do
  files <- IO.safeListDirectory "data/test"
  return $ L.sort (("data/test/" ++) <$> (".ib.idx" `L.isSuffixOf`) `filter` files)
{-# NOINLINE testFiles #-}

spec :: Spec
spec = describe "HaskellWorks.Data.BalancedParens.Internal.Broadword.FindClose.Vector8Spec" $ do
  describe "findClose" $ do
    it "Two element vector zero as second word" $ require $ withTests 1000 $ property $ do
      w   <- forAll $ G.word8 R.constantBounded
      p   <- forAll $ G.word64 (R.linear 1 8)
      _   <- forAll $ pure $ bitShow w
      v   <- forAll $ pure $ DVS.fromList [w, 0]
      V8.findClose v p === G.findCloseN w 0 p
    it "Two element vector up to position 16" $ require $ withTests 1000 $ property $ do
      w0  <- forAll $ G.word8 R.constantBounded
      w1  <- forAll $ G.word8 R.constantBounded
      w   <- forAll $ pure $ id @Word16 $
                (widen w1 .<. (bitLength w0 * 1)) .|.
                (widen w0 .<. (bitLength w0 * 0))
      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
      _   <- forAll $ pure $ bitShow w
      v   <- forAll $ pure $ DVS.fromList [w0, w1]
      V8.findClose v p === G.findCloseN w 0 p
    it "Four element vector up to position 32" $ require $ withTests 1000 $ property $ do
      w0  <- forAll $ G.word8 R.constantBounded
      w1  <- forAll $ G.word8 R.constantBounded
      w2  <- forAll $ G.word8 R.constantBounded
      w3  <- forAll $ G.word8 R.constantBounded
      w   <- forAll $ pure $ id @Word32 $
                (widen w3 .<. (bitLength w0 * 3)) .|.
                (widen w2 .<. (bitLength w0 * 2)) .|.
                (widen w1 .<. (bitLength w0 * 1)) .|.
                (widen w0 .<. (bitLength w0 * 0))
      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
      _   <- forAll $ pure $ bitShow w
      v   <- forAll $ pure $ DVS.fromList [w0, w1, w2, w3]
      V8.findClose v p === G.findCloseN w 0 p
    it "Eight element vector up to position 64" $ require $ withTests 1000 $ property $ do
      w0  <- forAll $ G.word8 R.constantBounded
      w1  <- forAll $ G.word8 R.constantBounded
      w2  <- forAll $ G.word8 R.constantBounded
      w3  <- forAll $ G.word8 R.constantBounded
      w4  <- forAll $ G.word8 R.constantBounded
      w5  <- forAll $ G.word8 R.constantBounded
      w6  <- forAll $ G.word8 R.constantBounded
      w7  <- forAll $ G.word8 R.constantBounded
      w   <- forAll $ pure $ id @Word64 $
                (widen w7 .<. (bitLength w0 * 7)) .|.
                (widen w6 .<. (bitLength w0 * 6)) .|.
                (widen w5 .<. (bitLength w0 * 5)) .|.
                (widen w4 .<. (bitLength w0 * 4)) .|.
                (widen w3 .<. (bitLength w0 * 3)) .|.
                (widen w2 .<. (bitLength w0 * 2)) .|.
                (widen w1 .<. (bitLength w0 * 1)) .|.
                (widen w0 .<. (bitLength w0 * 0))
      p   <- forAll $ G.word64 (R.linear 1 (bitLength w))
      _   <- forAll $ pure $ bitShow w
      v   <- forAll $ pure $ DVS.fromList [w0, w1, w2, w3, w4, w5, w6, w7]
      V8.findClose v p === G.findCloseN w 0 p
    it "Two element vector" $ require $ withTests 1000 $ property $ do
      w0  <- forAll $ G.word8 R.constantBounded
      w1  <- forAll $ G.word8 R.constantBounded
      p   <- forAll $ G.word64 (R.linear 1 (bitLength w0 * 2))
      v   <- forAll $ pure $ DVS.fromList [w0, w1]
      _   <- forAll $ pure $ bitShow v
      V8.findClose v p === G.findCloseN v 0 p
    describe "Corpus tests" $ do
      forM_ testFiles $ \file -> do
        it ("File " <> file) $ do
          v     <- IO.mmapFromForeignRegion file
          let rmm2 = RM2.mkRangeMin2 (v :: DVS.Vector Word64)
          require $ withTests 100000 $ property $ do
            _   <- forAll $ pure file
            p   <- forAll $ G.word64 (R.linear 1 (bitLength v))
            _   <- forAll $ pure $ bitShow v
            mfilter (<= bitLength v) (CLS.findClose v p) === CLS.findClose rmm2 p