1

我有一个任务,为旅行商问题编码遗传算法。我已经使用锦标赛选择编写了一些给出正确结果的代码。问题是,我必须做 Wheel 和 Rank,我得到的结果是不正确的。

这是我使用锦标赛选择的代码:

clc;
clear all;
close all;

nofCities = 30;
initialPopulationSize = nofCities*nofCities;
generations = nofCities*ceil(nofCities/10);

cities = floor(rand([nofCities 2])*100+1);

figure;
hold on;
scatter(cities(:,1), cities(:,2), 5, 'b','fill');
line(cities(:,1), cities(:,2));
line(cities([1 end],1), cities([1 end],2));
axis([0 110 0 110]);

population = zeros(initialPopulationSize ,nofCities);

for i=1:initialPopulationSize 
   population(i,:) = randperm(nofCities);
end

distanceMatrix = zeros(nofCities);
for i=1:nofCities
    for j=1:nofCities
        if (i==j)
            distanceMatrix(i,j)=0;
        else
            distanceMatrix(i,j) = sqrt((cities(i,1)-cities(j,1))^2+(cities(i,2)-cities(j,2))^2);
        end
    end
end

for u=1:generations     
    tourDistance = zeros(initialPopulationSize ,1);
    for i=1:initialPopulationSize 
       for j=1:length(cities)-1
           tourDistance(i) = tourDistance(i) + distanceMatrix(population(i,j),population(i,j+1));
       end
    end
    for i=1:initialPopulationSize 
        tourDistance(i) = tourDistance(i) + distanceMatrix(population(i,end),population(i,1));
    end

    min(tourDistance)

    newPopulation = zeros(initialPopulationSize,nofCities);

    for k=1:initialPopulationSize
        child = zeros(1,nofCities);
        %tournament start
        for i=1:5
           tournamentParent1(i) = ceil(rand()*initialPopulationSize);
        end
        p1 = find(tourDistance == min(tourDistance([tournamentParent1])));
        parent1 = population(p1(1), :);
        for i=1:5
           tournamentParent2(i) = ceil(rand()*initialPopulationSize);
        end
        p2 = find(tourDistance == min(tourDistance([tournamentParent2])));
        parent2 = population(p2(1), :);
        %tournament end
        %crossover
        startPos = ceil(rand()*(nofCities/2));
        endPos = ceil(rand()*(nofCities/2)+10);

        for i=1:nofCities
           if (i>startPos && i<endPos) 
               child(i) = parent1(i);
           end
        end

        for i=1:nofCities
            if (isempty(find(child==parent2(i))))
                for j=1:nofCities
                    if (child(j) == 0)
                        child(j) = parent2(i);
                        break;
                    end
                end
            end
        end

        newPopulation(k,:) = child;
    end

    %mutation
    mutationRate = 0.015;
    for i=1:initialPopulationSize
       if (rand() < mutationRate)
           pos1 = ceil(rand()*nofCities);
           pos2 = ceil(rand()*nofCities);
           mutation1 = newPopulation(i,pos1);
           mutation2 = newPopulation(i,pos2);
           newPopulation(i,pos1) = mutation2;
           newPopulation(i,pos2) = mutation1;           
       end
    end

    population = newPopulation;
    u
end

figure;
hold on;
scatter(cities(:,1), cities(:,2), 5, 'b','fill');
line(cities(population(i,:),1), cities(population(i,:),2));
line(cities([population(i,1) population(i,end)],1), cities([population(i,1) population(i,end)],2));
axis([0 110 0 110]);

%close all;

我想要的是用轮子和排名代码替换锦标赛代码。

这是我为车轮选择写的:

 fitness = tourDistance./sum(tourDistance);
        wheel = cumsum(fitness);
        parent1 = population(find(wheel >= rand(),1),:);
        parent2 = population(find(wheel >= rand(),1),:);
4

2 回答 2

1

为了使车轮选择起作用,您应该从设计一个健身测量开始,让更健康的个体具有更大的价值。与距离更好的个体具有较小的值相反。那么你对 cumsum 的方法应该有效。

排名选择的问题在哪里?

于 2015-06-01T08:01:15.380 回答
1

这是 Matlab 中轮盘选择的矢量化实现:

[~,W] = min(ones(popSize,1)*rand(1,2*popSize) > ((cumsum(fitness)*ones(1,2*popSize)/sum(fitness))),[],1);

这假设选择方案的适应度输入是一个大小为 (popSize x 1) 的矩阵(或与总体成员数量相同大小的列向量)。

popSize 显然是您的人口中的成员数量。W 是获胜者或被选为父母/交叉的人口成员。

选择的输出将是 selected_pa​​rents ,它是大小为 2*popSize 的双行向量,其中包含将在交叉阶段使用的总体成员的所有索引。

然后可以将此行向量输入到向量化交叉方案中,该方案可能如下所示:

%% Single-Point Preservation Crossover
    Pop2 = Pop(W(1:2:end),:);                       % Pop2 Winners 1
    P2A  = Pop(W(2:2:end),:);                       % Pop2 Winners 2
    Lidx = sub2ind(size(Pop),[1:popSize]',round(rand(popSize,1)*(genome-1)+1));
    vLidx = P2A(Lidx)*ones(1,genome);
    [r,c]=find(Pop2==vLidx);
    [~,Ord]=sort(r);
    r = r(Ord); c = c(Ord);
    Lidx2 = sub2ind(size(Pop),r,c);
    Pop2(Lidx2) = Pop2(Lidx);
    Pop2(Lidx) = P2A(Lidx);

这个交叉假设 W 变量来自选择方案的输入。它还使用 Pop,它是按基因组矩阵存储在 popSize 中的种群成员。(基因组是一次旅行中的城市数量,也恰好是基因组的大小)。基因组被存储为一个整数数组,每个整数代表一个城市,旅行被定义为从基因组数组的值从数组的第一个索引到数组的最后一个索引的顺序。

当我们这样做时,我们还可以为置换遗传算法(就是这样)包含一个很好的矢量化变异方案。

     %% Mutation (Permutation)
        idx = rand(popSize,1)<mutRate;
        Loc1 = sub2ind(size(Pop2),1:popSize,round(rand(1,popSize)*(genome-1)+1));
        Loc2 = sub2ind(size(Pop2),1:popSize,round(rand(1,popSize)*(genome-1)+1));

        Loc2(idx == 0) = Loc1(idx == 0);
        [Pop2(Loc1), Pop2(Loc2)] = deal(Pop2(Loc2), Pop2(Loc1));

这种突变随机翻转了我们游览(基因组)中 2 个城市的顺序。

最后确保在我们完成所有这些工作之后更新您的人口!

%% Update Population!
Pop = Pop2; % updates the population to include crossovers and mutation.

所以我知道这个回复对于你的任务来说可能为时已晚,但希望它能帮助其他有类似问题的人。

我真的非常推荐任何对 Matlab 中矢量化遗传算法感兴趣的人阅读这篇论文:UCL: Efficiently Vectorized Code for Population Based Optimization Algorithms

这是我在示例中所有代码的基础,它会告诉你为什么要这样编写代码。它是一个很好的资源,也是我开始使用 GA 的原因。

于 2015-06-25T19:21:24.293 回答