diff --git a/bindings/python/cconfigspace/__init__.py b/bindings/python/cconfigspace/__init__.py index 9582cf396d8795cbc92c42e8f3890ebcf8f1c038..42764c261971d365ea339fecb16fce9072a3fa1c 100644 --- a/bindings/python/cconfigspace/__init__.py +++ b/bindings/python/cconfigspace/__init__.py @@ -15,3 +15,6 @@ from .expression import * from .context import * from .configuration_space import * from .configuration import * +from .objective_space import * +from .evaluation import * +from .tuner import * diff --git a/bindings/python/cconfigspace/base.py b/bindings/python/cconfigspace/base.py index 719e776b7f163af14be68b082187b3307a71cf18..d06e3d19bde013d9ea756e4b9c9cc543cc92f882 100644 --- a/bindings/python/cconfigspace/base.py +++ b/bindings/python/cconfigspace/base.py @@ -1,9 +1,6 @@ import ctypes as ct from . import libcconfigspace -ccs_init = libcconfigspace.ccs_init -ccs_init.restype = ct.c_int - class ccs_version(ct.Structure): _fields_ = [("revision", ct.c_ushort), ("patch", ct.c_ushort), @@ -159,6 +156,12 @@ class CEnumeration64(ct.c_longlong, metaclass=CEnumerationType64): def __str__(self): return "%s.%s" % (self.__class__.__name__, self.name) + def __eq__(self, other): + if isinstance(other, int): + return self.value == other + else: + return self.value == other.value + @property def name(self): if self.value in self._reverse_members_: @@ -324,12 +327,16 @@ class Error(Exception): if err < 0: raise cls(ccs_error(-err)) +ccs_init = _ccs_get_function("ccs_init") ccs_get_version = _ccs_get_function("ccs_get_version", restype = ccs_version) ccs_retain_object = _ccs_get_function("ccs_retain_object", [ccs_object]) ccs_release_object = _ccs_get_function("ccs_release_object", [ccs_object]) ccs_object_get_type = _ccs_get_function("ccs_object_get_type", [ccs_object, ct.POINTER(ccs_object_type)]) ccs_object_get_refcount = _ccs_get_function("ccs_object_get_refcount", [ccs_object, ct.POINTER(ct.c_int)]) +_res = ccs_init() +Error.check(_res) + class Object: def __init__(self, handle, retain = False, auto_release = True): if handle is None: @@ -383,6 +390,12 @@ class Object: return ConfigurationSpace.from_handle(h) elif v == ccs_object_type.CONFIGURATION: return Configuration.from_handle(h) + elif v == ccs_object_type.OBJECTIVE_SPACE: + return ObjectiveSpace.from_handle(h) + elif v == ccs_object_type.EVALUATION: + return Evaluation.from_handle(h) + elif v == ccs_object_type.Tuner: + return Tuner.from_handle(h) else: raise Error(ccs_error.INVALID_OBJECT) @@ -398,3 +411,5 @@ from .hyperparameter import Hyperparameter from .expression import Expression from .configuration_space import ConfigurationSpace from .configuration import Configuration +from .evaluation import Evaluation +from .tuner import Tuner diff --git a/bindings/python/cconfigspace/configuration_space.py b/bindings/python/cconfigspace/configuration_space.py index 558fa53614bae5d2a14961e01816f78821c254bc..9c070116965c66619ef5955bba6b0f8be90cf615 100644 --- a/bindings/python/cconfigspace/configuration_space.py +++ b/bindings/python/cconfigspace/configuration_space.py @@ -182,7 +182,7 @@ class ConfigurationSpace(Context): sz = len(expressions) if sz == 0: return None - v = (ccs_expression * sz)(*[x.handle.value if x else x for x in expressions]) + v = (ccs_expression * sz)(*[x.handle.value for x in expressions]) res = ccs_configuration_space_add_forbidden_clauses(self.handle, sz, v) Error.check(res) diff --git a/bindings/python/cconfigspace/evaluation.py b/bindings/python/cconfigspace/evaluation.py new file mode 100644 index 0000000000000000000000000000000000000000..87dd9d533611e72f2fc11b9680e54d00b161fc02 --- /dev/null +++ b/bindings/python/cconfigspace/evaluation.py @@ -0,0 +1,161 @@ +import ctypes as ct +from .base import Object, Error, CEnumeration, ccs_error, ccs_result, _ccs_get_function, ccs_context, ccs_hyperparameter, ccs_configuration_space, ccs_configuration, ccs_datum, ccs_objective_space, ccs_evaluation +from .context import Context +from .hyperparameter import Hyperparameter +from .configuration_space import ConfigurationSpace +from .configuration import Configuration +from .objective_space import ObjectiveSpace + +class ccs_comparison(CEnumeration): + _members_ = [ + ('BETTER', -1), + ('EQUIVALENT', 0), + ('WORSE', 1), + ('NOT_COMPARABLE', 2) ] + +ccs_create_evaluation = _ccs_get_function("ccs_create_evaluation", [ccs_objective_space, ccs_configuration, ccs_result, ct.c_size_t, ct.POINTER(ccs_datum), ct.c_void_p, ct.POINTER(ccs_evaluation)]) +ccs_evaluation_get_objective_space = _ccs_get_function("ccs_evaluation_get_objective_space", [ccs_evaluation, ct.POINTER(ccs_objective_space)]) +ccs_evaluation_get_configuration = _ccs_get_function("ccs_evaluation_get_configuration", [ccs_evaluation, ct.POINTER(ccs_configuration)]) +ccs_evaluation_get_user_data = _ccs_get_function("ccs_evaluation_get_user_data", [ccs_evaluation, ct.POINTER(ct.c_void_p)]) +ccs_evaluation_get_error = _ccs_get_function("ccs_evaluation_get_error", [ccs_evaluation, ct.POINTER(ccs_result)]) +ccs_evaluation_set_error = _ccs_get_function("ccs_evaluation_set_error", [ccs_evaluation, ccs_result]) +ccs_evaluation_get_value = _ccs_get_function("ccs_evaluation_get_value", [ccs_evaluation, ct.c_size_t, ct.POINTER(ccs_datum)]) +ccs_evaluation_set_value = _ccs_get_function("ccs_evaluation_set_value", [ccs_evaluation, ct.c_size_t, ccs_datum]) +ccs_evaluation_get_values = _ccs_get_function("ccs_evaluation_get_values", [ccs_evaluation, ct.c_size_t, ct.POINTER(ccs_datum), ct.POINTER(ct.c_size_t)]) +ccs_evaluation_get_value_by_name = _ccs_get_function("ccs_evaluation_get_value_by_name", [ccs_evaluation, ct.c_char_p, ccs_datum]) +ccs_evaluation_get_objective_value = _ccs_get_function("ccs_evaluation_get_objective_value", [ccs_evaluation, ct.c_size_t, ct.POINTER(ccs_datum)]) +ccs_evaluation_get_objective_values = _ccs_get_function("ccs_evaluation_get_objective_values", [ccs_evaluation, ct.c_size_t, ct.POINTER(ccs_datum), ct.POINTER(ct.c_size_t)]) +ccs_evaluation_cmp = _ccs_get_function("ccs_evaluation_cmp", [ccs_evaluation, ccs_evaluation, ct.POINTER(ccs_comparison)]) + +class Evaluation(Object): + def __init__(self, handle = None, retain = False, objective_space = None, configuration = None, error = ccs_error.SUCCESS, values = None, user_data = None): + if handle is None: + count = 0 + if values: + count = len(values) + vals = (ccs_datum * count)() + for i in range(count): + vals[i].value = values[i] + else: + vals = None + handle = ccs_evaluation() + res = ccs_create_evaluation(objective_space.handle, configuration.handle, error, count, vals, user_data, ct.byref(handle)) + Error.check(res) + super().__init__(handle = handle, retain = False) + else: + super().__init__(handle = handle, retain = retain) + + @classmethod + def from_handle(cls, handle): + return cls(handle = handle, retain = True) + + @property + def user_data(self): + if hasattr(self, "_user_data"): + return self._user_data + v = ct.c_void_p() + res = ccs_evaluation_get_user_data(self.handle, ct.byref(v)) + Error.check(res) + self._user_data = v + return v + + @property + def objective_space(self): + if hasattr(self, "_objective_space"): + return self._objective_space + v = ccs_objective_space() + res = ccs_evaluation_get_objective_space(self.handle, ct.byref(v)) + Error.check(res) + self._objective_space = ObjectiveSpace.from_handle(v) + return self._objective_space + + @property + def configuration(self): + if hasattr(self, "_configuration"): + return self._configuration + v = ccs_configuration() + res = ccs_evaluation_get_configuration(self.handle, ct.byref(v)) + Error.check(res) + self._configuration = Configuration.from_handle(v) + return self._configuration + + @property + def error(self): + v = ccs_result() + res = ccs_evaluation_get_error(self.handle, ct.byref(v)) + Error.check(res) + return v.value + + @error.setter + def error(self, v): + res = ccs_evaluation_set_error(self.handle, v) + Error.check(res) + + def set_value(self, hyperparameter, value): + if isinstance(hyperparameter, Hyperparameter): + hyperparameter = self.objective_space.hyperparameter_index(hyperparameter) + elif isinstance(hyperparameter, str): + hyperparameter = self.objective_space.hyperparameter_index_by_name(hyperparameter) + pv = ccs_datum(value) + v = ccs_datum_fix() + v.value = pv._value.i + v.type = pv.type + res = ccs_evaluation_set_value(self.handle, hyperparameter, v) + Error.check(res) + + def value(self, hyperparameter): + v = ccs_datum() + if isinstance(hyperparameter, Hyperparameter): + res = ccs_evaluation_get_value(self.handle, self.objective_space.hyperparameter_index(hyperparameter), ct.byref(v)) + elif isinstance(hyperparameter, str): + res = ccs_evaluation_get_value_by_name(self.handle, str.encode(hyperparameter), ct.byref(v)) + else: + res = ccs_evaluation_get_value(self.handle, hyperparameter, ct.byref(v)) + Error.check(res) + return v.value + + @property + def num_values(self): + if hasattr(self, "_num_values"): + return self._num_values + v = ct.c_size_t() + res = ccs_evaluation_get_values(self.handle, 0, None, ct.byref(v)) + Error.check(res) + self._num_values = v.value + return self._num_values + + @property + def values(self): + sz = self.num_values + if sz == 0: + return [] + v = (ccs_datum * sz)() + res = ccs_evaluation_get_values(self.handle, sz, v, None) + Error.check(res) + return [x.value for x in v] + + @property + def num_objective_values(self): + if hasattr(self, "_num_objective_values"): + return self._num_objective_values + v = ct.c_size_t() + res = ccs_evaluation_get_objective_values(self.handle, 0, None, ct.byref(v)) + Error.check(res) + self._num_objective_values = v.value + return self._num_objective_values + + @property + def objective_values(self): + sz = self.num_objective_values + if sz == 0: + return [] + v = (ccs_datum * sz)() + res = ccs_evaluation_get_objective_values(self.handle, sz, v, None) + Error.check(res) + return [x.value for x in v] + + def cmp(self, other): + v = ccs_comparison() + res = ccs_evaluation_cmp(self.handle, other.handle, ct.byref(v)) + Error.check(res) + return v diff --git a/bindings/python/cconfigspace/objective_space.py b/bindings/python/cconfigspace/objective_space.py new file mode 100644 index 0000000000000000000000000000000000000000..998629b3190904e784d8e9a33b78b5ddcd04b235 --- /dev/null +++ b/bindings/python/cconfigspace/objective_space.py @@ -0,0 +1,156 @@ +import ctypes as ct +from .base import Object, Error, CEnumeration, ccs_error, _ccs_get_function, ccs_context, ccs_hyperparameter, ccs_configuration_space, ccs_configuration, ccs_rng, ccs_distribution, ccs_expression, ccs_datum, ccs_objective_space +from .context import Context +from .hyperparameter import Hyperparameter +from .expression import Expression +from .configuration_space import ConfigurationSpace +from .configuration import Configuration + +class ccs_objective_type(CEnumeration): + _members_ = [ + ('MINIMIZE', 0), + 'MAXINIZE' ] + +ccs_create_objective_space = _ccs_get_function("ccs_create_objective_space", [ct.c_char_p, ct.c_void_p, ct.POINTER(ccs_objective_space)]) +ccs_objective_space_get_name = _ccs_get_function("ccs_objective_space_get_name", [ccs_objective_space, ct.POINTER(ct.c_char_p)]) +ccs_objective_space_get_user_data = _ccs_get_function("ccs_objective_space_get_user_data", [ccs_objective_space, ct.POINTER(ct.c_void_p)]) +ccs_objective_space_add_hyperparameter = _ccs_get_function("ccs_objective_space_add_hyperparameter", [ccs_objective_space, ccs_hyperparameter]) +ccs_objective_space_add_hyperparameters = _ccs_get_function("ccs_objective_space_add_hyperparameters", [ccs_objective_space, ct.c_size_t, ct.POINTER(ccs_hyperparameter)]) +ccs_objective_space_get_num_hyperparameters = _ccs_get_function("ccs_objective_space_get_num_hyperparameters", [ccs_objective_space, ct.POINTER(ct.c_size_t,)]) +ccs_objective_space_get_hyperparameter = _ccs_get_function("ccs_objective_space_get_hyperparameter", [ccs_objective_space, ct.c_size_t, ct.POINTER(ccs_hyperparameter)]) +ccs_objective_space_get_hyperparameter_by_name = _ccs_get_function("ccs_objective_space_get_hyperparameter_by_name", [ccs_objective_space, ct.c_char_p, ct.POINTER(ccs_hyperparameter)]) +ccs_objective_space_get_hyperparameter_index_by_name = _ccs_get_function("ccs_objective_space_get_hyperparameter_index_by_name", [ccs_objective_space, ct.c_char_p, ct.POINTER(ct.c_size_t)]) +ccs_objective_space_get_hyperparameter_index = _ccs_get_function("ccs_objective_space_get_hyperparameter_index", [ccs_objective_space, ccs_hyperparameter, ct.POINTER(ct.c_size_t)]) +ccs_objective_space_get_hyperparameters = _ccs_get_function("ccs_objective_space_get_hyperparameters", [ccs_objective_space, ct.c_size_t, ct.POINTER(ccs_hyperparameter), ct.POINTER(ct.c_size_t)]) +ccs_objective_space_add_objective = _ccs_get_function("ccs_objective_space_add_objective", [ccs_objective_space, ccs_expression, ccs_objective_type]) +ccs_objective_space_add_objectives = _ccs_get_function("ccs_objective_space_add_objectives", [ccs_objective_space, ct.c_size_t, ct.POINTER(ccs_expression), ct.POINTER(ccs_objective_type)]) +ccs_objective_space_get_objective = _ccs_get_function("ccs_objective_space_get_objective", [ccs_objective_space, ct.c_size_t, ct.POINTER(ccs_expression), ct.POINTER(ccs_objective_type)]) +ccs_objective_space_get_objectives = _ccs_get_function("ccs_objective_space_get_objectives", [ccs_objective_space, ct.c_size_t, ct.POINTER(ccs_expression), ct.POINTER(ccs_objective_type), ct.POINTER(ct.c_size_t)]) + +class ObjectiveSpace(Context): + def __init__(self, handle = None, retain = False, name = "", user_data = None): + if handle is None: + handle = ccs_objective_space() + res = ccs_create_objective_space(str.encode(name), user_data, ct.byref(handle)) + Error.check(res) + super().__init__(handle = handle, retain = False) + else: + super().__init__(handle = handle, retain = retain) + + @classmethod + def from_handle(cls, handle): + return cls(handle = handle, retain = True) + + @property + def user_data(self): + if hasattr(self, "_user_data"): + return self._user_data + v = ct.c_void_p() + res = ccs_objective_space_get_user_data(self.handle, ct.byref(v)) + Error.check(res) + self._user_data = v + return v + + @property + def name(self): + if hasattr(self, "_name"): + return self._name + v = ct.c_char_p() + res = ccs_objective_space_get_name(self.handle, ct.byref(v)) + Error.check(res) + self._name = v.value.decode() + return self._name + + def add_hyperparameter(self, hyperparameter): + res = ccs_objective_space_add_hyperparameter(self.handle, hyperparameter.handle) + Error.check(res) + + def add_hyperparameters(self, hyperparameters): + count = len(hyperparameters) + if count == 0: + return None + hypers = (ccs_hyperparameter * count)(*[x.handle.value for x in hyperparameters]) + res = ccs_objective_space_add_hyperparameters(self.handle, count, hypers) + Error.check(res) + + def hyperparameter(self, index): + v = ccs_hyperparameter() + res = ccs_objective_space_get_hyperparameter(self.handle, index, ct.byref(v)) + Error.check(res) + return Hyperparameter.from_handle(v) + + def hyperparameter_by_name(self, name): + v = ccs_hyperparameter() + res = ccs_objective_space_get_hyperparameter_by_name(self.handle, str.encode(name), ct.byref(v)) + Error.check(res) + return Hyperparameter.from_handle(v) + + def hyperparameter_index(self, hyperparameter): + v = ct.c_size_t() + res = ccs_objective_space_get_hyperparameter_index(self.handle, hyperparameter.handle, ct.byref(v)) + Error.check(res) + return v.value + + def hyperparameter_index_by_name(self, name): + v = ct.c_size_t() + res = ccs_objective_space_get_hyperparameter_index_by_name(self.handle, str.encode(name), ct.byref(v)) + Error.check(res) + return v.value + + @property + def num_hyperparameters(self): + v = ct.c_size_t(0) + res = ccs_objective_space_get_num_hyperparameters(self.handle, ct.byref(v)) + Error.check(res) + return v.value + + @property + def hyperparameters(self): + count = self.num_hyperparameters + if count == 0: + return [] + v = (ccs_hyperparameter * count)() + res = ccs_objective_space_get_hyperparameters(self.handle, count, v, None) + Error.check(res) + return [Hyperparameter.from_handle(ccs_hyperparameter(x)) for x in v] + + def add_objective(self, expression, t = ccs_objective_type.MINIMIZE): + res = ccs_objective_space_add_objective(self.handle, expression.handle, t) + Error.check(res) + + def add_objectives(self, expressions, types = None): + sz = len(expressions) + if sz == 0: + return None + if types: + if len(types) != sz: + raise Error(ccs_error.INVALID_VALUE) + types = (ccs_objective_type * sz)(*types) + else: + types = (ccs_objective_type * sz)(*([ccs_objective_type.MINIMIZE] * sz)) + v = (ccs_expression * sz)(*[x.handle.value for x in expressions]) + res = ccs_objective_space_add_objectives(self.handle, sz, v, types) + Error.check(res) + + def get_objective(self, index): + v = ccs_expression() + t = ccs_objective_type() + res = ccs_objective_space_get_objective(self.handle, index, ct.byref(v), ct.byref(t)) + Error.check(res) + return (Expression.from_handle(v), t) + + @property + def num_objective(self): + v = ct.c_size_t() + res = ccs_objective_space_get_objectives(self.handle, 0, None, None, ct.byref(v)) + Error.check(res) + return v.value + + @property + def objectives(self): + sz = self.num_objective + v = (ccs_expression * sz)() + t = (ccs_objective_type * sz)() + res = ccs_objective_space_get_objectives(self.handle, sz, v, t, None) + Error.check(res) + return [(Expression.from_handle(ccs_expression(v[x])), ccs_objective_type(t[x])) for x in range(sz)] diff --git a/bindings/python/cconfigspace/tuner.py b/bindings/python/cconfigspace/tuner.py new file mode 100644 index 0000000000000000000000000000000000000000..b538830ca177245d223e60217040b729b851b5e3 --- /dev/null +++ b/bindings/python/cconfigspace/tuner.py @@ -0,0 +1,144 @@ +import ctypes as ct +from .base import Object, Error, CEnumeration, ccs_error, ccs_result, _ccs_get_function, ccs_context, ccs_hyperparameter, ccs_configuration_space, ccs_configuration, ccs_datum, ccs_objective_space, ccs_evaluation, ccs_tuner +from .context import Context +from .hyperparameter import Hyperparameter +from .configuration_space import ConfigurationSpace +from .configuration import Configuration +from .objective_space import ObjectiveSpace +from .evaluation import Evaluation + +class ccs_tuner_type(CEnumeration): + _members_ = [ + ('TUNER_RANDOM',0), + 'TUNER_USER_DEFINED' ] + +ccs_tuner_get_type = _ccs_get_function("ccs_tuner_get_type", [ccs_tuner, ct.POINTER(ccs_tuner_type)]) +ccs_tuner_get_name = _ccs_get_function("ccs_tuner_get_name", [ccs_tuner, ct.POINTER(ct.c_char_p)]) +ccs_tuner_get_user_data = _ccs_get_function("ccs_tuner_get_user_data", [ccs_tuner, ct.POINTER(ct.c_void_p)]) +ccs_tuner_get_configuration_space = _ccs_get_function("ccs_tuner_get_configuration_space", [ccs_tuner, ct.POINTER(ccs_configuration_space)]) +ccs_tuner_get_objective_space = _ccs_get_function("ccs_tuner_get_objective_space", [ccs_tuner, ct.POINTER(ccs_objective_space)]) +ccs_tuner_ask = _ccs_get_function("ccs_tuner_ask", [ccs_tuner, ct.c_size_t, ct.POINTER(ccs_configuration), ct.POINTER(ct.c_size_t)]) +ccs_tuner_tell = _ccs_get_function("ccs_tuner_tell", [ccs_tuner, ct.c_size_t, ct.POINTER(ccs_evaluation)]) +ccs_tuner_get_optimums = _ccs_get_function("ccs_tuner_get_optimums", [ccs_tuner, ct.c_size_t, ct.POINTER(ccs_evaluation), ct.POINTER(ct.c_size_t)]) +ccs_tuner_get_history = _ccs_get_function("ccs_tuner_get_history", [ccs_tuner, ct.c_size_t, ct.POINTER(ccs_evaluation), ct.POINTER(ct.c_size_t)]) + +class Tuner(Object): + @classmethod + def from_handle(cls, handle): + v = ccs_tuner_type(0) + res = ccs_tuner_get_type(handle, ct.byref(v)) + Error.check(res) + v = v.value + if v == ccs_tuner_type.RANDOM: + return RandomTuner(handle = handle, retain = True) + elif v == ccs_hyperparameter_type.USER_DEFIND: + return UserDefinedTuner(handle = handle, retain = True) + else: + raise Error(ccs_error.INVALID_TUNER) + + @property + def type(self): + if hasattr(self, "_type"): + return self._type + v = ccs_tuner_type(0) + res = ccs_tuner_get_type(self.handle, ct.byref(v)) + Error.check(res) + self._type = v + return v + + @property + def user_data(self): + if hasattr(self, "_user_data"): + return self._user_data + v = ct.c_void_p() + res = ccs_tuner_get_user_data(self.handle, ct.byref(v)) + Error.check(res) + self._user_data = v + return v + + @property + def name(self): + if hasattr(self, "_name"): + return self._name + v = ct.c_char_p() + res = ccs_tuner_get_name(self.handle, ct.byref(v)) + Error.check(res) + self._name = v.value.decode() + return self._name + + @property + def objective_space(self): + if hasattr(self, "_objective_space"): + return self._objective_space + v = ccs_objective_space() + res = ccs_tuner_get_objective_space(self.handle, ct.byref(v)) + Error.check(res) + self._objective_space = ObjectiveSpace.from_handle(v) + return self._objective_space + + @property + def configuration_space(self): + if hasattr(self, "_configuration_space"): + return self._configuration_space + v = ccs_configuration_space() + res = ccs_evaluation_get_configuration_space(self.handle, ct.byref(v)) + Error.check(res) + self._configuration_space = ConfigurationSpace.from_handle(v) + return self._configuration_space + + def ask(self, count = 1): + v = (ccs_configuration * count)() + c = ct.c_size_t() + res = ccs_tuner_ask(self.handle, count, v, ct.byref(c)) + Error.check(res) + count = c.value + return [Configuration.from_handle(ccs_configuration(v[x])) for x in range(count)] + + def tell(self, evaluations): + count = len(evaluations) + v = (ccs_evaluation * count)(*[x.handle.value for x in evaluations]) + res = ccs_tuner_tell(self.handle, count, v) + Error.check(res) + + @property + def history_size(self): + v = ct.c_size_t() + res = ccs_tuner_get_history(self.handle, 0, None, ct.byref(v)) + Error.check(res) + return v.value + + @property + def history(self): + count = self.history_size + v = (ccs_evaluation * count)() + res = ccs_tuner_get_history(self.handle, count, v, None) + Error.check(res) + return [Evaluation.from_handle(ccs_evaluation(x)) for x in v] + + @property + def num_optimums(self): + v = ct.c_size_t() + res = ccs_tuner_get_optimums(self.handle, 0, None, ct.byref(v)) + Error.check(res) + return v.value + + @property + def optimums(self): + count = self.num_optimums + v = (ccs_evaluation * count)() + res = ccs_tuner_get_optimums(self.handle, count, v, None) + Error.check(res) + return [Evaluation.from_handle(ccs_evaluation(x)) for x in v] + +ccs_create_random_tuner = _ccs_get_function("ccs_create_random_tuner", [ct.c_char_p, ccs_configuration_space, ccs_objective_space, ct.c_void_p, ct.POINTER(ccs_tuner)]) + +class RandomTuner(Tuner): + def __init__(self, handle = None, retain = False, name = None, configuration_space = None, objective_space = None, user_data = None): + if handle is None: + handle = ccs_tuner() + res = ccs_create_random_tuner(str.encode(name), configuration_space.handle, objective_space.handle, user_data, ct.byref(handle)) + Error.check(res) + super().__init__(handle = handle, retain = False) + else: + super().__init__(handle = handle, retain = retain) + diff --git a/bindings/python/test/test_tuner.py b/bindings/python/test/test_tuner.py new file mode 100644 index 0000000000000000000000000000000000000000..177da9e22bc2cec7afeca6f204564444c1ad546f --- /dev/null +++ b/bindings/python/test/test_tuner.py @@ -0,0 +1,45 @@ +import unittest +import sys +sys.path.insert(1, '.') +sys.path.insert(1, '..') +import cconfigspace as ccs +from math import sin + +class TestTuner(unittest.TestCase): + def create_tuning_problem(self): + cs = ccs.ConfigurationSpace(name = "cspace") + h1 = ccs.NumericalHyperparameter(lower = -5.0, upper = 5.0) + h2 = ccs.NumericalHyperparameter(lower = -5.0, upper = 5.0) + h3 = ccs.NumericalHyperparameter(lower = -5.0, upper = 5.0) + cs.add_hyperparameters([h1, h2, h3]) + os = ccs.ObjectiveSpace(name = "ospace") + v1 = ccs.NumericalHyperparameter(lower = float('-inf'), upper = float('inf')) + v2 = ccs.NumericalHyperparameter(lower = float('-inf'), upper = float('inf')) + os.add_hyperparameters([v1, v2]) + e1 = ccs.Variable(hyperparameter = v1) + e2 = ccs.Variable(hyperparameter = v2) + os.add_objectives( [e1, e2] ) + return (cs, os) + + def test_create_random(self): + (cs, os) = self.create_tuning_problem() + t = ccs.RandomTuner(name = "tuner", configuration_space = cs, objective_space = os) + self.assertEqual("tuner", t.name) + self.assertEqual(ccs.TUNER_RANDOM, t.type.value) + func = lambda x, y, z: [(x-2)*(x-2), sin(z+y)] + evals = [ccs.Evaluation(objective_space = os, configuration = c, values = func(*(c.values))) for c in t.ask(100)] + t.tell(evals) + hist = t.history + self.assertEqual(100, len(hist)) + evals = [ccs.Evaluation(objective_space = os, configuration = c, values = func(*(c.values))) for c in t.ask(100)] + t.tell(evals) + hist = t.history + self.assertEqual(200, len(hist)) + optims = t.optimums + objs = [x.objective_values for x in optims] + objs.sort(key = lambda x: x[0]) + self.assertTrue(all(objs[i] <= objs[i+1] for i in range(len(objs)-1))) + +if __name__ == '__main__': + unittest.main() +