Arbitrary instance for generating unbiased graphs for quickcheck

匆匆过客 提交于 2019-12-04 15:07:53

First you must figure out how to construct a graph which satisfies those properties.

DAG: If your nodes admit some ordering, and for each edge (u,v) you have u < v then the graph is acyclic. This ordering can be any ordering at all, so you can just manufacture an arbitrary ordering on the set of nodes in the graph.

Forest: If your graph has no edges, this property is trivially satisfied. Initially you can add any edge whose source is any node. If you add an edge, remove the source of that edge from the remaining available nodes.

I guess the big question is how to translate this to code. QuickCheck provides many combinators, esp. for selecting from lists, with and without replacement, of various sizes, etc.

instance (Ord v, Arbitrary v) => Arbitrary (Graph v) where 
  arbitrary = do 
    ns <- Set.fromList <$> liftA2 (++) (replicateM 10 arbitrary) arbitrary

First you generate a random set of nodes.

    let ns' = map reverse $ drop 2 $ inits $ Set.toList ns 

For each node, this computes the (non-empty) set of nodes which are "greater" than that node. Here "greater" just means according to the arbitrary ordering induced by the order of the elements in the list. This gets you the DAG property.

    es <- sublistOf ns' >>= 
            mapM (\(f:ts) -> Edge f <$> elements ts)

You then get a random sublist of that list (which gets you the forest property), and for each element in that random sublist, you create an edge pointing from the "largest" node in that set to one that is "smaller".

    return $ Graph ns (Set.fromList es) 

Then you're done! Test like so:

main = quickCheck $ forAll arbitrary (liftA2 (&&) (isDAG :: Graph Integer -> Bool) isForest)

A natural way of constructing graphs is inductively, adding one node at a time. Then it becomes quite easy to ensure the required properties hold:

  • If for each added node its edges point only to existing nodes (and not in the other direction), we ensure the DAG property.
  • If there is at most one edge going from a node, we ensure the forest property. (As you didn't provide the adj function, it's not clear if by "forest" you mean there is at most one edge going from a node or to a node.)

So the process of generating such a graph would go as follows:

  1. Generate a list of random nodes.
  2. Construct a graph by add them one by one. For each node, either add a random edge to one of the already added nodes, or no edge (decide randomly).

The main factor here is deciding whether to add an edge or not. By tweaking this parameter you get more or less trees in your forest. One option is to use frequency for that.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!