math-grads-0.1.6.2: test/SSSR.hs
{-# LANGUAGE ViewPatterns #-}
module Main where
import Data.List (group, nub, sort)
import Data.Map (Map)
import qualified Data.Map as M
import Test.Hspec (Expectation, Spec, describe, hspec,
it, shouldBe, shouldMatchList,
shouldSatisfy)
import Math.Grads.Algo.SSSR (findSSSR)
import Math.Grads.GenericGraph (GenericGraph)
import Math.Grads.Graph (GraphEdge, fromList)
main :: IO ()
main = hspec $ describe "SSSR" $ do
graphSpec "graphA" graphA resultA
graphSpec "graphB" graphB resultB
graphSpec "graphC" graphC resultC
graphSpec "graphD" graphD resultD
graphSpec :: String -> GenericGraph Int Int -> Map Int Int -> Spec
graphSpec name (sort . fmap sort . findSSSR -> sssr) cycleMap = it name $ do
sssr `shouldMatchList` nub sssr
mapM_ checkSimpleCycle sssr
sssr `shouldSatisfy` (==) (sum . M.elems $ cycleMap) . length
mapM_ (\(len, count) -> numCyclesOfLen len `shouldBe` count) $ M.toList cycleMap
where
checkSimpleCycle :: [GraphEdge Int] -> Expectation
checkSimpleCycle = mapM_ (`shouldSatisfy` (==) 2 . length) . group . sort . concatMap (\(x, y, _) -> [x, y])
numCyclesOfLen :: Int -> Int
numCyclesOfLen n = length . filter ((==) n . length) $ sssr
-- | This 4 graphs comes from figure 5 page 5 of the original paper.
-- <https://www.ncbi.nlm.nih.gov/pubmed/19805142>
--
-- | Note that this graph image wrong in the paper - it has 3 cycles of length 4.
-- We fix it with 3 additional edges to match with results from table 4 page 5 of the paper.
--
graphA :: GenericGraph Int Int
graphA = fromList (
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],
[(0,1,1),(0,5,1),(0,10,1),(0,13,1),(0,20,1),(1,2,1),(1,3,1),(1,4,1),(1,5,1),(1,20,1),(2,3,1),
(2,8,1),(2,10,1),(2,20,1),(3,4,1),(3,8,1),(3,14,1),(3,15,1),(4,5,1),(4,15,1),(4,16,1),(4,19,1),
(5,6,1),(5,13,1),(5,19,1),(6,7,1),(6,12,1),(6,13,1),(6,18,1),(6,19,1),(7,8,1),(7,9,1),(7,11,1),
(7,12,1),(7,14,1),(7,17,1),(7,18,1),(8,9,1),(8,10,1),(8,14,1),(9,10,1),(9,11,1),(10,11,1),
(10,12,1),(10,13,1),(11,12,1),(12,13,1),(14,15,1),(14,17,1),(15,16,1),(15,17,1),(16,17,1),
(16,18,1),(16,19,1),(17,18,1),(18,19,1)])
resultA :: Map Int Int
resultA = M.fromList [(3, 36)]
graphB :: GenericGraph Int Int
graphB = fromList (
[0,1,2,3,4,5,6,7,8,9,10,11,12],
[(0,1,1),(0,10,1),(1,2,1),(1,8,1),(1,12,1),(2,3,1),(2,7,1),(3,4,1),(3,12,1),(4,5,1),(4,11,1),
(5,6,1),(5,10,1),(6,7,1),(6,9,1),(7,8,1),(8,9,1),(9,10,1),(10,11,1),(11,12,1)])
resultB :: Map Int Int
resultB = M.fromList [(4, 6), (5, 2)]
graphC :: GenericGraph Int Int
graphC = fromList (
[0,1,2,3,4,5,6,7,8,9,10,11,12],
[(0,1,1),(0,12,1),(1,2,1),(1,8,1),(1,9,1),(1,10,1),(2,3,1),(2,4,1),(2,9,1),(3,4,1),(3,5,1),
(3,9,1),(4,5,1),(4,12,1),(5,6,1),(5,12,1),(6,7,1),(6,11,1),(6,12,1),(7,8,1),(7,10,1),(7,11,1),
(8,9,1),(8,10,1),(10,11,1),(11,12,1)])
resultC :: Map Int Int
resultC = M.fromList [(3, 12), (5, 2)]
graphD :: GenericGraph Int Int
graphD = fromList (
[0,1,2,3,4,5,6,7,8,9],
[(0,1,1),(0,3,1),(1,2,1),(1,9,1),(2,3,1),(2,9,1),(3,4,1),(3,5,1),(4,5,1),(4,6,1),(5,6,1),(6,7,1),
(6,8,1),(7,8,1),(7,9,1),(8,9,1)])
resultD :: Map Int Int
resultD = M.fromList [(3, 5), (4, 1), (6, 1)]