genetic.lua 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. --Localized Lua libraries
  2. local newRand = math.random
  3. local tbinsert = table.insert
  4. return function (...)
  5. local config = {...}
  6. local g = {}
  7. -- configuration
  8. g.problemSize = config[1] or 64
  9. g.populationSize = config[2] or 64
  10. g.maxGenerations = config[3] or 50
  11. g.selectionTournamentSize = config[4] or 3
  12. g.mutationRate = config[5] or 0.005
  13. g.crossoverRate = config[6] or 0.98
  14. function g.crossover(a, b)
  15. if newRand() > g.crossoverRate then return a end
  16. local cut = newRand(a:len()-1)
  17. return a:sub(1,cut) .. b:sub(cut+1, -1)
  18. end
  19. function g.mutation(bitstring)
  20. local s,sp = {}, 1
  21. for c in string.gmatch(bitstring, ".") do
  22. if newRand() < g.mutationRate then
  23. if c == "0" then s[sp] = "1"
  24. else s[sp] = "0" end
  25. else
  26. s[sp] = c
  27. end
  28. sp = sp + 1
  29. end
  30. return table.concat(s)
  31. end
  32. function g.selection(population, fitnesses)
  33. local pop = {}
  34. repeat
  35. local bestString
  36. local bestFitness = 0
  37. for i=1, g.selectionTournamentSize do
  38. local selection = newRand(#fitnesses)
  39. if fitnesses[selection] > bestFitness then
  40. bestFitness = fitnesses[selection]
  41. bestString = population[selection]
  42. end
  43. end
  44. tbinsert(pop, bestString)
  45. until #pop == #population
  46. return pop
  47. end
  48. function g.reproduce(selected)
  49. local pop = {}
  50. for i=1, #selected do
  51. local p1 = selected[i]
  52. local p2
  53. if (i%2)==0 then p2=selected[i-1] else p2=selected[i+1] end
  54. local child = g.crossover(p1, p2)
  55. local mutantChild = g.mutation(child)
  56. tbinsert(pop, mutantChild);
  57. end
  58. return pop
  59. end
  60. function g.fitness(bitstring)
  61. local cost = 0
  62. for c in string.gmatch(bitstring, ".") do
  63. if c == "1" then cost = cost + 1 end
  64. end
  65. return cost
  66. end
  67. function g.random_bitstring(length)
  68. local s = {}
  69. for sp = 1, length do
  70. if newRand() < 0.5 then s[sp] = "0"
  71. else s[sp] = "1" end
  72. end
  73. return table.concat(s)
  74. end
  75. function g.getBest(currentBest, population, fitnesses)
  76. local bestScore = currentBest==nil and 0 or g.fitness(currentBest)
  77. local best = currentBest
  78. for i=1, #fitnesses do
  79. local f = fitnesses[i]
  80. if(f > bestScore) then
  81. bestScore = f
  82. best = population[i]
  83. end
  84. end
  85. return best
  86. end
  87. function g.evolve()
  88. local population = {}
  89. local bestString = nil
  90. -- initialize the popuation random pool
  91. for i=1, g.populationSize do
  92. tbinsert(population, g.random_bitstring(g.problemSize))
  93. end
  94. -- optimize the population (fixed duration)
  95. for i=1, g.maxGenerations do
  96. -- evaluate
  97. local fitnesses = {}
  98. for i=1, #population do
  99. local v = population[i]
  100. tbinsert(fitnesses, g.fitness(v))
  101. end
  102. -- update best
  103. bestString = g.getBest(bestString, population, fitnesses)
  104. -- select
  105. local tmpPop = g.selection(population, fitnesses)
  106. -- reproduce
  107. population = g.reproduce(tmpPop)
  108. --printf(">gen %d, best cost=%d [%s]\n", i, fitness(bestString), bestString)
  109. end
  110. return bestString
  111. end
  112. return g
  113. end
  114. -- run
  115. --printf("Genetic Algorithm on OneMax, with %s\n",_VERSION);
  116. --math.randomseed(os.time())
  117. --local best = evolve()
  118. --printf("Finished!\nBest solution found had the fitness of %d [%s].\n", fitness(best), best)