dirkschumacher / ompr

R package to model Mixed Integer Linear Programs
https://dirkschumacher.github.io/ompr/
Other
268 stars 35 forks source link

Same issue translating a MIPModel to MILPModel #256

Open yeahthisiscuddy opened 5 years ago

yeahthisiscuddy commented 5 years ago

I am sorry to bring this up again, but I can't find a solution to a common problem and it's driving me crazy. I have this code that works fine in MIPModel:

a <- matrix(sample(0:1,3*2, replace=TRUE),3,2)

model <- MIPModel() %>% add_variable(x[i], i=1:3, type="binary") %>% add_variable(g[t], t=1:2, type="binary") %>% add_constraint(g[t]<=sum_expr(a[i, t]*x[i], i=1:3), t=1:2) %>% add_constraint(sum_expr(g[t], t=1:2)>=2)

But throws off the "non-numeric" error in MILP on that first constraint.

model2 <- MILPModel() %>% add_variable(x[i], i=1:3, type="binary") %>% add_variable(g[t], t=1:2, type="binary") %>% add_constraint(g[t]<=sum_expr(a[i, t]x[i], i=1:3), t=1:2) %>% #Error in a[i, t] x[i] : non-numeric argument to binary operator add_constraint(sum_expr(g[t], t=1:2)>=2)

yeahthisiscuddy commented 5 years ago

I got it to stop erroring out with a function instead of a matrix:

a <- matrix(sample(0:1,3*2, replace=TRUE),3,2)

afun <- function(i, t) { vapply(seq_along(i), function(k) a[i[k], t[k]], numeric(1L)) }

model2 <- MILPModel() %>% add_variable(x[i], i=1:3, type="binary") %>% add_variable(g[t], t=1:2, type="binary") %>%

add_constraint(sum_expr(x[i], i=1:3)<3) %>%

add_constraint(g[t]<=sum_expr(a2[i]x[i], i=1:3), t=1:2) %>% #Error in a[i, t] x[i] : non-numeric argument to binary operator

add_constraint(g[t] <= sum_expr(afun(i,t)*x[i], i=1:3), t=1:2) %>% add_constraint(sum_expr(g[t], t=1:2)>=1)

But when I run the solution it comes up 0s. Any help would be much appreciated.

yeahthisiscuddy commented 5 years ago

Loosening this constraint:

add_constraint(sum_expr(g[t], t=1:2)>=1)

to >=0 gets me results, but I still want to limit the rows it can choose from so it's not doing what I'm looking for.

I thnk the problem is still in this constraint:

add_constraint(g[t] <= sum_expr(afun(i,t)*x[i], i=1:3), t=1:2)

I added a colwise around the function "afun," but that didn't help either.

Really struggling here. Any help would be much much appreciated.

EnhaoLiu commented 5 years ago

Hi, I had the same problem before but later I figure it out.

Firstly, you have to update your ompr and ompr.roi to the latest version because the colwise() function has been updated.

devtools::install_github("dirkschumacher/ompr")
devtools::install_github("dirkschumacher/ompr.roi")

Let's assume the a matrix is

a <- matrix(c(1, 1, 1, -1,  -1, -1),
            nrow = 3,
            ncol = 2)

a = [,1] [,2] [1,] 1 -1 [2,] 1 -1 [3,] 1 -1

The afunc should be a function that returns a vector. In this case, it should be (1, 1, 1, -1, -1, -1) when i = 1:3 and t = 1:2.

afunc <- function(i,t){
  a_sub <- a[i, t] # get the `a` matrix accroding to i range and t range
  a_vec <- as.vector(a_sub) # convert `a_sub` matrix to be vector (1 1 1 -1 -1 -1)
  return(a_vec)
}

The tricky thing is that x[i] for i = 1:3 only contains three elements. The current version of colwise() cannot partition the vector (1 1 1 -1 -1 -1) to be (1, 1,1) and (-1, -1, -1) when iterating t from 1 to 2.

Note that colwise() is not able to do this because variable x only contains one dimension. I will show an example later to explain this.

Therefore, we should write a loop for t to do this.

model2 <- MILPModel() %>%
  add_variable(x[i], i=1:3, type="binary") %>%
  add_variable(g[t], t=1:2, type="binary") 
for (t in 1:2){
  model2 <- add_constraint(model2, g[t] <= sum_expr(colwise(afunc(i, t)) * x[i], i=1:3), t = t)
}

#check results
model2$constraints

As mentioned before, I thought the above things might be a bug in the currently developing version of colwise() because if we set a new variable y[i, j], i = 1:3 and j = 1:5. Also, the coefficients of y is the same as x. We could see that colwise() works good without writing the loop.

model2 <- MILPModel() %>%
  add_variable(x[i], i=1:3, type="binary") %>%
  add_variable(g[t], t=1:2, type="binary") %>%
  add_variable(y[i,j], i = 1:3, j = 1:5)%>%
  add_constraint(g[t] <= sum_expr(colwise(afunc(i, t)) * y[i,j], i=1:3), t = 1:2, j =1:5)

# for (t in 1:2){
#   model2 <- add_constraint(model2, g[t] <= sum_expr(colwise(afunc(i, t)) * x[i], i=1:3), t = t)
# }

#check results
model2$constraints