problems.bend

unified-nsga-iii@0.1.2.0 · 180 lines · 0 definitions

1# Named problems — C# Unsga3.Problems Zdt1 / Zdt2 / Dtlz2.
2# Bounds + Evaluate match the attached C# IProblem / problem files.
3# Minimize. Unconstrained (NumberOfConstraints = 0).
4
5import Base
6import unified-nsga-iii@0.1.2.0/individual.bend as Ind
7import unified-nsga-iii@0.1.2.0/bounds.bend as Bounds
8import unified-nsga-iii@0.1.2.0/util.bend as Util
9
10type Family is Data:
11  Zdt1{}
12  Zdt2{}
13  Dtlz2{}
14
15type Problem is Data:
16  MkProblem{
17    kind: Family
18    box: Bounds.Box
19  }
20
21def box_of(p: Problem) -> Bounds.Box:
22  match p:
23    case MkProblem{kind, box}:
24      box
25
26def kind_of(p: Problem) -> Family:
27  match p:
28    case MkProblem{kind, box}:
29      kind
30
31def n_obj(p: Problem) -> Nat:
32  Bounds.n_obj(box_of(p))
33
34def n_var(p: Problem) -> Nat:
35  Bounds.n_var(box_of(p))
36
37# ZDT1 / ZDT2: n variables (C# default 30), 2 objectives, x ∈ [0,1]^n.
38def zdt1(n: Nat) -> Problem:
39  MkProblem{Zdt1{}, Bounds.unit_n(n, 2n)}
40
41def zdt2(n: Nat) -> Problem:
42  MkProblem{Zdt2{}, Bounds.unit_n(n, 2n)}
43
44# n = M + k - 1 (C# Dtlz2Problem).
45def dtlz_n(m: Nat, k: Nat) -> Nat:
46  match m:
47    case 0n:
48      k
49    case 1n+pm:
50      match k:
51        case 0n:
52          pm
53        case 1n+pk:
54          Nat.add(pm, 1n+pk)
55
56# DTLZ2: C# default M=3, k=10 ⇒ n=12, x ∈ [0,1]^n.
57def dtlz2(+m: Nat, k: Nat) -> Problem:
58  MkProblem{Dtlz2{}, Bounds.unit_n(dtlz_n(m, k), m)}
59
60def sum_from(xs: List<&2, F32>) -> F32:
61  match xs:
62    case Nil{}:
63      0.0
64    case h <> t:
65      F32.add(h, sum_from(t))
66
67def sum_tail(xs: List<&2, F32>) -> F32:
68  match xs:
69    case Nil{}:
70      0.0
71    case h <> t:
72      sum_from(t)
73
74def zdt_den(n: Nat) -> F32:
75  match n:
76    case 0n:
77      1.0
78    case 1n:
79      1.0
80    case 1n+p:
81      F32.from_nat(p)
82
83# C# Zdt1Problem.GLinear: 1 + 9 * sum(x[1..]) / (n - 1).
84def zdt_g(+x: List<&2, F32>) -> F32:
85  +n = Util.list_len(F32, x)
86  F32.add(1.0, F32.div(F32.mul(9.0, sum_tail(x)), zdt_den(n)))
87
88def zdt1_f(+x: List<&2, F32>) -> List<&2, F32>:
89  +x0 = Util.get_f32(x, 0n)
90  +g = zdt_g(x)
91  x0 <> [F32.mul(g, F32.sub(1.0, F32.sqrt(F32.div(x0, g))))]
92
93def zdt2_f(+x: List<&2, F32>) -> List<&2, F32>:
94  +x0 = Util.get_f32(x, 0n)
95  +g = zdt_g(x)
96  +r = F32.div(x0, g)
97  x0 <> [F32.mul(g, F32.sub(1.0, F32.mul(r, r)))]
98
99def pred(n: Nat) -> Nat:
100  match n:
101    case 0n:
102      0n
103    case 1n+p:
104      p
105
106def sum_sq_half(xs: List<&2, F32>) -> F32:
107  match xs:
108    case Nil{}:
109      0.0
110    case h <> t:
111      F32.add(F32.square(F32.sub(h, 0.5)), sum_sq_half(t))
112
113# C# DtlzHelper.GDtlz2: sum (x[i] - 0.5)^2 for i >= M-1.
114def dtlz2_g(+x: List<&2, F32>, m: Nat) -> F32:
115  sum_sq_half(List.drop(&2, F32, x, pred(m)))
116
117def half_pi() -> F32:
118  F32.div(F32.pi(), 2.0)
119
120def prod_cos.go(+x: List<&2, F32>, fuel: Nat, +i: Nat, acc: F32) -> F32:
121  match fuel:
122    case 0n:
123      acc
124    case 1n+f:
125      prod_cos.go(
126        x,
127        f,
128        1n+i,
129        F32.mul(acc, F32.cos(F32.mul(Util.get_f32(x, i), half_pi())))
130      )
131
132def prod_cos(+x: List<&2, F32>, n: Nat) -> F32:
133  prod_cos.go(x, n, 0n, 1.0)
134
135def dtlz2_sin(+x: List<&2, F32>, +m: Nat, +i: Nat) -> F32:
136  F32.sin(F32.mul(Util.get_f32(x, pred(Nat.sub(m, i))), half_pi()))
137
138def dtlz2_fi.tail(+x: List<&2, F32>, +m: Nat, +g: F32, +i: Nat, +body: F32, first: Bool) -> F32:
139  match first:
140    case True{}:
141      body
142    case False{}:
143      F32.mul(body, dtlz2_sin(x, m, i))
144
145# C# Dtlz2Problem: (1+g) * prod_{j<M-i-1} cos(x[j] π/2) [* sin(x[M-i-1] π/2) if i>0].
146def dtlz2_fi(+x: List<&2, F32>, +m: Nat, +g: F32, +i: Nat) -> F32:
147  dtlz2_fi.tail(
148    x,
149    m,
150    g,
151    i,
152    F32.mul(F32.add(1.0, g), prod_cos(x, pred(Nat.sub(m, i)))),
153    Nat.is_eq(i, 0n)
154  )
155
156def dtlz2_fs.go(+x: List<&2, F32>, +m: Nat, +g: F32, fuel: Nat, +i: Nat) -> List<&2, F32>:
157  match fuel:
158    case 0n:
159      Nil{}
160    case 1n+f:
161      dtlz2_fi(x, m, g, i) <> dtlz2_fs.go(x, m, g, f, 1n+i)
162
163def dtlz2_f(+x: List<&2, F32>, +m: Nat) -> List<&2, F32>:
164  dtlz2_fs.go(x, m, dtlz2_g(x, m), m, 0n)
165
166def eval_kind(kind: Family, +x: List<&2, F32>, +m: Nat) -> List<&2, F32>:
167  match kind:
168    case Zdt1{}:
169      zdt1_f(x)
170    case Zdt2{}:
171      zdt2_f(x)
172    case Dtlz2{}:
173      dtlz2_f(x, m)
174
175def evaluate(+p: Problem, +ind: Ind.Individual) -> Ind.Individual:
176  Ind.set_objectives(ind, eval_kind(kind_of(p), Ind.variables(ind), n_obj(p)))
177
178# Independent per individual. Mid-split + parallel recurse; same order as cons.
179def evaluate_all(+p: Problem, +xs: List<&2, Ind.Individual>) -> List<&2, Ind.Individual>:
180  Util.map_halves(~Ind.Individual, ~Ind.Individual, ~Problem, ~evaluate, p, xs)