Skip to main content

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

Answered

Comments

7 comments

  • Official comment
    Simranjit Kaur
    • Gurobi Staff
    This post is more than three years old. Some information may not be up to date. For current information, please check the Gurobi Documentation or Knowledge Base. If you need more help, please create a new post in the community forum, or try Gurobot, our chatbot interface offering instant, expert-level support.
  • Eli Towle
    • 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

    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

    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

Post is closed for comments.