Advertisement
finalmail

Untitled

Nov 17th, 2019
148
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.93 KB | None | 0 0
  1. /* eslint-disable no-console */
  2. /* eslint-disable padding-line-between-statements */
  3. /* eslint-disable prettier/prettier */
  4. const generationSize = 100
  5.  
  6. const getRandomNumber = max => Math.round(Math.random() * Math.floor(max)) / 10
  7.  
  8. const getRandomInteger = max => Math.floor(Math.random() * (max + 1))
  9.  
  10. const generatePoints = N => {
  11. const points = []
  12. const currentPointsMap = {}
  13.  
  14. while (points.length < N) {
  15. const point = { x: getRandomNumber(20), y: getRandomNumber(20) }
  16. const stringifiedPoint = JSON.stringify(point)
  17.  
  18. if (!currentPointsMap[stringifiedPoint]) {
  19. currentPointsMap[stringifiedPoint] = true
  20. points.push(point)
  21. }
  22. }
  23.  
  24. return points
  25. }
  26.  
  27. const shuffle = a => {
  28. for (let i = a.length - 1; i > 0; i--) {
  29. const j = Math.floor(Math.random() * (i + 1))
  30. ;[a[i], a[j]] = [a[j], a[i]]
  31. }
  32. return a
  33. }
  34.  
  35. const generatePopulation = N => {
  36. const population = []
  37. for (let i = 0; i < generationSize; i++) {
  38. const chromosome = shuffle(Array.from({ length: N }, (_, ind) => ind))
  39. population.push(chromosome)
  40. }
  41. return population
  42. }
  43.  
  44. const getEuclideanDistance = (a, b) =>
  45. Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2)
  46.  
  47. const calcTotalDistance = points =>
  48. points.reduce((totalDistance, point, ind, arr) => {
  49. if (ind === 0) {
  50. return totalDistance
  51. }
  52.  
  53. const prevPoint = arr[ind - 1]
  54. const distanceToPrev = getEuclideanDistance(point, prevPoint)
  55.  
  56. return totalDistance + distanceToPrev
  57. }, 0)
  58.  
  59. const difference = (a, b) => b.filter(el => !a.includes(el))
  60.  
  61. // const select = (N, initialPopulation) => {
  62. // const sortedInitialPop = [...initialPopulation].sort(
  63. // (a, b) =>
  64. // calcTotalDistance(a.map(ind => points[ind])) -
  65. // calcTotalDistance(b.map(ind => points[ind]))
  66. // )
  67.  
  68. // return sortedInitialPop.slice(0, N)
  69. // }
  70.  
  71. const crossOver = (parent1, parent2) => {
  72. const length = parent1.length
  73. const [randomInd1, randomInd2] = [
  74. getRandomInteger(length - 1),
  75. getRandomInteger(length - 1)
  76. ]
  77. const i = Math.min(randomInd1, randomInd2)
  78. const j = Math.max(randomInd1, randomInd2)
  79. const p1substr = parent1.slice(i, j + 1)
  80. const p2substr = parent2.slice(i, j + 1)
  81.  
  82. let ch1 = new Array(length).fill(-1)
  83. let ch2 = new Array(length).fill(-1)
  84.  
  85. ch1 = ch1
  86. .slice(0, i)
  87. .concat(p1substr)
  88. .concat(ch1.slice(j + 1))
  89. ch2 = ch2
  90. .slice(0, i)
  91. .concat(p2substr)
  92. .concat(ch2.slice(j + 1))
  93.  
  94. const mapping = {}
  95. const diff = difference(p1substr, p2substr)
  96.  
  97. diff.forEach(missingFromP1 => {
  98. let ind = parent2.indexOf(missingFromP1)
  99. let currParent = 0
  100. const parents = [parent1, parent2]
  101.  
  102. while (ind === -1 || (i <= ind && ind <= j)) {
  103. const el = parents[currParent][ind]
  104. currParent = (currParent + 1) % 2
  105. ind = parents[currParent].indexOf(el)
  106. currParent = (currParent + 1) % 2
  107. }
  108.  
  109. mapping[missingFromP1] = parents[(currParent + 1) % 2][ind]
  110. })
  111.  
  112. Object.entries(mapping).forEach(entry => {
  113. const [fromP1, fromP2] = entry
  114. const fromP1ind = parent1.indexOf(Number(fromP1))
  115. const fromP2ind = parent2.indexOf(Number(fromP2))
  116.  
  117. ch1[fromP2ind] = Number(fromP1)
  118. ch2[fromP1ind] = Number(fromP2)
  119. })
  120.  
  121. ch1 = ch1.map((el, ind) => (el === -1 ? parent2[ind] : el))
  122. ch2 = ch2.map((el, ind) => (el === -1 ? parent1[ind] : el))
  123.  
  124. return [ch1, ch2]
  125. }
  126.  
  127. const mutateChromosome = chromosome => {
  128. const i = getRandomInteger(chromosome.length - 1)
  129. const j = getRandomInteger(chromosome.length - 1)
  130.  
  131. const temp = chromosome[i]
  132. chromosome[i] = chromosome[j]
  133. chromosome[j] = temp
  134.  
  135. return chromosome
  136. }
  137.  
  138. const getNextGeneration = currGen => {
  139. let children = []
  140.  
  141. const sortedCurrGen = [...currGen].sort(
  142. (a, b) =>
  143. calcTotalDistance(a.map(ind => points[ind])) -
  144. calcTotalDistance(b.map(ind => points[ind]))
  145. )
  146.  
  147. const best20percent = sortedCurrGen.slice(0, 20)
  148. const worst6percent = sortedCurrGen.slice(94)
  149.  
  150. children = children.concat(best20percent)
  151.  
  152. for (let i = 0; i < (currGen.length - 20 - 6) / 2; i++) {
  153. const [ch1, ch2] = crossOver(currGen[i], currGen[currGen.length - 1 - i])
  154. children.push(ch1)
  155. children.push(ch2)
  156. }
  157.  
  158. const mutatedWorst6percent = worst6percent.map(mutateChromosome)
  159.  
  160. children = children.concat(mutatedWorst6percent)
  161.  
  162. return children
  163. }
  164.  
  165. // main
  166. const N = 50
  167. const MAX_GENERATIONS = 300
  168. const points = generatePoints(N)
  169. const initialPopulation = generatePopulation(N)
  170.  
  171. let prevGeneration = initialPopulation
  172. for (let i = 0; i < MAX_GENERATIONS; i++) {
  173. const newGeneration = getNextGeneration(prevGeneration)
  174. if ([10, 35, 99, ~~(MAX_GENERATIONS / 2), MAX_GENERATIONS - 1].includes(i)) {
  175. const min = Math.min(
  176. ...newGeneration.map(chromosome =>
  177. calcTotalDistance(chromosome.map(ind => points[ind]))
  178. )
  179. )
  180. console.log("min", min)
  181. }
  182. prevGeneration = newGeneration
  183. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement