果蝇算法--背包问题

来源:互联网 发布:adobe flash mac 编辑:程序博客网 时间:2024/05/06 17:37

果蝇算法简介


原理

果蝇优化算法(简称FOA)是一种基于果蝇觅食行为推演出寻求全局优化的新方法。果蝇本身在感官知觉上优于其他物种,尤其是嗅觉和视觉上。果蝇的嗅觉器官能很好的搜集漂浮在空气中的各种气味,甚至能够嗅到40公里以外的食物源。然后,飞到食物位置附近后亦可使用敏锐的视觉发现食物和同伴聚集的位置,并且向该方向飞去。


迭代过程

1)随机初始化果蝇群体位置

  Init X_axis

  Init Y_axis


2)赋予果蝇个体利用嗅觉搜寻食物的随机距离与方向。

  Xi = X_axis +Random Value

  Yi = Y_axis +Random Value


3)由于无法得知食物的位置,因此先估计与原点的距离Dist再计算味道浓度判定值S此值为距离的倒数。

Disti =sqrt(Xi^2 + Yi^2)

Si = 1 /Disti


4)味道浓度判定值S代入味道浓度判定函数(或称为Fitnessfunction以求出该果蝇个体位置的味道浓度Smell

Smelli =Function(Si)


5)找出该果蝇群体中味道浓度最佳的果蝇。

  [bestSmellbestIndex]= max(Smell)/min(Smell)


6)保留最佳味道浓度值与xy的坐标,此时果蝇群体利用视觉往该位置飞去。

Smellbest =bestSmell

X_axis =X(bestIndex)

Y_axis =Y(bestIndex)


7)进入迭代寻优,重复执行步骤2-5,并判断味道浓度是否优于前一迭代味道浓度,若是则实行步骤6


以下是果蝇算法的原理简图:


果蝇算法解决01背包问题

关于简单的01背包问题描述请参看我的博文遗传算法--背包问题,关于背包物品的数据组织方式参看博文粒子群算法--背包问题。

先上代码:(java实现)

package main.java;import java.io.BufferedReader;import java.io.FileReader;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.List;import java.util.Random;// 背包中单个物品项class PackItem implements Comparable<PackItem>{public int weight = 0;// 重量public int value = 0;// 价值public double utility_rate = 0.0;// 利用率 = v/w public PackItem() {}public PackItem(int w, int v){weight = w;value = v;utility_rate = (double)v/w;}@Overridepublic int compareTo(PackItem other) {/* 按 utility_rate 降序排列 */int ret = 0;ret = (this.utility_rate > other.utility_rate ? -1 :(this.utility_rate == other.utility_rate ? 0 : 1) );return ret;}}// 果蝇个体class Fly{public List<PackItem> items_ref = null; // 背包数据的引用public int[] code_bits = null; // 编码二进制串,和背包物品项类似,也是按 utility_rate 降序生成public int weight_all = 0; // 总重量public int value_all = 0; // 总价值public final int weight_limit = 1000; // 总重量限重// 复制一个果蝇个体,返回新个体static Fly copy(Fly src){Fly dst = new Fly();dst.items_ref = src.items_ref;dst.code_bits = Arrays.copyOf(src.code_bits, src.code_bits.length);dst.weight_all = src.weight_all;dst.value_all = src.value_all;return dst;}public Fly() {}public Fly(List<PackItem> items, double[] pro_vec){items_ref = items;Random r = new Random();code_bits = new int[items_ref.size()];for(int i = 0; i < code_bits.length; i++){code_bits[i] = (r.nextDouble() < pro_vec[i] ? 1 : 0);}calcFitness(); // 在有参构造中直接计算个体的适应度值}// 果蝇个体局部搜索,返回搜索到的最好个体public Fly localSearch(int new_fly_num, int selected_bit_num){List<Fly> new_flys = generateFlyNeighbors(new_fly_num, selected_bit_num);return repairAndFindBest(new_flys);}// 计算自身的适应度值(包括总重量、总价值)public void calcFitness(){int sum_weight = 0, sum_value = 0;for(int i = 0; i < code_bits.length; i++){if(code_bits[i] == 1){sum_weight += items_ref.get(i).weight;sum_value += items_ref.get(i).value;}}if(sum_weight > weight_limit) { sum_value = 0; }this.weight_all = sum_weight;this.value_all = sum_value;}// 生成当前果蝇个体的新邻居果蝇个体群private List<Fly> generateFlyNeighbors(int new_fly_num, int selected_bit_num){List<Fly> new_flys = new ArrayList<Fly>();for(int i = 0; i < new_fly_num; i++){Fly _new_one = Fly.copy(this);Random r = new Random();for(int j = 0; j < selected_bit_num; j++){int selected_idx = r.nextInt(code_bits.length);_new_one.code_bits[selected_idx] = (_new_one.code_bits[selected_idx] == 0 ? 1 : 0);}_new_one.calcFitness();new_flys.add(_new_one);}return new_flys;}// 逐一检查并修复新产生的果蝇群和原果蝇,找出最优个体// 返回最优个体,若返回null,表示原个体最优private Fly repairAndFindBest(List<Fly> new_flys){for(Fly f : new_flys){f.repairSelf();}this.repairSelf();// 找到最优个体int idx = -1;int max_value = this.value_all;for(int i = 0; i < new_flys.size(); i++){if(new_flys.get(i).value_all > max_value){idx = i;max_value = new_flys.get(i).value_all;}}return (idx != -1 ? new_flys.get(idx) : null);}// 修复当前个体自身public void repairSelf(){if(this.weight_all <= weight_limit) { return ; }/* code_bits已经按照物品的 utility_rate 降序排列了 */// 先按照utility_rate从小到大,剔除超重的物品位,将其从1变为0for(int i = code_bits.length - 1; i >= 0 && weight_all > weight_limit; i--){if(code_bits[i] == 1){code_bits[i] = 0;weight_all -= items_ref.get(i).weight;}}// 再按照utility_rate从大到小,依次添加不超过总限重的物品项for(int i = 0; i < code_bits.length; i++){if(code_bits[i] == 0 &&weight_all + items_ref.get(i).weight <= weight_limit){code_bits[i] = 1;weight_all += items_ref.get(i).weight;}}// 修复完后,重新计算当前个体的适应度值calcFitness();}public String result(){StringBuffer ret = new StringBuffer();ret.append("[");for(int i = 0; i < code_bits.length; i++){ret.append(i + ", ");}ret.append("], 总重量:" + weight_all + ", 总价值:" + value_all);return ret.toString();}}// 果蝇算法类class FFO{private final int POP_NUM = 30; // 种群数量private final int ITERATE_NUM = 30; // 迭代次数private final int NEW_INDIVIDUAL_NUM_IN_LOCAL_SEARCH = 3; // 每个果蝇个体局部搜索时产生的新个体数量private final int SELECTED_BIT_NUM_IN_LOCAL_SEARCH = 3; // 每个果蝇个体局部搜索时选择的变异位的个数private final int VISION_SENSITIVITY_COEFF = 30; // 果蝇种群全局搜索更新时使用的视觉敏感系数private List<PackItem> items = new ArrayList<PackItem>(); // 背包数据private List<Fly> flys = new ArrayList<Fly>(); // 果蝇种群private double[] probability_vector = null; // 用于产生新种群的概率向量,每次迭代时都要更新private Fly best_fly_in_pop = null; // 每次迭代中种群中的最优个体public FFO() {}// 载入背包数据public void loadPackData(String file) throws Exception{String line;BufferedReader br = new BufferedReader(new FileReader(file));while( (line = br.readLine()) != null ){String[] strs = line.split(" ");if(strs.length != 2) { continue; }items.add( new PackItem(Integer.parseInt(strs[0]), Integer.parseInt(strs[1]) ));}// 按背包中物品项的利用率 降序排列Collections.sort(items);}public void run(){// 初始化概率向量initProVec();for(int i = 0; i < ITERATE_NUM; i++){// 初始化果蝇种群initFlyPop();// 果蝇种群局部搜索flyPopLocalSearch();// 找到当前种群中最优个体findBestFly();System.out.println("第" + i + "次迭代找到的最优个体:" + best_fly_in_pop.result());// 全局搜索,更新概率向量 probability_vectorglobalSearchUpdateProVec();}}// 初始化概率向量private void initProVec(){probability_vector = new double[items.size()];for(int i = 0; i < probability_vector.length; i++){ probability_vector[i] = 0.5; }}// 初始化果蝇种群private void initFlyPop(){flys.clear();for(int i = 0; i < POP_NUM; i++){flys.add( new Fly(items, probability_vector) );}}// 果蝇种群局部搜索private void flyPopLocalSearch(){for(int i = 0; i < POP_NUM; i++){Fly local_best = flys.get(i).localSearch(NEW_INDIVIDUAL_NUM_IN_LOCAL_SEARCH, SELECTED_BIT_NUM_IN_LOCAL_SEARCH);if(local_best != null){flys.set(i, local_best);}}}// 找到当前种群中最优个体private void findBestFly(){best_fly_in_pop = flys.get(0);for(Fly f : flys){if(f.value_all > best_fly_in_pop.value_all){best_fly_in_pop = f;}}}// 全局搜索,更新概率向量 probability_vectorprivate void globalSearchUpdateProVec(){Fly f1 = null;Fly f2 = null;do {f1 = flys.get(new Random().nextInt(flys.size()));} while(f1 == best_fly_in_pop);do {f2 = flys.get(new Random().nextInt(flys.size()));} while(f2 == f1 || f2 == best_fly_in_pop);for(int i = 0; i < probability_vector.length; i++){double coeff = (double)best_fly_in_pop.code_bits[i] + 0.5 * (f1.code_bits[i] - f2.code_bits[i]);probability_vector[i] = 1 / (1 + Math.pow(Math.E, 0 - VISION_SENSITIVITY_COEFF * (coeff - 0.5)));}}}public class FFODemo {public static void main(String[] args) throws Exception {FFO ffo = new FFO();ffo.loadPackData("knapsack.data");ffo.run();}}

有以下几个设计要点:

编码

二进制编码,用01序列表示背包问题的一个解


初始化

1、定义一个概率向量P(g),初始化为P(g)=(0.5, 0.5, 0.5, ……)

2、利用该概率向量P(g),初始化果蝇种群

3、每次迭代完成后,根据迭代结果修改该概率向量P(g),下次迭代开始前,再利用P(g)初始化果蝇种群


局部嗅觉搜索

针对单个果蝇个体:

1、随机选择L

2、所选位取反(0->11->0

3、重复上述2步,生成S个邻居个体

备注:SL为该算法中的关键可调参数,取S=L=3


局部视觉搜索

针对单个果蝇的局部嗅觉搜索结果:

1、找到当前果蝇个体和生成的邻居个体中味道浓度最佳的个体

2、用最佳个体替换当前个体


全局视觉搜索

针对果蝇种群:

1、找到当前种群中的最佳个体

2、随机抽选另外2个个体,和最佳个体协作修改概率向量P(g)

按照以下公式更新全局概率向量P(g):


b代表果蝇的视觉敏感度,为关键可调参数,取30


修复操作

针对背包中的物品,引入物品利用率:U = V / W

对果蝇个体中的二进制序列:

1、按U从小到大检测每一位,若该位为1W> W,则该位置0W减去该位物品对应的重量,直到重量达标。

2、按U从大到小检测每一位,若该位为0W+该位物品重量< W,则该位置1W加上该位物品对应的重量。


总流程图:



参考文献:

Ling Wang, Xiao-longZheng,Sheng-yao Wang, A novel binary fruit flyoptimization algorithm for solving the multidimensional knapsack problem,Knowledge-Based Systems 482013) 17-23

原创粉丝点击