{"id":646,"date":"2008-06-10T15:50:12","date_gmt":"2008-06-10T15:50:12","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2008\/06\/10\/solving-linear-programming-problems\/"},"modified":"2008-06-10T15:50:12","modified_gmt":"2008-06-10T15:50:12","slug":"solving-linear-programming-problems","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2008\/06\/10\/solving-linear-programming-problems\/","title":{"rendered":"Solving Linear Programming Problems"},"content":{"rendered":"<p> So, I&#8217;ve finally had some time to get back to the linear programming<br \/>\nfollowup. You might want to go back and <a href=\"http:\/\/scientopia.org\/blogs\/goodmath\/2008\/05\/linear-programming\">look at the earlier post<\/a> to remember what I was talking about.<\/p>\n<p><!--more--><\/p>\n<p> The basic idea is that we&#8217;ve got a system we&#8217;d like to optimize. The constraints of the system are defined by a set of linear inequalities, and<br \/>\nwe&#8217;ve got a linear expression that we&#8217;d like to maximize.<\/p>\n<p> So, for example, we could have a factory which is capable of producing two<br \/>\ndifferent kinds of widgets. The factory has a maximum capacity of what it can<br \/>\nproduce of 300 widgets per day. It gets a supply of metal and plastic for<br \/>\nmaking widgets: 5000 kilograms of steel, and 100 kilograms of plastic. There<br \/>\nare two kinds of widgets. Type 1 widgets take 23 kg of steel, and 2kg of<br \/>\nplastic, and sell for $900 each. Type 2 widgets take 5kg of steel, and 2<br \/>\nkilograms of plastic, and sell for $700 each. The factories customers need a<br \/>\nminimum of 5 type 1 and 2 type 2 widgets per day. So, the question is, what&#8217;s the optimal way to run the factory? How many of each widget should it make?<\/p>\n<p> Using the formulation we discussed last time, we can formulate this<br \/>\nas a linear programming problem as follows:<\/p>\n<ol>\n<li> Let x1 be the number of type one widgets we produce.<\/li>\n<li> Let x2 be the number of type two widgets we produce.<\/li>\n<li> <b>Objective:<\/b> maximize 900x<sub>1<\/sub> + 700x<sub>2<\/sub>, where:<\/li>\n<li> x<sub>1<\/sub> + x<sub>2<\/sub> &le; 300<\/li>\n<li> 23x<sub>1<\/sub> + 5x<sub>2<\/sub> &le; 500<\/li>\n<li> 2x<sub>1<\/sub> + 2x<sub>2<\/sub> &le; 50<\/li>\n<li> x<sub>1<\/sub> &ge; 5, x<sub>2<\/sub> &ge; 2<\/li>\n<\/ol>\n<p> Now, how do we get the answer? As I discussed last time,<br \/>\nthere&#8217;s a conceptually simple algorithm called <em>simplex<\/em>. The<br \/>\nidea of the simplex algorithm is to do a basic form of something called hill-climbing. The idea of hill-climbing is really simple. You&#8217;re looking for the highest possible point in something which is modeled as a surface. So you try to go uphill: each step, you look for the next step which will get you the furthest up.<\/p>\n<p> In simplex, you know that the solution is a vertex of an N-dimensional polygon. So you find an initial vertex &#8211; it doesn&#8217;t matter which one. Then you look at the edges that are incident on that vertex &#8211; and you pick the one that looks like it&#8217;ll get you the farthest uphill. You keep doing that until you get to one where no edge will take you to a higher vertex &#8211; and you&#8217;re at the maximum.<\/p>\n<p> In general, simplex is very fast. Typically, even if you have the bad luck to start at a minimum vertex, you&#8217;ll get to the maximum very quickly. But the worst case is pretty bad: you can create LP problems where you&#8217;ll wind up visiting <em>every<\/em> vertex. You can see why by imagining a cube. You can distort the cube so that if you start at the minimum vertex, and always climb the edge with the steepest slope, you&#8217;ll have to visit every single vertex. And there are O(2<sup>n<\/sup>) vertices in an N-dimensional polygon. As you increase dimensions, you can do the same distortion trick, to force the simplex algorithm to visit all of the vertices. (Or at least O(2<sup>N<\/sup>) vertices.) But those cases are very rare, and frankly very contrived. So<br \/>\nin general, you don&#8217;t worry about them.<\/p>\n<p> There are other algorithms to solve linear programming problems. There&#8217;s a very fast one &#8211; fast even in the pathological worst cases &#8211; called the interior points method. But for the most part, simplex is the way people go. <\/p>\n<p> If you really need to solve a linear programming problem, you<br \/>\n<em>don&#8217;t<\/em> generally write simplex yourself. Implementing simplex<br \/>\ncorrectly is a pain. It&#8217;s typical of complex numerical analysis problems &#8211;<br \/>\nit&#8217;s a miserable pain in the ass to implement. But, it&#8217;s also such a common<br \/>\nproblem that there are a huge number of highly optimized solvers already<br \/>\nwritten; you just grab one off the shelf. (There&#8217;s a lesson in there;<br \/>\nnever waste time doing work yourself if you know someone else has already done it.) So, for this post, I grabbed a copy<br \/>\nof <a href=\"http:\/\/maxima.sourceforge.net\/\">maxima<\/a>, an open-source symbolic algebra system, which<br \/>\nincludes a very nice solver.<\/p>\n<p> In the last post, I showed how you can formulate the problem as a matrix, which is the input for the simplex algorithm. But maxima, since it&#8217;s so good at symbolic work, doesn&#8217;t even require you to do that (although <em>most<\/em> simplex solvers do take the problem in matrix form). Here&#8217;s how I wrote the problem as a maxima script:<\/p>\n<pre>\nload(\"simplex\")$\nmaximize_lp(\t9*x1 + 7*x2,\n[x1 + x2 &lt;= 300,\n23*x1 + 5*x2 &lt;= 500,\n2*x1 + 2*x2 &lt;= 50,\nx1 &gt;= 5,\nx2 &gt;= 2]), nonegative_lp=true;\n<\/pre>\n<p> When I feed that in to maxima, it converts it to the matrix form,<br \/>\nand then solves it. The answer is that the maximum profit is<br \/>\nabout $21,667, which you can make by producing 4 1\/6 type 1 widgets,<br \/>\nand 20 5\/6 type 2 widgets. <\/p>\n<p> Now, that&#8217;s very nice isn&#8217;t it? We can maximize the factory&#8217;s profit<br \/>\nby producing 4 1\/6 type one widgets. How how we produce 1\/6th of a widget?<\/p>\n<p> The way we formulated the problem is great for working out probabilities<br \/>\nfor optimal grand strategies for zero-sum games &#8211; probabilities can<br \/>\nbe arbitrary real numbers. But for the problem that we&#8217;re talking about &#8211; optimizing profit by producing discrete entities, you need an additional<br \/>\nconstraint: the values in the solution must be integers. <\/p>\n<p> For integer solutions, the simplex method goes right out the window. It&#8217;s actually an entirely different problem: integer linear programming. The strategies and solutions for solving ILP programs are quite different. Integer linear programming is a much harder problem. Instead of the polynomial time<br \/>\nalgorithms that work for general LP, ILP is NP-hard &#8211; that is, its decision<br \/>\nproblem (asking &#8220;Is this the optimal solution?&#8221;) is NP-complete; actually computing the answer is even worse.<\/p>\n<p> Anyway, next post, we&#8217;ll get back to game theory &#8211; how we can set<br \/>\nup a zero-sum game as a linear programming matrix in order to find the<br \/>\noptimal grand strategy.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So, I&#8217;ve finally had some time to get back to the linear programming followup. You might want to go back and look at the earlier post to remember what I was talking about.<\/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":[88],"tags":[],"class_list":["post-646","post","type-post","status-publish","format-standard","hentry","category-game-theory"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-aq","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/646","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=646"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/646\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=646"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=646"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=646"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}