1 # Unsga3Algorithm.Run — C# Unsga3.Algorithm.Unsga3Algorithm. 2 # init → evaluate → loop: tournament parents → SBX (η=30, p=1.0) → 3 # polynomial mutation (η=20, p=1/n) → evaluate → survival Select 4 # with persistent Normalization. Defaults match C# operator defaults. 5 # Mating tournament for A/B is PymooCompatible. RankNicheDistance (C# 6 # ctor default) is rank → niche count → perpendicular distance → coin. 7 # Survival niching in Run threads rng (C# Select(..., rng): random among 8 # equal min-count niches). Empty niches 9 # take closest; extras are random among near-best on that ray. Uniform 10 # inNiche[Next] with this LCG collapsed oracle ZDT2. 11 # Duplicate keys round each decision variable to 12 decimal places 12 # (round(x*1e12)/1e12). That is not C# ToString("G12") (12 significant 13 # digits). Small variables diverge; see src/g12_key.bend. 14 # The seen set is the survivor population, then accepted offspring 15 # (C# CreateOffspring hashes population.Members). After pop*40 pair 16 # attempts, up to max(pop*20, 1) mutations must still be a new key; 17 # only then are duplicates accepted. 18 # Odd N: the last parent enters SBX, paired with parent 0. Even N 19 # pair lookups stay the monotonic cursor (reset to pair 0 once the 20 # cursor passes the last in-range start). 21 22 import Base 23 import ./individual.bend as Ind 24 import ./non_dominated_sort.bend as NDS 25 import ./normalization.bend as Norm 26 import ./reference_directions.bend as Refs 27 import ./survival.bend as Surv 28 import ./bounds.bend as Bounds 29 import ./rng.bend as Rng 30 import ./sbx.bend as Sbx 31 import ./polynomial_mutation.bend as Poly 32 import ./problems.bend as Prob 33 import ./tournament.bend as Tour 34 import ./util.bend as Util 35 36 type Config is Data: 37 MkConfig{ 38 dirs: List<&2, List<&2, F32>> 39 pop_size: Nat 40 gens: Nat 41 seed: Nat 42 mode: Tour.Mode 43 elim_dups: Bool 44 } 45 46 def mk(+dirs: List<&2, List<&2, F32>>, +pop_size: Nat, +gens: Nat, +seed: Nat, +mode: Tour.Mode, +elim_dups: Bool) -> Config: 47 MkConfig{dirs, pop_size, gens, seed, mode, elim_dups} 48 49 def cfg_dirs(c: Config) -> List<&2, List<&2, F32>>: 50 match c: 51 case MkConfig{dirs, pop_size, gens, seed, mode, elim_dups}: 52 dirs 53 54 def cfg_pop(c: Config) -> Nat: 55 match c: 56 case MkConfig{dirs, pop_size, gens, seed, mode, elim_dups}: 57 pop_size 58 59 def cfg_gens(c: Config) -> Nat: 60 match c: 61 case MkConfig{dirs, pop_size, gens, seed, mode, elim_dups}: 62 gens 63 64 def cfg_seed(c: Config) -> Nat: 65 match c: 66 case MkConfig{dirs, pop_size, gens, seed, mode, elim_dups}: 67 seed 68 69 def cfg_mode(c: Config) -> Tour.Mode: 70 match c: 71 case MkConfig{dirs, pop_size, gens, seed, mode, elim_dups}: 72 mode 73 74 def cfg_elim(c: Config) -> Bool: 75 match c: 76 case MkConfig{dirs, pop_size, gens, seed, mode, elim_dups}: 77 elim_dups 78 79 # Smoke (not oracle): ZDT1 n=30, partitions=4 → 5 refs, pop=8, gens=3, seed=1. 80 def smoke_zdt1() -> Config: 81 mk(Refs.das_dennis(2n, 4n), 8n, 3n, 1n, Tour.pymoo(), True{}) 82 83 # C# OracleCompare / EQUIVALENCE-style settings (not the smoke default). 84 def oracle_zdt1() -> Config: 85 mk(Refs.das_dennis(2n, 12n), 52n, 100n, 1n, Tour.pymoo(), True{}) 86 87 def oracle_dtlz2() -> Config: 88 mk(Refs.das_dennis(3n, 12n), 92n, 150n, 1n, Tour.pymoo(), True{}) 89 90 def get_ind(+pop: List<&2, Ind.Individual>, i: Nat) -> Ind.Individual: 91 Maybe.default(&2, Ind.Individual, List.get(&2, Ind.Individual, pop, i), Ind.from_variables(Nil{}, 1n)) 92 93 def rand_xs.go(+box: Bounds.Box, fuel: Nat, +i: Nat, rng: Rng.State, acc: List<&2, F32>) -> Rng.State & List<&2, F32>: 94 match fuel: 95 case 0n: 96 (rng, List.reverse(&2, F32, acc)) 97 case 1n+f: 98 +iv = Bounds.at(box, i) 99 +rng2 = Rng.next_double(rng) 100 +lo = Bounds.lo(iv) 101 +hi = Bounds.hi(iv) 102 rand_xs.go( 103 box, 104 f, 105 1n+i, 106 rng2, 107 F32.add(lo, F32.mul(F32.sub(hi, lo), Rng.last_double(rng2))) <> acc 108 ) 109 110 def rand_xs(+box: Bounds.Box, rng: Rng.State) -> Rng.State & List<&2, F32>: 111 rand_xs.go(box, Bounds.n_var(box), 0n, rng, Nil{}) 112 113 type IHold is Data: 114 IH{ 115 rng: Rng.State 116 acc: List<&2, Ind.Individual> 117 } 118 119 def init_next.xs(+n_obj: Nat, acc: List<&2, Ind.Individual>, pair: Rng.State & List<&2, F32>) -> IHold: 120 (rng, xs) = pair 121 IH{rng, Ind.from_variables(xs, n_obj) <> acc} 122 123 def init_next(+box: Bounds.Box, +n_obj: Nat, hold: IHold) -> IHold: 124 match hold: 125 case IH{rng, acc}: 126 init_next.xs(n_obj, acc, rand_xs(box, rng)) 127 128 def init_loop(fuel: Nat, hold: IHold, +box: Bounds.Box, +n_obj: Nat) -> Rng.State & List<&2, Ind.Individual>: 129 match fuel hold: 130 case 0n IH{rng, acc}: 131 (rng, List.reverse(&2, Ind.Individual, acc)) 132 case 1n+f h: 133 init_loop(f, init_next(box, n_obj, h), box, n_obj) 134 135 def init_pop(+prob: Prob.Problem, n: Nat, rng: Rng.State) -> Rng.State & List<&2, Ind.Individual>: 136 init_loop(n, IH{rng, Nil{}}, Prob.box_of(prob), Prob.n_obj(prob)) 137 138 def vars_of.go(xs: List<&2, Ind.Individual>, acc: List<&2, List<&2, F32>>) -> List<&2, List<&2, F32>>: 139 match xs: 140 case Nil{}: 141 List.reverse(&2, List<&2, F32>, acc) 142 case +ind <> rest: 143 vars_of.go(rest, Util.g12_vec(Ind.variables(ind)) <> acc) 144 145 def vars_of(xs: List<&2, Ind.Individual>) -> List<&2, List<&2, F32>>: 146 vars_of.go(xs, Nil{}) 147 148 def try_add.go(+acc: List<&2, Ind.Individual>, +child: Ind.Individual, +seen: List<&2, List<&2, F32>>, +key: List<&2, F32>, skip: Bool) -> List<&2, Ind.Individual> & List<&2, List<&2, F32>> & Bool: 149 match skip: 150 case True{}: 151 (acc, seen, False{}) 152 case False{}: 153 (List.append(&2, Ind.Individual, acc, [child]), key <> seen, True{}) 154 155 def try_add(+acc: List<&2, Ind.Individual>, +child: Ind.Individual, +seen: List<&2, List<&2, F32>>, elim: Bool) -> List<&2, Ind.Individual> & List<&2, List<&2, F32>> & Bool: 156 +key = Util.g12_vec(Ind.variables(child)) 157 try_add.go(acc, child, seen, key, Bool.and(elim, Util.has_f32s(key, seen))) 158 159 def pred_or_zero(n: Nat) -> Nat: 160 match n: 161 case 0n: 162 0n 163 case 1n+p: 164 p 165 166 def dec_if(n: Nat, hit: Bool) -> Nat: 167 match hit: 168 case True{}: 169 pred_or_zero(n) 170 case False{}: 171 n 172 173 # in_range: pair+1 < n → use `pair` (even-N sequence, and odd N before 174 # the last parent). last: pair+1 == n → keep `pair` so parent N-1 175 # enters SBX. Otherwise reset to 0 (cursor already past the end). 176 def wrap_pair.keep(+pair: Nat, last: Bool) -> Nat: 177 match last: 178 case True{}: 179 pair 180 case False{}: 181 0n 182 183 def wrap_pair.go(+pair: Nat, in_range: Bool, last: Bool) -> Nat: 184 match in_range: 185 case True{}: 186 pair 187 case False{}: 188 wrap_pair.keep(pair, last) 189 190 def wrap_pair(+pair: Nat, +n: Nat) -> Nat: 191 wrap_pair.go(pair, Nat.is_lt(1n+pair, n), Nat.is_eq(1n+pair, n)) 192 193 # Second parent. In range: pair+1. At the end (odd N, first parent is 194 # N-1): parent 0. Even N never asks for a mate past N-1. 195 def pair_mate.go(+i: Nat, ok: Bool) -> Nat: 196 match ok: 197 case True{}: 198 i 199 case False{}: 200 0n 201 202 def pair_mate(+p0: Nat, +n: Nat) -> Nat: 203 pair_mate.go(1n+p0, Nat.is_lt(1n+p0, n)) 204 205 # C# fallback cap: max(pop * 20, 1). Unique-key stage before duplicates. 206 def dup_fallback_cap(n: Nat) -> Nat: 207 Util.nat_max(Nat.mul(n, 20n), 1n) 208 209 type FHold is Data: 210 FH{ 211 rng: Rng.State 212 acc: List<&2, Ind.Individual> 213 } 214 215 def fallback_next.m(acc: List<&2, Ind.Individual>, pair: Rng.State & Ind.Individual) -> FHold: 216 (rng, extra) = pair 217 FH{rng, List.append(&2, Ind.Individual, acc, [extra])} 218 219 def fallback_next(+parents: List<&2, Ind.Individual>, +prob: Prob.Problem, +mut_p: F32, hold: FHold) -> FHold: 220 match hold: 221 case FH{rng, acc}: 222 +n = Util.list_len(Ind.Individual, parents) 223 +rng_i = Rng.next_nat(rng, n) 224 fallback_next.m(acc, Poly.mutate(Poly.default(), get_ind(parents, Rng.last_nat(rng_i)), Prob.box_of(prob), rng_i, mut_p)) 225 226 def fallback_loop(need: Nat, hold: FHold, +parents: List<&2, Ind.Individual>, +prob: Prob.Problem, +mut_p: F32) -> Rng.State & List<&2, Ind.Individual>: 227 match need hold: 228 case 0n FH{rng, acc}: 229 (rng, acc) 230 case 1n+k h: 231 fallback_loop(k, fallback_next(parents, prob, mut_p, h), parents, prob, mut_p) 232 233 def offs_add2.hit(+need1: Nat, trip: List<&2, Ind.Individual> & List<&2, List<&2, F32>> & Bool) -> Nat & List<&2, Ind.Individual> & List<&2, List<&2, F32>>: 234 (acc2, seen2, hit2) = trip 235 (dec_if(need1, hit2), acc2, seen2) 236 237 def offs_add2.rest(+need1: Nat, +elim: Bool, +c2: Ind.Individual, acc1: List<&2, Ind.Individual>, seen1: List<&2, List<&2, F32>>, done: Bool) -> Nat & List<&2, Ind.Individual> & List<&2, List<&2, F32>>: 238 match done: 239 case True{}: 240 (0n, acc1, seen1) 241 case False{}: 242 offs_add2.hit(need1, try_add(acc1, c2, seen1, elim)) 243 244 def offs_add2( 245 +need: Nat, 246 acc: List<&2, Ind.Individual>, 247 seen: List<&2, List<&2, F32>>, 248 +elim: Bool, 249 +c2: Ind.Individual, 250 trip: List<&2, Ind.Individual> & List<&2, List<&2, F32>> & Bool 251 ) -> Nat & List<&2, Ind.Individual> & List<&2, List<&2, F32>>: 252 (acc1, seen1, hit1) = trip 253 +need1 = dec_if(need, hit1) 254 offs_add2.rest(need1, elim, c2, acc1, seen1, Nat.is_eq(need1, 0n)) 255 256 def offs_pair.done(rng3: Rng.State, trip: Nat & List<&2, Ind.Individual> & List<&2, List<&2, F32>>) -> Rng.State & Nat & List<&2, Ind.Individual> & List<&2, List<&2, F32>>: 257 (need2, acc2, seen2) = trip 258 (rng3, need2, acc2, seen2) 259 260 def offs_pair.m2(+need: Nat, +acc: List<&2, Ind.Individual>, +seen: List<&2, List<&2, F32>>, +elim: Bool, +m1: Ind.Individual, pair: Rng.State & Ind.Individual) -> Rng.State & Nat & List<&2, Ind.Individual> & List<&2, List<&2, F32>>: 261 (rng3, m2) = pair 262 offs_pair.done(rng3, offs_add2(need, acc, seen, elim, m2, try_add(acc, m1, seen, elim))) 263 264 def offs_pair.m1(+need: Nat, +acc: List<&2, Ind.Individual>, +seen: List<&2, List<&2, F32>>, +prob: Prob.Problem, +mut_p: F32, +elim: Bool, +c2: Ind.Individual, pair: Rng.State & Ind.Individual) -> Rng.State & Nat & List<&2, Ind.Individual> & List<&2, List<&2, F32>>: 265 (rng2, m1) = pair 266 offs_pair.m2(need, acc, seen, elim, m1, Poly.mutate(Poly.default(), c2, Prob.box_of(prob), rng2, mut_p)) 267 268 def offs_pair.sbx(+need: Nat, +acc: List<&2, Ind.Individual>, +seen: List<&2, List<&2, F32>>, +prob: Prob.Problem, +mut_p: F32, +elim: Bool, trip: Rng.State & Ind.Individual & Ind.Individual) -> Rng.State & Nat & List<&2, Ind.Individual> & List<&2, List<&2, F32>>: 269 (rng1, c1, c2) = trip 270 offs_pair.m1(need, acc, seen, prob, mut_p, elim, c2, Poly.mutate(Poly.default(), c1, Prob.box_of(prob), rng1, mut_p)) 271 272 def offs_pair( 273 +parents: List<&2, Ind.Individual>, 274 +pair: Nat, 275 +need: Nat, 276 +acc: List<&2, Ind.Individual>, 277 +seen: List<&2, List<&2, F32>>, 278 rng: Rng.State, 279 +prob: Prob.Problem, 280 +mut_p: F32, 281 +elim: Bool 282 ) -> Rng.State & Nat & List<&2, Ind.Individual> & List<&2, List<&2, F32>>: 283 +n = Util.list_len(Ind.Individual, parents) 284 +p0 = wrap_pair(pair, n) 285 offs_pair.sbx( 286 need, 287 acc, 288 seen, 289 prob, 290 mut_p, 291 elim, 292 Sbx.crossover(Sbx.default(), get_ind(parents, p0), get_ind(parents, pair_mate(p0, n)), Prob.box_of(prob), rng) 293 ) 294 295 type OHold is Data: 296 OH{ 297 need: Nat 298 pair: Nat 299 rng: Rng.State 300 acc: List<&2, Ind.Individual> 301 seen: List<&2, List<&2, F32>> 302 } 303 304 def offs_next.q(+pair0: Nat, quad: Rng.State & Nat & List<&2, Ind.Individual> & List<&2, List<&2, F32>>) -> OHold: 305 (rng, need, acc, seen) = quad 306 OH{need, Nat.add(pair0, 2n), rng, acc, seen} 307 308 def offs_next(+parents: List<&2, Ind.Individual>, +prob: Prob.Problem, +mut_p: F32, +elim: Bool, hold: OHold) -> OHold: 309 match hold: 310 case OH{need, +pair, rng, acc, seen}: 311 offs_next.q(pair, offs_pair(parents, pair, need, acc, seen, rng, prob, mut_p, elim)) 312 313 # Middle loop: mutation that must still be a new key. `need` is the 314 # remaining slots. Cap is max(pop*20, 1), counted in `fuel`. 315 type UHold is Data: 316 UH{ 317 rng: Rng.State 318 acc: List<&2, Ind.Individual> 319 seen: List<&2, List<&2, F32>> 320 need: Nat 321 } 322 323 def u_have(hold: UHold) -> Rng.State & List<&2, Ind.Individual>: 324 match hold: 325 case UH{rng, acc, seen, need}: 326 (rng, acc) 327 328 def u_fallback(+parents: List<&2, Ind.Individual>, +prob: Prob.Problem, +mut_p: F32, hold: UHold) -> Rng.State & List<&2, Ind.Individual>: 329 match hold: 330 case UH{rng, acc, seen, need}: 331 fallback_loop(need, FH{rng, acc}, parents, prob, mut_p) 332 333 def u_step.hold(+rng: Rng.State, +need: Nat, trip: List<&2, Ind.Individual> & List<&2, List<&2, F32>> & Bool) -> UHold: 334 (acc2, seen2, hit) = trip 335 UH{rng, acc2, seen2, dec_if(need, hit)} 336 337 def u_step.child(+elim: Bool, +acc: List<&2, Ind.Individual>, +seen: List<&2, List<&2, F32>>, +need: Nat, +rng: Rng.State, +child: Ind.Individual) -> UHold: 338 u_step.hold(rng, need, try_add(acc, child, seen, elim)) 339 340 def u_step(+elim: Bool, +acc: List<&2, Ind.Individual>, +seen: List<&2, List<&2, F32>>, +need: Nat, pair: Rng.State & Ind.Individual) -> UHold: 341 (rng, child) = pair 342 u_step.child(elim, acc, seen, need, rng, child) 343 344 def u_next(+parents: List<&2, Ind.Individual>, +prob: Prob.Problem, +mut_p: F32, +elim: Bool, hold: UHold) -> UHold: 345 match hold: 346 case UH{rng, acc, seen, need}: 347 +n = Util.list_len(Ind.Individual, parents) 348 +rng_i = Rng.next_nat(rng, n) 349 u_step(elim, acc, seen, need, Poly.mutate(Poly.default(), get_ind(parents, Rng.last_nat(rng_i)), Prob.box_of(prob), rng_i, mut_p)) 350 351 def u_loop( 352 fuel: Nat, 353 hold: UHold, 354 +parents: List<&2, Ind.Individual>, 355 +prob: Prob.Problem, 356 +mut_p: F32, 357 +elim: Bool 358 ) -> Rng.State & List<&2, Ind.Individual>: 359 match fuel hold: 360 case 0n h: 361 u_fallback(parents, prob, mut_p, h) 362 case 1n+f UH{rng, acc, seen, 0n}: 363 u_have(UH{rng, acc, seen, 0n}) 364 case 1n+f UH{rng, acc, seen, 1n+k}: 365 u_loop(f, u_next(parents, prob, mut_p, elim, UH{rng, acc, seen, 1n+k}), parents, prob, mut_p, elim) 366 367 def offs_done(+parents: List<&2, Ind.Individual>, +prob: Prob.Problem, +mut_p: F32, +elim: Bool, +n: Nat, hold: OHold) -> Rng.State & List<&2, Ind.Individual>: 368 match hold: 369 case OH{nrest, pair, rng, acc, seen}: 370 u_loop(dup_fallback_cap(n), UH{rng, acc, seen, nrest}, parents, prob, mut_p, elim) 371 372 def offs_have(hold: OHold) -> Rng.State & List<&2, Ind.Individual>: 373 match hold: 374 case OH{need, pair, rng, acc, seen}: 375 (rng, acc) 376 377 def offs_loop( 378 fuel: Nat, 379 hold: OHold, 380 +parents: List<&2, Ind.Individual>, 381 +prob: Prob.Problem, 382 +mut_p: F32, 383 +elim: Bool, 384 +n: Nat 385 ) -> Rng.State & List<&2, Ind.Individual>: 386 match fuel hold: 387 case 0n h: 388 offs_done(parents, prob, mut_p, elim, n, h) 389 case 1n+f OH{0n, pair, rng, acc, seen}: 390 offs_have(OH{0n, pair, rng, acc, seen}) 391 case 1n+f OH{1n+k, pair, rng, acc, seen}: 392 offs_loop(f, offs_next(parents, prob, mut_p, elim, OH{1n+k, pair, rng, acc, seen}), parents, prob, mut_p, elim, n) 393 394 # Hash the survivor population (not the mating sample). An individual 395 # who lost every tournament is still a duplicate of P. 396 def seen_start(+survivors: List<&2, Ind.Individual>, elim: Bool) -> List<&2, List<&2, F32>>: 397 match elim: 398 case True{}: 399 vars_of(survivors) 400 case False{}: 401 Nil{} 402 403 def create_offspring( 404 +prob: Prob.Problem, 405 +survivors: List<&2, Ind.Individual>, 406 +parents: List<&2, Ind.Individual>, 407 +n: Nat, 408 rng: Rng.State, 409 +elim: Bool 410 ) -> Rng.State & List<&2, Ind.Individual>: 411 offs_loop( 412 Nat.mul(n, 40n), 413 OH{n, 0n, rng, Nil{}, seen_start(survivors, elim)}, 414 parents, 415 prob, 416 Poly.typical_probability(Prob.n_var(prob)), 417 elim, 418 n 419 ) 420 421 def nd_front(+pop: List<&2, Ind.Individual>) -> List<&2, Ind.Individual>: 422 Surv.gather(pop, Surv.front0(NDS.sort(pop))) 423 424 def emit_front(xs: List<&2, Ind.Individual>) -> IO(Unit): 425 match xs: 426 case Nil{}: 427 do IO: 428 return Unit{} 429 case ind <> rest: 430 do IO: 431 IO.print(Util.show_f32s(Ind.objectives(ind))) 432 emit_front(rest) 433 434 type GHold is Data: 435 GH{ 436 st: Norm.State 437 xs: List<&2, Ind.Individual> 438 rng: Rng.State 439 } 440 441 def one_gen.prep(+rng: Rng.State, pair: Norm.State & List<&2, Ind.Individual>) -> GHold: 442 (st, xs) = pair 443 GH{st, xs, rng} 444 445 def one_gen.s(+prob: Prob.Problem, +cfg: Config, trip: Norm.State & List<&2, Ind.Individual> & Rng.State) -> GHold: 446 (st, xs, rng) = trip 447 one_gen.prep(rng, Tour.prepare(xs, cfg_dirs(cfg), st)) 448 449 def one_gen.o(+prob: Prob.Problem, +cfg: Config, +pop: List<&2, Ind.Individual>, +state: Norm.State, trip: Rng.State & List<&2, Ind.Individual>) -> GHold: 450 (rng2, offs) = trip 451 one_gen.s( 452 prob, 453 cfg, 454 Surv.select_st( 455 List.append(&2, Ind.Individual, pop, Prob.evaluate_all(prob, offs)), 456 cfg_pop(cfg), 457 cfg_dirs(cfg), 458 state, 459 rng2 460 ) 461 ) 462 463 def one_gen.p(+prob: Prob.Problem, +cfg: Config, +pop: List<&2, Ind.Individual>, +state: Norm.State, trip: Rng.State & List<&2, Ind.Individual>) -> GHold: 464 (rng1, parents) = trip 465 one_gen.o(prob, cfg, pop, state, create_offspring(prob, pop, parents, cfg_pop(cfg), rng1, cfg_elim(cfg))) 466 467 def one_gen(+prob: Prob.Problem, +cfg: Config, hold: GHold) -> GHold: 468 match hold: 469 case GH{st, +xs, rng}: 470 one_gen.p(prob, cfg, xs, st, Tour.select_parents(cfg_mode(cfg), xs, cfg_pop(cfg), rng)) 471 472 def gen_pop(hold: GHold) -> List<&2, Ind.Individual>: 473 match hold: 474 case GH{st, xs, rng}: 475 xs 476 477 def gen_loop(fuel: Nat, hold: GHold, +prob: Prob.Problem, +cfg: Config) -> List<&2, Ind.Individual>: 478 match fuel hold: 479 case 0n h: 480 gen_pop(h) 481 case 1n+g h: 482 gen_loop(g, one_gen(prob, cfg, h), prob, cfg) 483 484 def run.after_prep(+prob: Prob.Problem, +cfg: Config, rng: Rng.State, pair: Norm.State & List<&2, Ind.Individual>) -> List<&2, Ind.Individual>: 485 (st1, pop1) = pair 486 gen_loop(cfg_gens(cfg), GH{st1, pop1, rng}, prob, cfg) 487 488 def run.go(+prob: Prob.Problem, +cfg: Config, pair: Rng.State & List<&2, Ind.Individual>) -> List<&2, Ind.Individual>: 489 (rng, raw) = pair 490 run.after_prep(prob, cfg, rng, Tour.prepare(Prob.evaluate_all(prob, raw), cfg_dirs(cfg), Norm.new_state(Prob.n_obj(prob)))) 491 492 def run.sized(+prob: Prob.Problem, +cfg: Config, n: Nat) -> List<&2, Ind.Individual>: 493 match n: 494 case 0n: 495 Nil{} 496 case 1n+p: 497 run.go(prob, cfg, init_pop(prob, 1n+p, Rng.from_nat(cfg_seed(cfg)))) 498 499 def run(+prob: Prob.Problem, +cfg: Config) -> List<&2, Ind.Individual>: 500 +n = cfg_pop(cfg) 501 Util.list_take_pad(Ind.Individual, Ind.from_objectives(Nil{}), run.sized(prob, cfg, n), n) 502 503 def run_zdt1_smoke() -> List<&2, Ind.Individual>: 504 run(Prob.zdt1(30n), smoke_zdt1())