diff options
| author | sanine <sanine.not@pm.me> | 2025-01-01 10:11:34 -0600 | 
|---|---|---|
| committer | sanine <sanine.not@pm.me> | 2025-01-01 10:11:34 -0600 | 
| commit | 2a03fd9a56c82a711854ae82a7e596482ee8f67b (patch) | |
| tree | f5aef391c67ae8bd268d94764c10ee1d6c923682 /ga.lua | |
initial commit
Diffstat (limited to 'ga.lua')
| -rw-r--r-- | ga.lua | 93 | 
1 files changed, 93 insertions, 0 deletions
| @@ -0,0 +1,93 @@ +local module = {} +setmetatable(module, {__index=_G}) +setfenv(1, module) + + +local GA = {} +local metaGA = { __index=GA } + + +function module.createGA(population, operators) +  local self = {  +    population=population, +    operators=operators, +  } + +  local totalWeight =  +    (operators.crossWeight or 1) +  +    (operators.mutationWeight or 1) +  +    (operators.reproductionWeight or 1) + +  self.operators.crossDensity = (operators.crossWeight or 1) / totalWeight +  self.operators.mutationDensity = self.operators.crossDensity + ((operators.mutationWeight or 1) / totalWeight) +  self.operators.reproductionDensity = 1 + +  setmetatable(self, metaGA) +  return self +end + + +function GA.evaluate(self) +  self.fitnesses = {} +  for i, p in ipairs(self.population) do +    self.fitnesses[i] = self.operators.evaluate(p) +    if i == 1 or self.fitnesses[i] > self.maxFitness then +      self.maxFitness = self.fitnesses[i] +      self.bestMember = i +    end +  end +end + + +function GA.tournamentPick(self, k) +  local tournamentPop = {} +  while #tournamentPop < k do +    table.insert(tournamentPop, math.ceil(#self.population * math.random())) +  end +  table.sort(tournamentPop, function(a, b) return self.fitnesses[a] > self.fitnesses[b] end) +  return tournamentPop[1] +end + + +function GA.stochasticPick(self) +  local idx = math.ceil(#self.population * math.random()) +  local f = self.fitnesses[idx] / self.maxFitness +  if math.random() < f then +    return idx +  else +    return self:stochasticPick() +  end +end + + +function GA.createNewPopulation(self, k) +  k = k or 128 +  local newPop = {} +  while #newPop < #self.population do +    local r = math.random() +    if r < self.operators.crossDensity then +      local a = self:tournamentPick(k) +      local b = self:tournamentPick(k) +      table.insert(newPop, self.operators.crossover(self.population[a], self.population[b])) +    elseif r < self.operators.mutationDensity then +      local a = self:tournamentPick(k) +      table.insert(newPop, self.operators.mutate(self.population[a])) +    elseif r < self.operators.reproductionDensity then +      local a = self:tournamentPick(k) +      table.insert(newPop, self.population[a]) +    end +  end +  return newPop +end + + +function GA.step(self) +  self.fitnesses = nil +  self.maxFitness = nil +  self:evaluate() +  self.population = self:createNewPopulation() +  return self.maxFitness +end + + +return module | 
