individual.bend

unified-nsga-iii@0.2.2.0 · 146 lines · 26 definitions

1# Individual — C# Unsga3.Algorithm.Individual.
2# Objectives + decision variables + evaluated + tournament bookkeeping
3# (rank / niche / associated ref / perp distance).
4# Constraints are g ≤ 0. `cv` is the sum of the positive parts
5# (RefreshConstraintViolation). Feasible iff cv ≤ 0. Empty g is cv 0,
6# so unconstrained ZDT / DTLZ stay on the Pareto path.
7# `lnk` is false until `stamp` (C# AssociatedReference starts at -1).
8# CV-fill clears it again: those members are not in a niche.
9
10import Base
11
12type Individual is Data:
13  MkIndividual{
14    x: List<&2, F32>
15    f: List<&2, F32>
16    g: List<&2, F32>
17    cv: F32
18    rnk: Nat
19    nic: Nat
20    aref: Nat
21    dist: F32
22    ev: Bool
23    lnk: Bool
24  }
25
26def pos_part(+x: F32) -> F32:
27  Bool.pick(F32, F32.is_gt(x, 0.0), x, 0.0)
28
29# Sum of g_i where g_i > 0. Non-positive parts add nothing.
30def sum_pos(xs: List<&2, F32>) -> F32:
31  match xs:
32    case Nil{}:
33      0.0
34    case +h <> t:
35      F32.add(pos_part(h), sum_pos(t))
36
37# v0 / A/B path: objectives already known; no decision vector.
38# No constraints → cv 0 (feasible).
39def from_objectives(+f: List<&2, F32>) -> Individual:
40  MkIndividual{Nil{}, f, Nil{}, 0.0, 0n, 0n, 0n, 0.0, True{}, False{}}
41
42# Unevaluated candidate: variables set, objectives zeroed (C# ctor).
43# Constraints empty until a problem writes them.
44def from_variables(+x: List<&2, F32>, n_obj: Nat) -> Individual:
45  MkIndividual{x, List.replicate(F32, n_obj, 0.0), Nil{}, 0.0, 0n, 0n, 0n, 0.0, False{}, False{}}
46
47def variables(ind: Individual) -> List<&2, F32>:
48  match ind:
49    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
50      x
51
52def objectives(ind: Individual) -> List<&2, F32>:
53  match ind:
54    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
55      f
56
57def constraints(ind: Individual) -> List<&2, F32>:
58  match ind:
59    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
60      g
61
62def constraint_violation(ind: Individual) -> F32:
63  match ind:
64    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
65      cv
66
67# C# IsFeasible: ConstraintViolation <= 0.
68def feasible(ind: Individual) -> Bool:
69  F32.is_le(constraint_violation(ind), 0.0)
70
71def rank(ind: Individual) -> Nat:
72  match ind:
73    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
74      rnk
75
76def evaluated(ind: Individual) -> Bool:
77  match ind:
78    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
79      ev
80
81def n_obj(ind: Individual) -> Nat:
82  List.length(&2, F32, objectives(ind))
83
84def n_var(ind: Individual) -> Nat:
85  List.length(&2, F32, variables(ind))
86
87def var_at(ind: Individual, i: Nat) -> F32:
88  Maybe.default(&2, F32, List.get(&2, F32, variables(ind), i), 0.0)
89
90def set_var_at(ind: Individual, i: Nat, v: F32) -> Individual:
91  match ind:
92    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
93      MkIndividual{List.set(&2, F32, x, i, v), f, g, cv, rnk, nic, ar, pd, ev, lnk}
94
95def set_evaluated(ind: Individual, ev2: Bool) -> Individual:
96  match ind:
97    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
98      MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev2, lnk}
99
100def niche(ind: Individual) -> Nat:
101  match ind:
102    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
103      nic
104
105def associated_ref(ind: Individual) -> Nat:
106  match ind:
107    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
108      ar
109
110def perp_dist(ind: Individual) -> F32:
111  match ind:
112    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
113      pd
114
115def set_objectives(ind: Individual, +f2: List<&2, F32>) -> Individual:
116  match ind:
117    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
118      MkIndividual{x, f2, g, cv, rnk, nic, ar, pd, True{}, lnk}
119
120# Replace g and recompute cv (sum of positive parts).
121def set_constraints(ind: Individual, +g2: List<&2, F32>) -> Individual:
122  match ind:
123    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
124      MkIndividual{x, f, g2, sum_pos(g2), rnk, nic, ar, pd, ev, lnk}
125
126def set_rank(ind: Individual, rnk2: Nat) -> Individual:
127  match ind:
128    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
129      MkIndividual{x, f, g, cv, rnk2, nic, ar, pd, ev, lnk}
130
131def stamp(ind: Individual, +rnk2: Nat, +nic2: Nat, +aref2: Nat, +dist2: F32) -> Individual:
132  match ind:
133    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
134      MkIndividual{x, f, g, cv, rnk2, nic2, aref2, dist2, ev, True{}}
135
136# C# AssociatedReference starts at -1. `stamp` is the assignment.
137def niche_linked(ind: Individual) -> Bool:
138  match ind:
139    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
140      lnk
141
142# CV fill does not assign a niche (pymoo merges these after survival).
143def clear_niche(ind: Individual) -> Individual:
144  match ind:
145    case MkIndividual{x, f, g, cv, rnk, nic, ar, pd, ev, lnk}:
146      MkIndividual{x, f, g, cv, rnk, 0n, 0n, 0.0, ev, False{}}