简体   繁体   中英

How can I change my script so it minimizes the cost, and at the same time calculates the volume and weight chosen is viable?

I created a function using pulp which takes in an array of items and of trucks. Each item has a capacity, and every truck has a capacity and a cost. I used a pulp solver to calculate the minimum number of trucks required, whilst keeping the minimum cost. The constraining factor is the capacity, and the optimizing factor is the bin cost. But now, I want to add another constraining factor of volume. Can it be done ? Can you suggest a way to do this using the solver itself ?? I am trying to do that part without using the solver, but it is not helping at all. Thanks a lot.

I tried to create a function to which replaces the minimum truck with the next largest truck whenever I get the message, "Trucks not sufficient"

UPDATE: @kabdulla helped me get the answer, but also pointed that it has a big flaw that it only takes into consideration the whole volume of items rather than geometry of the items to fit inside; a 2 X 2 X 2 item should fit in a truck easily, but a 8 X 1 X 1 has a different geometry and has different constraints. Here is my updated code(all thanks to @kabdulla ) with item and truck details.

from pulp import *
import numpy as np

# Item details
item_name = ["Mudguard1","Mudguard2","Mudguard3","Mudguard4",]
item_id = ["1001474185","1001474401","1001474182","1001474154"]
item_length = [14,22,16,16]
item_breadth = [12,24,14,12]
item_height = [9,26,12,17]
item_quantity = [14,8,10,1]
item_vol = [12.25,63.55,15.55,1.88]
item_mass= [160,528,83,5]
n_items = len(item_id)
set_items = range(n_items)

# Details of trucks
item_name = ["Tata-407-9.5","Tata-407-13","Tata-407-17","Tata-407-16",]
item_id = ["1","2","3","4"]
truck_length = [14,22,16,16]
truck_breadth = [12,24,14,12]
truck_height = [9,26,12,17]
truck_quantity = [14,8,10,1]
truck_vol = [12.25,63.55,15.55,1.88]
truck_mass= [160,528,83,5]
truck_cost = [7,1.5,18,100]


n_trucks = len(truck_cost)
set_trucks = range(n_trucks)

y = pulp.LpVariable.dicts('truckUsed', set_trucks,
    lowBound=0, upBound=1, cat=LpInteger)

x = pulp.LpVariable.dicts('itemInTruck', (set_items, set_trucks), 
    lowBound=0, upBound=1, cat=LpInteger)

# Model formulation
prob = LpProblem("Truck allocation problem", LpMinimize)

# Objective
prob += lpSum([truck_cost[i] * y[i] for i in set_trucks])

# Constraints
for j in set_items:
    # Every item must be taken in one truck
    prob += lpSum([x[j][i] for i in set_trucks]) == 1

for i in set_trucks:
    # Respect the mass constraint of trucks
    prob += lpSum([item_mass[j] * x[j][i] for j in set_items]) <= truck_mass[i]*y[i]

    # Respect the volume constraint of trucks
    prob += lpSum([item_vol[j] * x[j][i] for j in set_items]) <= truck_vol[i]*y[i]

# Ensure y variables have to be set to make use of x variables:
for j in set_items:
    for i in set_trucks:
        x[j][i] <= y[i]


prob.solve()

x_soln = np.array([[x[i][j].varValue for i in set_items] for j in set_trucks])
y_soln = np.array([y[i].varValue for i in set_trucks])

print (("Status:"), LpStatus[prob.status])
print ("Total Cost is: ", value(prob.objective))
print("x_soln"); print(x_soln)
print("y_soln"); print(y_soln)

print("Trucks used: " + str(sum(([y_soln[i] for i in set_trucks]))))

for i in set_items:
    for j in set_trucks:
        if x[i][j].value() == 1:
            print("Item " + str(i) + " is packed in vehicle "+ str(j))

totalitemvol = sum(item_vol)

totaltruckvol = sum([y[i].value() * truck_vol[i] for i in set_trucks])
print("Volume of used trucks is " + str(totaltruckvol))

if(totaltruckvol >= totalitemvol):
  print("Trucks are sufficient")
else:
  print("Items cannot fit")

This is my output:

Status: Optimal
Total Cost is:  126.5
x_soln
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]]
y_soln
[1. 1. 1. 1.]
Trucks used: 4.0
Item 0 is packed in vehicle 0
Item 1 is packed in vehicle 1
Item 2 is packed in vehicle 2
Item 3 is packed in vehicle 3
The volume of used trucks is 93.22999999999999
Trucks are sufficient

Here is a colab link to play around. https://colab.research.google.com/drive/1uKuS2F4Xd1Lbps8yAwivLbhzZrD_Hv0-

The version of the code below assumes there is a total carrying mass, and a total carrying volume constraint on each truck. NB: this does not guarantee a combination of items which fit within trucks (an item which is 8m x 1m x 1m is 8 cubic meters in volume, but would not fit in a truck whose internal space was 2m x 2m x 2m = 8 cubic meters for example, but using the volume constraint below this would not violate the constraint).

from pulp import *
import numpy as np

# Item masses, volumes
item_mass = [16, 10, 5]
item_vol = [25, 12, 1]
n_items = len(item_vol)
set_items = range(n_items)

# Mass & volume capacities of trucks
truck_mass = [7, 15, 15, 15, 18, 38, 64, 100]
truck_vol = [25, 50, 50, 50, 100, 125, 250, 500]

# Cost of using each truck
truck_cost = [7, 1.5, 1.5, 1.5, 18, 380, 640, 1000]

n_trucks = len(truck_cost)
set_trucks = range(n_trucks)

y = pulp.LpVariable.dicts('truckUsed', set_trucks,
    lowBound=0, upBound=1, cat=LpInteger)

x = pulp.LpVariable.dicts('itemInTruck', (set_items, set_trucks), 
    lowBound=0, upBound=1, cat=LpInteger)

# Model formulation
prob = LpProblem("Truck allocatoin problem", LpMinimize)

# Objective
prob += lpSum([truck_cost[i] * y[i] for i in set_trucks])

# Constraints
for j in set_items:
    # Every item must be taken in one truck
    prob += lpSum([x[j][i] for i in set_trucks]) == 1

for i in set_trucks:
    # Respect the mass constraint of trucks
    prob += lpSum([item_mass[j] * x[j][i] for j in set_items]) <= truck_mass[i]*y[i]

    # Respect the volume constraint of trucks
    prob += lpSum([item_vol[j] * x[j][i] for j in set_items]) <= truck_vol[i]*y[i]

# Ensure y variables have to be set to make use of x variables:
for j in set_items:
    for i in set_trucks:
        x[j][i] <= y[i]


prob.solve()

x_soln = np.array([[x[i][j].varValue for i in set_items] for j in set_trucks])
y_soln = np.array([y[i].varValue for i in set_trucks])

print (("Status:"), LpStatus[prob.status])
print ("Total Cost is: ", value(prob.objective))
print("x_soln"); print(x_soln)
print("y_soln"); print(y_soln)

print("Trucks used: " + str(sum(([y_soln[i] for i in set_trucks]))))

for i in set_items:
    for j in set_trucks:
        if x[i][j].value() == 1:
            print("Item " + str(i) + " is packed in vehicle "+ str(j))

totalitemvol = sum(item_vol)

totaltruckvol = sum([y[i].value() * truck_vol[i] for i in set_trucks])
print("Volume of used trucks is " + str(totaltruckvol))

if(totaltruckvol >= totalitemvol):
  print("Trucks are sufficient")
else:
  print("Items cannot fit")

Which should return the following:

('Status:', 'Optimal')
('Total Cost is: ', 19.5)
x_soln
[[0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 1. 1.]
 [1. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]
 [0. 0. 0.]]
y_soln
[0. 0. 0. 1. 1. 0. 0. 0.]
Trucks used: 2.0
Item 0 is packed in vehicle 4
Item 1 is packed in vehicle 3
Item 2 is packed in vehicle 3
Volume of used trucks is 150.0
Trucks are sufficient

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM