PageRenderTime 25ms CodeModel.GetById 37ms RepoModel.GetById 0ms app.codeStats 0ms

/vol2/vol2-csharp-examples/AIFH-Vol2-Core/Core/ACO/DiscreteACO.cs

https://gitlab.com/alvinahmadov2/aifh
C# | 363 lines | 195 code | 40 blank | 128 comment | 20 complexity | 1d982e551107a6597a17385297d4717c MD5 | raw file
  1. // Artificial Intelligence for Humans
  2. // Volume 2: Nature-Inspired Algorithms
  3. // C# Version
  4. // http://www.aifh.org
  5. // http://www.jeffheaton.com
  6. //
  7. // Code repository:
  8. // https://github.com/jeffheaton/aifh
  9. //
  10. // Copyright 2014 by Jeff Heaton
  11. //
  12. // Licensed under the Apache License, Version 2.0 (the "License");
  13. // you may not use this file except in compliance with the License.
  14. // You may obtain a copy of the License at
  15. //
  16. // http://www.apache.org/licenses/LICENSE-2.0
  17. //
  18. // Unless required by applicable law or agreed to in writing, software
  19. // distributed under the License is distributed on an "AS IS" BASIS,
  20. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. // See the License for the specific language governing permissions and
  22. // limitations under the License.
  23. //
  24. // For more information on Heaton Research copyrights, licenses
  25. // and trademarks visit:
  26. // http://www.heatonresearch.com/copyright
  27. //
  28. using AIFH_Vol2.Core.Randomize;
  29. using System;
  30. using System.Collections.Generic;
  31. using System.Linq;
  32. using System.Text;
  33. using System.Threading.Tasks;
  34. namespace AIFH_Vol2.Core.ACO
  35. {
  36. /// <summary>
  37. /// The ant colony optimization (ACO) algorithm finds an optimal path through a graph. It works by establishing
  38. /// pheromone trails between the graph nodes. The pheromone trails increase in strength as ants travel over the
  39. /// edges of the graph. The pheromone trails decrease over time. The discrete version of ACO arranges a path
  40. /// to visit the nodes of a graph, that minimizes cost.
  41. ///
  42. /// References:
  43. ///
  44. /// http://en.wikipedia.org/wiki/Ant_colony_optimization_algorithms
  45. ///
  46. /// M. Dorigo, Optimization, Learning and Natural Algorithms, PhD thesis, Politecnico di Milano, Italy, 1992.
  47. /// </summary>
  48. public class DiscreteACO
  49. {
  50. /// <summary>
  51. /// The pheromone trails between graph segments.
  52. /// </summary>
  53. private readonly double[][] _pheromone;
  54. /// <summary>
  55. /// A graph of costs.
  56. /// </summary>
  57. private readonly ICostGraph _graph;
  58. /// <summary>
  59. /// The ants.
  60. /// </summary>
  61. private readonly IList<DiscreteAnt> _ants = new List<DiscreteAnt>();
  62. /// <summary>
  63. /// The initial value of the pheromone trails.
  64. /// </summary>
  65. public const double INITIAL_PHEROMONE = 1.0;
  66. /// <summary>
  67. /// Constant that defines the attractiveness of the pheromone trail.
  68. /// </summary>
  69. public double Alpha { get; set; }
  70. /// <summary>
  71. /// Constant that defines the attractiveness of better state transitions (from one node to another).
  72. /// </summary>
  73. public double Beta { get; set; }
  74. /// <summary>
  75. /// Constant that defines how quickly the pheromone path evaporates.
  76. /// </summary>
  77. public double Evaporation { get; set; }
  78. /// <summary>
  79. /// The amount of pheromone that the nodes of a path share for a trip.
  80. /// </summary>
  81. public double Q { get; set; }
  82. /// <summary>
  83. /// The base probability.
  84. /// </summary>
  85. public double PR { get; set; }
  86. /// <summary>
  87. /// A random number generator.
  88. /// </summary>
  89. public IGenerateRandom Random { get; set; }
  90. /// <summary>
  91. /// The current best path.
  92. /// </summary>
  93. private readonly int[] _bestPath;
  94. /// <summary>
  95. /// The cost of the best path. We are trying to minimize this.
  96. /// </summary>
  97. private double _bestCost;
  98. /// <summary>
  99. /// The constructor.
  100. /// </summary>
  101. /// <param name="theGraph">The graph that we are seeking a minimal path through.</param>
  102. /// <param name="theAntCount">The number of ants to use.</param>
  103. public DiscreteACO(ICostGraph theGraph, int theAntCount)
  104. {
  105. Alpha = 1;
  106. Beta = 5;
  107. Evaporation = 0.5;
  108. Q = 500;
  109. PR = 0.01;
  110. Random = new MersenneTwisterGenerateRandom();
  111. int len = theGraph.Count;
  112. _graph = theGraph;
  113. _pheromone = new double[len][];
  114. _bestPath = new int[len];
  115. _bestCost = double.PositiveInfinity;
  116. for (int i = 0; i < len; i++)
  117. {
  118. _pheromone[i] = new double[len];
  119. for (int j = 0; j < len; j++)
  120. {
  121. _pheromone[i][j] = INITIAL_PHEROMONE;
  122. }
  123. }
  124. for (int i = 0; i < theAntCount; i++)
  125. {
  126. _ants.Add(new DiscreteAnt(len));
  127. }
  128. }
  129. /// <summary>
  130. /// Calculate the probability of a given ant moving to any of the next nodes.
  131. /// </summary>
  132. /// <param name="currentIndex">The index into the path.</param>
  133. /// <param name="ant">The ant.</param>
  134. /// <returns>The probability of moving to the next node.</returns>
  135. private double[] CalculateProbability(int currentIndex, DiscreteAnt ant)
  136. {
  137. double[] result = new double[_graph.Count];
  138. int i = ant.Path[currentIndex - 1];
  139. double d = 0.0;
  140. for (int l = 0; l < _graph.Count; l++)
  141. if (!ant.WasVisited(l))
  142. d += Math.Pow(_pheromone[i][l], Alpha)
  143. * Math.Pow(1.0 / _graph.Cost(i, l), Beta);
  144. for (int j = 0; j < _graph.Count; j++)
  145. {
  146. if (ant.WasVisited(j))
  147. {
  148. result[j] = 0.0;
  149. }
  150. else
  151. {
  152. double n = Math.Pow(_pheromone[i][j], Alpha)
  153. * Math.Pow(1.0 / _graph.Cost(i, j), Beta);
  154. result[j] = n / d;
  155. }
  156. }
  157. return result;
  158. }
  159. /// <summary>
  160. /// Choose the next node for an ant to visit. This is based on probability.
  161. /// </summary>
  162. /// <param name="currentIndex">The step we are at in the path.</param>
  163. /// <param name="ant">The ant being evaluated.</param>
  164. /// <returns>The node we will move into.</returns>
  165. private int PickNextNode(int currentIndex, DiscreteAnt ant)
  166. {
  167. if (currentIndex == 0 || Random.NextDouble() < PR)
  168. {
  169. int index;
  170. do
  171. {
  172. index = Random.NextInt(0, _graph.Count);
  173. } while (ant.WasVisited(index));
  174. return index;
  175. }
  176. double[] prob = CalculateProbability(currentIndex, ant);
  177. double r = Random.NextDouble();
  178. double sum = 0;
  179. for (int i = 0; i < _graph.Count; i++)
  180. {
  181. sum += prob[i];
  182. if (sum >= r)
  183. return i;
  184. }
  185. // should not happen!
  186. return -1;
  187. }
  188. /// <summary>
  189. /// Update the pheromone levels both for ants traveling and evaporation.
  190. /// </summary>
  191. private void UpdatePheromone()
  192. {
  193. // Cause evaporation.
  194. for (int i = 0; i < _pheromone.Length; i++)
  195. for (int j = 0; j < _pheromone[i].Length; j++)
  196. _pheromone[i][j] *= Evaporation;
  197. // Adjust for ants.
  198. foreach (DiscreteAnt a in _ants)
  199. {
  200. double d = Q / a.CalculateCost(_graph.Count, _graph);
  201. for (int i = 0; i < _graph.Count - 1; i++)
  202. {
  203. _pheromone[a.Path[i]][a.Path[i + 1]] += d;
  204. }
  205. _pheromone[a.Path[_graph.Count - 1]][a.Path[0]] += d;
  206. }
  207. }
  208. /// <summary>
  209. /// Move the ants forward on their path.
  210. /// </summary>
  211. private void March()
  212. {
  213. for (int currentIndex = 0; currentIndex < _graph.Count; currentIndex++)
  214. {
  215. foreach (DiscreteAnt a in _ants)
  216. {
  217. int next = PickNextNode(currentIndex, a);
  218. a.Visit(currentIndex, next);
  219. }
  220. }
  221. }
  222. /// <summary>
  223. /// Reset the ants.
  224. /// </summary>
  225. private void SetupAnts()
  226. {
  227. foreach (DiscreteAnt a in _ants)
  228. {
  229. a.Clear();
  230. }
  231. }
  232. /// <summary>
  233. /// Update the best path.
  234. /// </summary>
  235. private void UpdateBest()
  236. {
  237. int[] bestPathFound = null;
  238. foreach (DiscreteAnt a in _ants)
  239. {
  240. double cost = a.CalculateCost(_graph.Count, _graph);
  241. if (cost < _bestCost)
  242. {
  243. bestPathFound = a.Path;
  244. _bestCost = cost;
  245. }
  246. }
  247. if (bestPathFound != null)
  248. {
  249. Array.Copy(bestPathFound, _bestPath, _bestPath.Length);
  250. }
  251. }
  252. /// <summary>
  253. /// Perform one iteration.
  254. /// </summary>
  255. public void Iteration()
  256. {
  257. SetupAnts();
  258. March();
  259. UpdatePheromone();
  260. UpdateBest();
  261. }
  262. /// <summary>
  263. /// The best tour/path.
  264. /// </summary>
  265. public int[] BestTour
  266. {
  267. get
  268. {
  269. return _bestPath;
  270. }
  271. }
  272. /// <summary>
  273. /// The best cost.
  274. /// </summary>
  275. public double BestCost
  276. {
  277. get
  278. {
  279. return _bestCost;
  280. }
  281. }
  282. /// <summary>
  283. /// The pheromone levels.
  284. /// </summary>
  285. public double[][] Pheromone
  286. {
  287. get
  288. {
  289. return _pheromone;
  290. }
  291. }
  292. /// <summary>
  293. /// The cost graph.
  294. /// </summary>
  295. public ICostGraph Graph
  296. {
  297. get
  298. {
  299. return _graph;
  300. }
  301. }
  302. /// <summary>
  303. /// The ants.
  304. /// </summary>
  305. public IList<DiscreteAnt> Ants
  306. {
  307. get
  308. {
  309. return _ants;
  310. }
  311. }
  312. /// <summary>
  313. /// The best path.
  314. /// </summary>
  315. public int[] BestPath
  316. {
  317. get
  318. {
  319. return _bestPath;
  320. }
  321. }
  322. }
  323. }