Creating a directed acyclic graph in haskell with lists and sets - haskell

I want to create a DAG in haskell but since I'm new to the whole functional programming thing I would like some directions.
The graph needs to be built with only lists and sets, and the following functions must be implemented:
v = add_vertex(g,w)
A vertex with the specified weight w is added to the DAG g and its unique vertex identifier v is returned.
add_edge(g,a,b,w)
An edge from the vertex with vertex identifier a to the vertex with vertex identifier b is added to the DAG g with weight w.
What I've done so far is creating a data type which looks like this:
data Graph v w = Graph {vertices :: [(v, w)],
edges :: [([(v, w)], [(v, w)], w)]} deriving Show
And I guess I need some form of constructor for the graph, it looks like this:
create_graph :: (v,w) -> w -> Graph v w
create_graph v w = Graph [v] [(v, v, w)]
What I would like to do is to create just an empty graph, but now I need to input some starting values if I understand correctly. How can I fix that?
The add_vertex function looks like this:
add_vertex :: Graph v w -> (v, w) -> Graph v w
add_vertex (Graph v w) x = Graph (v ++ [x]) w
But I dont really know how to return a vertex identifier instead of the whole graph. I guess I should also specify that the identifier needs to be a char and the weights can be either floats or ints, where do I do that?
I would also like to have functions for topological ordering and getting the weight for the longest path. With this in mind, should I define the structure of the graph in a different way?
Thanks

what I would do is define the graph like a tree
data Graph a = Graph [(a,[a])] -- Graph is a list of origins paired with edgeends
createGraph ::Eq a => [(a,a)] -> Graph a
createGraph = undefined
empty :: Graph a
empty = Graph []
insertVertex :: Eq a => a -> Graph a -> Graph a
insertVertex = undefined -- insert if not already in the Graph (with empty edges)
insertEdge :: Eq a => (a,a) -> Graph a -> Graph a
insertEdge = undefined -- insert edge in list of origin
--do not forget to add origin, end if they don't exist
implement these and worry about bfs/topsort later and think about the result of a bfs - what do you want as a result? (the result of topsort should be a list i guess).

Related

Data type for a simple, undirected graph without multiple edges or loops in Haskell

I am new to Haskell and I am trying to come up with a suitable way to represent a graph. First some background for an undirected simple graph. For all vertices u and v, an edge between u and v is the same as an edge between v and u, there is at most one edge between u and v, and there is no edge between u and u.
Later on I want to be able to write functions to check if the graph is 1) empty, 2) add new vertices, 3) add new edges, 4) obtain all neighbors to a vertex and 5) obtain a list of all vertices in a graph.
After doing research, I am a bit confused by all the ways to define a graph data type, which I also hope to get some help to clarify. All seem to agree that a you need some way to represent a Vertex/Node and the edges/links to other Vertices/Nodes. However, the implementations differ.
Before I have done a Tree with infinite amount of branches, following this question tree-with-an-arbitrary-number-of-branches
data Tree a = Node a [Tree a]
deriving (Eq, Show)
Whats different with a graph I guess is that a nodes on the same "level" and nodes on different "branches" can be connected with an edge, see figure below.
What I came up with first was defining a data type using recursive data structures with a type variable where each Vertex/Node has a list with its associated nodes:
data Node a = Node a [a]
deriving Show
data Graph a = Graph [Node a]
deriving Show
However, what I am a bit unsure about is whether this representation makes it possible to insert new edges later on. With this definition a graph is just a list of nodes that in turn contains list of nodes they link/edge to.
After doing research about how to represent a graph in Haskell I found some interesting ideas. The first was to define a graph just using type synonyms:
type Node = Int
type Element = String
type Edge = (Node, Node)
type Node = (Node, Element)
type Graph = ([Node], [Edge])
Here we have that a Graph is a list of nodes with an associated list of its connections/links/edges. However, I was not sure what the corresponding data type definition would look like and with a type variable/parameter instead of a concrete type. In this regard, I found this question declare-data-constructor-for-graphs suggesting to represent a graph like this:
type Vertex = Integer
data Graph = Graph [Vertex] [(Vertex, Vertex)]
Which I guess with type parameter instead could be translated to:
data Graph a = Graph [a] [(a, a)]
Is this correct? Would this solution work for creating a simple, undirected graph without multiple edges or loops in Haskell? That also support the creation of the specified functions above.
In continuation, similar to this representation, I found this question directed-acyclic-graph where a graph is defined as:
data Graph a = Graph [(a,[a])] -- Graph is a list of origins paired with edgeends
Here I guess the author defines a graph as a list of tuples where each tuple consists of one node and a list of its linked nodes.
Another way I found was to use record syntax in the question graph-data-type-representation.
data Node a = Node { value :: a
, neighbors :: [Node a]
} deriving (Show)
-- or simply,
data Node a = Node a [Node a]
deriving (Show)
Which I guess is the same reasoning. A Node/Vertex has a value, and neighbors that a just a list of other Vertices. Building on top of this, a graph definition would be:
data Graph a = Graph [Node a]
Or am I wrong? If so, this implementation is similar to what my initial thinking, but differs in the data Node definition. Not sure whats more correct here.
In summary, I have found many ways to represent a graph data type in Haskell. But I am a bit confused about which way that best suits my use-case, to create a simple, undirected graph without multiple edges or loops that also supports the functions I would like to implement.
Looking forward answers and comments to clarify this!
Ended up using
data Graph a = Graph [(a, [a])] deriving (Show)
Since Algebraic data types are just a way to represent data, it is mostly about choosing a design that fits your needs. Here is a good source to read more about it: Learn you a haskell
For example, choosing this data type representation makes adding vertices to a graph possible in this way.
addVertex :: Eq a => Graph a -> a -> Graph a
addVertex (Graph vList) v
| not (containsVertex v vList) = Graph (vList ++ makeVertex v)
| otherwise = Graph vList
makeVertex :: a -> [(a, [a])]
makeVertex x = [(x, [])]
containsVertex :: Eq a => a -> [(a, [a])] -> Bool
containsVertex _ [] = False
containsVertex x ((v, _) : ys) = x == v || containsVertex x ys
Thus, just easy to deal with and manage the Graph when expressed in this way.

Haskell Generating graphs with QuickCheck properties

Graphs have these properties:
The type 'Edge' represents an edge between two nodes.
data Edge v = Edge {source :: v, target :: v}
deriving (Show,Eq,Ord)
The 'Graph' type represents a directed graph.
data Graph v = Graph {nodes :: Set v, edges :: Set (Edge v)}
deriving Show
The fuction 'isDAG' tests if a graph is acyclic.
isDAG :: Ord v => Graph v -> Bool
isDAG g = isValid g && all nocycle (nodes g)
where nocycle v = all (\a -> v `notMember` reachable g a) $ Set.map target (adj g v)
The fuction 'isForest' tests if a valid DAG is a forest (a set of trees)
isForest :: Ord v => DAG v -> Bool
isForest g = isDAG g && all (\v -> length (adj g v) <= 1) (nodes g)
The generators code is:
DAGs generator
dag :: (Ord v, Arbitrary v) => Gen (DAG v)
dag = arbitrary `suchThat` isDAG
Forests generator
forest :: (Ord v, Arbitrary v) => Gen (Forest v)
forest = arbitrary `suchThat` isForest
I want to improve the generators Dag and Forest, so they are defined based on their properties and not with 'suchThat'. How can I do it?
Thank you in advance.
I believe the question at the core is how to generate DAGs and forests.
What's a forest? Forest is a collection of trees. What's a tree? Tree is a graph where every node except the root has exactly one parent. How do we turn it into an algorithm? Generate a list of nodes. For every node in the list going from the left randomly pick an element to the right of it as its parent and create an edge to it.
What is a DAG? DAG is a directed acyclic graph. What can we do with DAGs? We can topologically order them. What does that mean? It means we can put them in a sequence where every edge goes from left to right. How do we turn it into an algorithm? Generate a list of nodes. For every node in the list going from the left randomly pick a subset of elements to the right of it and create an edge to them.

Using a typeclass to access fields of similar data types in Haskell

I am in the process of working on some graph problems in Haskell. In the middle of my work, I decided that I wanted to be able to represent edge colors within a graph data type. So I started with edges: Edges could be either colored or uncolored. Here's a quick mock-up of what I was thinking about. Keep in mind, I'm aware that there are terrible flaws in this code.
data BasicEdge v w = BasicEdge { b_endpoints :: (v,v), b_weight :: w}
data ColoredEdge v w c = ColoredEdge { c_endpoints :: (v,v), c_weight :: w, color :: c}
class Edge e where
endpoints :: e -> (v,v)
weight :: e -> w
instance Edge (BasicEdge v w) where
endpoints = b_endpoints
weight = b_weight
instance Edge (ColoredEdge v w c) where
endpoints = c_endpoints
weight = c_weight
Problem 1: v and w in BasicEdge are different type variables than v and w in ColoredEdge. Thus, attempting to access them in a polymorphic manner is preposterous.
Problem 2: return values in the Edge class definition are free type variables, so they cannot be matched with the return values of b_endpoints and c_endpoints, etc.
I do need the type variables - Vertices could be characters, strings, integers, etc.. Edge weights could be any sort of number (Floats are helpful for some problems). Colors could even be a constructed data type.
Is there an "idiomatic" way to do this in the language? It seems that this is a basic type of polymorphism, but I am struggling to understand how to implement it.
Thanks in advance for your help, and please understand that I have spent the past day trying to search on the internet for guidance. It is difficult to structure a search query for this problem.
Your type class can be fixed by including the type parameters v and w in the class definition.
class Edge e where
endpoints :: e v w -> (v,v)
weight :: e v w -> w
Now e has the kind * -> * -> * meaning that it needs to be a type that takes two additional type parameters and these parameters are then used in endpoints and weight to actually link the result type to the type of the edge.
However, you need to tweak your ColoredEdge type a bit so that v and w are the last two parameters, so
data BasicEdge v w = BasicEdge { b_endpoints :: (v,v), b_weight :: w}
data ColoredEdge c v w = ColoredEdge { c_endpoints :: (v,v), c_weight :: w, color :: c}
Now you can define the instances as
instance Edge BasicEdge where
endpoints = b_endpoints
weight = b_weight
instance Edge (ColoredEdge c) where
endpoints = c_endpoints
weight = c_weight
Another option is to use the TypeFamilies language extension and make the vertex and weight types associated type synonyms in the Edge class. That way the order to type parameters in the instance types becomes irrelevant.
{-# LANGUAGE TypeFamilies #-}
class Edge e where
type Vertex e
type Weight e
endpoints :: e -> (Vertex e, Vertex e)
weight :: e -> Weight e
instance Edge (BasicEdge v w) where
type Vertex (BasicEdge v w) = v
type Weight (BasicEdge v w) = w
endpoints = b_endpoints
weight = b_weight
instance Edge (ColoredEdge v w c) where
type Vertex (ColoredEdge v w c) = v
type Weight (ColoredEdge v w c) = w
endpoints = c_endpoints
weight = c_weight
However, usually type classes are not the best solution for this kind of polymorphism. I would simply include an extra parameter in your Edge type for any additional data, as in
data Edge v w d = Edge { endpoints :: (v,v), weight :: w, edgeData :: d }
Now you can put color in d or a record that contains multiple fields of data for an edge and still query the shape of the graph in a generic way.
Your original edge types could now be represented with the type synonyms
type BasicEdge v w = Edge v w ()
type ColoredEdge v w c = Edge v w c

Requiring that a function must be a retraction in Haskell?

I'm envisioning an implementation of a monadic graph. I'll do my best to explain how it is to be constructed here.
The Graph type should be isomorphic to the following:
data Graph e v = Graph{ vertices :: [v], edges :: [(e, (v, v))] }
Where e is the edge type, and v is the vertex type, we include a list of vertices and a list of edges along with the vertices they connect.
What I'm envisioning is a monad instance of this type as follows:
instance Monad (Graph e) where
return v = Graph v [] -- | Empty graph with one vertex
m >>= f = {- see below -}
I have an idea of how to implement >>= which basically takes each vertex, maps it to a new graph, and then re-connects the vertex which built each graph correspondingly based on how the original graph was connected.
For example, consider a function f which takes a vertex and produces the complete graph on two vertices (K_2) from it. Then if we bound K_2 itself to f, we'd get something like:
A----B
| |
C D
where the graph A----B was the original, and the graphs A----C and B----D were produced from A and B respectively. In the end, A and B need to be connected since they were connected in the original graph. Note that A and B need not be exactly the same, but they need to directly map to something in the new graph. I'm leaving out some information for simplicity (what are the edges of the graph, etc), but the main point I've noticed is that for this to actually work as a Monad instance, A needs to be directly mapped to a vertex in f A, and the same goes for B. In general, each vertex in the original graph needs to be mapped directly to a graph in the graph resulting from f.
If I'm understanding correctly, this means that f must be a retraction for some other morphism g. If it is, we can clearly join the graph by connecting each morphed vertex in its resulting graph to the morphed vertices in the others, producing a new graph of the type we want.
Mostly this is just an idea I had, but I really wanted to if there is any way to, in Haskell, require that f be a retraction? Is there a way to state this within the confines of the language in order to supply an appropriate instance of Monad for a graph, or to do this, must I say "this is really only a monad if the function you're binding to is a retraction?" I suspect the latter, but I just wanted to check.
Alternatively, I may be understanding everything wrong! Feel free to correct me or give me some thoughts of your own.
Like the comments say, you could use a pointed graph:
module PointedGraph where
import Control.Arrow (second)
data PointedGraph e v = PointedGraph { hops :: [(e, PointedGraph e v)], center :: v }
deriving (Eq, Show)
instance Monad (PointedGraph e) where
return = PointedGraph []
PointedGraph hs c >>= f = PointedGraph (hs' ++ map (second (>>= f)) hs) c'
where PointedGraph hs' c' = f c
connect :: PointedGraph e v -> e -> PointedGraph e v -> PointedGraph e v
connect g e g' = g { hops = (e,g') : hops g }
k2, ex :: PointedGraph String Int
k2 = connect (return 0) "original" (return 2)
ex = do
n <- k2
connect (return n) "derived" (return $ n + 1)
So this makes:
k2: 0 -original-> 2
ex: 0 -original-> 2
| |
derived derived
| |
v v
1 3
Note that we have no checking for uniqueness of the vertex labels (that'd require an Eq constraint or the like) so we could easily have something like
k2 >>= const k2:
0 -original-> 0
| |
original original
| |
v v
2 2

Haskell can't match type, claims rigid variable

I am new to Haskell, and I am playing around with creating a typeclass for graphs and the nodes in them. Since I want both directed and undirected graphs, I have
data Node = Node { label :: Char
, index :: Int
} deriving (Ord, Eq)
type Graph edgeType = ([Node], [edgeType])
data Edge = DirectedEdge {h :: Node, t :: Node}
| UndirectedEdge {a :: Node, b :: Node}
instance Show Node where
show n = ['(', label n, ')']
instance Show Edge where
show (DirectedEdge h t) = show h ++ "->" ++ show t
show (UndirectedEdge a b) = show a ++ "-" ++ show b
So I am distinguishing between directed and undirected edges. A graph must only have edges of either type. I also have the following:
nodes :: [Node]
nodes = zipWith Node ['a'..] [0..]
emptyGraph :: [Node] -> Graph edgeType
emptyGraph ns = (ns, [])
So far so good, however I am writing a function connect, with connects a node to an existing graph. Ideally, I only want it to apply to undirected graphs, but that doesn't seem to be an option. Instead, I have something like this:
connect :: Graph edgeType -> Node -> Graph edgeType
connect (ns, es) n = (n:ns, e:es)
where e = UndirectedEdge n (head ns)
But this gives the following error:
Couldn't match type `edgeType' with `Edge'
`edgeType' is a rigid type variable bound by
the type signature for
connect :: Graph edgeType -> Node -> Graph edgeType
What is the best way to accomplish what I am trying to achieve?
You probably want to have two separate edge types instead of Edge
newtype DirectedEdge = DirectedEdge { h :: Node, t :: Node}
newtype UndirectedEdge = UndirectedEdge { a :: Node, b :: Node}
And you probably want some kind of typeclass that gives you back a (Node, Node) given an arbitrary edge:
class HasNodeEndpoints a where
endpoints :: a -> (Node, Node)
-- obvious instances for DirectedEdge and UndirectedEdge
Then when you want to talk about arbitrary graphs, you will write functions that work on Graph a, and probably on HasNodeEndpoints a => Graph a. Algorithms that care about the graph kind would work on Graph DirectedEdge and Graph UndirectedEdge for directed and undirected graphs, respectively.
Another natural extension would be labeled directed and undirected edges.
class HasLabeled a where
type Label a -- associated type synonym
label :: a -> Label a
updateLabel :: a -> (Label a -> Label a) -> a
-- now define data types and instances for labeled directed and undirected edges
Because you choose a specific edge type, namely Edge, when you use UndirectedEdge, the result is that your graph is no longer polymorphic in the edge type. It has to have the type:
connect :: Graph Edge -> Node -> Graph Edge
connect (ns, es) n = (n:ns, e:es)
where e = UndirectedEdge n (head ns)
Since there's noo other type your edges can be, given that clear use of UndirectedEdge.
As an aside, I'd use strictness annotations on the nodes, just as a matter of good hygiene:
data Node = Node { label :: !Char
, index :: !Int
} deriving (Ord, Eq)

Resources