Using lp_solve in R

R is a language and environment for statistical computing and graphics. It is a GNU project which is similar to the S language and environment which was developed at Bell Laboratories (formerly AT&T, now Lucent Technologies) by John Chambers and colleagues. R can be considered as a different implementation of S. There are some important differences, but much code written for S runs unaltered under R. For more information or to download R please visit the R website.

There are currently two R packages based on lp_solve. The lpSolve R package provides high-level functions for solving general linear/integer problems, assignment problems and transportation problems. The lpSolveAPI R package provides an R API mirroring the lp_solve C API and hence provides a great deal more functionality but has a steeper learning curve. Both packages are available from CRAN.

Installation

To install the lpSolve package use the command command:

  > install.packages("lpSolve")
and to install the lpSolveAPI package use the command:
  > install.packages("lpSolveAPI")

Note

The > shown before each R command is the R prompt. Only the text after > must be entered.

Getting Help

Documentation is provided for each function in the lpSolve and lpSolveAPI packages using R's built-in help system. For example, the command

  > ?lp
will display the documentation for the lp function in the lpSolve package. The lpSolve package also contains the functions lp.assign and lp.transport which solve assignment and transportation problems. Read these three help files first. If you have a problem that can not be solved using one of these three functions you will have to use the lpSolveAPI package.

Building and Solving Linear Programs Using the lpSolveAPI R Package

The lpSolveAPI package provides an API for building and solving linear programs that mimics the lp_solve C API. This approach allows much greater flexibility but also has a few caveats. The most important is that the lpSolve linear program model objects created by make.lp and read.lp are not actually R objects but external pointers to lp_solve 'lprec' structures. R does not know how to deal with these structures. In particular, R cannot duplicate them. Thus one must never assign an existing lpSolve linear program model object in R code.

Consider the following example. First we create an empty model x.

  > x <- make.lp(2, 2)
Then we assign x to y.
  > y <- x
Next we set some columns in x.
  > set.column(x, 1, c(1, 2))
  > set.column(x, 2, c(3, 4))
And finally, take a look at y.
  > y
  Model name: 
              C1    C2         
  Minimize     0     0         
  R1           1     3  free  0
  R2           2     4  free  0
  Type      Real  Real         
  upbo       Inf   Inf         
  lowbo        0     0         
The changes we made in x appear in y as well. Although x and y are two distinct objects in R, they both refer to the same lp_solve 'lprec' structure.

The safest way to use the lpSolve API is inside an R function - do not return the lpSolve linear program model object.

Learning by Example
  > lprec <- make.lp(0, 4)
  > set.objfn(lprec, c(1, 3, 6.24, 0.1))
  > add.constraint(lprec, c(0, 78.26, 0, 2.9), ">=", 92.3)
  > add.constraint(lprec, c(0.24, 0, 11.31, 0), "<=", 14.8)
  > add.constraint(lprec, c(12.68, 0, 0.08, 0.9), ">=", 4)
  > set.bounds(lprec, lower = c(28.6, 18), columns = c(1, 4))
  > set.bounds(lprec, upper = 48.98, columns = 4)
  > RowNames <- c("THISROW", "THATROW", "LASTROW")
  > ColNames <- c("COLONE", "COLTWO", "COLTHREE", "COLFOUR")
  > dimnames(lprec) <- list(RowNames, ColNames)
Lets take a look at what we have done so far.
  > lprec  # or equivalently print(lprec)
  Model name: 
              COLONE    COLTWO  COLTHREE   COLFOUR          
  Minimize         1         3      6.24       0.1          
  THISROW          0     78.26         0       2.9  >=  92.3
  THATROW       0.24         0     11.31         0  <=  14.8
  LASTROW      12.68         0      0.08       0.9  >=     4
  Type          Real      Real      Real      Real          
  upbo           Inf       Inf       Inf     48.98          
  lowbo         28.6         0         0        18
Now lets solve the model.
  > solve(lprec)
  [1] 0

  > get.objective(lprec)
  [1] 31.78276

  > get.variables(lprec)
  [1] 28.60000  0.00000  0.00000 31.82759

  > get.constraints(lprec)
  [1]  92.3000   6.8640 391.2928

Note that there are some commands that return an answer. For the accessor functions (generally named get.*) the output should be clear. For other functions (e.g., solve), the interpretation of the returned value is described in the documentation. Since solve is generic in R, use the command

  > ?solve.lpExtPtr
to view the appropriate documentation. The assignment functions (generally named set.*) also have a return value - often a logical value indicating whether the command was successful - that is returned invisibly. Invisible values can be assigned but are not echoed to the console. For example,
  > status <- add.constraint(lprec, c(12.68, 0, 0.08, 0.9), ">=", 4)
  > status
  [1] TRUE
indicates that the operation was successful. Invisible values can also be used in flow control.