Skip to content

Commit

Permalink
Ant Colony Optimization (eugenp#1237)
Browse files Browse the repository at this point in the history
  • Loading branch information
maibin authored and KevinGilmore committed Feb 27, 2017
1 parent 5930f9d commit 29882a1
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import java.util.Scanner;

import com.baeldung.algorithms.annealing.SimulatedAnnealing;
import com.baeldung.algorithms.ga.annealing.SimulatedAnnealing;
import com.baeldung.algorithms.ga.ant_colony.AntColonyOptimization;
import com.baeldung.algorithms.ga.binary.SimpleGeneticAlgorithm;
import com.baeldung.algorithms.slope_one.SlopeOne;

Expand All @@ -14,6 +15,7 @@ public static void main(String[] args) {
System.out.println("1 - Simulated Annealing");
System.out.println("2 - Slope One");
System.out.println("3 - Simple Genetic Algorithm");
System.out.println("4 - Ant Colony");
int decision = in.nextInt();
switch (decision) {
case 1:
Expand All @@ -27,6 +29,10 @@ public static void main(String[] args) {
SimpleGeneticAlgorithm ga = new SimpleGeneticAlgorithm();
ga.runAlgorithm(50, "1011000100000100010000100000100111001000000100000100000000001111");
break;
case 4:
AntColonyOptimization antColony = new AntColonyOptimization(21);
antColony.startAntOptimization();
break;
default:
System.out.println("Unknown option");
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.baeldung.algorithms.annealing;
package com.baeldung.algorithms.ga.annealing;

import lombok.Data;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.baeldung.algorithms.annealing;
package com.baeldung.algorithms.ga.annealing;

public class SimulatedAnnealing {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.baeldung.algorithms.annealing;
package com.baeldung.algorithms.ga.annealing;

import java.util.ArrayList;
import java.util.Collections;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.baeldung.algorithms.ga.ant_colony;

public class Ant {

protected int trailSize;
protected int trail[];
protected boolean visited[];

public Ant(int tourSize) {
this.trailSize = tourSize;
this.trail = new int[tourSize];
this.visited = new boolean[tourSize];
}

protected void visitCity(int currentIndex, int city) {
trail[currentIndex + 1] = city;
visited[city] = true;
}

protected boolean visited(int i) {
return visited[i];
}

protected double trailLength(double graph[][]) {
double length = graph[trail[trailSize - 1]][trail[0]];
for (int i = 0; i < trailSize - 1; i++) {
length += graph[trail[i]][trail[i + 1]];
}
return length;
}

protected void clear() {
for (int i = 0; i < trailSize; i++)
visited[i] = false;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package com.baeldung.algorithms.ga.ant_colony;

import java.util.Arrays;
import java.util.Random;

public class AntColonyOptimization {

private double c = 1.0;
private double alpha = 1;
private double beta = 5;
private double evaporation = 0.5;
private double Q = 500;
private double antFactor = 0.8;
private double randomFactor = 0.01;

private int maxIterations = 1000;

public int numberOfCities;
public int numberOfAnts;
private double graph[][];
private double trails[][];
private Ant ants[];
private Random random = new Random();
private double probabilities[];

private int currentIndex;

public int[] bestTourOrder;
public double bestTourLength;

public AntColonyOptimization(int noOfCities) {
graph = generateRandomMatrix(noOfCities);
numberOfCities = graph.length;
numberOfAnts = (int) (numberOfCities * antFactor);

trails = new double[numberOfCities][numberOfCities];
probabilities = new double[numberOfCities];
ants = new Ant[numberOfAnts];
for (int j = 0; j < numberOfAnts; j++) {
ants[j] = new Ant(numberOfCities);
}
}

/**
* Generate initial solution
* @param n
* @return
*/
public double[][] generateRandomMatrix(int n) {
double[][] randomMatrix = new double[n][n];
random.setSeed(System.currentTimeMillis());
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
Integer r = random.nextInt(100) + 1;
randomMatrix[i][j] = Math.abs(r);
}
}
return randomMatrix;
}

/**
* Perform ant optimization
* @return
*/
public int[] startAntOptimization() {
int[] finalResult = null;
for (int i = 1; i <= 3; i++) {
System.out.println("Attempt #" + i);
finalResult = solve();
}
return finalResult;
}

/**
* Use this method to run the main logic
* @return
*/
private int[] solve() {
setupAnts();
clearTrails();
int iteration = 0;
while (iteration < maxIterations) {
moveAnts();
updateTrails();
updateBest();
iteration++;
}
System.out.println("Best tour length: " + (bestTourLength - numberOfCities));
System.out.println("Best tour order: " + Arrays.toString(bestTourOrder));
return bestTourOrder.clone();
}

/**
* Prepare ants for the simulation
*/
private void setupAnts() {
currentIndex = -1;
for (int i = 0; i < numberOfAnts; i++) {
ants[i].clear();
ants[i].visitCity(currentIndex, random.nextInt(numberOfCities));
}
currentIndex++;
}

/**
* At each iteration, move ants
*/
private void moveAnts() {
while (currentIndex < numberOfCities - 1) {
for (Ant a : ants)
a.visitCity(currentIndex, selectNextCity(a));
currentIndex++;
}
}

/**
* Select next city for each ant
* @param ant
* @return
*/
private int selectNextCity(Ant ant) {
if (random.nextDouble() < randomFactor) {
int t = random.nextInt(numberOfCities - currentIndex);
int j = -1;
for (int i = 0; i < numberOfCities; i++) {
if (!ant.visited(i)) {
j++;
}
if (j == t) {
return i;
}
}
}
calculateProbabilities(ant);
double r = random.nextDouble();
double total = 0;
for (int i = 0; i < numberOfCities; i++) {
total += probabilities[i];
if (total >= r) {
return i;
}
}

throw new RuntimeException("There are no other cities");
}

/**
* Calculate the next city picks probabilites
* @param ant
*/
private void calculateProbabilities(Ant ant) {
int i = ant.trail[currentIndex];
double pheromone = 0.0;
for (int l = 0; l < numberOfCities; l++) {
if (!ant.visited(l)) {
pheromone += Math.pow(trails[i][l], alpha) * Math.pow(1.0 / graph[i][l], beta);
}
}
for (int j = 0; j < numberOfCities; j++) {
if (ant.visited(j)) {
probabilities[j] = 0.0;
} else {
double numerator = Math.pow(trails[i][j], alpha) * Math.pow(1.0 / graph[i][j], beta);
probabilities[j] = numerator / pheromone;
}
}
}

/**
* Update trails that ants used
*/
private void updateTrails() {
for (int i = 0; i < numberOfCities; i++) {
for (int j = 0; j < numberOfCities; j++) {
trails[i][j] *= evaporation;
}
}
for (Ant a : ants) {
double contribution = Q / a.trailLength(graph);
for (int i = 0; i < numberOfCities - 1; i++) {
trails[a.trail[i]][a.trail[i + 1]] += contribution;
}
trails[a.trail[numberOfCities - 1]][a.trail[0]] += contribution;
}
}

/**
* Update the best solution
*/
private void updateBest() {
if (bestTourOrder == null) {
bestTourOrder = ants[0].trail;
bestTourLength = ants[0].trailLength(graph);
}
for (Ant a : ants) {
if (a.trailLength(graph) < bestTourLength) {
bestTourLength = a.trailLength(graph);
bestTourOrder = a.trail.clone();
}
}
}

/**
* Clear trails after simulation
*/
private void clearTrails() {
for (int i = 0; i < numberOfCities; i++)
for (int j = 0; j < numberOfCities; j++)
trails[i][j] = c;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.baeldung.algorithms;

import org.junit.Assert;
import org.junit.Test;

import com.baeldung.algorithms.ga.ant_colony.AntColonyOptimization;

public class AntColonyOptimizationTest {

@Test
public void testGenerateRandomMatrix() {
AntColonyOptimization antTSP = new AntColonyOptimization(5);
Assert.assertNotNull(antTSP.generateRandomMatrix(5));
}

@Test
public void testStartAntOptimization() {
AntColonyOptimization antTSP = new AntColonyOptimization(5);
Assert.assertNotNull(antTSP.startAntOptimization());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import org.junit.Assert;
import org.junit.Test;

import com.baeldung.algorithms.annealing.SimulatedAnnealing;
import com.baeldung.algorithms.ga.annealing.SimulatedAnnealing;

public class SimulatedAnnealingTest {

Expand Down

0 comments on commit 29882a1

Please sign in to comment.