fitspec-0.4.10: bench/digraphs.hs
-- This program applies FitSpec to the Digraph library.
--
-- Usage:
-- analyse properties about membership functions:
-- ./digraphs [options] m
--
-- analyse properties about ispath and subgraph functions:
-- ./digraphs [options] ps <refinement-id>
--
--
-- This program is more complicated than it should, as it:
-- * allows switching between two function-tuples/property-sets -- 'digraphs m' or 'digraphs ps';
-- * allows switching between refinements -- 'digraphs ps 0', 'digraphs ps 1', ...;
-- * uses polymorphism where it could use monomorphism.
import Digraph as D
import Test.FitSpec
import Data.List ((\\))
import qualified Data.List as L (delete)
import Control.Monad
instance (Ord a, Listable a) => Listable (Digraph a) where
tiers = concatMapT graphs $ setsOf tiers
where
graphs ns = mapT (D . zip ns)
$ listsOfLength (length ns) (setsOf $ toTiers ns)
-- Our digraph instance above is too complicated.
-- Simple reference implementation:
listDigraphsInneficient :: (Ord a, Listable a) => [Digraph a]
listDigraphsInneficient = concat tiers'
where
tiers' = cons1 D `suchThat` okDigraph `ofWeight` 0
-- Tests Listable Digraph listable instance
-- by comparing to an equivalent inneficient implementation:
--
-- > tiers === tiersDigraphsInneficient
listableOK :: Bool
listableOK = and
[ holds 10000 $ \d -> okDigraph (d :: Digraph A) -- sound
, take 100 list `subset` (listDigraphsInneficient :: [Digraph A]) -- sound
, take 100 (listDigraphsInneficient :: [Digraph A]) `subset` list -- complete
]
where xs `subset` ys = all (`elem` ys) xs
-- For debugging the digraphs instance
putDigraphs :: Int -> IO ()
putDigraphs n = putStrLn . unlines . map (unlines . map show)
$ take n (tiers :: [[Digraph A]])
instance (Ord a, Listable a) => Mutable (Digraph a) where mutiers = mutiersEq
instance (Ord a, Show a, Listable a) => ShowMutable (Digraph a) where
mutantS = mutantSEq
type Preds a = a -> Digraph a -> [a]
type Succs a = a -> Digraph a -> [a]
type IsNode a = a -> Digraph a -> Bool
type IsEdge a = a -> a -> Digraph a -> Bool
type TyM a = (Preds a, Succs a, IsNode a, IsEdge a)
-- | properties about membership in a digraph
propertiesM :: (Ord a, Eq a, Show a, Listable a) => TyM a -> [Property]
propertiesM (preds, succs, isNode, isEdge) =
[ property $ \d t -> D.strictOrder (preds t d)
, property $ \d s -> D.strictOrder (succs s d)
, property $ \d s t -> (s `elem` preds t d) == (t `elem` succs s d)
, property $ \d s t -> (t `elem` succs s d) == isEdge s t d
, property $ \d s t -> isEdge s t d ==> (isNode s d && isNode t d)
, property $ \d s -> isNode s d == (s `elem` D.nodes d)
]
functionsM :: Ord a => TyM a
functionsM = (preds,succs,isNode,isEdge)
type IsPath a = a -> a -> Digraph a -> Bool
type Subgraph a = [a] -> Digraph a -> Digraph a
type TyPS a = (IsPath a, Subgraph a)
-- | properties abouth path and subgraph
propertiesPS :: (Ord a, Eq a, Show a, Listable a) => TyPS a -> [Property]
propertiesPS (isPath, subgraph) =
[ property $ \n d -> isPath n n d == isNode n d
, property $ \n1 n2 n3 d -> isPath n1 n2 d && isPath n2 n3 d ==> isPath n1 n3 d
, property $ \d -> subgraph (D.nodes d) d == d
, property $ \ns1 ns2 d -> subgraph ns1 (subgraph ns2 d) == subgraph ns2 (subgraph ns1 d)
, property $ \n1 n2 ns d -> isPath n1 n2 (subgraph ns d) ==> isPath n1 n2 d
-- 5-7
, property $ \n1 n2 d -> isPath n1 n2 d ==> isNode n1 d && isNode n2 d
, property $ \n1 n2 d -> isPath n1 n2 d && n1 /= n2 ==>
any (\n1' -> n1' /= n1 && isPath n1' n2 d) (succs n1 d)
, property $ \n1 n2 d -> n1 /= n2 ==>
isPath n1 n2 d ==
let d' = subgraph (nodes d \\ [n1]) d in
any (\n1' -> isPath n1' n2 d')
(succs n1 d)
-- 8-9
, property $ \n ns d -> isNode n (subgraph ns d) == (isNode n d && n `elem` ns)
, property $ \n1 n2 ns d -> isEdge n1 n2 (subgraph ns d)
== (isEdge n1 n2 d && n1 `elem` ns && n2 `elem` ns)
]
functionsPS :: Ord a => TyPS a
functionsPS = (isPath, subgraph)
extraMutantsM :: Ord a => [TyM a]
extraMutantsM = []
extraMutantsPS :: Ord a => [TyPS a]
extraMutantsPS = drop 1
[ (isPath, subgraph)
, (\n1 n2 d -> isNode n1 d && isNode n2 d, subgraph)
, (isPath, \ns d -> D [])
]
main :: IO ()
main = do
unless listableOK
$ putStrLn "WARNING: Listable Digraph is broken! (read my source.)"
as <- getArgsWith args { names = [ "isPath n1 n2 d"
, "subgraph ns d" ] }
let (pset,step) = case extra as of
(p:s:_) -> (p ,read s)
[p] -> (p ,0)
[] -> ("m",0)
case pset of
"m" ->
mainWith as { names = [ "preds n d"
, "succs n d"
, "isNode n d"
, "isEdge s t d" ] }
(functionsM :: TyM A)
propertiesM
"ps" ->
let is = case step of
0 -> [ ]
1 -> [0,1,2,3,4 ]
2 -> [0,1,2,3,4,5,6 ]
3 -> [0,1,2,3,4,5,6, 8,9]
4 -> [0,1,2,3,4,5, 7,8,9]
5 -> [0, 7,8,9]
_ -> [0,1,2,3,4,5,6,7,8,9] -- not an actual step
in
mainWith as { names = [ "isPath n1 n2 d"
, "subgraph ns d" ] }
(functionsPS :: TyPS A)
((!!! is) . propertiesPS)
(!!!) :: [a] -> [Int] -> [a]
xs !!! is = map (xs !!) is