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 __init__ suite_instance and suite_options can be empty strings.
Method reset reset to original state, affecting next_problem(), current_problem, current_index
Method next_problem return the "next" problem in this Suite.
Method get_problem return a Problem instance, by default unobserved, using id: str or index (where id: int) to identify the desired problem.
Method get_problem_by_function_dimension_instance return a Problem instance, by default unobserved, using function, dimension and instance to identify the desired problem.
Method __getitem__ self[i] is a synonym for self.get_problem(i), see get_problem
Method free free underlying C structures
Method find_problem_ids has been renamed to ids
Method ids ids(*id_snippets, get_problem=False, verbose=False) return all problem IDs that contain all of the id_snippets.
Method current_problem current "open/active" problem to be benchmarked
Method current_index index in the enumerator of all problems in this suite.
Method problem_names list of problem names in this Suite, see also ids
Method dimensions list of problem dimensions occuring at least once in this Suite
Method number_of_objectives list of number of objectives occuring in this Suite
Method indices list of all problem indices, deprecated.
Method name name of this suite as used to instantiate the suite via Suite(name, ...)
Method instance instance of this suite as used to instantiate the suite via Suite(name, instance, ...)
Method options options for this suite as used to instantiate the suite via Suite(name, instance, options)
Method info Undocumented
def __init__(self, suite_name, suite_instance, suite_options):
suite_instance and suite_options can be empty strings.
def reset(self):
reset to original state, affecting next_problem(), current_problem, current_index
def next_problem(self, observer=None):

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.

def get_problem(self, id, observer=None):

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 and len(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 and current_index attributes.
  • For some suites and/or observers, the free() method of the problem must be called before the next call of get_problem. Otherwise Python might just silently die, which is e.g. a known issue of the "bbob" observer.

See also ids.

def get_problem_by_function_dimension_instance(self, function, dimension, instance, observer=None):

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 and current_index attributes.
  • For some suites and/or observers, the free() method of the problem must be called before the next call of get_problem_by_function_dimension_instance. Otherwise Python might just silently die, which is e.g. a known issue of the "bbob" observer.
def __getitem__(self, key):
self[i] is a synonym for self.get_problem(i), see get_problem
def free(self):
free underlying C structures
def find_problem_ids(self, *args, **kwargs):
has been renamed to ids
def ids(self, *id_snippets, **kwargs):

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
@property
def current_problem(self):
current "open/active" problem to be benchmarked
@property
def current_index(self):

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)
@property
def problem_names(self):
list of problem names in this Suite, see also ids
@property
def dimensions(self):
list of problem dimensions occuring at least once in this Suite
@property
def number_of_objectives(self):
list of number of objectives occuring in this Suite
@property
def indices(self):

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).

@property
def name(self):
name of this suite as used to instantiate the suite via Suite(name, ...)
@property
def instance(self):
instance of this suite as used to instantiate the suite via Suite(name, instance, ...)
@property
def options(self):
options for this suite as used to instantiate the suite via Suite(name, instance, options)
@property
def info(self):
Undocumented
API Documentation for cocoex, generated by pydoctor at 2020-01-21 17:05:05.