packages feed

bitvec-1.0.0.1: test/Tests/SetOps.hs

module Tests.SetOps where

import Support ()

import Data.Bit
import Data.Bits
import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.Vector.Unboxed as U
import Test.Tasty
import Test.Tasty.QuickCheck hiding ((.&.))

setOpTests :: TestTree
setOpTests = testGroup
  "Set operations"
  [ testProperty "union"         prop_union_def
  , testProperty "intersection"  prop_intersection_def
  , testProperty "difference"    prop_difference_def
  , testProperty "symDiff"       prop_symDiff_def
  -- , testProperty "unions"        prop_unions_def
  -- , testProperty "intersections" prop_unions_def
  , testProperty "invert"        prop_invert_def
  , testProperty "select"        prop_select_def
  , testProperty "exclude"       prop_exclude_def
  , testProperty "selectBits"    prop_selectBits_def
  , testProperty "excludeBits"   prop_excludeBits_def
  , testProperty "countBits"     prop_countBits_def
  ]

union :: U.Vector Bit -> U.Vector Bit -> U.Vector Bit
union = zipBits (.|.)

prop_union_def :: U.Vector Bit -> U.Vector Bit -> Property
prop_union_def xs ys =
  U.toList (union xs ys) === zipWith (.|.) (U.toList xs) (U.toList ys)

intersection :: U.Vector Bit -> U.Vector Bit -> U.Vector Bit
intersection = zipBits (.&.)

prop_intersection_def :: U.Vector Bit -> U.Vector Bit -> Property
prop_intersection_def xs ys =
  U.toList (intersection xs ys) === zipWith (.&.) (U.toList xs) (U.toList ys)

difference :: U.Vector Bit -> U.Vector Bit -> U.Vector Bit
difference = zipBits (\a b -> a .&. complement b)

prop_difference_def :: U.Vector Bit -> U.Vector Bit -> Property
prop_difference_def xs ys = U.toList (difference xs ys)
  === zipWith diff (U.toList xs) (U.toList ys)
  where diff x y = x .&. complement y

symDiff :: U.Vector Bit -> U.Vector Bit -> U.Vector Bit
symDiff = zipBits xor

prop_symDiff_def :: U.Vector Bit -> U.Vector Bit -> Property
prop_symDiff_def xs ys =
  U.toList (symDiff xs ys) === zipWith xor (U.toList xs) (U.toList ys)

unions :: NonEmpty (U.Vector Bit) -> U.Vector Bit
unions (x :| xs) = U.slice 0 l $ U.modify (go xs) x
 where
  l = minimum $ fmap U.length (x :| xs)
  go []       _   = pure ()
  go (y : ys) acc = do
    zipInPlace (.|.) y acc
    go ys acc

prop_unions_def :: U.Vector Bit -> [U.Vector Bit] -> Property
prop_unions_def xs xss = unions (xs :| xss) === foldr union xs xss

intersections :: NonEmpty (U.Vector Bit) -> U.Vector Bit
intersections (x :| xs) = U.slice 0 l $ U.modify (go xs) x
 where
  l = minimum $ fmap U.length (x :| xs)
  go []       _   = pure ()
  go (y : ys) acc = do
    zipInPlace (.&.) y acc
    go ys acc

prop_intersections_def :: U.Vector Bit -> [U.Vector Bit] -> Property
prop_intersections_def xs xss =
  intersections (xs :| xss) === foldr intersection xs xss

prop_invert_def :: U.Vector Bit -> Bool
prop_invert_def xs =
  U.toList (U.modify invertInPlace xs) == map complement (U.toList xs)

select :: U.Unbox a => U.Vector Bit -> U.Vector a -> [a]
select mask ws = U.toList (U.map snd (U.filter (unBit . fst) (U.zip mask ws)))

prop_select_def :: U.Vector Bit -> U.Vector Word -> Bool
prop_select_def xs ys =
  select xs ys == [ x | (Bit True, x) <- zip (U.toList xs) (U.toList ys) ]

exclude :: U.Unbox a => U.Vector Bit -> U.Vector a -> [a]
exclude mask ws =
  U.toList (U.map snd (U.filter (not . unBit . fst) (U.zip mask ws)))

prop_exclude_def :: U.Vector Bit -> U.Vector Word -> Bool
prop_exclude_def xs ys =
  exclude xs ys == [ x | (Bit False, x) <- zip (U.toList xs) (U.toList ys) ]

prop_selectBits_def :: U.Vector Bit -> U.Vector Bit -> Bool
prop_selectBits_def xs ys = selectBits xs ys == U.fromList (select xs ys)

prop_excludeBits_def :: U.Vector Bit -> U.Vector Bit -> Bool
prop_excludeBits_def xs ys = excludeBits xs ys == U.fromList (exclude xs ys)

prop_countBits_def :: U.Vector Bit -> Bool
prop_countBits_def xs = countBits xs == U.length (selectBits xs xs)