作者简介:本人擅长运筹优化建模及算法设计,包括各类车辆路径问题、生产车间调度、二三维装箱问题,熟悉CPLEX和gurobi求解器
微信公众号:运筹优化与学习
若有运筹优化建模及算法定制需求,欢迎联系我们私聊沟通
前言
前篇推文开启了作业车间调度问题的学习,介绍了遗传算法求解作业车间调度问题,本篇将介绍另一种经典的启发式算法-蚁群优化算法(Ant Colony Optimization,ACO)用以求解作业车间调度问题。
感兴趣的可以先去阅读一下前一篇推文,了解作业车间调度问题以及遗传算法求解思路:
本次代码还是求解上篇推文提到的作业车间调度问题,故不再重复介绍问题背景,如有不熟悉的可通过上文链接进行了解学习。
蚁群算法原理
(1)状态转移函数
初始状态下,每条路径上的信息素数量是相同的。同时,初始状态下,每只蚂蚁会通过随机寻找路径的方式前行,信息素释放的数量与搜索路径的目标函数值成反比。随后,搜索过程中,每只蚂蚁根据路径上残留的信息素,计算蚂蚁前往每一个节点的概率,并基于概率选择下一个访问的节点。其中,第 t t t次迭代蚂蚁 k k k从节点 i i i前往节点 j j j的概率 P i j k ( t ) P_{ij}^k(t) Pijk(t)的计算表达式如下:
表达式中, τ i j ( t ) \tau_{ij}(t) τij(t)表示第 t t t次迭代从节点 i i i前往节点 j j j残留的信息素数量, η i j ( t ) \eta_{ij}(t) ηij(t)表示节点 i i i前往节点 j j j的距离长度的倒数, J k J_k Jk表示蚂蚁 k k k还没有访问过的节点的集合。同时, a a a表示信息素因子, b b b表示启发函数因子,这两个参数为蚁群优化算法的关键参数。
(2)更新信息素
在初始状态下,每条路径的信息素数量均设置为0。在搜索过程中,部分信息素会随着时间流逝而挥发,信息素挥发快慢通过参数信息素挥发因子 c c c进行控制。信息素的更新计算表达式如下:
表达式中, Δ τ i j k \Delta \tau_{ij}^k Δτijk蚂蚁 k k k遍历过的路径总长度的倒数, τ i j ( t ) \tau_{ij}(t) τij(t)表示第 t t t次迭代从节点 i i i前往节点 j j j残留的信息素数量。
代码说明
编码方式同样采用基于工序编码全排列的编码方式进行编码,染色体的长度等于所有工件的工序之和。编码顺序代表工序被加工的优先级。
读取数据类
读取算例数据
class Information():
def __init__(self, file_name, init_pheromone, min_pheromone):
self.min_pheromone = min_pheromone
#Read Data
self.data = self.__readData(file_name)
self.num_jobs = len(self.data)
self.num_machines = len(self.data[0])
#Create Graph
self.G, self.node_names = self.__buildGraph(init_pheromone)
def __readData(self, file_name):
jobs = []
with open("../test_instances/" + file_name,'r') as file:
for line in file:
machines = {}
this_machine = None
for j,value in enumerate(line.split()):
if j%2 != 0:
machines.update({this_machine : value})
else:
this_machine = value
jobs.append(machines)
return jobs
蚂蚁类
构造蚂蚁的搜索路径
class Ant():
def __init__(self, Graph, node_names, ALPHA, BETA, seed, extended_seed):
self.seed = seed + extended_seed
self.ALPHA = ALPHA
self.BETA = BETA
self.G = Graph
self.not_visited = node_names.copy()
self.ant_path = []
def evolve(self):
np.random.seed(self.seed)
current_node = (-1,-1)
while self.not_visited:
if len(self.not_visited) == 1:
next_node = self.not_visited[0]
else:
next_node = self.__chooseNextNode(current_node)
self.ant_path.append((current_node, next_node))
current_node = next_node
self.not_visited.remove(next_node)
return self.ant_path
def __chooseNextNode(self, current_node):
node_probabilities = self.__calculateNodeProbabilityChoices(current_node)
nodes = list(node_probabilities.keys())
normalized_probabilities = self.__normalizeProbabilities(node_probabilities.values())
indexs = [ i for i in range(len(normalized_probabilities))]
next_node_index = np.random.choice(
indexs,
p=normalized_probabilities)
return nodes[next_node_index]
若有运筹优化建模及算法定制需求,欢迎联系我们私聊沟通