ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/loops/TSPExchangerTest.java
(Generate patch)

Comparing jsr166/src/test/loops/TSPExchangerTest.java (file contents):
Revision 1.2 by dl, Sat Dec 10 20:08:51 2005 UTC vs.
Revision 1.3 by dl, Mon Dec 12 20:06:20 2005 UTC

# Line 13 | Line 13 | import java.util.concurrent.locks.*;
13   * A parallel Traveling Salesperson Problem (TSP) program based on a
14   * genetic algorithm using an Exchanger.  A population of chromosomes
15   * is distributed among "pools".  The chromosomes represent tours, and
16 < * their fitness is the total tour length. Each chromosome is
17 < * initialized as a random tour.  A Task is associated with each pool.
18 < * Each task repeatedly does, for a fixed number of iterations
19 < * (generations):
20 < *
16 > * their fitness is the total tour length. A Task is associated with
17 > * each pool.  Each task repeatedly does, for a fixed number of
18 > * iterations (generations):
19   * <ol>
20   *   <li> Select a breeder b from the pool
21   *   <li> Create a strand of its tour with a random starting point and length
# Line 33 | Line 31 | import java.util.concurrent.locks.*;
31   *
32   */
33   public class TSPExchangerTest {
34 <    static final int DEFAULT_MAX_THREADS  =
35 <        (Runtime.getRuntime().availableProcessors() + 2);
34 >    static final int NCPUS = Runtime.getRuntime().availableProcessors();
35 >
36 >    static final int DEFAULT_MAX_THREADS  = NCPUS + 6;
37  
38      /**
39       * The problem size. Each city is a random point. The goal is to
# Line 103 | Line 102 | public class TSPExchangerTest {
102       */
103      static final int DYER_DECAY = 1;
104  
105 <    /**
107 <     * The probability mask for a task to give up running and
108 <     * resubmit itself. On each iteration, a task stops iterating
109 <     * and resubmits itself with probability 1 / (RESUBMIT_MASK+1).
110 <     * This avoids some tasks running to completion before others
111 <     * even start when there are more pools than threads.
112 <     *
113 <     * Must be 1 less than a power of two.
114 <     */
115 <    static final int RESUBMIT_MASK = 63;
116 <
117 <    static final boolean verbose = true;
105 >    static final boolean verbose = false;
106      static final long SNAPSHOT_RATE = 10000; // in milliseconds
107  
108      /**
# Line 181 | Line 169 | public class TSPExchangerTest {
169  
170      /**
171       * Perform one run with the given parameters.  Each run completes
172 <     * when all but one of the tasks has finished.  The last remaining
173 <     * task may have no one left to exchange with, so the pool is
174 <     * abruptly terminated.
172 >     * when there are fewer than nThreads-2 tasks remaining.  This
173 >     * avoids measuring termination effects, as well as cases where
174 >     * the one last remaining task has no one left to exchange with,
175 >     * so the pool is abruptly terminated.
176       */
177      static void oneRun(int nThreads, int nPools, int poolSize, int nGen)
178          throws InterruptedException {
# Line 229 | Line 218 | public class TSPExchangerTest {
218              this.nGen = nGen;
219              this.poolSize = poolSize;
220              this.exchanger = new Exchanger<Strand>();
221 <            this.done = new CountDownLatch(nPools-1);
221 >            this.done = new CountDownLatch(Math.max(1, nPools - nThreads - 2));
222              this.tasks = new Task[nPools];
223              for (int i = 0; i < nPools; i++)
224                  tasks[i] = new Task(this);
# Line 267 | Line 256 | public class TSPExchangerTest {
256           * fewer than nGen iterations.
257           */
258          void resubmit(Task task) {
259 <            exec.execute(task);
259 >            try {
260 >                exec.execute(task);
261 >            } catch(RejectedExecutionException ignore) {}
262          }
263  
264          void printSnapshot(double secs) {
265              int gens = 0;
266 <            double best = Double.MAX_VALUE;
267 <            double worst = 0;
266 >            Chromosome bestc = tasks[0].chromosomes[0];
267 >            Chromosome worstc = bestc;
268              for (int k = 0; k < tasks.length; ++k) {
269                  gens += tasks[k].gen;
270                  Chromosome[] cs = tasks[k].chromosomes;
271 <                float b = cs[0].fitness;
272 <                if (b < best)
273 <                    best = b;
274 <                float w = cs[cs.length-1].fitness;
275 <                if (w > worst)
276 <                    worst = w;
277 <            }
271 >                if (cs[0].fitness < bestc.fitness)
272 >                    bestc = cs[0];
273 >                int w = cs[cs.length-1].fitness;
274 >                if (cs[cs.length-1].fitness > worstc.fitness)
275 >                    worstc = cs[cs.length-1];
276 >            }
277 >            double sqrtn = Math.sqrt(cities.length);
278 >            double best = bestc.unitTourLength() / sqrtn;
279 >            double worst = worstc.unitTourLength() / sqrtn;
280              int avegen = (done.getCount() == 0)? nGen : gens / tasks.length;
281 <            System.out.printf("Time:%9.3f Best:%9.3f Worst:%9.3f Gen:%6d Threads:%4d\n",
281 >            System.out.printf("Time:%9.3f Best:%7.3f Worst:%7.3f Gen:%6d Threads:%4d\n",
282                                secs, best, worst, avegen, nThreads);
283          }
284          
292        float averageFitness() { // currently unused
293            float total = 0;
294            int count = 0;
295            for (int k = 0; k < tasks.length; ++k) {
296                Chromosome[] cs = tasks[k].chromosomes;
297                for (int i = 0; i < cs.length; i++)
298                    total += cs[i].fitness;
299                count += cs.length;
300            }
301            return total/(float)count;
302        }
285      }
286  
287      /**
# Line 318 | Line 300 | public class TSPExchangerTest {
300          final RNG rng;
301          final int poolSize;
302          final int nGen;
303 +        final int genPerRun;
304          int gen;
305  
306          Task(Population pop) {
# Line 325 | Line 308 | public class TSPExchangerTest {
308              this.nGen = pop.nGen;
309              this.gen = 0;
310              this.poolSize = pop.poolSize;
311 +            this.genPerRun = 4 * poolSize * Math.min(NCPUS, pop.nThreads);
312              this.exchanger = pop.exchanger;
313              this.rng = new RNG();
314              int length = cities.length;
# Line 337 | Line 321 | public class TSPExchangerTest {
321          }
322  
323          /**
324 <         * Run one or more update cycles.
324 >         * Run one or more update cycles.  An average of genPerRun
325 >         * iterations are performed per run, and then the task is
326 >         * resubmitted. The rate is proportional to both pool size and
327 >         * number of threads.  This keeps average rate of breeding
328 >         * across pools approximately constant across different test
329 >         * runs.
330           */
331          public void run() {
332              try {
333 <                for (;;) {
333 >                int maxGen = gen + 1 + rng.next() % genPerRun;
334 >                if (maxGen > nGen)
335 >                    maxGen = nGen;
336 >                while (gen++ < maxGen)
337                      update();
338 <                    if (++gen >= nGen) {
339 <                        pop.taskDone();
340 <                        return;
341 <                    }
350 <                    if ((rng.next() & RESUBMIT_MASK) == 1) {
351 <                        pop.resubmit(this);
352 <                        return;
353 <                    }
354 <                }
338 >                if (maxGen < nGen)
339 >                    pop.resubmit(this);
340 >                else
341 >                    pop.taskDone();
342              } catch (InterruptedException ie) {
343                  pop.taskDone();
344              }
# Line 470 | Line 457 | public class TSPExchangerTest {
457           */
458          void fixOrder(Chromosome c, int k) {
459              Chromosome[] cs = chromosomes;
460 <            float oldFitness = c.fitness;
460 >            int oldFitness = c.fitness;
461              c.recalcFitness();
462 <            float newFitness = c.fitness;
462 >            int newFitness = c.fitness;
463              if (newFitness < oldFitness) {
464                  int j = k;
465                  int p = j - 1;
# Line 500 | Line 487 | public class TSPExchangerTest {
487          /** Index of cities in tour order */
488          final int[] alleles;
489          /** Total tour length */
490 <        float fitness;
490 >        int fitness;
491  
492          /**
493           * Initialize to random tour
# Line 519 | Line 506 | public class TSPExchangerTest {
506          }
507  
508          public int compareTo(Object x) { // to enable sorting
509 <            float xf = ((Chromosome)x).fitness;
510 <            float f = fitness;
509 >            int xf = ((Chromosome)x).fitness;
510 >            int f = fitness;
511              return ((f == xf)? 0 :((f < xf)? -1 : 1));
512          }
513  
# Line 528 | Line 515 | public class TSPExchangerTest {
515              int[] a = alleles;
516              int len = a.length;
517              int p = a[0];
518 <            float f = cities.distanceBetween(a[len-1], p);
518 >            long f = cities.distanceBetween(a[len-1], p);
519              for (int i = 1; i < len; i++) {
520                  int n = a[i];
521                  f += cities.distanceBetween(p, n);
522                  p = n;
523              }
524 <            fitness = f;
524 >            fitness = (int)(f / len);
525 >        }
526 >
527 >        double unitTourLength() {
528 >            int[] a = alleles;
529 >            int len = a.length;
530 >            int p = a[0];
531 >            double f = cities.unitDistanceBetween(a[len-1], p);
532 >            for (int i = 1; i < len; i++) {
533 >                int n = a[i];
534 >                f += cities.unitDistanceBetween(p, n);
535 >                p = n;
536 >            }
537 >            return f;
538          }
539  
540          void validate() { // Ensure that this is a valid tour.
# Line 561 | Line 561 | public class TSPExchangerTest {
561      }
562  
563      /**
564 <     * A collection of (x,y) points that represent cities.  Distances
565 <     * are scaled in [0,1) to simply checking results.  The expected
566 <     * optimal TSP for random points is believed to be around 0.76 *
567 <     * sqrt(N). For papers discussing this, see
568 <     * http://www.densis.fee.unicamp.br/~moscato/TSPBIB_home.html for
564 >     * A collection of (x,y) points that represent cities.
565       */
566      static final class CitySet {
571        // Scale ints to doubles in [0,1)
572        static final double PSCALE = (double)0x80000000L;
567  
568          final int length;
569          final int[] xPts;
570          final int[] yPts;
571 <        final float[][] distances;
571 >        final int[][] distances;
572  
573          CitySet(int n) {
574              this.length = n;
575              this.xPts = new int[n];
576              this.yPts = new int[n];
577 <            this.distances = new float[n][n];
577 >            this.distances = new int[n][n];
578  
579              RNG random = new RNG();
580              for (int i = 0; i < n; i++) {
# Line 590 | Line 584 | public class TSPExchangerTest {
584  
585              for (int i = 0; i < n; i++) {
586                  for (int j = 0; j < n; j++) {
587 <                    double dX = (xPts[i] - xPts[j]) / PSCALE;
588 <                    double dY = (yPts[i] - yPts[j]) / PSCALE;
589 <                    distances[i][j] = (float)Math.hypot(dX, dY);
587 >                    double dx = (double)xPts[i] - (double)xPts[j];
588 >                    double dy = (double)yPts[i] - (double)yPts[j];
589 >                    double dd = Math.hypot(dx, dy) / 2.0;
590 >                    long ld = Math.round(dd);
591 >                    distances[i][j] = (ld >= Integer.MAX_VALUE)?
592 >                        Integer.MAX_VALUE : (int)ld;
593                  }
594              }
595          }
596  
597 <        // Retrieve the cached distance between a pair of cities
598 <        float distanceBetween(int i, int j) {
597 >        /**
598 >         *  Returns the cached distance between a pair of cities
599 >         */
600 >        int distanceBetween(int i, int j) {
601              return distances[i][j];
602          }
603 +
604 +        // Scale ints to doubles in [0,1)
605 +        static final double PSCALE = (double)0x80000000L;
606 +
607 +        /**
608 +         * Return distance for points scaled in [0,1). This simplifies
609 +         * checking results.  The expected optimal TSP for random
610 +         * points is believed to be around 0.76 * sqrt(N). For papers
611 +         * discussing this, see
612 +         * http://www.densis.fee.unicamp.br/~moscato/TSPBIB_home.html
613 +         */
614 +        double unitDistanceBetween(int i, int j) {
615 +            double dx = ((double)xPts[i] - (double)xPts[j]) / PSCALE;
616 +            double dy = ((double)yPts[i] - (double)yPts[j]) / PSCALE;
617 +            return Math.hypot(dx, dy);
618 +        }
619 +            
620      }
621  
622      /**
# Line 612 | Line 628 | public class TSPExchangerTest {
628  
629          int seed;
630          RNG(int seed) { this.seed = seed; }
631 <        RNG()         { this.seed = seedGenerator.nextInt(); }
631 >        RNG()         { this.seed = seedGenerator.nextInt() | 1;  }
632  
633          int next() {
634              int x = seed;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines