Skip to content

Commit 098f158

Browse files
committed
fix(dra): stabilize Pareto front with neighborhood spreading and dampened utility
1 parent a38765d commit 098f158

1 file changed

Lines changed: 13 additions & 9 deletions

File tree

src/portfolio/moead_dra.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,7 @@ def generate_pareto_front(
6565
else:
6666
# 30% of population is updated in focused mode
6767
size = max(1, int(0.3 * num_points))
68-
selection = self._tournament_selection(
69-
utility, size, weight_vectors
70-
)
68+
selection = self._tournament_selection(utility, size, weight_vectors)
7169

7270
for i in selection:
7371
nb_idx = neighbors[i]
@@ -90,12 +88,14 @@ def generate_pareto_front(
9088
off_fn = self._normalise(off_f)
9189

9290
# Update neighbors using shared logic
91+
# For DRA, we use nr = T (full neighborhood) to spread progress
92+
# and smooth out the front, since fewer parents are updated.
9393
self._update_neighborhood(
9494
offspring,
9595
off_f,
9696
off_fn,
9797
nb_idx,
98-
nr,
98+
T,
9999
weight_vectors,
100100
population,
101101
f_phys,
@@ -124,10 +124,14 @@ def generate_pareto_front(
124124

125125
for k in range(num_points):
126126
if delta[k] > 0.0001:
127-
utility[k] = 1.0
127+
# Dampened success: Blend new utility (1.0) with old
128+
utility[k] = 0.9 * utility[k] + 0.1 * 1.0
128129
else:
129-
# Slightly slower decay (0.98) and lower threshold
130-
utility[k] = (0.98 + 0.02 * delta[k] / 0.0001) * utility[k]
130+
# Slightly slower decay (0.99) for stability
131+
utility[k] = (0.99 + 0.01 * delta[k] / 0.0001) * utility[k]
132+
133+
# Ensure a minimum utility so no subproblem is permanently ignored
134+
utility[k] = max(utility[k], 0.01)
131135

132136
old_g = new_g
133137

@@ -145,15 +149,15 @@ def generate_pareto_front(
145149
def _tournament_selection(self, utility, size, weight_vectors):
146150
num_points = len(utility)
147151
selected = []
148-
152+
149153
# 1. 90% Selection based on utility (Tournament)
150154
# Reduced tournament size (5) for better exploration
151155
n_tournament = int(0.9 * size)
152156
for _ in range(n_tournament):
153157
candidates = np.random.choice(num_points, 5, replace=False)
154158
best = candidates[np.argmax(utility[candidates])]
155159
selected.append(best)
156-
160+
157161
# 2. 10% Pure Random Selection to prevent local optima
158162
n_random = size - n_tournament
159163
if n_random > 0:

0 commit comments

Comments
 (0)