116 lines
2.7 KiB
Pony
116 lines
2.7 KiB
Pony
use "random"
|
|
use "collections"
|
|
|
|
class CreationFactory
|
|
let _desired: String
|
|
|
|
new create(d: String) =>
|
|
_desired = d
|
|
|
|
fun apply(c: String): Creation =>
|
|
Creation(c, _fitness(c))
|
|
|
|
fun _fitness(s: String): USize =>
|
|
var f = USize(0)
|
|
for i in Range(0, s.size()) do
|
|
try
|
|
if s(i)? == _desired(i)? then
|
|
f = f +1
|
|
end
|
|
end
|
|
end
|
|
f
|
|
|
|
class val Creation
|
|
let string: String
|
|
let fitness: USize
|
|
|
|
new val create(s: String = "", f: USize = 0) =>
|
|
string = s
|
|
fitness = f
|
|
|
|
class Mutator
|
|
embed _rand: MT = MT
|
|
let _possibilities: String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
|
|
let _cf: CreationFactory
|
|
|
|
new create(cf: CreationFactory) =>
|
|
_cf = cf
|
|
|
|
fun ref apply(parent: Creation, rate: F64): Creation =>
|
|
let ns = _new_string(parent.string, rate)
|
|
_cf(ns)
|
|
|
|
fun ref _new_string(parent: String, rate: F64): String =>
|
|
var mutated = recover String(parent.size()) end
|
|
for char in parent.values() do
|
|
mutated.push(_mutate_letter(char, rate))
|
|
end
|
|
consume mutated
|
|
|
|
fun ref _mutate_letter(current: U8, rate: F64): U8 =>
|
|
if _rand.real() <= rate then
|
|
_random_letter()
|
|
else
|
|
current
|
|
end
|
|
|
|
fun ref _random_letter(): U8 =>
|
|
let ln = _rand.int(_possibilities.size().u64()).usize()
|
|
try _possibilities(ln)? else ' ' end
|
|
|
|
class Generation
|
|
let _size: USize
|
|
let _desired: Creation
|
|
let _mutator: Mutator
|
|
|
|
new create(size: USize = 100, desired: Creation, mutator: Mutator) =>
|
|
_size = size
|
|
_desired = desired
|
|
_mutator = consume mutator
|
|
|
|
fun ref apply(parent: Creation): Creation =>
|
|
var best = parent
|
|
let mutation_rate = _mutation_rate(best)
|
|
for i in Range(0, _size) do
|
|
let candidate = _mutator(best, mutation_rate)
|
|
if candidate.fitness > best.fitness then
|
|
best = candidate
|
|
end
|
|
end
|
|
best
|
|
|
|
fun _mutation_rate(best: Creation): F64 =>
|
|
let min_mutate_rate: F64 = 0.09
|
|
|
|
let df = _desired.fitness.f64()
|
|
let bf = best.fitness.f64()
|
|
|
|
((df - bf) / df) * (1.0 - min_mutate_rate)
|
|
|
|
actor Main
|
|
new create(env: Env) =>
|
|
let d = "METHINKS IT IS LIKE A WEASEL"
|
|
let cf = CreationFactory(d)
|
|
let desired = cf(d)
|
|
let mutator = Mutator(cf)
|
|
let start = mutator(desired, 1.0)
|
|
let spawn_per_generation = USize(100)
|
|
|
|
var iterations = U64(0)
|
|
var best = start
|
|
|
|
repeat
|
|
best = Generation(spawn_per_generation, desired, mutator)(best)
|
|
|
|
iterations = iterations + 1
|
|
if (iterations % 100) == 0 then
|
|
env.out.print(
|
|
iterations.string() + ": "
|
|
+ best.string + ", fitness: " + best.fitness.string()
|
|
)
|
|
end
|
|
until best.string == desired.string end
|
|
|
|
env.out.print(best.string + ", " + iterations.string())
|