While the R packages Rglpk, and lpSolveAPI are great interfaces for GLPK and lpsolve, the logic behind the development of these R wrappers was thinking in a single problem at a time, which is not good enough for me.
In another project that I’m working on, I need to solve a couple of
hundred (or thousand) problems at the same time. The good news are that
a lot of the structure of these problems is equal across instances,
which means that I can save time by just updating some parameters of the
LP and resolve it. Moreover, if all this could be done in a seemless way
using Rcpp, it would be
ideal. This was the main reason why I decided to write rcppglpk
.
Important Notice that the rcpp
is in lowercase.
You can install this package using devtools.
devtools::install_github("gvegayon/rcppglpk")
To compile it, you will need to have GNU GLPK installed in your system.
The following function is included in src/glpk-test.cpp
#include <rcppglpk.h>
using namespace Rcpp;
List glpk_example(
const NumericVector & obj,
const NumericMatrix & subj_lhs,
const NumericVector & subj_rhs,
const IntegerVector & cols_bnds_type,
const NumericVector & cols_bnds_lb,
const NumericVector & cols_bnds_ub,
const IntegerVector & rows_bnds_type,
const NumericVector & rows_bnds_lb,
const NumericVector & rows_bnds_ub,
int DIR,
const StringVector pname = "sample")
{
// Checking dimensions
if (obj.size() != subj_lhs.ncol())
stop("The objective function doesn't have as many columns in there are in constraints.");
if (subj_lhs.nrow() != subj_rhs.size())
stop("The constraints don't have as many rows as the RHS.");
// Creating the object
rcppglpk::LP lp(
obj,
subj_lhs,
subj_rhs,
// Columns
cols_bnds_type,
cols_bnds_lb,
cols_bnds_ub,
// Rows
rows_bnds_type,
rows_bnds_lb,
rows_bnds_ub,
DIR
);
// Calling the solver
lp.simplex();
return lp.getSol();
}
Things to point out:
-
The
rcppglpk.h
header includes Rcpp, so we don’t need to add it again. -
To create a new linear programming problem, we just typed
rcppglpk::LP
and passed the arguments. -
We called the
simplex
solver via the method of the same name. -
The method
getSol()
returns an object of classRcpp::List
with the value of the objective function, and the parameters.
Once compiled, we can call it in R:
library(rcppglpk)
# Brief example from de glpk manual:
# max:
# z = 10x_1 + 6x_2 + 4x_3
#
# subject to:
# p = x_1 + x_2 + x_3
# q = 10x_1 + 4x_2 + 5x_3
# r = 2x_1 + 2x_2 + 6x_3
#
# And bounds of variables
# p <= 100, 0 <= x_1
# q <= 600, 0 <= x_2
# r <= 300, 0 <= x_3
#
# Where (p,q,r) are auxiliary variables, and (x_1,x_2,x_2) are
# structural variables.
obj <- c(10, 6, 4)
subj_lhs <- matrix(c(1, 10, 2, 1, 4, 2, 1, 5, 6), ncol = 3)
subj_rhs <- c(100, 600, 300)
# Bounds
cols_bnds_type <- rep(GLP_LO, 3)
cols_bnds_lb <- cols_bnds_ub <- rep(0.0, 3)
rows_bnds_type <- rep(GLP_UP, 3)
rows_bnds_lb <- rep(0.0, 3)
rows_bnds_ub <- subj_rhs
lp(
obj, subj_lhs, subj_rhs,
cols_bnds_type, cols_bnds_lb, cols_bnds_ub,
rows_bnds_type, rows_bnds_lb, rows_bnds_ub,
DIR = GLP_MAX
)
#> $val
#> [1] 733.3333
#>
#> $par
#> [1] 33.33333 66.66667 0.00000
To use the header of rcppglpk
you need to add the following:
LinkingTo: Rcpp, rcppglpk
in yourDESCRIPTION
filePKG_LIBS = -lglpk
in yourMakevars
file (you need to have glpk in your system)
Voila! You should be able to compile your R package linking to
rcppglpk