dirkschumacher / ompr

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

MILPModel: constraint matrix * variable vector - revisited #328

Open sbmack opened 3 years ago

sbmack commented 3 years ago

This issue has been posted several times. I have not been able to discover a work-around beyond using an external for loop. To recap:

m <- matrix(2:10, ncol = 3, byrow = TRUE)
rhs <- c(30, 60, 90)

model <- MIPModel() %>% 
      add_variable(x[i], i = 1:3, lb = 0) %>% 
      set_objective(sum_expr(x[i], i = 1:3)) %>% 
      add_constraint(sum_expr(m[j, i] * x[i], i = 1:3) <= rhs[j], j = 1:3)

Works, while:

model <- MILPModel() %>% 
      add_variable(x[i], i = 1:3, lb = 0) %>% 
      set_objective(sum_expr(x[i], i = 1:3)) %>% 
      add_constraint(sum_expr(colwise(m[j, i]) * x[i], i = 1:3) <= rhs[j], j = 1:3)

Fails with the error: Error in colwise(m[j, i]) * x[i] : non-numeric argument to binary operator

The loop solution does work:

model <- MILPModel() %>% 
      add_variable(x[i], i = 1:3, lb = 0) %>% 
      set_objective(sum_expr(x[i], i = 1:3))
      for(j in 1:3){
            model %<>% add_constraint(sum_expr(m[j, i] * x[i], i = 1:3) <= rhs[j])
      }

However, the obvious preference is using only ompr elements inside of an ompr formulation. Has anyone come up with a generalized solution for multiplying a matrix block of constraint coefficients and a variable vector? Dirk, are you planning on working on a fix for this? Any feedback appreciated. SteveM

dirkschumacher commented 3 years ago

Thanks @sbmack for bringing this up again. I will try to look into this. I think the general problem is that the semantics of MILPModel are unexpected in certain situations and don't always work well in multi-dimensional contexts.

sbmack commented 3 years ago

Thanks @sbmack for bringing this up again. I will try to look into this. I think the general problem is that the semantics of MILPModel are unexpected in certain situations and don't always work well in multi-dimensional contexts.

Dirk, thanks for the reply. Without that capability, MILPModel is not really a viable alternative to MIPModel because almost all constraint sets are defined by blocks of the same type that have associated coefficient matrices .

What is strange is that m[j, i] * x[i]indexed over i, jfails with MILPModel but the single constraint, e.g. m[1, i] where j is fixed to 1 works. So something is going on with that one index.

As an aside. would it make sense to embed the colwise function inside of the MILPModel source code? In other words, a model coefficient vector would be converted without the need for the colwise wrapper.

BTW, ompr has great potential I think because R allows the user to do his/her data processing external to the model manager and just use simple constraint definitions. I hope you can repair this bug without too much trouble.

Thanks again for your effort and time.

Regards,

SteveM

dirkschumacher commented 3 years ago

On a side note: if you feel adventures, I started to experiment with ideas for a better modelling system (that may or may not be the next major version of ompr).

options(repos = c(
  ropt = 'https://r-opt.r-universe.dev',
  CRAN = 'https://cloud.r-project.org'))

# Install some packages
install.packages("rmpk")
install.packages("ROIoptimzer")

# load the packages
library(rmpk)
library(ROIoptimzer)
library(ROI.plugin.glpk)

m <- matrix(2:10, ncol = 3, byrow = TRUE)
rhs <- c(30, 60, 90)
model <- optimization_model(ROI_optimizer("glpk"))
x <- model$add_variable("x", i = 1:3, lb = 0)
model$set_objective(sum_expr(x[i], i = 1:3), sense = "max")
model$add_constraint(sum_expr(m[j, i] * x[i], i = 1:3) <= rhs[j], j = 1:3)
model$optimize()
model$get_variable_value(x[i])
#>   name i value
#> 1    x 1 11.25
#> 2    x 3  0.00
#> 3    x 2  0.00
sbmack commented 3 years ago

On a side note: if you feel adventures, I started to experiment with ideas for a better modelling system (that may or may not be the next major version of ompr).

Installed fine and it works. Nice job. Thanks. I will test it with other models.

Happy to be a future tester as you continue development.

Regards,

SteveM

BTW, I created and uploaded 3 ompr toy models as shiny/flexdashboard apps:

Call Center Staffing

Cell Tower Locations

Project Portfolio Selection

lucazav commented 3 years ago

I'm facing the same "non-numeric argument to binary operator" error with MILP using this:

model <- MIPModel() %>% 
    add_variable( x[i, j], i = 1:n_warehouses, j = 1:n_countries, type = "integer" ) %>% 
    set_objective( sum_expr(cost_matrix[i, j] * x[i, j], i = 1:n_warehouses, j = 1:n_countries), sense = 'min' )

I think that this syntax must be allowed by MILP, otherwise the usability is lost.