The ompr.xpress
package allows the use of the FICO Xpress optimizer to
solve mixed integer and linear programming problems with the OMPR
package.
A FICO Xpress installation and xpress
package installation are
required for ompr.xpress
to function. The xpress
package is not
available on CRAN, but is rather included with downloads of the Xpress
solver from FICO for Xpress verions greater than 8.13.
If a commercial licensed installation is not already available to you, a community version can be download from the link below. Community license is limited to problem with rows + columns <= 5000.
FICO® Xpress Community License | FICO
Installation instructions for the xpress
package are located inside
the directory of the Xpress installation. Instructions from FICO are at
the link below:
Installation of the R and Python packages (fico.com)
You can install the development version of ompr.xpress from GitHub with:
# install.packages("devtools")
devtools::install_github("bmdahl1/ompr.xpress")
We can use a simple police dispatch shift scheduling problem:
A police department must employ a specified number of dispatchers for all 4-hour shifts throughout the day. Each dispatcher must work an 8-hour shift, and shifts from 2000 - 0800 earn a higher wage rate.
The goal of the optimization will be to minimize total wage costs while supplying all needed dispatchers.
Shift.Time | Required | Shift Rate |
---|---|---|
0000 - 0400 | 6 | $45.00 |
0400 - 0800 | 7 | $45.00 |
0800 - 1200 | 13 | $35.00 |
1200 - 1600 | 13 | $35.00 |
1600 - 2000 | 9 | $35.00 |
2000 - 0000 | 6 | $45.00 |
suppressWarnings(suppressMessages(library(ompr.xpress)))
suppressWarnings(suppressMessages(library(ompr)))
suppressWarnings(suppressMessages(library(xpress)))
# Set Shift Parameters
shift_required <- c(6,7,13,13,9,6)
shift_rate <- c(45, 45, 35, 35, 35, 45)
n_shifts <- 6
# Create OMPR Model
model <- MIPModel() |>
add_variable(start_shift[s], type = 'integer', s = 1:n_shifts, lb = 0) |>
add_variable(on_shift[s], type = 'continuous', s = 1:n_shifts, lb = 0) |>
add_constraint(on_shift[s] == (start_shift[s] + start_shift[s-1]), s = 2:n_shifts) |>
add_constraint(on_shift[s] == start_shift[s] + start_shift[n_shifts], s = 1) |>
add_constraint(on_shift[s] >= shift_required[s], s = 1:n_shifts) |>
set_objective(sum_over(on_shift[s]*shift_rate[s], s = 1:n_shifts), sense = 'min')
# Solve with Xpress
model_results <- model |>
solve_model(xpress_optimizer())
#>
#> Final MIP objective : 2150
#> Final MIP bound : 2150
#> Solution time / primaldual integral : 0s / 0.00%
#> Number of solutions found / nodes : 3 / 0
#> MIPSTATUS: 6
Shift Time | Shift.Rate | Decision Variables | Required | ||
---|---|---|---|---|---|
Starting | On Shift | Total Hourly Wages | |||
0000 - 0400 | 45 | 0 | 6 | 270 | 6 |
0400 - 0800 | 45 | 7 | 7 | 630 | 7 |
0800 - 1200 | 35 | 6 | 13 | 1365 | 13 |
1200 - 1600 | 35 | 9 | 15 | 2100 | 13 |
1600 - 2000 | 35 | 0 | 9 | 1575 | 9 |
2000 - 0000 | 45 | 6 | 6 | 1620 | 6 |
Sensitivity Analysis will be performed on both LP and MIP problems. When the problem is MIP, then all integer variables will be fixed to the solution from the mixed integer solution, and the problem will be rerun as an LP to perform the sensitivity analysis.
Returns upper and lower sensitivity ranges for specified objective
function coefficients.
If the objective coefficients are varied within these ranges the current
basis remains optimal and the reduced costs remain valid.
(objsa
(fico.com))
Objective Function Sensitivity Analysis | ||
Variable | lower | upper |
---|---|---|
start_shift[1] | -90 | 100000000000000000000 |
start_shift[2] | -80 | 100000000000000000000 |
start_shift[3] | -70 | 100000000000000000000 |
start_shift[4] | -70 | 100000000000000000000 |
start_shift[5] | -80 | 100000000000000000000 |
start_shift[6] | -90 | 100000000000000000000 |
on_shift[1] | -100000000000000000000 | 100000000000000000000 |
on_shift[2] | -100000000000000000000 | 100000000000000000000 |
on_shift[3] | -100000000000000000000 | 100000000000000000000 |
on_shift[4] | -100000000000000000000 | 100000000000000000000 |
on_shift[5] | -100000000000000000000 | 100000000000000000000 |
on_shift[6] | -100000000000000000000 | 100000000000000000000 |
Returns upper and lower sensitivity ranges for specified variables’
lower and upper bounds.
If the bounds are varied within these ranges the current basis remains
optimal and feasible.
Upper and Lower Bounds Sensitivity Analysis | ||||
Variable | lblower | lbupper | ublower | ubupper |
---|---|---|---|---|
start_shift[1] | -0.000001 | 100000000000000000000 | 0 | 100000000000000000000 |
start_shift[2] | 6.999999 | 100000000000000000000 | 7 | 100000000000000000000 |
start_shift[3] | 5.999999 | 100000000000000000000 | 6 | 100000000000000000000 |
start_shift[4] | 8.999999 | 100000000000000000000 | 9 | 100000000000000000000 |
start_shift[5] | -0.000001 | 100000000000000000000 | 0 | 100000000000000000000 |
start_shift[6] | 5.999999 | 100000000000000000000 | 6 | 100000000000000000000 |
on_shift[1] | -100000000000000000000.000000 | 6 | 6 | 100000000000000000000 |
on_shift[2] | -100000000000000000000.000000 | 7 | 7 | 100000000000000000000 |
on_shift[3] | -100000000000000000000.000000 | 13 | 13 | 100000000000000000000 |
on_shift[4] | -100000000000000000000.000000 | 15 | 15 | 100000000000000000000 |
on_shift[5] | -100000000000000000000.000000 | 9 | 9 | 100000000000000000000 |
on_shift[6] | -100000000000000000000.000000 | 6 | 6 | 100000000000000000000 |
Returns upper and lower sensitivity ranges for specified right hand side
(RHS) function coefficients.
If the RHS coefficients are varied within these ranges the current basis
remains optimal and the reduced costs remain valid.
Righ-Hnd Side Sensitivity Analysis | ||
constraint | lower | upper |
---|---|---|
1 | -0.000001 | 100000000000000000000.000000 |
2 | -0.000001 | 100000000000000000000.000000 |
3 | -2.000001 | 100000000000000000000.000000 |
4 | -0.000001 | 100000000000000000000.000000 |
5 | -0.000001 | 100000000000000000000.000000 |
6 | -0.000001 | 100000000000000000000.000000 |
7 | -100000000000000000000.000000 | 6.000001 |
8 | -100000000000000000000.000000 | 7.000001 |
9 | -100000000000000000000.000000 | 13.000001 |
10 | -100000000000000000000.000000 | 15.000001 |
11 | -100000000000000000000.000000 | 9.000001 |
12 | -100000000000000000000.000000 | 6.000001 |
The dual values for the row constraints automatically generated from the LP optimize function.
Row Constraint Dual Values | |
Constraint | Duals |
---|---|
1 | 45 |
2 | 35 |
3 | 35 |
4 | 35 |
5 | 45 |
6 | 45 |
7 | 0 |
8 | 0 |
9 | 0 |
10 | 0 |
11 | 0 |
12 | 0 |
The decision variable reduced costs are automatically generated from the LP optimize function.
Decision Variable Reduced Costs | |
Variable | Reduced Costs |
---|---|
start_shift[1] | 90 |
start_shift[2] | 80 |
start_shift[3] | 70 |
start_shift[4] | 70 |
start_shift[5] | 80 |
start_shift[6] | 90 |
on_shift[1] | 0 |
on_shift[2] | 0 |
on_shift[3] | 0 |
on_shift[4] | 0 |
on_shift[5] | 0 |
on_shift[6] | 0 |