-- | Max flow tests. module Tests.MaxFlow (tests) where import AtCoder.MaxFlow qualified as MF import Data.Bit (Bit(..)) import Data.Vector.Unboxed qualified as VU import System.IO.Unsafe (unsafePerformIO) import Test.Hspec import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.Hspec unit_zero :: TestTree unit_zero = testCase "zero" $ do _ <- MF.new @_ @Int 0 _ <- MF.new @_ @Double 0 pure () -- Assign is skipped unit_simple :: TestTree unit_simple = testCase "simple" $ do g <- MF.new 4 (@?= 0) =<< MF.addEdge g 0 1 (1 :: Int) (@?= 1) =<< MF.addEdge g 0 2 1 (@?= 2) =<< MF.addEdge g 1 3 1 (@?= 3) =<< MF.addEdge g 2 3 1 (@?= 4) =<< MF.addEdge g 1 2 1 -- TODO: combine the builder and the graph (@?= 2) =<< MF.flow g 0 3 maxBound (@?= (0, 1, 1, 1)) =<< MF.getEdge g 0 (@?= (0, 2, 1, 1)) =<< MF.getEdge g 1 (@?= (1, 3, 1, 1)) =<< MF.getEdge g 2 (@?= (2, 3, 1, 1)) =<< MF.getEdge g 3 (@?= (1, 2, 1, 0)) =<< MF.getEdge g 4 (@?= VU.map Bit (VU.fromList [True, False, False, False])) =<< MF.minCut g 0 unit_notSimple :: TestTree unit_notSimple = testCase "notSimple" $ do g <- MF.new 2 (@?= 0) =<< MF.addEdge g 0 1 (1 :: Int) (@?= 1) =<< MF.addEdge g 0 1 2 (@?= 2) =<< MF.addEdge g 0 1 3 (@?= 3) =<< MF.addEdge g 0 1 4 (@?= 4) =<< MF.addEdge g 0 1 5 (@?= 5) =<< MF.addEdge g 0 0 6 (@?= 6) =<< MF.addEdge g 1 1 7 (@?= 15) =<< MF.flow g 0 1 maxBound (@?= (0, 1, 1, 1)) =<< MF.getEdge g 0 (@?= (0, 1, 2, 2)) =<< MF.getEdge g 1 (@?= (0, 1, 3, 3)) =<< MF.getEdge g 2 (@?= (0, 1, 4, 4)) =<< MF.getEdge g 3 (@?= (0, 1, 5, 5)) =<< MF.getEdge g 4 (@?= VU.map Bit (VU.fromList [True, False])) =<< MF.minCut g 0 unit_minCut :: TestTree unit_minCut = testCase "minCut" $ do g <- MF.new 3 (@?= 0) =<< MF.addEdge g 0 1 (2 :: Int) (@?= 1) =<< MF.addEdge g 1 2 1 (@?= 1) =<< MF.flow g 0 2 maxBound (@?= (0, 1, 2, 1)) =<< MF.getEdge g 0 (@?= (1, 2, 1, 1)) =<< MF.getEdge g 1 (@?= VU.map Bit (VU.fromList [True, True, False])) =<< MF.minCut g 0 unit_twice :: TestTree unit_twice = testCase "twice" $ do g <- MF.new 3 (@?= 0) =<< MF.addEdge g 0 1 (1 :: Int) (@?= 1) =<< MF.addEdge g 0 2 1 (@?= 2) =<< MF.addEdge g 1 2 1 (@?= 2) =<< MF.flow g 0 2 maxBound (@?= (0, 1, 1, 1)) =<< MF.getEdge g 0 (@?= (0, 2, 1, 1)) =<< MF.getEdge g 1 (@?= (1, 2, 1, 1)) =<< MF.getEdge g 2 MF.changeEdge g 0 100 10 (@?= (0, 1, 100, 10)) =<< MF.getEdge g 0 (@?= 0) =<< MF.flow g 0 2 maxBound (@?= 90) =<< MF.flow g 0 1 maxBound (@?= (0, 1, 100, 100)) =<< MF.getEdge g 0 (@?= (0, 2, 1, 1)) =<< MF.getEdge g 1 (@?= (1, 2, 1, 1)) =<< MF.getEdge g 2 (@?= 2) =<< MF.flow g 2 0 maxBound (@?= (0, 1, 100, 99)) =<< MF.getEdge g 0 (@?= (0, 2, 1, 0)) =<< MF.getEdge g 1 (@?= (1, 2, 1, 0)) =<< MF.getEdge g 2 unit_maxFlowBound :: TestTree unit_maxFlowBound = testCase "maxFlowBound" $ do g <- MF.new 3 (@?= 0) =<< MF.addEdge g 0 1 (maxBound :: Int) (@?= 1) =<< MF.addEdge g 1 0 maxBound (@?= 2) =<< MF.addEdge g 0 2 maxBound (@?= maxBound) =<< MF.flow g 0 2 maxBound (@?= (0, 1, maxBound, 0)) =<< MF.getEdge g 0 (@?= (1, 0, maxBound, 0)) =<< MF.getEdge g 1 (@?= (0, 2, maxBound, maxBound)) =<< MF.getEdge g 2 -- BoundUInt is skipped unit_selfLoop :: TestTree unit_selfLoop = testCase "selfLoop" $ do g <- MF.new 3 (@?= 0) =<< MF.addEdge g 0 0 (100 :: Int) (@?= (0, 0, 100, 0)) =<< MF.getEdge g 0 spec_invalidFlow :: IO TestTree spec_invalidFlow = testSpec "invalidFlow" $ do g <- runIO $ MF.new @_ @Int 2 it "throws error" $ do MF.flow g 0 0 0 `shouldThrow` anyException -- TODO: stress test tests :: [TestTree] tests = [ unit_zero, -- assign, unit_simple, unit_notSimple, unit_minCut, unit_twice, unit_maxFlowBound, -- maxFlowBoundUInt unit_selfLoop, unsafePerformIO spec_invalidFlow -- stress ]