Skip to content

Commit 8beca49

Browse files
committed
impelment comments
1 parent e2cd177 commit 8beca49

File tree

1 file changed

+55
-3
lines changed

1 file changed

+55
-3
lines changed

promptolution/optimizers/capoeira.py

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ def _step(self) -> List[Prompt]:
147147
return self.prompts
148148

149149
def _do_intensification(self, challenger: Prompt) -> None:
150+
if challenger in self.incumbents:
151+
return
152+
if challenger in self.non_incumbents:
153+
# remove from non-incumbents to re-evaluate
154+
self.non_incumbents.remove(challenger)
155+
150156
common_blocks = self._get_common_blocks(self.incumbents)
151157

152158
# bootstrap if no common blocks yet
@@ -330,8 +336,9 @@ def _select_survivors(self) -> None:
330336
dists = self._calculate_crowding_distance(worst_front_vecs)
331337

332338
# Find index relative to the worst front list
333-
local_worst_idx = int(np.argmin(dists))
334-
# Map back to the main challenger list index
339+
min_dist = np.min(dists)
340+
tied_indices = np.where(dists == min_dist)[0]
341+
local_worst_idx = np.random.choice(tied_indices)
335342
victim_idx = worst_front_indices[local_worst_idx]
336343

337344
self.non_incumbents.pop(victim_idx)
@@ -369,12 +376,52 @@ def _select_parent_from_pool(self, selection_pool: List[Prompt]) -> Prompt:
369376
if p2 in self.incumbents:
370377
return p2
371378

379+
# both are non-incumbents
380+
blocks_map = self.task.get_evaluated_blocks([p1, p2])
381+
blocks1 = blocks_map.get(str(p1), set())
382+
blocks2 = blocks_map.get(str(p2), set())
383+
384+
if blocks1 == blocks2: # both evaluated on same blocks
385+
# use NDS + Crowding Distance
386+
self.task.set_block_idx(list(sorted(blocks1)))
387+
res = self.task.evaluate([p1, p2], self.predictor)
388+
# check if dominated
389+
vecs = self._get_objective_vectors(res)
390+
if self._is_dominated(vecs[0], vecs[1]):
391+
return p2
392+
if self._is_dominated(vecs[1], vecs[0]):
393+
return p1
394+
# tie-breaker: crowding distance
395+
distances = self._calculate_crowding_distance(vecs)
396+
if distances[0] > distances[1]:
397+
return p1
398+
if distances[1] > distances[0]:
399+
return p2
400+
401+
# same crowding distance: random
402+
403+
# use weaker dominance definition
404+
# eval on common blocks only
405+
common_blocks = blocks1 & blocks2
406+
if common_blocks:
407+
self.task.set_block_idx(list(sorted(common_blocks)))
408+
res = self.task.evaluate([p1, p2], self.predictor)
409+
vecs = self._get_objective_vectors(res)
410+
411+
if self._is_weakly_dominated(vecs[0], vecs[1]):
412+
return p2
413+
if self._is_weakly_dominated(vecs[1], vecs[0]):
414+
return p1
415+
372416
return random.choice((p1, p2))
373417

374418

375419
def _pick_incumbent_by_crowding(self, p1: Prompt, p2: Prompt) -> Prompt:
376420
"""Break incumbent ties using crowding distance over common evaluated blocks."""
377-
res = self.task.evaluate(self.incumbents, self.predictor, eval_strategy="evaluated")
421+
common_blocks = self._get_common_blocks([p1, p2])
422+
if common_blocks:
423+
self.task.set_block_idx(common_blocks)
424+
res = self.task.evaluate(self.incumbents, self.predictor)
378425
inc_vectors = self._get_objective_vectors(res)
379426
inc_distances = self._calculate_crowding_distance(inc_vectors)
380427

@@ -430,6 +477,11 @@ def _non_dominated_sort(obj_vectors: np.ndarray) -> List[List[int]]:
430477
def _is_dominated(vec1, vec2):
431478
"""Returns True if vec2 dominates vec1 in a maximize-all setting."""
432479
return np.all(vec2 >= vec1) and np.any(vec2 > vec1)
480+
481+
@staticmethod
482+
def _is_weakly_dominated(vec1, vec2):
483+
"""Returns True if vec2 weakly dominates vec1 in a maximize-all setting."""
484+
return np.all(vec2 >= vec1)
433485

434486
@staticmethod
435487
def _calculate_crowding_distance(obj_vectors: np.ndarray) -> np.ndarray:

0 commit comments

Comments
 (0)