coco-experiment 2.7.1__tar.gz → 2.7.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/PKG-INFO +1 -1
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/src/cocoex/_version.py +1 -1
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/src/cocoex/coco.c +1 -1
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/src/cocoex/noiser.py +49 -23
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/src/cocoex/utilities.py +30 -16
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/.gitignore +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/LICENSE +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/README.md +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/meson.build +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/pyproject.toml +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/scripts/run-doctest.py +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/src/cocoex/__init__.py +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/src/cocoex/bare_problem.pyx +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/src/cocoex/coco.h +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/src/cocoex/exceptions.py +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/src/cocoex/interface.pyx +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/src/cocoex/solvers.py +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/tests/bbob2009_testcases.txt +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/tests/bbob2009_testcases2.txt +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/tests/test_bare_problem.py +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/tests/test_regression.py +0 -0
- {coco_experiment-2.7.1 → coco_experiment-2.7.3}/tests/test_suite.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coco-experiment
|
|
3
|
-
Version: 2.7.
|
|
3
|
+
Version: 2.7.3
|
|
4
4
|
Summary: Benchmarking framework for all types of black-box optimization algorithms.
|
|
5
5
|
Project-URL: Homepage, https://github.com/numbbo/coco-experiment
|
|
6
6
|
Project-URL: Documentation, https://numbbo.github.io/coco-doc/apidocs/cocoex/
|
|
@@ -31526,7 +31526,7 @@ void coco_archive_free(coco_archive_t *archive) {
|
|
|
31526
31526
|
* don't change, don't track in version control!
|
|
31527
31527
|
*/
|
|
31528
31528
|
|
|
31529
|
-
const char *coco_version = "2.7.
|
|
31529
|
+
const char *coco_version = "2.7.3";
|
|
31530
31530
|
#line 1 "coco_runtime_c.c"
|
|
31531
31531
|
/**
|
|
31532
31532
|
* @file coco_runtime_c.c
|
|
@@ -33,12 +33,12 @@ class Noisifier:
|
|
|
33
33
|
- adding a value (leading to bad outliers)
|
|
34
34
|
- adding a small `epsilon` normally distributed noise
|
|
35
35
|
|
|
36
|
-
The noise is frozen in x and y: whether
|
|
37
|
-
|
|
36
|
+
The noise is frozen in x and y: whether the noise is applied to y and
|
|
37
|
+
its value depend both _deterministically_ on the input x.
|
|
38
38
|
|
|
39
|
-
The outlier noise distribution is a Cauchy distribution multiplied
|
|
40
|
-
pi/2, which generates values larger than k with a probability
|
|
41
|
-
close to k
|
|
39
|
+
The outlier noise distribution is a half Cauchy distribution multiplied
|
|
40
|
+
by pi/2, which generates values larger than k with a probability
|
|
41
|
+
awfully close to 1/k when k >= 10.
|
|
42
42
|
|
|
43
43
|
Example::
|
|
44
44
|
|
|
@@ -63,23 +63,41 @@ class Noisifier:
|
|
|
63
63
|
of the original problem.
|
|
64
64
|
|
|
65
65
|
Details: the random number generators can be passed as argument and
|
|
66
|
-
need to obey the interface of `noiser.rand`. ``rands[0]``
|
|
67
|
-
|
|
68
|
-
``abs(rands[2])``
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
about 1/
|
|
66
|
+
need to obey the interface of `noiser.rand`. By default, ``rands[0]``
|
|
67
|
+
is uniform in [0,1] and ``rands[1]`` is Gaussian noise,
|
|
68
|
+
``abs(rands[2])`` and ``abs(rands[-1])`` are used to sample added and
|
|
69
|
+
subtracted noise, respectively. Both are by default the same Cauchy
|
|
70
|
+
noise generator and the numbers scaled by pi/2 such that P(number > k)
|
|
71
|
+
equals about 1/k when k >= 5.
|
|
72
72
|
|
|
73
|
-
See https://github.com/numbbo/coco-experiment/blob/main/build/python/example/example_experiment_complete.py
|
|
73
|
+
See also https://github.com/numbbo/coco-experiment/blob/main/build/python/example/example_experiment_complete.py
|
|
74
74
|
|
|
75
75
|
"""
|
|
76
76
|
def __init__(self, p_add=0.2, p_subtract=0.0, p_epsilon=0, epsilon=1e-4,
|
|
77
77
|
rands=(rand, randn, randc)):
|
|
78
|
+
"""constructor with 4 optional parameters for the noise model,
|
|
79
|
+
|
|
80
|
+
`p_add`: probability for adding a positive heavy tail random value
|
|
81
|
+
making the solution look worse than it is.
|
|
82
|
+
|
|
83
|
+
`p_subtract`: probability for subtracting a positive heavy tail
|
|
84
|
+
random value making the solution look better than it is.
|
|
85
|
+
|
|
86
|
+
`p_epsilon`: probability for adding a Gaussian random value
|
|
87
|
+
|
|
88
|
+
`epsilon`: standard deviation of the Gaussian random value
|
|
89
|
+
"""
|
|
78
90
|
self._params = {k: v for k, v in locals().items() if k != 'self'}
|
|
79
91
|
if sum(self._params[p] for p in ('p_subtract', 'p_add')) > 1:
|
|
80
92
|
warnings.warn("p_subtract={0} + p_add={1} > 1, hence p_add is interpreted"
|
|
81
93
|
" as ``1-p_subtract``"
|
|
82
94
|
.format(self._params['p_subtract'], self._params['p_add']))
|
|
95
|
+
if p_add < 0 or p_subtract < 0 or p_epsilon < 0 or epsilon < 0:
|
|
96
|
+
raise ValueError("parameters cannot be negative but were {0}"
|
|
97
|
+
.format(self._params))
|
|
98
|
+
if p_epsilon > 0 and epsilon == 0:
|
|
99
|
+
warnings.warn("p_epsilon = {0} > 0 is not effective because epsilon = 0"
|
|
100
|
+
.format(p_epsilon))
|
|
83
101
|
|
|
84
102
|
def noisify(self, problem):
|
|
85
103
|
"""wrap `problem` with frozen noise"""
|
|
@@ -113,7 +131,12 @@ class Noisifier:
|
|
|
113
131
|
return getattr(self._problem, name)
|
|
114
132
|
|
|
115
133
|
def __call__(self, x):
|
|
116
|
-
|
|
134
|
+
fval = self._problem(x)
|
|
135
|
+
try: # as quick as hasattr(fval, '__iter__')
|
|
136
|
+
en = enumerate(fval) # multiobjective
|
|
137
|
+
except TypeError:
|
|
138
|
+
return fval + self._fnoise(x) # single objective
|
|
139
|
+
return np.array([f + self._fnoise([x[0] + 1.001 * i, x[1]]) for i, f in en])
|
|
117
140
|
|
|
118
141
|
def constraint(self, x):
|
|
119
142
|
"""return noisy constraint values"""
|
|
@@ -122,11 +145,14 @@ class Noisifier:
|
|
|
122
145
|
constraint[i] += self._cnoise([x[i % 2], c])
|
|
123
146
|
return constraint
|
|
124
147
|
|
|
125
|
-
def
|
|
148
|
+
def rand0(self, x, fac=1):
|
|
149
|
+
"""uniform by default"""
|
|
126
150
|
return self._params['rands'][0](x, fac)
|
|
127
|
-
def
|
|
151
|
+
def rand1(self, x, fac=1):
|
|
152
|
+
"""Gaussian by default"""
|
|
128
153
|
return self._params['rands'][1](x, fac)
|
|
129
|
-
def
|
|
154
|
+
def rand2(self, x, fac=1):
|
|
155
|
+
"""Cauchy by default"""
|
|
130
156
|
return self._params['rands'][2](x, fac)
|
|
131
157
|
|
|
132
158
|
def _cnoise(self, x):
|
|
@@ -135,24 +161,24 @@ class Noisifier:
|
|
|
135
161
|
def _fnoise(self, x):
|
|
136
162
|
"""x-dependent abs Cauchy noise with median pi/2"""
|
|
137
163
|
n = 0 # no noise by default
|
|
138
|
-
if self._params['p_epsilon'] > 0 and self.
|
|
139
|
-
n = self._params['epsilon'] * self.
|
|
164
|
+
if self._params['p_epsilon'] > 0 and self.rand0(x, 3) < self._params['p_epsilon']:
|
|
165
|
+
n = self._params['epsilon'] * self.rand1(x)
|
|
140
166
|
assert np.isfinite(n)
|
|
141
167
|
if all(self._params[p] <= 0 for p in ('p_add', 'p_subtract')):
|
|
142
168
|
return n
|
|
143
|
-
r = self.
|
|
169
|
+
r = self.rand0(x, 2) # a uniform random number
|
|
144
170
|
assert 0 <= r <= 1, r
|
|
145
171
|
i = 4
|
|
146
|
-
for
|
|
147
|
-
|
|
172
|
+
for p, fac, irand in [(self._params['p_add'], 1.5707963267948966, 2),
|
|
173
|
+
(self._params['p_subtract'], -1.5707963267948966, -1)]:
|
|
148
174
|
if r < p:
|
|
149
175
|
assert p > 0, (r, p)
|
|
150
176
|
nn = self._params['rands'][irand](x, i)
|
|
151
177
|
if nn < 0:
|
|
152
178
|
nn *= -1
|
|
153
|
-
return n +
|
|
179
|
+
return n + fac * nn
|
|
154
180
|
# self.randn(x, 2) / self.randn(x, 12)
|
|
155
|
-
# was: return n + s * 2 * r / self._params[p] / self.
|
|
181
|
+
# was: return n + s * 2 * r / self._params[p] / self.rand0(x)
|
|
156
182
|
r = 1 - r # prevent sampling another r
|
|
157
183
|
i += 1 # not clear why we need to change i
|
|
158
184
|
assert np.isfinite(n)
|
|
@@ -647,8 +647,9 @@ class ExperimentRepeater:
|
|
|
647
647
|
When problem instances are repeated in a single suite, they may be
|
|
648
648
|
*partially* skipped *after* the first full sweep. That is, the
|
|
649
649
|
configuration ``1-5,1-5,1-5`` can also lead to four trials of each
|
|
650
|
-
instance 1-5
|
|
651
|
-
of times
|
|
650
|
+
instance 1-5 of some problems when all instances have been repeated the
|
|
651
|
+
same number of times and have enough successes or the budget is
|
|
652
|
+
exhaused.
|
|
652
653
|
|
|
653
654
|
>>> import cocoex # some not very meaningful testing
|
|
654
655
|
>>> repeater = cocoex.ExperimentRepeater(2)
|
|
@@ -658,18 +659,31 @@ class ExperimentRepeater:
|
|
|
658
659
|
>>> assert len(repeater.evaluations((1, 2))) == 0
|
|
659
660
|
|
|
660
661
|
"""
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
662
|
+
min_successes_default = 11
|
|
663
|
+
max_sweeps_default = 20
|
|
664
|
+
def __init__(self, budget_multiplier, min_successes=None, max_sweeps=None):
|
|
665
|
+
"""constructor for `ExperimentRepeater`.
|
|
666
|
+
|
|
667
|
+
The "timeout" budget is computed as ``budget_multiplier`` times
|
|
668
|
+
problem dimension.
|
|
669
|
+
|
|
670
|
+
``min_successes=11`` is default and provokes at least three sweeps
|
|
671
|
+
when the suite has (only) 5 instance and the `budget_multiplier` is
|
|
672
|
+
large enough such that the algorithm terminates the second sweep
|
|
673
|
+
before the overall budget is exhausted. This would emulate the 3 x
|
|
674
|
+
1-5 instance-setup from BBOB 2009, however the choice of the
|
|
675
|
+
initial solution still slightly differs.
|
|
676
|
+
|
|
677
|
+
``max_sweeps`` is the limit number of repititions for each
|
|
678
|
+
instance, by default 20. To have a limit is in particular useful
|
|
679
|
+
when the budget is large but an algorithm terminates very quickly
|
|
680
|
+
and invariably unsuccessfully.
|
|
669
681
|
"""
|
|
670
682
|
self.params = {k: v for k, v in locals().items() if k != 'self'}
|
|
671
|
-
self.min_successes =
|
|
672
|
-
|
|
683
|
+
self.min_successes = ExperimentRepeater.min_successes_default if (
|
|
684
|
+
min_successes is None) else min_successes
|
|
685
|
+
self.max_sweeps = ExperimentRepeater.max_sweeps_default if (
|
|
686
|
+
max_sweeps is None) else max_sweeps # useful on F7
|
|
673
687
|
self._dimension_offset = 0
|
|
674
688
|
'''budget = (dimension + offset) * budget_multiplier'''
|
|
675
689
|
self._data = _collections.OrderedDict()
|
|
@@ -848,7 +862,7 @@ class ExperimentRepeater:
|
|
|
848
862
|
it cannot account for problems that have not yet been run once.
|
|
849
863
|
|
|
850
864
|
Calling ``done()`` increments the sweep counter iff it returns
|
|
851
|
-
`False`, the default for ``max_sweeps`` is ``
|
|
865
|
+
`False`, the default for ``max_sweeps`` is ``20``. The attribute
|
|
852
866
|
can be directly reassigned at any time.
|
|
853
867
|
|
|
854
868
|
See also: `remaining_problems`
|
|
@@ -861,11 +875,11 @@ class ExperimentRepeater:
|
|
|
861
875
|
return True
|
|
862
876
|
if message: # prints nothing when no data are found
|
|
863
877
|
print(self.message_sweep(), end='') # indicates "sequence of problems" case
|
|
864
|
-
self._sweeps += 1 # the sweep number to come
|
|
865
|
-
done = self._sweeps
|
|
878
|
+
self._sweeps += 1 # the sweep number to come, needed in remaining_problems()
|
|
879
|
+
done = self._sweeps > self.max_sweeps or (
|
|
866
880
|
self._sweeps > 1 and len(self._data) == 0) or (
|
|
867
881
|
self.n_problem_instances() > 0 and not self.remaining_problems())
|
|
868
|
-
self._sweeps -= done #
|
|
882
|
+
self._sweeps -= done # revert increment when done is True
|
|
869
883
|
return done
|
|
870
884
|
def remaining_problems(self, suite=None):
|
|
871
885
|
"""return `list` of (probably) remaining problem instances to run.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|