R/243_reductions_solvers_conic_solvers_glpk_mi_conif.R

#####
## DO NOT EDIT THIS FILE!! EDIT THE SOURCE INSTEAD: rsrc_tree/reductions/solvers/conic_solvers/glpk_mi_conif.R
#####

## CVXPY SOURCE: reductions/solvers/conic_solvers/glpk_mi_conif.py
## GLPK_MI conic solver interface for MILP problems (mixed-integer).
##
## Inherits from GLPK_Solver, overrides:
## - MIP_CAPABLE = TRUE
## - solver_name -> "GLPK_MI"
## - solve_via_data: passes integer/boolean variable types to Rglpk
## - reduction_invert: skips duals (not available for MIP)


# -- GLPK_MI_Solver class -------------------------------------------------------
## CVXPY SOURCE: glpk_mi_conif.py class GLPK_MI(GLPK)

GLPK_MI_Solver <- new_class("GLPK_MI_Solver", parent = GLPK_Solver,
  package = "CVXR",
  constructor = function() {
    new_object(S7_object(),
      .cache = new.env(parent = emptyenv()),
      MIP_CAPABLE = TRUE,
      BOUNDED_VARIABLES = FALSE,
      SUPPORTED_CONSTRAINTS = list(Zero, NonNeg),
      EXP_CONE_ORDER = NULL,
      REQUIRES_CONSTR = FALSE
    )
  }
)

method(solver_name, GLPK_MI_Solver) <- function(x) GLPK_MI_SOLVER

# -- solve_via_data --------------------------------------------------------------
## Override: add integer/boolean variable types for MILP.
## Rglpk types: "C" = continuous, "I" = integer, "B" = binary.

method(solve_via_data, GLPK_MI_Solver) <- function(x, data, warm_start = FALSE, verbose = FALSE,
                                                      solver_opts = list(), ...) {
  if (!requireNamespace("Rglpk", quietly = TRUE)) {
    cli_abort("Package {.pkg Rglpk} is required but not installed.")
  }

  c_vec <- data[[SD_C]]
  nvars <- length(c_vec)
  dims <- data[[SD_DIMS]]

  zero_dim <- dims@zero
  nonneg_dim <- dims@nonneg
  total_rows <- zero_dim + nonneg_dim

  A_solver <- data[[SD_A]]
  b_solver <- data[[SD_B]]

  ## Build constraint matrix and direction vector (same as GLPK_Solver)
  if (total_rows > 0L) {
    mat <- .dgC_to_stm(A_solver)

    dir <- character(total_rows)
    if (zero_dim > 0L) {
      dir[seq_len(zero_dim)] <- "=="
    }
    if (nonneg_dim > 0L) {
      dir[(zero_dim + 1L):(zero_dim + nonneg_dim)] <- "<="
    }

    rhs <- b_solver
  } else {
    mat <- slam::simple_triplet_matrix(
      i = integer(0), j = integer(0), v = numeric(0),
      nrow = 0L, ncol = nvars
    )
    dir <- character(0)
    rhs <- numeric(0)
  }

  ## Variable bounds: (-Inf, Inf) -- conic pipeline handles bounds
  bounds <- list(
    lower = list(ind = seq_len(nvars), val = rep(-Inf, nvars)),
    upper = list(ind = seq_len(nvars), val = rep(Inf, nvars))
  )

  ## Variable types: default continuous, override for integer/boolean
  types <- rep("C", nvars)

  bool_idx <- data[["bool_idx"]]
  if (length(bool_idx) > 0L) {
    for (idx in bool_idx) {
      types[idx] <- "B"
      ## Rglpk binary variables need [0,1] bounds
      bounds$lower$val[idx] <- max(bounds$lower$val[idx], 0)
      bounds$upper$val[idx] <- min(bounds$upper$val[idx], 1)
    }
  }

  int_idx <- data[["int_idx"]]
  if (length(int_idx) > 0L) {
    for (idx in int_idx) {
      types[idx] <- "I"
    }
  }

  ## Build control list
  ctrl <- list(canonicalize_status = FALSE, verbose = verbose)
  for (opt_name in names(solver_opts)) {
    ctrl[[opt_name]] <- solver_opts[[opt_name]]
  }

  ## Call Rglpk
  result <- Rglpk::Rglpk_solve_LP(
    obj     = c_vec,
    mat     = mat,
    dir     = dir,
    rhs     = rhs,
    bounds  = bounds,
    types   = types,
    max     = FALSE,
    control = ctrl
  )

  result
}

# -- reduction_invert ------------------------------------------------------------
## CVXPY SOURCE: glpk_mi_conif.py invert()
## No dual variables for MIP problems.

method(reduction_invert, GLPK_MI_Solver) <- function(x, solution, inverse_data, ...) {
  attr_list <- list()

  status_code <- solution$status
  status <- GLPK_STATUS_MAP[[as.character(status_code)]]
  if (is.null(status)) status <- SOLVER_ERROR

  if (status %in% SOLUTION_PRESENT) {
    opt_val <- solution$optimum + inverse_data[[SD_OFFSET]]

    primal_vars <- list()
    primal_vars[[as.character(inverse_data[[SOLVER_VAR_ID]])]] <- solution$solution

    ## No duals for MIP (matching CVXPY GLPK_MI.invert)
    Solution(status, opt_val, primal_vars, list(), attr_list)
  } else {
    failure_solution(status, attr_list)
  }
}

# -- print -----------------------------------------------------------------------

method(print, GLPK_MI_Solver) <- function(x, ...) {
  cat("GLPK_MI_Solver()\n")
  invisible(x)
}

Try the CVXR package in your browser

Any scripts or data that you put into this service are public.

CVXR documentation built on March 6, 2026, 9:10 a.m.