{"id":513,"date":"2007-09-18T21:09:56","date_gmt":"2007-09-18T21:09:56","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2007\/09\/18\/using-graphs-to-represent-information-lattices-and-semi-lattices\/"},"modified":"2007-09-18T21:09:56","modified_gmt":"2007-09-18T21:09:56","slug":"using-graphs-to-represent-information-lattices-and-semi-lattices","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2007\/09\/18\/using-graphs-to-represent-information-lattices-and-semi-lattices\/","title":{"rendered":"Using Graphs to Represent Information: Lattices and Semi-Lattices"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" alt=\"lattice002.bmp\" src=\"http:\/\/scientopia.org\/img-archive\/goodmath\/img_271.bmp\" width=\"126\" height=\"121\" class=\"inset right\" \/><\/p>\n<p> There&#8217;s a kind of graph which is very commonly used by people like me for analysis applications, called a lattice. A lattice is a graph with special properties that make it<br \/>\nextremely useful for representing information in an analysis system.<\/p>\n<p><!--more--><\/p>\n<p> I&#8217;ve mentioned before that you can use a graph G=(V,E) to describe a partial order over its vertices, where given two vertices a,b&isin;V, a&lt;b if and only if either (a,b) &isin;E, or there exists<br \/>\nsome vertex c&isin;V such that a&lt;c and c&lt;b. If this is true, G is called a partial order graph (POG). <\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" alt=\"glb-graph.png\" src=\"https:\/\/i0.wp.com\/scientopia.org\/img-archive\/goodmath\/img_272.png?resize=213%2C236\" width=\"213\" height=\"236\" class=\"inset right\" \/><\/p>\n<p> If we look at POGs, we can create a kind of completion property for describing certain POGs, without<br \/>\ncausing them to become total orders, called a greatest lower bound property. Suppose we&#8217;ve got two<br \/>\nvertices a and b, where a is <em>not<\/em> less that b, and b is <em>not<\/em> less than a. In a graph with<br \/>\nthe GLB property, there is some set of vertices which are the <em>largest<\/em> vertices according to the<br \/>\ngraph partial order, and which are less than both a and b. This set, called the greatest lower bound set (GLB set) of a and b will consist of vertices that are not ordered relative to each other in the graph partial order. For example, if you look at the graph to the right, you can J and C are both GLBs of A and B &#8211; but J is not less that C, and C is not less than J. They&#8217;re not comparable. But they, in turn, have their own GLB &#8211; D is the GLB of C and J.<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" alt=\"semi-lattice.png\" src=\"https:\/\/i0.wp.com\/scientopia.org\/img-archive\/goodmath\/img_273.png?resize=258%2C274\" width=\"258\" height=\"274\" class=\"inset right\" \/><\/p>\n<p> Given a POG P, if for any any pair of vertices a and b in P, there is exactly one member in GLB(a,b), then the graph is called a <em>semi-lattice<\/em>. The example graph above is <em>not<\/em> a semi-lattice: the GLB(A,B) contains two elements. The graph to the right <em>is<\/em> a semi-lattice.<\/p>\n<p> There&#8217;s a symmetric notion &#8211; the least upper bound. You can guess it&#8217;s definition. If a graph<br \/>\nhas both a LUB and a GLB, then it&#8217;s called a lattice.<\/p>\n<p> Why are lattices so important? <\/p>\n<p> A lot of the work that I&#8217;ve done has been on program analysis of one kind or another. Program<br \/>\nanalysis is pretty typical of how lattices are used. When you&#8217;re doing an analysis of some kind on a program, at some location in the program, you have some knowledge about the properties of the program<br \/>\nat that point. Then you reach a conditional. At the end of one branch of the conditional, what<br \/>\nyou know can be represented as some value T. At the end of the other branch of the conditional, what<br \/>\nyou know can be represented as some value F. What do you know <em>after the two branches join<\/em>, at the first statement after the conditional? What you know is the <em>greatest lower bound<\/em> of T and F.<\/p>\n<p> Suppose that you know that statement A and statement B are completely independent. After A, you know some set of facts F<sub>A<\/sub>; after statement B, you know some set of facts F<sub>B<\/sub>. What<br \/>\ndo you know after both A and B? You know the <em>least upper bound<\/em> of F<sub>A<\/sub> and<br \/>\nF<sub>B<\/sub>.<\/p>\n<p> For a program analysis to be sound and conservative &#8211; which is a fancy way of saying &#8220;absolutely sure that its results are correct&#8221; &#8211; the set of values that can be produced by the analysis must, at least, be a semi-lattice.<\/p>\n<p> To give you a better sense, let&#8217;s look at an example.<\/p>\n<pre>\ndef foo(a,b):\nx = 13\ny = x*2\nz = x * a\nif (b &lt; z):\nz = y*z\nelse:\nx = sqrt(y)\nq = x\/11\nreturn z\n<\/pre>\n<p> Suppose we want to see what we can replace with constants in the code above. After the first<br \/>\nstatement, X is a constant: {Const(x,13)}. After the second statement, we can say that y is a constant,<br \/>\ntoo &#8211; it&#8217;s a constant times a constant. {Const(x,13), Const(y,26)}. After the third statement, we&#8217;re x and<br \/>\ny are still constant; z isn&#8217;t: {Const(x,13), Const(y,26), Var(z)}.<\/p>\n<p> Now we start the conditional. In the true branch, we end up with: {Const(x,13), Const(y,26&times;26),<br \/>\nVar(z)}. In the false branch, we wind up with {Const(x,sqrt(26)), Const(y,26), Var(z)}.<\/p>\n<p> After the conditional, what do we have? It&#8217;s not just something like set union, or set intersection,<br \/>\nor even set difference. It&#8217;s something specific to this kind of information &#8211; the lower bound of the two<br \/>\nbranches. We lose X as a constant &#8211; because it could be one of two different constants, based on the value<br \/>\nof the parameter b, which we don&#8217;t know. What we end up with is {Var(x),Const(y,26),Var(z)} &#8211; the lower<br \/>\nbound of the two branches in the semi-lattice.<\/p>\n<p> This is part of a common, general pattern in all sorts of analysis, from programs, to planning, to<br \/>\nknowledge representation. When we combine two sets of information, we can either know that both are true<br \/>\n(in which case we combine them using the upper bound), or we can know that one <em>or<\/em> the other is<br \/>\ntrue (in which case we combine them using the lower bound). By making sure that the values form<br \/>\na lattice, and using the lower and upper bounds in the lattice to combine information, we know that our results are safe in the sense that we&#8217;ll never claim to know something that we don&#8217;t. <\/p>\n<p> What that means for program analysis, in practical terms, is that we can perform optimizations &#8211;  make changes to the program to make it more efficient &#8211;  based on information from the analysis: if the analysis says that the optimization won&#8217;t change the results of the program, then we can be absolutely sure that it won&#8217;t. We call that being conservative: we only do things that we can be absolutely sure<br \/>\nwon&#8217;t change the meaning of the program. That&#8217;s obviously a pretty critical thing in a compiler. Proving that the set of values used by the analysis form a lattice is by far the easiest way of showing that the analysis is conservative.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There&#8217;s a kind of graph which is very commonly used by people like me for analysis applications, called a lattice. A lattice is a graph with special properties that make it extremely useful for representing information in an analysis system.<\/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-513","post","type-post","status-publish","format-standard","hentry","category-graph-theory"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-8h","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/513","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=513"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/513\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=513"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=513"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=513"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}