-
Notifications
You must be signed in to change notification settings - Fork 8
/
PACO.java
917 lines (818 loc) · 34.4 KB
/
PACO.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
package org.logisticPlanning.tsp.solving.algorithms.metaheuristics.permutation.paco;
import java.io.PrintStream;
import java.util.Arrays;
import org.logisticPlanning.tsp.benchmarking.instances.Instance;
import org.logisticPlanning.tsp.benchmarking.objective.ObjectiveFunction;
import org.logisticPlanning.tsp.solving.Individual;
import org.logisticPlanning.tsp.solving.TSPAlgorithm;
import org.logisticPlanning.tsp.solving.TSPAlgorithmRunner;
import org.logisticPlanning.tsp.solving.algorithms.metaheuristics.permutation.paco.update.Age;
import org.logisticPlanning.tsp.solving.utils.NodeManager;
import org.logisticPlanning.utils.config.Configurable;
import org.logisticPlanning.utils.config.Configuration;
import org.logisticPlanning.utils.math.random.Randomizer;
/**
*
<p>
* In this class, we implement the Population-based ACO algorithm for
* symmetric and asymmetric TSPs.
* </p>
* <h2 id="paco">Population-based ACO</h2>
* <p>
* The Population-based <a href=
* "https://en.wikipedia.org/wiki/Ant_colony_optimization_algorithms"
* >ACO</a> algorithm (pACO) [<a href="#cite_G2004AAISAMCE"
* style="font-weight:bold">1</a>, <a href="#cite_GM2002APBAFA"
* style="font-weight:bold">2</a>, <a href="#cite_GM2002APBATDOP"
* style="font-weight:bold">3</a>] is a version of the Ant Colony
* Optimization Algorithm that does not require the presence and updating
* of a complete pheromone matrix in memory. Instead, it maintains a set
* ("population") of {@code k} ants (paths, solutions,
* permutations) which in their describe the pheromone information τ
* completely. The efficiency of this algorithm has been verified
* in [<a href="#cite_OHSRD2011ADAOTPBACOAFTTATQ"
* style="font-weight:bold">4</a>, <a
* href="#cite_OHSRD2011ADAOTPBACOAFTTATQ2"
* style="font-weight:bold">5</a>].
* </p>
* <p>
* <a href=
* "https://en.wikipedia.org/wiki/Ant_colony_optimization_algorithms">Ant
* Colony Optimization</a> has been introduced by Dorigo [<a
* href="#cite_D1992OLANA" style="font-weight:bold">6</a>, <a
* href="#cite_DS2004ACO" style="font-weight:bold">7</a>, <a
* href="#cite_DB2005ACO" style="font-weight:bold">8</a>, <a
* href="#cite_DBS2006ACOAAAACIT" style="font-weight:bold">9</a>, <a
* href="#cite_DGMS2002SCOACO" style="font-weight:bold">10</a>]. In ACO,
* solutions are generated by a constructive heuristic. The constructive
* heuristic proceeds as follows: A simulated ant starts at a node in a
* graph. It will decide to which node to move next based on two pieces on
* information assigned to each edge: a static heuristic value assigned to
* the edge and a "pheromone" value assigned to the edge which
* may be modified. The ant continues to move until it reaches a
* destination node. In TSPs, this means that it will visit all nodes. In
* each of the algorithm's rounds, several solutions are created by
* applying the heuristic/ant simulation process. At the end of the
* iteration, the pheromones on the edges will be updated: If a solution
* was particularly well, then the pheromones of the edges it includes will
* be increased and thus, make the edge more likely to be visited by ants
* in the future round. The pheromones in plain ACO are stored in a matrix
* of {@code n*n} elements, but in pACO, only {@code k*n} elements are
* necessary, with {@code k<<n}.
* </p>
* <p>
* The idea of pACO is that each edge in each of these {@code k} solutions
* contributes exactly an amount Δ to the amount of pheromone on that
* edge. If an ant/solution {@code x} enters the population, Δ
* pheromone is added to each edge in {@code x}. Vice versa, if an ant
* leaves the population, for instance because it was replaced by another
* younger or better ant, exactly this amount of pheromone is subtracted
* again from the pheromone value of all of its edges. No other negative
* update (like vaporization or something) is necessary.
* </p>
* <p>
* The default configuration of the algorithm is taken mainly from [<a
* href="#cite_GM2002APBATDOP" style="font-weight:bold">3</a>], with the
* exception of {@code m=10} and {@code k=5} which are taken from [<a
* href="#cite_GM2002APBAFA" style="font-weight:bold">2</a>].
* </p>
* <p>
* This class provides two hook methods,
* {@link #createInitialPopulation(Individual[], ObjectiveFunction)} and
* {@link #refineSolution(int[], long, ObjectiveFunction)}, which allow to
* extend the ACO with local search capability.
* </p>
* <h2>References</h2>
* <ol>
* <li><div><span id="cite_G2004AAISAMCE" /><a
* href="http://www.aifb.kit.edu/web/Michael_Guntsch/en">Michael
* Guntsch</a>: <span
* style="font-style:italic;font-family:cursive;">“Ant Algorithms in
* Stochastic and Multi-Criteria Environments,”</span> PhD Thesis,
* January 13, 2004, Karlsruhe, Germany: University of Karlsruhe
* (Friedriciana), Department of Economics and Business Engineering
* and Karlsruhe, Germany: University of Karlsruhe (Friedriciana),
* Institute for Applied Computer Science and Formal Description Methods
* (AIFB). Google Book ID: <a
* href="http://books.google.com/books?id=Lf1ztwAACAAJ">Lf1ztwAACAAJ</a>.
* <div>links: [<a
* href="http://www.lania.mx/~ccoello/EMOO/thesis_guntsch.pdf.gz">1</a>]
* and [<a
* href="http://digbib.ubka.uni-karlsruhe.de/volltexte/212004">2</a>];
* urn: <a href=
* "http://wm-urn.org/?urn=urn:nbn:de:swb:90-AAA2120045&redirect=1"
* >urn:nbn:de:swb:90-AAA2120045</a></div></div></li>
* <li><div><span id="cite_GM2002APBAFA" /><a
* href="http://www.aifb.kit.edu/web/Michael_Guntsch/en">Michael
* Guntsch</a> and <a href=
* "http://pacosy.informatik.uni-leipzig.de/15-0-Prof+Dr+Martin+Middendorf.html"
* >Martin Middendorf</a>: <span style="font-weight:bold">“A
* Population Based Approach for ACO,”</span> in <span
* style="font-style:italic;font-family:cursive;">Applications of
* Evolutionary Computing, Proceedings of EvoWorkshops 2002: EvoCOP,
* EvoIASP, EvoSTIM/EvoPLAN (EvoWorkshops'02)</span>, April 2–4,
* 2002, Kinsale, Ireland, pages 72–81, <a
* href="http://www.ce.unipr.it/people/cagnoni/">Stefano Cagnoni</a>, Jens
* Gottlieb, <a
* href="http://www.soc.napier.ac.uk/~emmah/Prof_Emma_Hart/Welcome.html"
* >Emma Hart</a>, <a href=
* "http://pacosy.informatik.uni-leipzig.de/15-0-Prof+Dr+Martin+Middendorf.html"
* >Martin Middendorf</a>, and <a
* href="https://www.ads.tuwien.ac.at/raidl/">Günther R. Raidl</a>,
* editors, volume 2279 of Lecture Notes in Computer Science (LNCS),
* Berlin, Germany: Springer-Verlag GmbH. ISBN: <a
* href="https://www.worldcat.org/isbn/3540434321">3-540-43432-1</a>
* and <a
* href="https://www.worldcat.org/isbn/9783540434320">978-3-540-
* 43432-0</a>; doi: <a
* href="http://dx.doi.org/10.1007/3-540-46004-7_8"
* >10.1007/3-540-46004-7_8</a>; ISSN: <a
* href="https://www.worldcat.org/issn/03029743">0302-9743</a> and <a
* href="https://www.worldcat.org/issn/16113349">1611-3349</a>.
* <div>CiteSeer<sup>x</sup><sub
* style="font-style:italic">β</sub>: <a href
* ="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.13.2514"
* >10.1.1.13 .2514</a></div></div></li>
* <li><div><span id="cite_GM2002APBATDOP" /><a
* href="http://www.aifb.kit.edu/web/Michael_Guntsch/en">Michael
* Guntsch</a> and <a href=
* "http://pacosy.informatik.uni-leipzig.de/15-0-Prof+Dr+Martin+Middendorf.html"
* >Martin Middendorf</a>: <span style="font-weight:bold">“Applying
* Population Based ACO to Dynamic Optimization Problems,”</span> in
* <span style="font-style:italic;font-family:cursive;">From Ant Colonies
* to Artificial Ants ‒ Proceedings of the Third International
* Workshop on Ant Colony Optimization (ANTS'02)</span>,
* September 12–14, 2002, Brussels, Belgium, pages
* 111–122, <a
* href="https://en.wikipedia.org/wiki/Marco_Dorigo">Marco Dorigo</a>, <a
* href="http://www.idsia.ch/~gianni/">Gianni A. Di Caro</a>,
* and Michael Samples, editors, volume 2463/2002 of Lecture Notes in
* Computer Science (LNCS), Berlin, Germany: Springer-Verlag GmbH.
* ISBN: <a
* href="https://www.worldcat.org/isbn/3540441468">3-540-44146-8</a>
* and <a
* href="https://www.worldcat.org/isbn/9783540441465">978-3-540-
* 44146-5</a>; doi: <a
* href="http://dx.doi.org/10.1007/3-540-45724-0_10">10.1007/3-540-45724
* -0_10</a>; ISSN: <a
* href="https://www.worldcat.org/issn/03029743">0302-9743</a> and <a
* href="https://www.worldcat.org/issn/16113349">1611-3349</a>.
* <div>CiteSeer<sup>x</sup><sub
* style="font-style:italic">β</sub>: <a href
* ="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.12.6580"
* >10.1.1.12 .6580</a></div></div></li>
* <li><div><span id="cite_OHSRD2011ADAOTPBACOAFTTATQ" />Sabrina M.
* Oliveira, Mohamed Saifullah Hussin, <a
* href="http://iridia.ulb.ac.be/~stuetzle/">Thomas Stützle</a>,
* Andrea Roli, and <a
* href="https://en.wikipedia.org/wiki/Marco_Dorigo">Marco Dorigo</a>:
* <span style="font-weight:bold">“A Detailed Analysis of the
* Population-based Ant Colony Optimization Algorithm for the TSP and the
* QAP,”</span> <span
* style="font-style:italic;font-family:cursive;">Technical Report</span>
* Number TR/IRIDIA/2011-006, February 2011; published by
* Brussels, Belgium: Université Libre de Bruxelles, Institut de
* Recherches Interdisciplinaires et de Développements en Intelligence
* Artificielle (IRIDIA). ISSN: <a
* href="https://www.worldcat.org/issn/17813794">1781-3794</a>. <div>link:
* [<a href
* ="http://iridia.ulb.ac.be/IridiaTrSeries/rev/IridiaTr2011-006r001.pdf"
* >1</ a>]</div></div></li>
* <li><div><span id="cite_OHSRD2011ADAOTPBACOAFTTATQ2" />Sabrina M.
* Oliveira, Mohamed Saifullah Hussin, <a
* href="http://iridia.ulb.ac.be/~stuetzle/">Thomas Stützle</a>,
* Andrea Roli, and <a
* href="https://en.wikipedia.org/wiki/Marco_Dorigo">Marco Dorigo</a>:
* <span style="font-weight:bold">“A Detailed Analysis of the
* Population-based Ant Colony Optimization Algorithm for the TSP and the
* QAP,”</span> in <span
* style="font-style:italic;font-family:cursive;">Proceedings of the
* Genetic and Evolutionary Computation Conference (GECCO'11)</span>,
* July 12–16, 2011, Dublin, Ireland, pages 13–14.
* doi: <a href="http://dx.doi.org/10.1145/2001858.2001866">10.1145/
* 2001858.2001866</a>. <div>link: [<a
* href="http://code.ulb.ac.be/dbfiles/OliHusStu-etal2011gecco.pdf"
* >1</a>]</div></div></li>
* <li><div><span id="cite_D1992OLANA" /><a
* href="https://en.wikipedia.org/wiki/Marco_Dorigo">Marco Dorigo</a>:
* <span
* style="font-style:italic;font-family:cursive;">“Optimization,
* Learning and Natural Algorithms,”</span> PhD Thesis,
* January 1992, Milano, Italy: Dipartimento di Elettronica,
* Politecnico di Milano</div></li>
* <li><div><span id="cite_DS2004ACO" /><a
* href="https://en.wikipedia.org/wiki/Marco_Dorigo">Marco Dorigo</a>
* and <a href="http://iridia.ulb.ac.be/~stuetzle/">Thomas
* Stützle</a>: <span
* style="font-style:italic;font-family:cursive;">“Ant Colony
* Optimization,”</span> July 1, 2004, Bradford Books,
* Cambridge, MA, USA: MIT Press. ISBN: <a
* href="https://www.worldcat.org/isbn/0262042193">0-262-04219-3</a>
* and <a
* href="https://www.worldcat.org/isbn/9780262042192">978-0-262-
* 04219-2</a>; Google Book ID: <a
* href="http://books.google.com/books?id=_aefcpY8GiEC"
* >_aefcpY8GiEC</a></div></li>
* <li><div><span id="cite_DB2005ACO" /><a
* href="https://en.wikipedia.org/wiki/Marco_Dorigo">Marco Dorigo</a>
* and Christian Blum: <span style="font-weight:bold">“Ant
* Colony Optimization Theory: A Survey,”</span> in <span
* style="font-style:italic;font-family:cursive;">Theoretical Computer
* Science</span> 344(2-3), November 17, 2005; published by Essex, UK:
* Elsevier Science Publishers B.V.. doi: <a
* href="http://dx.doi.org/10.1016/j.tcs.2005.05.020"
* >10.1016/j.tcs.2005.05.020</a>; ISSN: <a
* href="https://www.worldcat.org/issn/03043975">0304-3975</a>. <div>link:
* [<a
* href="http://code.ulb.ac.be/dbfiles/DorBlu2005tcs.pdf">1</a>]</div></
* div></li>
* <li><div><span id="cite_DBS2006ACOAAAACIT" /><a
* href="https://en.wikipedia.org/wiki/Marco_Dorigo">Marco Dorigo</a>,
* Mauro Birattari, and <a
* href="http://iridia.ulb.ac.be/~stuetzle/">Thomas Stützle</a>: <span
* style="font-weight:bold">“Ant Colony Optimization ‒
* Artificial Ants as a Computational Intelligence Technique,”</span>
* in <span style="font-style:italic;font-family:cursive;">IEEE
* Computational Intelligence Magazine (CIM)</span> 1(4):28–39,
* November 2006; published by Piscataway, NJ, USA: IEEE Computational
* Intelligence Society. doi: <a
* href="http://dx.doi.org/10.1109/MCI.2006.329691"
* >10.1109/MCI.2006.329691</a>; ISSN: <a
* href="https://www.worldcat.org/issn/1556603X">1556-603X</a>; INSPEC
* Accession Number: 9184238. <div>links: [<a
* href="http://iridia.ulb.ac.be/~mbiro/paperi/IridiaTr2006-023r001.pdf"
* >1</a>] and [<a
* href="http://iridia.ulb.ac.be/~mbiro/paperi/DorBirStu2006ieee-cim.pdf"
* >2</a>]; CiteSeer<sup>x</sup><sub
* style="font-style:italic">β</sub>: <a
* href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.64.9532"
* >10.1.1.64.9532</a></div></div></li>
* <li><div><span id="cite_DGMS2002SCOACO" /><a
* href="https://en.wikipedia.org/wiki/Marco_Dorigo">Marco Dorigo</a>, <a
* href="http://www.idsia.ch/~luca/">Luca Maria Gambardella</a>, <a href=
* "http://pacosy.informatik.uni-leipzig.de/15-0-Prof+Dr+Martin+Middendorf.html"
* >Martin Middendorf</a>, and <a
* href="http://iridia.ulb.ac.be/~stuetzle/">Thomas Stützle</a>: <span
* style="font-weight:bold">“Special Section on “Ant Colony
* Optimization”,”</span> in <span
* style="font-style:italic;font-family:cursive;">IEEE Transactions on
* Evolutionary Computation (IEEE-EC)</span> 6(4):317–365,
* August 2002; published by Washington, DC, USA: IEEE Computer
* Society. LCCN: <a href="http://lccn.loc.gov/97648327">97648327</a>;
* doi: <a href
* ="http://dx.doi.org/10.1109/TEVC.2002.802446">10.1109/TEVC
* .2002.802446</a>; ISSN: <a
* href="https://www.worldcat.org/issn/1089778X">1089-778X</a> and <a
* href="https://www.worldcat.org/issn/19410026">1941-0026</a>;
* CODEN: <a href=
* "http://www-library.desy.de/cgi-bin/spiface/find/coden/www?code=ITEVF5"
* >ITEVF5</a>; further information: [<a
* href="http://www.ieee-cis.org/pubs/tec/">1</a>]</div></li>
* </ol>
*/
public class PACO extends TSPAlgorithm {
/** the serial version uid */
private static final long serialVersionUID = 1L;
/** the default {@link #m_alpha alpha}: {@value} */
public static final double DEFAULT_ALPHA = 1d;
/** the default {@link #m_beta beta}: {@value} */
public static final double DEFAULT_BETA = 5d;
/** the default {@link #m_populationSize population size} k: {@value} */
public static final int DEFAULT_POPULATION_SIZE = 5;
/** the default {@link #m_q0 q0}: {@value} */
public static final double DEFAULT_Q0 = 0.9d;
/** the default {@link #m_tauMax tau_max}: {@value} */
public static final double DEFAULT_TAU_MAX = 1d;
/** the default {@link #m_antCount ant count} m: {@value} */
public static final int DEFAULT_ANT_COUNT = 10;
/** the default {@link #m_update update strategy} */
private static final PopulationUpdateStrategy DEFAULT_UPDATE = Age.INSTANCE;
/** the {@link #m_alpha alpha} parameter: {@value} */
public static final String PARAM_ALPHA = "alpha"; //$NON-NLS-1$
/** the {@link #m_beta beta} parameter: {@value} */
public static final String PARAM_BETA = "beta"; //$NON-NLS-1$
/** the {@link #m_populationSize population size} parameter k: {@value} */
public static final String PARAM_POPULATION_SIZE = "populationSize"; //$NON-NLS-1$
/** the @link #m_q0 q0} parameter: {@value} */
public static final String PARAM_Q0 = "q0"; //$NON-NLS-1$
/** the {@link #m_tauMax tau_max} parameter: {@value} */
public static final String PARAM_TAU_MAX = "tauMax"; //$NON-NLS-1$
/** the {@link #m_antCount ant count} parameter m: {@value} */
public static final String PARAM_ANT_COUNT = "antsPerIteration"; //$NON-NLS-1$
/** the {@link #m_update update strategy} parameter: {@value} */
private static final String PARAM_UPDATE = "populationUpdateStrategy"; //$NON-NLS-1$
/**
* The error distance which is used for zero distances: Here, we simply
* use a value of 2. Normally, the heuristic value used for any distance
* {@code d} is {@code 1/d}. Shorter distances lead to larger heuristic
* values. As distances are always integers, the heuristic values are
* always in {@code (0, 1]}. For a zero distance, we choose {@code 2} as
* it is larger (better) than any other distance.
*/
private static final double ERROR_NU = (2d);
/**
* the alpha parameter ruling the influence of the pheromone [<a
* href="#cite_G2004AAISAMCE" style="font-weight:bold">1</a>, <a
* href="#cite_GM2002APBAFA" style="font-weight:bold">2</a>, <a
* href="#cite_GM2002APBATDOP" style="font-weight:bold">3</a>], with
* default value {@value #DEFAULT_ALPHA}.
*
* @serial serializable field
*/
private double m_alpha;
/**
* the beta parameter ruling the influence of the distance [<a
* href="#cite_G2004AAISAMCE" style="font-weight:bold">1</a>, <a
* href="#cite_GM2002APBAFA" style="font-weight:bold">2</a>, <a
* href="#cite_GM2002APBATDOP" style="font-weight:bold">3</a>], with
* default value {@value #DEFAULT_BETA}.
*
* @serial serializable field
*/
private double m_beta;
/**
* the population size {@code k}, i.e., the number of ants maintained,
* i.e., the ants/paths defining the pheromones [<a
* href="#cite_G2004AAISAMCE" style="font-weight:bold">1</a>, <a
* href="#cite_GM2002APBAFA" style="font-weight:bold">2</a>, <a
* href="#cite_GM2002APBATDOP" style="font-weight:bold">3</a>], with
* default value {@value #DEFAULT_POPULATION_SIZE}.
*
* @serial serializable field
*/
private int m_populationSize;
/**
* the probability {@code q0} of simply taking the best heuristic
* step [<a href="#cite_G2004AAISAMCE"
* style="font-weight:bold">1</a>, <a href="#cite_GM2002APBAFA"
* style="font-weight:bold">2</a>, <a href="#cite_GM2002APBATDOP"
* style="font-weight:bold">3</a>], with default value
* {@value #DEFAULT_Q0}
*
* @serial serializable field
*/
private double m_q0;
/**
* the maximum pheromone value <code>tau<sub>max</sub></code> [<a
* href="#cite_G2004AAISAMCE" style="font-weight:bold">1</a>, <a
* href="#cite_GM2002APBAFA" style="font-weight:bold">2</a>, <a
* href="#cite_GM2002APBATDOP" style="font-weight:bold">3</a>], with
* default value {@value #DEFAULT_TAU_MAX}
*
* @serial serializable field
*/
private double m_tauMax;
/**
* the number {@code m} of ants created per iteration, from which the
* best ant may enter the population [<a href="#cite_G2004AAISAMCE"
* style="font-weight:bold">1</a>, <a href="#cite_GM2002APBAFA"
* style="font-weight:bold">2</a>, <a href="#cite_GM2002APBATDOP"
* style="font-weight:bold">3</a>], with default value
* {@value #DEFAULT_ANT_COUNT}
*
* @serial serializable field
*/
private int m_antCount;
/**
* the population update strategy [<a href="#cite_G2004AAISAMCE"
* style="font-weight:bold">1</a>, <a href="#cite_GM2002APBAFA"
* style="font-weight:bold">2</a>, <a href="#cite_GM2002APBATDOP"
* style="font-weight:bold">3</a>]
*
* @serial serializable field
*/
private PopulationUpdateStrategy m_update;
/** a temporary variable for the current solution */
private transient int[] m_cur;
/** a temporary variable for the distances */
private transient int[] m_dists;
/** a temporary variable for the pheromone decision table */
private transient double[] m_table;
/** a temporary variable for the node manager */
transient NodeManager m_nodes;
/** a temporary variable for the pheromone matrix */
private transient PheromoneMatrix m_matrix;
/** a temporary variable for the population */
private transient PACOIndividual[] m_pop;
/**
* instantiate
*
* @param name
* the name of the algorithm, to be prepented to the name of
* {@link PACO}
*/
protected PACO(final String name) {
super(((name != null) ? (name) : "") + //$NON-NLS-1$
"Population-based ACO"); //$NON-NLS-1$
this.m_alpha = PACO.DEFAULT_ALPHA;
this.m_beta = PACO.DEFAULT_BETA;
this.m_populationSize = PACO.DEFAULT_POPULATION_SIZE;
this.m_q0 = PACO.DEFAULT_Q0;
this.m_tauMax = PACO.DEFAULT_TAU_MAX;
this.m_antCount = PACO.DEFAULT_ANT_COUNT;
this.m_update = PACO.DEFAULT_UPDATE;
this.__clearInstance();
}
/** instantiate */
public PACO() {
this(null);
}
/**
* Get the alpha parameter ruling the influence of the pheromone
*
* @return the alpha parameter ruling the influence of the pheromone
*/
public final double getAlpha() {
return this.m_alpha;
}
/**
* Set the alpha parameter ruling the influence of the pheromone
*
* @param alpha
* the alpha parameter ruling the influence of the pheromone
*/
public final void setAlpha(final double alpha) {
this.m_alpha = alpha;
}
/**
* Get the beta parameter ruling the influence of the distance
*
* @return the beta parameter ruling the influence of the distance
*/
public final double getBeta() {
return this.m_beta;
}
/**
* Set the beta parameter ruling the influence of the distance
*
* @param beta
* the beta parameter ruling the influence of the distance
*/
public final void setBeta(final double beta) {
this.m_beta = beta;
}
/**
* Get the population size
*
* @return the population size
*/
public final int getPopulationSize() {
return this.m_populationSize;
}
/**
* set the population size
*
* @param ps
* the population size
*/
public final void setPopulationSize(final int ps) {
this.m_populationSize = ps;
}
/**
* Get the number of ants per iteration
*
* @return the number of ants per iteration
*/
public final int getAntCount() {
return this.m_antCount;
}
/**
* set the number of ants per iteration
*
* @param ac
* the number of ants per iteration
*/
public final void setAntCount(final int ac) {
this.m_antCount = ac;
}
/** initialize an instance: this method is called by clone */
private final void __clearInstance() {
this.m_cur = null;
this.m_dists = null;
this.m_table = null;
this.m_pop = null;
this.m_nodes = null;
this.m_matrix = null;
}
/** {@inheritDoc} */
@Override
public PACO clone() {
final PACO res;
res = ((PACO) (super.clone()));
res.__clearInstance();
res.m_update = ((PopulationUpdateStrategy) (res.m_update.clone()));
return res;
}
/**
* Execute the population-based ACO [<a href="#cite_G2004AAISAMCE"
* style="font-weight:bold">1</a>, <a href="#cite_GM2002APBAFA"
* style="font-weight:bold">2</a>, <a href="#cite_GM2002APBATDOP"
* style="font-weight:bold">3</a>]
*
* @param f
* the objective function defining the TSP problem to solve
*/
@Override
public final void solve(final ObjectiveFunction f) {
final int n, m;
final PheromoneMatrix matrix;
final int[] cur, dists;
final double[] table;
final NodeManager nodes;
final Randomizer r;
final double alpha, beta, q0;
final PACOIndividual[] pop;
final PopulationUpdateStrategy update;
PACOIndividual bestGen;
int curAnt, i, j, curNode, lastNode, nodesLeft, dist, bestNode, bestDist;
double phero, bestPhero, pheroSum;
boolean decideRandomly;
long curTotalDist, gen;
boolean initialized;
// initialize all local variables and stuff
n = f.n();
matrix = this.m_matrix;
// the node manager is an O(1) thingy that allows us to 1) keep track
// of
// all unvisited nodes, 2) delete nodes by visiting them, 3) find
// random
// nodes and deleting them
nodes = this.m_nodes;
// allocate temporary variables
cur = this.m_cur;
dists = this.m_dists;
table = this.m_table;
r = f.getRandom();
// get local copies of algorithm parameters
m = this.m_antCount;
alpha = this.m_alpha;
beta = this.m_beta;
q0 = this.m_q0;
update = this.m_update;
curAnt = 0; // curAnt = the index of the ant
gen = 1l; // the algorithm iteration/generation index
// the initially empty population
pop = this.m_pop;
// Create the initial population, if initialization heuristics are
// used.
// If
// individuals are created, check them into the pheromone matrix.
this.createInitialPopulation(pop, f);// call the initialization
// heuristics
initialized = false;
for (final PACOIndividual ind : pop) {// check if any individuals were
// created
if (ind.tourLength != Individual.TOUR_LENGTH_NOT_SET) {
ind.m_birthday = gen; // ok, individuals were created, set
// birthday
initialized = true; // remember to increase generation
matrix.add(ind.solution);// check individuals into matrix
} else { // ok, no more individuals, break loop
break; // this is the fast exit if no initialization
}
}
if (initialized) {// individuals were created by a heuristic
gen++;// thus, we need to increase the generation
}
bestGen = new PACOIndividual();
// main algorithm part: run as long as we can
while (!(f.shouldTerminate())) {
nodes.init(n);
// Build one new candidate solution by simulating the behavior of
// one ant
// moving through the graph.
nodesLeft = n;
i = 0;
cur[i++] = curNode = nodes.deleteRandom(r); // start at a random
// node
curTotalDist = 0l;
// Visit the nodes, after starting at a random node (skipping the
// last
// node as there is no decision to make for the last node).
for (; (--nodesLeft) > 1;) {// for (n-2) times do...
lastNode = curNode;
// With probability q0, always choose best node directly.
decideRandomly = (r.nextDouble() >= q0);
// Ok, calculate the matrix stuff.
// First: setup the best values.
bestPhero = Double.NEGATIVE_INFINITY;
bestDist = bestNode = (-1);
pheroSum = 0d;
// Then: for each node which is not yet assigned...
for (j = 0; j < nodesLeft; j++) {
// Get that node.
curNode = nodes.getByIndex(j);
// Get the distance from the last node.
dist = f.distance(lastNode, curNode);
// Compute the pheromone/heuristic value.
phero = (Math.pow(matrix.get(lastNode, curNode), alpha) * //
Math.pow(((dist != 0) ? (1d / dist) : PACO.ERROR_NU), beta));
// Is this the best pheromone/heuristic value?
if (phero >= bestPhero) { // Then remember it.
bestPhero = phero;
bestNode = curNode;
bestDist = dist;
}
if (decideRandomly) {
// Only if we actually are going to use the tables we
// need to add
// up the pheromone/heuristic values and remember them.
// This is
// needed to later make a value-proportional choice.
// Otherwise, if
// we decide deterministically anyway, we don't do this
// to save
// runtime.
pheroSum += phero;
table[j] = pheroSum;
dists[j] = dist;
}
}
// Ok, by now we have either found the best node to add (in case
// of
// !decideRandomly) or built the complete distance/pheromone
// decision
// table (in case of decideRandomly).
// After we have decided, bestDist should hold the distance of
// this
// step and curNode is the selected node.
if (decideRandomly) {
// Decide randomly based on the table that we have
// constructed.
table[nodesLeft - 1] = Double.POSITIVE_INFINITY;
j = Arrays.binarySearch(table, 0, nodesLeft,//
r.nextDouble() * pheroSum);
if (j < 0) {
j = (-(j + 1));
}
bestDist = dists[j];
curNode = nodes.getByIndex(j);
} else {
// No random decision: choose the best.
curNode = bestNode;
}
// Visit the chosen node!
cur[i++] = curNode;// Store node in solution.
nodes.deleteByID(curNode);// Delete node from list of available
// nodes.
curTotalDist += bestDist;
}
// Add the last node: There only is one choice.
cur[i] = bestNode = nodes.deleteLast();
// And we can compute the total distance by adding the distance to
// the
// last node and the distance back to the beginning.
curTotalDist += f.distance(curNode, bestNode) + //
f.distance(bestNode, cur[0]);
// Register this FE: We have constructed a complete solution!
f.registerFE(cur, curTotalDist);
// Call the local search procedure, if any. This procedure, if it
// does
// something, must also register its FEs and DEs.
curTotalDist = this.refineSolution(cur, curTotalDist, f);
// Is this the best ant of this generation so far?
if (curTotalDist < bestGen.tourLength) {
bestGen.setup(cur, curTotalDist, gen);
}
curAnt++; // Ok, one ant has finished
if (curAnt == m) { // Every m steps...
// we update the population and matrix!
update.update(pop, bestGen, matrix);
// Start next cycle of m ants.
curAnt = 0;
gen++;
bestGen.doclear();
}
}
}
/** {@inheritDoc} */
@Override
public void configure(final Configuration config) {
super.configure(config);
this.m_alpha = config.getDouble(PACO.PARAM_ALPHA, 0d, 1000d,
this.m_alpha);
this.m_beta = config
.getDouble(PACO.PARAM_BETA, 0d, 1000d, this.m_beta);
this.m_antCount = config.getInt(PACO.PARAM_ANT_COUNT, 1, 10000,//
this.m_antCount);
this.m_populationSize = config.getInt(PACO.PARAM_POPULATION_SIZE, 1,
10000, this.m_populationSize);
this.m_q0 = config.getDouble(PACO.PARAM_Q0, 0d, 1d, this.m_q0);
this.m_tauMax = config.getDouble(PACO.PARAM_TAU_MAX, 0.5d, 100000d,
this.m_tauMax);
this.m_update = config.getInstance(PACO.PARAM_UPDATE,
PopulationUpdateStrategy.class, null, this.m_update);
}
/** {@inheritDoc} */
@Override
public void printConfiguration(final PrintStream ps) {
super.printConfiguration(ps);
Configurable.printKey(PACO.PARAM_ALPHA, ps);
ps.println(this.m_alpha);
Configurable.printKey(PACO.PARAM_BETA, ps);
ps.println(this.m_beta);
Configurable.printKey(PACO.PARAM_ANT_COUNT, ps);
ps.println(this.m_antCount);
Configurable.printKey(PACO.PARAM_POPULATION_SIZE, ps);
ps.println(this.m_populationSize);
Configurable.printKey(PACO.PARAM_Q0, ps);
ps.println(this.m_q0);
Configurable.printKey(PACO.PARAM_TAU_MAX, ps);
ps.println(this.m_tauMax);
Configurable.printKey(PACO.PARAM_UPDATE, ps);
Configurable.printlnObject(this.m_update, ps);
}
/** {@inheritDoc} */
@Override
public void printParameters(final PrintStream ps) {
super.printParameters(ps);
Configurable.printKey(PACO.PARAM_ALPHA, ps);
ps.println("the weight of the pheromones"); //$NON-NLS-1$
Configurable.printKey(PACO.PARAM_BETA, ps);
ps.println("the weight of the visibility (inverse node distance)"); //$NON-NLS-1$
Configurable.printKey(PACO.PARAM_ANT_COUNT, ps);
ps.println("the number of ants/solutions per algorithm iteration"); //$NON-NLS-1$
Configurable.printKey(PACO.PARAM_POPULATION_SIZE, ps);
ps.println("the size of the population"); //$NON-NLS-1$
Configurable.printKey(PACO.PARAM_Q0, ps);
ps.println("the probability to follow the heuristic-maximizing path"); //$NON-NLS-1$
Configurable.printKey(PACO.PARAM_TAU_MAX, ps);
ps.println("the maximum pheromone"); //$NON-NLS-1$
Configurable.printKey(PACO.PARAM_UPDATE, ps);
ps.println("the population update strategy"); //$NON-NLS-1$
}
/**
* This method can be overridden to create the initial population of ACO.
* This may be useful if an heuristic initialization procedure is
* performed. The default implementation in class {@link PACO} does
* nothing.
*
* @param pop
* the population to fill
* @param f
* the objective function
*/
protected void createInitialPopulation(final Individual<int[]>[] pop,
final ObjectiveFunction f) {
//
}
/**
* This method can be overridden to perform a local search on an
* individual which was created by ACO. The default implementation in
* class {@link PACO} does nothing.
*
* @param solution
* the solution to be refined. The contents of this array may be
* modified
* @param tourLength
* the tour length of {@code solution}
* @param f
* the objective function
* @return the tour length of whatever is now stored in {@code solution}
*/
protected long refineSolution(final int[] solution,
final long tourLength, final ObjectiveFunction f) {
return tourLength;
}
/**
* Perform the population-based ACO
*
* @param args
* the command line arguments
*/
public static void main(final String[] args) {
TSPAlgorithmRunner.benchmark(//
Instance.ALL_INSTANCES, PACO.class,//
args);
}
/** {@inheritDoc} */
@Override
public void beginRun(final ObjectiveFunction f) {
final int n;
final PACOIndividual[] res;
int i;
super.beginRun(f);
this.m_nodes = new NodeManager();
n = f.n();
this.m_matrix = new PheromoneMatrix();
this.m_matrix.init(n, this.m_populationSize, this.m_tauMax);
this.m_cur = new int[n];
this.m_dists = new int[n];
this.m_table = new double[n];
this.m_pop = res = new PACOIndividual[this.m_populationSize];
for (i = res.length; (--i) >= 0;) {
res[i] = new PACOIndividual();
}
this.m_update.beginRun(f);
}
/** {@inheritDoc} */
@Override
public void endRun(final ObjectiveFunction f) {
this.__clearInstance();
try {
this.m_update.endRun(f);
} finally {
super.endRun(f);
}
}
}