Skip to content

Commit 05bc3d4

Browse files
committed
Ant System unit testing on tsp
1 parent 637f27a commit 05bc3d4

File tree

8 files changed

+310
-99
lines changed

8 files changed

+310
-99
lines changed

README.md

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Add the following dependency to your POM file:
1919
<dependency>
2020
<groupId>com.github.chen0040</groupId>
2121
<artifactId>java-swarm-intelligence</artifactId>
22-
<version>1.0.2</version>
22+
<version>1.0.3</version>
2323
</dependency>
2424
```
2525

@@ -94,5 +94,51 @@ logger.info("trend: {}", trend);
9494
assertThat(bestSolution.getCost()).isCloseTo(0, within(0.01));
9595
```
9696

97+
### Ant System
98+
99+
The sample code below shows how to solve a TSP (Travelling Salesman Problem) instance using Ant System:
100+
101+
```java
102+
// load the bayg29 TSP instance
103+
TspBenchmark benchmark = Tsp.get(Tsp.Instance.bayg29);
104+
105+
PathCostFunction costFunction = new PathCostFunction() {
106+
// compute the cost of the tour constructed by an ant on the problem bayg29
107+
@Override public double evaluate(List<Integer> path) {
108+
double cost = 0;
109+
for(int i=0; i < path.size(); ++i) {
110+
int j = (i+1) % path.size();
111+
double distance = benchmark.distance(path.get(i), path.get(j));
112+
cost += distance;
113+
}
114+
return cost;
115+
}
116+
117+
// heuristic weight for transition from state1 to state2 during path construction
118+
// the higher the weight the more favorable to transit from state1 to state2
119+
@Override public double stateTransitionWeight(int state1, int state2) {
120+
return 1 / (1 + benchmark.distance(state1, state2));
121+
}
122+
};
123+
124+
125+
126+
AntSystem antSystem = new AntSystem();
127+
antSystem.setProblemSize(benchmark.size());
128+
antSystem.setCostFunction(costFunction);
129+
130+
antSystem.setMaxIterations(100);
131+
132+
Ant bestAnt = antSystem.solve();
133+
134+
System.out.println("minimal total distance found by Ant System: " + bestAnt.getCost());
135+
System.out.println("known minimal total distance: " + costFunction.evaluate(benchmark.optTour()));
136+
137+
System.out.println("best TSP path found: ");
138+
for(int i=0; i < bestAnt.getPath().size(); ++i) {
139+
int j = (i + 1) % bestAnt.getPath().size();
140+
System.out.println(bestAnt.getPath().get(i) + " => " + bestAnt.getPath().get(j));
141+
}
142+
```
97143

98144

pom.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.github.chen0040</groupId>
88
<artifactId>java-swarm-intelligence</artifactId>
9-
<version>1.0.3</version>
9+
<version>1.0.4</version>
1010

1111

1212

@@ -516,6 +516,12 @@
516516
<version>1.0.11</version>
517517
</dependency>
518518

519+
<dependency>
520+
<groupId>com.github.chen0040</groupId>
521+
<artifactId>java-datasets-discrete-optimization</artifactId>
522+
<version>1.0.1</version>
523+
</dependency>
524+
519525

520526
</dependencies>
521527

src/main/java/com/github/chen0040/si/ant/Ant.java

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
import lombok.Setter;
88

99
import java.util.ArrayList;
10+
import java.util.HashSet;
1011
import java.util.List;
12+
import java.util.Set;
1113

1214

1315
/**
@@ -17,28 +19,29 @@
1719
@Getter
1820
@Setter
1921
public class Ant {
20-
protected final List<Integer> visitedStates = new ArrayList<>();
22+
protected final List<Integer> path = new ArrayList<>();
23+
protected final Set<Integer> visited = new HashSet<>();
2124
private boolean costValid = false;
2225
private double cost;
2326

2427
public int currentState()
2528
{
26-
if(visitedStates.isEmpty()) {
29+
if(path.isEmpty()) {
2730
return -1;
2831
} else {
29-
return visitedStates.get(visitedStates.size()-1);
32+
return path.get(path.size()-1);
3033
}
3134
}
3235

3336
public List<TupleTwo<Integer, Integer>> path()
3437
{
35-
if(visitedStates.isEmpty()) return new ArrayList<>();
38+
if(path.isEmpty()) return new ArrayList<>();
3639

3740
List<TupleTwo<Integer, Integer>> path = new ArrayList<>();
38-
for(int i = 0; i < this.visitedStates.size()-1; ++i)
41+
for(int i = 0; i < this.path.size()-1; ++i)
3942
{
40-
int state1_id = this.visitedStates.get(i);
41-
int state2_id = this.visitedStates.get(i + 1);
43+
int state1_id = this.path.get(i);
44+
int state2_id = this.path.get(i + 1);
4245
path.add(new TupleTwo<>(state1_id, state2_id));
4346
}
4447

@@ -51,30 +54,31 @@ public Ant()
5154

5255
public void visit(int state)
5356
{
54-
visitedStates.add(state);
57+
path.add(state);
58+
visited.add(state);
5559
costValid = false;
5660
}
5761

5862
public void reset()
5963
{
60-
visitedStates.clear();
64+
path.clear();
65+
visited.clear();
6166
costValid = false;
6267
}
6368

64-
public int pathLength()
65-
{
66-
return visitedStates.size();
67-
}
6869

6970
public boolean hasVisited(int state_id)
7071
{
71-
return visitedStates.contains(state_id);
72+
return visited.contains(state_id);
7273
}
7374

7475
public void copy(Ant rhs)
7576
{
76-
visitedStates.clear();
77-
visitedStates.addAll(rhs.visitedStates);
77+
path.clear();
78+
path.addAll(rhs.path);
79+
visited.clear();
80+
visited.addAll(rhs.visited);
81+
7882
costValid = rhs.costValid;
7983
cost = rhs.cost;
8084
}
@@ -88,7 +92,17 @@ public boolean isBetterThan(Ant that) {
8892

8993

9094
public void evaluate(PathMediator mediator) {
91-
cost = mediator.evaluate(visitedStates);
95+
cost = mediator.evaluate(path);
9296
costValid = true;
9397
}
98+
99+
100+
public void update(List<Integer> path, double pathCost) {
101+
this.path.clear();
102+
this.path.addAll(path);
103+
this.visited.clear();
104+
this.visited.addAll(path);
105+
this.cost = pathCost;
106+
this.costValid = true;
107+
}
94108
}

src/main/java/com/github/chen0040/si/ant/AntColonySystem.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,30 @@ public class AntColonySystem extends AntSystem {
1313
@Override
1414
public void depositPheromone()
1515
{
16-
List<TupleTwo<Integer,Integer>> path = mGlobalBestAnt.path();
16+
List<TupleTwo<Integer,Integer>> path = globalBestAnt.path();
1717
int segment_count = path.size();
1818
for (int i = 0; i < segment_count; ++i)
1919
{
2020
TupleTwo<Integer,Integer> state_transition = path.get(i);
2121
int state1_id = state_transition._1();
2222
int state2_id = state_transition._2();
23-
double pheromone = mPheromones.get(state1_id, state2_id);
24-
double p_delta = getRewardPerStateTransition(mGlobalBestAnt);
25-
pheromone += m_alpha * p_delta;
23+
double pheromone = pheromones.get(state1_id, state2_id);
24+
double p_delta = getRewardPerStateTransition(globalBestAnt);
25+
pheromone += alpha * p_delta;
2626

27-
mPheromones.set(state1_id, state2_id, pheromone);
28-
if (mSymmetric)
27+
pheromones.set(state1_id, state2_id, pheromone);
28+
if (symmetric)
2929
{
30-
mPheromones.set(state2_id, state1_id, pheromone);
30+
pheromones.set(state2_id, state1_id, pheromone);
3131
}
3232
}
3333
}
3434

3535
@Override
36-
public void transitStates(Ant ant, int state_index)
36+
public void transitStates(Ant ant)
3737
{
3838
int current_state_id = ant.currentState();
39-
List<Integer> candidate_states = getCandidateNextStates(ant, current_state_id);
39+
List<Integer> candidate_states = getCandidateNextStates(ant);
4040

4141
if (candidate_states.isEmpty()) return;
4242

@@ -50,10 +50,10 @@ public void transitStates(Ant ant, int state_index)
5050
for (int i = 0; i < candidate_states.size(); ++i)
5151
{
5252
int candidate_state_id = candidate_states.get(i);
53-
double pheromone = mPheromones.get(current_state_id, candidate_state_id);
54-
double heuristic_cost = heuristicCost(current_state_id, candidate_state_id);
53+
double pheromone = pheromones.get(current_state_id, candidate_state_id);
54+
double heuristic_cost = heuristicValue(current_state_id, candidate_state_id);
5555

56-
double product = Math.pow(pheromone, m_alpha) * Math.pow(heuristic_cost, m_beta);
56+
double product = Math.pow(pheromone, alpha) * Math.pow(heuristic_cost, beta);
5757

5858
product_sum += product;
5959
acc_prob[i] = product_sum;
@@ -66,7 +66,7 @@ public void transitStates(Ant ant, int state_index)
6666
}
6767

6868
double r = mediator.nextDouble();
69-
if (r <= m_Q)
69+
if (r <= Q)
7070
{
7171
selected_state_id = state_id_with_max_prob;
7272
}
@@ -93,18 +93,18 @@ public void transitStates(Ant ant, int state_index)
9393

9494
protected void localPheromoneUpdate(int state1_id, int state2_id)
9595
{
96-
double pheromone = mPheromones.get(state1_id, state2_id);
96+
double pheromone = pheromones.get(state1_id, state2_id);
9797

98-
pheromone = (1 - m_rho) * pheromone + m_rho * mTau0;
99-
if (pheromone <= mTau0)
98+
pheromone = (1 - rho) * pheromone + rho * tau0;
99+
if (pheromone <= tau0)
100100
{
101-
pheromone = mTau0;
101+
pheromone = tau0;
102102
}
103103

104-
mPheromones.set(state1_id, state2_id, pheromone);
105-
if (mSymmetric)
104+
pheromones.set(state1_id, state2_id, pheromone);
105+
if (symmetric)
106106
{
107-
mPheromones.set(state2_id, state1_id, pheromone);
107+
pheromones.set(state2_id, state1_id, pheromone);
108108
}
109109
}
110110
}

0 commit comments

Comments
 (0)