OR-TOOLS:具有交付模式的 PCVRP
OR-TOOLS: PCVRP with delivery patterns
请帮我解决周期性的有能力的车辆路径问题。
在 google 组中找到相同的问题 here。
我要建模的内容:
1 个仓库
多个客户(假设有 4 个)
多天(假设 3 天)
具有每公里价格和特定容量的多种车型
每个客户都有:交货频率和每次交货的需求
每个客户都必须分配给一个交付模式。每个频率可能有多种交付模式。该模式指示当天是否可以交货。对于 1 和 3 个工作日的频率:[[1,0,0],[0,1,0],[0,0,1]]
,2 [[1,1,0],[1,0,1],[1,1,0]]
的频率,3 的频率:[1,1,1]
这些是可能的模式。
每个客户每次发货的需求是相同的,每天执行一次发货
所以我们有一组客户必须由一个 depo 交付。多种车辆类型可用于该工作。服务日期是灵活的,因为只有频率是固定给客户的,但是有多种可能性来满足需求。
到目前为止我做了什么:
我按工作日数复制了每个节点。
我限制了每天的depo节点开始和结束。
我用车辆乘以天数。
此外,我把日子当作不同种类的货物来处理。当那天不应该使用车辆时,我确实为车辆分配了零容量。
[[10, 15, 15, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 10, 15, 15, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 10, 15, 15]]
前三辆车是第一天的,后三辆车是第二天的
最后 3 个是第 3 天。
对于需求矩阵,我使用了相同的技巧。在 4 个客户 + 1 个仓库的情况下,需求矩阵可能如下所示
[[0, 3, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 3, 4, 5, 2, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2]]
第一个列表中的第二个条目 (3) 和第二个列表中的第 7 个条目 (3) 是针对同一客户的,只是在两个不同的日子。节点已复制。
到目前为止效果很好。但这不是我想做的。
我确实为每个客户每天手动分配需求,但我想通过为每个客户选择的交付模式分配需求。
模型可以将模式 [1,0,1]
分配给一个客户,频率为 2,将模式 [0,0,1]
分配给另一客户。这将导致有可能在第 3 天计划一次结合这两种需求的旅行。
我需要帮助来定义管理模式分配给客户的维度,从而产生“灵活”的需求矩阵。
感谢您的帮助。
完整代码:
"""Periodic Capacited Vehicles Routing Problem (PCVRP)."""
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
import numpy as np
def dublicate_nodes(base_distance_matrix, num_days):
matrix = []
for i in range(num_days):
day_element = []
for node in range(len(base_distance_matrix)):
node_element = []
for day in range(num_days):
node_element.append(base_distance_matrix[node])
day_element.append(np.concatenate(node_element).tolist())
matrix.extend(day_element)
#print(matrix)
return matrix
def depo_nodes(num_days, num_verhicles, num_nodes):
depo_array = []
for day in range(num_days):
for veh in range(int(num_verhicles/num_days)):
depo_array.append(day*num_nodes)
#print(depo_array)
return depo_array
def veh_types_costs(cost_array, num_per_type, num_days):
cost_array_km = []
for day in range(num_days):
for i in range(len(cost_array)):
for num in range(num_per_type[i]):
cost_array_km.append(cost_array[i])
#print(cost_array_km)
return(cost_array_km)
def veh_capacity_matrix(num_vehicle_per_type, vehicle_capacity_type, num_days):
matrix= []
for index in range(num_days):
matrix_element = []
for day in range(num_days):
for i, num in enumerate(num_vehicle_per_type):
for times in range(num):
if day == index:
matrix_element.append(vehicle_capacity_type[i]);
else:
matrix_element.append(0)
matrix.append(matrix_element)
#print(matrix)
return matrix
def create_data_model():
data = {}
data["num_days"] = 3 #Anzahl Tage
### Definition der Fahrezugtypen
data["num_vehicle_per_type"] = [1, 2] #Anzahl Fahrzeuge pro Typ
data["vehicle_costs_type_per_km"] = [1, 0.01] #Kosten pro km pro Fahrzeugtyp
data["vehicle_costs_type_per_stop"] = [1, 1000] #Kosten pro Stop pro Fahrzeugtyp
data['price_per_km'] = veh_types_costs(data["vehicle_costs_type_per_km"], data["num_vehicle_per_type"], data["num_days"]) #Matrix für price_per_km je Fahrzeug ertsellen
data["price_per_stop"] = veh_types_costs(data["vehicle_costs_type_per_stop"], data["num_vehicle_per_type"], data["num_days"])
data["vehicle_capacity_type"] = [10, 15] # Kapaität pro Fahrzeugtyp
data['vehicle_capacities_matrix'] = veh_capacity_matrix(data["num_vehicle_per_type"], data["vehicle_capacity_type"], data["num_days"]) #Kapazitäten pro Fahrzeugs pro Tag
print('vehicle_capacities_matrix')
print(data['vehicle_capacities_matrix'])
data["num_vehicles_per_day"] = sum(data["num_vehicle_per_type"]) #Gesamtanzahl der Fahrzeuge pro Tag
data['num_vehicles'] = data["num_days"] * data["num_vehicles_per_day"]# Gesamtanzahl der Fahrzeuge in gesamten Zeitraum
###Distanzmatrix bestimmen
data["base_distance_matrix"] = [
[
0, 548, 776, 696, 582
],
[
548, 0, 684, 308, 194
],
[
776, 684, 0, 992, 878
],
[
696, 308, 992, 0, 114
],
[
582, 194, 878, 114, 0
]
] #Distanzmatrix mit allen Kunden einzeln
data['distance_matrix'] = dublicate_nodes(data["base_distance_matrix"], data["num_days"]) # Distanzmatrix mit mehrfachen Nodes pro Kunden, je Tag ein Node
###Start und Ende festlegen
data["num_nodes"] = len(data["base_distance_matrix"]) # Anzahl Kunden
data['starts'] = depo_nodes(data["num_days"], data['num_vehicles'], data["num_nodes"]) #Deponodes (Start) für die einzelnen Fahrzeuge (Tage)
data['ends'] = depo_nodes(data["num_days"], data['num_vehicles'], data["num_nodes"]) #Deponodes (Ende) für die einzelnen Fahrzeuge (Tage)
###Demand pro Kunde
data['demands_matrix'] = [[0, 3, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 3, 4, 5, 2, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2]] #Demandmatrix mit je einer list pro Tag
return data
def print_solution(data, manager, routing, solution):
"""Prints solution on console."""
total_distance = 0
total_load = 0
for vehicle_id in range(data['num_vehicles']):
if vehicle_id % data["num_vehicles_per_day"] == 0:
print(("------Tag {}------").format(int(vehicle_id/data["num_vehicles_per_day"])))
if routing.IsVehicleUsed(assignment= solution, vehicle=vehicle_id) == False:
continue
index = routing.Start(vehicle_id)
if vehicle_id >= data["num_vehicles_per_day"]:
plan_output = 'Route for vehicle {}:\n'.format(abs(vehicle_id-data["num_vehicles_per_day"]*int(vehicle_id/data["num_vehicles_per_day"])))
else:
plan_output = 'Route for vehicle {}:\n'.format(vehicle_id)
route_costs = 0
route_load = 0
while not routing.IsEnd(index):
node_index = manager.IndexToNode(index)
capacity_ID = int(vehicle_id/data["num_vehicles_per_day"])
route_load += data['demands_matrix'][capacity_ID][node_index]
plan_output += ' {0} Load({1}) -> '.format(node_index, route_load)
previous_index = index
index = solution.Value(routing.NextVar(index))
route_costs += routing.GetArcCostForVehicle(
previous_index, index, vehicle_id)
plan_output += ' {0} Load({1})\n'.format(manager.IndexToNode(index),
route_load)
plan_output += 'Costs of the route: {}€\n'.format(route_costs)
plan_output += 'Load of the route: {}\n'.format(route_load)
print(plan_output)
total_distance += route_costs
total_load += route_load
print('Total costs of all routes: {}€'.format(total_distance))
print('Total load of all routes: {}'.format(total_load))
def main():
"""Periodic CVRP problem."""
# Instantiate the data problem.
data = create_data_model()
# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']), data['num_vehicles'], data['starts'],
data['ends'])
# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)
### Kostenfunktion je Fahrzeug festlegen ###
def create_cost_callback(dist_matrix, km_costs, stop_costs):
# Create a callback to calculate distances between cities.
def distance_callback(from_index, to_index):
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return int(dist_matrix[from_node][to_node]) * (km_costs) + (stop_costs)
return distance_callback
for i in range(data['num_vehicles']):
cost_callback = create_cost_callback(data['distance_matrix'], data["price_per_km"][i],
data["price_per_stop"][i]) # Callbackfunktion erstellen
cost_callback_index = routing.RegisterTransitCallback(cost_callback) # registrieren
routing.SetArcCostEvaluatorOfVehicle(cost_callback_index, i) # Vehicle zuordnen
#Define Capacities for Vehicles for every Day
def create_demand_callback(demand_matrix, demand_index):
# Create a callback to calculate capacity usage.
def demand_callback(from_index):
#Returns the demand of the node.
# Convert from routing variable Index to demands NodeIndex.
from_node = manager.IndexToNode(from_index)
return demand_matrix[demand_index][from_node]
return demand_callback
for i in range(data["num_days"]): #Jedes Fahrzeug hat pro Tag eine andere Kapazität
demand_callback = create_demand_callback(data['demands_matrix'], i)
demand_callback_index = routing.RegisterUnaryTransitCallback(demand_callback)
dimension_name = 'Capacity_day_{}'.format(i)
routing.AddDimensionWithVehicleCapacity(
demand_callback_index,
0, # null capacity slack
data['vehicle_capacities_matrix'][i], # vehicle maximum capacities
True, # start cumul to zero
dimension_name)
# Setting first solution heuristic.
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.AUTOMATIC)
search_parameters.local_search_metaheuristic = (
routing_enums_pb2.LocalSearchMetaheuristic.AUTOMATIC)
search_parameters.time_limit.FromSeconds(1)
# Solve the problem.
solution = routing.SolveWithParameters(search_parameters)
# Print solution on console.
if solution:
print_solution(data, manager, routing, solution)
return solution
if __name__ == '__main__':
solution_array = []
solution = main()
所以我找到了解决问题的方法。
超过 40 个客户的问题的解决时间可能会更好。
我将不胜感激改进建议。
"""Periodic Capacited Vehicles Routing Problem with delivery pattern(PCVRP)."""
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
import numpy as np
import random
import math
import pandas as pd
def dublicate_nodes(base_distance_matrix, num_days):
matrix = []
for i in range(num_days):
day_element = []
for node in range(len(base_distance_matrix)):
node_element = []
for day in range(num_days):
node_element.append(base_distance_matrix[node])
day_element.append(np.concatenate(node_element).tolist())
matrix.extend(day_element)
#print(matrix)
return matrix
def depo_nodes(num_days, num_verhicles, num_nodes):
depo_array = []
for day in range(num_days):
for veh in range(int(num_verhicles/num_days)):
depo_array.append(day*num_nodes)
#print(depo_array)
return depo_array
def veh_types_costs(cost_array, num_per_type, num_days):
cost_array_km = []
for day in range(num_days):
for i in range(len(cost_array)):
for num in range(num_per_type[i]):
cost_array_km.append(cost_array[i])
#print(cost_array_km)
return(cost_array_km)
def veh_capacity_matrix(num_vehicle_per_type, vehicle_capacity_type, num_days):
matrix= []
for index in range(num_days):
matrix_element = []
for day in range(num_days):
for i, num in enumerate(num_vehicle_per_type):
for times in range(num):
if day == index:
matrix_element.append(vehicle_capacity_type[i]);
else:
matrix_element.append(0)
matrix.append(matrix_element)
#print(matrix)
return matrix
def dist_matrix(koordianten):
matrix =[]
for k_1 in koordianten:
matrix_element = []
for k_2 in koordianten:
matrix_element.append(np.linalg.norm(k_1-k_2))
matrix.append(matrix_element)
#print(matrix)
return matrix
def demand_matrix(demand_matrix_day,num_days):
matrix = []
for index in range(num_days):
matrix_element = []
for day in range(num_days):
if day == index:
matrix_element = matrix_element +demand_matrix_day
else:
matrix_element = matrix_element +(list(np.zeros(len(demand_matrix_day))))
matrix.append(matrix_element)
return matrix
def kunden_indizes(ID_list, num_days):
indizes = {}
for ID in ID_list:
indizes[ID] = []
for index, key in enumerate(indizes):
for i in range(len(ID_list)*num_days):
if (i % len(ID_list)) == index:
indizes[key].append(i)
#print(indizes)
return indizes
def create_data_model(node_num):
data = {}
data["num_days"] = 5 #Anzahl Tage
###Kundenset
num_IDs = node_num
base = [0]
data["IDs"] = list(range(0, num_IDs))
#data["IDs"] = [0, 1, 2, 3, 4]
print(data["IDs"])
data["demand"] = [random.randint(1,30) for i in range(0,num_IDs)]
#data["demand"] =[0, 16, 8, 1, 7]
data["demand"][0] = 0
print("demand", data["demand"])
data["frequenz"] = [random.randint(1,5) for i in range(0,num_IDs)]
#data["frequenz"] =[0, 3, 5, 2, 1]
data["frequenz"][0] = 0
print("freq ",data["frequenz"])
summe_dem =0
for index, demand in enumerate(data["demand"]):
summe_dem += data["demand"][index] * data["frequenz"][index]
print("DEMANDSUMME: ",summe_dem)
data["koordianten"] = np.random.rand(num_IDs, 2)*1000
#data["koordianten"] = np.array([(0, 0), (4, 0), (4, 4), (0, 4), (3, 3)])*100
data["koordianten"][0] = (0,0)
#print("koord ", data["koordianten"])
data["PAT"] = {
5:
[[1, 1, 1, 1, 1]],
4:
[[0, 1, 1, 1, 1],
[1, 0, 1, 1, 1],
[1, 1, 0, 1, 1],
[1, 1, 1, 0, 1],
[1, 1, 1, 1, 0]],
3: [[0, 1, 0, 1, 1],
[1, 0, 1, 0, 1],
[1, 1, 0, 1, 0],
[0, 1, 1, 0, 1],
[1, 0, 1, 1, 0],
],
2: [[1, 0, 1, 0, 0],
[0, 1, 0, 1, 0],
[0, 0, 1, 0, 1],
[1, 0, 0, 1, 0],
[0, 1, 0, 0, 1]],
1: [[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 1]],
}
### Definition der Fahrezugtypen
data["vehicle_costs_type_per_km"] = [1, 0.01] #Kosten pro km pro Fahrzeugtyp
data["vehicle_costs_type_per_stop"] = [1, 1000] #Kosten pro Stop pro Fahrzeugtyp
data["vehicle_capacity_type"] = [100, 200] # Kapaität pro Fahrzeugtyp
data["num_vehicle_per_type"] = [math.ceil(summe_dem /data["vehicle_capacity_type"][0]), math.ceil(summe_dem /data["vehicle_capacity_type"][1])] # Anzahl Fahrzeuge pro Typ
data['price_per_km'] = veh_types_costs(data["vehicle_costs_type_per_km"], data["num_vehicle_per_type"], data["num_days"]) #Matrix für price_per_km je Fahrzeug ertsellen
data["price_per_stop"] = veh_types_costs(data["vehicle_costs_type_per_stop"], data["num_vehicle_per_type"], data["num_days"])
data['vehicle_capacities_matrix'] = veh_capacity_matrix(data["num_vehicle_per_type"], data["vehicle_capacity_type"], data["num_days"]) #Kapazitäten pro Fahrzeugs pro Tag
#print('vehicle_capacities_matrix')
#print(data['vehicle_capacities_matrix'])
data["num_vehicles_per_day"] = sum(data["num_vehicle_per_type"]) #Gesamtanzahl der Fahrzeuge pro Tag
data['num_vehicles'] = data["num_days"] * data["num_vehicles_per_day"]# Gesamtanzahl der Fahrzeuge in gesamten Zeitraum
###Distanzmatrix bestimmen
data["base_distance_matrix"] = dist_matrix(data["koordianten"])
data['distance_matrix'] = dublicate_nodes(data["base_distance_matrix"], data["num_days"]) # Distanzmatrix mit mehrfachen Nodes pro Kunden, je Tag ein Node
###Start und Ende festlegen
data["num_nodes"] = len(data["base_distance_matrix"]) # Anzahl Kunden
data['starts'] = depo_nodes(data["num_days"], data['num_vehicles'], data["num_nodes"]) #Deponodes (Start) für die einzelnen Fahrzeuge (Tage)
data['ends'] = depo_nodes(data["num_days"], data['num_vehicles'], data["num_nodes"]) #Deponodes (Ende) für die einzelnen Fahrzeuge (Tage)
###Demand pro Kunde
data["kunden_indizes"] = kunden_indizes(data["IDs"], data["num_days"])
data["demands_matrix"] = demand_matrix(demand_matrix_day=data["demand"], num_days=data["num_days"])
#print(data["demands_matrix"])
return data
def print_solution(data, manager, routing, solution):
"""Prints solution on console."""
total_distance = 0
total_load = 0
for vehicle_id in range(data['num_vehicles']):
if vehicle_id % data["num_vehicles_per_day"] == 0:
print(("------Tag {}------").format(int(vehicle_id/data["num_vehicles_per_day"])))
if routing.IsVehicleUsed(assignment= solution, vehicle=vehicle_id) == False:
continue
index = routing.Start(vehicle_id)
if vehicle_id >= data["num_vehicles_per_day"]:
plan_output = 'Route for vehicle {}:\n'.format(abs(vehicle_id-data["num_vehicles_per_day"]*int(vehicle_id/data["num_vehicles_per_day"])))
else:
plan_output = 'Route for vehicle {}:\n'.format(vehicle_id)
route_costs = 0
route_load = 0
while not routing.IsEnd(index):
node_index = manager.IndexToNode(index)
capacity_ID = int(vehicle_id/data["num_vehicles_per_day"])
route_load += data['demands_matrix'][capacity_ID][node_index]
plan_output += ' {0} Load({1}) -> '.format(node_index, route_load)
previous_index = index
index = solution.Value(routing.NextVar(index))
route_costs += routing.GetArcCostForVehicle(
previous_index, index, vehicle_id)
plan_output += ' {0} Load({1})\n'.format(manager.IndexToNode(index),
route_load)
plan_output += 'Costs of the route: {}€\n'.format(route_costs)
plan_output += 'Load of the route: {}\n'.format(route_load)
print(plan_output)
total_distance += route_costs
total_load += route_load
print('Total costs of all routes: {}€'.format(total_distance))
print('Total load of all routes: {}'.format(total_load))
def main(node_num):
"""Periodic CVRP problem."""
# Instantiate the data problem.
data = create_data_model(node_num)
# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']), data['num_vehicles'], data['starts'],
data['ends'])
# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)
### Kostenfunktion je Fahrzeug festlegen ###
def create_cost_callback(dist_matrix, km_costs, stop_costs):
# Create a callback to calculate distances between cities.
def distance_callback(from_index, to_index):
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return int(dist_matrix[from_node][to_node]) * (km_costs) + (stop_costs)
return distance_callback
for i in range(data['num_vehicles']):
cost_callback = create_cost_callback(data['distance_matrix'], data["price_per_km"][i],
data["price_per_stop"][i]) # Callbackfunktion erstellen
cost_callback_index = routing.RegisterTransitCallback(cost_callback) # registrieren
routing.SetArcCostEvaluatorOfVehicle(cost_callback_index, i) # Vehicle zuordnen
#Define Capacities for Vehicles for every Day
def create_demand_callback(demand_matrix, demand_index):
# Create a callback to calculate capacity usage.
def demand_callback(from_index):
#Returns the demand of the node.
# Convert from routing variable Index to demands NodeIndex.
from_node = manager.IndexToNode(from_index)
return demand_matrix[demand_index][from_node]
return demand_callback
for i in range(data["num_days"]): #Jedes Fahrzeug hat pro Tag eine andere Kapazität
demand_callback = create_demand_callback(data['demands_matrix'], i)
demand_callback_index = routing.RegisterUnaryTransitCallback(demand_callback)
dimension_name = 'Capacity_day_{}'.format(i)
routing.AddDimensionWithVehicleCapacity(
demand_callback_index,
0, # null capacity slack
data['vehicle_capacities_matrix'][i], # vehicle maximum capacities
True, # start cumul to zero
dimension_name)
#Drop visits that would exceed the frequency
for index, key in enumerate(data["kunden_indizes"]):
if index == 0:
continue
#routing.solver().Add(sum(routing.ActiveVar(manager.NodeToIndex(i)) for i in data["kunden_indizes"][key]) == data["frequenz"][index])
bool_array = []
for index, freq in enumerate(data["frequenz"]):
if index == 0:
continue
bool_array_part =[]
for index_pat, pat in enumerate(data["PAT"][freq]):
#print(index,freq,index_pat)
bool_name = str(index) +str(freq) + str(index_pat)
bool_array_part.append(routing.solver().BoolVar(bool_name))
bool_array.append(bool_array_part)
#print(bool_array)
for i in bool_array:
routing.solver().Add(sum(i) == 1)
node_array = []
for index, freq in enumerate(data["frequenz"]):
if index == 0:
continue
node_array_part = []
for index_pat, pat in enumerate(data["PAT"][freq]):
node_array_sub_part = []
for index_day, day_value in enumerate(pat):
if day_value == 1:
node_array_sub_part.append(data["kunden_indizes"][index][index_day])
#print(node_array_part)
node_array_part.append(node_array_sub_part)
node_array.append(node_array_part)
#print(node_array)
for index, bool in enumerate(bool_array):
for i in range(len(bool)):
#print(node_array[index][i])
#print(bool_array[index][i])
routing.solver().Add(sum(routing.ActiveVar(manager.NodeToIndex(i)) for i in node_array[index][i]) * bool_array[index][i] == bool_array[index][i] * len(node_array[index][i]))
#routing.solver().Add(routing.ActiveVar(manager.NodeToIndex(5)) == 1)
penalty = 0
for node in range(0, len(data['distance_matrix'])):
if node in data["kunden_indizes"][0]:
continue
else:
routing.AddDisjunction([manager.NodeToIndex(node)], penalty)
# Setting first solution heuristic.
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.AUTOMATIC)
search_parameters.local_search_metaheuristic = (
routing_enums_pb2.LocalSearchMetaheuristic.AUTOMATIC)
#search_parameters.time_limit.FromSeconds(300)
# Solve the problem.
solution = routing.SolveWithParameters(search_parameters)
# Print solution on console.
if solution:
print_solution(data, manager, routing, solution)
print()
print("Statistics")
print(' - wall time : %f s' % (int(routing.solver().WallTime())/1000))
solvingtime = int(routing.solver().WallTime())/1000
return solvingtime
if __name__ == '__main__':
node_num_array = [10,20,30,40,50,60,70,80,90,100]
solvingtime_array = []
num_array =[]
for i in node_num_array:
for j in range(0,4):
solvingtime = main(i)
solvingtime_array.append(solvingtime)
num_array.append(i)
print(i, "-->",solvingtime)
print(solvingtime_array)
print(num_array)
df_results = pd.DataFrame(data= {"num_nodes":num_array, "solvingtime":solvingtime_array})
#encoding="latin_1", sep=";")
print(df_results)
请帮我解决周期性的有能力的车辆路径问题。
在 google 组中找到相同的问题 here。
我要建模的内容:
1 个仓库
多个客户(假设有 4 个)
多天(假设 3 天)
具有每公里价格和特定容量的多种车型
每个客户都有:交货频率和每次交货的需求
每个客户都必须分配给一个交付模式。每个频率可能有多种交付模式。该模式指示当天是否可以交货。对于 1 和 3 个工作日的频率:
[[1,0,0],[0,1,0],[0,0,1]]
,2[[1,1,0],[1,0,1],[1,1,0]]
的频率,3 的频率:[1,1,1]
这些是可能的模式。
每个客户每次发货的需求是相同的,每天执行一次发货
所以我们有一组客户必须由一个 depo 交付。多种车辆类型可用于该工作。服务日期是灵活的,因为只有频率是固定给客户的,但是有多种可能性来满足需求。
到目前为止我做了什么:
我按工作日数复制了每个节点。
我限制了每天的depo节点开始和结束。
我用车辆乘以天数。
此外,我把日子当作不同种类的货物来处理。当那天不应该使用车辆时,我确实为车辆分配了零容量。
[[10, 15, 15, 0, 0, 0, 0, 0, 0], [0, 0, 0, 10, 15, 15, 0, 0, 0], [0, 0, 0, 0, 0, 0, 10, 15, 15]]
前三辆车是第一天的,后三辆车是第二天的 最后 3 个是第 3 天。
对于需求矩阵,我使用了相同的技巧。在 4 个客户 + 1 个仓库的情况下,需求矩阵可能如下所示
[[0, 3, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 3, 4, 5, 2, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2]]
第一个列表中的第二个条目 (3) 和第二个列表中的第 7 个条目 (3) 是针对同一客户的,只是在两个不同的日子。节点已复制。
到目前为止效果很好。但这不是我想做的。
我确实为每个客户每天手动分配需求,但我想通过为每个客户选择的交付模式分配需求。
模型可以将模式 [1,0,1]
分配给一个客户,频率为 2,将模式 [0,0,1]
分配给另一客户。这将导致有可能在第 3 天计划一次结合这两种需求的旅行。
我需要帮助来定义管理模式分配给客户的维度,从而产生“灵活”的需求矩阵。
感谢您的帮助。
完整代码:
"""Periodic Capacited Vehicles Routing Problem (PCVRP)."""
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
import numpy as np
def dublicate_nodes(base_distance_matrix, num_days):
matrix = []
for i in range(num_days):
day_element = []
for node in range(len(base_distance_matrix)):
node_element = []
for day in range(num_days):
node_element.append(base_distance_matrix[node])
day_element.append(np.concatenate(node_element).tolist())
matrix.extend(day_element)
#print(matrix)
return matrix
def depo_nodes(num_days, num_verhicles, num_nodes):
depo_array = []
for day in range(num_days):
for veh in range(int(num_verhicles/num_days)):
depo_array.append(day*num_nodes)
#print(depo_array)
return depo_array
def veh_types_costs(cost_array, num_per_type, num_days):
cost_array_km = []
for day in range(num_days):
for i in range(len(cost_array)):
for num in range(num_per_type[i]):
cost_array_km.append(cost_array[i])
#print(cost_array_km)
return(cost_array_km)
def veh_capacity_matrix(num_vehicle_per_type, vehicle_capacity_type, num_days):
matrix= []
for index in range(num_days):
matrix_element = []
for day in range(num_days):
for i, num in enumerate(num_vehicle_per_type):
for times in range(num):
if day == index:
matrix_element.append(vehicle_capacity_type[i]);
else:
matrix_element.append(0)
matrix.append(matrix_element)
#print(matrix)
return matrix
def create_data_model():
data = {}
data["num_days"] = 3 #Anzahl Tage
### Definition der Fahrezugtypen
data["num_vehicle_per_type"] = [1, 2] #Anzahl Fahrzeuge pro Typ
data["vehicle_costs_type_per_km"] = [1, 0.01] #Kosten pro km pro Fahrzeugtyp
data["vehicle_costs_type_per_stop"] = [1, 1000] #Kosten pro Stop pro Fahrzeugtyp
data['price_per_km'] = veh_types_costs(data["vehicle_costs_type_per_km"], data["num_vehicle_per_type"], data["num_days"]) #Matrix für price_per_km je Fahrzeug ertsellen
data["price_per_stop"] = veh_types_costs(data["vehicle_costs_type_per_stop"], data["num_vehicle_per_type"], data["num_days"])
data["vehicle_capacity_type"] = [10, 15] # Kapaität pro Fahrzeugtyp
data['vehicle_capacities_matrix'] = veh_capacity_matrix(data["num_vehicle_per_type"], data["vehicle_capacity_type"], data["num_days"]) #Kapazitäten pro Fahrzeugs pro Tag
print('vehicle_capacities_matrix')
print(data['vehicle_capacities_matrix'])
data["num_vehicles_per_day"] = sum(data["num_vehicle_per_type"]) #Gesamtanzahl der Fahrzeuge pro Tag
data['num_vehicles'] = data["num_days"] * data["num_vehicles_per_day"]# Gesamtanzahl der Fahrzeuge in gesamten Zeitraum
###Distanzmatrix bestimmen
data["base_distance_matrix"] = [
[
0, 548, 776, 696, 582
],
[
548, 0, 684, 308, 194
],
[
776, 684, 0, 992, 878
],
[
696, 308, 992, 0, 114
],
[
582, 194, 878, 114, 0
]
] #Distanzmatrix mit allen Kunden einzeln
data['distance_matrix'] = dublicate_nodes(data["base_distance_matrix"], data["num_days"]) # Distanzmatrix mit mehrfachen Nodes pro Kunden, je Tag ein Node
###Start und Ende festlegen
data["num_nodes"] = len(data["base_distance_matrix"]) # Anzahl Kunden
data['starts'] = depo_nodes(data["num_days"], data['num_vehicles'], data["num_nodes"]) #Deponodes (Start) für die einzelnen Fahrzeuge (Tage)
data['ends'] = depo_nodes(data["num_days"], data['num_vehicles'], data["num_nodes"]) #Deponodes (Ende) für die einzelnen Fahrzeuge (Tage)
###Demand pro Kunde
data['demands_matrix'] = [[0, 3, 0, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 3, 4, 5, 2, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2]] #Demandmatrix mit je einer list pro Tag
return data
def print_solution(data, manager, routing, solution):
"""Prints solution on console."""
total_distance = 0
total_load = 0
for vehicle_id in range(data['num_vehicles']):
if vehicle_id % data["num_vehicles_per_day"] == 0:
print(("------Tag {}------").format(int(vehicle_id/data["num_vehicles_per_day"])))
if routing.IsVehicleUsed(assignment= solution, vehicle=vehicle_id) == False:
continue
index = routing.Start(vehicle_id)
if vehicle_id >= data["num_vehicles_per_day"]:
plan_output = 'Route for vehicle {}:\n'.format(abs(vehicle_id-data["num_vehicles_per_day"]*int(vehicle_id/data["num_vehicles_per_day"])))
else:
plan_output = 'Route for vehicle {}:\n'.format(vehicle_id)
route_costs = 0
route_load = 0
while not routing.IsEnd(index):
node_index = manager.IndexToNode(index)
capacity_ID = int(vehicle_id/data["num_vehicles_per_day"])
route_load += data['demands_matrix'][capacity_ID][node_index]
plan_output += ' {0} Load({1}) -> '.format(node_index, route_load)
previous_index = index
index = solution.Value(routing.NextVar(index))
route_costs += routing.GetArcCostForVehicle(
previous_index, index, vehicle_id)
plan_output += ' {0} Load({1})\n'.format(manager.IndexToNode(index),
route_load)
plan_output += 'Costs of the route: {}€\n'.format(route_costs)
plan_output += 'Load of the route: {}\n'.format(route_load)
print(plan_output)
total_distance += route_costs
total_load += route_load
print('Total costs of all routes: {}€'.format(total_distance))
print('Total load of all routes: {}'.format(total_load))
def main():
"""Periodic CVRP problem."""
# Instantiate the data problem.
data = create_data_model()
# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']), data['num_vehicles'], data['starts'],
data['ends'])
# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)
### Kostenfunktion je Fahrzeug festlegen ###
def create_cost_callback(dist_matrix, km_costs, stop_costs):
# Create a callback to calculate distances between cities.
def distance_callback(from_index, to_index):
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return int(dist_matrix[from_node][to_node]) * (km_costs) + (stop_costs)
return distance_callback
for i in range(data['num_vehicles']):
cost_callback = create_cost_callback(data['distance_matrix'], data["price_per_km"][i],
data["price_per_stop"][i]) # Callbackfunktion erstellen
cost_callback_index = routing.RegisterTransitCallback(cost_callback) # registrieren
routing.SetArcCostEvaluatorOfVehicle(cost_callback_index, i) # Vehicle zuordnen
#Define Capacities for Vehicles for every Day
def create_demand_callback(demand_matrix, demand_index):
# Create a callback to calculate capacity usage.
def demand_callback(from_index):
#Returns the demand of the node.
# Convert from routing variable Index to demands NodeIndex.
from_node = manager.IndexToNode(from_index)
return demand_matrix[demand_index][from_node]
return demand_callback
for i in range(data["num_days"]): #Jedes Fahrzeug hat pro Tag eine andere Kapazität
demand_callback = create_demand_callback(data['demands_matrix'], i)
demand_callback_index = routing.RegisterUnaryTransitCallback(demand_callback)
dimension_name = 'Capacity_day_{}'.format(i)
routing.AddDimensionWithVehicleCapacity(
demand_callback_index,
0, # null capacity slack
data['vehicle_capacities_matrix'][i], # vehicle maximum capacities
True, # start cumul to zero
dimension_name)
# Setting first solution heuristic.
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.AUTOMATIC)
search_parameters.local_search_metaheuristic = (
routing_enums_pb2.LocalSearchMetaheuristic.AUTOMATIC)
search_parameters.time_limit.FromSeconds(1)
# Solve the problem.
solution = routing.SolveWithParameters(search_parameters)
# Print solution on console.
if solution:
print_solution(data, manager, routing, solution)
return solution
if __name__ == '__main__':
solution_array = []
solution = main()
所以我找到了解决问题的方法。
超过 40 个客户的问题的解决时间可能会更好。
我将不胜感激改进建议。
"""Periodic Capacited Vehicles Routing Problem with delivery pattern(PCVRP)."""
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
import numpy as np
import random
import math
import pandas as pd
def dublicate_nodes(base_distance_matrix, num_days):
matrix = []
for i in range(num_days):
day_element = []
for node in range(len(base_distance_matrix)):
node_element = []
for day in range(num_days):
node_element.append(base_distance_matrix[node])
day_element.append(np.concatenate(node_element).tolist())
matrix.extend(day_element)
#print(matrix)
return matrix
def depo_nodes(num_days, num_verhicles, num_nodes):
depo_array = []
for day in range(num_days):
for veh in range(int(num_verhicles/num_days)):
depo_array.append(day*num_nodes)
#print(depo_array)
return depo_array
def veh_types_costs(cost_array, num_per_type, num_days):
cost_array_km = []
for day in range(num_days):
for i in range(len(cost_array)):
for num in range(num_per_type[i]):
cost_array_km.append(cost_array[i])
#print(cost_array_km)
return(cost_array_km)
def veh_capacity_matrix(num_vehicle_per_type, vehicle_capacity_type, num_days):
matrix= []
for index in range(num_days):
matrix_element = []
for day in range(num_days):
for i, num in enumerate(num_vehicle_per_type):
for times in range(num):
if day == index:
matrix_element.append(vehicle_capacity_type[i]);
else:
matrix_element.append(0)
matrix.append(matrix_element)
#print(matrix)
return matrix
def dist_matrix(koordianten):
matrix =[]
for k_1 in koordianten:
matrix_element = []
for k_2 in koordianten:
matrix_element.append(np.linalg.norm(k_1-k_2))
matrix.append(matrix_element)
#print(matrix)
return matrix
def demand_matrix(demand_matrix_day,num_days):
matrix = []
for index in range(num_days):
matrix_element = []
for day in range(num_days):
if day == index:
matrix_element = matrix_element +demand_matrix_day
else:
matrix_element = matrix_element +(list(np.zeros(len(demand_matrix_day))))
matrix.append(matrix_element)
return matrix
def kunden_indizes(ID_list, num_days):
indizes = {}
for ID in ID_list:
indizes[ID] = []
for index, key in enumerate(indizes):
for i in range(len(ID_list)*num_days):
if (i % len(ID_list)) == index:
indizes[key].append(i)
#print(indizes)
return indizes
def create_data_model(node_num):
data = {}
data["num_days"] = 5 #Anzahl Tage
###Kundenset
num_IDs = node_num
base = [0]
data["IDs"] = list(range(0, num_IDs))
#data["IDs"] = [0, 1, 2, 3, 4]
print(data["IDs"])
data["demand"] = [random.randint(1,30) for i in range(0,num_IDs)]
#data["demand"] =[0, 16, 8, 1, 7]
data["demand"][0] = 0
print("demand", data["demand"])
data["frequenz"] = [random.randint(1,5) for i in range(0,num_IDs)]
#data["frequenz"] =[0, 3, 5, 2, 1]
data["frequenz"][0] = 0
print("freq ",data["frequenz"])
summe_dem =0
for index, demand in enumerate(data["demand"]):
summe_dem += data["demand"][index] * data["frequenz"][index]
print("DEMANDSUMME: ",summe_dem)
data["koordianten"] = np.random.rand(num_IDs, 2)*1000
#data["koordianten"] = np.array([(0, 0), (4, 0), (4, 4), (0, 4), (3, 3)])*100
data["koordianten"][0] = (0,0)
#print("koord ", data["koordianten"])
data["PAT"] = {
5:
[[1, 1, 1, 1, 1]],
4:
[[0, 1, 1, 1, 1],
[1, 0, 1, 1, 1],
[1, 1, 0, 1, 1],
[1, 1, 1, 0, 1],
[1, 1, 1, 1, 0]],
3: [[0, 1, 0, 1, 1],
[1, 0, 1, 0, 1],
[1, 1, 0, 1, 0],
[0, 1, 1, 0, 1],
[1, 0, 1, 1, 0],
],
2: [[1, 0, 1, 0, 0],
[0, 1, 0, 1, 0],
[0, 0, 1, 0, 1],
[1, 0, 0, 1, 0],
[0, 1, 0, 0, 1]],
1: [[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 1]],
}
### Definition der Fahrezugtypen
data["vehicle_costs_type_per_km"] = [1, 0.01] #Kosten pro km pro Fahrzeugtyp
data["vehicle_costs_type_per_stop"] = [1, 1000] #Kosten pro Stop pro Fahrzeugtyp
data["vehicle_capacity_type"] = [100, 200] # Kapaität pro Fahrzeugtyp
data["num_vehicle_per_type"] = [math.ceil(summe_dem /data["vehicle_capacity_type"][0]), math.ceil(summe_dem /data["vehicle_capacity_type"][1])] # Anzahl Fahrzeuge pro Typ
data['price_per_km'] = veh_types_costs(data["vehicle_costs_type_per_km"], data["num_vehicle_per_type"], data["num_days"]) #Matrix für price_per_km je Fahrzeug ertsellen
data["price_per_stop"] = veh_types_costs(data["vehicle_costs_type_per_stop"], data["num_vehicle_per_type"], data["num_days"])
data['vehicle_capacities_matrix'] = veh_capacity_matrix(data["num_vehicle_per_type"], data["vehicle_capacity_type"], data["num_days"]) #Kapazitäten pro Fahrzeugs pro Tag
#print('vehicle_capacities_matrix')
#print(data['vehicle_capacities_matrix'])
data["num_vehicles_per_day"] = sum(data["num_vehicle_per_type"]) #Gesamtanzahl der Fahrzeuge pro Tag
data['num_vehicles'] = data["num_days"] * data["num_vehicles_per_day"]# Gesamtanzahl der Fahrzeuge in gesamten Zeitraum
###Distanzmatrix bestimmen
data["base_distance_matrix"] = dist_matrix(data["koordianten"])
data['distance_matrix'] = dublicate_nodes(data["base_distance_matrix"], data["num_days"]) # Distanzmatrix mit mehrfachen Nodes pro Kunden, je Tag ein Node
###Start und Ende festlegen
data["num_nodes"] = len(data["base_distance_matrix"]) # Anzahl Kunden
data['starts'] = depo_nodes(data["num_days"], data['num_vehicles'], data["num_nodes"]) #Deponodes (Start) für die einzelnen Fahrzeuge (Tage)
data['ends'] = depo_nodes(data["num_days"], data['num_vehicles'], data["num_nodes"]) #Deponodes (Ende) für die einzelnen Fahrzeuge (Tage)
###Demand pro Kunde
data["kunden_indizes"] = kunden_indizes(data["IDs"], data["num_days"])
data["demands_matrix"] = demand_matrix(demand_matrix_day=data["demand"], num_days=data["num_days"])
#print(data["demands_matrix"])
return data
def print_solution(data, manager, routing, solution):
"""Prints solution on console."""
total_distance = 0
total_load = 0
for vehicle_id in range(data['num_vehicles']):
if vehicle_id % data["num_vehicles_per_day"] == 0:
print(("------Tag {}------").format(int(vehicle_id/data["num_vehicles_per_day"])))
if routing.IsVehicleUsed(assignment= solution, vehicle=vehicle_id) == False:
continue
index = routing.Start(vehicle_id)
if vehicle_id >= data["num_vehicles_per_day"]:
plan_output = 'Route for vehicle {}:\n'.format(abs(vehicle_id-data["num_vehicles_per_day"]*int(vehicle_id/data["num_vehicles_per_day"])))
else:
plan_output = 'Route for vehicle {}:\n'.format(vehicle_id)
route_costs = 0
route_load = 0
while not routing.IsEnd(index):
node_index = manager.IndexToNode(index)
capacity_ID = int(vehicle_id/data["num_vehicles_per_day"])
route_load += data['demands_matrix'][capacity_ID][node_index]
plan_output += ' {0} Load({1}) -> '.format(node_index, route_load)
previous_index = index
index = solution.Value(routing.NextVar(index))
route_costs += routing.GetArcCostForVehicle(
previous_index, index, vehicle_id)
plan_output += ' {0} Load({1})\n'.format(manager.IndexToNode(index),
route_load)
plan_output += 'Costs of the route: {}€\n'.format(route_costs)
plan_output += 'Load of the route: {}\n'.format(route_load)
print(plan_output)
total_distance += route_costs
total_load += route_load
print('Total costs of all routes: {}€'.format(total_distance))
print('Total load of all routes: {}'.format(total_load))
def main(node_num):
"""Periodic CVRP problem."""
# Instantiate the data problem.
data = create_data_model(node_num)
# Create the routing index manager.
manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']), data['num_vehicles'], data['starts'],
data['ends'])
# Create Routing Model.
routing = pywrapcp.RoutingModel(manager)
### Kostenfunktion je Fahrzeug festlegen ###
def create_cost_callback(dist_matrix, km_costs, stop_costs):
# Create a callback to calculate distances between cities.
def distance_callback(from_index, to_index):
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return int(dist_matrix[from_node][to_node]) * (km_costs) + (stop_costs)
return distance_callback
for i in range(data['num_vehicles']):
cost_callback = create_cost_callback(data['distance_matrix'], data["price_per_km"][i],
data["price_per_stop"][i]) # Callbackfunktion erstellen
cost_callback_index = routing.RegisterTransitCallback(cost_callback) # registrieren
routing.SetArcCostEvaluatorOfVehicle(cost_callback_index, i) # Vehicle zuordnen
#Define Capacities for Vehicles for every Day
def create_demand_callback(demand_matrix, demand_index):
# Create a callback to calculate capacity usage.
def demand_callback(from_index):
#Returns the demand of the node.
# Convert from routing variable Index to demands NodeIndex.
from_node = manager.IndexToNode(from_index)
return demand_matrix[demand_index][from_node]
return demand_callback
for i in range(data["num_days"]): #Jedes Fahrzeug hat pro Tag eine andere Kapazität
demand_callback = create_demand_callback(data['demands_matrix'], i)
demand_callback_index = routing.RegisterUnaryTransitCallback(demand_callback)
dimension_name = 'Capacity_day_{}'.format(i)
routing.AddDimensionWithVehicleCapacity(
demand_callback_index,
0, # null capacity slack
data['vehicle_capacities_matrix'][i], # vehicle maximum capacities
True, # start cumul to zero
dimension_name)
#Drop visits that would exceed the frequency
for index, key in enumerate(data["kunden_indizes"]):
if index == 0:
continue
#routing.solver().Add(sum(routing.ActiveVar(manager.NodeToIndex(i)) for i in data["kunden_indizes"][key]) == data["frequenz"][index])
bool_array = []
for index, freq in enumerate(data["frequenz"]):
if index == 0:
continue
bool_array_part =[]
for index_pat, pat in enumerate(data["PAT"][freq]):
#print(index,freq,index_pat)
bool_name = str(index) +str(freq) + str(index_pat)
bool_array_part.append(routing.solver().BoolVar(bool_name))
bool_array.append(bool_array_part)
#print(bool_array)
for i in bool_array:
routing.solver().Add(sum(i) == 1)
node_array = []
for index, freq in enumerate(data["frequenz"]):
if index == 0:
continue
node_array_part = []
for index_pat, pat in enumerate(data["PAT"][freq]):
node_array_sub_part = []
for index_day, day_value in enumerate(pat):
if day_value == 1:
node_array_sub_part.append(data["kunden_indizes"][index][index_day])
#print(node_array_part)
node_array_part.append(node_array_sub_part)
node_array.append(node_array_part)
#print(node_array)
for index, bool in enumerate(bool_array):
for i in range(len(bool)):
#print(node_array[index][i])
#print(bool_array[index][i])
routing.solver().Add(sum(routing.ActiveVar(manager.NodeToIndex(i)) for i in node_array[index][i]) * bool_array[index][i] == bool_array[index][i] * len(node_array[index][i]))
#routing.solver().Add(routing.ActiveVar(manager.NodeToIndex(5)) == 1)
penalty = 0
for node in range(0, len(data['distance_matrix'])):
if node in data["kunden_indizes"][0]:
continue
else:
routing.AddDisjunction([manager.NodeToIndex(node)], penalty)
# Setting first solution heuristic.
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.AUTOMATIC)
search_parameters.local_search_metaheuristic = (
routing_enums_pb2.LocalSearchMetaheuristic.AUTOMATIC)
#search_parameters.time_limit.FromSeconds(300)
# Solve the problem.
solution = routing.SolveWithParameters(search_parameters)
# Print solution on console.
if solution:
print_solution(data, manager, routing, solution)
print()
print("Statistics")
print(' - wall time : %f s' % (int(routing.solver().WallTime())/1000))
solvingtime = int(routing.solver().WallTime())/1000
return solvingtime
if __name__ == '__main__':
node_num_array = [10,20,30,40,50,60,70,80,90,100]
solvingtime_array = []
num_array =[]
for i in node_num_array:
for j in range(0,4):
solvingtime = main(i)
solvingtime_array.append(solvingtime)
num_array.append(i)
print(i, "-->",solvingtime)
print(solvingtime_array)
print(num_array)
df_results = pd.DataFrame(data= {"num_nodes":num_array, "solvingtime":solvingtime_array})
#encoding="latin_1", sep=";")
print(df_results)