dirkschumacher / ompr

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

Modelling with MILP - variable mapping #253

Open balintba opened 5 years ago

balintba commented 5 years ago

Hello,

first of all many thanks for the excellent package! I have a question regarding variable mapping with the MILP model. I would like to speed up things and that is why I want to switch to this newer model. I was reading through all the previous questions, but still feel a little bit unsure. In the documentation I have seen that there is a possibility to create a grid and pass the values in the grid directly to variables, which speed things up and make different conditional statements unnecessary. I tried to create a small example, just to see how things work but was not really successful... :(

`#Creating a grid as in the documentation example grid <- expand.grid(i = 1:8, j = 1:8)

defining some arbitrary points in the grid

dd <- c(3,5,1,6,3) ee <- c(5,5,6,6,6)

Defining a diagonal

grid_2 <- grid[which(grid$i == grid$j),]

milp_model <- MILPModel() %>% add_variable(x[grid$i, grid$j],type = "binary") %>% set_objective(sum_expr(x[grid_2$i,grid_2$j]), sense = "max") %>% add_constraint(x[dd,ee] == 0)

solution_milp <- solve_model(milp_model, with_ROI("cbc", sec = 120))`

Now please note, that I referenced everywhere the direct index of the variable x. If I check the model, it returns:

Mixed integer linear optimization problem Variables: Continuous: 0 Integer: 0 Binary: 64 Model sense: maximize Constraints: 5

Checking the variables:

$x $x$name [1] "x"

$x$arity [1] 2

$x$type [1] "binary"

$x$lb [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

$x$ub [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

$x$indexmapping variable V1 V2 col 1: x 1 1 1 2: x 2 1 2 3: x 3 1 3 4: x 4 1 4 5: x 5 1 5 6: x 6 1 6 7: x 7 1 7 8: x 8 1 8 9: x 1 2 9 10: x 2 2 10 11: x 3 2 11 12: x 4 2 12 13: x 5 2 13 14: x 6 2 14 15: x 7 2 15 16: x 8 2 16 17: x 1 3 17 18: x 2 3 18 19: x 3 3 19 20: x 4 3 20 21: x 5 3 21 22: x 6 3 22 23: x 7 3 23 24: x 8 3 24 25: x 1 4 25 26: x 2 4 26 27: x 3 4 27 28: x 4 4 28 29: x 5 4 29 30: x 6 4 30 31: x 7 4 31 32: x 8 4 32 33: x 1 5 33 34: x 2 5 34 35: x 3 5 35 36: x 4 5 36 37: x 5 5 37 38: x 6 5 38 39: x 7 5 39 40: x 8 5 40 41: x 1 6 41 42: x 2 6 42 43: x 3 6 43 44: x 4 6 44 45: x 5 6 45 46: x 6 6 46_ 47: x 7 6 47 48: x 8 6 48 49: x 1 7 49 50: x 2 7 50 51: x 3 7 51 52: x 4 7 52 53: x 5 7 53 54: x 6 7 54 55: x 7 7 55 56: x 8 7 56 57: x 1 8 57 58: x 2 8 58 59: x 3 8 59 60: x 4 8 60 61: x 5 8 61 62: x 6 8 62 63: x 7 8 63 64: x 8 8 64 variable V1 V2 col

Checking the constraints:

[[1]] $lhs An object of class "LinearVariableCollection" Slot "variables": variable row col coef 1: x 1 35 1 2: x 2 37 1 3: x 3 41 1 4: x 4 46 1 5: x 5 43 1

Slot "index_mapping": function (x) model$var_index_mapping_list[[x]] <bytecode: 0x000000003380c020> <environment: 0x0000000032357ec0>

$sense [1] "=="

$rhs [1] 0

attr(,"class") [1] "milp_model_constraint"

Now I was hoping to maximize the values of the variables where i == j, the diagonal so to say. Some of the constraints are superfluous as they do not concern the diagonal value. I have indicated in the variable list, the instances which are influenced by the constraints I set. Everything seems to be fine. This is of course a very simple problem, and I believe the result of it should be:

x[1,1] = 1, x[2,2] = 1, x[3,3] = 1, x[4,4] = 1, x[5,5] = 0, x[6,6] = 0, x[7,7] = 1, x[8,8] = 1

x[5,5] and x[6,6] should be 0 according to the constraint.

However if I solve this maximization problem, the solution returns a solution with objective value 0 - I was hoping to see obj. value 6 - and indeed all of the binary values are 0

Every value is zero. It is really strange. What did I miss? I was hoping to summarize the diagonal values and I was searching for the values which maximize the sum of the diagonal. "Colwise" is a bit difficult to work with, as I see others also had some difficulties with it, but I believe I understand the underlying concept and intention. I tried to include this expression in the objective function, no difference in results.

It could be really nice, if I could refer to the indexes as displayed above, since I have a complex problem to solve, I just cannot understand why the solver returns this strange result.

Thanks for your help in advance!

Best regards, Balazs Balint

hugolarzabal commented 5 years ago

HI, That would be the way to use colwise in order to obtain the right model:

milp_model <- MILPModel() %>%
  add_variable(x[grid$i, grid$j],type = "binary") %>%
  set_objective(sum_expr(x[i,colwise(grid_2$j)], i = grid_2$i), sense = "max") %>%
  add_constraint(x[dd,ee] == 0)

Expressions inside sum_expr do not behave exactly the same way as in add_constraint which can be often confusing.

For debugging, you can execute the sum_expr expression alone to see what it contains:

sum_expr(x[i,colwise(grid_2$j)], i= grid_2$i )
x[1L, colwise(grid_2$j)] + x[2L, colwise(grid_2$j)] + x[3L, colwise(grid_2$j)] + 
    x[4L, colwise(grid_2$j)] + x[5L, colwise(grid_2$j)] + x[6L, 
    colwise(grid_2$j)] + x[7L, colwise(grid_2$j)] + x[8L, colwise(grid_2$j)]

I do agree that this behavious of sum_expr is really confusing. It took me several trials and error to find the right way to write it.