Skip to main content

binary programming for 0/m instead of 0/1 variables

Answered

Comments

6 comments

  • Eli Towle
    Gurobi Staff Gurobi Staff

    You could introduce auxiliary binary variables \( z \in \{0,1\}^n \), then add the constraint \( x_i = m z_i\) for \( i = 1, \ldots, n \). This way, each \( x_i \) will be equal to \( 0 \) or \( m \).

    0
  • Xiaoyu Shan
    Gurobi-versary
    First Question
    First Comment

    Thanks for the comment! What if the value of m is also unknown? i.e., m is also an unknown variable that I need to find out with optimization?

    0
  • Eli Towle
    Gurobi Staff Gurobi Staff

    You could define \( m \) to be a nonnegative variable. Then, those same constraints include the product of a binary variable and a continuous variable. Fortunately, there is an equivalent linear formulation of this product that Gurobi will automatically apply during presolve. To help Gurobi out, be sure to define a strong upper bound on the new \( m \) variable.

    0
  • Xiaoyu Shan
    Gurobi-versary
    First Question
    First Comment

    I think I conceptually got it but find it hard to write codes for introducing new auxiliary variables. So now the problem becomes min(x'Qx-c'x), s.t. x=mz, z = 0 or 1, 0=<m<=2 (2 for instance), right? Does it mean that x, z, m are all variables to solve now? If so, should the Q and c in my objective also be changed?

    Could you please show an example code of how to introduce such "auxiliary variables" in R?

    0
  • Eli Towle
    Gurobi Staff Gurobi Staff

    So now the problem becomes min(x'Qx-c'x), s.t. x=mz, z = 0 or 1, 0=<m<=2 (2 for instance), right? Does it mean that x, z, m are all variables to solve now? If so, should the Q and c in my objective also be changed?

    Yes, that problem statement is correct, and we are indeed optimizing over \(x\), \(z\), and \(u\) now. Though to be a bit more explicit with the dimensions of the variables, I would write the problem as follows (renaming \( m \) to \( u \), since using \( m \) as a variable can be confusing):

    $$\begin{alignat*}{2} \min_{x,z,u}\ && x^\top &Q x - c^\top x && \\ \textrm{s.t.}\ && x_i &= u z_i && i = 1, \ldots, n \\ && z &\in \{0, 1\}^n \quad && \\ && u &\in [0,2]. &&\end{alignat*}$$

    Your objective can stay exactly the same; the purpose of the additional variables and constraints is to ensure each \( x_i \) is equal to either \( 0 \) or \( u \).

    Could you please show an example code of how to introduce such "auxiliary variables" in R?

    Below is an example that minimizes \( \sum_{i = 1}^n (n-i+1) x_i^2 - \sum_{i = 1}^n i x_i \). Introducing additional variables in R requires increasing the dimension of your matrices/vectors to account for the increased number of model variables/columns. You can read more about the different named components featured below in Gurobi's R documentation. The qp.R and qcp.R examples are also useful references for quadratic problems like this.

    library(gurobi)

    # total number of variables is 2n+1
    n <- 10

    model <- list()
    model$A <- matrix(c(rep(0,2*n), 1), nrow=1, byrow=T)
    model$rhs <- c(2.0) # upper bound on u
    model$sense <- c('<')
    model$obj <- c(-(1:n), rep(0, n+1))
    model$Q <- spMatrix(2*n+1, 2*n+1, 1:n, 1:n, n:1)
    model$vtype <- c(rep('C', n), rep('B', n), 'C')
    model$varnames <- c(sprintf('x[%s]', 1:n), sprintf('z[%s]', 1:n), 'u')

    qcs = list()
    for (i in 1:n) {
    qcs[[i]] <- list()
    qcs[[i]]$Qc <- spMatrix(2*n+1, 2*n+1, c(n+i), c(2*n+1), c(-1.0))
    qcs[[i]]$rhs <- 0
    qcs[[i]]$q <- c(rep(0, i-1), 1, rep(0, 2*n+1-i))
    qcs[[i]]$sense <- '='
    qcs[[i]]$name <- sprintf('set_x[%s]',i)
    }
    model$quadcon <- qcs

    result <- gurobi(model)

    print(result$objval)
    print(result$x)

    # Write an LP file for visual inspection
    gurobi_write(model, 'model.lp')
    0
  • Xiaoyu Shan
    Gurobi-versary
    First Question
    First Comment

    This is very helpful. Thanks!!

    0

Please sign in to leave a comment.