PsoAlgorithm.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. package holeg.algorithm.binary;
  2. import holeg.api.AlgorithmFrameworkFlex;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.TreeSet;
  6. import java.util.stream.Collectors;
  7. import javax.swing.JFrame;
  8. public class PsoAlgorithm extends AlgorithmFrameworkFlex {
  9. //Parameter for Algo with default Values:
  10. private int swarmSize = 20;
  11. private int maxIterations = 100;
  12. private double dependency = 2.07;
  13. private int mutationIteration = 1;
  14. private boolean useIntervalMutation = true;
  15. private double mutationRate = 0.01;
  16. private double mutateProbabilityInterval = 0.01;
  17. private double maxMutationPercent = 0.01;
  18. private double c1, c2, w;
  19. private double maxVelocity = 4.0;
  20. private boolean moreInformation = false;
  21. public PsoAlgorithm() {
  22. super();
  23. addIntParameter("Particles", swarmSize, intValue -> swarmSize = intValue, () -> swarmSize, 1);
  24. addIntParameter("Iterations", maxIterations, intValue -> maxIterations = intValue,
  25. () -> maxIterations, 1);
  26. addDoubleParameter("Dependency", dependency, doubleValue -> dependency = doubleValue,
  27. () -> dependency, 2.001, 2.4);
  28. addIntParameter("Mutation iteration", mutationIteration,
  29. intValue -> mutationIteration = intValue, () -> mutationIteration, 0);
  30. addBooleanParameter("Interval-based mutation", useIntervalMutation,
  31. booleanValue -> useIntervalMutation = booleanValue);
  32. addDoubleParameter("Mutation probability (%)", mutateProbabilityInterval,
  33. doubleValue -> mutateProbabilityInterval = doubleValue, () -> mutateProbabilityInterval,
  34. 0.0, 1.0);
  35. // addDoubleParameter("mutationRate", mutationRate, doubleValue -> mutationRate = doubleValue, () -> mutationRate, 0.0, 1.0);
  36. addDoubleParameter("Mutation severity (% of problem size)", maxMutationPercent,
  37. doubleValue -> maxMutationPercent = doubleValue, () -> maxMutationPercent, 0.0, 1.0);
  38. addDoubleParameter("Velocity", maxVelocity, doubleValue -> maxVelocity = doubleValue,
  39. () -> maxVelocity, 0.0);
  40. addBooleanParameter("Detailed information", moreInformation,
  41. booleanValue -> moreInformation = booleanValue);
  42. }
  43. public static void main(String[] args) {
  44. JFrame newFrame = new JFrame("exampleWindow");
  45. PsoAlgorithm instance = new PsoAlgorithm();
  46. newFrame.setContentPane(instance.getPanel());
  47. newFrame.pack();
  48. newFrame.setVisible(true);
  49. newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  50. }
  51. @Override
  52. protected int getProgressBarMaxCount() {
  53. return swarmSize * (maxIterations + 1) * rounds + rounds;
  54. }
  55. /**
  56. * <p>Algo from Paper:</p><font size="3"><pre>
  57. *
  58. * Begin
  59. * t = 0; {t: generation index}
  60. * initialize particles x<sub>p,i,j</sub>(t);
  61. * evaluation x<sub>p,i,j</sub>(t);
  62. * while (termination condition &ne; true) do
  63. * v<sub>i,j</sub>(t) = update v<sub>i,j</sub>(t); {by Eq. (6)}
  64. * x<sub>g,i,j</sub>(t) = update x<sub>g,i,j</sub>(t); {by Eq. (7)}
  65. * x<sub>g,i,j</sub>(t) = mutation x<sub>g,i,j</sub>(t); {by Eq. (11)}
  66. * x<sub>p,i,j</sub>(t) = decode x<sub>g,i,j</sub>(t); {by Eqs. (8) and (9)}
  67. * evaluate x<sub>p,i,j</sub>(t);
  68. * t = t + 1;
  69. * end while
  70. * End</pre></font>
  71. * <p>with:</p><font size="3">
  72. * <p>
  73. * x<sub>g,i,j</sub>: genotype ->genetic information -> in continuous space<br> x<sub>p,i,j</sub>:
  74. * phenotype -> observable characteristics-> in binary space<br> X<sub>g,max</sub>: is the Maximum
  75. * here set to 4.<br> Eq. (6):v<sub>i,j</sub>(t + 1) = wv<sub>i,j</sub>+c<sub>1</sub>R<sub>1</sub>(P<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))+c<sub>2</sub>R<sub>2</sub>(g<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))<br>
  76. * Eq. (7):x<sub>g,i,j</sub>(t + 1) = x<sub>g,i,j</sub>(t) + v<sub>i,j</sub>(t + 1)<br> Eq.
  77. * (11):<b>if(</b>rand()&lt;r<sub>mu</sub><b>)then</b> x<sub>g,i,j</sub>(t + 1) =
  78. * -x<sub>g,i,j</sub>(t + 1)<br> Eq. (8):x<sub>p,i,j</sub>(t + 1) = <b>(</b>rand() &lt;
  79. * S(x<sub>g,i,j</sub>(t + 1))<b>) ?</b> 1 <b>:</b> 0<br> Eq. (9) Sigmoid:S(x<sub>g,i,j</sub>(t +
  80. * 1)) := 1/(1 + e<sup>-x<sub>g,i,j</sub>(t + 1)</sup>)<br></font>
  81. * <p>Parameter:</p>
  82. * w inertia, calculated from phi(Variable:{@link #dependency})<br> c1: influence, calculated from
  83. * phi(Variable:{@link #dependency}) <br> c2: influence, calculated from phi(Variable:{@link
  84. * #dependency})<br> r<sub>mu</sub>: probability that the proposed operation is conducted defined
  85. * by limit(Variable:{@link #})<br>
  86. */
  87. @Override
  88. protected Individual executeAlgo() {
  89. initDependentParameter();
  90. Individual globalBest = new Individual();
  91. globalBest.position = extractPositionAndAccess();
  92. globalBest.fitness = evaluatePosition(globalBest.position);
  93. console.println("Start Value:" + globalBest.fitness);
  94. int dimensions = globalBest.position.size();
  95. List<Particle> swarm = initializeParticles(dimensions);
  96. List<Double> runList = new ArrayList<Double>();
  97. runList.add(globalBest.fitness);
  98. evaluation(globalBest, swarm);
  99. runList.add(globalBest.fitness);
  100. for (int iteration = 0; iteration < maxIterations; iteration++) {
  101. int mutationAllowed = iteration % mutationIteration;
  102. double bitsFlipped = 0;
  103. for (int particleNumber = 0; particleNumber < swarmSize; particleNumber++) {
  104. Particle particle = swarm.get(particleNumber);
  105. if (this.useIntervalMutation) {
  106. boolean allowMutation = (Random.nextDouble() < this.mutateProbabilityInterval);
  107. TreeSet<Integer> mutationLocationSet = null;
  108. if (allowMutation) {
  109. mutationLocationSet = locationsToMutate(dimensions);
  110. }
  111. for (int index = 0; index < dimensions; index++) {
  112. updateVelocity(particle, index, globalBest);
  113. updateGenotype(particle, index);
  114. if (allowMutation && mutationAllowed == 0 && iteration != 0
  115. && mutationLocationSet.contains(index)) {
  116. mutation(particle, index);
  117. }
  118. decode(particle, index);
  119. }
  120. } else {
  121. int count = 0;
  122. for (int index = 0; index < dimensions; index++) {
  123. updateVelocity(particle, index, globalBest);
  124. updateGenotype(particle, index);
  125. if (mutationAllowed == 0 && iteration != 0
  126. && Random.nextDouble() < mutateProbabilityInterval) {
  127. count++;
  128. mutation(particle, index);
  129. }
  130. decode(particle, index);
  131. }
  132. bitsFlipped += count;
  133. }
  134. }
  135. if (moreInformation) {
  136. console.println("\t\t\t\t\t\tAvgBitsMutate: " + (bitsFlipped / (double) swarmSize));
  137. }
  138. if (cancel) {
  139. return null;
  140. }
  141. evaluation(globalBest, swarm);
  142. runList.add(globalBest.fitness);
  143. if (moreInformation) {
  144. console.println("------------------------");
  145. }
  146. }
  147. console.println(" End Value:" + globalBest.fitness);
  148. this.runList = runList;
  149. return globalBest;
  150. }
  151. /**
  152. * @param j maximum index of position in the particle
  153. * @return
  154. */
  155. private List<Particle> initializeParticles(int j) {
  156. List<Particle> swarm = new ArrayList<Particle>();
  157. //Create The Particle
  158. for (int particleNumber = 0; particleNumber < swarmSize; particleNumber++) {
  159. //Create a Random position
  160. List<Boolean> aRandomPosition = new ArrayList<Boolean>();
  161. for (int index = 0; index < j; index++) {
  162. aRandomPosition.add(Random.nextBoolean());
  163. }
  164. swarm.add(new Particle(aRandomPosition));
  165. }
  166. return swarm;
  167. }
  168. /**
  169. * Calculate w, c1, c2
  170. */
  171. private void initDependentParameter() {
  172. w = 1.0 / (dependency - 1 + Math.sqrt(dependency * dependency - 2 * dependency));
  173. c1 = c2 = dependency * w;
  174. }
  175. /**
  176. * Evaluate each particle and update the global Best position;
  177. *
  178. * @param globalBest
  179. * @param swarm
  180. */
  181. private void evaluation(Individual globalBest, List<Particle> swarm) {
  182. for (Particle p : swarm) {
  183. double localEvaluationValue = evaluatePosition(p.xPhenotype);
  184. if (moreInformation) {
  185. console.println("Fitness " + localEvaluationValue);
  186. }
  187. p.checkNewEvaluationValue(localEvaluationValue);
  188. if (localEvaluationValue < globalBest.fitness) {
  189. globalBest.fitness = localEvaluationValue;
  190. globalBest.position = p.localBest.position;
  191. }
  192. }
  193. }
  194. /**
  195. * Eq. (6):v<sub>i,j</sub>(t + 1) = wv<sub>i,j</sub>+c<sub>1</sub>R<sub>1</sub>(P<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))+c<sub>2</sub>R<sub>2</sub>(g<sub>best,i,j</sub>-x<sub>p,i,j</sub>(t))<br>
  196. *
  197. * @param particle
  198. * @param index
  199. * @param globalBest
  200. */
  201. private void updateVelocity(Particle particle, int index, Individual globalBest) {
  202. double r1 = Random.nextDouble();
  203. double r2 = Random.nextDouble();
  204. double posValue = particle.xPhenotype.get(index) ? 1.0 : 0.0;
  205. particle.velocity.set(index, clamp(w * particle.velocity.get(index) + c1 * r1 * (
  206. (particle.localBest.position.get(index) ? 1.0 : 0.0) - posValue) + c2 * r2 * (
  207. (globalBest.position.get(index) ? 1.0 : 0.0) - posValue)));
  208. }
  209. /**
  210. * Eq. (7):x<sub>g,i,j</sub>(t + 1) = x<sub>g,i,j</sub>(t) + v<sub>i,j</sub>(t + 1)<br>
  211. *
  212. * @param particle
  213. * @param index
  214. */
  215. private void updateGenotype(Particle particle, int index) {
  216. particle.xGenotype.set(index,
  217. clamp(particle.xGenotype.get(index) + particle.velocity.get(index)));
  218. }
  219. /**
  220. * Eq. (11):<b>if(</b>rand()&lt;r<sub>mu</sub><b>)then</b> x<sub>g,i,j</sub>(t + 1) =
  221. * -x<sub>g,i,j</sub>(t + 1)<br>
  222. *
  223. * @param particle
  224. * @param index
  225. */
  226. private void mutation(Particle particle, int index) {
  227. //if(Random.nextDouble() < limit)
  228. particle.xGenotype.set(index, -particle.xGenotype.get(index));
  229. }
  230. /**
  231. * Eq. (8):x<sub>p,i,j</sub>(t + 1) = <b>(</b>rand() &lt; S(x<sub>g,i,j</sub>(t + 1))<b>) ?</b> 1
  232. * <b>:</b> 0<br>
  233. *
  234. * @param particle
  235. * @param index
  236. */
  237. private void decode(Particle particle, int index) {
  238. particle.xPhenotype.set(index, Random.nextDouble() < Sigmoid(particle.xGenotype.get(index)));
  239. }
  240. /**
  241. * Eq. (9) Sigmoid:S(x<sub>g,i,j</sub>(t + 1)) := 1/(1 + e<sup>-x<sub>g,i,j</sub>(t +
  242. * 1)</sup>)<br></font>
  243. *
  244. * @param value
  245. * @return
  246. */
  247. private double Sigmoid(double value) {
  248. return 1.0 / (1.0 + Math.exp(-value));
  249. }
  250. /**
  251. * To clamp X<sub>g,j,i</sub> and v<sub>i,j</sub> in Range [-X<sub>g,max</sub>|+X<sub>g,max</sub>]
  252. * with {X<sub>g,max</sub>= 4}
  253. *
  254. * @param value
  255. * @return
  256. */
  257. private double clamp(double value) {
  258. return Math.max(-maxVelocity, Math.min(maxVelocity, value));
  259. }
  260. private TreeSet<Integer> locationsToMutate(int dimensions) {
  261. TreeSet<Integer> mutationLocation = new TreeSet<Integer>(); //sortedSet
  262. int maximumAmountOfMutatedBits = Math.max(1,
  263. (int) Math.round(((double) dimensions) * this.maxMutationPercent));
  264. int randomUniformAmountOfMutatedValues = Random.nextIntegerInRange(1,
  265. maximumAmountOfMutatedBits + 1);
  266. for (int i = 0; i < randomUniformAmountOfMutatedValues; i++) {
  267. boolean success = mutationLocation.add(Random.nextIntegerInRange(0, dimensions));
  268. if (!success) {
  269. i--; //can be add up to some series long loops if maximumAmountOfMutatedBits get closed to problemsize.
  270. }
  271. }
  272. return mutationLocation;
  273. }
  274. @Override
  275. protected String algoInformationToPrint() {
  276. // private int swarmSize = 20;
  277. // private int maxIterations = 100;
  278. // private double limit = 0.01;
  279. // private double dependency = 2.07;
  280. // private int mutationInterval = 1;
  281. // private boolean useIntervalMutation = true;
  282. // private double mutateProbabilityInterval = 0.01;
  283. // private double maxMutationPercent = 0.01;
  284. return "PsoAlgo" + " Rounds:" + rounds
  285. + " maxIterations:" + maxIterations
  286. + " swarmSize:" + swarmSize
  287. + " dependency:" + dependency
  288. + " mutationInterval:" + mutationIteration
  289. + " maxVelocity: " + maxVelocity
  290. + (useIntervalMutation ?
  291. (" mutateProbabilityInterval:" + mutateProbabilityInterval
  292. + " maxMutationPercent:" + maxMutationPercent) : " mutationRate:" + mutationRate);
  293. }
  294. @Override
  295. protected String plottFileName() {
  296. return "plottPsoAlgo.txt";
  297. }
  298. /**
  299. * Class to represent a Particle.
  300. */
  301. private class Particle {
  302. /**
  303. * The velocity of a particle.
  304. */
  305. public List<Double> velocity;
  306. /**
  307. * The positions genotype.
  308. */
  309. public List<Double> xGenotype;
  310. /**
  311. * The positions phenotype. Alias the current position.
  312. */
  313. public List<Boolean> xPhenotype;
  314. public Individual localBest;
  315. Particle(List<Boolean> position) {
  316. this.xPhenotype = position;
  317. //Init velocity, xGenotype with 0.0 values.
  318. this.velocity = position.stream().map(bool -> 0.0).collect(Collectors.toList());
  319. this.xGenotype = position.stream().map(bool -> 0.0).collect(Collectors.toList());
  320. localBest = new Individual();
  321. localBest.fitness = Double.MAX_VALUE;
  322. }
  323. public void checkNewEvaluationValue(double newEvaluationValue) {
  324. if (newEvaluationValue < localBest.fitness) {
  325. localBest.fitness = newEvaluationValue;
  326. localBest.position = xPhenotype.stream().map(bool -> bool).collect(Collectors.toList());
  327. }
  328. }
  329. public String toString() {
  330. return "Particle with xPhenotype(Position), xGenotype, velocity:["
  331. + listToString(xPhenotype) + "],[" + listToString(xGenotype) + "],["
  332. + listToString(velocity) + "]";
  333. }
  334. private <Type> String listToString(List<Type> list) {
  335. return list.stream().map(Object::toString).collect(Collectors.joining(", "));
  336. }
  337. }
  338. }