#' ROI plugin for COIN CBC
#'
#' @docType package
#' @keywords package
#' @name ROI.plugin.cbc
NULL
#' @noRd
solver_name <- ROI::ROI_plugin_get_solver_name(getPackageName())
#' @noRd
solver <- function(x, control) {
obj <- as.numeric(as.matrix(stats::terms(ROI::objective(x))[["L"]]))
# convert verbose control to cbc logLevel
# TODO: check how the control mechanism really works
verbose_in_control <- !is.null(control[["verbose"]])
if (verbose_in_control) {
control$logLevel <- if (control[["verbose"]]) 1 else 0
control$verbose <- NULL
}
n_cols <- length(obj)
# build column bounds
# 0 as lb is the default in ROI
col_lb <- rep.int(0, n_cols)
col_ub <- rep.int(Inf, n_cols)
col_types <- ROI::types(x)
if (!is.null(col_types)) {
stopifnot(length(col_types) == n_cols)
col_ub[col_types == "B"] <- 1
is_integer <- col_types %in% c("I", "B")
} else {
is_integer <- rep.int(FALSE, n_cols)
}
# build column bounds when they are differents from default in ROI
bounds <- ROI::bounds(x)
lb_ind <- bounds$lower$ind
lb_val <- bounds$lower$val
ub_ind <- bounds$upper$ind
ub_val <- bounds$upper$val
if (!is.null(lb_ind)) {
col_lb[lb_ind] <- lb_val
}
if (!is.null(ub_ind)) {
col_ub[ub_ind] <- ub_val
}
# build row bounds
constraints <- ROI::constraints(x)
row_dir <- constraints$dir
row_ub <- constraints$rhs
row_ub[row_dir == ">="] <- Inf
row_lb <- constraints$rhs
row_lb[row_dir == "<="] <- -Inf
mat <- constraints$L
mat <- Matrix::spMatrix(nrow(mat), ncol(mat), mat$i, mat$j, x = mat$v)
result <- rcbc::cbc_solve(
obj = obj,
mat = mat,
row_lb = row_lb,
row_ub = row_ub,
col_lb = col_lb,
col_ub = col_ub,
max = x$maximum,
is_integer = is_integer,
cbc_args = control
)
status_codes <- c(
"optimal" = 5L,
"infeasible" = 3L,
"unbounded" = 6L,
"nodelimit" = 7L,
"solutionlimit" = 8L,
"abandoned" = 9L,
"iterationlimit" = 10L,
"timelimit" = 11L
)
status_code <- status_codes[rcbc::solution_status(result)]
ROI::ROI_plugin_canonicalize_solution(
solution = rcbc::column_solution(result),
optimum = rcbc::objective_value(result),
status = status_code,
solver = solver_name
)
}
.onLoad <- function(libname, pkgname) {
solver_not_available <- !pkgname %in% ROI::ROI_registered_solvers()
if (solver_not_available) {
solver_signature <- ROI::ROI_plugin_make_signature(
objective = "L",
constraints = "L",
types = c(
"C", "I", "B",
"CI", "CB",
"IB", "CIB"
),
bounds = c("X", "V"),
maximum = c(
TRUE,
FALSE
)
)
ROI::ROI_plugin_get_solver_name(pkgname)
ROI::ROI_plugin_register_solver_method(
signatures = solver_signature,
solver = solver_name,
method = solver
)
# threads
ROI::ROI_plugin_register_solver_control(
solver_name,
"threads",
"X"
)
# from here
# https://projects.coin-or.org/CoinBinary/export/1059/OptimizationSuite/
# trunk/Installer/files/doc/cbcCommandLine.pdf
# pre processing
ROI::ROI_plugin_register_solver_control(
solver_name,
"prep",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"passp",
"X"
)
# Cut Generation
ROI::ROI_plugin_register_solver_control(
solver_name,
"cuts",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"clique",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"lift",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"mixed",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"two",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"knapsack",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"flow",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"probing",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"residual",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"cutD",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"cutL",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"passC",
"X"
)
# heuristics
ROI::ROI_plugin_register_solver_control(
solver_name,
"heur",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"round",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"feas",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"passF",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"local",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"pivotAndC",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"pivotAndF",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"combine",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"Combine2",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"rins",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"rens",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"vnd",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"divingG",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"divingP",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"divingF",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"divingS",
"X"
)
# limits
ROI::ROI_plugin_register_solver_control(
solver_name,
"sec",
"max_time"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"maxN",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"maxS",
"X"
)
ROI::ROI_plugin_register_solver_control(
solver_name,
"logLevel",
"verbosity_level"
)
ROI::ROI_plugin_add_status_code_to_db(
solver_name,
5L,
"optimal",
"Solution is optimal.",
0L
)
ROI::ROI_plugin_add_status_code_to_db(
solver_name,
3L,
"infeasible",
"Solution is infeasible."
)
ROI::ROI_plugin_add_status_code_to_db(
solver_name,
6L,
"unbounded",
"Solution is unbounded."
)
ROI::ROI_plugin_add_status_code_to_db(
solver_name,
7L,
"nodelimit",
"Node limit reached."
)
ROI::ROI_plugin_add_status_code_to_db(
solver_name,
8L,
"solutionlimit",
"Solution limit reached.",
0L
)
ROI::ROI_plugin_add_status_code_to_db(
solver_name,
9L,
"abandoned",
"Numerical instability."
)
ROI::ROI_plugin_add_status_code_to_db(
solver_name,
10L,
"iterationlimit",
"Iteration limit reached."
)
ROI::ROI_plugin_add_status_code_to_db(
solver_name,
11L,
"timelimit",
"Time limit reached.",
0L
)
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.