changeset 11:4ea23241ff5b

cleaned up prose
author Robert McIntyre <rlm@mit.edu>
date Wed, 02 Nov 2011 10:28:50 -0700
parents eedd6897197d
children 89462678a932
files org/lpsolve.org
diffstat 1 files changed, 81 insertions(+), 125 deletions(-) [+]
line wrap: on
line diff
     1.1 --- a/org/lpsolve.org	Wed Nov 02 08:02:11 2011 -0700
     1.2 +++ b/org/lpsolve.org	Wed Nov 02 10:28:50 2011 -0700
     1.3 @@ -1,87 +1,78 @@
     1.4  #+title: Discovering Effective Pok\eacute{}mon Types Using Linear Optimization
     1.5  #+author: Robert McIntyre & Dylan Holmes
     1.6  #+EMAIL:     rlm@mit.edu
     1.7 +#+description: Using Lpsolve to func effective pokemon types in clojure.
     1.8 +#+keywords: Pokemon, clojure, linear optimization, lp_spolve, LpSolve
     1.9  #+SETUPFILE: ../../aurellem/org/setup.org
    1.10  #+INCLUDE: ../../aurellem/org/level-0.org
    1.11  
    1.12  
    1.13  
    1.14  * Introduction
    1.15 -In the [[./types.org][previous post]], we used the best-first search algorithm to
    1.16 -locate the most effective Pok\eacute{}mon type
    1.17 -combinations. Afterwards, we realized that we could transform this
    1.18 -search problem into a /linear optimization problem/.  This conversion
    1.19 -offeres several advantages: first, search algorithms are comparatively
    1.20 -slow, whereas linear optimization algorithms are extremely fast;
    1.21 -second, it is difficult to determine whether a search problem has any
    1.22 -solution, whereas it is straightforward to determine whether a linear
    1.23 -optimization problem has any solution; finally, because systems of
    1.24 -linear equations are so common, many programming languages have linear
    1.25 -equation solvers written for them.
    1.26 +This post continues the [[./types.org][previous one]] about pok\eacute{}mon types.
    1.27 +Pok\eacute{}mon is a game in which adorable creatures battle each
    1.28 +other using fantastic attacks.  It was made into a several gameboy
    1.29 +games that all share the same battle system.  Every pok\eacute{}mon in
    1.30 +the gameboy game has one or two /types/, such as Ground, Fire, Water,
    1.31 +etc. Every pok\eacute{}mon attack has exactly one type. Certain
    1.32 +defending types are weak or strong to other attacking types.  For
    1.33 +example, Water attacks are strong against Fire pok\eacute{}mon, while
    1.34 +Electric attacks are weak against Ground Pok\eacute{}mon.  In the
    1.35 +games, attacks can be either twice as effective as normal (Water
    1.36 +vs. Fire), neutrally effective (Normal vs. Normal), half as effective
    1.37 +(Fire vs. Water), or not effective at all (Electric vs. Ground). We
    1.38 +represent these strengths and weakessness as the numbers 2, 1,
    1.39 +$\frac{1}{2}$, and 0, and call them the /susceptance/ of one type to
    1.40 +another.
    1.41  
    1.42 -In this article, we will 
    1.43 +If a pokemon has two types, then the strengths and weakness of each
    1.44 +type are /multiplied/ together.  Thus Electric (2x weak to Ground)
    1.45 +combined with Flying (immune to Ground (0x)) is immune to Ground.
    1.46 +Fire (2x weak to Water) combined with Water (1/2x resistant to Water)
    1.47 +is neutral to Water. If both types are resistant to another type, then
    1.48 +the combination is doubly-resistant (1/4x) to that type. If both types
    1.49 +are weak to a certain type then the combination is double-weak (4x) to
    1.50 +that type.
    1.51 +
    1.52 +In the [[./types.org][previous post]], we used the best-first search algorithm to find
    1.53 +the most effective Pok\eacute{}mon type combinations. Afterwards, we
    1.54 +realized that we could transform this search problem into a /linear
    1.55 +optimization problem/.  This conversion offeres several advantages:
    1.56 +first, search algorithms are comparatively slow, whereas linear
    1.57 +optimization algorithms are extremely fast; second, it is difficult to
    1.58 +determine whether a search problem has any solution, whereas it is
    1.59 +straightforward to determine whether a linear optimization problem has
    1.60 +any solution; finally, because systems of linear equations are so
    1.61 +common, many programming languages have linear equation solvers
    1.62 +written for them.
    1.63 +
    1.64 +In this article, we will:
    1.65   - Solve a simple linear optimization problem in C :: We demonstrate
    1.66        how to use the linear programming C library, =lp_solve=, to
    1.67 -      solve a simple linear
    1.68 -      optimization problem.
    1.69 +      solve a simple linear optimization problem.
    1.70   - Incorporate a C library into Clojure :: We will show how we gave
    1.71        Clojure access to the linear programming C library, =lp_solve=.
    1.72   - Find effective Pokemon types using linear programming :: Building
    1.73 -      on our earlier code, (...)
    1.74 -- Present our results :: 
    1.75 +      on our earlier code, we answer some questions that were
    1.76 +      impossible to answer using best-first search.
    1.77 +- Present our results :: We found some cool examples and learned a lot
    1.78 +     about the pok\eacute{}mon type system as a whole.
    1.79   
    1.80 -#which can be represented and solved as a system of linear equations.
    1.81 -  
    1.82 -* COMMENT  
    1.83 -This post continues the [[./types.org][previous one]] about pok\eacute{}mon types. 
    1.84 -Pok\eacute{}mon is a game in which adorable creatures battle each
    1.85 -other using fantastic attacks.  It was made into a several gameboy
    1.86 -games that all share the same battle system.  Every pok\eacute{}mon in the
    1.87 -gameboy game has one or two /types/, such as Ground, Fire, Water,
    1.88 -etc. Every pok\eacute{}mon attack has exactly one type. Certain defending
    1.89 -types are weak or strong to other attacking types.  For example, Water
    1.90 -attacks are strong against Fire pok\eacute{}mon, while Electric attacks are
    1.91 -weak against Ground Pok\eacute{}mon.  In the games, attacks can be either
    1.92 -twice as effective as normal (Water vs. Fire), neutrally effective
    1.93 -(Normal vs. Normal), half as effective (Fire vs. Water), or not
    1.94 -effective at all (Electric vs. Ground).  Thus the range of defense
    1.95 -values for a particular type is the set 0, 1/2, 1, 2. These are
    1.96 -referred to in the game as being immune, resistant, neutral, and
    1.97 -weak, respectively. I call them the /susceptance/ of one type to another.
    1.98 -
    1.99 -If a pokemon has two types, then the strengths and weakness of each
   1.100 -type are /multiplied/ together.  Thus Electric (2x weak to Ground)
   1.101 -combined with Flying (immune to Ground (0x)) is immune to
   1.102 -Ground.  Fire (2x weak to Water) combined with Water (1/2x resistant
   1.103 -to Water) is neutral to Water. If both types are resistant to another
   1.104 -type, then the combination is doubly-resistant (1/4x) to that type. If
   1.105 -both types are weak to a certain type then the combination is
   1.106 -double-weak (4x) to that type.
   1.107  
   1.108  ** Immortal Types
   1.109  
   1.110 -In the game, pok\eacute{}mon can have either one type, or two types. If this
   1.111 -restriction is lifted, is there any combination of types that is
   1.112 +In the game, pok\eacute{}mon can have either one type or two types. If
   1.113 +this restriction is lifted, is there any combination of types that is
   1.114  resistant to all types?  I call such a combination an /Immortal Type/,
   1.115  since if that type's pattern was repeated over and over again towards
   1.116  infinity, the resulting type would be immune to all attack types.
   1.117  
   1.118  * Linear Programming
   1.119  
   1.120 -** Terminology
   1.121  Linear programming is the process of finding an optimal solution to a
   1.122  linear equation of several variables which are constrained by some linear
   1.123  inequalities.
   1.124  
   1.125 -In linear programming terminology, the function to be extremized is
   1.126 -the /objective function/.
   1.127 -
   1.128 -** COMMENT 
   1.129 -First, we'll give a small example of a linear optimization problem,
   1.130 -and show how it can be solved with Clojure and =lp_solve=.  Then,
   1.131 -we'll show how finding immortal pok\eacute{}mon types can be converted
   1.132 -into a linear problem suitable for solving in the same way.
   1.133 -
   1.134  ** The Farmer's Problem
   1.135  
   1.136  Let's solve the Farmer's Problem, an example linear programming problem
   1.137 @@ -161,21 +152,10 @@
   1.138  +wheat +barley <= 75;
   1.139  #+end_src
   1.140  
   1.141 -
   1.142 -#This is a set of linear equations ideal for solving using a program like
   1.143 -#=lp_solve=. In Linear Algebra terms we are maximizing the linear function 
   1.144 -
   1.145 -#\(\text{profit} = 143\text{ wheat} + 60\text{ barley}\), subject to the constraints
   1.146 -
   1.147 -#Ax <= b,
   1.148 -
   1.149 -#where A is [120 210 110 30 1 1], x is [wheat barley] and b is [15000
   1.150 -#4000 75].
   1.151 -
   1.152  Running the =lp_solve= program on =farmer.lp= yields the following output.
   1.153  
   1.154  #+begin_src sh :exports both :results scalar
   1.155 -~/roBin/lpsolve/lp_solve ~/aurellem/src/pokemon/farmer.lp
   1.156 +lp_solve ~/proj/pokemon-types/lp/farmer.lp
   1.157  #+end_src
   1.158  
   1.159  #+results:
   1.160 @@ -190,55 +170,35 @@
   1.161  of the available acres with wheat and the remaining 53.125 acres with
   1.162  barley; by doing so, he will make $6315.62(5) in profit.
   1.163  
   1.164 -
   1.165 -#The farmer can make a profit of $6315.62 by planting 21.875 acres of
   1.166 -#his land with wheat and the other 53.125 acres of his land with barley.
   1.167 -
   1.168  * Incorporating  =lp_solve= into Clojure 
   1.169  
   1.170 -There is a Java API available which enables Java programs to use Lp
   1.171 -Solve. Although Clojure can use this Java API directly, the
   1.172 -interaction between Java, C, and Clojure is clumsy:
   1.173 -
   1.174 -
   1.175 -The Java API for LP Solve makes it possible to use Lp Solve algorithms
   1.176 -within Java. Although Clojure can use this  Java API directly, 
   1.177 -
   1.178 +There is a [[http://lpsolve.sourceforge.net/5.5/Java/README.html][Java API]] written by Juergen Ebert which enables Java
   1.179 +programs to use =lp_solve=. Although Clojure can use this Java API
   1.180 +directly, the interaction between Java, C, and Clojure is clumsy:
   1.181  
   1.182  ** The Farmer's Problem in Clojure
   1.183 +
   1.184  We are going to solve the same problem involving wheat and barley,
   1.185 -that we did above, but this time using clojure and the lpsolve API.
   1.186 -
   1.187 -#Because we ultimately intend to use Lp Solve to find optimal Pokemon type combinations.
   1.188 -# we want to solve linear optimization problems within Clojure, the language 
   1.189 -
   1.190 -** Setup
   1.191 -=lp_solve= is a crufty =C= program which already comes with a JNI
   1.192 -interface written by Juergen Ebert.  It's API is not
   1.193 -particularly friendly from a functional/immutable perspective, but
   1.194 -with a little work, we can build something that works great with
   1.195 -clojure.
   1.196 +that we did above, but this time using clojure and the =lp_solve= API.
   1.197  
   1.198  #+srcname: intro
   1.199  #+begin_src clojure :results silent
   1.200  (ns pokemon.lpsolve
   1.201 -  (:use rlm.ns-rlm))
   1.202 -(rlm.ns-rlm/ns-clone rlm.light-base)
   1.203 -(use 'clojure.set)
   1.204 -(import 'lpsolve.LpSolve)
   1.205 -(use '[clojure [pprint :only [pprint]]])
   1.206 +  (:use [clojure.contrib def set [seq :only [indexed]] pprint])
   1.207 +  (:import lpsolve.LpSolve)
   1.208 +  (:require pokemon.types)
   1.209 +  (:require incanter.core))
   1.210  #+end_src
   1.211  
   1.212 -The LpSolve Java interface is available from the same site as
   1.213 -=lp_solve= itself, http://lpsolve.sourceforge.net/ 
   1.214 -Using it is the same as many other =C=
   1.215 -programs. There are excellent instructions to get set
   1.216 -up.  The short version is that you must call Java with
   1.217 +The =lp_solve= Java interface is available from the same site as
   1.218 +=lp_solve= itself, http://lpsolve.sourceforge.net/ Using it is the
   1.219 +same as many other =C= programs. There are excellent instructions to
   1.220 +get set up.  The short version is that you must call Java with
   1.221  =-Djava.library.path=/path/to/lpsolve/libraries= and also add the
   1.222  libraries to your export =LD_LIBRARY_PATH= if you are using Linux. For
   1.223  example, in my =.bashrc= file, I have the line
   1.224 -=LD_LIBRARY_PATH=$HOME/roBin/lpsolve:$LD_LIBRARY_PATH=.
   1.225 -If everything is set-up correctly, 
   1.226 +=LD_LIBRARY_PATH=$HOME/roBin/lpsolve:$LD_LIBRARY_PATH=.  If everything
   1.227 +is set-up correctly,
   1.228  
   1.229  #+srcname: body 
   1.230  #+begin_src clojure :results verbatim :exports both
   1.231 @@ -287,6 +247,7 @@
   1.232  (declare solve get-results)
   1.233  #+end_src
   1.234  
   1.235 +
   1.236  *** Memory Management
   1.237  
   1.238  Every instance of =LpSolve= must be manually garbage collected via a
   1.239 @@ -339,7 +300,7 @@
   1.240      (slurp target)))
   1.241  
   1.242  (defn results
   1.243 -  "given an LpSolve object, solves the object and returns a map of the
   1.244 +  "Given an LpSolve object, solves the object and returns a map of the
   1.245    essential values which compose the solution."
   1.246    [#^LpSolve lps]
   1.247    (locking lps
   1.248 @@ -349,8 +310,9 @@
   1.249  	  optimal-values (do (.getVariables lps optimal-values)
   1.250  			     (seq optimal-values))
   1.251  	  variable-names
   1.252 -	  (doall ;; the doall is necessary since the lps object might
   1.253 -	   ;; soon be deleted
   1.254 +	  (doall 
   1.255 +           ;; The doall is necessary since the lps object might
   1.256 +	   ;; soon be deleted.
   1.257  	   (map
   1.258  	    #(.getColName lps (inc %))
   1.259  	    (range number-of-variables)))
   1.260 @@ -556,9 +518,9 @@
   1.261  are immutable.
   1.262  
   1.263  * Using LpSolve to find Immortal Types
   1.264 -** Converting the Pokemon problem into a linear form
   1.265 +** Converting the Pok\eacute{}mon problem into a linear form
   1.266  How can the original question about pok\eacute{}mon types be converted
   1.267 -into a linear problem? 
   1.268 +into a linear problem?
   1.269  
   1.270  Pokemon types can be considered to be vectors of numbers representing
   1.271  their susceptances to various attacking types, so Water might look
   1.272 @@ -621,9 +583,6 @@
   1.273  #+begin_src clojure :results silent
   1.274  (in-ns 'pokemon.lpsolve)
   1.275  
   1.276 -(require 'pokemon.types)
   1.277 -(require 'incanter.core)
   1.278 -
   1.279  (defn log-clamp-matrix [matrix]
   1.280    ;; we have to clamp the Infinities to a more reasonable negative
   1.281    ;; value because lp_solve does not play well with infinities in its
   1.282 @@ -652,7 +611,6 @@
   1.283  (defn all-neutral []
   1.284    (doall (map (constantly 0) (pokemon.types/type-names))))
   1.285  
   1.286 -
   1.287  ;; objective functions
   1.288  (defn number-of-types []
   1.289    (doall (map (constantly 1) (pokemon.types/type-names))))
   1.290 @@ -710,7 +668,6 @@
   1.291    (if (not (= (:status results) "OPTIMAL"))
   1.292      (:status results)
   1.293      (:solution results)))
   1.294 -
   1.295  #+end_src
   1.296  
   1.297  With this, we are finally able to get some results.
   1.298 @@ -954,11 +911,11 @@
   1.299   ":rock" 0.0}
   1.300  #+end_example
   1.301  
   1.302 -The best attacking type combination is strangely Dragon from the
   1.303 -original games.  It is neutral against all the original types except
   1.304 -for Dragon, which it is strong against.  There is no way to make an
   1.305 -attacking type that is strong against every type, or even one that is
   1.306 -strong or neutral against every type, in the new games.
   1.307 +The best attacking type combination is Dragon from the original games.
   1.308 +It is neutral against all the original types except for Dragon, which
   1.309 +it is strong against.  There is no way to make an attacking type that
   1.310 +is strong against every type, or even one that is strong or neutral
   1.311 +against every type, in the new games.
   1.312  
   1.313  
   1.314  *** Weakest Attack/Defense Combinations
   1.315 @@ -1038,7 +995,8 @@
   1.316  combination.
   1.317  
   1.318  It's so interesting that it takes 20 types to make an attack type that
   1.319 -is weak to all types that the combination merits further investigation.
   1.320 +is weak to all types that the combination merits further
   1.321 +investigation.
   1.322  
   1.323  Unfortunately, all of the tools that we've written so far are focused
   1.324  on defense type combinations.  However, it is possible to make every
   1.325 @@ -1345,11 +1303,11 @@
   1.326  
   1.327  * Summary
   1.328  
   1.329 -Overall, the pok\eacute{}mon type system is slanted more towards defense
   1.330 -rather than offense.  While it is possible to create superior
   1.331 -defensive types and exceptionally weak attack types, it is not possible to
   1.332 -create exceptionally weak defensive types or very powerful attack
   1.333 -types.
   1.334 +Overall, the pok\eacute{}mon type system is slanted more towards
   1.335 +defense rather than offense.  While it is possible to create superior
   1.336 +defensive types and exceptionally weak attack types, it is not
   1.337 +possible to create exceptionally weak defensive types or very powerful
   1.338 +attack types.
   1.339  
   1.340  Using the =lp_solve= library was more complicated than the best-first
   1.341  search, but yielded results quickly and efficiently. Expressing the
   1.342 @@ -1378,6 +1336,4 @@
   1.343  #+end_src
   1.344  
   1.345  
   1.346 -* COMMENT Stuff to do.
   1.347 -** TODO fix namespaces to not use rlm.light-base
   1.348