{"id":503,"date":"2017-01-31T23:36:52","date_gmt":"2017-01-31T23:36:52","guid":{"rendered":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/?p=503"},"modified":"2017-11-16T10:58:39","modified_gmt":"2017-11-16T10:58:39","slug":"old-graphs-from-new-types","status":"publish","type":"post","link":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/old-graphs-from-new-types\/","title":{"rendered":"Old graphs from new types"},"content":{"rendered":"<p>After I got back from the holiday that I planned in the <a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/graphs-in-disguise\/\">previous blog post<\/a>, I spent the whole January playing with the <a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/tag\/algebra\/\">algebra of graphs<\/a> and trying to find\u00a0interesting and useful ways of constructing graphs, focusing on writing polymorphic code that can manipulate\u00a0graph expressions without turning them into concrete data structures. I&#8217;ve put together a small toolbox containing a few\u00a0quirky\u00a0types, which I&#8217;d like to share with you in this blog post. If you are not familiar with the algebra of graphs, please read <a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/an-algebra-of-graphs\/\">the introductory blog post<\/a> first.<\/p>\n<p><strong>Update:<\/strong>\u00a0This series of blog posts was published as a <a href=\"https:\/\/github.com\/snowleopard\/alga-paper\">functional pearl<\/a> at the Haskell Symposium 2017.<\/p>\n<p><!--more--><\/p>\n<h3>Graph transpose<\/h3>\n<p>One of the simplest transformations one can apply to a graph is\u00a0to flip the direction of all of its edges. It&#8217;s usually straightforward to implement but whatever data structure you use to represent graphs, you will spend at least <em>O(1)<\/em> time to modify it (say, by flipping the <strong><code>treatAsTransposed<\/code><\/strong> flag); much more often\u00a0you will have to traverse the data structure\u00a0and flip every edge, resulting in <em>O(|V|+|E|)<\/em> time complexity. What if I told you that by using Haskell&#8217;s type system, we can transpose polymorphic graphs in <em>zero<\/em>\u00a0time? Sounds\u00a0suspicious? Let&#8217;s see how this works.<\/p>\n<p>Consider the following <strong><code>Graph<\/code><\/strong> instance:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">newtype<\/span> <span style=\"color: #811f24;font-weight: bold\">Transpose<\/span> g <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">T<\/span> { transpose <span style=\"color: #794938\">::<\/span> g }\r\n\r\n<span style=\"color: #794938\">instance<\/span> <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Transpose<\/span> <span style=\"color: #234a97\">g<\/span>) <span style=\"color: #794938\">where<\/span>\r\n    <span style=\"color: #794938\">type<\/span> <span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> (<span style=\"color: #811f24;font-weight: bold\">Transpose<\/span> g) <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> g\r\n    empty       <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">T<\/span> empty\r\n    vertex      <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">T<\/span> <span style=\"color: #794938\">.<\/span> vertex\r\n    overlay x y <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">T<\/span> <span style=\"color: #794938\">$<\/span> transpose x <span style=\"color: #794938\">`overlay`<\/span> transpose y\r\n    connect x y <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">T<\/span> <span style=\"color: #794938\">$<\/span> transpose y <span style=\"color: #794938\">`connect`<\/span> transpose x <span style=\"color: #5a525f;font-style: italic\">-- flip<\/span>\r\n<\/pre>\n<p>We wrap a graph in a <strong><code>newtype<\/code><\/strong>\u00a0flipping the order of arguments to <strong><code>connect<\/code><\/strong>. Let&#8217;s check if this works:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">\u03bb&gt;<\/span> edgeList <span style=\"color: #794938\">$<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> * (<span style=\"color: #811f24;font-weight: bold\">2<\/span> <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">3<\/span>) * <span style=\"color: #811f24;font-weight: bold\">4<\/span>\r\n[(<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">2<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">3<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">4<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">4<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">3<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">4<\/span>)]\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> edgeList <span style=\"color: #794938\">$<\/span> transpose <span style=\"color: #794938\">$<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> * (<span style=\"color: #811f24;font-weight: bold\">2<\/span> <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">3<\/span>) * <span style=\"color: #811f24;font-weight: bold\">4<\/span>\r\n[(<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">1<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">3<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">1<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">4<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">1<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">4<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">2<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">4<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">3<\/span>)]\r\n<\/pre>\n<p>Cool! And this has zero runtime cost, because all we do is wrapping and unwrapping the <code><strong>newtype<\/strong><\/code>, which\u00a0is <a href=\"https:\/\/wiki.haskell.org\/Performance\/Data_types#Newtypes\">guaranteed to be free<\/a>. As an exercise, verify that transpose\u00a0is an <a href=\"https:\/\/en.wikipedia.org\/wiki\/Antihomomorphism\">antihomomorphism<\/a> on graphs, that is:<\/p>\n<ul>\n<li>T(\u03b5) =\u00a0\u03b5<\/li>\n<li>T(v) = v<\/li>\n<li>T(x + y) = T(x) + T(y)<\/li>\n<li>T(x \u2192 y) = T(y) \u2192 T(x)<\/li>\n<\/ul>\n<p>Furthermore, transpose is its own inverse: <strong><code>transpose . transpose = id<\/code><\/strong>.<\/p>\n<p>To make sure <strong><code>transpose<\/code><\/strong> is only applied to polymorphic graphs, we do not export the constructor <strong><code>T<\/code><\/strong>, therefore the only way to call <strong><code>transpose<\/code><\/strong> is to give it a polymorphic argument and let the type inference interpret it as a value of type <strong><code>Transpose<\/code><\/strong>. The type signature is a little unsatisfying though:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">\u03bb&gt;<\/span> <span style=\"color: #794938\">:<\/span>t transpose\r\n<span style=\"color: #bf4f24\">transpose<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Transpose<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">g<\/span>\r\n<\/pre>\n<p>It&#8217;s not clear at all from the type that the function operates on graphs. Do you have any ideas how to improve it?<\/p>\n<h3>Merging graph vertices with a functor<\/h3>\n<p>Here is a puzzle for you: can you implement a function <strong><code>gmap<\/code><\/strong> that given a function <strong><code>a -&gt; b<\/code><\/strong> and a polymorphic graph whose vertices are of type <strong><code>a<\/code><\/strong> will produce a polymorphic graph with vertices of type <strong><code>b<\/code><\/strong> by applying the function to each vertex?\u00a0Yes, this is almost a <strong><code>Functor<\/code><\/strong>\u00a0but it doesn&#8217;t have the usual\u00a0type signature, because <strong><code>Graph<\/code><\/strong> is\u00a0not a higher-kinded type.<\/p>\n<p>My solution is as follows, but I feel there may be simpler ones:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">newtype<\/span> <span style=\"color: #811f24;font-weight: bold\">GraphFunctor<\/span> a <span style=\"color: #794938\">=<\/span>\r\n    <span style=\"color: #811f24;font-weight: bold\">GF<\/span> { gfor <span style=\"color: #794938\">::<\/span> forall g<span style=\"color: #794938\">.<\/span> <span style=\"color: #811f24;font-weight: bold\">Graph<\/span> g <span style=\"color: #794938\">=&gt;<\/span> (a <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> g) <span style=\"color: #794938\">-&gt;<\/span> g }\r\n\r\n<span style=\"color: #794938\">instance<\/span> <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> (<span style=\"color: #a71d5d;font-style: italic\">GraphFunctor<\/span> <span style=\"color: #234a97\">a<\/span>) <span style=\"color: #794938\">where<\/span>\r\n    <span style=\"color: #794938\">type<\/span> <span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> (<span style=\"color: #811f24;font-weight: bold\">GraphFunctor<\/span> a) <span style=\"color: #794938\">=<\/span> a\r\n    empty       <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">GF<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>_ <span style=\"color: #794938\">-&gt;<\/span> empty\r\n    vertex  x   <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">GF<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>f <span style=\"color: #794938\">-&gt;<\/span> vertex (f x)\r\n    overlay x y <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">GF<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>f <span style=\"color: #794938\">-&gt;<\/span> gmap f x <span style=\"color: #794938\">`overlay`<\/span> gmap f y\r\n    connect x y <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">GF<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>f <span style=\"color: #794938\">-&gt;<\/span> gmap f x <span style=\"color: #794938\">`connect`<\/span> gmap f y\r\n\r\n<span style=\"color: #bf4f24\">gmap<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">=&gt;<\/span> (<span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">GraphFunctor<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">g<\/span>\r\ngmap <span style=\"color: #794938\">=<\/span> <span style=\"color: #693a17\">flip<\/span> gfor\r\n<\/pre>\n<p>Essentially, we are defining another\u00a0<strong><code>newtype<\/code><\/strong> wrapper, which pushes the given function all the way towards the vertices.\u00a0This has no runtime cost, just as before, although\u00a0the actual evaluation of the given function at each vertex will not be free, of course. Let&#8217;s test this!<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">\u03bb&gt;<\/span> adjacencyList <span style=\"color: #794938\">$<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> * <span style=\"color: #811f24;font-weight: bold\">2<\/span> * <span style=\"color: #811f24;font-weight: bold\">3<\/span> <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">4<\/span> * <span style=\"color: #811f24;font-weight: bold\">5<\/span>\r\n[(<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">3<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">3<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">3<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">[]<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">4<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">5<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">5<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">[]<\/span>)]\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> <span style=\"color: #794938\">:<\/span>t gmap (<span style=\"color: #794938\">+<\/span><span style=\"color: #811f24;font-weight: bold\">1<\/span>) <span style=\"color: #794938\">$<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> * <span style=\"color: #811f24;font-weight: bold\">2<\/span> * <span style=\"color: #811f24;font-weight: bold\">3<\/span> <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">4<\/span> * <span style=\"color: #811f24;font-weight: bold\">5<\/span>\r\ngmap (<span style=\"color: #794938\">+<\/span><span style=\"color: #811f24;font-weight: bold\">1<\/span>) <span style=\"color: #794938\">$<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> * <span style=\"color: #811f24;font-weight: bold\">2<\/span> * <span style=\"color: #811f24;font-weight: bold\">3<\/span> <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">4<\/span> * <span style=\"color: #811f24;font-weight: bold\">5<\/span> <span style=\"color: #794938\">::<\/span> (<span style=\"color: #811f24;font-weight: bold\">Graph<\/span> g<span style=\"color: #794938\">,<\/span> <span style=\"color: #811f24;font-weight: bold\">Num<\/span> (<span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> g)) <span style=\"color: #794938\">=&gt;<\/span> g\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> adjacencyList <span style=\"color: #794938\">$<\/span> gmap (<span style=\"color: #794938\">+<\/span><span style=\"color: #811f24;font-weight: bold\">1<\/span>) <span style=\"color: #794938\">$<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> * <span style=\"color: #811f24;font-weight: bold\">2<\/span> * <span style=\"color: #811f24;font-weight: bold\">3<\/span> <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">4<\/span> * <span style=\"color: #811f24;font-weight: bold\">5<\/span>\r\n[(<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">3<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">4<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">3<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">4<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">4<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">[]<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">5<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">6<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">6<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">[]<\/span>)]\r\n<\/pre>\n<p>As\u00a0you can see, we can increment the value of each vertex by mapping function <strong><code>(+1)<\/code><\/strong> over the graph. The resulting expression is a polymorphic graph, as desired. Again, we&#8217;ve done some useful work without\u00a0turning the graph into a concrete data structure. As an exercise,\u00a0show that\u00a0<strong><code>gmap<\/code><\/strong> satisfies the functor laws: <strong><code>gmap id = id<\/code><\/strong> and <strong><code>gmap f . gmap g = gmap (f . g)<\/code><\/strong>. A useful first step is to prove that mapping a function is a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Homomorphism\">homomorphism<\/a>:<\/p>\n<ul>\n<li>\u00a0M<sub>f<\/sub>(\u03b5) =\u00a0\u03b5<\/li>\n<li>\u00a0M<sub>f<\/sub>(v) = f(v)<\/li>\n<li>\u00a0M<sub>f<\/sub>(x + y) =\u00a0\u00a0M<sub>f<\/sub>(x) +\u00a0\u00a0M<sub>f<\/sub>(y)<\/li>\n<li>\u00a0M<sub>f<\/sub>(x \u2192 y) =\u00a0\u00a0M<sub>f<\/sub>(x) \u2192 M<sub>f<\/sub>(y)<\/li>\n<\/ul>\n<p>An alert reader might wonder: what happens if the function maps two original vertices into the same one? They will be merged! Merging graph vertices is a useful function, so let&#8217;s define it in terms of <strong><code>gmap<\/code><\/strong>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">mergeVertices<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">=&gt;<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #691c97\">Bool<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span>\r\n    <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">GraphFunctor<\/span> (<span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> g) <span style=\"color: #794938\">-&gt;<\/span> g\r\nmergeVertices p v <span style=\"color: #794938\">=<\/span> gmap <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>u <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #794938\">if<\/span> p u <span style=\"color: #794938\">then<\/span> v <span style=\"color: #794938\">else<\/span> u\r\n\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> adjacencyList <span style=\"color: #794938\">$<\/span> mergeVertices <span style=\"color: #693a17\">odd<\/span> <span style=\"color: #811f24;font-weight: bold\">3<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> * <span style=\"color: #811f24;font-weight: bold\">2<\/span> * <span style=\"color: #811f24;font-weight: bold\">3<\/span> <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">4<\/span> * <span style=\"color: #811f24;font-weight: bold\">5<\/span>\r\n[(<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">3<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">3<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">3<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">4<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">3<\/span>])]\r\n<\/pre>\n<p>The function takes a predicate on graph vertices and a target vertex and maps all vertices satisfying the predicate into the target vertex, thereby merging them. In our example all odd vertices {1, 3, 5} are merged into 3, in particular creating the self-loop 3 \u2192 3. Note: it takes linear time\u00a0<em>O(|g|)<\/em> for\u00a0<strong><code>mergeVertices<\/code><\/strong> to apply the\u00a0predicate to each vertex (|g| is the size of the expression g), which may be much\u00a0more efficient than merging vertices in a concrete data structure; for example, if the graph is represented by an adjacency matrix, it will likely be necessary to rebuild the resulting matrix from scratch, which takes\u00a0<em>O(|V|^2)<\/em> time. Since for many graphs we have |g| = <em>O(|V|)<\/em>, the matrix-based <strong><code>mergeVertices<\/code><\/strong> will run in <em>O(|g|^2)<\/em>.<\/p>\n<h3>Expanding vertices into subgraphs (hey, monads!)<\/h3>\n<p>What do the operations of removing a vertex and splitting a vertex have in common? They both can be implemented by replacing each vertex of a graph with a (possibly empty) subgraph and flattening the result. Sounds familiar?\u00a0You may recognise this as monad&#8217;s <strong><code>bind<\/code><\/strong>\u00a0function, or Haskell&#8217;s operator <strong><code>&gt;&gt;=<\/code><\/strong>, which\u00a0is so useful that it even made it to the <a href=\"https:\/\/www.haskell.org\/\">Haskell&#8217;s logo<\/a>. We are going to implement <strong><code>bind<\/code><\/strong> on graphs by wrapping it into yet another\u00a0<strong><code>newtype<\/code><\/strong>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">newtype<\/span> <span style=\"color: #811f24;font-weight: bold\">GraphMonad<\/span> a <span style=\"color: #794938\">=<\/span>\r\n    <span style=\"color: #811f24;font-weight: bold\">GM<\/span> { bind <span style=\"color: #794938\">::<\/span> forall g<span style=\"color: #794938\">.<\/span> <span style=\"color: #811f24;font-weight: bold\">Graph<\/span> g <span style=\"color: #794938\">=&gt;<\/span> (a <span style=\"color: #794938\">-&gt;<\/span> g) <span style=\"color: #794938\">-&gt;<\/span> g }\r\n\r\n<span style=\"color: #794938\">instance<\/span> <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> (<span style=\"color: #a71d5d;font-style: italic\">GraphMonad<\/span> <span style=\"color: #234a97\">a<\/span>) <span style=\"color: #794938\">where<\/span>\r\n    <span style=\"color: #794938\">type<\/span> <span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> (<span style=\"color: #811f24;font-weight: bold\">GraphMonad<\/span> a) <span style=\"color: #794938\">=<\/span> a\r\n    empty       <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">GM<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>_ <span style=\"color: #794938\">-&gt;<\/span> empty\r\n    vertex  x   <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">GM<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>f <span style=\"color: #794938\">-&gt;<\/span> f x <span style=\"color: #5a525f;font-style: italic\">-- here is the trick!<\/span>\r\n    overlay x y <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">GM<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>f <span style=\"color: #794938\">-&gt;<\/span> bind x f <span style=\"color: #794938\">`overlay`<\/span> bind y f\r\n    connect x y <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">GM<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>f <span style=\"color: #794938\">-&gt;<\/span> bind x f <span style=\"color: #794938\">`connect`<\/span> bind y f\r\n<\/pre>\n<p>As you can see, the implementation is almost identical to\u00a0<strong><code>gmap<\/code><\/strong>: instead of wrapping the value\u00a0<strong><code>f<\/code> <code>x<\/code><\/strong>\u00a0into a <strong><code>vertex<\/code><\/strong>, we should just leave it as is. The resulting transformation is also a homomorphism. Let&#8217;s see how we can make use of this new type in our toolbox.<\/p>\n<p>We are first going to implement a filter-like function\u00a0<strong><code>induce<\/code><\/strong> that, given a vertex predicate and a graph, will compute the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Induced_subgraph\">induced subgraph<\/a> on the set of vertices that satisfy the predicate by turning all other vertices into <em>empty subgraphs<\/em> and flattening the result.<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">induce<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">=&gt;<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #691c97\">Bool<\/span>)\r\n    <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">GraphMonad<\/span> (<span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> g) <span style=\"color: #794938\">-&gt;<\/span> g\r\ninduce p g <span style=\"color: #794938\">=<\/span> bind g <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>v <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #794938\">if<\/span> p v <span style=\"color: #794938\">then<\/span> vertex v <span style=\"color: #794938\">else<\/span> empty\r\n\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> edgeList <span style=\"color: #794938\">$<\/span> clique [<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">..<\/span><span style=\"color: #811f24;font-weight: bold\">4<\/span>]\r\n[(<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">1<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">2<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">3<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">4<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">2<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">3<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">4<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">3<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">4<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">3<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">4<\/span>)]\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> edgeList <span style=\"color: #794938\">$<\/span> induce (<span style=\"color: #794938\">&lt;<\/span><span style=\"color: #811f24;font-weight: bold\">3<\/span>) <span style=\"color: #794938\">$<\/span> clique [<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">..<\/span><span style=\"color: #811f24;font-weight: bold\">4<\/span>]\r\n[(<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">1<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">2<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">2<\/span>)]\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> induce (<span style=\"color: #794938\">&lt;<\/span><span style=\"color: #811f24;font-weight: bold\">3<\/span>) (clique [<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">..<\/span><span style=\"color: #811f24;font-weight: bold\">4<\/span>]) <span style=\"color: #794938\">==<\/span> (clique [<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">..<\/span><span style=\"color: #811f24;font-weight: bold\">2<\/span>] <span style=\"color: #794938\">::<\/span> <span style=\"color: #811f24;font-weight: bold\">Basic<\/span> <span style=\"color: #811f24;font-weight: bold\">Int<\/span>)\r\n<span style=\"color: #b4371f\">True<\/span>\r\n<\/pre>\n<p>As you can see, by inducing a clique on a\u00a0subset of the vertices that we like (<strong><code>&lt;3<\/code><\/strong>), we get a smaller clique, as expected.<\/p>\n<p>We can now implement <strong><code>removeVertex<\/code><\/strong> via <strong><code>induce<\/code><\/strong>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">removeVertex<\/span> <span style=\"color: #794938\">::<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Eq<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span>), <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> <span style=\"color: #234a97\">g<\/span>) <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span>\r\n    <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">GraphMonad<\/span> (<span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> g) <span style=\"color: #794938\">-&gt;<\/span> g\r\nremoveVertex v <span style=\"color: #794938\">=<\/span> induce (<span style=\"color: #794938\">\/=<\/span> v)\r\n\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> adjacencyList <span style=\"color: #794938\">$<\/span> removeVertex <span style=\"color: #811f24;font-weight: bold\">2<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> * (<span style=\"color: #811f24;font-weight: bold\">2<\/span> <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">3<\/span>)\r\n[(<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">3<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">3<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">[]<\/span>)]\r\n<\/pre>\n<p>Removing an edge is not as simple.\u00a0I suspect that this has something to do with the fact that the corresponding transformation doesn&#8217;t seem to be a homomorphism. Indeed, you will find it tricky\u00a0to\u00a0satisfy the last homomorphism requirement on\u00a0R<sub>x\u2192y<\/sub>:<\/p>\n<ul>\n<li>R<sub>x\u2192y<\/sub>(x \u2192 y) = R<sub>x\u2192y<\/sub>(x)\u00a0\u2192 R<sub>x\u2192y<\/sub>(y)<\/li>\n<\/ul>\n<p>We can, however, implement\u00a0a function <strong><code>disconnect<\/code><\/strong>\u00a0that removes all edges between two <em>different<\/em> vertices as follows:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">disconnect<\/span> <span style=\"color: #794938\">::<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Eq<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span>), <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> <span style=\"color: #234a97\">g<\/span>) <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span>\r\n    <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">GraphMonad<\/span> (<span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> g) <span style=\"color: #794938\">-&gt;<\/span> g\r\ndisconnect u v g <span style=\"color: #794938\">=<\/span> removeVertex u g <span style=\"color: #794938\">`overlay`<\/span> removeVertex v g\r\n\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> adjacencyList <span style=\"color: #794938\">$<\/span> disconnect <span style=\"color: #811f24;font-weight: bold\">1<\/span> <span style=\"color: #811f24;font-weight: bold\">2<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> * (<span style=\"color: #811f24;font-weight: bold\">2<\/span> <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">3<\/span>)\r\n[(<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">3<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">[]<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">3<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">[]<\/span>)]\r\n<\/pre>\n<p>That is, we\u00a0create two graphs: one without u, the other without v, and overlay them, which removes both\u00a0u\u00a0\u2192 v and v\u00a0\u2192 u edges. I still don&#8217;t have a solution for removing just a single edge u\u00a0\u2192 v, or even just a self-loop\u00a0v\u00a0\u2192 v (note: \u00a0<strong><code>disconnect v v = removeVertex v<\/code><\/strong>). Maybe you can find a solution? (<em>Update:<\/em> Arseniy Alekseyev found a solution for removing self-loops that can be generalised for removing edges, see a note at the end of the blog post.)<\/p>\n<p>Curiously, we can have a slightly shorter implementation of\u00a0<strong><code>disconnect<\/code><\/strong>, because a function returning a graph can also be given a <strong><code>Graph<\/code><\/strong> instance:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">instance<\/span> <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> (<span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">g<\/span>) <span style=\"color: #794938\">where<\/span>\r\n    <span style=\"color: #794938\">type<\/span> <span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> (a <span style=\"color: #794938\">-&gt;<\/span> g) <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> g\r\n    empty       <span style=\"color: #794938\">=<\/span> pure empty\r\n    vertex      <span style=\"color: #794938\">=<\/span> pure <span style=\"color: #794938\">.<\/span> vertex\r\n    overlay x y <span style=\"color: #794938\">=<\/span> overlay <span style=\"color: #794938\">&lt;$&gt;<\/span> x <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> y\r\n    connect x y <span style=\"color: #794938\">=<\/span> connect <span style=\"color: #794938\">&lt;$&gt;<\/span> x <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> y\r\n\r\n<span style=\"color: #bf4f24\">disconnect<\/span> <span style=\"color: #794938\">::<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Eq<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span>), <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> <span style=\"color: #234a97\">g<\/span>) <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span>\r\n    <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">GraphMonad<\/span> (<span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> g) <span style=\"color: #794938\">-&gt;<\/span> g\r\ndisconnect u v <span style=\"color: #794938\">=<\/span> removeVertex u <span style=\"color: #794938\">`overlay`<\/span> removeVertex v\r\n<\/pre>\n<p>Finally, as promised, here is how we can split a vertex into a list of given vertices using the\u00a0<strong><code>bind<\/code><\/strong>\u00a0function:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">splitVertex<\/span> <span style=\"color: #794938\">::<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Eq<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span>), <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> <span style=\"color: #234a97\">g<\/span>) <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span>\r\n    <span style=\"color: #794938\">-&gt;<\/span> [<span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> g] <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">GraphMonad<\/span> (<span style=\"color: #811f24;font-weight: bold\">Vertex<\/span> g) <span style=\"color: #794938\">-&gt;<\/span> g\r\nsplitVertex v vs g <span style=\"color: #794938\">=<\/span> bind g <span style=\"color: #794938\">$<\/span>\r\n    <span style=\"color: #794938\">\\<\/span>u <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #794938\">if<\/span> u <span style=\"color: #794938\">==<\/span> v <span style=\"color: #794938\">then<\/span> vertices vs <span style=\"color: #794938\">else<\/span> vertex u\r\n\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> adjacencyList <span style=\"color: #794938\">$<\/span> splitVertex <span style=\"color: #811f24;font-weight: bold\">1<\/span> [<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">,<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span>] <span style=\"color: #794938\">$<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> * (<span style=\"color: #811f24;font-weight: bold\">2<\/span> <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">3<\/span>)\r\n[(<span style=\"color: #811f24;font-weight: bold\">0<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">3<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">3<\/span>])<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">[]<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #811f24;font-weight: bold\">3<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">[]<\/span>)]\r\n<\/pre>\n<p>Here vertex 1 is split into a pair of vertices {0, 1} that have the same connectivity.<\/p>\n<h3>Constructing De Bruijn graphs<\/h3>\n<p>To demonstrate that we can construct reasonably sophisticated graphs using the presented toolkit,\u00a0let&#8217;s try it on <a href=\"https:\/\/en.wikipedia.org\/wiki\/De_Bruijn_graph\">De Bruijn graphs<\/a>, an interesting combinatorial object that frequently shows up in computer engineering and bioinformatics. My implementation is fairly short, but requires some explanation:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">deBruijn<\/span> <span style=\"color: #794938\">::<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> <span style=\"color: #234a97\">g<\/span>, <span style=\"color: #a71d5d;font-style: italic\">Vertex<\/span> <span style=\"color: #234a97\">g<\/span> ~ [<span style=\"color: #234a97\">a<\/span>]) <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #691c97\">Int<\/span> <span style=\"color: #794938\">-&gt;<\/span> [<span style=\"color: #234a97\">a<\/span>] <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">g<\/span>\r\ndeBruijn len alphabet <span style=\"color: #794938\">=<\/span> bind skeleton expand\r\n  <span style=\"color: #794938\">where<\/span>\r\n    overlaps <span style=\"color: #794938\">=<\/span> <span style=\"color: #693a17\">mapM<\/span> (<span style=\"color: #693a17\">const<\/span> alphabet) [<span style=\"color: #811f24;font-weight: bold\">2<\/span><span style=\"color: #794938\">..<\/span>len]\r\n    skeleton <span style=\"color: #794938\">=<\/span> fromEdgeList [       (<span style=\"color: #b4371f\">Left<\/span> s<span style=\"color: #794938\">,<\/span> <span style=\"color: #b4371f\">Right<\/span> s)  <span style=\"color: #794938\">|<\/span> s <span style=\"color: #794938\">&lt;-<\/span> overlaps ]\r\n    expand v <span style=\"color: #794938\">=<\/span> vertices     [ either ([a]<span style=\"color: #794938\">++<\/span>) (<span style=\"color: #794938\">++<\/span>[a]) v <span style=\"color: #794938\">|<\/span> a <span style=\"color: #794938\">&lt;-<\/span> alphabet ]\r\n<\/pre>\n<p>The function builds a De Bruijn graph of dimension <strong><code>len<\/code><\/strong>\u00a0from symbols of\u00a0the given <strong><code>alphabet<\/code><\/strong>.\u00a0The vertices of the graph are all possible words of length <strong><code>len<\/code><\/strong>\u00a0containing symbols of the <strong><code>alphabet<\/code><\/strong>, and two words are connected\u00a0x\u00a0\u2192 y whenever x and y match after we remove the first symbol of x and the last symbol of\u00a0y (equivalently, when\u00a0x = az and y = zb for some symbols a and b). An example of a 3-dimensional De Bruijn graph on the alphabet {0, 1} is shown in the diagram below (right).<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2017\/01\/De-Bruijn-construction.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-205\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2017\/01\/De-Bruijn-construction.png\" alt=\"De Bruijn graph construction\" width=\"2400\" height=\"1106\" \/><\/a><\/p>\n<p>Here are all the ingredients of the solution:<\/p>\n<ul>\n<li><strong><code>overlaps<\/code><\/strong> contains all possible words of length <strong><code>len-1<\/code><\/strong>\u00a0that\u00a0correspond to overlaps of connected vertices.<\/li>\n<li><strong><code>skeleton<\/code><\/strong>\u00a0is a graph with one edge per overlap,\u00a0with <strong><code>Left<\/code><\/strong> and <strong><code>Right<\/code><\/strong> vertices\u00a0acting as temporary placeholders (see the diagram).<\/li>\n<li>We replace a vertex<strong><code>\u00a0<\/code><\/strong><strong><code>Left s\u00a0<\/code><\/strong>with a subgraph of two vertices {<strong><code>0s<\/code><\/strong>, <strong><code>1s<\/code><\/strong>}, i.e. the vertices whose suffix is <strong><code>s<\/code><\/strong>. Symmetrically,<strong><code>\u00a0<\/code><\/strong><strong><code>Right s\u00a0<\/code><\/strong>is replaced by a subgraph of two vertices {<strong><code>s0<\/code><\/strong>, <strong><code>s1<\/code><\/strong>}. This is captured by the function\u00a0<strong><code>expand<\/code><\/strong>.<\/li>\n<li>The result is obtained by\u00a0computing <strong><code>bind skeleton expand<\/code><\/strong>, as illustrated above.<\/li>\n<\/ul>\n<p>&#8230;and this works as expected:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">\u03bb&gt;<\/span> edgeList <span style=\"color: #794938\">$<\/span> deBruijn <span style=\"color: #811f24;font-weight: bold\">3<\/span> <span style=\"color: #0b6125\">\"01\"<\/span>\r\n[(<span style=\"color: #0b6125\">\"000\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"000\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"000\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"001\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"001\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"010\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"001\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"011\"<\/span>)\r\n<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"010\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"100\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"010\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"101\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"011\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"110\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"011\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"111\"<\/span>)\r\n<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"100\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"000\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"100\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"001\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"101\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"010\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"101\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"011\"<\/span>)\r\n<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"110\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"100\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"110\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"101\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"111\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"110\"<\/span>)<span style=\"color: #794938\">,<\/span>(<span style=\"color: #0b6125\">\"111\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"111\"<\/span>)]\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> <span style=\"color: #693a17\">all<\/span> (<span style=\"color: #794938\">\\<\/span>(x<span style=\"color: #794938\">,<\/span>y) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #693a17\">drop<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> x <span style=\"color: #794938\">==<\/span> dropEnd <span style=\"color: #811f24;font-weight: bold\">1<\/span> y) <span style=\"color: #794938\">$<\/span> edgeList <span style=\"color: #794938\">$<\/span> deBruijn <span style=\"color: #811f24;font-weight: bold\">9<\/span> <span style=\"color: #0b6125\">\"abc\"<\/span>\r\n<span style=\"color: #b4371f\">True<\/span>\r\n<span style=\"color: #794938\">\u03bb&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">Set<\/span><span style=\"color: #794938\">.<\/span>size <span style=\"color: #794938\">$<\/span> vertexSet <span style=\"color: #794938\">$<\/span> deBruijn <span style=\"color: #811f24;font-weight: bold\">9<\/span> <span style=\"color: #0b6125\">\"abc\"<\/span>\r\n<span style=\"color: #811f24;font-weight: bold\">19683<\/span> <span style=\"color: #5a525f;font-style: italic\">-- i.e. 3^9<\/span>\r\n<\/pre>\n<p>That&#8217;s all for now! I hope I&#8217;ve convinced you that\u00a0you don&#8217;t necessarily need to operate on concrete data structures when constructing graphs. You can write both efficient and reusable code by using Haskell&#8217;s types for interpreting polymorphic graph expressions as maps, binds and other familiar\u00a0transforms.\u00a0Give me any\u00a0old graph,\u00a0and I&#8217;ll write you a new type to construct it! \ud83d\ude09<\/p>\n<p>P.S.: The\u00a0algebra of graphs\u00a0is\u00a0available in the <a href=\"https:\/\/github.com\/snowleopard\/alga\">alga<\/a> library.<\/p>\n<p><span style=\"text-decoration: underline\">Update<\/span>:\u00a0Arseniy Alekseyev found a nice solution for removing self-loops. Let R<sub>v<\/sub> denote the operation of removing a vertex v, and R<sub>v\u2192v<\/sub> denote the operation of removing a self-loop v \u2192 v. Then the latter can be defined as follows:<\/p>\n<ul>\n<li>R<sub>v\u2192v<\/sub>(\u03b5) =\u00a0\u03b5<\/li>\n<li>R<sub>v\u2192v<\/sub>(x) =\u00a0x<\/li>\n<li>R<sub>v\u2192v<\/sub>(x + y) =\u00a0R<sub>v\u2192v<\/sub>(x) +\u00a0R<sub>v\u2192v<\/sub>(y)<\/li>\n<li>R<sub>v\u2192v<\/sub>(x \u2192 y) = R<sub>v<\/sub>(x) \u2192 R<sub>v\u2192v<\/sub>(y) +\u00a0R<sub>v\u2192v<\/sub>(x)\u00a0\u2192\u00a0R<sub>v<\/sub>(y)<\/li>\n<\/ul>\n<p>It&#8217;s not a homomorphism, but it seems to work. Cool!\u00a0Furthermore, we can generalise the above and implement the operation R<sub>u\u2192v<\/sub>\u00a0that removes an edge u\u00a0\u2192 v:<\/p>\n<ul>\n<li>R<sub>u\u2192v<\/sub>(\u03b5) =\u00a0\u03b5<\/li>\n<li>R<sub>u\u2192v<\/sub>(x) =\u00a0x<\/li>\n<li>R<sub>u\u2192v<\/sub>(x + y) = R<sub>u\u2192v<\/sub>(x) +\u00a0R<sub>u\u2192v<\/sub>(y)<\/li>\n<li>R<sub>u\u2192v<\/sub>(x \u2192 y) = R<sub>u<\/sub>(x) \u2192 R<sub>u\u2192v<\/sub>(y) +\u00a0R<sub>u\u2192v<\/sub>(x)\u00a0\u2192\u00a0R<sub>v<\/sub>(y)<\/li>\n<\/ul>\n<p>Note that the size of the expression can substantially increase\u00a0as a result of applying such operations.\u00a0Given an expression g of size |g|, what is the worst possible size of the result |R<sub>u\u2192v<\/sub>(g)|?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After I got back from the holiday that I planned in the previous blog post, I spent the whole January playing with the algebra of graphs and trying to find\u00a0interesting and useful ways of constructing graphs, focusing on writing polymorphic code that can manipulate\u00a0graph expressions without turning them into concrete data structures. I&#8217;ve put together &hellip; <a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/old-graphs-from-new-types\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Old graphs from new types<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1174,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,10],"tags":[13,4],"class_list":["post-503","post","type-post","status-publish","format-standard","hentry","category-coding","category-math","tag-algebra","tag-haskell"],"_links":{"self":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/503","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/users\/1174"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/comments?post=503"}],"version-history":[{"count":68,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/503\/revisions"}],"predecessor-version":[{"id":622,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/503\/revisions\/622"}],"wp:attachment":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/media?parent=503"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/categories?post=503"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/tags?post=503"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}