coco-experiment 2.8.3__tar.gz → 2.8.4__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.
Files changed (23) hide show
  1. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/PKG-INFO +1 -1
  2. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/src/cocoex/_version.py +1 -1
  3. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/src/cocoex/coco.c +1 -1
  4. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/src/cocoex/interface.pyx +8 -1
  5. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/src/cocoex/noiser.py +48 -23
  6. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/src/cocoex/utilities.py +13 -4
  7. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/.gitignore +0 -0
  8. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/LICENSE +0 -0
  9. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/README.md +0 -0
  10. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/meson.build +0 -0
  11. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/pyproject.toml +0 -0
  12. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/scripts/run-doctest.py +0 -0
  13. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/src/cocoex/__init__.py +0 -0
  14. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/src/cocoex/bare_problem.pyx +0 -0
  15. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/src/cocoex/coco.h +0 -0
  16. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/src/cocoex/download_example.py +0 -0
  17. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/src/cocoex/exceptions.py +0 -0
  18. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/src/cocoex/solvers.py +0 -0
  19. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/tests/bbob2009_testcases.txt +0 -0
  20. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/tests/bbob2009_testcases2.txt +0 -0
  21. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/tests/test_bare_problem.py +0 -0
  22. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/tests/test_regression.py +0 -0
  23. {coco_experiment-2.8.3 → coco_experiment-2.8.4}/tests/test_suite.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: coco-experiment
3
- Version: 2.8.3
3
+ Version: 2.8.4
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/
@@ -1,7 +1,7 @@
1
1
  # file generated by fabricate
2
2
  # Do not change, do not track in version control!
3
3
 
4
- __version__ = "2.8.3"
4
+ __version__ = "2.8.4"
5
5
  version = __version__
6
6
 
7
7
  if __name__ == "__main__":
@@ -31553,7 +31553,7 @@ void coco_archive_free(coco_archive_t *archive) {
31553
31553
  * don't change, don't track in version control!
31554
31554
  */
31555
31555
 
31556
- const char *coco_version = "2.8.3";
31556
+ const char *coco_version = "2.8.4";
31557
31557
  #line 1 "coco_runtime_c.c"
31558
31558
  /**
31559
31559
  * @file coco_runtime_c.c
@@ -83,6 +83,7 @@ cdef extern from "coco.h":
83
83
  void bbob_problem_best_parameter_print(const coco_problem_t *problem)
84
84
  void bbob_biobj_problem_best_parameter_print(const coco_problem_t *problem)
85
85
 
86
+ cdef extern double coco_problem_get_best_value(coco_problem_t *p) # copied from bare_problem.pyx
86
87
 
87
88
  cdef bytes _bstring(s):
88
89
  if type(s) is bytes:
@@ -556,7 +557,7 @@ cdef class Problem:
556
557
  raise RuntimeError("Problem already initialized")
557
558
  if problem == NULL:
558
559
  raise ValueError("in Problem._initialize(problem,...): problem is NULL")
559
- self.problem = problem
560
+ self.problem = problem # should probably be private ._problem?
560
561
  self._problem_index = coco_problem_get_suite_dep_index(self.problem)
561
562
  self._do_free = free
562
563
  self._list_of_observers = []
@@ -783,6 +784,12 @@ cdef class Problem:
783
784
  """
784
785
  assert(self.problem)
785
786
  return bool(coco_problem_final_target_hit(self.problem))
787
+ @property
788
+ def _best_value(self):
789
+ """return best f-value
790
+ """
791
+ assert(self.problem)
792
+ return coco_problem_get_best_value(self.problem)
786
793
  #@property
787
794
  #def final_target_fvalue1(self):
788
795
  # assert(self.problem)
@@ -8,8 +8,12 @@ import json
8
8
  import numpy as np # for checking finite values
9
9
 
10
10
  _frozen_noise = True
11
- math_floor = int
12
11
  parameters_file = 'noiser_parameters.json'
12
+ '''default file name where to save current parameters of `Noisifier`'''
13
+ save_parameters = False
14
+ '''flag whether `Noisifier.__init__` saves noise parameters in file'''
15
+
16
+ math_floor = int
13
17
 
14
18
  def rand(x, i=0):
15
19
  """return a uniform random value seeded with ``x[:2]`` and `i`"""
@@ -20,7 +24,7 @@ def randn(x, i=0):
20
24
  def randc(x, i=0):
21
25
  """return a Cauchy random value seeded with ``x[:2]`` and `i`.
22
26
 
23
- We observe that median |Z| = 1 and p(pi x Z / 2 > a) = 1/a.
27
+ We observe that ``median(|Z|) == 1`` and ``p(pi x Z / 2 > a) == 1/a``.
24
28
  """
25
29
  return _cauchy(1, _seed(x, i))[0]
26
30
 
@@ -71,6 +75,10 @@ class Noisifier:
71
75
  noise generator and the numbers scaled by pi/2 such that P(number > k)
72
76
  equals about 1/k when k >= 5.
73
77
 
78
+ Parameter settings are by default saved to the file indicated by the module
79
+ global variable `cocoex.noiser.parameters_file` if
80
+ ``bool(cocoex.noiser.save_parameters) is True``.
81
+
74
82
  A minimal regression test:
75
83
 
76
84
  >>> import cocoex
@@ -95,7 +103,7 @@ class Noisifier:
95
103
  """
96
104
  p_add_single_default = 0.2
97
105
  def __init__(self, p_add=None, p_subtract=0.0, p_epsilon=0.0, epsilon=1e-4,
98
- rands=(rand, randn, randc)):
106
+ rands=(rand, randn, randc), filename=None):
99
107
  """constructor with 4 optional parameters for the noise model,
100
108
 
101
109
  `p_add`: probability for adding a positive heavy tail random value
@@ -108,6 +116,11 @@ class Noisifier:
108
116
  `p_epsilon`: probability for adding a Gaussian random value
109
117
 
110
118
  `epsilon`: standard deviation of the Gaussian random value
119
+
120
+ `filename`: for saving parameter setting, if not given use module global
121
+ variable `cocoex.noiser.parameters_file`, saving depends on the module
122
+ variable `save_parameters`.
123
+
111
124
  """
112
125
  if p_add is None:
113
126
  if p_subtract == p_epsilon == 0:
@@ -116,15 +129,17 @@ class Noisifier:
116
129
  p_add = 0.0
117
130
  self._params = {k: v for k, v in locals().items() if k != 'self'}
118
131
  if sum(self._params[p] for p in ('p_subtract', 'p_add')) > 1:
119
- warnings.warn("p_subtract={0} + p_add={1} > 1, hence p_add is interpreted"
120
- " as ``1-p_subtract``"
132
+ warnings.warn("p_subtract={0} + p_add={1} > 1, hence p_add" # noqa: UP030
133
+ " is interpreted as ``1-p_subtract``"
121
134
  .format(self._params['p_subtract'], self._params['p_add']))
122
135
  if p_add < 0 or p_subtract < 0 or p_epsilon < 0 or epsilon < 0:
123
- raise ValueError("parameters cannot be negative but were {0}"
124
- .format(self._params))
136
+ raise ValueError("parameters cannot be negative" # noqa: UP030, UP032
137
+ " but were {0}".format(self._params))
125
138
  if p_epsilon > 0 and epsilon == 0:
126
- warnings.warn("p_epsilon = {0} > 0 is not effective because epsilon = 0"
127
- .format(p_epsilon))
139
+ warnings.warn("p_epsilon = {0} > 0 is not effective" # noqa: UP030, UP032
140
+ " because epsilon = 0".format(p_epsilon))
141
+ if save_parameters:
142
+ self.save_parameters()
128
143
 
129
144
  def noisify(self, problem):
130
145
  """wrap `problem` with frozen noise"""
@@ -135,23 +150,19 @@ class Noisifier:
135
150
  def parameters(self):
136
151
  return {k: v for (k, v) in self._params.items() if k.startswith(('p_', 'eps'))}
137
152
 
138
- def _dump_params(self):
139
- with open(parameters_file, 'wt') as fp:
153
+ def save_parameters(self, filename=None):
154
+ """save parameter `dict` to a `json` file"""
155
+ with open(filename or self._params.get('filename')
156
+ or parameters_file, 'wt') as fp:
140
157
  json.dump(self.parameters, fp)
141
158
 
142
- def _load_params(self, filename=parameters_file, warn_errors=(FileNotFoundError,), ignore_errors=()):
143
- try:
144
- with open(parameters_file, 'rt') as fp:
145
- return json.load(fp)
146
- except warn_errors as e:
147
- warnings.warn('NoisifyProblem._load_params raised the exception "{0}"'.format(e))
148
- except ignore_errors:
149
- pass
150
- return {}
159
+ def _set_params(self, filename=None, **kwargs):
160
+ """set parameters from file `filename` or filename passed at
151
161
 
152
- def _set_params(self, filename=parameters_file, **kwargs):
153
- """set parameters from file `filename`"""
154
- self._params.update(self._load_params(filename), **kwargs)
162
+ instantiation or `cocoex.noiser.parameters_file`.
163
+ """
164
+ self._params.update(_read_params(filename or self._params.get('filename')
165
+ or parameters_file), **kwargs)
155
166
 
156
167
  def __getattr__(self, name):
157
168
  """pretend to be a COCO `problem` as passed in `noisify`"""
@@ -211,6 +222,20 @@ class Noisifier:
211
222
  assert np.isfinite(n)
212
223
  return n
213
224
 
225
+
226
+ def _read_params(filename=None,
227
+ warn_errors=(FileNotFoundError,), ignore_errors=()):
228
+ """read parameters from a json file and return a parameters `dict`"""
229
+ try:
230
+ with open(filename or parameters_file, 'rt') as fp:
231
+ return json.load(fp)
232
+ except warn_errors as e:
233
+ warnings.warn('noiser._read_params raised the exception: ' + str(e))
234
+ except ignore_errors:
235
+ pass
236
+ return {}
237
+
238
+
214
239
  _seed_weights = [1.23468, 2.34579] # otherwise, coordinate search would be noisefree
215
240
  _seeds = collections.deque(maxlen=99) # for the record only
216
241
  def _seed(x, i=0):
@@ -600,6 +600,9 @@ class ExperimentRepeater:
600
600
  sweeps until some given budget is exhaused, namely, ``budget_multiplier
601
601
  * dimension``.
602
602
 
603
+ CAVEAT: this works as desired only when all instances of the same problem
604
+ are run in the same batch, as it is the case with `BatchScheduler`.
605
+
603
606
  Example code snippet::
604
607
 
605
608
  [...]
@@ -934,6 +937,9 @@ class ExperimentRepeater:
934
937
  class BatchScheduler:
935
938
  """Facilitate to run a benchmarking experiment in independent batches.
936
939
 
940
+ All instances of the same ``(function, dimension)`` belong to the same
941
+ batch, in order to allow for uniform instance repetitions.
942
+
937
943
  The batch scheduler crucially assumes that in each batch the same
938
944
  problems are given *in the same order* when calling `is_in_batch`.
939
945
 
@@ -953,10 +959,13 @@ class BatchScheduler:
953
959
  ``batch_to_execute in (0,1,2,3)`` to generate the full experimental
954
960
  data.
955
961
 
956
- Details: to get a more even time distribution over all batches, it
957
- seems advisable that the number of functions is not divisible by the
958
- number of batches. That is, 4 (or 6 or 8 or 12) batches is not likely
959
- to be ideal on the `'bbob'` testbed of 24 functions.
962
+ Details: while making the number of functions not divisible by the number of
963
+ batches may sometimes achieve a more even time distribution over all
964
+ batches, in practice, it is advisable to keep each function in a single or a
965
+ few batches as it is enforced by the `BatchScheduler`. Hence, for the 24
966
+ functions of the `'bbob'` testbed, having 48 or 24 or 12 or 8 or 6 or 4
967
+ batches is advisable. Additionally, it can be useful to run the largest
968
+ dimension in a separate launch (with at most 24 batches in this case).
960
969
  """
961
970
  def __init__(self, number_of_batches, batch_to_execute):
962
971
  """distribute over `number_of_batches` batches and execute
File without changes