Skip to content

Commit

Permalink
Set novelty to the threshold when ProximityArchive is empty (#479)
Browse files Browse the repository at this point in the history
## Description

<!-- Provide a brief description of the PR's purpose here. -->

Previously, we returned inf novelty when the ProximityArchive was empty.
However, this can cause issues in code that expects ranking values to be
finite values, such as in `CMAEvolutionStrategy.check_stop`.
Functionally, this value works just as well as inf because it shows that
the solutions had enough novelty to be added to the archive. Strictly
speaking, since the archive is empty in this case, the novelty is
undefined, so there are many values that would work.

## Status

- [x] I have read the guidelines in

[CONTRIBUTING.md](https://github.com/icaros-usc/pyribs/blob/master/CONTRIBUTING.md)
- [x] I have formatted my code using `yapf`
- [x] I have tested my code by running `pytest`
- [x] I have linted my code with `pylint`
- [x] I have added a one-line description of my change to the changelog
in
      `HISTORY.md`
- [x] This PR is ready to go
  • Loading branch information
btjanaka authored Jul 2, 2024
1 parent 21ddf78 commit eb5471e
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 10 deletions.
2 changes: 1 addition & 1 deletion HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

- Add NoveltyRanker for novelty search ({pr}`477`)
- Add proximity_archive_plot for visualizing ProximityArchive ({pr}`476`)
- Add ProximityArchive for novelty search ({pr}`472`)
- Add ProximityArchive for novelty search ({pr}`472`, {pr}`479`)
- Support diversity optimization in Scheduler.tell ({pr}`473`)
- Allow specifying separate dtypes for solution, objective, and measures
({pr}`471`)
Expand Down
11 changes: 5 additions & 6 deletions ribs/archives/_proximity_archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,9 @@ def add(self, solution, objective, measures, **fields):
- ``"novelty"`` (:class:`numpy.ndarray` of :attr:`dtypes`
["measures"]): The computed novelty of the solutions passed in. If
there were no solutions to compute novelty with respect to (e.g.,
the archive was empty), the novelty is set to infinity
(``numpy.inf``).
there were no solutions to compute novelty with respect to (i.e.,
the archive was empty), the novelty is set to the
:attr:`novelty_threshold`.
Raises:
ValueError: The array arguments do not match their specified shapes.
Expand All @@ -271,9 +271,8 @@ def add(self, solution, objective, measures, **fields):
# If there are no neighbors for computing nearest neighbors, there
# is infinite novelty and all solutions are added.
novelty = np.full(len(data["measures"]),
np.inf,
self.novelty_threshold,
dtype=self.dtypes["measures"])
eligible = np.ones(len(data["measures"]), dtype=bool)
else:
# Compute nearest neighbors.
k_neighbors = min(len(self), self.k_neighbors)
Expand All @@ -283,8 +282,8 @@ def add(self, solution, objective, measures, **fields):
dists = dists[:, None] if k_neighbors == 1 else dists

novelty = np.mean(dists, axis=1)
eligible = novelty >= self.novelty_threshold

eligible = novelty >= self.novelty_threshold
n_eligible = np.sum(eligible)
new_size = len(self) + n_eligible

Expand Down
6 changes: 3 additions & 3 deletions tests/archives/proximity_archive_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def test_add_single(data, use_list, add_mode):
# Objective should default to 0.0.
assert_archive_elite(data.archive, data.solution, 0.0, data.measures)
assert add_info["status"] == AddStatus.NEW
assert add_info["novelty"] == np.inf
assert add_info["novelty"] == data.archive.novelty_threshold


def test_add_single_after_clear(data):
Expand All @@ -199,14 +199,14 @@ def test_add_single_after_clear(data):
add_info = data.archive.add_single(data.solution, None, data.measures)

assert add_info["status"] == 2
assert add_info["novelty"] == np.inf
assert add_info["novelty"] == data.archive.novelty_threshold

data.archive.clear()

add_info = data.archive.add_single(data.solution, None, data.measures)

assert add_info["status"] == 2
assert add_info["novelty"] == np.inf
assert add_info["novelty"] == data.archive.novelty_threshold


def test_add_novel_solution():
Expand Down

0 comments on commit eb5471e

Please sign in to comment.