1. 程式人生 > 其它 >優化演算法——差分進化演算法(DE)

優化演算法——差分進化演算法(DE)

一、差分進化演算法的介紹

   差分進化演算法(Differential Evolution, DE)是一種基於群體差異的啟發式隨機搜尋演算法,該演算法是由R.Storn和K.Price為求解Chebyshev多項式而提出的。DE演算法也屬於智慧優化演算法,與前面的啟發式演算法,如ABC,PSO等類似,都屬於啟發式的優化演算法。DE演算法是我在一篇求解盒子覆蓋問題論文中使用的一種優化演算法。

二、差分進化演算法的流程

  1. 初始化種群
  2. 變異
  3. 交叉
  4. 選擇
(DE流程)

三、差分進化的具體步驟

   對於無約束優化問題

利用差分進化求解這樣的優化問題,主要分為初始化、變異、交叉和選擇等幾項操作。

4、選擇

   在DE中採用的是貪婪選擇的策略,即選擇較優的個體作為新的個體。

四、實際的優化問題

   求解優化問題:

一、Java實現

package org.zzy.de;

import java.util.Random;

public class Population {
	public static int NP = 1000;// 種群規模
	public static int size = 10;// 個體的長度
	public static int xMin = -10;// 最小值
	public static int xMax = 10;// 最大值
	public static double F = 0.5;// 變異的控制引數
	public static double CR = 0.8;// 雜交的控制引數

	private double X[][] = new double[NP][size];// 個體
	private double XMutation[][] = new double[NP][size];
	private double XCrossOver[][] = new double[NP][size];
	private double fitness_X[] = new double[NP];// 適應值

	public double[][] getX() {
		return X;
	}

	/**
	 * 矩陣的複製
	 * 
	 * @param x把x複製給個體
	 */
	public void setX(double x[][]) {
		for (int i = 0; i < NP; i++) {
			for (int j = 0; j < size; j++) {
				this.X[i][j] = x[i][j];
			}
		}
	}

	public double[] getFitness_X() {
		return fitness_X;
	}

	public void setFitness_X(double[] fitness_X) {
		for (int i = 0; i < NP; i++) {
			this.fitness_X[i] = fitness_X[i];
		}
	}

	public double[][] getXMutation() {
		return XMutation;
	}

	public void setXMutation(double xMutation[][]) {
		for (int i = 0; i < NP; i++) {
			for (int j = 0; j < size; j++) {
				this.XMutation[i][j] = xMutation[i][j];
			}
		}
	}

	public double[][] getXCrossOver() {
		return XCrossOver;
	}

	public void setXCrossOver(double xCrossOver[][]) {
		for (int i = 0; i < NP; i++) {
			for (int j = 0; j < size; j++) {
				this.XCrossOver[i][j] = xCrossOver[i][j];
			}
		}
	}

	/**
	 * 適應值的計算
	 * 
	 * @param XTemp根據個體計算適應值
	 * @return返回適應值
	 */
	public double CalculateFitness(double XTemp[]) {
		double fitness = 0;
		for (int i = 0; i < size; i++) {
			fitness += XTemp[i] * XTemp[i];// 做一個X的平方相加的函式
		}
		return fitness;
	}

	/**
	 * 初始化:隨機初始化種群,計算個體的適應值
	 */
	public void Initialize() {
		double XTemp[][] = new double[NP][size];
		double FitnessTemp[] = new double[NP];
		Random r = new Random();
		for (int i = 0; i < NP; i++) {
			for (int j = 0; j < size; j++) {
				XTemp[i][j] = xMin + r.nextDouble() * (xMax - xMin);
			}
			// 計算適應值
			FitnessTemp[i] = CalculateFitness(XTemp[i]);
		}

		this.setX(XTemp);
		this.setFitness_X(FitnessTemp);
	}

	/******** 變異操作 ***********/
	public void Mutation() {
		double XTemp[][] = new double[NP][size];
		double XMutationTemp[][] = new double[NP][size];
		XTemp = this.getX();
		Random r = new Random();
		for (int i = 0; i < NP; i++) {
			int r1 = 0, r2 = 0, r3 = 0;
			while (r1 == i || r2 == i || r3 == i || r1 == r2 || r1 == r3
					|| r2 == r3) {// 取r1,r2,r3
				r1 = r.nextInt(NP);
				r2 = r.nextInt(NP);
				r3 = r.nextInt(NP);
			}
			for (int j = 0; j < size; j++) {
				XMutationTemp[i][j] = XTemp[r1][j] + F
						* (XTemp[r2][j] - XTemp[r3][j]);
			}
		}
		this.setXMutation(XMutationTemp);
	}

	/**
	 * 交叉操作
	 */
	public void CrossOver() {
		double XTemp[][] = new double[NP][size];
		double XMutationTemp[][] = new double[NP][size];
		double XCrossOverTemp[][] = new double[NP][size];

		XTemp = this.getX();
		XMutationTemp = this.getXMutation();
		// 交叉操作
		Random r = new Random();
		for (int i = 0; i < NP; i++) {
			for (int j = 0; j < size; j++) {
				double rTemp = r.nextDouble();
				if (rTemp <= CR) {
					XCrossOverTemp[i][j] = XMutationTemp[i][j];
				} else {
					XCrossOverTemp[i][j] = XTemp[i][j];
				}
			}
		}
		this.setXCrossOver(XCrossOverTemp);
	}

	/**
	 * 選擇操作:使用貪婪選擇策略
	 */
	public void Selection() {
		double XTemp[][] = new double[NP][size];
		double XCrossOverTemp[][] = new double[NP][size];
		double FitnessTemp[] = new double[NP];
		double FitnessCrossOverTemp[] = new double[NP];
		
		XTemp = this.getX();
		XCrossOverTemp = this.getXCrossOver();// 交叉變異後的個體
		FitnessTemp = this.getFitness_X();
		
		// 對群體進行重新設定
		for (int i = 0; i < NP; i++) {
			FitnessCrossOverTemp[i] = CalculateFitness(XCrossOverTemp[i]);
			if (FitnessCrossOverTemp[i] < FitnessTemp[i]) {
				for (int j = 0; j < size; j++){
					XTemp[i][j] = XCrossOverTemp[i][j];
				}
				FitnessTemp[i] = FitnessCrossOverTemp[i];
			}
		}
		this.setX(XTemp);
		this.setFitness_X(FitnessTemp);
	}

	/**
	 * 儲存每一代的全域性最優值
	 */
	public void SaveBest() {
		double FitnessTemp[] = new double[NP];
		FitnessTemp = this.getFitness_X();
		int temp = 0;
		// 找出最小值
		for (int i = 1; i < NP; i++) {
			if (FitnessTemp[temp] > FitnessTemp[i]) {
				temp = i;
			}
		}
		System.out.println(FitnessTemp[temp]);
	}
}

測試

package org.zzy.test;

import org.zzy.de.Population;

public class DETest {
	public static void main(String args[]) {
		int gen = 0;
		int maxCycle = 1000;
		Population p = new Population();
		p.Initialize();// 初始化
		while (gen <= maxCycle) {
			p.Mutation();
			p.CrossOver();
			p.Selection();
			gen++;
			p.SaveBest();
		}
	}

}

二、收斂曲線