{"id":498,"date":"2007-08-24T19:14:33","date_gmt":"2007-08-24T19:14:33","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2007\/08\/24\/directed-graphs\/"},"modified":"2007-08-24T19:14:33","modified_gmt":"2007-08-24T19:14:33","slug":"directed-graphs","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2007\/08\/24\/directed-graphs\/","title":{"rendered":"Directed Graphs"},"content":{"rendered":"<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" alt=\"weighted-digraph.png\" src=\"https:\/\/i0.wp.com\/scientopia.org\/img-archive\/goodmath\/img_256.png?resize=155%2C182\" width=\"155\" height=\"182\" class=\"inset\" \/><\/p>\n<p> The next interesting variant on graphs is <em>directed graphs<\/em>, or <em>digraphs<\/em> for<br \/>\nshort. A digraph is a graph where each edge distinguished between its source and its target &#8211; so an edge is <em>from<\/em> one node, and <em>to<\/em> another node.  Unlike a simple graph, where if A is adjacent to B, then you can follow the edge either from A to B, or from B to A, in a directed graph, A to B and B to A are different edges.<\/p>\n<p><!--more--><\/p>\n<p> A lot of things change when you&#8217;re using digraphs instead of simple graphs. For example, the shortest<br \/>\npath: the shortest path from A to B is <em>different<\/em> than the shortest path from B to A. Look at the<br \/>\nfollowing example of a weighted digraph. The shortest path from A to B is 2 (A&rarr;B); the shortest path<br \/>\nfrom B to A is 9 (B&rarr;D&rarr;C&rarr;E&rarr;A).<\/p>\n<p> Digraphs come up in many places &#8211; basically anywhere where direction matters. Think, for example, of<br \/>\nNew York City streets. Every intersection is a vertex; streets between intersections are edges. How do you<br \/>\nget from 96th street and Madison to 18th street and 4th ave? Since most of the streets in Manhattan are<br \/>\none-way, you don&#8217;t want to try to do this with an undirected graph &#8211; you&#8217;ll get directions that you can&#8217;t<br \/>\nfollow. You need to know the directions of the edges. (An important point, which this illustrates, is<br \/>\nthat in a digraph, you can have <em>both<\/em> an edge from A to B <em>and<\/em> an edge from B to A.<br \/>\nTwo way streets get modeled as two edges &#8211; one in each direction.)<\/p>\n<p> For a less obvious  example of this, we can look at something very close to home for me. There&#8217;s<br \/>\na very famous software tool, first implemented at Bell Labs, called &#8220;make&#8221;. The purpose of make<br \/>\nis to provide an automated way of compiling software, which ensures that no more work is done compiling than necessary.<\/p>\n<p> This is important, because there are often many steps to compiling a software system. For example, a program that I wrote to generate some fractals consists of:<\/p>\n<ol>\n<li> a graph description file (GDF).<\/li>\n<li> A python program which processes the GDF, and generates a C++ program.<\/li>\n<li> A library &#8211; that is, a set of other C++ sources that aren&#8217;t specific to one particular<br \/>\nimage, but which know how to generate &#8220;pdf&#8221; image files &#8211; that is used by the C++ program to<br \/>\ngenerate the image.<\/li>\n<li> The C++ standard library &#8211; which is used both by the program generated from my GDF file,<br \/>\nand by the PDF library. I don&#8217;t have to compile this &#8211; but it&#8217;s a component that gets<br \/>\nincluded to turn anything into an executable.<\/li>\n<\/ol>\n<p> So, to generate an image, I write a GDF. Then the python program runs on the GDF, generating<br \/>\na C++ program. Then the C++ program is compiled. The library is compiled; and then the compiled<br \/>\nC++ program and the two libraries are linked and run, to generate the image.<\/p>\n<p> Suppose I write a GDF file which generates a nice picture of the mandelbrot set. Then I run<br \/>\nmake to compile it. It generates C++, compiles the C++ and the library, and runs the program<br \/>\nto generate the image.<\/p>\n<p> Then I want to use a different GDF file &#8211; this time, I want to generate a Julia fractal. There&#8217;s no<br \/>\nreason to recompile the C++ library. I already did that when I was generating a mandelbrot, and<br \/>\nthe library hasn&#8217;t changed. I can just re-use the library from last time. <\/p>\n<p> I look at my Julia image, and it&#8217;s no good &#8211; it&#8217;s very pixelated. So I add some kind of<br \/>\nscaling factor to the library. But I&#8217;m not changing my gdf file, and I&#8217;m not changing the python script.  I shouldn&#8217;t need to rerun the python script on the unchanged GDF; and that means that<br \/>\nthe generated C++ program can&#8217;t change either. I need to recompile the library, and I need to<br \/>\nrelink the compiled C++.<\/p>\n<p> That&#8217;s what make is for. It figures out what needs to be redone, based an what changed. The way<br \/>\nthat it does that is by using a <em>dependency graph<\/em>. A dependency graph is a digraph which<br \/>\nhas a vertex for every input to, and every output from, any step of a build process. There is an edge<br \/>\nfrom a vertex A to a vertex B if changing A means that B needs to be recompiled. For example, below is<br \/>\nthe digraph for the scenario I described above. In it, I&#8217;ve made C++ files red\/orange, libraries and executables green, python source blue, and my gdf file purple. Source files are rounded boxes, libraries are ovals, object files are diamonds, and executables are rectangles.<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" alt=\"depgraph.png\" src=\"https:\/\/i0.wp.com\/scientopia.org\/img-archive\/goodmath\/img_257.png?resize=454%2C234\" width=\"454\" height=\"234\" \/><\/p>\n<p>\tTo build the executable for my fractal generator<br \/>\n(&#8220;foo.exe&#8221;), I need to have the generated source file &#8220;foo.cc&#8221;, the pdf library (&#8220;libpdf.a&#8221;), and<br \/>\nthe C++ standard library (&#8220;libstdc++.a&#8221;); to build &#8220;foo.cc&#8221;, I need<br \/>\nboth an input file, &#8220;foo.gdf&#8221;, and the python script &#8220;gen.py&#8221;, and so on. <\/p>\n<p> So, now, suppose I edit &#8220;foo.gdf&#8221;. That means I need to rebuild everything on any path<br \/>\nfrom &#8220;foo.gdf&#8221; up to &#8220;foo.exe&#8221;: so I need to run &#8220;gen.py&#8221; to build &#8220;foo.cc&#8221;; then I need to compile<br \/>\n&#8220;foo.cc&#8221;, and link it against the two libraries to build &#8220;foo.exe&#8221;.<\/p>\n<p> If I updated the version of my C++ library, then I would just need to recompile and link &#8220;foo.cc&#8221;.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The next interesting variant on graphs is directed graphs, or digraphs for short. A digraph is a graph where each edge distinguished between its source and its target &#8211; so an edge is from one node, and to another node. Unlike a simple graph, where if A is adjacent to B, then you can follow [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[25],"tags":[],"class_list":["post-498","post","type-post","status-publish","format-standard","hentry","category-graph-theory"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-82","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/498","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/comments?post=498"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/498\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=498"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=498"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=498"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}