tabu禁忌搜索

禁忌搜索算法是模拟人类行为的一种优化算法,举个例子,有一天你准备出门,但是发现家里的钥匙不见了,所以你在桌子上、床上、衣服口袋找了一遍,仍然没找到,下一步你可能会去洗脸台、阳台找钥匙,这就是人的记忆原则:已经寻找过的地方不太可能再次寻找。当你翻遍所有可能的地方还是没有找到,这是你很有可能返回桌子、床上、衣服口袋再次寻找,因为你会不自觉地认为刚才的寻找不够仔细。。。

关于算法的理论讲解看下面三个图,从书上引用的。





拿一个实例来说:现在我有一个数组data=[1,2,3,4,5,6,7],一个评价函数accessment(data,w)=data*w;每次我们可以交换data中的任意两个元素,后一次交换操作在前一次的操作结果上进行,要求在有限的交换次数下,找到使accessmen最大的交换结果。为了便于理解这里设定w=[7,6,5,4,3,2,1]'。简单来说怎么样改变data中元素的位置使data*w最大,直观来看,当data=[7,6,5,4,3,2,1]时为全局最优解。下面我们用禁忌搜索算法来模拟这个搜索过程。

%============函数1:禁忌搜索

function [out,top]=tabu_search(data_orig,weight,N)
% % %禁忌搜索的主函数
%data_orig初始样本 ,weight权重列向量,N搜索的最大次数
%out 最优的交换结果,top是accessment函数的最大值
data=data_orig;
top=accessment(data,weight); %初始化全局最优值
tabu=[]; %初始情况下,禁忌表为空
for i=1:1:N
    n=length(data);
    y=nchoosek(1:n,2); %data中数字的所有交换方式,共有count种
    data_change=data_refine(data,y);  %按照y中的方式对data中的数字进行交换,得到结果data_change
    target=accessment(data_change,weight);%所有交换结果的评价值
    [seq]=sort(target);
    cadinate=[];
    
    local_top=seq(end:-1:end-4);
    prior=zeros(5,2);
    for j=1:1:5  %选取评价值较高的5个结果,作为候选解
        p=find(target==local_top(j));
        prior(j,:)=[y(p(1),1),y(p(1),2)];
        target(p(1))=-1;
        cadinate=[cadinate;data(prior(j,1)),data(prior(j,2))];
    end
    
    E_P=zeros(5,2); %判断这5个候选解是否属于禁忌表
    for ep=1:1:5
        [exist,pos]=belong_tabulist(tabu,cadinate(ep,:));
        E_P(ep,1)=exist;E_P(ep,2)=pos;
    end
    
    if E_P(1,1)==1 %最优的候选解已经在禁忌表中
        if local_top(1)>top  %禁忌项满足特赦准则
            top=local_top(1);
            data=data_refine(data,prior(1,:));
            tabu=tabu_refine(tabu,cadinate(1,:),E_P(1,2));
        else  %禁忌项不满足特赦准则,需要找到最优的非禁忌项
            bin=find(E_P(:,1)==0);
            idx=bin(1);
            if local_top(idx)>top
                top=local_top(idx);
            end
            data=data_refine(data,prior(idx,:));
            tabu=tabu_refine(tabu,cadinate(idx,:),E_P(idx,2));
        end
    else %最优候选解不在禁忌表中
        if local_top(1)>top
                top=local_top(1);
        end
        data=data_refine(data,prior(1,:));
        tabu=tabu_refine(tabu,cadinate(1,:),E_P(1,2));
    end
    data
    top
end
out=data;
    

%============函数2:评价函数

function target=accessment(data,weight)
%评价函数
%data中每行代表一个可行解
%weight ,权重列向量,可以按照实际情况给出合适值
%该函数对data每行数据进行一个评价,结果存放于target
[row,col]=size(data);
target=[];
for i=1:1:row
    target=[data(i,:)*weight;target];
end


%============函数3:禁忌项判断函数

function [exist,pos]=belong_tabulist(tabu_list,cadinate)
%次函数是判断某个候选解cadinate是否已经在禁忌表tabu_list中存在
%若该候选解已经存在 exist==true,pos表示该候选解位于禁忌表中的第几位
%若该候选解不存在,exist==false,pos==0
%tabu_list尺寸为n*3,每一行为一个禁忌项及其禁忌时效,cadinate是一个二维行向量
exist=0;
pos=0;
n=size(tabu_list,1);
if n==0
    return;
else
    for tb=1:1:n
        error=tabu_list(tb,1:2)-cadinate;
        if error*error'==0  %表明候选解cadinate与禁忌表中的第tb个禁忌项相等
            pos=tb;   %用pos记录该候选解在禁忌表中的位置
            exist=1;
            break;  %停止查找
        end
    end
end
       

%============函数4:更新样本数据

function data_change=data_refine(data,method)
%对data中的数字按照method提供的位置进行交换,交换后所有的结果存放在data_change
data_change=[];
for m=1:1:size(method,1)
    temp=data;
    t=temp(method(m,1));
    temp(method(m,1))=temp(method(m,2));
    temp(method(m,2))=t;
    data_change=[data_change;temp];
end


%============函数5:更新禁忌表

function tabu_list=tabu_refine(tabu_list,tabu_new,pos)
%tabu_list原始的禁忌表,尺寸为n*3,表示共有n个禁忌项
%tabu_new需要更新的禁忌项
%pos新的禁忌项tabu_new在禁忌表tabu_list中的位置
n=size(tabu_list,1);

if n==0 %说明禁忌表为空,新的禁忌项的时效为3,即在3步之后禁忌解除
    tabu_list=[tabu_new,3;tabu_list];
else
    %禁忌表不为空,那么将该禁忌项添加到禁忌表中合适位置,并将其余禁忌项的禁忌次数减一
    if pos>0 %说明禁忌项tabu_new已经在禁忌表tabu_list中出现过
        tabu_list(pos,:)=[];
        tabu_list(:,3)=tabu_list(:,3)-1;
        tabu_list=[tabu_new,3;tabu_list];
    else
        tabu_list(:,3)=tabu_list(:,3)-1;
        tabu_list=[tabu_new,3;tabu_list];
    end
end
%删除禁忌表中禁忌次数等于0的项
num=size(tabu_list,1);
for i=1:1:num
    if tabu_list(num+1-i,3)<1
        tabu_list(num+1-i,:)=[];
    else
        break;
    end
end

%==================================函数演示=================

%还是刚才数组排序的问题,可以在matlab上这样编写代码

clear all
>> data=[1,2,3,4,5,6,7];
>> w=[7,6,5,4,3,2,1]';
>> [out,top]=tabu_search(data,w,10);

%最终得到的全局最优解为134,接近于真实的全局最优解140。这里需要解释一下,为什么禁忌搜索没有找到真正的全局最优呢?经过多次尝试,我发现禁忌搜索算法对初始值的依赖很强,如果你的初始值不合适,搜索的结果就不太理想。

猜你喜欢

转载自blog.csdn.net/cutelily2014/article/details/52886915