Suite of benchmark problems.
Input arguments to Suite
are name: str
, instance: str
, options: str
,
and passed to the respective C code (see coco.h
).
>>> import cocoex as ex >>> suite = ex.Suite("bbob", "", "") >>> f = suite.next_problem() >>> assert f.number_of_objectives == 1 >>> assert f.evaluations == 0 >>> print("f([1,2]) = %.11f" % f([1,2])) f([1,2]) = 90.00369408000 >>> assert f.evaluations == 1
Sweeping through all problems is as simple as:
>>> import cocoex as ex >>> suite = ex.Suite("bbob-biobj", "", "") >>> observer = ex.Observer("bbob-biobj", "result_folder:doctest") >>> for fun in suite: ... if fun.index == 0: ... print("Number of objectives %d, %d, %d" % ... (fun.number_of_objectives, ... suite.number_of_objectives[0], ... suite.number_of_objectives[-1])) ... fun.observe_with(observer) ... assert fun.evaluations == 0 ... assert fun.number_of_objectives == suite.number_of_objectives[0] ... # run run run using fun # doctest: +ELLIPSIS Number of objectives 2, 2, 2...
In the example, an observer was added to produce output data for the COCO post-processing.
The following example runs the entire bbob2009 benchmark suite on random search:
>>> import numpy as np >>> from cocoex import Suite, Observer ... >>> MAX_FE = 22 # max f-evaluations >>> def random_search(f, lb, ub, m): # don't use m >> 1e5 with this implementation ... candidates = lb + (ub - lb) * np.random.rand(m, len(lb)) ... return candidates[np.argmin([f(x) for x in candidates])] ... >>> solver = random_search >>> suite = Suite("bbob", "year:2009", "") >>> observer = Observer("bbob", ... "result_folder: %s_on_%s" % (solver.__name__, "bbob2009")) >>> for fun in suite: ... assert fun.evaluations == 0 ... if fun.dimension >= 10: ... break ... print('Current problem index = %d' % fun.index) ... fun.observe_with(observer) ... assert fun.evaluations == 0 ... solver(fun, fun.lower_bounds, fun.upper_bounds, MAX_FE) ... # data should be now in the "exdata/random_search_on_bbob2009" folder ... assert fun.evaluations == MAX_FE # depends on the solver ... # doctest: +ELLIPSIS Current problem index = 0... >>> # >>> # Exactly the same using another looping technique: >>> for id in suite.ids(): ... fun = suite.get_problem(id, observer) ... _ = solver(fun, fun.lower_bounds, fun.upper_bounds, MAX_FE) ... print("Evaluations on %s: %d" % (fun.name, fun.evaluations)) ... fun.free() # this is absolutely necessary here ... # doctest: +ELLIPSIS Evaluations on ...
We can select a single function, say BBOB f9 in 20D, of a given suite like:
>>> import cocoex as ex >>> suite = ex.Suite("bbob", "", "dimensions:20 instance_indices:1") >>> len(suite) 24 >>> f9 = suite.get_problem(8) >>> x = f9.initial_solution # a copy of a feasible point >>> all(x == 0) True
See module attribute cocoex.known_suite_names
for known suite names:
>>> import cocoex as ex >>> for suite_name in ex.known_suite_names: ... suite = ex.Suite(suite_name, "", "") ... print(suite.dimensions) ... for f in suite: ... assert f.dimension in suite.dimensions ... assert f.evaluations == 0 ... # doctest: +ELLIPSIS [2, 3, 5, 10, 20, 40]...
See file example_experiment.py
for a full example use case.
Details: depending on the benchmark suite and observer, only one problem can
be open at a time. Using get_problem
without free
or mixing the use of
next_problem
and get_problem
may not be possible. For example, in this
case the "bbob" observer is known to lead to a crash of the Python
interpreter.
See also Observer
and example_experiment.py
.
Method | __getitem__ |
self[i] is a synonym for self.get_problem(i) , see get_problem |
Method | __init__ |
suite_instance and suite_options can be empty strings. |
Method | find |
has been renamed to ids |
Method | free |
free underlying C structures |
Method | get |
return a Problem instance, by default unobserved, using id: str or index (where id: int) to identify the desired problem. |
Method | get |
return a Problem instance, by default unobserved, using function, dimension and instance to identify the desired problem. |
Method | ids |
ids(*id_snippets, get_problem=False, verbose=False) return all problem IDs that contain all of the id_snippets . |
Method | next |
return the "next" problem in this Suite . |
Method | reset |
reset to original state, affecting next_problem() , current_problem , current_index |
Property | current |
index in the enumerator of all problems in this suite. |
Property | current |
current "open/active" problem to be benchmarked |
Property | dimensions |
list of problem dimensions occuring at least once in this Suite |
Property | indices |
list of all problem indices, deprecated. |
Property | info |
Undocumented |
Property | instance |
instance of this suite as used to instantiate the suite via Suite(name, instance, ...) |
Property | name |
name of this suite as used to instantiate the suite via Suite(name, ...) |
Property | number |
list of number of objectives occuring in this Suite |
Property | options |
options for this suite as used to instantiate the suite via Suite(name, instance, options) |
Property | problem |
list of problem names in this Suite , see also ids |
return a Problem
instance, by default unobserved, using id: str
or index (where id: int) to identify the desired problem.
All values between zero and len(self) - 1
are valid index values:
>>> import cocoex as ex >>> suite = ex.Suite("bbob-biobj", "", "") >>> for index in range(len(suite)): ... problem = suite.get_problem(index) ... # work work work using problem ... problem.free()
A shortcut for suite.get_problem(index)
is suite[index]
, they are
synonym.
- Details:
- Here an
index
takes values between 0 andlen(self) - 1
and can in principle be different from the problem index in the benchmark suite. - This call does not affect the state of the
current_problem
andcurrent_index
attributes. - For some suites and/or observers, the
free()
method of the problem must be called before the next call ofget_problem
. Otherwise Python might just silently die, which is e.g. a known issue of the "bbob" observer.
- Here an
See also ids
.
return a Problem
instance, by default unobserved, using function,
dimension and instance to identify the desired problem.
If a suite contains multiple problems with the same function, dimension and instance, the first corresponding problem is returned.
>>> import cocoex as ex >>> suite = ex.Suite("bbob-biobj", "", "") >>> problem = suite.get_problem_by_function_dimension_instance(1, 2, 3) >>> # work work work using problem >>> problem.free()
- Details:
- Function, dimension and instance are integer values from 1 on.
- This call does not affect the state of the
current_problem
andcurrent_index
attributes. - For some suites and/or observers, the
free()
method of the problem must be called before the next call ofget_problem_by_function_dimension_instance
. Otherwise Python might just silently die, which is e.g. a known issue of the "bbob" observer.
ids(*id_snippets, get_problem=False, verbose=False)
return all problem IDs that contain all of the id_snippets
.
An ID can be used for indexing, that is, when calling the method
get_problem(id)
.
If get_problem is True
, the problem for the first matching ID is
returned.
>>> import cocoex as ex >>> s = ex.Suite("bbob", "", "") >>> s.ids("f001", "d10", "i01") ['bbob_f001_i01_d10']
We can sweep through all instances of the ellipsoidal function f10 in 20-D of the BBOB suite like this:
>>> import cocoex as ex >>> suite = ex.Suite("bbob", "", "") >>> ids = suite.ids("f010", "d20") >>> used_indices = [] >>> for p in suite: ... if p.id in ids: ... # work work work with problem `p` ... used_indices.append(p.index) >>> print(used_indices) [1575, 1576, 1577, 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589]
A desired problem can also be filtered out during creation:
>>> import cocoex as ex >>> f9 = ex.Suite("bbob", "", ... "function_indices:9 dimensions:20 instance_indices:1-5")[0] >>> print(f9.id) bbob_f009_i01_d20
return the "next" problem in this Suite
.
return the first problem on the first call or after
reset
().
next_problem
serves to sweep through the Suite
smoothly.
index in the enumerator of all problems in this suite.
Details: To get the index in the underlying C implementation, which
usually matches current_index
one-to-one, use:
>>> import cocoex as ex >>> suite = ex.Suite("bbob", "", "") >>> suite.current_index is None True >>> suite.next_problem().id[-17:].lower() 'bbob_f001_i01_d02' >>> suite.current_index, suite.indices[suite.current_index] (0, 0)
list of all problem indices, deprecated.
These values are (only) used to call the underlying C structures.
Indices used in the Python interface run between 0 and len(self)
.