python实现禁忌搜索算法

禁忌搜索算法实现订单接收与调度

在按订单生产的制造系统中,有限的生产能力与严格的订单交货期要求决策者从若干候选订单中选择接受某些订单并
编制生产计划。决策者需在订单收益与拖期惩罚之间进行权衡,以所有接受订单的实际收益之和最大为目标进行优化。提出了一种禁忌搜索算法用于求解考虑发布日期和队列准备时间的单机环境下的订单接受与调度问题。
数据文件如下:

订单序号惩罚系数Wj库存费用Kt收益Qj交货期DJ处理时间Pj
10.1420.002550228
20.1320.002245205
30.3210.002346197
40.3450.002245159
50.4320.0017353311
60.1230.0013262013
70.1220.0023461414
80.1330.001428139
90.1540.002958206
100.1430.002245219

代码如下:

import pandas as pd
import numpy as np
import copy
import random




    
def Inc(candidate,rate):
    
    global current_scheme
    
    #增加的订单的次序
    incOrder = random.sample(range(1, max(current_scheme)+2), 1)[0]
    #选择增加的位置,不能和已经有的重合
    empty_index = [n for m,n in zip(current_scheme,np.arange(len(current_scheme))) if m == 0]
    opsition = random.sample(empty_index, 1)[0]
    
    #得到增加一个order的可行解
    inc_candidate = copy.copy(current_scheme)
    inc_candidate[opsition] = incOrder
    
    #对incOrder后编号的订单号加1
    for i in range(incOrder,max(current_scheme)+1):
        inc_candidate[current_scheme.index(i)] = i+1
        
    candidate.append(inc_candidate)
    #取inc_candidate的邻域,取得数量由rate控制,对inc_candidate进行交换就可以
    
    #存储两个交换的位置,避免重复交换
    
    exchange_position = []
    #由订单的数量max(inc_candidate)与rate共同决定
    orderNum = max(inc_candidate)
    temp = int((orderNum*(orderNum-1)/2+orderNum*(len(inc_candidate)-orderNum))*rate)
    
    #随机选取邻域
    while True:
        #获取交换的位置
        current = random.sample(range(0,len(inc_candidate)), 2)
        current.sort()
        #若果这两个位置都是0不必交换
        if inc_candidate[current[0]] == inc_candidate[current[1]]:
            exchange_position.append(current)
            
        if current not in exchange_position:
            exchange_position.append(current)
            candidate.append(exchange(current,inc_candidate))   
            temp -= 1
            if temp == 0:
                break
                
    return candidate



def Dec(candidate,rate):
    
    global current_scheme
    
    #选择减的位置,和已经有的重合
    occupy_index = [n for m,n in zip(current_scheme,np.arange(len(current_scheme))) if m != 0]
    opsition = random.sample(occupy_index, 1)[0]
    #确定减少的订单的序列值
    decOrder = current_scheme[opsition]
    
    #得到减少一个order的可行解
    dec_candidate = copy.copy(current_scheme)
    dec_candidate[opsition] = 0
    
    #对incOrder后编号的订单号减1
    for i in range(decOrder+1,max(current_scheme)+1):
        dec_candidate[current_scheme.index(i)] = i-1
        
    candidate.append(dec_candidate)
    #取inc_candidate的邻域,取得数量由rate控制,对inc_candidate进行交换就可以
    
    #存储两个交换的位置,避免重复交换
    exchange_position = []
    #由订单的数量max(inc_candidate)与rate共同决定
    orderNum = max(dec_candidate)
    temp = int((orderNum*(orderNum-1)/2+orderNum*(len(dec_candidate)-orderNum))*rate)
    
    #获取邻域
    while True:
        #获取交换的位置
        current = random.sample(range(0,len(dec_candidate)), 2)
        current.sort()

        #若果这两个位置都是0不必交换
        if dec_candidate[current[0]] == dec_candidate[current[1]]:
            exchange_position.append(current)

        if current not in exchange_position:
            exchange_position.append(current)
            candidate.append(exchange(current,dec_candidate))   
            temp -= 1

            if temp == 0:
                break
                
    return candidate


def Fix(candidate,rate):
    
    global current_scheme
    
    
    candidate.append(current_scheme)
    #取inc_candidate的邻域,取得数量由rate控制,对inc_candidate进行交换就可以
    #存储两个交换的位置,避免重复交换
    exchange_position = []
    #由订单的数量max(inc_candidate)与rate共同决定
    orderNum = max(current_scheme)
    temp = int((orderNum*(orderNum-1)/2+orderNum*(len(current_scheme)-orderNum))*rate)
    
    #获取邻域
    while True:
        #获取交换的位置
        current = random.sample(range(0,len(current_scheme)), 2)
        current.sort()

        #若果这两个位置都是0不必交换
        if current_scheme[current[0]] == current_scheme[current[1]]:
            exchange_position.append(current)

        if current not in exchange_position:
            exchange_position.append(current)
            candidate.append(exchange(current,current_scheme))   
            temp -= 1
            
            if temp == 0:
                break
                
    return candidate
    

#初始化可行解
def initialize_scheme(order_num):
    global best_scheme
    global best_q
    global current_scheme
    global current_q
    global current_best
    
    #选择订单的个数,初始为所有的一半
    selectNumOrder = int(order_num/2)
    #得到选择的订单,这是0-9选 5 个
    selectOrder = random.sample(range(0,len(data)-1),selectNumOrder) 
    
    #给选择的订单排序从1开始
    orderOrder = random.sample(range(1,selectNumOrder+1),selectNumOrder) 
    
    #生成可行解序列
    for i in range(selectNumOrder):
        current_scheme[selectOrder[i]] = orderOrder[i]
    
    #获得初始可行解获得的受益
    current_q = profit(current_scheme)
    current_best.append(current_q)
    #初始化最好解和受益
    best_scheme.append(current_scheme)
    best_q.append(current_q)
    
    
    
    
    
    
def profit(scheme):
    global alpha
    global beta
    global data
    #y1是接收订单的数量
    y1 = max(scheme)
    
    #y2是受益,S是上一个订单的开始时间,+P为这个订单结束时间
    y2 = 0.0
    S = 0.0
    
    #依次计算每个订单的受益,scheme.index(i)是排在第i位执行的订单
    for i in range(1,y1+1):
        
        #获得第i位执行的订单的信息
        order = scheme.index(i)
        W = data.iloc[order]['惩罚系数Wj']
        K = data.iloc[order]['库存费用Kt']
        Q = data.iloc[order]['收益Qj']
        D = data.iloc[order]['交货期DJ']
        P = data.iloc[order]['处理时间Pj']

        #该订单结束处理的时间
        S += P 
        #延期的时间,
        delay_time = max(S - D,0)
        y2 += Q - W*delay_time - K*delay_time
        
    total_profit = y1*alpha+y2*beta
    return total_profit




def getCandidate(numCandidates):
    
    global best_q
    global best_scheme
    global current_tabu_num
    global current_q
    global current_scheme
    global tabu_list
    global current_best
    
    #记录邻域候选解
    candidate = []
    #录邻域候选解的收益
    candidate_q = []
    #找到三个方向的candidate,并选取这里面的最优解最为current_scheme
    #判断是否能增加或者减少一个order
    orderNum = max(current_scheme)
    
    if 1 < orderNum < len(current_scheme):
        candidate = Inc(candidate,numCandidates)
        candidate = Dec(candidate,numCandidates)
        candidate = Fix(candidate,numCandidates)
        
    elif orderNum == 1:
        candidate = Inc(candidate,numCandidates)
        candidate = Fix(candidate,numCandidates)
        
    elif orderNum == len(current_scheme):
        candidate = Dec(candidate,numCandidates)
        candidate = Fix(candidate,numCandidates)
        
    #计算邻域候选解的收益
    for scheme in candidate:
        if scheme not in tabu_list:
            candidate_q.append(profit(scheme))
        else:
            candidate_q.append(0)
    

    #得到候选解中的最优解
    candidate_best = max(candidate_q)
    best_index = candidate_q.index(candidate_best)
    
    #更新现在的最优解
    current_scheme = copy.copy(candidate[best_index])
    current_q = candidate_best
    
    
    #与当前最优解进行比较 
    now_best_q = best_q[-1]
    now_best_scheme = best_scheme[-1]
    
    current_best.append(now_best_q)
    if current_q > now_best_q:
        best_q.append(current_q)
        best_scheme.append(current_scheme)
    else:
        best_q.append(now_best_q)
        best_scheme.append(now_best_scheme)
        
    #加入禁忌表
    tabu_list.append(current_scheme)  
    
    
def exchange(current,inc_candidate):
    index1 = current[0]
    index2 = current[1]
    current_list = copy.copy(inc_candidate)
    mid = current_list[index1]
    current_list[index1] = current_list[index2]
    current_list[index2] = mid
    return current_list
    
    
#更新禁忌表
def update_tabu(tabu_limit):
    global tabu_list
    tabu_list_len = len(tabu_list)
    if tabu_list_len > tabu_limit:
        del(tabu_list[0])
        
if __name__  == '__main__':
    data = pd.read_excel(r'data.xlsx')
    #订单数量
    order_num = len(data)
    #订单序号 惩罚系数Wj 库存费用Kt 收益Qj 交货期DJ 处理时间Pj
    #先随机初始化,得到一个可行解队列
    #记录迭代次数
    iteration = 20 ###########################################################可以调整的参数
    alpha = 0.01 ###########################################
    beta = 0.99 ###############################################
    #记录每次迭代最好的方案
    best_scheme = []
    best_q = []
    #记录邻域中最好的方案
    current_scheme = [0]*order_num
    current_q = 0.0
    current_best = []
    #禁忌表
    tabu_list = []
    #禁忌长度,即禁忌期限
    tabu_limit = 30 ############################################################
    #当前禁忌对象数量
    current_tabu_num = 0        
    #定义获得邻域的候选解数量,为理论邻域数量的多少。5*4/2 + 5*5
    numCandidates = 0.5 ############################################################3
    initialize_scheme(order_num)
    for it in range(iteration):
        print('第',it,'次迭代')
        print('最佳收益:',best_q[-1])
        #获得候选解,邻域,这里有三种方式,增加1个订单,减少1个订单,不改变订单数量->交换订单的执行次序
        getCandidate(numCandidates)
        update_tabu(tabu_limit)
    print("最好的方案是:",best_scheme[-1])

运行结果作图:

#下面进行可视化,甘特图,迭代曲线
import matplotlib.pyplot as plt
from pylab import mpl
from matplotlib import rcParams


plt.figure(dpi = 160,figsize=(5, 4))
config = {
    "font.family":"serif",    #serif
    "font.size": 10,
    "mathtext.fontset":'stix',
}
rcParams.update(config)

plt.plot(np.arange(len(best_q)),best_q,'-ok')
plt.rcParams['xtick.direction'] = 'in'#将x周的刻度线方向设置向内
plt.rcParams['ytick.direction'] = 'in'#将y轴的刻度方向设置向内

plt.xlabel("Iteration",{"size":10})
plt.ylabel("Total revenue",{"size":10})
plt.show()

在这里插入图片描述
甘特图,代码如下:

def gantt(best_scheme,data):
    #对应加工的订单号
    orders = []
    #对应的加工开始时间
    ST = []
    #对应的加工结束时间
    ET = []
    #对应的DDL
    DL = []
    s = 0
    for i in range(1,max(best_scheme[-1])+1):
        order = best_scheme[-1].index(i)
        orders.append(order+1)
        ST.append(s)
        s += data.iloc[order]['处理时间Pj']
        ET.append(s)
        DL.append(data.iloc[order]['交货期DJ'])
    
    plt.figure(dpi = 160,figsize=(5, 4))
    config = {
        "font.family":"serif",    #serif
        "font.size": 10,
        "mathtext.fontset":'stix',
    }
    rcParams.update(config)
    
    for i in range(len(orders)):
        plt.barh(orders[i], ET[i]-ST[i],0.3, left=ST[i],color = 'k')
        plt.barh(orders[i], 0.2,0.5, left=DL[i],color = 'r')
    
    plt.xlabel("Time",{"size":10})
    plt.ylabel("Order Number ",{"size":10})
    plt.yticks(np.arange(1,len(best_scheme[-1])+1))
    plt.legend(['Process','Deadline'],loc='upper right',frameon=False,fontsize = "small")


    
gantt(best_scheme,data)
    



在这里插入图片描述

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
作为AI语言,Python的应用范围非常广泛,包括求解CVRP问题。禁忌搜索算法是一种优化算法,它是一种局部搜索技术,通过在搜索过程中维护一个禁忌列表来避免陷入局部最优解而得到全局最优解。 以下是使用Python实现禁忌搜索算法求解CVRP问题的步骤: 1. 定义问题 CVRP问题是指在有限的车辆数量和容量限制下,将一定数量的货物从一个中央仓库运送到不同的客户处,使得运输成本最小化。该问题可以用一个带有容量限制的图来表示,其中每个节点代表一个客户,边权代表两个节点之间的距离,节点权代表每个客户的需求量。 2. 初始化 初始化一个禁忌列表和一个初始解,初始解可以通过随机化或贪心算法得到。禁忌列表用于记录已经访问过的解,以避免在搜索过程中重复访问。 3. 迭代搜索 在每个迭代中,根据禁忌列表和当前解生成一组邻域解,并选择其中最优解作为下一个解。如果该解不在禁忌列表中,则将其加入禁忌列表中。如果禁忌列表已满,则删除其中最早的解。 4. 跳出循环 在达到最大迭代次数或满足停止准则时跳出循环。 5. 输出结果 输出得到的最优解及其对应的路径和成本。 下面是一个简单的Python代码示例: ``` import random def get_initial_solution(): # 随机化或贪心算法得到初始解 return solution def get_neighborhood(solution): # 生成邻域解 return neighborhood def is_tabu(solution): # 判断该解是否在禁忌列表中 return solution in tabu_list def update_tabu(solution): # 更新禁忌列表 tabu_list.append(solution) if len(tabu_list) > tabu_list_size: tabu_list.pop(0) def get_best_solution(neighborhood): # 选择最优解 return best_solution def taboo_search(max_iterations, tabu_list_size): # 禁忌搜索算法 tabu_list = [] current_solution = get_initial_solution() best_solution = current_solution for i in range(max_iterations): neighborhood = get_neighborhood(current_solution) candidate_solution = get_best_solution(neighborhood) if is_tabu(candidate_solution): continue if candidate_solution < best_solution: best_solution = candidate_solution current_solution = candidate_solution update_tabu(candidate_solution) return best_solution best_solution = taboo_search(max_iterations=1000, tabu_list_size=10) print(best_solution) ``` 在实现禁忌搜索算法时,需要注意选择合适的搜索策略和参数,以及合适的停止准则,以确保得到最优解。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值