problems.bend
unified-nsga-iii@0.2.1.0 · 654 lines · 0 definitions
1# Named problems — C# Unsga3.Problems.
2# ZDT1 / ZDT2 / DTLZ2 stay the oracle problems. The rest of the unconstrained
3# catalog (ZDT3 / ZDT4 / ZDT6, DTLZ1 / DTLZ3 / DTLZ4 / DTLZ7, Sphere / Ackley /
4# Rosenbrock) matches the same C# Evaluate formulas. Minimize.
5# OSY / TNK / C1-DTLZ1 match ConstrainedProblems.cs (g ≤ 0, positive = violation).
6# Unconstrained kinds write an empty constraint vector (cv 0). No IGD here.
7# `alpha` is DTLZ4's exponent (C# default 100). Other kinds ignore it.
8
9import Base
10import unified-nsga-iii@0.2.1.0/individual.bend as Ind
11import unified-nsga-iii@0.2.1.0/bounds.bend as Bounds
12import unified-nsga-iii@0.2.1.0/util.bend as Util
13
14type Family is Data:
15 Zdt1{}
16 Zdt2{}
17 Zdt3{}
18 Zdt4{}
19 Zdt6{}
20 Dtlz1{}
21 Dtlz2{}
22 Dtlz3{}
23 Dtlz4{}
24 Dtlz7{}
25 Sphere{}
26 Ackley{}
27 Rosenbrock{}
28 Osy{}
29 Tnk{}
30 C1Dtlz1{}
31
32type Problem is Data:
33 MkProblem{
34 kind: Family
35 box: Bounds.Box
36 alpha: F32
37 }
38
39def box_of(p: Problem) -> Bounds.Box:
40 match p:
41 case MkProblem{kind, box, alpha}:
42 box
43
44def kind_of(p: Problem) -> Family:
45 match p:
46 case MkProblem{kind, box, alpha}:
47 kind
48
49def alpha_of(p: Problem) -> F32:
50 match p:
51 case MkProblem{kind, box, alpha}:
52 alpha
53
54def n_obj(p: Problem) -> Nat:
55 Bounds.n_obj(box_of(p))
56
57def n_var(p: Problem) -> Nat:
58 Bounds.n_var(box_of(p))
59
60def mk_prob(kind: Family, box: Bounds.Box) -> Problem:
61 MkProblem{kind, box, 0.0}
62
63# ZDT1 / ZDT2 / ZDT3: n variables (C# default 30), 2 objectives, x ∈ [0,1]^n.
64def zdt1(n: Nat) -> Problem:
65 mk_prob(Zdt1{}, Bounds.unit_n(n, 2n))
66
67def zdt2(n: Nat) -> Problem:
68 mk_prob(Zdt2{}, Bounds.unit_n(n, 2n))
69
70def zdt3(n: Nat) -> Problem:
71 mk_prob(Zdt3{}, Bounds.unit_n(n, 2n))
72
73# ZDT4: C# default n=10. x0 ∈ [0,1], x1.. ∈ [-5,5].
74def zdt4_ivs(n: Nat) -> List<&2, Bounds.Interval>:
75 match n:
76 case 0n:
77 Nil{}
78 case 1n+p:
79 Bounds.interval(0.0, 1.0) <> List.replicate(Bounds.Interval, p, Bounds.interval(F32.neg(5.0), 5.0))
80
81def zdt4(n: Nat) -> Problem:
82 mk_prob(Zdt4{}, Bounds.box(2n, zdt4_ivs(n)))
83
84# ZDT6: C# default n=10, x ∈ [0,1]^n.
85def zdt6(n: Nat) -> Problem:
86 mk_prob(Zdt6{}, Bounds.unit_n(n, 2n))
87
88# n = M + k - 1 (C# Dtlz*Problem).
89def dtlz_n(m: Nat, k: Nat) -> Nat:
90 match m:
91 case 0n:
92 k
93 case 1n+pm:
94 match k:
95 case 0n:
96 pm
97 case 1n+pk:
98 Nat.add(pm, 1n+pk)
99
100# DTLZ2: C# default M=3, k=10 ⇒ n=12, x ∈ [0,1]^n.
101def dtlz2(+m: Nat, k: Nat) -> Problem:
102 mk_prob(Dtlz2{}, Bounds.unit_n(dtlz_n(m, k), m))
103
104# DTLZ1: C# default M=3, k=5 ⇒ n=7.
105def dtlz1(+m: Nat, k: Nat) -> Problem:
106 mk_prob(Dtlz1{}, Bounds.unit_n(dtlz_n(m, k), m))
107
108# DTLZ3: C# default M=3, k=10. DTLZ2 map, DTLZ1 g.
109def dtlz3(+m: Nat, k: Nat) -> Problem:
110 mk_prob(Dtlz3{}, Bounds.unit_n(dtlz_n(m, k), m))
111
112# DTLZ4: C# default α=100, k=10.
113def dtlz4_alpha(+m: Nat, k: Nat, +alpha: F32) -> Problem:
114 MkProblem{Dtlz4{}, Bounds.unit_n(dtlz_n(m, k), m), alpha}
115
116def dtlz4(+m: Nat, k: Nat) -> Problem:
117 dtlz4_alpha(m, k, 100.0)
118
119# DTLZ7: C# default M=3, k=20 ⇒ n=22.
120def dtlz7(+m: Nat, k: Nat) -> Problem:
121 mk_prob(Dtlz7{}, Bounds.unit_n(dtlz_n(m, k), m))
122
123# Single-objective. M=1. C# defaults: Sphere n=10, Ackley n=30, Rosenbrock n=10.
124def sphere(n: Nat) -> Problem:
125 mk_prob(Sphere{}, Bounds.span_n(n, 1n, F32.neg(5.12), 5.12))
126
127def ackley(n: Nat) -> Problem:
128 mk_prob(Ackley{}, Bounds.span_n(n, 1n, F32.neg(32.768), 32.768))
129
130def rosenbrock(n: Nat) -> Problem:
131 mk_prob(Rosenbrock{}, Bounds.span_n(n, 1n, F32.neg(2.048), 2.048))
132
133# OSY: 6 variables, 2 objectives, 6 inequalities. pymoo 0.6 scaling.
134def osy() -> Problem:
135 mk_prob(
136 Osy{},
137 Bounds.box(
138 2n,
139 Bounds.interval(0.0, 10.0)
140 <> Bounds.interval(0.0, 10.0)
141 <> Bounds.interval(1.0, 5.0)
142 <> Bounds.interval(0.0, 6.0)
143 <> Bounds.interval(1.0, 5.0)
144 <> [Bounds.interval(0.0, 10.0)]
145 )
146 )
147
148# TNK: [0, π] × [1e-30, π]. Disk constraint uses pymoo's factor of two.
149def tnk() -> Problem:
150 mk_prob(
151 Tnk{},
152 Bounds.box(2n, Bounds.interval(0.0, F32.pi()) <> [Bounds.interval(1.0e-30, F32.pi())])
153 )
154
155# C1-DTLZ1: DTLZ1 plus one inequality. C# default M=3, k=5 (n = M+k-1).
156def c1_dtlz1(+m: Nat, k: Nat) -> Problem:
157 mk_prob(C1Dtlz1{}, Bounds.unit_n(dtlz_n(m, k), m))
158
159def sum_from(xs: List<&2, F32>) -> F32:
160 match xs:
161 case Nil{}:
162 0.0
163 case h <> t:
164 F32.add(h, sum_from(t))
165
166def sum_tail(xs: List<&2, F32>) -> F32:
167 match xs:
168 case Nil{}:
169 0.0
170 case h <> t:
171 sum_from(t)
172
173def list_tail(xs: List<&2, F32>) -> List<&2, F32>:
174 match xs:
175 case Nil{}:
176 Nil{}
177 case h <> t:
178 t
179
180def zdt_den(n: Nat) -> F32:
181 match n:
182 case 0n:
183 1.0
184 case 1n:
185 1.0
186 case 1n+p:
187 F32.from_nat(p)
188
189# C# Zdt1Problem.GLinear: 1 + 9 * sum(x[1..]) / (n - 1).
190def zdt_g(+x: List<&2, F32>) -> F32:
191 +n = Util.list_len(F32, x)
192 F32.add(1.0, F32.div(F32.mul(9.0, sum_tail(x)), zdt_den(n)))
193
194def zdt1_f(+x: List<&2, F32>) -> List<&2, F32>:
195 +x0 = Util.get_f32(x, 0n)
196 +g = zdt_g(x)
197 x0 <> [F32.mul(g, F32.sub(1.0, F32.sqrt(F32.div(x0, g))))]
198
199def zdt2_f(+x: List<&2, F32>) -> List<&2, F32>:
200 +x0 = Util.get_f32(x, 0n)
201 +g = zdt_g(x)
202 +r = F32.div(x0, g)
203 x0 <> [F32.mul(g, F32.sub(1.0, F32.mul(r, r)))]
204
205# C# Zdt3Problem: g * (1 - sqrt(r) - r * sin(10 π x0)), r = x0/g.
206def zdt3_f(+x: List<&2, F32>) -> List<&2, F32>:
207 +x0 = Util.get_f32(x, 0n)
208 +g = zdt_g(x)
209 +r = F32.div(x0, g)
210 +s = F32.sin(F32.mul(F32.mul(10.0, F32.pi()), x0))
211 x0 <> [F32.mul(g, F32.sub(F32.sub(1.0, F32.sqrt(r)), F32.mul(r, s)))]
212
213def zdt4_term(+xi: F32) -> F32:
214 F32.sub(F32.square(xi), F32.mul(10.0, F32.cos(F32.mul(F32.mul(4.0, F32.pi()), xi))))
215
216def sum_zdt4(xs: List<&2, F32>) -> F32:
217 match xs:
218 case Nil{}:
219 0.0
220 case h <> t:
221 F32.add(zdt4_term(h), sum_zdt4(t))
222
223def pred(n: Nat) -> Nat:
224 match n:
225 case 0n:
226 0n
227 case 1n+p:
228 p
229
230# C# Zdt4Problem: 1 + 10*(n-1) + Σ_{i≥1} (x_i² - 10 cos(4 π x_i)).
231def zdt4_g(+x: List<&2, F32>) -> F32:
232 +n = Util.list_len(F32, x)
233 F32.add(F32.add(1.0, F32.mul(10.0, F32.from_nat(pred(n)))), sum_zdt4(list_tail(x)))
234
235def zdt4_f(+x: List<&2, F32>) -> List<&2, F32>:
236 +x0 = Util.get_f32(x, 0n)
237 +g = zdt4_g(x)
238 x0 <> [F32.mul(g, F32.sub(1.0, F32.sqrt(F32.div(x0, g))))]
239
240# C# Zdt6Problem: biased density. g = 1 + 9 * (mean of x[1..])^0.25.
241def zdt6_f(+x: List<&2, F32>) -> List<&2, F32>:
242 +x0 = Util.get_f32(x, 0n)
243 +wave = F32.pow(F32.sin(F32.mul(F32.mul(6.0, F32.pi()), x0)), 6.0)
244 +f0 = F32.sub(1.0, F32.mul(F32.exp(F32.mul(F32.neg(4.0), x0)), wave))
245 +n = Util.list_len(F32, x)
246 +g = F32.add(1.0, F32.mul(9.0, F32.pow(F32.div(sum_tail(x), zdt_den(n)), 0.25)))
247 +r = F32.div(f0, g)
248 f0 <> [F32.mul(g, F32.sub(1.0, F32.mul(r, r)))]
249
250def sum_sq_half(xs: List<&2, F32>) -> F32:
251 match xs:
252 case Nil{}:
253 0.0
254 case h <> t:
255 F32.add(F32.square(F32.sub(h, 0.5)), sum_sq_half(t))
256
257def tail_from_m(+x: List<&2, F32>, m: Nat) -> List<&2, F32>:
258 List.drop(&2, F32, x, pred(m))
259
260# C# DtlzHelper.GDtlz2: sum (x[i] - 0.5)^2 for i >= M-1.
261def dtlz2_g(+x: List<&2, F32>, m: Nat) -> F32:
262 sum_sq_half(tail_from_m(x, m))
263
264def dtlz1_term(+xi: F32) -> F32:
265 +d = F32.sub(xi, 0.5)
266 F32.sub(F32.square(d), F32.cos(F32.mul(F32.mul(20.0, F32.pi()), d)))
267
268def sum_dtlz1(xs: List<&2, F32>) -> F32:
269 match xs:
270 case Nil{}:
271 0.0
272 case h <> t:
273 F32.add(dtlz1_term(h), sum_dtlz1(t))
274
275# C# DtlzHelper.GDtlz1: 100 * ((n - M + 1) + Σ (d² - cos(20 π d))), d = x-0.5.
276# On a legal k≥1 box the tail length is n-M+1, which is that coefficient.
277def dtlz1_g(+x: List<&2, F32>, m: Nat) -> F32:
278 +tail = tail_from_m(x, m)
279 F32.mul(100.0, F32.add(F32.from_nat(Util.list_len(F32, tail)), sum_dtlz1(tail)))
280
281def half_pi() -> F32:
282 F32.div(F32.pi(), 2.0)
283
284def prod_cos.go(+x: List<&2, F32>, fuel: Nat, +i: Nat, acc: F32) -> F32:
285 match fuel:
286 case 0n:
287 acc
288 case 1n+f:
289 prod_cos.go(
290 x,
291 f,
292 1n+i,
293 F32.mul(acc, F32.cos(F32.mul(Util.get_f32(x, i), half_pi())))
294 )
295
296def prod_cos(+x: List<&2, F32>, n: Nat) -> F32:
297 prod_cos.go(x, n, 0n, 1.0)
298
299def dtlz2_sin(+x: List<&2, F32>, +m: Nat, +i: Nat) -> F32:
300 F32.sin(F32.mul(Util.get_f32(x, pred(Nat.sub(m, i))), half_pi()))
301
302def dtlz2_fi.tail(+x: List<&2, F32>, +m: Nat, +g: F32, +i: Nat, +body: F32, first: Bool) -> F32:
303 match first:
304 case True{}:
305 body
306 case False{}:
307 F32.mul(body, dtlz2_sin(x, m, i))
308
309# C# Dtlz2Problem: (1+g) * prod_{j<M-i-1} cos(x[j] π/2) [* sin(x[M-i-1] π/2) if i>0].
310def dtlz2_fi(+x: List<&2, F32>, +m: Nat, +g: F32, +i: Nat) -> F32:
311 dtlz2_fi.tail(
312 x,
313 m,
314 g,
315 i,
316 F32.mul(F32.add(1.0, g), prod_cos(x, pred(Nat.sub(m, i)))),
317 Nat.is_eq(i, 0n)
318 )
319
320def dtlz2_fs.go(+x: List<&2, F32>, +m: Nat, +g: F32, fuel: Nat, +i: Nat) -> List<&2, F32>:
321 match fuel:
322 case 0n:
323 Nil{}
324 case 1n+f:
325 dtlz2_fi(x, m, g, i) <> dtlz2_fs.go(x, m, g, f, 1n+i)
326
327def dtlz2_f(+x: List<&2, F32>, +m: Nat) -> List<&2, F32>:
328 dtlz2_fs.go(x, m, dtlz2_g(x, m), m, 0n)
329
330def prod_xs.go(+x: List<&2, F32>, fuel: Nat, +i: Nat, acc: F32) -> F32:
331 match fuel:
332 case 0n:
333 acc
334 case 1n+f:
335 prod_xs.go(x, f, 1n+i, F32.mul(acc, Util.get_f32(x, i)))
336
337def prod_xs(+x: List<&2, F32>, n: Nat) -> F32:
338 prod_xs.go(x, n, 0n, 1.0)
339
340def dtlz1_scale(+body: F32, +x: List<&2, F32>, +idx: Nat, first: Bool) -> F32:
341 match first:
342 case True{}:
343 body
344 case False{}:
345 F32.mul(body, F32.sub(1.0, Util.get_f32(x, idx)))
346
347# C# Dtlz1Problem: 0.5*(1+g) * prod_{j<M-i-1} x[j] [* (1-x[M-i-1]) if i>0].
348def dtlz1_fi(+x: List<&2, F32>, +m: Nat, +g: F32, +i: Nat) -> F32:
349 +idx = pred(Nat.sub(m, i))
350 dtlz1_scale(F32.mul(F32.mul(0.5, F32.add(1.0, g)), prod_xs(x, idx)), x, idx, Nat.is_eq(i, 0n))
351
352def dtlz1_fs.go(+x: List<&2, F32>, +m: Nat, +g: F32, fuel: Nat, +i: Nat) -> List<&2, F32>:
353 match fuel:
354 case 0n:
355 Nil{}
356 case 1n+f:
357 dtlz1_fi(x, m, g, i) <> dtlz1_fs.go(x, m, g, f, 1n+i)
358
359def dtlz1_f(+x: List<&2, F32>, +m: Nat) -> List<&2, F32>:
360 dtlz1_fs.go(x, m, dtlz1_g(x, m), m, 0n)
361
362# F32 cos(π/2) is -4.371139e-8, not 0. The DTLZ2 map multiplies that
363# factor by (1+g). DTLZ3's g stays large on local fronts, so an in-bound
364# x=1 (SBX / polynomial mutation clamp to the box) gets a strictly
365# negative objective. Every feasible point has f≥0, so nothing dominates
366# that row. It stays on the ND front and pins an ASF extreme at (1+g).
367# DTLZ2's (1+g) is ~1, so the same raw trig is left alone (published
368# fronts). Clamp only this map back to the mathematical range f≥0.
369def nn_obj(+v: F32) -> F32:
370 Bool.pick(F32, F32.is_lt(v, 0.0), 0.0, v)
371
372def nn_objs(xs: List<&2, F32>) -> List<&2, F32>:
373 match xs:
374 case Nil{}:
375 Nil{}
376 case h <> t:
377 nn_obj(h) <> nn_objs(t)
378
379# C# Dtlz3Problem: DTLZ2 map with DTLZ1's g.
380def dtlz3_f(+x: List<&2, F32>, +m: Nat) -> List<&2, F32>:
381 nn_objs(dtlz2_fs.go(x, m, dtlz1_g(x, m), m, 0n))
382
383# Fuel shrinks first so the recursive call terminates. The g-tail stays raw.
384def map_prefix_pow.go(fuel: Nat, xs: List<&2, F32>, +alpha: F32) -> List<&2, F32>:
385 match fuel:
386 case 0n:
387 xs
388 case 1n+f:
389 match xs:
390 case Nil{}:
391 Nil{}
392 case h <> t:
393 F32.pow(h, alpha) <> map_prefix_pow.go(f, t, alpha)
394
395# Raise the first `fuel` decision variables to α.
396def map_prefix_pow(+xs: List<&2, F32>, fuel: Nat, +alpha: F32) -> List<&2, F32>:
397 map_prefix_pow.go(fuel, xs, alpha)
398
399# C# Dtlz4Problem: DTLZ2 with x^α inside the sine/cosine map. g is still GDtlz2.
400def dtlz4_f(+x: List<&2, F32>, +m: Nat, +alpha: F32) -> List<&2, F32>:
401 dtlz2_f(map_prefix_pow(x, pred(m), alpha), m)
402
403def pos_or.fin(+x: F32, +fallback: F32, ok: Bool) -> F32:
404 match ok:
405 case True{}:
406 x
407 case False{}:
408 fallback
409
410def pos_or(+x: F32, +fallback: F32) -> F32:
411 pos_or.fin(x, fallback, F32.is_gt(x, 0.0))
412
413# C# Dtlz7Problem g: 1 + 9 * sum(x[M-1..]) / (n - M + 1).
414def dtlz7_g(+x: List<&2, F32>, m: Nat) -> F32:
415 +tail = tail_from_m(x, m)
416 +den = pos_or(F32.from_nat(Util.list_len(F32, tail)), 1.0)
417 F32.add(1.0, F32.div(F32.mul(9.0, sum_from(tail)), den))
418
419def dtlz7_h.go(+x: List<&2, F32>, +g1: F32, fuel: Nat, +i: Nat, acc: F32) -> F32:
420 match fuel:
421 case 0n:
422 acc
423 case 1n+f:
424 +fi = Util.get_f32(x, i)
425 +term = F32.mul(F32.div(fi, g1), F32.add(1.0, F32.sin(F32.mul(F32.mul(3.0, F32.pi()), fi))))
426 dtlz7_h.go(x, g1, f, 1n+i, F32.add(acc, term))
427
428def dtlz7_prefix(+x: List<&2, F32>, fuel: Nat, +i: Nat) -> List<&2, F32>:
429 match fuel:
430 case 0n:
431 Nil{}
432 case 1n+f:
433 Util.get_f32(x, i) <> dtlz7_prefix(x, f, 1n+i)
434
435# f[i]=x[i] for i<M-1; f[M-1]=(1+g)*h; h = M - Σ f_i/(1+g) * (1+sin(3 π f_i)).
436def dtlz7_f(+x: List<&2, F32>, +m: Nat) -> List<&2, F32>:
437 match m:
438 case 0n:
439 Nil{}
440 case 1n+p:
441 +g = dtlz7_g(x, m)
442 +g1 = F32.add(1.0, g)
443 +h = F32.sub(F32.from_nat(m), dtlz7_h.go(x, g1, p, 0n, 0.0))
444 List.append(&2, F32, dtlz7_prefix(x, p, 0n), [F32.mul(g1, h)])
445
446def sum_sq(xs: List<&2, F32>) -> F32:
447 match xs:
448 case Nil{}:
449 0.0
450 case h <> t:
451 F32.add(F32.square(h), sum_sq(t))
452
453def sphere_f(+x: List<&2, F32>) -> List<&2, F32>:
454 [sum_sq(x)]
455
456type Acc2 is Data:
457 Acc2{
458 s1: F32
459 s2: F32
460 }
461
462def ackley_go(xs: List<&2, F32>, +s1: F32, +s2: F32) -> Acc2:
463 match xs:
464 case Nil{}:
465 Acc2{s1, s2}
466 case +h <> t:
467 ackley_go(
468 t,
469 F32.add(s1, F32.square(h)),
470 F32.add(s2, F32.cos(F32.mul(F32.mul(2.0, F32.pi()), h)))
471 )
472
473def ackley_den(n: Nat) -> F32:
474 match n:
475 case 0n:
476 1.0
477 case 1n+p:
478 F32.from_nat(1n+p)
479
480def ackley_from(+n: Nat, acc: Acc2) -> List<&2, F32>:
481 match acc:
482 case Acc2{s1, s2}:
483 +den = ackley_den(n)
484 [F32.add(
485 F32.add(
486 F32.mul(F32.neg(20.0), F32.exp(F32.mul(F32.neg(0.2), F32.sqrt(F32.div(s1, den))))),
487 F32.neg(F32.exp(F32.div(s2, den)))
488 ),
489 F32.add(20.0, F32.exp(1.0))
490 )]
491
492# C# AckleyProblem. n=0 stays total (denominator 1) instead of dividing by zero.
493def ackley_f(+x: List<&2, F32>) -> List<&2, F32>:
494 ackley_from(Util.list_len(F32, x), ackley_go(x, 0.0, 0.0))
495
496def rosen_step(rest: List<&2, F32>, +a: F32) -> F32:
497 match rest:
498 case Nil{}:
499 0.0
500 case +b <> t:
501 +diff = F32.sub(b, F32.square(a))
502 +one = F32.sub(1.0, a)
503 F32.add(F32.add(F32.mul(100.0, F32.square(diff)), F32.square(one)), rosen_step(t, b))
504
505def rosenbrock_f(+x: List<&2, F32>) -> List<&2, F32>:
506 match x:
507 case Nil{}:
508 [0.0]
509 case a <> rest:
510 [rosen_step(rest, a)]
511
512# Objectives plus g ≤ 0. Unconstrained kinds leave g empty.
513type Scored is Data:
514 Scored{
515 f: List<&2, F32>
516 g: List<&2, F32>
517 }
518
519def plain(+f: List<&2, F32>) -> Scored:
520 Scored{f, Nil{}}
521
522def scored_f(s: Scored) -> List<&2, F32>:
523 match s:
524 case Scored{f, g}:
525 f
526
527def scored_g(s: Scored) -> List<&2, F32>:
528 match s:
529 case Scored{f, g}:
530 g
531
532# C# OsyProblem. f0 negates the weighted squares (x5 is not in f0).
533def osy_f(+x: List<&2, F32>) -> List<&2, F32>:
534 +x0 = Util.get_f32(x, 0n)
535 +x1 = Util.get_f32(x, 1n)
536 +x2 = Util.get_f32(x, 2n)
537 +x3 = Util.get_f32(x, 3n)
538 +x4 = Util.get_f32(x, 4n)
539 +pen = F32.add(
540 F32.mul(25.0, F32.square(F32.sub(x0, 2.0))),
541 F32.add(
542 F32.square(F32.sub(x1, 2.0)),
543 F32.add(
544 F32.square(F32.sub(x2, 1.0)),
545 F32.add(F32.square(F32.sub(x3, 4.0)), F32.square(F32.sub(x4, 1.0)))
546 )
547 )
548 )
549 F32.neg(pen) <> [sum_sq(x)]
550
551# pymoo divisors, then negated so a positive value is a violation.
552def osy_g(+x: List<&2, F32>) -> List<&2, F32>:
553 +x0 = Util.get_f32(x, 0n)
554 +x1 = Util.get_f32(x, 1n)
555 +x2 = Util.get_f32(x, 2n)
556 +x3 = Util.get_f32(x, 3n)
557 +x4 = Util.get_f32(x, 4n)
558 +x5 = Util.get_f32(x, 5n)
559 F32.neg(F32.div(F32.sub(F32.add(x0, x1), 2.0), 2.0))
560 <> F32.neg(F32.div(F32.sub(F32.sub(6.0, x0), x1), 6.0))
561 <> F32.neg(F32.div(F32.add(F32.sub(2.0, x1), x0), 2.0))
562 <> F32.neg(F32.div(F32.add(F32.sub(2.0, x0), F32.mul(3.0, x1)), 2.0))
563 <> F32.neg(F32.div(F32.sub(F32.sub(4.0, F32.square(F32.sub(x2, 3.0))), x3), 4.0))
564 <> [F32.neg(F32.div(F32.sub(F32.add(F32.square(F32.sub(x4, 3.0)), x5), 4.0), 4.0))]
565
566def osy_score(+x: List<&2, F32>) -> Scored:
567 Scored{osy_f(x), osy_g(x)}
568
569# C# TnkProblem. g0 = -(x²+y²-1-0.1 cos(16 atan(x/y))). g1 = 2((x-0.5)²+(y-0.5)²)-1.
570def tnk_g(+x: List<&2, F32>) -> List<&2, F32>:
571 +x0 = Util.get_f32(x, 0n)
572 +x1 = Util.get_f32(x, 1n)
573 +circle = F32.sub(
574 F32.sub(F32.add(F32.square(x0), F32.square(x1)), 1.0),
575 F32.mul(0.1, F32.cos(F32.mul(16.0, F32.atan(F32.div(x0, x1)))))
576 )
577 +dx = F32.sub(x0, 0.5)
578 +dy = F32.sub(x1, 0.5)
579 F32.neg(circle) <> [F32.sub(F32.mul(2.0, F32.add(F32.square(dx), F32.square(dy))), 1.0)]
580
581def tnk_score(+x: List<&2, F32>) -> Scored:
582 Scored{Util.get_f32(x, 0n) <> [Util.get_f32(x, 1n)], tnk_g(x)}
583
584# Last objective / 0.6, earlier objectives / 0.5. fuel starts at |f|.
585def c1_w(fuel: Nat, fs: List<&2, F32>, +acc: F32) -> F32:
586 match fuel:
587 case 0n:
588 acc
589 case 1n:
590 match fs:
591 case Nil{}:
592 acc
593 case +h <> rest:
594 F32.add(acc, F32.div(h, 0.6))
595 case 1n+f:
596 match fs:
597 case Nil{}:
598 acc
599 case +h <> rest:
600 c1_w(f, rest, F32.add(acc, F32.div(h, 0.5)))
601
602def c1_g(+fs: List<&2, F32>) -> List<&2, F32>:
603 [F32.sub(c1_w(Util.list_len(F32, fs), fs, 0.0), 1.0)]
604
605def c1_score(+x: List<&2, F32>, +m: Nat) -> Scored:
606 +f = dtlz1_f(x, m)
607 Scored{f, c1_g(f)}
608
609def eval_kind(kind: Family, +x: List<&2, F32>, +m: Nat, +alpha: F32) -> Scored:
610 match kind:
611 case Zdt1{}:
612 plain(zdt1_f(x))
613 case Zdt2{}:
614 plain(zdt2_f(x))
615 case Zdt3{}:
616 plain(zdt3_f(x))
617 case Zdt4{}:
618 plain(zdt4_f(x))
619 case Zdt6{}:
620 plain(zdt6_f(x))
621 case Dtlz1{}:
622 plain(dtlz1_f(x, m))
623 case Dtlz2{}:
624 plain(dtlz2_f(x, m))
625 case Dtlz3{}:
626 plain(dtlz3_f(x, m))
627 case Dtlz4{}:
628 plain(dtlz4_f(x, m, alpha))
629 case Dtlz7{}:
630 plain(dtlz7_f(x, m))
631 case Sphere{}:
632 plain(sphere_f(x))
633 case Ackley{}:
634 plain(ackley_f(x))
635 case Rosenbrock{}:
636 plain(rosenbrock_f(x))
637 case Osy{}:
638 osy_score(x)
639 case Tnk{}:
640 tnk_score(x)
641 case C1Dtlz1{}:
642 c1_score(x, m)
643
644def apply_score(+ind: Ind.Individual, s: Scored) -> Ind.Individual:
645 match s:
646 case Scored{f, g}:
647 Ind.set_constraints(Ind.set_objectives(ind, f), g)
648
649def evaluate(+p: Problem, +ind: Ind.Individual) -> Ind.Individual:
650 apply_score(ind, eval_kind(kind_of(p), Ind.variables(ind), n_obj(p), alpha_of(p)))
651
652# Independent per individual. Mid-split + parallel recurse; same order as cons.
653def evaluate_all(+p: Problem, +xs: List<&2, Ind.Individual>) -> List<&2, Ind.Individual>:
654 Util.map_halves(~Ind.Individual, ~Ind.Individual, ~Problem, ~evaluate, p, xs)