Ant Colony Optimization A threaded application in Java What is it? • An ant colony optimization algorithm seeks to solve hard problem by mimicking the behavior of ants. • This presentation shows an application of a basic ant colony algorithm to generate reasonably good solutions to the Travelling Salesperson Problem. The Ant Colony Simulation GUI Input params Map graphic Text output Program flow • Send some number of ants to explore the problem space (visit each city, then return) in a probabilistic fashion. • Ants deposit pheromones on the trails they visit. The intensity of these pheromones increases as the path distance decreases. Thus, the probability increases that more favorable paths get used more often. • Pheromones evaporate by some percentage each time an iteration occurs. (run only by threads[0]) • Return the result when the processing budget has been exhausted. Parallelism • The activities of the ants can be run using threads. • Running the course/collecting the distance data. • Depositing the pheromones • The GUI and ActionListener also run in threads. Synchronized methods This is how a mutex lock is implemented in Java: private synchronized void applyPheromone( int distance, int bestPathDistance, String[] run) { long newpheromoneLevel; newpheromoneLevel = (long) (distance/Math.sqrt(distance)); // each ant deposits pheromone for (int i=1; i < run.length; i++) { pheromoneLevels[getCityIndex(run[i-1])][getCityIndex(run[i])] += newpheromoneLevel; } pheromoneLevels[getCityIndex(run[(run.length)-1][getCityIndex(run[0])] += newpheromoneLevel; } Synchronized code within a method private void applyPheromone(int distance, int bestPathDistance, String[] run) { long newpheromoneLevel; newpheromoneLevel = (long) (distance/Math.sqrt(distance)); // each ant deposits pheromone synchronized(pheromoneLevels) { for (int i=1; i < run.length; i++) { pheromoneLevels[getCityIndex(run[i-1])][getCityIndex(run[i])] += newpheromoneLevel; } pheromoneLevels[getCityIndex(run[(run.length)-1])][getCityIndex(run[0])] += newpheromoneLevel; } } Interleaved synchronization • If you have class variables that are never used together, create a mutex for each of them, public class MsLunch { thus: private private private Object(); private Object(); long c1 = 0; long c2 = 0; Object lock1 = new Object lock2 = new public void inc1() { synchronized(lock1) { c1++; } } public void inc2() { synchronized(lock2) { c2++; } } } Implementing threads // In the actionPerformed method (Run button has been clicked) for (int i = 0; i < numThreads; i++) { //ThreadRunner contains the run() method threads[i] = new Thread(new ThreadRunner(), Integer.toString(i)); threads[i].start(); } for (int i = 0; i < numThreads; i++) { threads[i].join(); } // In the run() method // Evaporate once each run, before any pheromone is applied. // Only thread 0 gets to evaporate. if (k > 0 && Thread.currentThread().getName().equals("0")) { evaporate(); } Volatility • The volatile keyword, applied to variables, guarantees that a thread sees the latest version of it. // read from memory, not from thread cache private volatile int[][] pheromoneLevels; Resource usage • Workload is more or less shared equally between processors if run in server mode. (ex. java –jar [path]/SwingAnts.jar -server) • Otherwise, using one or all the CPUs depends on the platform you’re using. Performance • On (DogNet machine) grey: – 1 thread/100000 runs: 12500 ms – 2 threads/50000 runs: 6600 ms – 4 threads/25000 runs: 6700 ms – 8 threads/12500 runs: 6800 ms Java support for parallelism • Plain Old Threads (the Runnable class) • java.util.concurrent Packages (Java 7) – executors – Callables – Fork/join ExecutorTest output run: Pool size: 10: 679 ms. (this run was a “warm up”) Pool size: 5: 651 ms Pool size: 100: 675 ms. Pool size: 500: 746 ms. Pool size: 1000: 851 ms. BUILD SUCCESSFUL (total time: 36 seconds) SerialTest output (tail end of the output) result 46 start - Task 47 run time 1.105 secs result 47 start - Task 48 run time 1.103 secs result 48 start - Task 49 run time 1.123 secs result 49 run time 55.618 secs BUILD SUCCESSFUL (total time: 55 seconds) ExecutorServiceTest output (the tail end of the output) result 45 start - Task 49 run time 1.19 secs result 46 run time 1.19 secs result 47 run time 1.124 secs result 48 run time 1.12 secs result 49 run time 16.036 secs BUILD SUCCESSFUL (total time: 16 seconds) Useful references/tutorials • http://embarcaderos.net/2011/01/23/parallel -processing-and-multi-core-utilization-withjava/ • http://openjdk.java.net/groups/hotspot/docs/ RuntimeOverview.html • http://www.vogella.com/tutorials/JavaConcur rency/article.html