An R interface to COIN-OR Clp, the simplex and interior point linear programming solver of the COIN-OR project.
coinclp replaces the clpAPI
package, which was archived from CRAN on 2021-11-30 and took
ROI.plugin.clp with it in
January 2022. The bindings here are written from scratch against the current
Clp callable library, use registered .Call entry points and external
pointers with finalizers, and build on R 4.5 and R 4.6. A compatibility layer
reproduces clpAPI's exported functions so existing code runs unchanged.
Clp is not bundled; install the library first.
| Platform | Command |
|---|---|
| Windows | nothing to do: Rtools ships Clp (verified on Rtools 4.5) |
| Debian / Ubuntu | sudo apt-get install coinor-libclp-dev |
| Fedora / RHEL | sudo dnf install coin-or-Clp-devel |
| macOS | brew install clp |
| conda-forge | conda install coin-or-clp |
Then:
# install.packages("remotes")
remotes::install_github("SamLovick/coinclp")If Clp sits somewhere pkg-config does not look:
R CMD INSTALL coinclp \
--configure-args='--with-clp-include=/opt/clp/include/coin --with-clp-lib=/opt/clp/lib'The CLP_CFLAGS and CLP_LIBS environment variables do the same job and
work on every platform, Windows included:
CLP_CFLAGS="-I/opt/clp/include/coin" CLP_LIBS="-L/opt/clp/lib -lClp -lCoinUtils" \
R CMD INSTALL coinclpInstalling the binary from CRAN needs nothing at all: no Rtools, no
compiler, no COIN-OR installation. Clp is a static library in the Rtools
tree, so it ends up inside coinclp.dll, whose only runtime dependencies
are R.dll and the C runtime.
Building from source on Windows — which is what install_github() does
— needs Rtools, as any package with compiled code does. Clp is present in
the Rtools 4.5 toolchain, which is what this package is tested against, and
in 4.3 and 4.4, which use the same library tree. Rtools 4.2 and earlier do
not carry Clp, so on R 4.2 or older either point the build at your own Clp
with CLP_CFLAGS and CLP_LIBS, or use a current R.
library(coinclp)
# maximise 143x + 60y subject to
# 120x + 210y <= 15000
# 110x + 30y <= 4000
# x + y <= 75
A <- rbind(c(120, 210), c(110, 30), c(1, 1))
res <- clp_solve(c(143, 60), A, "<=", c(15000, 4000, 75), max = TRUE)
res$objval # 6315.625
res$solution # 21.875 53.125
res$duals # 0.000 1.0375 28.875constraints accepts a dense matrix, a sparse Matrix object, a
slam::simple_triplet_matrix, or a list of i/j/v triplets. Ranged
constraints are written with row_lower and row_upper instead of
dir/rhs.
The full callable library is available for building a model once and re-solving it as it changes, which is where Clp earns its keep:
model <- clp_model()
clp_load_problem(model, ncols = 2, nrows = 3,
start = c(0L, 3L, 6L),
index = c(0L, 1L, 2L, 0L, 1L, 2L),
value = c(120, 110, 1, 210, 30, 1),
obj = c(-143, -60),
rowub = c(15000, 4000, 75))
clp_initial_solve(model)
clp_objective_value(model) # -6315.625
basis <- clp_status_array(model) # keep the optimal basis
clp_set_row_upper(model, c(15000, 4000, 70))
clp_copyin_status(model, basis) # warm start
clp_dual_simplex(model) # re-solves in 0 iterations
clp_free(model)Also bound: presolve options (clp_options() and the clp_options_*
setters), barrier and idiot crash entry points, row and column names, MPS
input and output, model snapshots, infeasibility and unboundedness rays, and
every tolerance and limit Clp exposes.
Row and column positions in the clp_* bindings are 0-based, matching the
Clp documentation. clp_solve(), clp_matrix() and the name accessors use
ordinary 1-based R positions.
Every function clpAPI exported is here with the same name and arguments, so
older scripts need only a new library() line:
lp <- initProbCLP()
setLogLevelCLP(lp, 0)
loadProblemCLP(lp, 2, 3, c(0, 3, 6), c(0, 1, 2, 0, 1, 2),
c(120, 110, 1, 210, 30, 1),
lb = c(0, 0), ub = c(1e30, 1e30), obj_coef = c(143, 60),
rlb = rep(-1e30, 3), rub = c(15000, 4000, 75))
setObjDirCLP(lp, -1)
solveInitialCLP(lp)
getObjValCLP(lp) # 6315.625
delProbCLP(lp)The clpPtr S4 class, its accessors and the status_codeCLP() /
return_codeCLP() helpers behave as before. New code should prefer the
clp_* interface.
Clp 1.16 or later works. A few entry points were added to the C API after
the 1.17 series (Clp_writeMps, Clp_modifyCoefficient, Clp_setRowName,
Clp_setColumnName); configure detects them by link test, and
clp_features() reports what the current build has. Where Clp_writeMps is
missing — including the Clp 1.17.0 that Rtools ships — clp_write_mps()
falls back to an MPS writer implemented in R.
The package is released under the Eclipse Public License, matching COIN-OR. Clp itself is a separate work under EPL 2.0 and is not distributed here.
Prior art: the clpAPI package by Gabriel Gelius-Dietrich (GPL-3) defined the
*CLP function names that the compatibility layer reproduces; none of its
code is used here.