{"id":639,"date":"2008-05-07T14:28:31","date_gmt":"2008-05-07T14:28:31","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2008\/05\/07\/linear-programming\/"},"modified":"2008-05-07T14:28:31","modified_gmt":"2008-05-07T14:28:31","slug":"linear-programming","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2008\/05\/07\/linear-programming\/","title":{"rendered":"Linear Programming"},"content":{"rendered":"<p> In my last post on game theory, I said that you could find an optimal<br \/>\nprobabilistic grand strategy for any two-player, simultaneous move, zero-sum game.<br \/>\nIt&#8217;s done through something called linear programming. But linear programming<br \/>\nis useful for a whole lot more than just game theory.<\/p>\n<p> Linear programming is a general technique for solving a huge family of<br \/>\noptimization problems. It&#8217;s incredibly useful for scheduling, resource<br \/>\nallocation, economic planning, financial portfolio management,<br \/>\nand a ton of of other, similar things.<\/p>\n<p> The basic idea of it is that you have a linear function,<br \/>\ncalled an <em>objective function<\/em>, which describes what you&#8217;d like<br \/>\nto maximize. Then you have a collection of inequalities, describing<br \/>\nthe constraints of the values in the objective function. The solution to<br \/>\nthe problem is a set of assignments to the variables in the objective function<br \/>\nthat provide a maximum.<\/p>\n<p><!--more--><\/p>\n<p> For example, imagine that you run a widget factory, which can<br \/>\nproduce a maximum of W widgets per day. You can produce two<br \/>\ndifferent kinds of widgets &#8211; either widget 1, or widget 2. Widget one<br \/>\ntakes s<sub>1<\/sub> grams of iron to produce; widget 2 needs s<sub>2<\/sub><br \/>\ngrams of iron. You can sell a widget 1 for a profit p<sub>1<\/sub> dollars,<br \/>\nand a widget 2 for a profit of p<sub>2<\/sub> dollars. You&#8217;ve got G grams of iron<br \/>\navailable for producing widgets. In order to maximize your profit, how<br \/>\nmany widgets of each type should you produce with the iron you have<br \/>\navailable to you?<\/p>\n<p> You can reduce this to the following:<\/p>\n<ol>\n<li> You want to maximize the objective function<br \/>\np<sub>1<\/sub>x<sub>1<\/sub> + p<sub>2<\/sub>x<sub>2<\/sub>, where x<sub>1<\/sub> is the number of type 1 widgets you&#8217;ll produce, and x<sub>2<\/sub> is the number<br \/>\nof type 2 widgets.<\/li>\n<li> x<sub>1<\/sub> + x<sub>2<\/sub> &le; W. (You can&#8217;t produce more than W widgets.)\n<li> s<sub>1<\/sub>x<sub>1<\/sub> + s<sub>2<\/sub>x<sub>2<\/sub> &le; G. (This is<br \/>\nthe constraint imposed by the amount of iron you have available to produce<br \/>\nwidgets.)<\/li>\n<li> x<sub>1<\/sub> &ge; 0, x<sub>2<\/sub> &ge; 0. (You can&#8217;t produce a<br \/>\nnegative number of either type of widgets.)<\/li>\n<\/ol>\n<p> The fourth one is easy to overlook, but it&#8217;s really important. One of the tricky things about linear programming is that you need to be sure that you<br \/>\nreally include all of the constraints. You can very easily get non-sensical<br \/>\nresults if you miss a constraint. For example, if we left that constraint out<br \/>\nof this problem, and the profit on a type 2 widget was significantly higher<br \/>\nthan the profit on a type 1 widget, then you might wind up producing a <em>negative<\/em> number of type 1 widgets, in order to allow you to produce<br \/>\nmore than W widgets per day.<\/p>\n<p> Once you&#8217;ve got all of the constraints laid out, you can convert the<br \/>\nproblem to a matrix form, which is what we&#8217;ll use for the<br \/>\nsolution. Basically, for each constraint equation where you&#8217;ve got<br \/>\nboth x<sub>1<\/sub> and x<sub>2<\/sub>, you add a row to a coefficient<br \/>\nmatrix containing the coefficients, and a row to the result matrix containing the right-hand side of the inequality. So, for example, you&#8217;d convert<br \/>\nthe inequality &#8220;s<sub>1<\/sub>x<sub>1<\/sub> + s<sub>2<\/sub>x<sub>2<\/sub> &le; G&#8221; to a row [s<sub>1<\/sub>,s<sub>2<\/sub>] in the coefficient matrix,<br \/>\nand &#8220;G&#8221; as a row in the result matrix. This rendering of the inequalities<br \/>\nis show below.<\/p>\n<p> Maximize: <\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" alt=\"linear-objective.png\" src=\"https:\/\/i0.wp.com\/scientopia.org\/img-archive\/goodmath\/img_307.png?resize=120%2C63\" width=\"120\" height=\"63\" \/><\/p>\n<p>where<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" alt=\"linear-simple.png\" src=\"https:\/\/i0.wp.com\/scientopia.org\/img-archive\/goodmath\/img_308.png?resize=264%2C62\" width=\"264\" height=\"62\" \/><\/p>\n<p> Once you&#8217;ve got the constraints worked out, you need to do something<br \/>\ncalled <em>adding slack<\/em>. The idea is that you want to convert the<br \/>\ninequalities to equalities. The way to do that is by adding variables. For<br \/>\nexample, given the inequality x<sub>1<\/sub> + x<sub>2<\/sub>&le;W, you<br \/>\ncan convert that to an equality by adding a variable representing<br \/>\nW-(x<sub>1<\/sub>+x<sub>2<\/sub>): x<sub>1<\/sub>+x<sub>2<\/sub>+x<sub>slack<\/sub>=W, where x<sub>slack<\/sub>&ge;0.<\/p>\n<p> So we take the constraint equations, and add slack variables to all of them,<br \/>\nwhich gives us the following:<\/p>\n<ol>\n<li> Maximize: p<sub>1<\/sub>x<sub>1<\/sub> + p<sub>2<\/sub>x<sub>2<\/sub><\/li>\n<li> x<sub>1<\/sub> + x<sub>2<\/sub> + x<sub>3<\/sub> = W.<\/li>\n<li> s<sub>1<\/sub>x<sub>1<\/sub> + s<sub>2<\/sub>x<sub>2<\/sub> + x<sub>4<\/sub> = G. <\/li>\n<li> x<sub>1<\/sub> &ge; 0, x<sub>2<\/sub> &ge; 0.<\/li>\n<\/ol>\n<p> We can re-render this into matrix form &#8211; but the next matrix needs<br \/>\nto includes rows and columns for the slack variables.<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" alt=\"linear-slack.png\" src=\"https:\/\/i0.wp.com\/scientopia.org\/img-archive\/goodmath\/img_309.png?resize=297%2C93\" width=\"297\" height=\"93\" \/><\/p>\n<p> Now, we need to work the real solution into the matrix. The way that we<br \/>\ndo that is by taking the solution &#8211; the maximum of the objective function &#8211; and naming it &#8220;Z&#8221;, and adding the new objective function equation into the<br \/>\nmatrix. In our example, since we&#8217;re trying to maximize the<br \/>\nobjective &#8220;p<sub>1<\/sub>x<sub>1<\/sub> + p<sub>2<\/sub>x<sub>2<\/sub>&#8220;,<br \/>\nwe represent that with an equation &#8220;Z-p<sub>1<\/sub>x<sub>1<\/sub>-p<sub>2<\/sub>x<sub>2<\/sub>=0&#8243;. So the<br \/>\nfinal matrix, called the <em>augmented form matrix<\/em> of our<br \/>\nlinear programming problem is:<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" alt=\"linear-augmented.png\" src=\"https:\/\/i0.wp.com\/scientopia.org\/img-archive\/goodmath\/img_310.png?resize=337%2C99\" width=\"337\" height=\"99\" \/><\/p>\n<p> Once you&#8217;ve got the augmented form, there are a variety of techniques that<br \/>\nyou can use to get a solution. The intuition behind it is fairly simple: the<br \/>\nset of inequalities, interpreted geometrically, form a convex polyhedron. The<br \/>\nmaximum will be at one of the vertices of the polyhedron.<\/p>\n<p> The simplest solution strategy is called the simplex algorithm. In the<br \/>\nsimplex algorithm, you basically start by finding an arbitrary vertex<br \/>\nof the polyhedron. You then look to see if either of the edges incident to that point slope upwards. If they do, you trace the edge upward to the next<br \/>\nvertex. And then you look to see if the other edge from that vertex slopes<br \/>\nupwards &#8211; and so on, until you reach a vertex where you can&#8217;t follow an edge to a higher point.<\/p>\n<p> In general, solving a linear programming problem via simplex is pretty<br \/>\nfast &#8211; but it&#8217;s not necessarily so. The worst case time of it is<br \/>\nexponential. But in real linear programming problems, the<br \/>\nexponential case basically doesn&#8217;t come up.<\/p>\n<p> (It&#8217;s like a wide range of problems. There are a lot of problems that are,<br \/>\nin theory, incredibly difficult &#8211; but because the difficult cases are<br \/>\nvery rare and rather contrived, they&#8217;re actually very easy to solve. Two<br \/>\nexamples of this that I find particularly interesting are both NP complete.<br \/>\nType checking in Haskell is one of them: in fact, the general type<br \/>\ninference in Haskell is worse that NP complete: the type validation is<br \/>\nNP-complete; type inference is NP-hard. But on real code, it&#8217;s effectively<br \/>\napproximately linear. The other one is a logic problem called 3-SAT. I<br \/>\nonce attended a great talk by a guy named Daniel Jackson, talking about<br \/>\na formal specification language he&#8217;d designed called <a href=\"\">Alloy<\/a>.<br \/>\nAlloy reduces<br \/>\nits specification checking to 3-SAT. Dan explained this saying: &#8220;The bad news<br \/>\nis, analyzing Alloy specifications is 3-SAT, so it&#8217;s exponential and NP-complete. But the good news is that analyzing Alloy specifications is 3-SAT,<br \/>\nso we can solve it really quickly.&#8221;)<\/p>\n<p> This is getting long, so I think I&#8217;ll stop here for today. Next post, I&#8217;ll<br \/>\nshow an implementation of the simplex algorithm, and maybe talk a little bit<br \/>\nabout the basic idea behind the non-exponential algorithms. After that, we&#8217;ll<br \/>\nget back to game theory, and I&#8217;ll show how you can construct a linear<br \/>\nprogramming problem out of a game.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my last post on game theory, I said that you could find an optimal probabilistic grand strategy for any two-player, simultaneous move, zero-sum game. It&#8217;s done through something called linear programming. But linear programming is useful for a whole lot more than just game theory. Linear programming is a general technique for solving a [&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-639","post","type-post","status-publish","format-standard","hentry","category-graph-theory"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-aj","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/639","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=639"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/639\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=639"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=639"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=639"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}