Skip to content

Instantly share code, notes, and snippets.

@def-
Created April 29, 2018 17:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save def-/4e4dea8f0f40ef7a77a2729148d8fe0e to your computer and use it in GitHub Desktop.
Save def-/4e4dea8f0f40ef7a77a2729148d8fe0e to your computer and use it in GitHub Desktop.
import math
const
params = 2'i32
print = 10000'i32
generations = 100000'i32
popsize = 100
mutate = 0.5
bound_from = 0.0
bound_to = 100.0
# Optimization problems
proc booth(x: array[params, float]): float =
# (1.0, 3.0) = 0
let t1 = pow(x[0] + 2*x[1] - 7.0, 2.0)
let t2 = pow(2*x[0] + x[1] - 5.0, 2.0)
t1 + t2
const optimizer = booth
# Helpers
proc min_index(x: array[popsize, float]): int32 =
var smallest = float.high
for i in 0..<x.len:
if x[i] < smallest:
smallest = x[i]
result = int32(i)
# Biased fast random
var
x: uint32 = 123456789
y: uint32 = 362436069
z: uint32 = 521288629
w: uint32 = 88675123
proc xor128(): uint32 =
var t: uint32
t = x xor (x shl 11)
x = y
y = z
z = w
w = w xor (w shr 19) xor t xor (t shr 8)
return w
proc f_rand(min, max: float): float =
# A biased random!
let r = float(xor128())
# pow(2, 32) - 1 == 4294967295
let rr = r / 4294967295.0
let rrr = rr * (max - min) + min
return rrr
proc i_rand(min, max: uint32): int32 =
# A biased random
result = int32((xor128() + min) mod max)
proc main =
var crossover = 0.9
var scores: array[popsize, float]
var others: array[3, int]
var donor: array[params, float]
var trial: array[params, float]
let scoresLen = scores.len().toFloat
# Init population
var pop: array[popsize, array[params, float]]
for i in 0..<popsize:
for j in 0..<params:
pop[i][j] = f_rand(boundFrom, boundTo)
scores[i] = optimizer(pop[i])
# For each generation
for g in 0..<generations:
crossover = f_rand(0.5, 1.0)
for i in 0..<popsize:
# Get three others
for j in 0..<3:
var idx = i_rand(0, popsize)
while idx == i:
idx = i_rand(0, popsize)
others[j] = idx
let x0 = pop[others[0]]
let x1 = pop[others[1]]
let x2 = pop[others[2]]
let xt = pop[i]
# Create donor
for j in 0..<params:
donor[j] = x0[j] + (x1[j] - x2[j]) * mutate
# Todo: EnsureBounds
# Create trial
for j in 0..<params:
if f_rand(0, 1.0) < crossover:
trial[j] = donor[j]
else:
trial[j] = xt[j]
# Greedy pick best
let score_trial = optimizer(trial)
let score_target = scores[i]
if score_trial < score_target:
for j in 0..<params:
pop[i][j] = trial[j]
scores[i] = score_trial
if g mod print == 0:
let mean = scores.sum() / scoresLen
echo "generation mean ", mean
echo "generation ", g
let best_idx = scores.min_index()
echo "best ", pop[best_idx]
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment