3

I have some troubles regarding a linear program I alreday solved and use excel but now i want to do it in r/python beacuse I already reach excels and the solvers limits. Therefore I am asking for help on this specific topic.

I tried it with the lPsovle package by also altering the lp.assign function but I cannot come up with an solution.

The problem is as follows:

Let's say I am a deliverer of an commodity good.

I have differnet depots which serve different areas. These areas MUST be served with their demands. My depots on the other hand, have a constraint regarding their capacity what they can handle and deliver. One depot can serve several areas, but one area can only be served by one depot.

I have the distance/cost matrix for the connections between depots and areas as well as the demand for that areas.

The objective for this solution should be that the areas should be served with the minimal possible effort.

Lets say the cost/distance matrix looks something like this:

assign.costs <- matrix (c(2, 7, 7, 2, 7, 7, 3, 2, 7, 2, 8, 10, 1, 9, 8, 2,7,8,9,10), 4, 10)

So this creates my matrix, with the costumers/areas in the first row/header and the depots in the first column/row names.

Now the demand of the areas/customers is:

assign.demand <- matrix (c(1,2,3,4,5,6,7,8,9,10), 1, 10)

The capacity restrictions, what amount the depos are able to serve is:

assign.capacity <- matrix (c(15,15,15,15), 4, 1)

So now i woukd like this problem to be solved by a lp to generate the allocation, which area should be served by which depot according to these restrictions.

The result should look something like this:

assign.solution <- matrix (c(1,0,0,0 ,0,1,0,0, 1,0,0,0, 1,0,0,0 ,0,0,0,1), 4, 10)

As for the restrictions this means that every column must some up to one.

I tried it with the lpsolve and lp.assign functions from lpSolve but I dont know exactly how to implement that exact kind of restrictions I have and i already tried to alter the lp.assign functions with no success. If it helps, i can also formulate the equations for the lp.

Thank you all for your help, I am really stuck right now :D

BR

Erwin Kalvelagen
  • 15,677
  • 2
  • 14
  • 39
rued
  • 45
  • 6
  • This is not really an assignment problem. You can model this as a combination of an assignment problem and a transportation problem. This would yield a general MIP model. First thing is to write down the mathematical model. After that things are relatively straightforward. – Erwin Kalvelagen Oct 17 '19 at 15:12
  • Are the costs per item or per transit of potentially several items? I.e. if the first depot ships 10 items to the last customer, is the cost 10 or 100? – fuglede Oct 19 '19 at 13:58

1 Answers1

6

Step 1. Develop a mathematical model

The mathematical model can look like:

enter image description here

The blue entries represent data and the red ones indicate a decision variable. i are the depots and j are the customers. Ship indicates if we ship from i to j (it is a binary variable). The first constraint says that total amount shipped from depot i should not exceed its capacity. The second constraint says that there must be exactly one supplier i for each customer j.

Step 2. Implementation

This is now just a question of being precise. I follow the model from the previous section as closely as I can.

library(dplyr)
library(tidyr)
library(ROI)
library(ROI.plugin.symphony)
library(ompr)
library(ompr.roi)

num_depots <- 4
num_cust <- 10

cost <- matrix(c(2, 7, 7, 2, 7, 7, 3, 2, 7, 2, 8, 10, 1, 9, 8, 2,7,8,9,10), num_depots, num_cust)
demand <- c(1,2,3,4,5,6,7,8,9,10)
capacity <- c(15,15,15,15)

m <- MIPModel() %>%
  add_variable(ship[i,j], i=1:num_depots, j=1:num_cust, type="binary") %>%
  add_constraint(sum_expr(demand[j]*ship[i,j], j=1:num_cust) <= capacity[i], i=1:num_depots) %>% 
  add_constraint(sum_expr(ship[i,j], i=1:num_depots) == 1, j=1:num_cust) %>% 
  set_objective(sum_expr(cost[i,j]*ship[i,j], i=1:num_depots, j=1:num_cust),"min") %>% 
  solve_model(with_ROI(solver = "symphony", verbosity=1))

cat("Status:",solver_status(m),"\n")
cat("Objective:",objective_value(m),"\n")
get_solution(m,ship[i, j]) %>%
  filter(value > 0) 

We see how important it is to first write down a mathematical model. It is much more compact and easier to reason about than a bunch of code. Going directly to code often leads to all kind of problems. Like building a house without a blueprint. Even for this small example, writing down the mathematical model is a useful exercise.

For the implementation I used OMPR instead of the LpSolve package because OMPR allows me to stay closer to the mathematical model. LpSolve has a matrix interface, which is very difficult to use except for very structured models.

Step 3: Solve it

Status: optimal 
Objective: 32 
   variable i  j value
1      ship 1  1     1
2      ship 4  2     1
3      ship 2  3     1
4      ship 1  4     1
5      ship 3  5     1
6      ship 4  6     1
7      ship 4  7     1
8      ship 2  8     1
9      ship 1  9     1
10     ship 3 10     1

I believe this is the correct solution.

Erwin Kalvelagen
  • 15,677
  • 2
  • 14
  • 39
  • Thank you so much! This is exactly what i was looking for but couldnt formulate by myself. May I ask another question: what software do you use to create the mathematical model? I have it written down on a piece of paper but I would like to use a software to formulate and document it Thank you! – rued Oct 18 '19 at 07:17
  • HTML + MathJax. – Erwin Kalvelagen Oct 18 '19 at 09:37