-
Notifications
You must be signed in to change notification settings - Fork 0
/
digraphs.hs
164 lines (134 loc) · 5.53 KB
/
digraphs.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
-- 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