1
data Edge v = Edge {source :: v, target :: v}
          deriving (Show,Eq,Ord)

data Graph v = Graph {nodes :: Set v, edges :: Set (Edge v)}
           deriving Show


instance Arbitrary v => Arbitrary (Edge v) where
    arbitrary = do s <- arbitrary
                   t <- arbitrary
                   return $ Edge {source = s, target = t}

instance (Ord v, Arbitrary v) => Arbitrary (Graph v) where
    arbitrary = aux `suchThat` validGraph
        where aux = do lNodes <- arbitrary
                       lEdges <- arbitrary
                       return $ Graph {nodes = fromList lNodes, edges = fromList lEdges}

I currently have this to generate my Graphs. However by using sample on ghci I noticed that it either doesn't generate edges or it generates a single one. Is it possible to control the number of edges generated? How would I do it?

EDIT: A Graph is considered valid when: 1-The source and target nodes of an edge exist. 2-A node can't be the source to more than one Edge.

ohiohai
  • 73
  • 8
  • 1
    it's probably really hard (you could say it's very *lucky*) to generate a `validGraph` like this (especially when there are more edges) - it's probably better to generate nodes and then draw pairs of nodes from those to generate edges – Random Dev Apr 23 '16 at 15:47
  • The thing is those pairs need to be generated arbitrarily. How do i tell haskell to form random pairs? – ohiohai Apr 23 '16 at 16:16

1 Answers1

3

An arbitrary value is a value in the Gen monad. You can do more in this monad than just combine arbitrary values together. You can perform any of the other Gen operations including choose:

choose :: Random a => (a, a) -> Gen a

Generates a random element in the given inclusive range.

You can use choose to generate other random values than just arbitrary ones.

instance (Ord v, Arbitrary v) => Arbitrary (Graph v) where
    arbitrary = do
        nodes <- arbitrary
        let
            lNodes = toList nodes
            numNodes = length lNodes
            arbitraryEdge = do
                source <- elements lNodes
                target <- elements lNodes
                return $ Edge {
                    source = source,
                    target = target
                }
        numEdges <- choose (0, numNodes * numNodes)
        lEdges <- vectorOf numEdges arbitraryEdge
        return $ Graph {nodes = nodes, edges = fromList lEdges}

This naive implementation isn't very efficient when generating large graphs. It could be a factor of number of nodes in the graph faster if it didn't need to scan the list for the generated values each time it uses elements

Cirdec
  • 24,019
  • 2
  • 50
  • 100
  • I see. However this brings me to the same problem.. Either it doesn't generate edges or, if i do it with something similar to what you sent me, it does but not in a way that my graph would be considered valid... – ohiohai Apr 25 '16 at 16:10
  • btw, continuing with what i commented previously: if i do it with what you sent me it doesn't generate valid graphs because it keeps using repeated nodes as "source" to several Edges. A valid graph can't have a node that's source to more then one Edge. – ohiohai Apr 25 '16 at 16:29
  • @ohiohai That's not the criteria for being valid you specified in the question. If a node can't be the source to more than one edge you can generate 0 or 1 edges for each node instead of generating a bunch of arbitrary edges. It also suggests that your graph data type is wrong, since you could represent the graph as `Map k (Maybe k)` and have every graph always be valid. – Cirdec Apr 25 '16 at 18:03
  • Ah crap. Forgot to put both criteria in the question, sorry. Gonna edit it. – ohiohai Apr 25 '16 at 18:51