在这一章节,我们将用到minizinc, 类似于一个编译器,但是它提供不同的solver帮助我们解决问题,我们只需要对问题中的限制(binary constraint network)进行描述(1.constant 2.variable 3.constraint),要求solver 为我们提供满足解或者最优解。
生活中我们会遇到很多资源分配问题,例如
在departure point, 有两种不同类型的车,一种只运常温货物,一种可以运常温和低温货物。每辆车都有各自的capacity
如今送货到很多家商店,每个商店都有对于货物的不同需求。
对于不同的问题条件,请给出不同的解决方案。
4.For the first three questions, you were required only to write MiniZinc encodings of the problems, and to note the limits on problem size that can be solved optimally, and on problems that can be solved at all, by MiniZinc’s solver alone. In order to scale up to somewhat larger problem instances, you will now implement large neighbourhood search (LNS) in Python, using MiniZinc with its default FD solver to search each successive neighbourhood.
Answer:
import argparse
import random
import csv
# Complete the file with your LNS solution
headline = [] # store the headline of the csv file
with open(start_solution_filename,'r') as f:
solution_list=f.readlines()
headline= solution_list[0].split(',') # read and split the headline
truck_amount = int(headline[0]) # load the truck amount
customer_amount = int(headline[1]) # Load the customer amount
cost = float(headline[2]) # load the original cost
truck= [] # a data structure([{},{},{}]) storing every truck's info
line = [] # a data structure([[],[],[]]) storing every line of csv
new_cost = 0 # store the new cost we got and compare it with original one
for index in range(1,len(solution_list)) : # create enough list to store the every line of csv.
line[index].append([])
for index in range(1, truck_amount+1) : # create enough dic to hold every truck's info
truck[index].append({})
for index in range(1,len(solution_list)):
# read and split the rest lines so that we can move its' info into truck[]
line[index] = solution_list[index].split(',')
for index in range(1,len(solution_list)) : # go through all the input lines
for truck_id in range(1,truck_amount): # match the truck with their info
if line[index][0] == truck_id:
for customer_order in range(1,customer_amount): # match the customer order with their info
if line[index][1] == customer_order:
truck[truck_id][customer_order] = line[index] # push the corresponding info into each dic
break
# start to detect the neighbourhood
for index in (1,truck_amount): # go through all the trucks
if len(truck[index])== 1: # if the truck only have one customer then skip it
continue
else:
for customer in range(1,len(truck[index])) : # if not, then change their order of visiting
# destroy a part of parameters(only the visiting order) and assign new value randomly
truck[index][customer][1] = random.choice(range(1,len(truck[index])))
# I have no idea how to load the .dzn files, so I use the pseudocode here
new_cost = (sum(each truck’running distance) * cost of cents per km / 100.
if new_cost < cost : # if the new assignment is better, then output this new solution
cost = new_cost # refresh the cost value
print(truck_amount, " ", customer_amount, " ", cost)
for index_1 in (1, truck_amount):
for index_2 in len(truck[index_1]):
print(truck[index_1][index_2])
if __name__ =='__main__':
parser = argparse.ArgumentParser()
parser.add_argument('problem_filename', help='problem file')
parser.add_argument('start_solution_filename', help='file describing the solution to improve')
args = parser.parse_args()
start_solution_filename = args.start_solution_filename
problem_filename = args.problem_filename
论述:
Because I have no idea how to load the .dzn files in python, so I have use a little part of pseudocode to calculate the “cost” in my python code.
In my design, the neighbourhood is the records, which are transported by the same truck but the different delivering order.
Every time when we find such a group, the parameters(delivering order) will be destroyed and assigned randomly.
If the now_cost is lower than cost in last situation, then output the new solution and refresh the cost value with new_cost.
In this way, after we go through the whole solution records then the optimal solution can be found.