class documentation

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_problem_ids has been renamed to ids
Method free free underlying C structures
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 ids ids(*id_snippets, get_problem=False, verbose=False) return all problem IDs that contain all of the id_snippets.
Method next_problem return the "next" problem in this Suite.
Method reset reset to original state, affecting next_problem(), current_problem, current_index
Property current_index index in the enumerator of all problems in this suite.
Property current_problem 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_of_objectives 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_names list of problem names in this Suite, see also ids
def __getitem__(self, key):

self[i] is a synonym for self.get_problem(i), see get_problem

def __init__(self, suite_name, suite_instance, suite_options):

suite_instance and suite_options can be empty strings.

def find_problem_ids(self, *args, **kwargs):

has been renamed to ids

def free(self):

free underlying C structures

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 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
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 reset(self):

reset to original state, affecting next_problem(), current_problem, current_index

@property
current_index =

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
current_problem =

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.

These values are (only) used to call the underlying C structures. Indices used in the Python interface run between 0 and len(self).

@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_of_objectives =

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_names =

list of problem names in this Suite, see also ids