Skip to content

Repository files navigation

coinclp

R-CMD-check

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.

Installation

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 coinclp

A note on Windows

Installing 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.

One call

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.875

constraints 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.

A model you keep

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.

Coming from clpAPI

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 versions

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.

Licence

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.

About

R interface to the COIN-OR Clp linear programming solver; a maintained replacement for the archived clpAPI package

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages