///- --package .
search (test)
test search: prelude
///- --test static --symbol
:< testing
:== genome = { first : i32; second : i32; third : i32 }
:= clamp_between (low : i32) (high : i32) (x : i32) : i32 =
? x < low ?> low |? x > high ?> high |: x
:< keyed_rng
:| search_roll =
| GeneNudge : u32
:+ purpose_code search_roll =
\ r =>
?= r ?|
| GeneNudge gene => 100u32 + gene
:= nudge_key (s : u32) (generation : i32) (child : i32) (gene : u32) : keyed_rng::roll_key search_roll =
:= t = keyed_rng::tick (conv generation)
keyed_rng::roll_key (keyed_rng::seed s) t (keyed_rng::entity (conv child)) (GeneNudge gene)
:= nudge (seed : u32) (generation : i32) (child : i32) (gene : u32) (spread : i32) (value : i32) : i32 =
:= draw : i32 = conv (keyed_rng::roll_between 0 (conv (2 * spread)) (nudge_key seed generation child gene))
value + draw - spread
:== gene_draw = { seed : u32; generation : i32; child : i32; spread : i32 }
:= drawn (d : gene_draw) (gene : u32) (low : i32) (high : i32) (value : i32) : i32 =
clamp_between low high (nudge d::seed d::generation d::child gene d::spread value)
:= mutate (d : gene_draw) (lo : genome) (hi : genome) (g : genome) : genome =
{
first = drawn d 1u32 lo::first hi::first g::first
second = drawn d 2u32 lo::second hi::second g::second
third = drawn d 3u32 lo::third hi::third g::third
}
:== genome_search = { low : genome; high : genome; seed : u32; offspring : i32; generations : i32; spread : i32 }
:== scored_genome = { g : genome; score : i32 }
:== genome_round = { s : genome_search; index : i32; width : i32; parent : scored_genome }
:= genome_child (r : genome_round) (child : i32) : genome =
mutate
{ seed = r::s::seed; generation = r::index; child = child; spread = r::width }
r::s::low
r::s::high
r::parent::g
:= fitter_genome (fitness : genome -> i32) (candidate : genome) (best : scored_genome) : scored_genome =
:= score = fitness candidate
? score > best::score ?> { g = candidate; score = score } |: best
:~ ^ offspring_from (fitness : genome -> i32) (r : genome_round) (child : i32) (best : scored_genome) : scored_genome =
? child >= r::s::offspring ?> best
|: offspring_from fitness r (child + 1) (fitter_genome fitness (genome_child r child) best)
:= next_genome_round (r : genome_round) (best : scored_genome) : genome_round =
{ r ?| index = r::index + 1; width = (? r::width > 1 ?> r::width / 2 |: 1); parent = best }
:~ ^ genome_climb (fitness : genome -> i32) (r : genome_round) : genome =
? r::index >= r::s::generations ?> r::parent::g
|: genome_climb fitness (next_genome_round r (offspring_from fitness r 0 r::parent))
:= evolve (fitness : genome -> i32) (s : genome_search) (start : genome) : genome =
genome_climb fitness { s = s; index = 0; width = s::spread; parent = { g = start; score = fitness start } }
:! vector = array i32
:= vector_of (count : i32) (value : i32) : vector =
:= x : array i32 = create count
:~ ^ fill (i : i32) : () =
? i < count ?>
set x i value
fill (i + 1)
fill 0
vector x
:= gene (vector v) (i : i32) : i32 = index v i
:= gene_count (vector v) : i32 = length v
:= with_gene (i : i32) (value : i32) (vector v) : vector =
set v i value
vector v
:== vector_search = { low : vector; high : vector; seed : u32; pairs : i32; generations : i32 }
:== scored_vector = { v : vector; score : i32 }
:== vector_round = { s : vector_search; index : i32; width : i32; parent : scored_vector }
:= pair_delta (r : vector_round) (pair : i32) (i : i32) : i32 =
:= range = gene r::s::high i - gene r::s::low i
:= spread = ? range * r::width / 1000 < 1 ?> 1 |: range * r::width / 1000
nudge r::s::seed r::index pair (conv i) spread 0
:= pair_genes (r : vector_round) (i : i32) (delta : i32) : i32 * i32 =
:= low, high, mid = gene r::s::low i, gene r::s::high i, gene r::parent::v i
clamp_between low high (mid + delta), clamp_between low high (mid - delta)
:= set_genes (i : i32) (up : i32) (down : i32) (plus : vector) (minus : vector) : () =
with_gene i up plus |> ignore
with_gene i down minus |> ignore
:~ ^ fill_pair (r : vector_round) (pair : i32) (plus : vector) (minus : vector) (i : i32) : () =
? i < gene_count plus ?>
:= up, down = pair_genes r i (pair_delta r pair i)
set_genes i up down plus minus
fill_pair r pair plus minus (i + 1)
:= antithetic_pair (r : vector_round) (pair : i32) : vector * vector =
:= n = gene_count r::parent::v
:= plus, minus = vector_of n 0, vector_of n 0
fill_pair r pair plus minus 0
plus, minus
:= stronger_vector (fitness : vector -> i32) (candidate : vector) (best : scored_vector) : scored_vector =
:= score = fitness candidate
? score > best::score ?> { v = candidate; score = score } |: best
:= pair_winner (fitness : vector -> i32) (r : vector_round) (pair : i32) (best : scored_vector) : scored_vector =
:= plus, minus = antithetic_pair r pair
stronger_vector fitness minus (stronger_vector fitness plus best)
:~ ^ pairs_from (fitness : vector -> i32) (r : vector_round) (pair : i32) (best : scored_vector) : scored_vector =
? pair >= r::s::pairs ?> best |: pairs_from fitness r (pair + 1) (pair_winner fitness r pair best)
:= next_vector_round (r : vector_round) (best : scored_vector) : vector_round =
{ r ?| index = r::index + 1; width = (? r::width * 4 / 5 > 10 ?> r::width * 4 / 5 |: 10); parent = best }
:~ ^ vector_climb (fitness : vector -> i32) (r : vector_round) : vector =
? r::index >= r::s::generations ?> r::parent::v
|: vector_climb fitness (next_vector_round r (pairs_from fitness r 0 r::parent))
:= evolve_vector (fitness : vector -> i32) (s : vector_search) (start : vector) : vector =
vector_climb fitness { s = s; index = 0; width = 250; parent = { v = start; score = fitness start } }
:= rescored (score : vector -> i32) (p : scored_vector) : scored_vector = { v = p::v; score = score p::v }
:~ ^ resampled_climb (fitness : i32 -> vector -> i32) (r : vector_round) : vector =
:= score = fitness r::index
? r::index >= r::s::generations ?> r::parent::v
|: resampled_climb fitness (next_vector_round r (pairs_from score r 0 (rescored score r::parent)))
:= evolve_vector_resampled (fitness : i32 -> vector -> i32) (s : vector_search) (start : vector) : vector =
resampled_climb fitness { s = s; index = 0; width = 250; parent = { v = start; score = 0 } }
:= peak_genome (g : genome) : i32 =
0 - (g::first - 40) * (g::first - 40) - (g::second - 7) * (g::second - 7) - (g::third + 5) * (g::third + 5)
:= peak_search (seed : u32) : genome_search =
:= low = { first = 0; second = -20; third = -20 }
:= high = { first = 100; second = 20; third = 20 }
{ low = low; high = high; seed = seed; offspring = 16; generations = 12; spread = 32 }
:= origin () : genome = { first = 0; second = 0; third = 0 }
evolve_climbs_a_known_peak (test)
test evolve_climbs_a_known_peak: passed
///- --test --symbol
///> c
:= ~seed = 3u32
:= best = evolve peak_genome (peak_search seed) (origin ())
(peak_genome best > peak_genome (origin ()), peak_genome best >= -12) |> _assert_eq (!+, !+)
__assert_eq { expected = (true, true) }
:= vector_peak_gene (i : i32) : i32 = ? i = 0 ?> 40 |? i = 1 ?> -7 |? i = 2 ?> 3 |: 90
:= squared_miss (v : vector) (i : i32) : i32 =
:= miss = gene v i - vector_peak_gene i
miss * miss
:~ ^ vector_loss (v : vector) (i : i32) (acc : i32) : i32 =
? i >= 4 ?> acc |: vector_loss v (i + 1) (acc - squared_miss v i)
:= vector_peak (v : vector) : i32 = vector_loss v 0 0
:= vector_peak_search (seed : u32) : vector_search =
{ low = vector_of 4 -100; high = vector_of 4 100; seed = seed; pairs = 8; generations = 20 }
evolve_vector_climbs_a_known_peak_with_antithetic_pairs (test)
test evolve_vector_climbs_a_known_peak_with_antithetic_pairs: passed
///- --test --symbol
///> c
:= ~seed = 3u32
:= best = evolve_vector vector_peak (vector_peak_search seed) (vector_of 4 0)
(vector_peak best > vector_peak (vector_of 4 0), vector_peak best >= -40) |> _assert_eq (!+, !+)
__assert_eq { expected = (true, true) }