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.