Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix overflow errors uncovered by Coverage-guided Fuzzing. #104

Merged
merged 5 commits into from
Apr 10, 2021
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@ jobs:
architecture: x64
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools numpy
python -m pip install --upgrade pip setuptools numpy hypothesis
pip install --progress-bar off .
- run: python -m unittest
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ __pycache__/
.eggs/
*.egg-info/
.tox/
.hypothesis

tmp/
benchmark/*.json
Expand Down
13 changes: 11 additions & 2 deletions cmaes/_cma.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@


_EPS = 1e-8
_MEAN_MAX = 1e32
_SIGMA_MAX = 1e32


Expand Down Expand Up @@ -78,6 +79,10 @@ def __init__(
):
assert sigma > 0, "sigma must be non-zero positive value"

assert np.all(
np.abs(mean) < _MEAN_MAX
), f"Abs of all elements of mean vector must be less than {_MEAN_MAX}"

n_dim = len(mean)
assert n_dim > 1, "The dimension of mean must be larger than 1"

Expand Down Expand Up @@ -280,8 +285,12 @@ def _repair_infeasible_params(self, param: np.ndarray) -> np.ndarray:

def tell(self, solutions: List[Tuple[np.ndarray, float]]) -> None:
"""Tell evaluation values"""
if len(solutions) != self._popsize:
raise ValueError("Must tell popsize-length solutions.")

assert len(solutions) == self._popsize, "Must tell popsize-length solutions."
for s in solutions:
assert np.all(
np.abs(s[0]) < _MEAN_MAX
), f"Abs of all param values must be less than {_MEAN_MAX} to avoid overflow errors"

self._g += 1
solutions.sort(key=lambda s: s[1])
Expand Down
3 changes: 3 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ numpy>=1.20.0
matplotlib
scipy

# tests
hypothesis

# lint
mypy
flake8
Expand Down
35 changes: 35 additions & 0 deletions tests/test_fuzzing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import hypothesis.extra.numpy as npst
import unittest
from hypothesis import given, strategies as st

from cmaes import CMA


class TestFuzzing(unittest.TestCase):
@given(
data=st.data(),
)
def test_cma_tell(self, data):
dim = data.draw(st.integers(min_value=2, max_value=100))
mean = data.draw(npst.arrays(dtype=float, shape=dim))
sigma = data.draw(st.floats(min_value=1e-16))
n_iterations = data.draw(st.integers(min_value=1))
try:
optimizer = CMA(mean, sigma)
except AssertionError:
return
popsize = optimizer.population_size
for _ in range(n_iterations):
tell_solutions = data.draw(
st.lists(
st.tuples(npst.arrays(dtype=float, shape=dim), st.floats()),
min_size=popsize,
max_size=popsize,
)
)
optimizer.ask()
try:
optimizer.tell(tell_solutions)
except AssertionError:
return
optimizer.ask()