packages feed

ac-library-hs-1.1.0.0: test/Tests/Extra/Graph.hs

module Tests.Extra.Graph where

import AtCoder.Extra.Graph qualified as Gr
import AtCoder.Internal.Buffer qualified as B
import Control.Monad (unless)
import Control.Monad.Fix (fix)
import Control.Monad.ST (runST)
import Data.List qualified as L
import Data.Vector.Generic qualified as VG
import Data.Vector.Unboxed qualified as VU
import Data.Vector.Unboxed.Mutable qualified as VUM
import Test.Tasty
import Test.Tasty.QuickCheck as QC

genDag :: Int -> QC.Gen (Gr.Csr ())
genDag n = do
  edges <- VU.fromList <$> QC.sublistOf [(u, v) | u <- [0 .. n - 1], v <- [u + 1 .. n - 1]]
  verts <- VU.fromList <$> QC.shuffle [0 .. n - 1]
  pure $ Gr.build n $ VU.map (\(!u, !v) -> (verts VG.! u, verts VG.! v, ())) edges

dfs :: Int -> (Int -> VU.Vector Int) -> Int -> VU.Vector Int
dfs n gr u0 = runST $ do
  buf <- B.new n
  vis <- VUM.replicate n False
  flip fix u0 $ \loop u -> do
    VU.forM_ (gr u) $ \v -> do
      b <- VUM.read vis v
      unless b $ do
        B.pushBack buf v
        loop v
  B.unsafeFreeze buf

testTopSort :: Int -> Gr.Csr () -> VU.Vector Int -> Bool
testTopSort n gr vs = and
    [ VU.notElem v (dfs n (gr `Gr.adj`) u)
      | u <- (vs VG.!) <$> [0 .. n - 1],
        v <- (vs VG.!) <$> [u + 1 .. n - 1]
    ]

-- | Tests lexicographically smallest topological ordering.
prop_topSort :: QC.Gen QC.Property
prop_topSort = do
  n <- QC.chooseInt (1, 8)
  dag <- genDag n
  let vs = Gr.topSort n (dag `Gr.adj`)
  let perms = map (VU.fromListN n) $ L.permutations [0 .. n - 1]
  pure $ vs QC.=== head (filter (testTopSort n dag) perms)

tests :: [TestTree]
tests =
  [ QC.testProperty "topSort" prop_topSort
  ]