算法描述:
根据某种规则随机产生初始化种群,根据变异规则产生变异后的种群,根据交叉规则产生交叉后的种群,然后执行选择函数,对交叉变异后的种群和原种群进行比较选择。对择优后的种群进行排序,选出Top N条种群向量。
算法参数:
种群大小、迭代次数、变异权值、交叉率、种群向量值范围
遗传算法&差分算法(个人理解):
1:遗传算法交叉后即择优,变异后即择优;差分算法交叉变异操作后择优一次。
2:遗传算法需要对种群进行初始编码;差分算法根据规则初始化种群。
3:都可以进行设定参数范围和停止准则
4:都属于种群进化算法
遗传算法示例(C++实现):
https://github.com/Consck/genetic-algorithm
代码示例:
import java.util.*;
/**
* There steps in differential evolution:
* 1. mutation
* 2. cross
* 3. selection
* 差分算法代码示例
* @author JunH (email: junh_cs@126.com)
*
*/
public class DifferentialEvolution4SeachParam {
private int population_size;
private int iter_num;
private int param_num;
private double param_bottom_bound;
private double param_upper_bound;
private double F = 0.5; // mutation factor [0, 1], range from 0 to 1
private double CR = 0.5; // cross rate (0, 1)
// tmp
private double[][] population;
private double[] scores;
private Random rand;
// output
private double[] final_individual;
public static void main(String[] args) {
DifferentialEvolution4SeachParam de = new DifferentialEvolution4SeachParam(10, 500, 5, -1, 1);
double[] params = de.getTheFinalParams();
System.out.println();
for (int j = 0; j < params.length-1; j++)
System.out.print(params[j]+", ");
System.out.println(params[params.length-1]+")");
System.out.println("HAVE A GOOD DAY!");
}
public DifferentialEvolution4SeachParam(int population_size, int iter_num,
int param_num, double param_bottom_bound, double param_upper_bound){
this.population_size = population_size;
this.iter_num = iter_num;
this.param_num = param_num;
this.param_bottom_bound = param_bottom_bound;
this.param_upper_bound = param_upper_bound;
final_individual = run();
}
public double[] getTheFinalParams(){
return final_individual;
}
private double[] run(){
this.init();
double[] final_best_individual = null;
/**
* 共迭代iter_num次,择优选择
*/
for (int iter = 0; iter < iter_num; iter++){
double[][] mutated_population = this.mutate(); //获得变异后的种群
double[][] crossed_population = this.cross(mutated_population); //在变异后的种群基础上进行交叉操作
this.select(crossed_population); //对变异 交叉后的种群进行择优
//根据适应度值对种群向量进行排序,返回适应度值最大的向量编号。若sortTopN设定为2,则返回适应度值最大的前两个向量编号
int[] index = insertDescendSortIndex(scores, 1);
//打印log
StringBuffer sb = new StringBuffer();
sb.append("The "+(iter+1)+"-th iter's score is "+scores[index[0]]+" (");
for (int j = 0; j < param_num-1; j++)
sb.append(this.population[index[0]][j]+", ");
sb.append(this.population[index[0]][param_num-1]+")");
System.out.println(sb.toString());
//保存适应度函数值最大的向量
final_best_individual = this.population[index[0]];
}
return final_best_individual;
}
private int[] insertDescendSortIndex(final double[] arr, int sortTopN){
int[] indexes = new int[arr.length];
//初始化数组
for (int i = 0; i < indexes.length; i++)
indexes[i] = i;
//根据适应度值进行排序,indexes存储种群向量编号
for (int i = 1; i < indexes.length; i++){
for (int j = 0; j < i && j < sortTopN; j++){
if (arr[indexes[i]] > arr[indexes[j]]){
int tmp = indexes[i];
indexes[i] = indexes[j];
indexes[j] = tmp;
}
}
}
//根据需要返回适应度排名前N个种群向量编号
if (indexes.length > sortTopN){
int[] ans = new int[sortTopN];
for (int i = 0; i < sortTopN; i++){
ans[i] = indexes[i];
}
return ans;
}
return indexes;
}
/**
* 迭代前的种群初始化
*/
private void init(){
rand = new Random(new Date().getTime());
population = new double[population_size][param_num];
scores = new double[population_size];
for (int i = 0; i < population_size; i++){
for (int j = 0; j < param_num; j++){
//初始化规则
population[i][j] = param_bottom_bound + rand.nextDouble() * (param_upper_bound - param_bottom_bound);
}
//计算初始化种群的向量适应度
scores[i] = scorefunc(population[i]);
}
}
private double[][] mutate(){
double[][] mutated_population = new double[population_size][param_num];
for (int i = 0; i < population_size; i++){ //变异后种群大小不变
/**
* 随机产生3个不超过10的变量,作为变异随机选择的个体向量
*/
int ind1 = rand.nextInt(population_size);
int ind2 = rand.nextInt(population_size);
int ind3 = rand.nextInt(population_size);
/**
* 3条不同的种群个体向量,且不是当前向量
*/
while (ind1 == i || ind2 == i || ind3 == i
|| ind1 == ind2 || ind1 == ind3 || ind2 == ind3){
ind1 = rand.nextInt(population_size);
ind2 = rand.nextInt(population_size);
ind3 = rand.nextInt(population_size);
}
/**
* 变异规则:随机选择两个不同的个体向量相减产生差分向量,将差分向量赋予权值后与第三个随机选择的个体向量相加,产生变异向量
*/
for (int j = 0; j < param_num; j++){
mutated_population[i][j] = population[ind1][j] + F * (population[ind2][j] - population[ind3][j]);
}
}
//返回变异后的种群
return mutated_population;
}
private double[][] cross(double[][] mutated_population){
double[][] crossed_population = new double[population_size][param_num];
for (int i = 0; i < population_size; i++){ //交叉后种群大小不变
int Jrand = rand.nextInt(param_num); //随机选择向量中的某个固定位置
for (int j = 0; j < param_num; j++){
/**
* 交叉规则:如果当前向量j为产生的固定位置或随机变量小于初始化设定的交叉率,则交叉后向量值取变异操作后的向量值;
* 否则,交叉后向量值取原种群中的向量值,即不交叉
*/
if (j == Jrand || rand.nextDouble() < CR)
crossed_population[i][j] = mutated_population[i][j];
else crossed_population[i][j] = population[i][j];
/**
* 对交叉后的值进行判断,若超出设定的范围,则重新初始化
*/
if (crossed_population[i][j] > this.param_upper_bound
|| crossed_population[i][j] < this.param_bottom_bound){
crossed_population[i][j] = param_bottom_bound + rand.nextDouble() * (param_upper_bound - param_bottom_bound);
}
}
}
return crossed_population;
}
private void select(double[][] crossed_population){
for (int i = 0; i < population_size; i++){
//计算当前向量适应度
double new_sco = scorefunc(crossed_population[i]);
/**
* 若交叉变异后的向量适应度大于原种群向量适应度,则替换
*/
if (new_sco > scores[i]){
population[i] = crossed_population[i];
scores[i] = new_sco;
}
}
}
/**
* 适应度计算规则:向量值相加结果即为当前向量适应度值
* @param individual
* @return
*/
private double scorefunc(double[] individual){ // TODO the higher, the better.
double sco = 0.0;
for (int i = 0; i < param_num; i++)
sco += individual[i];
return sco;
}
}