从网上找了一个GA算法的模板,按照自己的理解重写了部分操作。附上注释粘贴如下:
/**
*
*/
package ga;
/**
* @author ly
*
*/
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
/**
*
* GA algorithm to solve TSP problem
*/
public class GAalgorithm {
// population size
private final static int M = 100;
// city number
private int cityNum;
// total execute number
private int total;
// the distance
private int[][] cityMap;
// the lowest distance
private int lowestDistance;
// the lowest path
private int[] bestPath;
// the parent population
private int[][] parentGeneration;
// the child population
private int[][] childGeneration;
// fitness
private int[] fitness;
// probability
private float[] probability;
// the probability of cross gene
private float crossProbability;
// the probability of gene mutation
private float mutateProbability;
// the random number
private Random random;
/**
* @param total
* @param corss
* @param mutate
* @param map
* @param cityNum
*
* using all the parameter to initial the class
*/
public GAalgorithm(int total, float corss, float mutate, int[][] map, int cityNum) {
this.total = total;
crossProbability = corss;
mutateProbability = mutate;
this.cityNum = cityNum;
cityMap = new int[cityNum][cityNum];
cityMap = map;
cityMap[cityNum - 1][cityNum - 1] = 0;
lowestDistance = Integer.MAX_VALUE;
bestPath = new int[cityNum + 1];
childGeneration = new int[M + 1][cityNum + 1];
parentGeneration = new int[M + 1][cityNum + 1];
fitness = new int[M];
probability = new float[M];
random = new Random(System.currentTimeMillis());
}
/**
* initial the group
*/
void initGroup() {
int k;
int[] node = new int[this.cityNum];
for (int p = 0; p < cityNum; p++) {
node[p] = p;
}
for (k = 0; k < M; k++) {
// parentGeneration[k][0] = random.nextInt(cityNum);
parentGeneration[k] = randomInitial(node, cityNum);
}
}
/**
* @param node
* @param n
* @return
*
* according to the initial list generate a random list
*/
public int[] randomInitial(int[] node, int n) {
int t = 0;
while (t < 10 * cityNum)
t = random.nextInt(30 * cityNum);
for (int i = 0; i <= t; i++) {
int a = random.nextInt(cityNum);
int b = random.nextInt(cityNum);
int c = node[a];
node[a] = node[b];
node[b] = c;
}
return node;
}
/**
* calculate the fitness
*/
public int evaluate(int[] gene) {
int len = 0;
// sum all the distance
for (int i = 1; i < cityNum; i++) {
len += cityMap[gene[i - 1]][gene[i]];
}
len += cityMap[gene[cityNum - 1]][gene[0]];
return len;
}
/**
* calculate the total probably and divide the whole [0,1)
*/
void calculateRange() {
int k;
double sumFitness = 0;
for (k = 0; k < M; k++) {
sumFitness += fitness[k];
}
probability[0] = (float) (fitness[0] / sumFitness);
// the range for choose K will be used in roulette()
for (k = 1; k < M; k++) {
probability[k] = (float) (fitness[k] / sumFitness + probability[k - 1]);
}
}
/**
* select the high fitness generation of all
*/
public void storeBsetGene() {
int k, i, maxid;
int maxevaluation;
maxid = 0;
maxevaluation = fitness[0];
for (k = 1; k < M; k++) {
if (maxevaluation > fitness[k]) {
maxevaluation = fitness[k];
maxid = k;
}
}
if (lowestDistance > maxevaluation) {
lowestDistance = maxevaluation;
for (i = 0; i < cityNum; i++) {
bestPath[i] = parentGeneration[maxid][i];
}
}
// store the high fitness generation in position 0;
copyToNextGeneration(0, maxid);
}
/**
* select the child generation using roulette gambling
*/
public void roulette() {
int k, i;
float ran;
for (k = 1; k < M; k++) {
ran = random.nextFloat();
for (i = 0; i < M; i++) {
if (ran <= probability[i]) {
break;
}
}
copyToNextGeneration(k, i);
}
}
/**
* get the k th child generation from parent generation
*/
public void copyToNextGeneration(int k, int j) {
int i;
for (i = 0; i < cityNum; i++) {
childGeneration[k][i] = parentGeneration[j][i];
}
}
/**
* the evolution of the group
*/
public void evolution() {
int k;
storeBsetGene();
roulette();
float r;
for (k = 0; k < M; k = k + 2) {
r = random.nextFloat();
// cross k th generation and the k+1 th generation gene
if (r < crossProbability) {
geneCrossover(k, k + 1);
}
r = random.nextFloat();
// mutate gene
if (r < mutateProbability) {
geneMutate(k);
}
r = random.nextFloat();
if (r < mutateProbability) {
geneMutate(k + 1);
}
}
}
/**
* @param a
* @param b
* @return if a has b
*/
public boolean containGene(int[] a, int b) {
for (int i = 0; i < a.length; i++) {
if (a[i] == b) {
return true;
}
}
return false;
}
/**
* crossover gene of the k1 th and k2 th
*
* @param k1
* @param k2
*/
public void geneCrossover(int k1, int k2) {
int[] child1 = new int[cityNum];
int[] child2 = new int[cityNum];
int ran1 = random.nextInt(cityNum);
int ran2 = random.nextInt(cityNum);
while (ran1 == ran2) {
ran2 = random.nextInt(cityNum);
}
if (ran1 > ran2) {
int temp = ran1;
ran1 = ran2;
ran2 = temp;
}
// store the part that will be switched
for (int i = ran1; i <= ran2; i++) {
child1[i] = childGeneration[k1][i];
child2[i] = childGeneration[k2][i];
}
int[] sss1=new int[ran2-ran1+1];
for(int i=0;i<=ran2-ran1;i++)
{
sss1[i]=childGeneration[k1][ran1+i];
}
for(int i=ran1;i<=ran2;i++)
{
if(!containGene(sss1, child2[i]))
{
for(int j=ran1;j<=ran2;j++)
{
//为了使得不重不漏,对于child2中不在chileGeneration[k1]中相应位置的元素,要替换为其中的元素
if(!containGene(child2, childGeneration[k1][j]))
{
child2[i]=childGeneration[k1][j];
}
}
}
}
int[] sss2=new int[ran2-ran1+1];
for(int i=0;i<=ran2-ran1;i++)
{
sss2[i]=childGeneration[k2][ran1+i];
}
for(int i=ran1;i<=ran2;i++)
{
if(!containGene(sss2, child1[i]))
{
for(int j=ran1;j<=ran2;j++)
{
if(!containGene(child1, childGeneration[k2][j]))
{
child1[i]=childGeneration[k2][j];
}
}
}
}
for(int i=ran1;i<=ran2;i++)
{
childGeneration[k1][i]=child2[i];
childGeneration[k2][i]=child1[i];
}
}
/**
* random mutate some times
*
* @param k
*/
public void geneMutate(int k) {
int ran1, ran2, temp;
int count;
count = random.nextInt(cityNum);
for (int i = 0; i < count; i++) {
ran1 = random.nextInt(cityNum);
ran2 = random.nextInt(cityNum);
while (ran1 == ran2) {
ran2 = random.nextInt(cityNum);
}
temp = childGeneration[k][ran1];
childGeneration[k][ran1] = childGeneration[k][ran2];
childGeneration[k][ran2] = temp;
}
}
/**
* the main function for GA algorithm
*/
public void run() {
int i;
int k;
// initial the group
initGroup();
// calculate the initial fitness
for (k = 0; k < M; k++) {
fitness[k] = evaluate(parentGeneration[k]);
}
// calculate the range for choosing k th generation and store the
// results in probability[max]
calculateRange();
for (int t = 0; t < total; t++) {
evolution();
// update the parent generation with the child generation
for (k = 0; k < M; k++) {
for (i = 0; i < cityNum; i++) {
parentGeneration[k][i] = childGeneration[k][i];
}
}
// calculate the new fitness
for (k = 0; k < M; k++) {
fitness[k] = evaluate(parentGeneration[k]);
}
// calculate the range for choosing k th generation and store the
// results in probability[max]
calculateRange();
}
System.out.println("minimum distance: " + lowestDistance);
System.out.print("best path: ");
for (i = 0; i < cityNum; i++) {
System.out.print(bestPath[i] + " ");
}
System.out.println("start and end with " + bestPath[0] + " ");
}
}
最后附一份测试代码(随机生成矩阵并测试)
本来是和回溯法以及分支限界法一起写的,这部分忽略就好
测试正确度的代码:
/**
*
*/
package test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import branch_bounding.*;
import ga.GAalgorithm;
import backTrack.*;
/**
* @author ly
*
*/
public class TSPtest {
public static Random random = new Random();
/**
* @param args
*/
public static void main(String[] args) {
/**
* all the node number start with number 0 the unconnected city is
* presented by a enormous number
*
*/
/**
* test the branch bounding
* testCaseNum是测试次数
*/
int testCaseNum = 14;
for (int i = 0; i < 10; i++) {
System.out.println("====================" + i + "====================");
int[][] path = testCase(testCaseNum, 100);
System.out.println("=>Back Track");
Recall r = new Recall(path, testCaseNum);
r.run();
// System.out.println("=>Branch Bounding");
// BranchBoundingAlgorithm sp = new BranchBoundingAlgorithm(path, testCaseNum);
// sp.run();
System.out.println("=>GA");
GAalgorithm ga = new GAalgorithm(500, 0.7f, 0.007f, path, testCaseNum);
ga.run();
}
}
/**
* 生成测试矩阵
*
* @param n
* 矩阵规模
* @param maxn
* 矩阵最大元素
* @return 随机生成的测试矩阵
*/
public static int[][] testCase(int n, int maxn) {
int[][] test = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
if (i == j)
test[i][j] = 0;
else {
int a = 0;
while (a <= 0) {
a = random.nextInt(maxn);
}
test[i][j] = a;
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (i == j)
test[i][j] = 0;
else {
test[i][j] = test[j][i];
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.printf("%-4s", test[i][j] + " ");
}
System.out.println();
}
return test;
}
}
测试时间性能的代码:
/**
*
*/
package test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import branch_bounding.*;
import ga.GAalgorithm;
import backTrack.*;
/**
* @author ly
*
*/
public class TSPPerformenceTest {
public static Random random = new Random();
public static int testCaseNum = 10;
/**
* @param args
*/
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String order = "";
System.out.println("please choose from BackTrack, BranchBounding, GA, quit");
while (true) {
try {
order = br.readLine();
switch (order) {
case "BackTrack":
testBackTrack();
break;
case "BranchBounding":
testBranchBounding();
break;
case "GA":
testGA();
break;
case "quit":
System.exit(0);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 测试GA
*/
private static void testGA() {
// TODO Auto-generated method stub
double sum = 0;
double start;
double end;
double currenttime;
for (int i = 5; i <= 20; i = i + 3) {
System.out.println("############## matrix scale: " + i + " ##################");
for (int j = 0; j < testCaseNum; j++) {
System.out.println("====================" + j + "====================");
int[][] path = testCase(i, 100);
System.out.println("=>GA");
GAalgorithm ga = new GAalgorithm(100000, 0.9f, 0.9f, path, i);
start = System.currentTimeMillis();
ga.run();
end = System.currentTimeMillis();
currenttime = end - start;
sum += currenttime;
System.out.println("time spent: " + currenttime);
}
sum = sum / testCaseNum;
System.out.println("matrix scale: " + i + " average time: " + sum);
sum = 0;
}
}
/**
* 测试BranchBounding
*/
private static void testBranchBounding() {
// TODO Auto-generated method stub
double sum = 0;
double start;
double end;
double currenttime;
// i为矩阵规模
for (int i = 5; i <= 20; i = i + 3) {
System.out.println("############## matrix scale: " + i + " ##################");
// j和testCaseNum都是表征每个规模的测试次数
for (int j = 0; j < testCaseNum; j++) {
System.out.println("====================" + j + "====================");
int[][] path = testCase(i, 100);
System.out.println("=>GA");
BranchBoundingAlgorithm b = new BranchBoundingAlgorithm(path, i);
start = System.currentTimeMillis();
b.run();
end = System.currentTimeMillis();
currenttime = end - start;
sum += currenttime;
System.out.println("time spent: " + currenttime);
}
sum = sum / testCaseNum;
System.out.println("matrix scale: " + i + " average time: " + sum);
sum = 0;
}
}
/**
* 测试BackTrack 代码结构同上
*/
private static void testBackTrack() {
// TODO Auto-generated method stub
double sum = 0;
double start;
double end;
double currenttime;
for (int i = 5; i <= 20; i = i + 3) {
System.out.println("############## matrix scale: " + i + " ##################");
for (int j = 0; j < testCaseNum; j++) {
System.out.println("====================" + j + "====================");
int[][] path = testCase(i, 100);
System.out.println("=>GA");
Recall r = new Recall(path, i);
start = System.currentTimeMillis();
r.run();
end = System.currentTimeMillis();
currenttime = end - start;
sum += currenttime;
System.out.println("time spent: " + currenttime);
}
sum = sum / testCaseNum;
System.out.println("matrix scale: " + i + " average time: " + sum);
sum = 0;
}
}
/**
* 生成测试矩阵
*
* @param n
* 矩阵规模
* @param maxn
* 矩阵最大元素
* @return 随机生成的测试矩阵
*/
public static int[][] testCase(int n, int maxn) {
int[][] test = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
if (i == j)
test[i][j] = 0;
else {
int a = 0;
while (a <= 0) {
a = random.nextInt(maxn);
}
test[i][j] = a;
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (i == j)
test[i][j] = 0;
else {
test[i][j] = test[j][i];
}
}
}
return test;
}
}