Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 58 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ The implementation of the two-objective archive is heavily based on the [`bisect


## Releases
- 1.1.0 added possibility of normalization of the indicators by adding `ideal_point` and `weights` methods to the archive
- [1.0.0](https://github.com/CMA-ES/moarchiving/releases/tag/r1.0.0) addition of MOArchive classes for 3 and 4 objectives, as well as a class for handling solutions to constrained problems
- 0.7.0 reimplementation of `BiobjectiveNondominatedSortedList.hypervolume_improvement` by extracting a sublist first.
- 0.6.0 the `infos` attribute is a `list` with corresponding (arbitrary) information, e.g. for keeping the respective solutions.
Expand All @@ -75,7 +76,7 @@ The implementation of the two-objective archive is heavily based on the [`bisect
3. [Accessing solution information](#3-accessing-solution-information)
4. [Adding solutions](#4-adding-solutions)
5. [Archive size](#5-archive-size)
6. [Performance indicators](#6-performance-indicators)
6. [Performance indicators and normalization](#6-performance-indicators-and-normalization)
7. [Contributing hypervolumes](#7-contributing-hypervolumes)
8. [Hypervolume improvement](#8-hypervolume-improvement)
9. [Distance to the Pareto front](#9-distance-to-the-pareto-front)
Expand Down Expand Up @@ -104,7 +105,7 @@ print("points in the 4 objective archive:", list(moa4obj))
points in the 2 objective archive: [[1, 5], [2, 3], [5, 0]]
points in the 3 objective archive: [[3, 3, 0], [2, 2, 1], [1, 2, 3]]
points in the 4 objective archive: [[1, 3, 0, 1], [1, 2, 3, 4]]


MOArchive objects can also be initialized empty.

Expand All @@ -115,10 +116,10 @@ print("points in the empty archive:", list(moa))
```

points in the empty archive: []


### 2. Constrained MOArchive
Constrained MOArchive supports all the functionalities of a non-constrained MOArchive, with the added capability of handling constraints when adding or initializing the archive. In addition to the objective values of a solution, constraint values must be provided in the form of a list or a number. A solution is deemed feasible when all its constraint values are less than or equal to zero.
Constrained MOArchive supports all the functionalities of a non-constrained MOArchive, with the added capability of handling constraints when adding or initializing the archive. In addition to the objective values of a solution, constraint values must be provided in the form of a list or a number. A solution is deemed feasible and added to the archive when all its constraint values are less than or equal to zero.


```python
Expand All @@ -130,7 +131,7 @@ print("points in the archive:", list(cmoa))
```

points in the archive: [[4, 3, 2], [1, 3, 4]]


### 3. Accessing solution information
`archive.infos` is used to get the information on solutions in the archive.
Expand All @@ -144,7 +145,7 @@ print("infos of the constrained archive", cmoa.infos)

infos of the empty archive []
infos of the constrained archive ['c', 'b']


### 4. Adding solutions
Solutions can be added to the MOArchive at any time using the `add` function (for a single solution) or the `add_list` function (for multiple solutions).
Expand All @@ -164,7 +165,7 @@ print("infos:", moa.infos)
infos: ['a']
points: [[3, 2, 1], [2, 2, 2], [1, 2, 3]]
infos: ['b', 'd', 'a']


When adding to the constrained archive, constraint values must be added as well.

Expand All @@ -177,7 +178,7 @@ print("infos:", cmoa.infos)

points: [[4, 3, 2], [3, 3, 3], [1, 3, 4]]
infos: ['c', 'e', 'b']


### 5. Archive size
The MOArchive implements some functionality of a list (in the 2 objective case, it actually extends the `list` class, though this is not the case in 3 and 4 objectives). In particular, it includes the `len` method to get the number of solutions in the archive as well as the `in` keyword to check if a point is in the archive.
Expand All @@ -194,27 +195,46 @@ print("[3, 2, 0] in moa:", [3, 2, 0] in moa)
Length of the archive: 3
[2, 2, 2] in moa: True
[3, 2, 0] in moa: False



### 6. Performance indicators
### 6. Performance indicators and normalization
An archive provides the following performance indicators:
- `hypervolume`
- `hypervolume_plus`, providing additionally the closest distance to the reference area for an empty archive, see [here](https://doi.org/10.1145/3321707.3321852) and [here](https://doi.org/10.1109/TEVC.2022.3210897)
- `hypervolume_plus_constr` (for CMOArchive), based on, but not completely equal to the one defined [here](https://doi.org/10.1016/j.ins.2022.05.106)

Indicators are defined for maximization (the original `hypervolume_plus_constr` indicator is multiplied by -1). When the archive is not empty, all the indicators are positive and have the same value. As the archive does not (yet) support an ideal point, the values of indicators are not normalized.
Indicators are defined for maximization (the original `hypervolume_plus_constr` indicator is multiplied by -1). When the archive is not empty, all the indicators are positive and have the same value. The values of indicators are normalized, if the user specifies the ideal point, which can be done at the initialization using `ideal_point` keyword or later using `ideal_point` method. Custom weights for each dimension can be set in the same way using `weights` keyword or method. The default weights are equal to 1 for all objectives.



```python
# not normalized values
print("Hypervolume of the archive:", moa.hypervolume)
print("Hypervolume plus of the archive:", moa.hypervolume_plus)

# add ideal point
moa.ideal_point([0, 0, 0])
print("Hypervolume of the normalized archive:", moa.hypervolume)

# add also weights
moa.weights([2, 3, 5])
print("Hypervolume of the normalized archive with weights:", moa.hypervolume)
```

Hypervolume of the archive: 12
Hypervolume plus of the archive: 12
Hypervolume of the normalized archive: 0.1875
Hypervolume of the normalized archive with weights: 5.625


When using constrained moarchive, the constraint violations can be normalized as well, if the list of max violations is provided.


```python
cmoa = get_cmo_archive([[1, 2, 3], [4, 4, 2], [3, 3, 3]], [[0, 10], [0.3, 4], [1, 0]],
reference_point=[5, 5, 5], ideal_point=[0, 0, 0], max_g_vals=[1, 10], tau=1)
```

In case of a constrained MOArchive, the `hypervolume_plus_constr` attribute can be accessed as well.


Expand All @@ -224,11 +244,24 @@ print("Hypervolume plus of the constrained archive:", cmoa.hypervolume_plus)
print("Hypervolume plus constr of the constrained archive:", cmoa.hypervolume_plus_constr)
```

Hyperolume of the constrained archive: 14
Hypervolume plus of the constrained archive: 14
Hypervolume plus constr of the constrained archive: 14
Hyperolume of the constrained archive: 0.0
Hypervolume plus of the constrained archive: -inf
Hypervolume plus constr of the constrained archive: -1.7



```python
cmoa.add([6, 6, 6], [0, 0])
print("Hyperolume of the constrained archive:", cmoa.hypervolume)
print("Hypervolume plus of the constrained archive:", cmoa.hypervolume_plus)
print("Hypervolume plus constr of the constrained archive:", cmoa.hypervolume_plus_constr)
```

Hyperolume of the constrained archive: 0.0
Hypervolume plus of the constrained archive: -0.3464101615137755
Hypervolume plus constr of the constrained archive: -0.3464101615137755


### 7. Contributing hypervolumes
The `contributing_hypervolumes` attribute provides a list of hypervolume contributions for each point of the archive. Alternatively, the contribution for a single point can be computed using the `contributing_hypervolume(point)` method.

Expand All @@ -241,11 +274,11 @@ for i, objectives in enumerate(moa):
print("All contributing hypervolumes:", moa.contributing_hypervolumes)
```

contributing hv of point [3, 2, 1] is 2
contributing hv of point [2, 2, 2] is 2
contributing hv of point [1, 2, 3] is 2
All contributing hypervolumes: [Fraction(2, 1), Fraction(2, 1), Fraction(2, 1)]

contributing hv of point [3, 2, 1] is 0.9375
contributing hv of point [2, 2, 2] is 0.9375
contributing hv of point [1, 2, 3] is 0.9375
All contributing hypervolumes: [0.9375, 0.9375, 0.9375]

### 8. Hypervolume improvement
The `hypervolume_improvement(point)` method returns the improvement of the hypervolume if we would add the point to the archive.
Expand All @@ -259,10 +292,10 @@ moa.add(point)
print(f"hypervolume after adding {point}: {moa.hypervolume}")
```

hypervolume before adding [1, 3, 0]: 12
hypervolume improvement of point [1, 3, 0]: 6
hypervolume after adding [1, 3, 0]: 18

hypervolume before adding [1, 3, 0]: 5.625
hypervolume improvement of point [1, 3, 0]: 2.8125
hypervolume after adding [1, 3, 0]: 8.4375

### 9. Distance to the empirical Pareto front
The `distance_to_pareto_front(point)` method returns the distance between the given point and the Pareto front.
Expand All @@ -276,8 +309,8 @@ print("Distance of [3, 2, 2] to pareto front:", moa.distance_to_pareto_front([3,

Current archive: [[1, 3, 0], [3, 2, 1], [2, 2, 2], [1, 2, 3]]
Distance of [3, 2, 1] to pareto front: 0.0
Distance of [3, 2, 2] to pareto front: 1.0

Distance of [3, 2, 2] to pareto front: 0.5

### 10. Enabling or disabling fractions
To avoid loss of precision, fractions are used by default. This can be changed to floats by setting the `hypervolume_final_float_type` and `hypervolume_computation_float_type` function attributes.
Expand All @@ -300,5 +333,3 @@ print(moa3_nofr.hypervolume)

161245156349030777798724819133399/10141204801825835211973625643008
15.899999999999999


Loading