{"id":393,"date":"2016-12-13T01:29:10","date_gmt":"2016-12-13T01:29:10","guid":{"rendered":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/?p=393"},"modified":"2017-11-16T10:57:29","modified_gmt":"2017-11-16T10:57:29","slug":"graphs-a-la-carte","status":"publish","type":"post","link":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/graphs-a-la-carte\/","title":{"rendered":"Graphs \u00e0 la carte"},"content":{"rendered":"<p>I received an overwhelming response to the\u00a0<a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/an-algebra-of-graphs\/\">introductory blog post<\/a>\u00a0about\u00a0the algebra of graphs; thank you all for your remarks, questions and suggestions! In the second part of the series I will\u00a0show that\u00a0the algebra is not restricted only to directed graphs, but can be extended to axiomatically represent\u00a0undirected graphs, reachability and dependency graphs (i.e. preorders and partial orders), their various combinations, and even hypergraphs.<\/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<h4>Why algebra?<\/h4>\n<p>Before we continue, I&#8217;d like to note\u00a0that any data structure for representing graphs (e.g. an edgelist, matrix-based representations, inductive graphs from the <a href=\"https:\/\/hackage.haskell.org\/package\/fgl\">fgl library<\/a>,\u00a0GHC&#8217;s standard <a href=\"https:\/\/hackage.haskell.org\/package\/containers-0.5.8.1\/docs\/Data-Graph.html\"><strong><code>Data.Graph<\/code><\/strong><\/a>, etc.) can satisfy the axioms of the algebra with appropriate definitions\u00a0of <strong><code>empty<\/code><\/strong>, <strong><code>vertex<\/code><\/strong>, <strong><code>overlay<\/code> <\/strong>and <strong><code>connect<\/code><\/strong>, and I do not intend\u00a0to compare these implementations\u00a0against each other. I&#8217;m more interested in implementation-independent (polymorphic) functions that we\u00a0can\u00a0write and reuse, and in proving properties\u00a0of these functions using the laws of the algebra.\u00a0That&#8217;s why I think the algebra is worth studying.<\/p>\n<p>As a warm-up exercise, let&#8217;s\u00a0look at\u00a0a few more examples of such polymorphic graph functions. <a href=\"https:\/\/www.reddit.com\/r\/haskell\/comments\/5gzpqb\/an_algebra_of_graphs\/dawqkln\/\">One of the threads<\/a>\u00a0in the reddit discussion was about the <em>path graph<\/em> <strong>P<sub>4<\/sub><\/strong>: i.e. the graph with 4 vertices connected in a chain. Here is a function that can construct such <a href=\"https:\/\/en.wikipedia.org\/wiki\/Path_graph\">path graphs<\/a> on a given list of vertices:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">path<\/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: #234a97\">g<\/span>\r\npath <span style=\"color: #811f24;font-weight: bold\">[]<\/span>  <span style=\"color: #794938\">=<\/span> empty\r\npath [x] <span style=\"color: #794938\">=<\/span> vertex x\r\npath xs  <span style=\"color: #794938\">=<\/span> fromEdgeList <span style=\"color: #794938\">$<\/span> <span style=\"color: #693a17\">zip<\/span> xs (<span style=\"color: #693a17\">tail<\/span> xs)\r\n\r\n<span style=\"color: #bf4f24\">p4<\/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: #691c97\">Char<\/span>) <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">g<\/span>\r\np4 <span style=\"color: #794938\">=<\/span> path [<span style=\"color: #0b6125\">'a'<\/span><span style=\"color: #794938\">,<\/span> <span style=\"color: #0b6125\">'b'<\/span><span style=\"color: #794938\">,<\/span> <span style=\"color: #0b6125\">'c'<\/span><span style=\"color: #794938\">,<\/span> <span style=\"color: #0b6125\">'d'<\/span>]\r\n<\/pre>\n<p>Note that graph\u00a0<strong><code>p4<\/code><\/strong> is also polymorphic: we\u00a0haven&#8217;t\u00a0committed to any particular data representation, but we know that the vertices of <strong><code>p4<\/code><\/strong> have type <strong><code>Char<\/code><\/strong>.<\/p>\n<p>If we connect the last vertex of a path to the first one, we get a <em>circuit graph<\/em>, or a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Cycle_graph\">cycle<\/a>. Let&#8217;s express\u00a0this in terms of the <strong><code>path<\/code><\/strong> function:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">circuit<\/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: #234a97\">g<\/span>\r\ncircuit <span style=\"color: #811f24;font-weight: bold\">[]<\/span>     <span style=\"color: #794938\">=<\/span> empty\r\ncircuit (x<span style=\"color: #794938\">:<\/span>xs) <span style=\"color: #794938\">=<\/span> path <span style=\"color: #794938\">$<\/span> [x] <span style=\"color: #794938\">++<\/span> xs <span style=\"color: #794938\">++<\/span> [x]\r\n\r\n<span style=\"color: #bf4f24\">pentagon<\/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: #691c97\">Int<\/span>) <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">g<\/span>\r\npentagon <span style=\"color: #794938\">=<\/span> circuit [<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">..<\/span><span style=\"color: #811f24;font-weight: bold\">5<\/span>]\r\n<\/pre>\n<p>From the definition we expect that a path is a subgraph of the corresponding circuit. Can we express this property in the algebra? Yes! It&#8217;s fairly standard to define a\u00a0\u2264 b as a + b = b for idempotent + and it turns out that this definition corresponds to the <em>subgraph relation<\/em> on graphs:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">isSubgraphOf<\/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\">Eq<\/span> <span style=\"color: #234a97\">g<\/span>) <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">g<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #691c97\">Bool<\/span>\r\nisSubgraphOf x y <span style=\"color: #794938\">=<\/span> overlay x y <span style=\"color: #794938\">==<\/span> y\r\n<\/pre>\n<p>We can\u00a0use QuickCheck to test that our implementation satisfies the property:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">\u03bb&gt;<\/span> quickCheck <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>xs <span style=\"color: #794938\">-&gt;<\/span> path xs <span style=\"color: #794938\">`isSubgraphOf`<\/span> (circuit xs <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: #794938\">+++<\/span> <span style=\"color: #811f24;font-weight: bold\">OK<\/span><span style=\"color: #794938\">,<\/span> passed <span style=\"color: #811f24;font-weight: bold\">100<\/span> tests<span style=\"color: #794938\">.<\/span>\r\n<\/pre>\n<p>QuickCheck\u00a0can only test the\u00a0property w.r.t. a particular instance, in this case we chose <strong><code>Basic Int<\/code><\/strong>, but using the algebra we can prove that it holds for all law-abiding instances of <strong><code>Graph<\/code><\/strong> (I leave this as an exercise for the reader).<\/p>\n<p>As a final example, we will implement\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/Cartesian_product_of_graphs\">Cartesian graph product<\/a>, usually denoted as\u00a0G\u00a0<img decoding=\"async\" class=\"mwe-math-fallback-image-inline\" src=\"https:\/\/wikimedia.org\/api\/rest_v1\/media\/math\/render\/svg\/455831d58fa08f311b934d324adcff89a868b4e4\" alt=\"\\square \" \/>\u00a0H, where the vertex set is V<sub>G<\/sub>\u00a0\u00d7 V<sub>H<\/sub> and vertex\u00a0(x, y)\u00a0is connected to vertex\u00a0(x&#8217;, y&#8217;)\u00a0if either x = x&#8217; and y is connected to y&#8217; in H, or y = y&#8217; and x is connected to x&#8217; in G:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">box<\/span> <span style=\"color: #794938\">::<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Functor<\/span> <span style=\"color: #234a97\">f<\/span>, <span style=\"color: #a71d5d;font-style: italic\">Foldable<\/span> <span style=\"color: #234a97\">f<\/span>, <span style=\"color: #a71d5d;font-style: italic\">Graph<\/span> (<span style=\"color: #234a97\">f<\/span> (<span style=\"color: #234a97\">a<\/span>,<span style=\"color: #234a97\">b<\/span>))) <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">b<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> (<span style=\"color: #234a97\">a<\/span>,<span style=\"color: #234a97\">b<\/span>)\r\nbox x y <span style=\"color: #794938\">=<\/span> <span style=\"color: #693a17\">foldr<\/span> overlay empty <span style=\"color: #794938\">$<\/span> xs <span style=\"color: #794938\">++<\/span> ys\r\n  <span style=\"color: #794938\">where<\/span>\r\n    xs <span style=\"color: #794938\">=<\/span> <span style=\"color: #693a17\">map<\/span> (<span style=\"color: #794938\">\\<\/span>b <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #693a17\">fmap<\/span> (<span style=\"color: #794938\">,<\/span>b) x) <span style=\"color: #794938\">$<\/span> toList y\r\n    ys <span style=\"color: #794938\">=<\/span> <span style=\"color: #693a17\">map<\/span> (<span style=\"color: #794938\">\\<\/span>a <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #693a17\">fmap<\/span> (a<span style=\"color: #794938\">,<\/span>) y) <span style=\"color: #794938\">$<\/span> toList x\r\n<\/pre>\n<p>The Cartesian product G\u00a0<img decoding=\"async\" class=\"mwe-math-fallback-image-inline\" src=\"https:\/\/wikimedia.org\/api\/rest_v1\/media\/math\/render\/svg\/455831d58fa08f311b934d324adcff89a868b4e4\" alt=\"\\square \" \/>\u00a0H\u00a0is assembled\u00a0by creating |V<sub>H<\/sub>| copies of graph G and overlaying them with |V<sub>G<\/sub>| copies of graph H. We get access to the list of graph vertices using <strong><code>toList<\/code><\/strong> from the <strong><code>Foldable<\/code><\/strong> instance and turn vertices of original graphs into pairs of vertices by\u00a0<strong><code>fmap<\/code><\/strong>\u00a0from the <strong><code>Functor<\/code><\/strong> instance.<\/p>\n<p>As you can see, the code is still implementation-independent, although it requires that the graph data type is a <strong><code>Functor<\/code><\/strong> and a <strong><code>Foldable<\/code><\/strong>.\u00a0Just like lists, trees and other containers, most graph data structures\u00a0have <strong><code>Functor<\/code><\/strong>, <strong><code>Foldable<\/code><\/strong>, <strong><code>Applicative<\/code><\/strong> and <strong><code>Monad<\/code><\/strong> instances (e.g.\u00a0our <strong><code>Basic<\/code><\/strong>\u00a0data type has them all). Here is how<code> <\/code><strong><code>pentagon `box` p4 <\/code><\/strong>looks:<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2016\/12\/graph-product.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-205\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2016\/12\/graph-product.png\" alt=\"Cartesian graph product\" width=\"2400\" height=\"704\" \/><\/a><\/p>\n<p>(A side note: the type signature of <strong><code>box<\/code><\/strong>\u00a0reminds me of <a href=\"http:\/\/blog.ezyang.com\/2012\/08\/applicative-functors\/\">this blog post<\/a> by Edward Yang and makes me wonder if <strong><code>Functor<\/code><\/strong>, <strong><code>Foldable<\/code><\/strong>\u00a0plus idempotent and commutative\u00a0<strong><code>Monoid<\/code><\/strong> together imply <strong><code>Monoidal<\/code><\/strong>, as it seems that I only had to use <strong><code>empty<\/code><\/strong> and <strong><code>overlay<\/code><\/strong> from the <strong><code>Graph<\/code><\/strong> type class. This seems odd.)<\/p>\n<h4>Undirected graphs<\/h4>\n<p>As I hinted in the previous blog post,\u00a0to switch from directed to undirected graphs it is sufficient to add the axiom of commutativity for the <em>connect<\/em> operator.\u00a0For undirected graphs it makes sense to denote <em>connect<\/em>\u00a0by \u2194 or \u2014, hence:<\/p>\n<ul>\n<li>x \u2194 y = y \u2194 x.<\/li>\n<\/ul>\n<p>Curiously, with the introduction of this axiom the associativity of \u2194 follows from the (left-associated version of) decomposition axiom and commutativity of +:<\/p>\n<table>\n<tbody style=\"font-size: 16px\">\n<tr>\n<td style=\"text-align: right\">\u00a0 \u00a0 (x \u2194 y) \u2194 z<code> <\/code><code> <\/code><code> <\/code><code> <\/code><\/td>\n<td>=<\/td>\n<td>x \u2194 y +\u00a0x \u2194 z + y\u00a0\u2194 z<\/td>\n<td>(left decomposition)<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td>=<\/td>\n<td>y \u2194 z + y \u2194 x + z \u2194 x<\/td>\n<td>(commutativity of + and \u2194)<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td>=<\/td>\n<td>(y \u2194 z) \u2194 x<\/td>\n<td>(left decomposition)<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td>=<\/td>\n<td>\u00a0x \u2194\u00a0(y \u2194 z)<\/td>\n<td>(commutativity of \u2194)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Commutativity of the <em>connect<\/em> operator\u00a0forces\u00a0graph expressions that\u00a0differ only in the direction of\u00a0edges into the same equivalence class. One\u00a0can implement this by the\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/Symmetric_closure\"><em>symmetric closure<\/em><\/a> of the underlying connectivity relation:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">newtype<\/span> <span style=\"color: #811f24;font-weight: bold\">Undirected<\/span> a <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Undirected<\/span> { fromUndirected <span style=\"color: #794938\">::<\/span> <span style=\"color: #811f24;font-weight: bold\">Basic<\/span> a }\r\n    <span style=\"color: #794938\">deriving<\/span> (<span style=\"color: #bf4f24\">Arbitrary<\/span>, <span style=\"color: #bf4f24\">Functor<\/span>, <span style=\"color: #bf4f24\">Foldable<\/span>, <span style=\"color: #bf4f24\">Num<\/span>, <span style=\"color: #bf4f24\">Show<\/span>)\r\n\r\n<span style=\"color: #794938\">instance<\/span> <span style=\"color: #a71d5d;font-style: italic\">Ord<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Eq<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Undirected<\/span> <span style=\"color: #234a97\">a<\/span>) <span style=\"color: #794938\">where<\/span>\r\n    x <span style=\"color: #794938\">==<\/span> y <span style=\"color: #794938\">=<\/span> toSymmetric x <span style=\"color: #794938\">==<\/span> toSymmetric y\r\n\r\n<span style=\"color: #bf4f24\">toSymmetric<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Ord<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Undirected<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Relation<\/span> <span style=\"color: #234a97\">a<\/span>\r\ntoSymmetric <span style=\"color: #794938\">=<\/span> symmetricClosure <span style=\"color: #794938\">.<\/span> toRelation <span style=\"color: #794938\">.<\/span> fromUndirected\r\n<\/pre>\n<p>As you can see, we simply wrap our <strong><code>Basic<\/code><\/strong> implementaion in a newtype with a custom <strong><code>Eq<\/code><\/strong> instance that takes care of the commutativity of\u00a0\u2194.\u00a0We know that the resulting <strong><code>Undirected<\/code><\/strong>\u00a0datatype satisfies all <strong><code>Graph<\/code><\/strong> laws, because\u00a0we only made some previously different expressions equal but\u00a0not vice versa.<\/p>\n<h4>Partial orders<\/h4>\n<p>In many applications graphs\u00a0satisfy the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Transitive_relation\"><em>transitivity<\/em><\/a> property: if vertex x is connected to y, and y is connected to z, then the edge between\u00a0x\u00a0and\u00a0z can be added or removed without changing the semantics of the graph. A common example is <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dependency_graph\"><em>dependency graphs<\/em><\/a>. The semantics of such graphs is typically a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Partially_ordered_set\"><em>partial order<\/em><\/a> on the set of vertices.\u00a0To describe this class of graphs algebraically we can\u00a0add the following <em>closure<\/em> axiom:<\/p>\n<ul>\n<li>y\u00a0\u2260\u00a0\u03b5\u00a0\u21d2 x\u00a0\u2192 y + y \u2192 z + x\u00a0\u2192 z\u00a0= x\u00a0\u2192 y + y\u00a0\u2192 z<\/li>\n<\/ul>\n<p>By using the axiom one can always rewrite a graph expression into its <a href=\"https:\/\/en.wikipedia.org\/wiki\/Transitive_closure\"><em>transitive closure<\/em><\/a> or, alternatively, into its <a href=\"https:\/\/en.wikipedia.org\/wiki\/Transitive_reduction\"><em>transitive reduction<\/em><\/a>, hence all graphs that differ only in\u00a0the existence of some transitive edges are forced into the same equivalence class. Note: the precondition (y\u00a0\u2260\u00a0\u03b5) is necessary as otherwise\u00a0+ and \u2192 can no longer be distinguished:<\/p>\n<p style=\"text-align: center\">x \u2192 z = x\u00a0\u2192 \u03b5 \u2192 z = x\u00a0\u2192 \u03b5 + \u03b5 \u2192 z + x\u00a0\u2192 z\u00a0= x\u00a0\u2192 \u03b5 + \u03b5 \u2192 z = x + z<\/p>\n<p>It is interesting that + and\u00a0\u2192 have a simple meaning for partial orders: they correspond to\u00a0<em>parallel and sequential composition<\/em> of partial orders, respectively. This allows one\u00a0to algebraically describe concurrent systems &#8212; I will dedicate a separate blog post to this topic.<\/p>\n<p>We can implement a <strong><code>PartialOrder<\/code><\/strong> instance by wrapping <strong><code>Basic<\/code><\/strong>\u00a0in a newtype and providing a custom\u00a0equality test via the transitive closure of the underlying relation,\u00a0just like we did for undirected graphs:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">newtype<\/span> <span style=\"color: #811f24;font-weight: bold\">PartialOrder<\/span> a <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">PartialOrder<\/span> { fromPartialOrder <span style=\"color: #794938\">::<\/span> <span style=\"color: #811f24;font-weight: bold\">Basic<\/span> a }\r\n    <span style=\"color: #794938\">deriving<\/span> (<span style=\"color: #bf4f24\">Arbitrary<\/span>, <span style=\"color: #bf4f24\">Functor<\/span>, <span style=\"color: #bf4f24\">Foldable<\/span>, <span style=\"color: #bf4f24\">Num<\/span>, <span style=\"color: #bf4f24\">Show<\/span>)\r\n\r\n<span style=\"color: #794938\">instance<\/span> <span style=\"color: #a71d5d;font-style: italic\">Ord<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Eq<\/span> (<span style=\"color: #a71d5d;font-style: italic\">PartialOrder<\/span> <span style=\"color: #234a97\">a<\/span>) <span style=\"color: #794938\">where<\/span>\r\n    x <span style=\"color: #794938\">==<\/span> y <span style=\"color: #794938\">=<\/span> toTransitive x <span style=\"color: #794938\">==<\/span> toTransitive y\r\n\r\n<span style=\"color: #bf4f24\">toTransitive<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Ord<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">PartialOrder<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Relation<\/span> <span style=\"color: #234a97\">a<\/span>\r\ntoTransitive <span style=\"color: #794938\">=<\/span> transitiveClosure <span style=\"color: #794938\">.<\/span> toRelation <span style=\"color: #794938\">.<\/span> fromPartialOrder\r\n<\/pre>\n<p>Let&#8217;s test that our implementation correctly recognises the fact that path graphs are equivalent to cliques when interpreted\u00a0as partial orders:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">\u03bb&gt;<\/span> quickCheck <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">\\<\/span>xs <span style=\"color: #794938\">-&gt;<\/span> path xs <span style=\"color: #794938\">==<\/span> (clique xs <span style=\"color: #794938\">::<\/span> <span style=\"color: #811f24;font-weight: bold\">PartialOrder<\/span> <span style=\"color: #811f24;font-weight: bold\">Int<\/span>)\r\n<span style=\"color: #794938\">+++<\/span> <span style=\"color: #811f24;font-weight: bold\">OK<\/span><span style=\"color: #794938\">,<\/span> passed <span style=\"color: #811f24;font-weight: bold\">100<\/span> tests<span style=\"color: #794938\">.<\/span>\r\n<\/pre>\n<p>Indeed, if we have a series of n tasks, where each task (apart from task 1) depends on the previous\u00a0task (as expressed by <strong><code>path [1..n]<\/code><\/strong>), then\u00a0task 1 is transitively a prerequisite for all subsequent\u00a0tasks, task\u00a02 is a prerequisite for tasks [3..n] etc., which can be expressed by <strong><code>clique [1..n]<\/code><\/strong>.<\/p>\n<h4>Reflexive graphs<\/h4>\n<p>A partial order is\u00a0<em>reflexive<\/em> (also called <em>weak<\/em>) if every\u00a0element is\u00a0related to itself. An example of a reflexive\u00a0partial order is <strong><code>isSubgraphOf<\/code><\/strong> as introduced above: indeed,<code> <\/code><strong><code>x `isSubgraphOf`\u00a0x == True <\/code><\/strong>for all graphs x. To represent <a href=\"http:\/\/mathworld.wolfram.com\/ReflexiveGraph.html\">reflexive graphs<\/a> algebraically we can introduce the following axiom:<\/p>\n<ul>\n<li>vertex x = vertex x\u00a0\u2192 vertex x<\/li>\n<\/ul>\n<p>This enforces that each vertex has a self-loop. The implementation of <strong><code>Reflexive<\/code> <\/strong>data type is very similar to that of\u00a0<strong><code>Undirected<\/code> <\/strong>and <strong><code>PartialOrder<\/code> <\/strong>so I do not show it here (it is based on the reflexive closure of the underlying relation).<\/p>\n<p>Note: cyclic reflexive partial orders\u00a0correspond to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Preorder\"><em>preorders<\/em><\/a>, for example:<\/p>\n<p style=\"text-align: center\">(1 + 2 + 3)\u00a0\u2192 (2 + 3 + 4)<\/p>\n<p>is a preorder with vertices 2 and 3 forming an equivalence class. We can find the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Strongly_connected_component\"><em>strongly-connected components<\/em><\/a> and derive the following <em>condensation<\/em>:<\/p>\n<p style=\"text-align: center\">{1} \u2192 {2, 3} \u2192 {4}<\/p>\n<p>One way to interpret this preorder as a dependency graph is that tasks 2 and 3 are\u00a0executed as a <em>step<\/em>, simultaneously, and that they both depend on task 1.<\/p>\n<h4>Mixing graph flavours<\/h4>\n<p>We can mix the three new axioms above in various combinations. For example, the algebra of undirected, reflexive and transitively closed graphs describes the laws of\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/Equivalence_relation\"><em>equivalence relations<\/em><\/a>. Notably,\u00a0it is not necessary to keep information about all edges in such graphs and there is\u00a0an efficient implementation based on the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Disjoint-set_data_structure\">disjoint set data structure<\/a>. If you are curious about potential applications of such graphs, have a look at <a href=\"https:\/\/www.staff.ncl.ac.uk\/andrey.mokhov\/switching-networks.pdf\">this paper<\/a> where I use them to model switching networks. More precisely, I model <em>families<\/em> of switching networks; this requires another extension to\u00a0the algebra: a unary\u00a0<em>condition<\/em> operator, which I will cover in a future blog post.<\/p>\n<h4>Hypergraphs<\/h4>\n<p><a href=\"https:\/\/news.ycombinator.com\/item?id=13126008\">This thread<\/a>\u00a0in the Hacker News discussion leads me another\u00a0twist of the algebra. Let&#8217;s replace the decomposition axiom with <em>3-decomposition<\/em>:<\/p>\n<ul>\n<li>w\u00a0\u2192 x\u00a0\u2192 y\u00a0\u2192 z =\u00a0w\u00a0\u2192 x\u00a0\u2192 y +\u00a0w\u00a0\u2192 x \u2192 z +\u00a0w\u00a0\u2192 y\u00a0\u2192 z +\u00a0x\u00a0\u2192 y\u00a0\u2192 z<\/li>\n<\/ul>\n<p>In words, instead of collapsing all expressions to vertices and edges (pairs of vertices), as we did with the 2-decomposition, we now collapse all expressions to vertices, edges and <em>triples<\/em> (or hyperedges of rank 3). I haven&#8217;t yet figured out whether the resulting algebra is particularly useful, but perhaps the reader\u00a0can provide an insight?<\/p>\n<p>To see the difference between 2- and 3-decomposition clearer, let&#8217;s substitute \u03b5 for w in 3-decomposition and simplify:<\/p>\n<p style=\"text-align: center\">x\u00a0\u2192 y\u00a0\u2192 z = x\u00a0\u2192 y + x \u2192 z + y\u00a0\u2192 z +\u00a0x\u00a0\u2192 y\u00a0\u2192 z<\/p>\n<p>Looks familiar? It&#8217;s <em>almost<\/em> the 2-decomposition axiom! Yet there is no way to get rid of the term\u00a0x\u00a0\u2192 y\u00a0\u2192 z on the right side: indeed, a triple is unbreakable in this algebra, and one can only extract the pairs (edges) that are\u00a0embedded in it. In fact, we can take this further and rewrite the above expression to also expose the embedded vertices:<\/p>\n<p style=\"text-align: center\">x\u00a0\u2192 y\u00a0\u2192 z = x + y + z + x\u00a0\u2192 y + x \u2192 z + y\u00a0\u2192 z +\u00a0x\u00a0\u2192 y\u00a0\u2192 z<\/p>\n<p>With 2-decomposition we can achieve something similar:<\/p>\n<p style=\"text-align: center\">x\u00a0\u2192 y = x + y +\u00a0x\u00a0\u2192 y<\/p>\n<p>which I call the <em>absorption theorem<\/em>. It says that an edge x\u00a0\u2192 y has vertices x and y (its endpoints) embedded in it. This seems intriguing but I have no idea where it leads to, I guess we&#8217;ll figure out together!<\/p>\n<p>P.S.: All code snippets above are\u00a0available in the <a href=\"https:\/\/github.com\/snowleopard\/alga\">alga<\/a>\u00a0repository. Look <a href=\"https:\/\/github.com\/snowleopard\/alga\/blob\/master\/test\/Test.hs\">how nicely we can test the library<\/a> thanks to the algebraic API!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I received an overwhelming response to the\u00a0introductory blog post\u00a0about\u00a0the algebra of graphs; thank you all for your remarks, questions and suggestions! In the second part of the series I will\u00a0show that\u00a0the algebra is not restricted only to directed graphs, but can be extended to axiomatically represent\u00a0undirected graphs, reachability and dependency graphs (i.e. preorders and partial &hellip; <a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/graphs-a-la-carte\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Graphs \u00e0 la carte<\/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-393","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\/393","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=393"}],"version-history":[{"count":71,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/393\/revisions"}],"predecessor-version":[{"id":621,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/393\/revisions\/621"}],"wp:attachment":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/media?parent=393"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/categories?post=393"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/tags?post=393"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}