diff options
Diffstat (limited to 'contrib/lua-torch/optim/de.lua')
-rw-r--r-- | contrib/lua-torch/optim/de.lua | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/contrib/lua-torch/optim/de.lua b/contrib/lua-torch/optim/de.lua new file mode 100644 index 000000000..1e8e8001d --- /dev/null +++ b/contrib/lua-torch/optim/de.lua @@ -0,0 +1,109 @@ +--[[ An implementation of `DE` (Differential Evolution), + +ARGS: + + -`opfunc` : a function that takes a single input (X), the point of + evaluation, and returns f(X) and df/dX. Note that df/dX is not used + -`x` : the initial point + -`state.popsize`: population size. If this is left empty, 10*d will be used + -`state.scaleFactor`: float, usually between 0.4 and 1 + -`state.crossoverRate`: float, usually between 0.1 and 0.9 + -`state.maxEval`: int, maximal number of function evaluations + +RETURN: + - `x*` : the new `x` vector, at the optimal point + - `f` : a table of all function values: + `f[1]` is the value of the function before any optimization and + `f[#f]` is the final fully optimized value, at `x*` +]] + +require 'torch' + +function optim.de(opfunc, x, config, state) + -- process input parameters + local config = config or {} + local state = state + local popsize = config.popsize -- population size + local scaleFactor = config.scaleFactor -- scale factor + local crossoverRate = config.crossoverRate -- crossover rate + local maxFEs = tonumber(config.maxFEs) -- maximal number of function evaluations + local maxRegion = config.maxRegion -- upper bound of search region + local minRegion = config.minRegion -- lower bound of search region + local xmean = x:clone():view(-1) -- distribution mean, a flattened copy + local D = xmean:size(1) -- number of objective variables/problem dimension + + if config.popsize == nil then + popsize = 10 * D + end + if config.maxRegion == nil then + maxRegion = 30 + end + if config.minRegion == nil then + minRegion = -30 + end + + -- Initialize population + local fx = x.new(maxFEs) + local pop = x.new(popsize, D) + local children = x.new(popsize, D) + local fitness = x.new(popsize) + local children_fitness = x.new(popsize) + local fes = 1 -- number of function evaluations + local best_fitness + local best_solution = x.new(D) + + -- Initialize population and evaluate the its fitness value + local gen = torch.Generator() + torch.manualSeed(gen, 1) + + pop:uniform(gen, minRegion, maxRegion) + for i = 1, popsize do + fitness[i] = opfunc(pop[i]) + fx[fes] = fitness[i] + fes = fes + 1 + end + + -- Find the best solution + local index + best_fitness, index = fitness:max(1) + best_fitness = best_fitness[1] + index = index[1] + best_solution:copy(pop[index]) + + -- Main loop + while fes < maxFEs do + local r1, r2 + for i = 1, popsize do + repeat + r1 = torch.random(gen, 1, popsize) + until(r1 ~= i) + repeat + r2 = torch.random(gen, 1, popsize) + until(r2 ~= r1 and r2 ~= i) + + local jrand = torch.random(gen, 1, D) + for j = 1, D do + if torch.uniform(gen, 0, 1) < crossoverRate or i == jrand then + children[i][j] = best_solution[j] + scaleFactor * (pop[r1][j] - pop[r2][j]) + else + children[i][j] = pop[i][j] + end + end + children_fitness[i] = opfunc(children[i]) + fx[fes] = children_fitness[i] + fes = fes + 1 + end + + for i = 1, popsize do + if children_fitness[i] <= fitness[i] then + pop[i]:copy(children[i]) + fitness[i] = children_fitness[i] + if fitness[i] < best_fitness then + best_fitness = fitness[i] + best_solution:copy(children[i]) + end + end + end + end + return best_solution, fx +end |