# Non-numeric argument to binary operator in MILPModel of ompr package

I am familiar with how to use ompr::MIPModel but I am trying to learn how to use MILPModel to take advantage of the model build speed. A simplified version of my model is below. I have two decision variables, x and y, binary and of equal length. I have constraints on the sum of all the x decision variables, and the sum of all the y decision variables. So far so good with MILPModel, I can build the model and solve it fast.

The problem is when I try to use the next constraint. The LHS of this constraint multiplies the x binary decision variables by a numeric column in a dataframe of the same length, then multiplies that by a matrix where the rows are equal to the length of x. Similar story in the RHS with the y variable. I then iterate this constraint 20 times to represent all the columns of the matrix.

I've used constraints similar to this many times using MIPModel, but now when I try this I get an error message, non-numeric argument to binary operator. I assume this has something to do with the colwise function, but I am completely lost on how to approach this, even after reading up on the ompr github site.

add_variable(x[i], i=1:10, type='binary') %>%

#model builds and solves until this point...
sum_expr( x[i]* df$$numeric_column[i] * matrix_a[i,j],i=1:10) <= sum_expr( 2* y[i]* df$$numeric_column[i] * df\$other_numeric_column[i] * matrix_a[i,j],i=1:10),
j=1:20)

• I can confirm the error message but don't know the fix, so I contacted Dirk Schumacher, the author of OMPR. He said he'll take a look next week. Aug 9 '20 at 13:16
• Answered here: stackoverflow.com/questions/63294305/… Aug 9 '20 at 13:53
• @prubin I answered in my crosspost in SO. There were some gymnastics involved in adapting the matrix multiplication in the last constraint, to allow for vectorization. Also - I learned about OMPR from your blog a few years ago, thank you so much for what you've done for the OR community! Aug 9 '20 at 13:54

Adding a follow-up on how to style matrix multiplication-type constraints and objective function values. This has been a major pain point for me, and now that I have a template, this will be a real productivity boost as I switch to being "MILPModel native".

Replace SYMPHONY with the solver of your choice...


library(tidyverse)
library(magrittr)
library(ompr)
library(ompr.roi)
library(ROI.plugin.symphony)

rm(list=ls())

set.seed(42)

#in this example, mat1 is a numeric matrix representing coefficients for 40 binary decision variables
mat1 <- matrix(ncol=10,nrow=4,runif(400))

#define this function, it will be necessary for matrix multiplication inside a MILPModel
matrix_multiplication_fcn <- function(static_matrix, row_variable, column_variable){
vapply(seq_along(row_variable), function(k) static_matrix[row_variable[k], column_variable[k]], numeric(1L))  }

milp_model <- ompr::MILPModel() %>%
#total binaries ==10

#sum of binaries * mat1 <= 7
matrix_multiplication_fcn(static_matrix=mat1,row_variable=rowindex,column_variable=colindex)) *
assign_units[rowindex,colindex],
rowindex = 1:4, colindex = 1:10) <= 7) %>%

#objective: maximize value
set_objective(sum_expr(
ompr::colwise(matrix_multiplication_fcn(static_matrix=mat1,row_variable=rowindex,column_variable=colindex)) *
assign_units[rowindex,colindex],
rowindex=1:4,colindex=  1:10),sense='max')

milp_model_out <-  milp_model %>%
ompr::solve_model(with_ROI(solver = "symphony",verbosity=-2,gap_limit=0,time_limit=180, node_limit=-1,first_feasible=FALSE))

#same with MIPModel

mip_model <- ompr::MIPModel() %>%
#total binaries ==10

#sum of binaries * mat1 <= 7
rowindex = 1:4, colindex = 1:10) <= 7) %>%

#objective: maximize value
set_objective(sum_expr(mat1[rowindex,colindex] * assign_units[rowindex,colindex],
rowindex=1:4,colindex=  1:10),sense='max')

mip_model_out <-  mip_model %>%
ompr::solve_model(with_ROI(solver = "symphony",verbosity=-2,gap_limit=0,time_limit=180, node_limit=-1,first_feasible=FALSE))

#compare results, both should be slightly above 7 (thus slightly violating the constraint), I assume due to floating point issues
mip_model_out
milp_model_out
$$$$
`