packages feed

multisets-0.1.0.0: test/Test/Transformations.hs

{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}

module Test.Transformations (
    tests,
) where

import Control.Monad ((>=>))
import Data.Coerce
import qualified Data.MultiSet.Natural as MS
import Numeric.Natural
import Test.Gen
import Test.Tasty
import Test.Tasty.QuickCheck

tests :: TestTree
tests =
    testGroup
        "transformations"
        [ testProperty "filter/true" prop_filterTrue
        , testProperty "filter/false" prop_filterFalse
        , testProperty "filter/composition" prop_filterComposition
        , testProperty "filterWithMultiplicity/bridge" prop_filterWithMultiplicityBridge
        , testProperty "filterWithMultiplicity/composition" prop_filterWithMultiplicityComposition
        , testProperty "partition/reconstruct" prop_partitionReconstruct
        , testProperty "partition/filter" prop_partitionFilter
        , testProperty "partitionWithMultiplicity/reconstruct" prop_partitionWithMultiplicityReconstruct
        , testProperty "partitionWithMultiplicity/filter" prop_partitionWithMultiplicityFilter
        , testProperty "partitionWithMultiplicity/bridge" prop_partitionWithMultiplicityBridge
        , testProperty "map/identity" prop_mapIdentity
        , testProperty "map/composition" prop_mapComposition
        , testProperty "map/union" prop_mapUnion
        , testProperty "mapWithMultiplicity/identity" prop_mapWithMultiplicityIdentity
        , testProperty "mapWithMultiplicity/decompose" prop_mapWithMultiplicityDecompose
        , testProperty "mapMultiplicities/identity" prop_mapMultiplicitiesIdentity
        , testProperty "mapMultiplicities/zero" prop_mapMultiplicitiesZero
        , testProperty "mapMultiplicities/composition" prop_mapMultiplicitiesComposition
        , testProperty "mapMaybe/identity" prop_mapMaybeIdentity
        , testProperty "mapMaybe/nothing" prop_mapMaybeNothing
        , testProperty "mapMaybe/composition" prop_mapMaybeComposition
        , testProperty "mapMaybe/map" prop_mapMaybeMap
        , testProperty "mapMaybeWithMultiplicity/identity" prop_mapMaybeWithMultiplicityIdentity
        , testProperty "mapMaybeWithMultiplicity/nothing" prop_mapMaybeWithMultiplicityNothing
        , testProperty "mapMaybeWithMultiplicity/mapMaybe" prop_mapMaybeWithMultiplicityMapMaybe
        , testProperty
            "mapMaybeWithMultiplicity/mapWithMultiplicity"
            prop_mapMaybeWithMultiplicityMapWithMultiplicity
        , testProperty "concatMap/left identity" prop_concatMapLeftIdentity
        , testProperty "concatMap/right identity" prop_concatMapRightIdentity
        , testProperty "concatMap/associativity" prop_concatMapAssociativity
        , testProperty "concatMap/map" prop_concatMapMap
        , testProperty "concatMap/scaling" prop_concatMapScaling
        ]

prop_filterTrue :: AMS -> Property
prop_filterTrue (AMS xs) = MS.filter (const True) xs === xs

prop_filterFalse :: AMS -> Property
prop_filterFalse (AMS xs) = MS.filter (const False) xs === MS.empty

prop_filterComposition :: Fun Int Bool -> Fun Int Bool -> AMS -> Property
prop_filterComposition pFun qFun (AMS xs) =
    MS.filter p (MS.filter q xs) === MS.filter (\x -> p x && q x) xs
  where
    p = applyFun pFun
    q = applyFun qFun

prop_filterWithMultiplicityBridge :: Fun Int Bool -> AMS -> Property
prop_filterWithMultiplicityBridge fun (AMS xs) =
    MS.filterWithMultiplicity (\x _ -> f x) xs === MS.filter f xs
  where
    f = applyFun fun

prop_filterWithMultiplicityComposition ::
    Fun (Int, Natural') Bool -> Fun (Int, Natural') Bool -> AMS -> Property
prop_filterWithMultiplicityComposition pFun qFun (AMS xs) =
    MS.filterWithMultiplicity p (MS.filterWithMultiplicity q xs)
        === MS.filterWithMultiplicity (\x n -> p x n && q x n) xs
  where
    p = curry . coerce $ applyFun pFun
    q = curry . coerce $ applyFun qFun

prop_partitionReconstruct :: Fun Int Bool -> AMS -> Property
prop_partitionReconstruct fun (AMS xs) =
    conjoin
        [ MS.union yes no === xs
        , property $ MS.disjoint yes no
        ]
  where
    (yes, no) = MS.partition (applyFun fun) xs

prop_partitionFilter :: Fun Int Bool -> AMS -> Property
prop_partitionFilter fun (AMS xs) =
    MS.partition p xs === (MS.filter p xs, MS.filter (not . p) xs)
  where
    p = applyFun fun

prop_partitionWithMultiplicityReconstruct :: Fun (Int, Natural') Bool -> AMS -> Property
prop_partitionWithMultiplicityReconstruct fun (AMS xs) =
    conjoin
        [ MS.union yes no === xs
        , property $ MS.disjoint yes no
        ]
  where
    (yes, no) = MS.partitionWithMultiplicity (curry . coerce $ applyFun fun) xs

prop_partitionWithMultiplicityFilter :: Fun (Int, Natural') Bool -> AMS -> Property
prop_partitionWithMultiplicityFilter fun (AMS xs) =
    MS.partitionWithMultiplicity p xs
        === (MS.filterWithMultiplicity p xs, MS.filterWithMultiplicity (\x n -> not $ p x n) xs)
  where
    p = curry . coerce $ applyFun fun

prop_partitionWithMultiplicityBridge :: Fun Int Bool -> AMS -> Property
prop_partitionWithMultiplicityBridge fun (AMS xs) =
    MS.partitionWithMultiplicity (\x _ -> p x) xs === MS.partition p xs
  where
    p = applyFun fun

prop_mapIdentity :: AMS -> Property
prop_mapIdentity (AMS xs) = MS.map id xs === xs

prop_mapComposition :: Fun Int Int -> Fun Int Int -> AMS -> Property
prop_mapComposition fFun gFun (AMS xs) =
    MS.map f (MS.map g xs) === MS.map (f . g) xs
  where
    f = applyFun fFun
    g = applyFun gFun

prop_mapUnion :: Fun Int Int -> AMS -> AMS -> Property
prop_mapUnion (Fun _ f) (AMS xs) (AMS ys) =
    MS.map f (MS.union xs ys) === MS.union (MS.map f xs) (MS.map f ys)

prop_mapWithMultiplicityIdentity :: AMS -> Property
prop_mapWithMultiplicityIdentity (AMS xs) = MS.mapWithMultiplicity (,) xs === xs

prop_mapWithMultiplicityDecompose :: Fun Int Int -> Fun Natural' Natural' -> AMS -> Property
prop_mapWithMultiplicityDecompose fFun gFun (AMS xs) =
    MS.mapWithMultiplicity (\x n -> (f x, g n)) xs === MS.map f (MS.mapMultiplicities g xs)
  where
    f = applyFun fFun
    g = coerce $ applyFun gFun

prop_mapMultiplicitiesIdentity :: AMS -> Property
prop_mapMultiplicitiesIdentity (AMS xs) = MS.mapMultiplicities id xs === xs

prop_mapMultiplicitiesZero :: AMS -> Property
prop_mapMultiplicitiesZero (AMS xs) = MS.mapMultiplicities (const 0) xs === MS.empty

prop_mapMultiplicitiesComposition ::
    Fun Natural' Natural' -> Fun Natural' Natural' -> AMS -> Property
prop_mapMultiplicitiesComposition fFun gFun (AMS xs) =
    MS.mapMultiplicities f (MS.mapMultiplicities g xs) === MS.mapMultiplicities (f . g) xs
  where
    f = zeroPreserving fFun
    g = zeroPreserving gFun

    zeroPreserving _ 0 = 0
    zeroPreserving fun n = coerce (applyFun fun) n

prop_mapMaybeIdentity :: AMS -> Property
prop_mapMaybeIdentity (AMS xs) = MS.mapMaybe Just xs === xs

prop_mapMaybeNothing :: AMS -> Property
prop_mapMaybeNothing (AMS xs) = MS.mapMaybe @Int (const Nothing) xs === MS.empty

prop_mapMaybeComposition :: Fun Int (Maybe Int) -> Fun Int (Maybe Int) -> AMS -> Property
prop_mapMaybeComposition fFun gFun (AMS xs) =
    MS.mapMaybe f (MS.mapMaybe g xs) === MS.mapMaybe (g >=> f) xs
  where
    f = applyFun fFun
    g = applyFun gFun

prop_mapMaybeMap :: Fun Int Int -> AMS -> Property
prop_mapMaybeMap fun (AMS xs) = MS.mapMaybe (Just . f) xs === MS.map f xs
  where
    f = applyFun fun

prop_mapMaybeWithMultiplicityIdentity :: AMS -> Property
prop_mapMaybeWithMultiplicityIdentity (AMS xs) =
    MS.mapMaybeWithMultiplicity (curry Just) xs === xs

prop_mapMaybeWithMultiplicityNothing :: AMS -> Property
prop_mapMaybeWithMultiplicityNothing (AMS xs) =
    MS.mapMaybeWithMultiplicity @Int (\_ _ -> Nothing) xs === MS.empty

prop_mapMaybeWithMultiplicityMapMaybe :: Fun Int (Maybe Int) -> AMS -> Property
prop_mapMaybeWithMultiplicityMapMaybe fun (AMS xs) =
    MS.mapMaybeWithMultiplicity (\x n -> (,n) <$> f x) xs === MS.mapMaybe f xs
  where
    f = applyFun fun

prop_mapMaybeWithMultiplicityMapWithMultiplicity ::
    Fun (Int, Natural') (Int, Natural') -> AMS -> Property
prop_mapMaybeWithMultiplicityMapWithMultiplicity fun (AMS xs) =
    MS.mapMaybeWithMultiplicity (\x n -> Just $ f x n) xs === MS.mapWithMultiplicity f xs
  where
    f :: Int -> Natural -> (Int, Natural)
    f = curry . coerce $ applyFun fun

prop_concatMapLeftIdentity :: Int -> Fun Int AMS -> Property
prop_concatMapLeftIdentity x fun = MS.concatMap f (MS.singleton x) === f x
  where
    f = getAMS . applyFun fun

prop_concatMapRightIdentity :: AMS -> Property
prop_concatMapRightIdentity (AMS xs) = MS.concatMap MS.singleton xs === xs

prop_concatMapAssociativity :: Fun Int AMS -> Fun Int AMS -> AMS -> Property
prop_concatMapAssociativity fFun gFun (AMS xs) =
    MS.concatMap f (MS.concatMap g xs) === MS.concatMap (MS.concatMap f . g) xs
  where
    f = getAMS . applyFun fFun
    g = getAMS . applyFun gFun

prop_concatMapMap :: Fun Int Int -> AMS -> Property
prop_concatMapMap fun (AMS xs) = MS.concatMap (MS.singleton . f) xs === MS.map f xs
  where
    f = applyFun fun

prop_concatMapScaling :: Fun Int AMS -> Int -> LNat -> Property
prop_concatMapScaling (Fun _ f) x (LNat n) =
    MS.concatMap (getAMS . f) (MS.singletonMany x n) === MS.mapMultiplicities (* n) (getAMS $ f x)