A peak hour drivers bonus optimization

Aleksandr Matrunich
4/18/2019

The setup

  • A peak hour where online time supply to be maximized
  • N drivers
  • Bonus budget
  • Average online time in the peak hour for each driver
  • Average increase of online time from a unit of bonus per each driver
  • Bonuses are driver specific

Inputs

# number of drivers
drivers <- 5
# Average online minutes per driver
online_ave <- runif(drivers) * 60
# Online minutes growth from added bonus 
bonus_adds <- runif(drivers, max = .3) * 60
budget <- 10

The model

solved_model <- MIPModel() %>%
  # Add per driver bonus variable
  add_variable(bonus[driver], 
               driver = seq_len(drivers), 
               lb = 0, # Lower bound
               type = "continuous") %>% 
  set_objective(
    sum_expr(
      online_ave[driver] + bonus_adds[driver] * bonus[driver], 
      driver = seq_len(drivers)), "max") %>% 
  add_constraint(
    sum_expr(
      bonus[driver], 
      driver = seq_len(drivers)) <= budget) %>% 
  # A driver can't provide more than 60 minutes of online time
  add_constraint(
    online_ave[driver] + bonus_adds[driver] * bonus[driver] <= 60, 
    driver = seq_len(drivers)) %>% 
  solve_model(with_ROI(solver = "glpk")) 

Results: online minutes

solved_model
Status: optimal
Objective value: 271.8976

Results: driver-specific bonus offer

solved_model %>% 
  get_solution(bonus[driver]) %>% 
  bind_cols(online_ave = online_ave, bonus_adds = bonus_adds) %>% 
  select(driver, online_ave, bonus_adds, bonus = value)
  driver online_ave bonus_adds     bonus
1      1   7.769553   7.787465 5.2964589
2      2  45.030264   5.565533 0.0000000
3      3   9.148695  11.825015 4.3003163
4      4  55.434466  11.322551 0.4032248
5      5  57.851774   5.669937 0.0000000

Model with 5000 drivers

# number of drivers
drivers <- 5000
# Average online minutes per driver
online_ave <- runif(drivers) * 60
# Online minutes growth from added bonus 
bonus_adds <- runif(drivers, max = .3) * 60
budget <- 1000

Results 5000

solved_model <- MIPModel() %>%
  add_variable(
    bonus[driver], 
    driver = seq_len(drivers), 
    lb = 0, # Lower bound
    type = "continuous") %>% 
  set_objective(
    sum_expr(online_ave[driver] + bonus_adds[driver] * bonus[driver], 
             driver = seq_len(drivers)), "max") %>% 
  add_constraint(
    sum_expr(bonus[driver], 
             driver = seq_len(drivers)) <= budget) %>% 
  add_constraint(
    online_ave[driver] + bonus_adds[driver] * bonus[driver] <= 60, 
    driver = seq_len(drivers)) %>% 
  solve_model(with_ROI(solver = "glpk")) 

solved_model
Status: optimal
Objective value: 169141.4

Bonuses for 5000 drivers

solved_model %>% 
  get_solution(bonus[driver]) %>% 
  bind_cols(online_ave = online_ave, bonus_adds = bonus_adds) %>% 
  select(driver, online_ave, bonus_adds, bonus = value) %>% 
  sample_n(10)
   driver online_ave bonus_adds    bonus
1    4642   9.861542  17.544665 2.857761
2    3892   8.776985  17.769883 2.882575
3    2658  58.341781  15.885188 0.000000
4    1145  22.217634  16.251237 2.324892
5    3931   5.763477   6.953985 0.000000
6    3230   3.723107   7.421736 0.000000
7    2914  34.154750  12.677663 0.000000
8     681  58.823600   2.984527 0.000000
9    1900  13.585682  13.590913 0.000000
10   2328  49.163095  14.167168 0.000000