From 23c5f0528eebbe1f9d15fc8f3b4bfb17fdd9e02d Mon Sep 17 00:00:00 2001 From: Brice Videau Date: Tue, 26 Sep 2023 18:04:01 -0500 Subject: [PATCH] Added distribution space abstraction, allowing configuration space to be immutable (except rng). --- bindings/python/cconfigspace/__init__.py | 1 + bindings/python/cconfigspace/base.py | 73 +-- .../cconfigspace/configuration_space.py | 43 +- .../python/cconfigspace/distribution_space.py | 61 +++ .../python/test/test_configuration_space.py | 13 +- bindings/ruby/lib/cconfigspace.rb | 1 + bindings/ruby/lib/cconfigspace/base.rb | 73 +-- .../lib/cconfigspace/configuration_space.rb | 46 +- .../lib/cconfigspace/distribution_space.rb | 60 +++ .../ruby/test/test_configuration_space.rb | 13 +- include/Makefile.am | 1 + include/cconfigspace.h | 1 + include/cconfigspace/base.h | 78 ++-- include/cconfigspace/configuration_space.h | 74 +-- include/cconfigspace/distribution_space.h | 109 +++++ src/Makefile.am | 3 + src/cconfigspace.c | 7 + src/configuration_space.c | 335 +++----------- src/configuration_space_deserialize.h | 73 +-- src/configuration_space_internal.h | 20 +- src/distribution_deserialize.h | 1 + src/distribution_space.c | 397 ++++++++++++++++ src/distribution_space_deserialize.h | 173 +++++++ src/distribution_space_internal.h | 149 ++++++ src/expression_deserialize.h | 1 + src/features_tuner_deserialize.h | 1 + src/features_tuner_random.c | 2 +- src/parameter_deserialize.h | 1 + src/tree_space_deserialize.h | 1 + src/tree_tuner_deserialize.h | 1 + src/tuner_deserialize.h | 1 + src/tuner_random.c | 2 +- tests/Makefile.am | 1 + tests/test_condition.c | 10 +- tests/test_configuration_space.c | 179 +------- tests/test_distribution_space.c | 432 ++++++++++++++++++ tests/test_forbidden.c | 10 +- tests/test_random_features_tuner.c | 2 +- tests/test_random_tuner.c | 2 +- tests/test_user_defined_features_tuner.c | 2 +- tests/test_user_defined_tuner.c | 2 +- 41 files changed, 1667 insertions(+), 788 deletions(-) create mode 100644 bindings/python/cconfigspace/distribution_space.py create mode 100644 bindings/ruby/lib/cconfigspace/distribution_space.rb create mode 100644 include/cconfigspace/distribution_space.h create mode 100644 src/distribution_space.c create mode 100644 src/distribution_space_deserialize.h create mode 100644 src/distribution_space_internal.h create mode 100644 tests/test_distribution_space.c diff --git a/bindings/python/cconfigspace/__init__.py b/bindings/python/cconfigspace/__init__.py index f8112ae4..ca36a49c 100644 --- a/bindings/python/cconfigspace/__init__.py +++ b/bindings/python/cconfigspace/__init__.py @@ -20,6 +20,7 @@ from .expression_parser import * from .context import * from .configuration_space import * +from .distribution_space import * from .binding import * from .configuration import * from .features_space import * diff --git a/bindings/python/cconfigspace/base.py b/bindings/python/cconfigspace/base.py index 29a9c10b..4369698d 100644 --- a/bindings/python/cconfigspace/base.py +++ b/bindings/python/cconfigspace/base.py @@ -27,6 +27,7 @@ def __str__(self): ccs_parameter = ccs_object ccs_expression = ccs_object ccs_context = ccs_object +ccs_distribution_space = ccs_object ccs_configuration_space = ccs_object ccs_binding = ccs_object ccs_configuration = ccs_object @@ -154,42 +155,44 @@ class ObjectType(CEnumeration): 'TREE_SPACE', 'TREE_CONFIGURATION', 'TREE_EVALUATION', - 'TREE_TUNER' ] + 'TREE_TUNER', + 'DISTRIBUTION_SPACE' ] class Result(CEnumeration): _members_ = [ - ('AGAIN', 1), - ('SUCCESS', 0), - ('ERROR_INVALID_OBJECT', -1), - ('ERROR_INVALID_VALUE', -2), - ('ERROR_INVALID_TYPE', -3), - ('ERROR_INVALID_SCALE', -4), - ('ERROR_INVALID_DISTRIBUTION', -5), - ('ERROR_INVALID_EXPRESSION', -6), - ('ERROR_INVALID_PARAMETER', -7), - ('ERROR_INVALID_CONFIGURATION', -8), - ('ERROR_INVALID_NAME', -9), - ('ERROR_INVALID_CONDITION', -10), - ('ERROR_INVALID_TUNER', -11), - ('ERROR_INVALID_GRAPH', -12), - ('ERROR_TYPE_NOT_COMPARABLE', -13), - ('ERROR_INVALID_BOUNDS', -14), - ('ERROR_OUT_OF_BOUNDS', -15), - ('ERROR_SAMPLING_UNSUCCESSFUL', -16), - ('ERROR_OUT_OF_MEMORY', -17), - ('ERROR_UNSUPPORTED_OPERATION', -18), - ('ERROR_INVALID_EVALUATION', -19), - ('ERROR_INVALID_FEATURES', -20), - ('ERROR_INVALID_FEATURES_TUNER', -21), - ('ERROR_INVALID_FILE_PATH', -22), - ('ERROR_NOT_ENOUGH_DATA', -23), - ('ERROR_DUPLICATE_HANDLE', -24), - ('ERROR_INVALID_HANDLE', -25), - ('ERROR_SYSTEM', -26), - ('ERROR_EXTERNAL', -27), - ('ERROR_INVALID_TREE', -28), - ('ERROR_INVALID_TREE_SPACE', -29), - ('ERROR_INVALID_TREE_TUNER', -30) ] + ('AGAIN', 1), + ('SUCCESS', 0), + ('ERROR_INVALID_OBJECT', -1), + ('ERROR_INVALID_VALUE', -2), + ('ERROR_INVALID_TYPE', -3), + ('ERROR_INVALID_SCALE', -4), + ('ERROR_INVALID_DISTRIBUTION', -5), + ('ERROR_INVALID_EXPRESSION', -6), + ('ERROR_INVALID_PARAMETER', -7), + ('ERROR_INVALID_CONFIGURATION', -8), + ('ERROR_INVALID_NAME', -9), + ('ERROR_INVALID_CONDITION', -10), + ('ERROR_INVALID_TUNER', -11), + ('ERROR_INVALID_GRAPH', -12), + ('ERROR_TYPE_NOT_COMPARABLE', -13), + ('ERROR_INVALID_BOUNDS', -14), + ('ERROR_OUT_OF_BOUNDS', -15), + ('ERROR_SAMPLING_UNSUCCESSFUL', -16), + ('ERROR_OUT_OF_MEMORY', -17), + ('ERROR_UNSUPPORTED_OPERATION', -18), + ('ERROR_INVALID_EVALUATION', -19), + ('ERROR_INVALID_FEATURES', -20), + ('ERROR_INVALID_FEATURES_TUNER', -21), + ('ERROR_INVALID_FILE_PATH', -22), + ('ERROR_NOT_ENOUGH_DATA', -23), + ('ERROR_DUPLICATE_HANDLE', -24), + ('ERROR_INVALID_HANDLE', -25), + ('ERROR_SYSTEM', -26), + ('ERROR_EXTERNAL', -27), + ('ERROR_INVALID_TREE', -28), + ('ERROR_INVALID_TREE_SPACE', -29), + ('ERROR_INVALID_TREE_TUNER', -30), + ('ERROR_INVALID_DISTRIBUTION_SPACE', -31) ] class DataType(CEnumeration): _members_ = [ @@ -748,6 +751,7 @@ def _ccs_get_id(): from .parameter import Parameter from .expression import Expression from .configuration_space import ConfigurationSpace +from .distribution_space import DistributionSpace from .configuration import Configuration from .features_space import FeaturesSpace from .features import Features @@ -784,7 +788,8 @@ def _ccs_get_id(): ObjectType.TREE_SPACE: TreeSpace, ObjectType.TREE_CONFIGURATION: TreeConfiguration, ObjectType.TREE_EVALUATION: TreeEvaluation, - ObjectType.TREE_TUNER: TreeTuner + ObjectType.TREE_TUNER: TreeTuner, + ObjectType.DISTRIBUTION_SPACE: DistributionSpace }) diff --git a/bindings/python/cconfigspace/configuration_space.py b/bindings/python/cconfigspace/configuration_space.py index b81309b2..1325c1ca 100644 --- a/bindings/python/cconfigspace/configuration_space.py +++ b/bindings/python/cconfigspace/configuration_space.py @@ -1,5 +1,5 @@ import ctypes as ct -from .base import Object, Error, Result, _ccs_get_function, ccs_context, ccs_parameter, ccs_configuration_space, ccs_configuration, ccs_rng, ccs_distribution, ccs_expression, Datum, ccs_bool +from .base import Object, Error, Result, _ccs_get_function, ccs_context, ccs_parameter, ccs_configuration_space, ccs_configuration, ccs_rng, ccs_expression, Datum, ccs_bool, ccs_distribution_space from .context import Context from .distribution import Distribution from .parameter import Parameter @@ -11,8 +11,6 @@ ccs_create_configuration_space = _ccs_get_function("ccs_create_configuration_space", [ct.c_char_p, ct.c_size_t, ct.POINTER(ccs_parameter), ct.POINTER(ccs_configuration_space)]) ccs_configuration_space_set_rng = _ccs_get_function("ccs_configuration_space_set_rng", [ccs_configuration_space, ccs_rng]) ccs_configuration_space_get_rng = _ccs_get_function("ccs_configuration_space_get_rng", [ccs_configuration_space, ct.POINTER(ccs_rng)]) -ccs_configuration_space_set_distribution = _ccs_get_function("ccs_configuration_space_set_distribution", [ccs_configuration_space, ccs_distribution, ct.POINTER(ct.c_size_t)]) -ccs_configuration_space_get_parameter_distribution = _ccs_get_function("ccs_configuration_space_get_parameter_distribution", [ccs_configuration_space, ct.c_size_t, ct.POINTER(ccs_distribution), ct.POINTER(ct.c_size_t)]) ccs_configuration_space_set_condition = _ccs_get_function("ccs_configuration_space_set_condition", [ccs_configuration_space, ct.c_size_t, ccs_expression]) ccs_configuration_space_get_condition = _ccs_get_function("ccs_configuration_space_get_condition", [ccs_configuration_space, ct.c_size_t, ct.POINTER(ccs_expression)]) ccs_configuration_space_get_conditions = _ccs_get_function("ccs_configuration_space_get_conditions", [ccs_configuration_space, ct.c_size_t, ct.POINTER(ccs_expression), ct.POINTER(ct.c_size_t)]) @@ -23,8 +21,8 @@ ccs_configuration_space_check_configuration = _ccs_get_function("ccs_configuration_space_check_configuration", [ccs_configuration_space, ccs_configuration, ct.POINTER(ccs_bool)]) ccs_configuration_space_check_configuration_values = _ccs_get_function("ccs_configuration_space_check_configuration_values", [ccs_configuration_space, ct.c_size_t, ct.POINTER(Datum), ct.POINTER(ccs_bool)]) ccs_configuration_space_get_default_configuration = _ccs_get_function("ccs_configuration_space_get_default_configuration", [ccs_configuration_space, ct.POINTER(ccs_configuration)]) -ccs_configuration_space_sample = _ccs_get_function("ccs_configuration_space_sample", [ccs_configuration_space, ct.POINTER(ccs_configuration)]) -ccs_configuration_space_samples = _ccs_get_function("ccs_configuration_space_samples", [ccs_configuration_space, ct.c_size_t, ct.POINTER(ccs_configuration)]) +ccs_configuration_space_sample = _ccs_get_function("ccs_configuration_space_sample", [ccs_configuration_space, ccs_distribution_space, ct.POINTER(ccs_configuration)]) +ccs_configuration_space_samples = _ccs_get_function("ccs_configuration_space_samples", [ccs_configuration_space, ccs_distribution_space, ct.c_size_t, ct.POINTER(ccs_configuration)]) class ConfigurationSpace(Context): def __init__(self, handle = None, retain = False, auto_release = True, @@ -55,33 +53,6 @@ def rng(self, r): res = ccs_configuration_space_set_rng(self.handle, r.handle) Error.check(res) - def set_distribution(self, distribution, parameters): - count = distribution.dimension - if count != len(parameters): - raise Error(Result(Result.ERROR_INVALID_VALUE)) - hyps = [] - for h in parameters: - if isinstance(h, Parameter): - hyps.append(self.parameter_index(h)) - elif isinstance(h, str): - hyps.append(self.parameter_index_by_name(h)) - else: - hyps.append(h) - v = (ct.c_size_t * count)(*hyps) - res = ccs_configuration_space_set_distribution(self.handle, distribution.handle, v) - Error.check(res) - - def get_parameter_distribution(self, parameter): - if isinstance(parameter, Parameter): - parameter = self.parameter_index(parameter) - elif isinstance(parameter, str): - parameter = self.parameter_index_by_name(parameter) - v1 = ccs_distribution() - v2 = ct.c_size_t() - res = ccs_configuration_space_get_parameter_distribution(self.handle, parameter, ct.byref(v1), ct.byref(v2)) - Error.check(res) - return [Distribution.from_handle(v1), v2.value] - def set_condition(self, parameter, expression): if isinstance(expression, str): expression = parser.parse(expression, context = PContext(extra=self)) @@ -191,15 +162,15 @@ def default_configuration(self): Error.check(res) return Configuration(handle = v, retain = False) - def sample(self): + def sample(self, distribution_space = None): v = ccs_configuration() - res = ccs_configuration_space_sample(self.handle, ct.byref(v)) + res = ccs_configuration_space_sample(self.handle, distribution_space.handle if distribution_space is not None else None, ct.byref(v)) Error.check(res) return Configuration(handle = v, retain = False) - def samples(self, count): + def samples(self, count, distribution_space = None): v = (ccs_configuration * count)() - res = ccs_configuration_space_samples(self.handle, count, v) + res = ccs_configuration_space_samples(self.handle, distribution_space.handle if distribution_space is not None else None, count, v) Error.check(res) return [Configuration(handle = ccs_configuration(x), retain = False) for x in v] diff --git a/bindings/python/cconfigspace/distribution_space.py b/bindings/python/cconfigspace/distribution_space.py new file mode 100644 index 00000000..1bc48037 --- /dev/null +++ b/bindings/python/cconfigspace/distribution_space.py @@ -0,0 +1,61 @@ +import ctypes as ct +from .base import Object, Error, Result, _ccs_get_function, ccs_configuration_space, ccs_distribution, ccs_distribution_space +from .distribution import Distribution +from .parameter import Parameter +from .configuration_space import ConfigurationSpace + +ccs_create_distribution_space = _ccs_get_function("ccs_create_distribution_space", [ccs_configuration_space, ct.POINTER(ccs_distribution_space)]) +ccs_distribution_space_get_configuration_space = _ccs_get_function("ccs_distribution_space_get_configuration_space", [ccs_distribution_space, ct.POINTER(ccs_configuration_space)]) +ccs_distribution_space_set_distribution = _ccs_get_function("ccs_distribution_space_set_distribution", [ccs_distribution_space, ccs_distribution, ct.POINTER(ct.c_size_t)]) +ccs_distribution_space_get_parameter_distribution = _ccs_get_function("ccs_distribution_space_get_parameter_distribution", [ccs_distribution_space, ct.c_size_t, ct.POINTER(ccs_distribution), ct.POINTER(ct.c_size_t)]) + +class DistributionSpace(Object): + + @property + def configuration_space(self): + if hasattr(self, "_configuration_space"): + return self._configuration_space + v = ccs_configuration_space() + res = ccs_distribution_space_get_configuration_space(self.handle, ct.byref(v)) + Error.check(res) + self._configuration_space = ConfigurationSpace.from_handle(v) + return self._configuration_space + + def __init__(self, handle = None, retain = False, auto_release = True, + configuration_space = None): + if handle is None: + handle = ccs_distribution_space() + res = ccs_create_distribution_space(configuration_space.handle, ct.byref(handle)) + Error.check(res) + super().__init__(handle = handle, retain = False) + else: + super().__init__(handle = handle, retain = retain, auto_release = auto_release) + + def set_distribution(self, distribution, parameters): + count = distribution.dimension + if count != len(parameters): + raise Error(Result(Result.ERROR_INVALID_VALUE)) + hyps = [] + for h in parameters: + if isinstance(h, Parameter): + hyps.append(self.configuration_space.parameter_index(h)) + elif isinstance(h, str): + hyps.append(self.configuration_space.parameter_index_by_name(h)) + else: + hyps.append(h) + v = (ct.c_size_t * count)(*hyps) + res = ccs_distribution_space_set_distribution(self.handle, distribution.handle, v) + Error.check(res) + + def get_parameter_distribution(self, parameter): + if isinstance(parameter, Parameter): + parameter = self.configuration_space.parameter_index(parameter) + elif isinstance(parameter, str): + parameter = self.configuration_space.parameter_index_by_name(parameter) + v1 = ccs_distribution() + v2 = ct.c_size_t() + res = ccs_distribution_space_get_parameter_distribution(self.handle, parameter, ct.byref(v1), ct.byref(v2)) + Error.check(res) + return [Distribution.from_handle(v1), v2.value] + + diff --git a/bindings/python/test/test_configuration_space.py b/bindings/python/test/test_configuration_space.py index 750aac0c..2cef4cca 100644 --- a/bindings/python/test/test_configuration_space.py +++ b/bindings/python/test/test_configuration_space.py @@ -36,21 +36,22 @@ def test_set_distribution(self): h2 = ccs.NumericalParameter.Float() h3 = ccs.NumericalParameter.Float() cs = ccs.ConfigurationSpace(name = "space", parameters = [h1, h2, h3]) + ds = ccs.DistributionSpace(configuration_space = cs) distributions = [ ccs.UniformDistribution.Float(lower = 0.1, upper = 0.3), ccs.UniformDistribution.Float(lower = 0.2, upper = 0.6) ] d = ccs.MultivariateDistribution(distributions = distributions) - cs.set_distribution(d, [h1, h2]) - (dist, indx) = cs.get_parameter_distribution(h1) + ds.set_distribution(d, [h1, h2]) + (dist, indx) = ds.get_parameter_distribution(h1) self.assertEqual( d.handle.value, dist.handle.value ) self.assertEqual( 0, indx ) - (dist, indx) = cs.get_parameter_distribution(h2) + (dist, indx) = ds.get_parameter_distribution(h2) self.assertEqual( d.handle.value, dist.handle.value ) self.assertEqual( 1, indx ) - cs.set_distribution(d, [h3, h1]) - (dist, indx) = cs.get_parameter_distribution(h1) + ds.set_distribution(d, [h3, h1]) + (dist, indx) = ds.get_parameter_distribution(h1) self.assertEqual( d.handle.value, dist.handle.value ) self.assertEqual( 1, indx ) - (dist, indx) = cs.get_parameter_distribution(h3) + (dist, indx) = ds.get_parameter_distribution(h3) self.assertEqual( d.handle.value, dist.handle.value ) self.assertEqual( 0, indx ) diff --git a/bindings/ruby/lib/cconfigspace.rb b/bindings/ruby/lib/cconfigspace.rb index 08784a64..77d3f0e4 100644 --- a/bindings/ruby/lib/cconfigspace.rb +++ b/bindings/ruby/lib/cconfigspace.rb @@ -12,6 +12,7 @@ require_relative 'cconfigspace/expression_parser' require_relative 'cconfigspace/context' require_relative 'cconfigspace/configuration_space' +require_relative 'cconfigspace/distribution_space' require_relative 'cconfigspace/binding' require_relative 'cconfigspace/configuration' require_relative 'cconfigspace/features_space' diff --git a/bindings/ruby/lib/cconfigspace/base.rb b/bindings/ruby/lib/cconfigspace/base.rb index e5f34038..f4e0c0eb 100644 --- a/bindings/ruby/lib/cconfigspace/base.rb +++ b/bindings/ruby/lib/cconfigspace/base.rb @@ -96,6 +96,7 @@ class Version < FFI::Struct typedef :ccs_object_t, :ccs_parameter_t typedef :ccs_object_t, :ccs_expression_t typedef :ccs_object_t, :ccs_context_t + typedef :ccs_object_t, :ccs_distribution_space_t typedef :ccs_object_t, :ccs_configuration_space_t typedef :ccs_object_t, :ccs_binding_t typedef :ccs_object_t, :ccs_configuration_t @@ -120,6 +121,7 @@ class MemoryPointer alias read_ccs_parameter_t read_ccs_object_t alias read_ccs_expression_t read_ccs_object_t alias read_ccs_context_t read_ccs_object_t + alias read_ccs_distribution_space_t read_ccs_object_t alias read_ccs_configuration_space_t read_ccs_object_t alias read_ccs_binding_t read_ccs_object_t alias read_ccs_configuration_t read_ccs_object_t @@ -159,41 +161,43 @@ class MemoryPointer :CCS_OBJECT_TYPE_TREE_SPACE, :CCS_OBJECT_TYPE_TREE_CONFIGURATION, :CCS_OBJECT_TYPE_TREE_EVALUATION, - :CCS_OBJECT_TYPE_TREE_TUNER ] + :CCS_OBJECT_TYPE_TREE_TUNER, + :CCS_OBJECT_TYPE_DISTRIBUTION_SPACE ] Error = enum FFI::Type::INT32, :ccs_result_t, [ - :CCS_RESULT_AGAIN, 1, - :CCS_RESULT_SUCCESS, 0, - :CCS_RESULT_ERROR_INVALID_OBJECT, -1, - :CCS_RESULT_ERROR_INVALID_VALUE, -2, - :CCS_RESULT_ERROR_INVALID_TYPE, -3, - :CCS_RESULT_ERROR_INVALID_SCALE, -4, - :CCS_RESULT_ERROR_INVALID_DISTRIBUTION, -5, - :CCS_RESULT_ERROR_INVALID_EXPRESSION, -6, - :CCS_RESULT_ERROR_INVALID_PARAMETER, -7, - :CCS_RESULT_ERROR_INVALID_CONFIGURATION, -8, - :CCS_RESULT_ERROR_INVALID_NAME, -9, - :CCS_RESULT_ERROR_INVALID_CONDITION, -10, - :CCS_RESULT_ERROR_INVALID_TUNER, -11, - :CCS_RESULT_ERROR_INVALID_GRAPH, -12, - :CCS_RESULT_ERROR_TYPE_NOT_COMPARABLE, -13, - :CCS_RESULT_ERROR_INVALID_BOUNDS, -14, - :CCS_RESULT_ERROR_OUT_OF_BOUNDS, -15, - :CCS_RESULT_ERROR_SAMPLING_UNSUCCESSFUL, -16, - :CCS_RESULT_ERROR_OUT_OF_MEMORY, -17, - :CCS_RESULT_ERROR_UNSUPPORTED_OPERATION, -18, - :CCS_RESULT_ERROR_INVALID_EVALUATION, -19, - :CCS_RESULT_ERROR_INVALID_FEATURES, -20, - :CCS_RESULT_ERROR_INVALID_FEATURES_TUNER, -21, - :CCS_RESULT_ERROR_INVALID_FILE_PATH, -22, - :CCS_RESULT_ERROR_NOT_ENOUGH_DATA, -23, - :CCS_RESULT_ERROR_DUPLICATE_HANDLE, -24, - :CCS_RESULT_ERROR_INVALID_HANDLE, -25, - :CCS_RESULT_ERROR_SYSTEM, -26, - :CCS_RESULT_ERROR_EXTERNAL, -27, - :CCS_RESULT_ERROR_INVALID_TREE, -28, - :CCS_RESULT_ERROR_INVALID_TREE_SPACE, -29, - :CCS_RESULT_ERROR_INVALID_TREE_TUNER, -30 ] + :CCS_RESULT_AGAIN, 1, + :CCS_RESULT_SUCCESS, 0, + :CCS_RESULT_ERROR_INVALID_OBJECT, -1, + :CCS_RESULT_ERROR_INVALID_VALUE, -2, + :CCS_RESULT_ERROR_INVALID_TYPE, -3, + :CCS_RESULT_ERROR_INVALID_SCALE, -4, + :CCS_RESULT_ERROR_INVALID_DISTRIBUTION, -5, + :CCS_RESULT_ERROR_INVALID_EXPRESSION, -6, + :CCS_RESULT_ERROR_INVALID_PARAMETER, -7, + :CCS_RESULT_ERROR_INVALID_CONFIGURATION, -8, + :CCS_RESULT_ERROR_INVALID_NAME, -9, + :CCS_RESULT_ERROR_INVALID_CONDITION, -10, + :CCS_RESULT_ERROR_INVALID_TUNER, -11, + :CCS_RESULT_ERROR_INVALID_GRAPH, -12, + :CCS_RESULT_ERROR_TYPE_NOT_COMPARABLE, -13, + :CCS_RESULT_ERROR_INVALID_BOUNDS, -14, + :CCS_RESULT_ERROR_OUT_OF_BOUNDS, -15, + :CCS_RESULT_ERROR_SAMPLING_UNSUCCESSFUL, -16, + :CCS_RESULT_ERROR_OUT_OF_MEMORY, -17, + :CCS_RESULT_ERROR_UNSUPPORTED_OPERATION, -18, + :CCS_RESULT_ERROR_INVALID_EVALUATION, -19, + :CCS_RESULT_ERROR_INVALID_FEATURES, -20, + :CCS_RESULT_ERROR_INVALID_FEATURES_TUNER, -21, + :CCS_RESULT_ERROR_INVALID_FILE_PATH, -22, + :CCS_RESULT_ERROR_NOT_ENOUGH_DATA, -23, + :CCS_RESULT_ERROR_DUPLICATE_HANDLE, -24, + :CCS_RESULT_ERROR_INVALID_HANDLE, -25, + :CCS_RESULT_ERROR_SYSTEM, -26, + :CCS_RESULT_ERROR_EXTERNAL, -27, + :CCS_RESULT_ERROR_INVALID_TREE, -28, + :CCS_RESULT_ERROR_INVALID_TREE_SPACE, -29, + :CCS_RESULT_ERROR_INVALID_TREE_TUNER, -30, + :CCS_RESULT_ERROR_INVALID_DISTRIBUTION_SPACE, -31 ] class MemoryPointer def read_ccs_object_type_t @@ -587,7 +591,8 @@ def self.class_map CCS_OBJECT_TYPE_TREE_SPACE: CCS::TreeSpace, CCS_OBJECT_TYPE_TREE_CONFIGURATION: CCS::TreeConfiguration, CCS_OBJECT_TYPE_TREE_EVALUATION: CCS::TreeEvaluation, - CCS_OBJECT_TYPE_TREE_TUNER: CCS::TreeTuner + CCS_OBJECT_TYPE_TREE_TUNER: CCS::TreeTuner, + CCS_OBJECT_TYPE_DISTRIBUTION_SPACE: CCS::DistributionSpace } end diff --git a/bindings/ruby/lib/cconfigspace/configuration_space.rb b/bindings/ruby/lib/cconfigspace/configuration_space.rb index 9ba096ab..792481af 100644 --- a/bindings/ruby/lib/cconfigspace/configuration_space.rb +++ b/bindings/ruby/lib/cconfigspace/configuration_space.rb @@ -2,8 +2,6 @@ module CCS attach_function :ccs_create_configuration_space, [:string, :size_t, :pointer, :pointer], :ccs_result_t attach_function :ccs_configuration_space_set_rng, [:ccs_configuration_space_t, :ccs_rng_t], :ccs_result_t attach_function :ccs_configuration_space_get_rng, [:ccs_configuration_space_t, :pointer], :ccs_result_t - attach_function :ccs_configuration_space_set_distribution, [:ccs_configuration_space_t, :ccs_distribution_t, :pointer], :ccs_result_t - attach_function :ccs_configuration_space_get_parameter_distribution, [:ccs_configuration_space_t, :size_t, :pointer, :pointer], :ccs_result_t attach_function :ccs_configuration_space_set_condition, [:ccs_configuration_space_t, :size_t, :ccs_expression_t], :ccs_result_t attach_function :ccs_configuration_space_get_condition, [:ccs_configuration_space_t, :size_t, :pointer], :ccs_result_t attach_function :ccs_configuration_space_get_conditions, [:ccs_configuration_space_t, :size_t, :pointer, :pointer], :ccs_result_t @@ -14,8 +12,8 @@ module CCS attach_function :ccs_configuration_space_check_configuration, [:ccs_configuration_space_t, :ccs_configuration_t, :pointer], :ccs_result_t attach_function :ccs_configuration_space_check_configuration_values, [:ccs_configuration_space_t, :size_t, :pointer, :pointer], :ccs_result_t attach_function :ccs_configuration_space_get_default_configuration, [:ccs_configuration_space_t, :pointer], :ccs_result_t - attach_function :ccs_configuration_space_sample, [:ccs_configuration_space_t, :pointer], :ccs_result_t - attach_function :ccs_configuration_space_samples, [:ccs_configuration_space_t, :size_t, :pointer], :ccs_result_t + attach_function :ccs_configuration_space_sample, [:ccs_configuration_space_t, :ccs_distribution_space_t, :pointer], :ccs_result_t + attach_function :ccs_configuration_space_samples, [:ccs_configuration_space_t, :ccs_distribution_space_t, :size_t, :pointer], :ccs_result_t class ConfigurationSpace < Context @@ -48,38 +46,6 @@ def rng=(r) r end - def set_distribution(distribution, parameters) - count = distribution.dimension - raise CCSError, :CCS_RESULT_ERROR_INVALID_VALUE if count != parameters.size - parameters = parameters.collect { |h| - case h - when Parameter - parameter_index(h) - when String, Symbol - parameter_index_by_name(parameter) - else - h - end - } - p_parameters = MemoryPointer::new(:size_t, count) - p_parameters.write_array_of_size_t(parameters) - CCS.error_check CCS.ccs_configuration_space_set_distribution(@handle, distribution, p_parameters) - self - end - - def get_parameter_distribution(parameter) - case parameter - when Parameter - parameter = parameter_index(parameter); - when String, Symbol - parameter = parameter_index_by_name(parameter); - end - p_distribution = MemoryPointer::new(:ccs_distribution_t) - p_indx = MemoryPointer::new(:size_t) - CCS.error_check CCS.ccs_configuration_space_get_parameter_distribution(@handle, parameter, p_distribution, p_indx) - [CCS::Distribution.from_handle(p_distribution.read_ccs_distribution_t), p_indx.read_size_t] - end - def set_condition(parameter, expression) if expression.kind_of? String expression = ExpressionParser::new(self).parse(expression) @@ -194,15 +160,15 @@ def default_configuration Configuration::new(ptr.read_ccs_configuration_t, retain: false) end - def sample + def sample(distribution_space: nil) ptr = MemoryPointer::new(:ccs_configuration_t) - CCS.error_check CCS.ccs_configuration_space_sample(@handle, ptr) + CCS.error_check CCS.ccs_configuration_space_sample(@handle, distribution_space ? distribution_space.handle : nil, ptr) Configuration::new(ptr.read_ccs_configuration_t, retain: false) end - def samples(count) + def samples(count, distribution_space: nil) ptr = MemoryPointer::new(:ccs_configuration_t, count) - CCS.error_check CCS.ccs_configuration_space_samples(@handle, count, ptr) + CCS.error_check CCS.ccs_configuration_space_samples(@handle, distribution_space ? distribution_space.handle : nil, count, ptr) count.times.collect { |i| Configuration::new(ptr[i].read_pointer, retain: false) } end end diff --git a/bindings/ruby/lib/cconfigspace/distribution_space.rb b/bindings/ruby/lib/cconfigspace/distribution_space.rb new file mode 100644 index 00000000..7241fa53 --- /dev/null +++ b/bindings/ruby/lib/cconfigspace/distribution_space.rb @@ -0,0 +1,60 @@ +module CCS + + attach_function :ccs_create_distribution_space, [:ccs_configuration_space_t, :pointer], :ccs_result_t + attach_function :ccs_distribution_space_get_configuration_space, [:ccs_distribution_space_t, :pointer], :ccs_result_t + attach_function :ccs_distribution_space_set_distribution, [:ccs_distribution_space_t, :ccs_distribution_t, :pointer], :ccs_result_t + attach_function :ccs_distribution_space_get_parameter_distribution, [:ccs_distribution_space_t, :size_t, :pointer, :pointer], :ccs_result_t + + class DistributionSpace < Object + add_handle_property :configuration_space, :ccs_configuration_space_t, :ccs_distribution_space_get_configuration_space, memoize: true + + def initialize(handle = nil, retain: false, auto_release: true, + name: "", configuration_space: nil) + if handle + super(handle, retain: retain, auto_release: auto_release) + else + ptr = MemoryPointer::new(:ccs_distribution_space_t) + CCS.error_check CCS.ccs_create_distribution_space(configuration_space, ptr) + super(ptr.read_ccs_distribution_space_t, retain:false) + end + end + + def self.from_handle(handle, retain: true, auto_release: true) + self.new(handle, retain: retain, auto_release: auto_release) + end + + def set_distribution(distribution, parameters) + count = distribution.dimension + raise CCSError, :CCS_RESULT_ERROR_INVALID_VALUE if count != parameters.size + parameters = parameters.collect { |h| + case h + when Parameter + configuration_space.parameter_index(h) + when String, Symbol + configuration_space.parameter_index_by_name(parameter) + else + h + end + } + p_parameters = MemoryPointer::new(:size_t, count) + p_parameters.write_array_of_size_t(parameters) + CCS.error_check CCS.ccs_distribution_space_set_distribution(@handle, distribution, p_parameters) + self + end + + def get_parameter_distribution(parameter) + case parameter + when Parameter + parameter = configuration_space.parameter_index(parameter); + when String, Symbol + parameter = configuration_space.parameter_index_by_name(parameter); + end + p_distribution = MemoryPointer::new(:ccs_distribution_t) + p_indx = MemoryPointer::new(:size_t) + CCS.error_check CCS.ccs_distribution_space_get_parameter_distribution(@handle, parameter, p_distribution, p_indx) + [CCS::Distribution.from_handle(p_distribution.read_ccs_distribution_t), p_indx.read_size_t] + end + + end + +end diff --git a/bindings/ruby/test/test_configuration_space.rb b/bindings/ruby/test/test_configuration_space.rb index e07c6e88..7f32692d 100644 --- a/bindings/ruby/test/test_configuration_space.rb +++ b/bindings/ruby/test/test_configuration_space.rb @@ -37,20 +37,21 @@ def test_set_distribution h2 = CCS::NumericalParameter::Float.new h3 = CCS::NumericalParameter::Float.new cs = CCS::ConfigurationSpace::new(name: "space", parameters: [h1, h2, h3]) + ds = CCS::DistributionSpace::new(configuration_space: cs) distributions = [ CCS::UniformDistribution::Float.new(lower: 0.1, upper: 0.3), CCS::UniformDistribution::Float.new(lower: 0.2, upper: 0.6) ] d = CCS::MultivariateDistribution::new(distributions: distributions) - cs.set_distribution(d, [h1, h2]) - dist, indx = cs.get_parameter_distribution(h1) + ds.set_distribution(d, [h1, h2]) + dist, indx = ds.get_parameter_distribution(h1) assert_equal( d.handle, dist.handle ) assert_equal( 0, indx ) - dist, indx = cs.get_parameter_distribution(h2) + dist, indx = ds.get_parameter_distribution(h2) assert_equal( d.handle, dist.handle ) assert_equal( 1, indx ) - cs.set_distribution(d, [h3, h1]) - dist, indx = cs.get_parameter_distribution(h1) + ds.set_distribution(d, [h3, h1]) + dist, indx = ds.get_parameter_distribution(h1) assert_equal( d.handle, dist.handle ) assert_equal( 1, indx ) - dist, indx = cs.get_parameter_distribution(h3) + dist, indx = ds.get_parameter_distribution(h3) assert_equal( d.handle, dist.handle ) assert_equal( 0, indx ) end diff --git a/include/Makefile.am b/include/Makefile.am index a2669ca3..07486e5a 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -9,6 +9,7 @@ include_ccs_HEADERS = \ cconfigspace/interval.h \ cconfigspace/context.h \ cconfigspace/configuration_space.h \ + cconfigspace/distribution_space.h \ cconfigspace/features_space.h \ cconfigspace/parameter.h \ cconfigspace/expression.h \ diff --git a/include/cconfigspace.h b/include/cconfigspace.h index 28667182..3c6be6ef 100644 --- a/include/cconfigspace.h +++ b/include/cconfigspace.h @@ -14,6 +14,7 @@ #include "cconfigspace/context.h" #include "cconfigspace/binding.h" #include "cconfigspace/configuration_space.h" +#include "cconfigspace/distribution_space.h" #include "cconfigspace/configuration.h" #include "cconfigspace/features_space.h" #include "cconfigspace/features.h" diff --git a/include/cconfigspace/base.h b/include/cconfigspace/base.h index a2fbd359..5cb5b48e 100644 --- a/include/cconfigspace/base.h +++ b/include/cconfigspace/base.h @@ -102,6 +102,10 @@ typedef struct _ccs_expression_s *ccs_expression_t; * An opaque type defining a CCS context. */ typedef struct _ccs_context_s *ccs_context_t; +/** + * An opaque type defining a CCS distribution space. + */ +typedef struct _ccs_distribution_space_s *ccs_distribution_space_t; /** * An opaque type defining a CCS configuration space. */ @@ -177,75 +181,77 @@ typedef struct _ccs_tree_tuner_s *ccs_tree_tuner_t; */ enum ccs_result_e { /** Guard */ - CCS_RESULT_MAX = 2, + CCS_RESULT_MAX = 2, /** Try again */ - CCS_RESULT_AGAIN = 1, + CCS_RESULT_AGAIN = 1, /** Success */ - CCS_RESULT_SUCCESS = 0, + CCS_RESULT_SUCCESS = 0, /** Not a CCS object or not initialized */ - CCS_RESULT_ERROR_INVALID_OBJECT = -1, + CCS_RESULT_ERROR_INVALID_OBJECT = -1, /** Parameter has an invalid value */ - CCS_RESULT_ERROR_INVALID_VALUE = -2, + CCS_RESULT_ERROR_INVALID_VALUE = -2, /** The data type is invalid */ - CCS_RESULT_ERROR_INVALID_TYPE = -3, + CCS_RESULT_ERROR_INVALID_TYPE = -3, /** The provided scale is invalid */ - CCS_RESULT_ERROR_INVALID_SCALE = -4, + CCS_RESULT_ERROR_INVALID_SCALE = -4, /** The provided distribution is invalid */ - CCS_RESULT_ERROR_INVALID_DISTRIBUTION = -5, + CCS_RESULT_ERROR_INVALID_DISTRIBUTION = -5, /** The provided expression is invalid */ - CCS_RESULT_ERROR_INVALID_EXPRESSION = -6, + CCS_RESULT_ERROR_INVALID_EXPRESSION = -6, /** The provided parameter is invalid */ - CCS_RESULT_ERROR_INVALID_PARAMETER = -7, + CCS_RESULT_ERROR_INVALID_PARAMETER = -7, /** The provided configuration is invalid */ - CCS_RESULT_ERROR_INVALID_CONFIGURATION = -8, + CCS_RESULT_ERROR_INVALID_CONFIGURATION = -8, /** The parameter name is invalid */ - CCS_RESULT_ERROR_INVALID_NAME = -9, + CCS_RESULT_ERROR_INVALID_NAME = -9, /** The condition is invalid (unused) */ - CCS_RESULT_ERROR_INVALID_CONDITION = -10, + CCS_RESULT_ERROR_INVALID_CONDITION = -10, /** The provided tuner is invalid */ - CCS_RESULT_ERROR_INVALID_TUNER = -11, + CCS_RESULT_ERROR_INVALID_TUNER = -11, /** The constraint graph would be invalid */ - CCS_RESULT_ERROR_INVALID_GRAPH = -12, + CCS_RESULT_ERROR_INVALID_GRAPH = -12, /** The type is not comparable (unused) */ - CCS_RESULT_ERROR_TYPE_NOT_COMPARABLE = -13, + CCS_RESULT_ERROR_TYPE_NOT_COMPARABLE = -13, /** The bounds are invalid (unused) */ - CCS_RESULT_ERROR_INVALID_BOUNDS = -14, + CCS_RESULT_ERROR_INVALID_BOUNDS = -14, /** The index is out of bounds */ - CCS_RESULT_ERROR_OUT_OF_BOUNDS = -15, + CCS_RESULT_ERROR_OUT_OF_BOUNDS = -15, /** Could not gather enough samples */ - CCS_RESULT_ERROR_SAMPLING_UNSUCCESSFUL = -16, + CCS_RESULT_ERROR_SAMPLING_UNSUCCESSFUL = -16, /** An allocation failed due to lack of available memory */ - CCS_RESULT_ERROR_OUT_OF_MEMORY = -17, + CCS_RESULT_ERROR_OUT_OF_MEMORY = -17, /** The object does not support this operation */ - CCS_RESULT_ERROR_UNSUPPORTED_OPERATION = -18, + CCS_RESULT_ERROR_UNSUPPORTED_OPERATION = -18, /** The provided evaluation is invalid */ - CCS_RESULT_ERROR_INVALID_EVALUATION = -19, + CCS_RESULT_ERROR_INVALID_EVALUATION = -19, /** The provided features is invalid */ - CCS_RESULT_ERROR_INVALID_FEATURES = -20, + CCS_RESULT_ERROR_INVALID_FEATURES = -20, /** The provided features tuner is invalid */ - CCS_RESULT_ERROR_INVALID_FEATURES_TUNER = -21, + CCS_RESULT_ERROR_INVALID_FEATURES_TUNER = -21, /** The provided file path is invalid */ - CCS_RESULT_ERROR_INVALID_FILE_PATH = -22, + CCS_RESULT_ERROR_INVALID_FILE_PATH = -22, /** The provided buffer or file is too short */ - CCS_RESULT_ERROR_NOT_ENOUGH_DATA = -23, + CCS_RESULT_ERROR_NOT_ENOUGH_DATA = -23, /** The handle was a duplicate */ - CCS_RESULT_ERROR_DUPLICATE_HANDLE = -24, + CCS_RESULT_ERROR_DUPLICATE_HANDLE = -24, /** The handle was not found */ - CCS_RESULT_ERROR_INVALID_HANDLE = -25, + CCS_RESULT_ERROR_INVALID_HANDLE = -25, /** A system error occurred */ - CCS_RESULT_ERROR_SYSTEM = -26, + CCS_RESULT_ERROR_SYSTEM = -26, /** External error occurred (binding?) */ - CCS_RESULT_ERROR_EXTERNAL = -27, + CCS_RESULT_ERROR_EXTERNAL = -27, /** The provided tree is invalid */ - CCS_RESULT_ERROR_INVALID_TREE = -28, + CCS_RESULT_ERROR_INVALID_TREE = -28, /** The provided tree space is invalid */ - CCS_RESULT_ERROR_INVALID_TREE_SPACE = -29, + CCS_RESULT_ERROR_INVALID_TREE_SPACE = -29, /** The provided tree tuner is invalid */ - CCS_RESULT_ERROR_INVALID_TREE_TUNER = -30, + CCS_RESULT_ERROR_INVALID_TREE_TUNER = -30, + /** The provided distribution space is invalid */ + CCS_RESULT_ERROR_INVALID_DISTRIBUTION_SPACE = -31, /** Guard */ - CCS_RESULT_MIN = -31, + CCS_RESULT_MIN = -32, /** Try forcing 32 bits value for bindings */ - CCS_RESULT_FORCE_32BIT = INT32_MAX + CCS_RESULT_FORCE_32BIT = INT32_MAX }; /** @@ -302,6 +308,8 @@ enum ccs_object_type_e { CCS_OBJECT_TYPE_TREE_EVALUATION, /** A tree tuner */ CCS_OBJECT_TYPE_TREE_TUNER, + /** A distribution space */ + CCS_OBJECT_TYPE_DISTRIBUTION_SPACE, /** Guard */ CCS_OBJECT_TYPE_MAX, /** Try forcing 32 bits value for bindings */ diff --git a/include/cconfigspace/configuration_space.h b/include/cconfigspace/configuration_space.h index 4e34e1bc..e13b4c1a 100644 --- a/include/cconfigspace/configuration_space.h +++ b/include/cconfigspace/configuration_space.h @@ -10,8 +10,7 @@ extern "C" { * A configuration space is a context (see context.h) defining a set of * parameters. Configuration space also offer as constraints system to * describe conditional parameter activation as well as forbidden - * parameter configurations. Sampling distributions of parameters can - * be specified. + * parameter configurations. */ /** @@ -91,33 +90,6 @@ ccs_configuration_space_get_rng( ccs_configuration_space_t configuration_space, ccs_rng_t *rng_ret); -/** - * Set the distribution of one or more parameters. Existing distributions - * are discarded, and if a parameter is left without a distribution it's - * default distribution is used. - * @param[in,out] configuration_space - * @param[in] distribution the distribution to associate to the parameters - * at the indices given by \p indices - * @param[in] indices an array of parameters indices with as many elements - * as the dimension of the distribution - * @return #CCS_RESULT_SUCCESS on success - * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p configuration_space is not a - * valid CCS configuration space; or distribution is not a valid CCS - * distribution - * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p indices is NULL; or if indices - * contains values greater or equal to the number of parameters in the - * configuration space; or if indices contain duplicate values - * @return #CCS_RESULT_ERROR_OUT_OF_MEMORY if a memory could not be allocated to - * store additional parameters and associated data structures - * @remarks - * This function is thread-safe - */ -extern ccs_result_t -ccs_configuration_space_set_distribution( - ccs_configuration_space_t configuration_space, - ccs_distribution_t distribution, - size_t *indices); - /** * Get the number of parameters in a configuration space. * @param[in] configuration_space @@ -137,7 +109,7 @@ ccs_configuration_space_get_num_parameters( size_t *num_parameters_ret); /** - * Get an parameter in a configuration space given its index. + * Get a parameter in a configuration space given its index. * @param[in] configuration_space * @param[in] index the index of the parameter to retrieve * @param[out] parameter_ret a pointer to the variable that will contain @@ -158,33 +130,7 @@ ccs_configuration_space_get_parameter( ccs_parameter_t *parameter_ret); /** - * Get an parameter's distribution in a configuration space given its - * index. - * @param[in] configuration_space - * @param[in] index the index of the parameter - * @param[out] distribution_ret a pointer to the variable that will contain the - * distribution - * @param[out] index_ret a pointer to the variable that will contain the index - * of the component in the distribution - * @return #CCS_RESULT_SUCCESS on success - * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p configuration_space is not a - * valid CCS configuration space - * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p distribution_ret is NULL; or if - * \p index_ret is NULL - * @return #CCS_RESULT_ERROR_OUT_OF_BOUNDS if \p index is greater than the count - * of parameters in the configuration space - * @remarks - * This function is thread-safe - */ -extern ccs_result_t -ccs_configuration_space_get_parameter_distribution( - ccs_configuration_space_t configuration_space, - size_t index, - ccs_distribution_t *distribution_ret, - size_t *index_ret); - -/** - * Get an parameter in a configuration space given its name. + * Get a parameter in a configuration space given its name. * @param[in] configuration_space * @param[in] name the name of the parameter to retrieve * @param[out] parameter_ret a pointer to the variable that will contain @@ -206,7 +152,7 @@ ccs_configuration_space_get_parameter_by_name( ccs_parameter_t *parameter_ret); /** - * Get the index of an parameter in the configuration space given its name. + * Get the index of a parameter in the configuration space given its name. * @param[in] configuration_space * @param[in] name the name of the parameter to retrieve the index of * @param[out] index_ret a pointer to the variable that will contain the index @@ -227,7 +173,7 @@ ccs_configuration_space_get_parameter_index_by_name( size_t *index_ret); /** - * Get the index of an parameter in the configuration space. + * Get the index of a parameter in the configuration space. * @param[in] configuration_space * @param[in] parameter * @param[out] index_ret a pointer to the variable which will contain the index @@ -600,11 +546,13 @@ ccs_configuration_space_get_default_configuration( * to their default distribution. Parameter that are found to be inactive * will have the #ccs_inactive value. Returned configuration is valid. * @param[in] configuration_space + * @param[in] distribution_space an optional distribution space to use * @param[out] configuration_ret a pointer to the variable that will contain the * returned configuration * @return #CCS_RESULT_SUCCESS on success * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p configuration_space is not a - * valid CCS configuration space + * valid CCS configuration space; or if \p distribution_space is not a valid + * CCS distribution space * @return #CCS_RESULT_ERROR_INVALID_VALUE if configuration_ret is NULL * @return #CCS_RESULT_ERROR_SAMPLING_UNSUCCESSFUL if no valid configuration * could be sampled @@ -618,6 +566,7 @@ ccs_configuration_space_get_default_configuration( extern ccs_result_t ccs_configuration_space_sample( ccs_configuration_space_t configuration_space, + ccs_distribution_space_t distribution_space, ccs_configuration_t *configuration_ret); /** @@ -627,12 +576,14 @@ ccs_configuration_space_sample( * inactive will have the #ccs_inactive value. Returned configurations are * valid. * @param[in] configuration_space + * @param[in] distribution_space an optional distribution space to use * @param[in] num_configurations the number of requested configurations * @param[out] configurations an array of \p num_configurations that will * contain the requested configurations * @return #CCS_RESULT_SUCCESS on success * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p configuration_space is not a - * valid CCS configuration space + * valid CCS configuration space; or if \p distribution_space is not a valid + * CCS distribution space * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p configurations is NULL and \p * num_configurations is greater than 0 * @return #CCS_RESULT_ERROR_SAMPLING_UNSUCCESSFUL if no or not enough valid @@ -649,6 +600,7 @@ ccs_configuration_space_sample( extern ccs_result_t ccs_configuration_space_samples( ccs_configuration_space_t configuration_space, + ccs_distribution_space_t distribution_space, size_t num_configurations, ccs_configuration_t *configurations); diff --git a/include/cconfigspace/distribution_space.h b/include/cconfigspace/distribution_space.h new file mode 100644 index 00000000..aaabfd88 --- /dev/null +++ b/include/cconfigspace/distribution_space.h @@ -0,0 +1,109 @@ +#ifndef _CCS_DISTRIBUTION_SPACE +#define _CCS_DISTRIBUTION_SPACE + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file distribution_space.h + * A distribution space is set of sampling distribution over the parameters of + * a configuration space. + */ + +/** + * Create an new distribution space. + * @param[in] configuration_space the configuration space the distribution + * space will be used to sample + * @param[out] distribution_space_ret a pointer to the variable that will + * contain the newly created distribution + * space + * @return #CCS_RESULT_SUCCESS on success + * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p configuration_space is not a + * valid CCS configuration space; or if \p objective_space is not a valid CCS + * objective space + * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p distribution_space_ret is NULL + * @remarks + * This function is thread-safe + */ +extern ccs_result_t +ccs_create_distribution_space( + ccs_configuration_space_t configuration_space, + ccs_distribution_space_t *distribution_space_ret); + +/** + * Get the associated configuration space. + * @param[in] distribution_space + * @param[out] configuration_space_ret a pointer to the variable that will + * contain the configuration space + * @return #CCS_RESULT_SUCCESS on success + * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p distribution_space is not a + * valid CCS distribution space + * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p configuration_space_ret is NULL + * @remarks + * This function is thread-safe + */ +extern ccs_result_t +ccs_distribution_space_get_configuration_space( + ccs_distribution_space_t distribution_space, + ccs_configuration_space_t *configuration_space_ret); + +/** + * Set the distribution of one or more parameters. Existing distributions + * are discarded, and if a parameter is left without a distribution it's + * default distribution is used. + * @param[in,out] distribution_space + * @param[in] distribution the distribution to associate to the parameters + * at the indices given by \p indices + * @param[in] indices an array of parameters indices with as many elements + * as the dimension of the distribution + * @return #CCS_RESULT_SUCCESS on success + * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p distribution_space is not a + * valid CCS distribution space; or distribution is not a valid CCS + * distribution + * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p indices is NULL; or if indices + * contains values greater or equal to the number of parameters in the + * distribution space's configuration space; or if indices contain duplicate + * values + * @return #CCS_RESULT_ERROR_OUT_OF_MEMORY if a memory could not be allocated to + * store additional parameters and associated data structures + * @remarks + * This function is thread-safe + */ +extern ccs_result_t +ccs_distribution_space_set_distribution( + ccs_distribution_space_t distribution_space, + ccs_distribution_t distribution, + size_t *indices); + +/** + * Get a parameter's distribution in a distribution space given its + * index. + * @param[in] distribution_space + * @param[in] index the index of the parameter + * @param[out] distribution_ret a pointer to the variable that will contain the + * distribution + * @param[out] index_ret a pointer to the variable that will contain the index + * of the component in the distribution + * @return #CCS_RESULT_SUCCESS on success + * @return #CCS_RESULT_ERROR_INVALID_OBJECT if \p distribution_space is not a + * valid CCS distribution space + * @return #CCS_RESULT_ERROR_INVALID_VALUE if \p distribution_ret is NULL; or if + * \p index_ret is NULL + * @return #CCS_RESULT_ERROR_OUT_OF_BOUNDS if \p index is greater than the count + * of parameters in the distribution space's configuration space + * @remarks + * This function is thread-safe + */ +extern ccs_result_t +ccs_distribution_space_get_parameter_distribution( + ccs_distribution_space_t distribution_space, + size_t index, + ccs_distribution_t *distribution_ret, + size_t *index_ret); + +#ifdef __cplusplus +} +#endif + +#endif //_CCS_DISTRIBUTION_SPACE diff --git a/src/Makefile.am b/src/Makefile.am index b6006778..000f5e3b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,6 +62,9 @@ libcconfigspace_la_SOURCES = \ configuration_space.c \ configuration_space_internal.h \ configuration_space_deserialize.h \ + distribution_space.c \ + distribution_space_internal.h \ + distribution_space_deserialize.h \ binding.c \ binding_internal.h \ configuration.c \ diff --git a/src/cconfigspace.c b/src/cconfigspace.c index 7574ec2f..3de67147 100644 --- a/src/cconfigspace.c +++ b/src/cconfigspace.c @@ -563,6 +563,7 @@ ccs_object_serialize( #include "expression_deserialize.h" #include "features_space_deserialize.h" #include "configuration_space_deserialize.h" +#include "distribution_space_deserialize.h" #include "objective_space_deserialize.h" #include "configuration_deserialize.h" #include "evaluation_deserialize.h" @@ -735,6 +736,11 @@ _ccs_object_deserialize_with_opts( (ccs_tree_tuner_t *)object_ret, format, version, buffer_size, buffer, opts)); break; + case CCS_OBJECT_TYPE_DISTRIBUTION_SPACE: + CCS_VALIDATE(_ccs_distribution_space_deserialize( + (ccs_distribution_space_t *)object_ret, format, + version, buffer_size, buffer, opts)); + break; default: CCS_RAISE( CCS_RESULT_ERROR_UNSUPPORTED_OPERATION, @@ -1072,6 +1078,7 @@ ccs_get_result_name(ccs_result_t result, const char **name) ETOCASE(CCS_RESULT_ERROR_INVALID_TREE); ETOCASE(CCS_RESULT_ERROR_INVALID_TREE_SPACE); ETOCASE(CCS_RESULT_ERROR_INVALID_TREE_TUNER); + ETOCASE(CCS_RESULT_ERROR_INVALID_DISTRIBUTION_SPACE); default: *name = NULL; CCS_RAISE( diff --git a/src/configuration_space.c b/src/configuration_space.c index 369b73bf..8c98a91e 100644 --- a/src/configuration_space.c +++ b/src/configuration_space.c @@ -1,5 +1,6 @@ #include "cconfigspace_internal.h" #include "configuration_space_internal.h" +#include "distribution_space_internal.h" #include "configuration_internal.h" #include "distribution_internal.h" #include "expression_internal.h" @@ -43,14 +44,12 @@ _ccs_configuration_space_del(ccs_object_t object) utarray_free(configuration_space->data->parameters); utarray_free(configuration_space->data->forbidden_clauses); utarray_free(configuration_space->data->sorted_indexes); - _ccs_distribution_wrapper_t *dw, *tmp; - DL_FOREACH_SAFE(configuration_space->data->distribution_list, dw, tmp) - { - DL_DELETE(configuration_space->data->distribution_list, dw); - ccs_release_object(dw->distribution); - free(dw); - } ccs_release_object(configuration_space->data->rng); + if (configuration_space->data->default_distribution_space) { + _ccs_distribution_space_del_no_release( + configuration_space->data->default_distribution_space); + free(configuration_space->data->default_distribution_space); + } return CCS_RESULT_SUCCESS; } @@ -62,8 +61,6 @@ _ccs_serialize_bin_size_ccs_configuration_space_data( { size_t condition_count; _ccs_parameter_wrapper_cs_t *wrapper; - size_t distribution_count; - _ccs_distribution_wrapper_t *dw; ccs_expression_t *expr; *cum_size += _ccs_serialize_bin_size_string(data->name); @@ -78,9 +75,6 @@ _ccs_serialize_bin_size_ccs_configuration_space_data( condition_count++; *cum_size += _ccs_serialize_bin_size_size(condition_count); - DL_COUNT(data->distribution_list, dw, distribution_count); - *cum_size += _ccs_serialize_bin_size_size(distribution_count); - *cum_size += _ccs_serialize_bin_size_size( utarray_len(data->forbidden_clauses)); @@ -112,19 +106,6 @@ _ccs_serialize_bin_size_ccs_configuration_space_data( condition_count++; } - /* distributions */ - dw = NULL; - DL_FOREACH(data->distribution_list, dw) - { - CCS_VALIDATE(dw->distribution->obj.ops->serialize_size( - dw->distribution, CCS_SERIALIZE_FORMAT_BINARY, cum_size, - opts)); - *cum_size += _ccs_serialize_bin_size_size(dw->dimension); - for (size_t i = 0; i < dw->dimension; i++) - *cum_size += _ccs_serialize_bin_size_size( - dw->parameter_indexes[i]); - } - /* forbidden clauses */ expr = NULL; while ((expr = (ccs_expression_t *)utarray_next( @@ -143,8 +124,6 @@ _ccs_serialize_bin_ccs_configuration_space_data( { size_t condition_count; _ccs_parameter_wrapper_cs_t *wrapper; - size_t distribution_count; - _ccs_distribution_wrapper_t *dw; ccs_expression_t *expr; CCS_VALIDATE( @@ -161,10 +140,6 @@ _ccs_serialize_bin_ccs_configuration_space_data( CCS_VALIDATE( _ccs_serialize_bin_size(condition_count, buffer_size, buffer)); - DL_COUNT(data->distribution_list, dw, distribution_count); - CCS_VALIDATE(_ccs_serialize_bin_size( - distribution_count, buffer_size, buffer)); - CCS_VALIDATE(_ccs_serialize_bin_size( utarray_len(data->forbidden_clauses), buffer_size, buffer)); @@ -196,20 +171,6 @@ _ccs_serialize_bin_ccs_configuration_space_data( condition_count++; } - /* distributions */ - dw = NULL; - DL_FOREACH(data->distribution_list, dw) - { - CCS_VALIDATE(dw->distribution->obj.ops->serialize( - dw->distribution, CCS_SERIALIZE_FORMAT_BINARY, - buffer_size, buffer, opts)); - CCS_VALIDATE(_ccs_serialize_bin_size( - dw->dimension, buffer_size, buffer)); - for (size_t i = 0; i < dw->dimension; i++) - CCS_VALIDATE(_ccs_serialize_bin_size( - dw->parameter_indexes[i], buffer_size, buffer)); - } - /* forbidden clauses */ expr = NULL; while ((expr = (ccs_expression_t *)utarray_next( @@ -381,49 +342,26 @@ _ccs_configuration_space_add_parameter( parameter_hash, CCS_RESULT_ERROR_INVALID_PARAMETER, "An parameter with name '%s' already exists in the configuration space", name); - UT_array *parameters; - size_t index; - size_t dimension; - _ccs_parameter_wrapper_cs_t parameter_wrapper; - _ccs_distribution_wrapper_t *distrib_wrapper; - ccs_distribution_t distribution; - uintptr_t pmem; + UT_array *parameters; + size_t index; + _ccs_parameter_wrapper_cs_t parameter_wrapper; parameter_wrapper.parameter = parameter; CCS_VALIDATE(ccs_retain_object(parameter)); - CCS_VALIDATE_ERR_GOTO( - err, - ccs_parameter_get_default_distribution(parameter, &distribution), - errorparameter); - dimension = 1; - pmem = (uintptr_t)malloc( - sizeof(_ccs_distribution_wrapper_t) + - sizeof(size_t) * dimension); - CCS_REFUTE_ERR_GOTO( - err, !pmem, CCS_RESULT_ERROR_OUT_OF_MEMORY, errordistrib); - distrib_wrapper = (_ccs_distribution_wrapper_t *)pmem; - distrib_wrapper->distribution = distribution; - distrib_wrapper->dimension = dimension; - distrib_wrapper->parameter_indexes = - (size_t *)(pmem + sizeof(_ccs_distribution_wrapper_t)); - parameter_hash = (_ccs_parameter_index_hash_t *)malloc( sizeof(_ccs_parameter_index_hash_t)); CCS_REFUTE_ERR_GOTO( err, !parameter_hash, CCS_RESULT_ERROR_OUT_OF_MEMORY, - errordistrib_wrapper); - - parameters = configuration_space->data->parameters; - index = utarray_len(parameters); - parameter_hash->parameter = parameter; - parameter_hash->name = name; - parameter_hash->index = index; - distrib_wrapper->parameter_indexes[0] = index; - parameter_wrapper.distribution_index = 0; - parameter_wrapper.distribution = distrib_wrapper; - parameter_wrapper.condition = NULL; - parameter_wrapper.parents = NULL; - parameter_wrapper.children = NULL; + errorparameter); + + parameters = configuration_space->data->parameters; + index = utarray_len(parameters); + parameter_hash->parameter = parameter; + parameter_hash->name = name; + parameter_hash->index = index; + parameter_wrapper.condition = NULL; + parameter_wrapper.parents = NULL; + parameter_wrapper.children = NULL; utarray_new(parameter_wrapper.parents, &_size_t_icd); utarray_new(parameter_wrapper.children, &_size_t_icd); @@ -436,8 +374,6 @@ _ccs_configuration_space_add_parameter( HASH_ADD( hh_handle, configuration_space->data->handle_hash, parameter, sizeof(ccs_parameter_t), parameter_hash); - DL_APPEND( - configuration_space->data->distribution_list, distrib_wrapper); return CCS_RESULT_SUCCESS; errorutarray: @@ -449,9 +385,6 @@ _ccs_configuration_space_add_parameter( utarray_free(parameter_wrapper.parents); if (parameter_wrapper.children) utarray_free(parameter_wrapper.children); - free(distrib_wrapper); -errordistrib: - ccs_release_object(distribution); errorparameter: ccs_release_object(parameter); return err; @@ -523,6 +456,12 @@ ccs_create_configuration_space( _ccs_configuration_space_add_parameters( config_space, num_parameters, parameters), errparams); + CCS_VALIDATE_ERR_GOTO( + err, + _ccs_create_distribution_space_no_retain( + config_space, NULL, + &config_space->data->default_distribution_space), + errparams); return CCS_RESULT_SUCCESS; errarrays: if (config_space->data->parameters) @@ -585,186 +524,6 @@ ccs_configuration_space_get_rng( return CCS_RESULT_SUCCESS; } -ccs_result_t -ccs_configuration_space_set_distribution( - ccs_configuration_space_t configuration_space, - ccs_distribution_t distribution, - size_t *indexes) -{ - CCS_CHECK_OBJ(configuration_space, CCS_OBJECT_TYPE_CONFIGURATION_SPACE); - CCS_CHECK_OBJ(distribution, CCS_OBJECT_TYPE_DISTRIBUTION); - CCS_CHECK_PTR(indexes); - - _ccs_distribution_wrapper_t *dwrapper; - _ccs_distribution_wrapper_t **p_dwrappers_to_del; - _ccs_distribution_wrapper_t **p_dwrappers_to_add; - _ccs_parameter_wrapper_cs_t *hwrapper; - ccs_result_t err; - size_t dim; - uintptr_t mem; - uintptr_t dmem; - uintptr_t cur_mem; - size_t *parameters_without_distrib; - size_t to_add_count = 0; - size_t to_del_count = 0; - size_t without_distrib_count = 0; - - CCS_VALIDATE(ccs_distribution_get_dimension(distribution, &dim)); - CCS_OBJ_WRLOCK(configuration_space); - UT_array *parameters = configuration_space->data->parameters; - size_t num_parameters = utarray_len(parameters); - - for (size_t i = 0; i < dim; i++) { - CCS_REFUTE_ERR_GOTO( - err, indexes[i] >= num_parameters, - CCS_RESULT_ERROR_INVALID_VALUE, errdistrib); - // Check duplicate entries - for (size_t j = i + 1; j < dim; j++) - CCS_REFUTE_ERR_GOTO( - err, indexes[i] == indexes[j], - CCS_RESULT_ERROR_INVALID_VALUE, errdistrib); - } - - mem = (uintptr_t)malloc( - sizeof(void *) * num_parameters * 2 + - sizeof(size_t) * num_parameters); - CCS_REFUTE_ERR_GOTO( - err, !mem, CCS_RESULT_ERROR_OUT_OF_MEMORY, errdistrib); - cur_mem = mem; - p_dwrappers_to_del = (_ccs_distribution_wrapper_t **)cur_mem; - cur_mem += sizeof(_ccs_distribution_wrapper_t *) * num_parameters; - p_dwrappers_to_add = (_ccs_distribution_wrapper_t **)cur_mem; - cur_mem += sizeof(_ccs_distribution_wrapper_t *) * num_parameters; - parameters_without_distrib = (size_t *)cur_mem; - cur_mem += sizeof(size_t) * num_parameters; - - for (size_t i = 0; i < dim; i++) { - int add = 1; - hwrapper = (_ccs_parameter_wrapper_cs_t *)utarray_eltptr( - parameters, indexes[i]); - for (size_t j = 0; j < to_del_count; j++) - if (p_dwrappers_to_del[j] == hwrapper->distribution) { - add = 0; - break; - } - if (add) - p_dwrappers_to_del[to_del_count++] = - hwrapper->distribution; - } - for (size_t i = 0; i < to_del_count; i++) { - for (size_t j = 0; j < p_dwrappers_to_del[i]->dimension; j++) { - parameters_without_distrib[without_distrib_count++] = - p_dwrappers_to_del[i]->parameter_indexes[j]; - } - } - - dmem = (uintptr_t)malloc( - sizeof(_ccs_distribution_wrapper_t) + sizeof(size_t) * dim); - CCS_REFUTE_ERR_GOTO(err, !dmem, CCS_RESULT_ERROR_OUT_OF_MEMORY, memory); - - dwrapper = (_ccs_distribution_wrapper_t *)dmem; - dwrapper->distribution = distribution; - dwrapper->dimension = dim; - dwrapper->parameter_indexes = - (size_t *)(dmem + sizeof(_ccs_distribution_wrapper_t)); - for (size_t i = 0; i < dim; i++) { - dwrapper->parameter_indexes[i] = indexes[i]; - size_t indx = 0; - for (size_t j = 0; j < without_distrib_count; j++, indx++) - if (parameters_without_distrib[j] == indexes[i]) - break; - for (size_t j = indx + 1; j < without_distrib_count; j++) - parameters_without_distrib[j - 1] = - parameters_without_distrib[j]; - without_distrib_count--; - } - CCS_VALIDATE_ERR_GOTO(err, ccs_retain_object(distribution), errdmem); - - p_dwrappers_to_add[0] = dwrapper; - to_add_count = 1; - for (size_t i = 0; i < without_distrib_count; i++) { - dmem = (uintptr_t)malloc( - sizeof(_ccs_distribution_wrapper_t) + sizeof(size_t)); - CCS_REFUTE_ERR_GOTO( - err, !dmem, CCS_RESULT_ERROR_OUT_OF_MEMORY, memory); - dwrapper = (_ccs_distribution_wrapper_t *)dmem; - dwrapper->parameter_indexes = - (size_t *)(dmem + sizeof(_ccs_distribution_wrapper_t)); - dwrapper->dimension = 1; - dwrapper->parameter_indexes[0] = parameters_without_distrib[i]; - hwrapper = (_ccs_parameter_wrapper_cs_t *)utarray_eltptr( - parameters, parameters_without_distrib[i]); - CCS_VALIDATE_ERR_GOTO( - err, - ccs_parameter_get_default_distribution( - hwrapper->parameter, &(dwrapper->distribution)), - dwrappers); - p_dwrappers_to_add[to_add_count++] = dwrapper; - } - - for (size_t i = 0; i < to_del_count; i++) { - DL_DELETE( - configuration_space->data->distribution_list, - p_dwrappers_to_del[i]); - ccs_release_object(p_dwrappers_to_del[i]->distribution); - free(p_dwrappers_to_del[i]); - } - for (size_t i = 0; i < to_add_count; i++) { - DL_APPEND( - configuration_space->data->distribution_list, - p_dwrappers_to_add[i]); - for (size_t j = 0; j < p_dwrappers_to_add[i]->dimension; j++) { - hwrapper = (_ccs_parameter_wrapper_cs_t *)utarray_eltptr( - parameters, - p_dwrappers_to_add[i]->parameter_indexes[j]); - hwrapper->distribution_index = j; - hwrapper->distribution = p_dwrappers_to_add[i]; - } - } - - free((void *)mem); - CCS_OBJ_UNLOCK(configuration_space); - return CCS_RESULT_SUCCESS; -dwrappers: - for (size_t i = 0; i < to_add_count; i++) { - ccs_release_object(p_dwrappers_to_add[i]->distribution); - free(p_dwrappers_to_add[i]); - } -errdmem: - if (dmem) - free((void *)dmem); -memory: - free((void *)mem); -errdistrib: - CCS_OBJ_UNLOCK(configuration_space); - return err; -} - -extern ccs_result_t -ccs_configuration_space_get_parameter_distribution( - ccs_configuration_space_t configuration_space, - size_t index, - ccs_distribution_t *distribution_ret, - size_t *index_ret) -{ - ccs_result_t err = CCS_RESULT_SUCCESS; - CCS_CHECK_OBJ(configuration_space, CCS_OBJECT_TYPE_CONFIGURATION_SPACE); - CCS_CHECK_PTR(distribution_ret); - CCS_CHECK_PTR(index_ret); - - CCS_OBJ_RDLOCK(configuration_space); - _ccs_parameter_wrapper_cs_t *wrapper = - (_ccs_parameter_wrapper_cs_t *)utarray_eltptr( - configuration_space->data->parameters, - (unsigned int)index); - CCS_REFUTE_ERR_GOTO(err, !wrapper, CCS_RESULT_ERROR_OUT_OF_BOUNDS, end); - *distribution_ret = wrapper->distribution->distribution; - *index_ret = wrapper->distribution_index; -end: - CCS_OBJ_UNLOCK(configuration_space); - return err; -} - ccs_result_t ccs_configuration_space_get_num_parameters( ccs_configuration_space_t configuration_space, @@ -1049,12 +808,14 @@ ccs_configuration_space_check_configuration_values( static ccs_result_t _sample(ccs_configuration_space_t configuration_space, + ccs_distribution_space_t distrib_space, ccs_configuration_t config, ccs_bool_t *found) { - ccs_result_t err; - ccs_rng_t rng = configuration_space->data->rng; - UT_array *array = configuration_space->data->parameters; + ccs_result_t err; + ccs_rng_t rng = configuration_space->data->rng; + UT_array *array = configuration_space->data->parameters; + ccs_distribution_space_t distribution_space; _ccs_distribution_wrapper_t *dwrapper = NULL; _ccs_parameter_wrapper_cs_t *hwrapper = NULL; ccs_datum_t *values = config->data->values; @@ -1070,7 +831,13 @@ _sample(ccs_configuration_space_t configuration_space, p_values = (ccs_datum_t *)mem; hps = (ccs_parameter_t *)(mem + num_parameters * sizeof(ccs_datum_t)); - DL_FOREACH(configuration_space->data->distribution_list, dwrapper) + if (distrib_space) { + distribution_space = distrib_space; + CCS_OBJ_RDLOCK(distrib_space); + } else + distribution_space = + configuration_space->data->default_distribution_space; + DL_FOREACH(distribution_space->data->distribution_list, dwrapper) { for (size_t i = 0; i < dwrapper->dimension; i++) { size_t hindex = dwrapper->parameter_indexes[i]; @@ -1097,6 +864,8 @@ _sample(ccs_configuration_space_t configuration_space, configuration_space, config->data->values, found), memory); memory: + if (distrib_space) + CCS_OBJ_UNLOCK(distrib_space); free((void *)mem); return err; } @@ -1104,9 +873,18 @@ _sample(ccs_configuration_space_t configuration_space, ccs_result_t ccs_configuration_space_sample( ccs_configuration_space_t configuration_space, + ccs_distribution_space_t distribution_space, ccs_configuration_t *configuration_ret) { CCS_CHECK_OBJ(configuration_space, CCS_OBJECT_TYPE_CONFIGURATION_SPACE); + if (distribution_space) { + CCS_CHECK_OBJ( + distribution_space, CCS_OBJECT_TYPE_DISTRIBUTION_SPACE); + CCS_REFUTE( + distribution_space->data->configuration_space != + configuration_space, + CCS_RESULT_ERROR_INVALID_DISTRIBUTION_SPACE); + } CCS_CHECK_PTR(configuration_ret); ccs_result_t err; ccs_bool_t found; @@ -1122,7 +900,9 @@ ccs_configuration_space_sample( errgraph); do { CCS_VALIDATE_ERR_GOTO( - err, _sample(configuration_space, config, &found), + err, + _sample(configuration_space, distribution_space, config, + &found), errc); counter++; } while (!found && counter < 100); @@ -1141,10 +921,19 @@ ccs_configuration_space_sample( ccs_result_t ccs_configuration_space_samples( ccs_configuration_space_t configuration_space, + ccs_distribution_space_t distribution_space, size_t num_configurations, ccs_configuration_t *configurations) { CCS_CHECK_OBJ(configuration_space, CCS_OBJECT_TYPE_CONFIGURATION_SPACE); + if (distribution_space) { + CCS_CHECK_OBJ( + distribution_space, CCS_OBJECT_TYPE_DISTRIBUTION_SPACE); + CCS_REFUTE( + distribution_space->data->configuration_space != + configuration_space, + CCS_RESULT_ERROR_INVALID_DISTRIBUTION_SPACE); + } CCS_CHECK_ARY(num_configurations, configurations); if (!num_configurations) return CCS_RESULT_SUCCESS; @@ -1169,7 +958,9 @@ ccs_configuration_space_samples( configuration_space, 0, NULL, &config), errgraph); CCS_VALIDATE_ERR_GOTO( - err, _sample(configuration_space, config, &found), + err, + _sample(configuration_space, distribution_space, config, + &found), errc); counter++; if (found) { diff --git a/src/configuration_space_deserialize.h b/src/configuration_space_deserialize.h index 68e80af7..c644248d 100644 --- a/src/configuration_space_deserialize.h +++ b/src/configuration_space_deserialize.h @@ -6,19 +6,15 @@ #include "rng_deserialize.h" struct _ccs_configuration_space_data_mock_s { - const char *name; - size_t num_parameters; - size_t num_conditions; - size_t num_distributions; - size_t num_forbidden_clauses; - ccs_rng_t rng; - ccs_parameter_t *parameters; - size_t *cond_parameter_indices; - ccs_expression_t *conditions; - ccs_distribution_t *distributions; - size_t *dimensions; - size_t *distrib_parameter_indices; - ccs_expression_t *forbidden_clauses; + const char *name; + size_t num_parameters; + size_t num_conditions; + size_t num_forbidden_clauses; + ccs_rng_t rng; + ccs_parameter_t *parameters; + size_t *cond_parameter_indices; + ccs_expression_t *conditions; + ccs_expression_t *forbidden_clauses; }; typedef struct _ccs_configuration_space_data_mock_s _ccs_configuration_space_data_mock_t; @@ -39,8 +35,6 @@ _ccs_deserialize_bin_ccs_configuration_space_data( &data->num_parameters, buffer_size, buffer)); CCS_VALIDATE(_ccs_deserialize_bin_size( &data->num_conditions, buffer_size, buffer)); - CCS_VALIDATE(_ccs_deserialize_bin_size( - &data->num_distributions, buffer_size, buffer)); CCS_VALIDATE(_ccs_deserialize_bin_size( &data->num_forbidden_clauses, buffer_size, buffer)); CCS_VALIDATE(_ccs_rng_deserialize( @@ -48,15 +42,12 @@ _ccs_deserialize_bin_ccs_configuration_space_data( buffer, opts)); if (!(data->num_parameters + data->num_conditions + - data->num_distributions + data->num_forbidden_clauses)) + data->num_forbidden_clauses)) return CCS_RESULT_SUCCESS; mem = (uintptr_t)calloc( - data->num_parameters * - (sizeof(ccs_parameter_t) + sizeof(size_t)) + + data->num_parameters * sizeof(ccs_parameter_t) + data->num_conditions * (sizeof(ccs_expression_t) + sizeof(size_t)) + - data->num_distributions * - (sizeof(ccs_distribution_t) + sizeof(size_t)) + data->num_forbidden_clauses * sizeof(ccs_expression_t), 1); CCS_REFUTE(!mem, CCS_RESULT_ERROR_OUT_OF_MEMORY); @@ -67,12 +58,6 @@ _ccs_deserialize_bin_ccs_configuration_space_data( mem += data->num_conditions * sizeof(size_t); data->conditions = (ccs_expression_t *)mem; mem += data->num_conditions * sizeof(ccs_expression_t); - data->distributions = (ccs_distribution_t *)mem; - mem += data->num_distributions * sizeof(ccs_distribution_t); - data->dimensions = (size_t *)mem; - mem += data->num_distributions * sizeof(size_t); - data->distrib_parameter_indices = (size_t *)mem; - mem += data->num_parameters * sizeof(size_t); data->forbidden_clauses = (ccs_expression_t *)mem; for (size_t i = 0; i < data->num_parameters; i++) @@ -88,21 +73,6 @@ _ccs_deserialize_bin_ccs_configuration_space_data( version, buffer_size, buffer, opts)); } - size_t *indices; - indices = data->distrib_parameter_indices; - for (size_t i = 0; i < data->num_distributions; i++) { - CCS_VALIDATE(_ccs_distribution_deserialize( - data->distributions + i, CCS_SERIALIZE_FORMAT_BINARY, - version, buffer_size, buffer, opts)); - CCS_VALIDATE(_ccs_deserialize_bin_size( - data->dimensions + i, buffer_size, buffer)); - for (size_t j = 0; j < data->dimensions[i]; j++) { - CCS_VALIDATE(_ccs_deserialize_bin_size( - indices, buffer_size, buffer)); - indices++; - } - } - for (size_t i = 0; i < data->num_forbidden_clauses; i++) { CCS_VALIDATE(_ccs_expression_deserialize( data->forbidden_clauses + i, @@ -134,10 +104,8 @@ _ccs_deserialize_bin_configuration_space( new_opts.map_values = CCS_TRUE; CCS_VALIDATE(ccs_create_map(&new_opts.handle_map)); - _ccs_configuration_space_data_mock_t data = {NULL, 0, 0, 0, - 0, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL}; + _ccs_configuration_space_data_mock_t data = { + NULL, 0, 0, 0, NULL, NULL, NULL, NULL, NULL}; CCS_VALIDATE_ERR_GOTO( res, _ccs_deserialize_bin_ccs_configuration_space_data( @@ -162,17 +130,6 @@ _ccs_deserialize_bin_configuration_space( data.cond_parameter_indices[i], data.conditions[i]), err_configuration_space); - size_t *indices; - indices = data.distrib_parameter_indices; - for (size_t i = 0; i < data.num_distributions; i++) { - CCS_VALIDATE_ERR_GOTO( - res, - ccs_configuration_space_set_distribution( - *configuration_space_ret, data.distributions[i], - indices), - err_configuration_space); - indices += data.dimensions[i]; - } CCS_VALIDATE_ERR_GOTO( res, ccs_configuration_space_add_forbidden_clauses( @@ -202,10 +159,6 @@ _ccs_deserialize_bin_configuration_space( for (size_t i = 0; i < data.num_conditions; i++) if (data.conditions[i]) ccs_release_object(data.conditions[i]); - if (data.distributions) - for (size_t i = 0; i < data.num_distributions; i++) - if (data.distributions[i]) - ccs_release_object(data.distributions[i]); if (data.forbidden_clauses) for (size_t i = 0; i < data.num_forbidden_clauses; i++) if (data.forbidden_clauses[i]) diff --git a/src/configuration_space_internal.h b/src/configuration_space_internal.h index abd1898c..272edbfc 100644 --- a/src/configuration_space_internal.h +++ b/src/configuration_space_internal.h @@ -6,23 +6,13 @@ struct _ccs_distribution_wrapper_s; typedef struct _ccs_distribution_wrapper_s _ccs_distribution_wrapper_t; struct _ccs_parameter_wrapper_cs_s { - ccs_parameter_t parameter; - size_t distribution_index; - _ccs_distribution_wrapper_t *distribution; - ccs_expression_t condition; - UT_array *parents; - UT_array *children; + ccs_parameter_t parameter; + ccs_expression_t condition; + UT_array *parents; + UT_array *children; }; typedef struct _ccs_parameter_wrapper_cs_s _ccs_parameter_wrapper_cs_t; -struct _ccs_distribution_wrapper_s { - ccs_distribution_t distribution; - size_t dimension; - size_t *parameter_indexes; - _ccs_distribution_wrapper_t *prev; - _ccs_distribution_wrapper_t *next; -}; - struct _ccs_configuration_space_data_s; typedef struct _ccs_configuration_space_data_s _ccs_configuration_space_data_t; @@ -42,10 +32,10 @@ struct _ccs_configuration_space_data_s { _ccs_parameter_index_hash_t *name_hash; _ccs_parameter_index_hash_t *handle_hash; ccs_rng_t rng; - _ccs_distribution_wrapper_t *distribution_list; UT_array *forbidden_clauses; ccs_bool_t graph_ok; UT_array *sorted_indexes; + ccs_distribution_space_t default_distribution_space; }; #endif //_CONFIGURATION_SPACE_INTERNAL_H diff --git a/src/distribution_deserialize.h b/src/distribution_deserialize.h index d476cf44..8d3529f6 100644 --- a/src/distribution_deserialize.h +++ b/src/distribution_deserialize.h @@ -372,6 +372,7 @@ _ccs_deserialize_bin_distribution( return CCS_RESULT_SUCCESS; err_dis: ccs_release_object(*distribution_ret); + *distribution_ret = NULL; return res; } diff --git a/src/distribution_space.c b/src/distribution_space.c new file mode 100644 index 00000000..8e1f3851 --- /dev/null +++ b/src/distribution_space.c @@ -0,0 +1,397 @@ +#include "cconfigspace_internal.h" +#include "distribution_space_internal.h" +#include "distribution_internal.h" + +static ccs_result_t +_ccs_distribution_space_del(ccs_object_t object) +{ + ccs_distribution_space_t distribution_space = + (ccs_distribution_space_t)object; + _ccs_distribution_space_del_no_release(distribution_space); + ccs_release_object(distribution_space->data->configuration_space); + return CCS_RESULT_SUCCESS; +} + +static inline ccs_result_t +_ccs_serialize_bin_size_ccs_distribution_space_data( + _ccs_distribution_space_data_t *data, + size_t *cum_size, + _ccs_object_serialize_options_t *opts) +{ + size_t distribution_count; + _ccs_distribution_wrapper_t *dw; + + *cum_size += + _ccs_serialize_bin_size_ccs_object(data->configuration_space); + *cum_size += _ccs_serialize_bin_size_size(data->num_parameters); + + DL_COUNT(data->distribution_list, dw, distribution_count); + *cum_size += _ccs_serialize_bin_size_size(distribution_count); + + dw = NULL; + DL_FOREACH(data->distribution_list, dw) + { + CCS_VALIDATE(dw->distribution->obj.ops->serialize_size( + dw->distribution, CCS_SERIALIZE_FORMAT_BINARY, cum_size, + opts)); + *cum_size += _ccs_serialize_bin_size_size(dw->dimension); + for (size_t i = 0; i < dw->dimension; i++) + *cum_size += _ccs_serialize_bin_size_size( + dw->parameter_indexes[i]); + } + return CCS_RESULT_SUCCESS; +} + +static inline ccs_result_t +_ccs_serialize_bin_ccs_distribution_space_data( + _ccs_distribution_space_data_t *data, + size_t *buffer_size, + char **buffer, + _ccs_object_serialize_options_t *opts) +{ + size_t distribution_count; + _ccs_distribution_wrapper_t *dw; + + CCS_VALIDATE(_ccs_serialize_bin_ccs_object( + data->configuration_space, buffer_size, buffer)); + CCS_VALIDATE(_ccs_serialize_bin_size( + data->num_parameters, buffer_size, buffer)); + + DL_COUNT(data->distribution_list, dw, distribution_count); + CCS_VALIDATE(_ccs_serialize_bin_size( + distribution_count, buffer_size, buffer)); + + dw = NULL; + DL_FOREACH(data->distribution_list, dw) + { + CCS_VALIDATE(dw->distribution->obj.ops->serialize( + dw->distribution, CCS_SERIALIZE_FORMAT_BINARY, + buffer_size, buffer, opts)); + CCS_VALIDATE(_ccs_serialize_bin_size( + dw->dimension, buffer_size, buffer)); + for (size_t i = 0; i < dw->dimension; i++) + CCS_VALIDATE(_ccs_serialize_bin_size( + dw->parameter_indexes[i], buffer_size, buffer)); + } + + return CCS_RESULT_SUCCESS; +} + +static inline ccs_result_t +_ccs_serialize_bin_size_ccs_distribution_space( + ccs_distribution_space_t distribution_space, + size_t *cum_size, + _ccs_object_serialize_options_t *opts) +{ + _ccs_distribution_space_data_t *data = + (_ccs_distribution_space_data_t *)(distribution_space->data); + *cum_size += _ccs_serialize_bin_size_ccs_object_internal( + (_ccs_object_internal_t *)distribution_space); + CCS_VALIDATE(_ccs_serialize_bin_size_ccs_distribution_space_data( + data, cum_size, opts)); + return CCS_RESULT_SUCCESS; +} + +static inline ccs_result_t +_ccs_serialize_bin_ccs_distribution_space( + ccs_distribution_space_t distribution_space, + size_t *buffer_size, + char **buffer, + _ccs_object_serialize_options_t *opts) +{ + _ccs_distribution_space_data_t *data = + (_ccs_distribution_space_data_t *)(distribution_space->data); + CCS_VALIDATE(_ccs_serialize_bin_ccs_object_internal( + (_ccs_object_internal_t *)distribution_space, buffer_size, + buffer)); + CCS_VALIDATE(_ccs_serialize_bin_ccs_distribution_space_data( + data, buffer_size, buffer, opts)); + return CCS_RESULT_SUCCESS; +} + +static ccs_result_t +_ccs_distribution_space_serialize_size( + ccs_object_t object, + ccs_serialize_format_t format, + size_t *cum_size, + _ccs_object_serialize_options_t *opts) +{ + ccs_result_t err = CCS_RESULT_SUCCESS; + CCS_OBJ_RDLOCK(object); + switch (format) { + case CCS_SERIALIZE_FORMAT_BINARY: + CCS_VALIDATE_ERR_GOTO( + err, + _ccs_serialize_bin_size_ccs_distribution_space( + (ccs_distribution_space_t)object, cum_size, + opts), + end); + break; + default: + CCS_RAISE_ERR_GOTO( + err, CCS_RESULT_ERROR_INVALID_VALUE, end, + "Unsupported serialization format: %d", format); + } + CCS_VALIDATE_ERR_GOTO( + err, + _ccs_object_serialize_user_data_size( + object, format, cum_size, opts), + end); +end: + CCS_OBJ_UNLOCK(object); + return err; +} + +static ccs_result_t +_ccs_distribution_space_serialize( + ccs_object_t object, + ccs_serialize_format_t format, + size_t *buffer_size, + char **buffer, + _ccs_object_serialize_options_t *opts) +{ + ccs_result_t err = CCS_RESULT_SUCCESS; + CCS_OBJ_RDLOCK(object); + switch (format) { + case CCS_SERIALIZE_FORMAT_BINARY: + CCS_VALIDATE_ERR_GOTO( + err, + _ccs_serialize_bin_ccs_distribution_space( + (ccs_distribution_space_t)object, buffer_size, + buffer, opts), + end); + break; + default: + CCS_RAISE_ERR_GOTO( + err, CCS_RESULT_ERROR_INVALID_VALUE, end, + "Unsupported serialization format: %d", format); + } + CCS_VALIDATE_ERR_GOTO( + err, + _ccs_object_serialize_user_data( + object, format, buffer_size, buffer, opts), + end); +end: + CCS_OBJ_UNLOCK(object); + return err; +} + +static _ccs_distribution_space_ops_t _distribution_space_ops = { + {&_ccs_distribution_space_del, &_ccs_distribution_space_serialize_size, + &_ccs_distribution_space_serialize}}; + +ccs_result_t +ccs_create_distribution_space( + ccs_configuration_space_t configuration_space, + ccs_distribution_space_t *distribution_space_ret) +{ + CCS_CHECK_OBJ(configuration_space, CCS_OBJECT_TYPE_CONFIGURATION_SPACE); + CCS_CHECK_PTR(distribution_space_ret); + CCS_VALIDATE(ccs_retain_object(configuration_space)); + ccs_result_t err = CCS_RESULT_SUCCESS; + CCS_VALIDATE_ERR_GOTO( + err, + _ccs_create_distribution_space_no_retain( + configuration_space, &_distribution_space_ops, + distribution_space_ret), + err_conf); + return CCS_RESULT_SUCCESS; +err_conf: + ccs_release_object(configuration_space); + return err; +} + +ccs_result_t +ccs_distribution_space_get_configuration_space( + ccs_distribution_space_t distribution_space, + ccs_configuration_space_t *configuration_space_ret) +{ + CCS_CHECK_OBJ(distribution_space, CCS_OBJECT_TYPE_DISTRIBUTION_SPACE); + CCS_CHECK_PTR(configuration_space_ret); + *configuration_space_ret = + distribution_space->data->configuration_space; + return CCS_RESULT_SUCCESS; +} + +ccs_result_t +ccs_distribution_space_set_distribution( + ccs_distribution_space_t distribution_space, + ccs_distribution_t distribution, + size_t *indexes) +{ + CCS_CHECK_OBJ(distribution_space, CCS_OBJECT_TYPE_DISTRIBUTION_SPACE); + CCS_CHECK_OBJ(distribution, CCS_OBJECT_TYPE_DISTRIBUTION); + CCS_CHECK_PTR(indexes); + + _ccs_distribution_wrapper_t *dwrapper; + _ccs_distribution_wrapper_t **p_dwrappers_to_del; + _ccs_distribution_wrapper_t **p_dwrappers_to_add; + _ccs_parameter_wrapper_cs_t *hwrapper; + _ccs_parameter_distribution_t *pdists; + _ccs_parameter_distribution_t *pdist; + ccs_result_t err; + UT_array *parameters; + size_t num_parameters; + size_t dim; + uintptr_t mem; + uintptr_t dmem; + uintptr_t cur_mem; + size_t *parameters_without_distrib; + size_t to_add_count = 0; + size_t to_del_count = 0; + size_t without_distrib_count = 0; + + CCS_VALIDATE(ccs_distribution_get_dimension(distribution, &dim)); + parameters = + distribution_space->data->configuration_space->data->parameters; + pdists = distribution_space->data->parameter_distributions; + num_parameters = distribution_space->data->num_parameters; + + for (size_t i = 0; i < dim; i++) { + CCS_REFUTE( + indexes[i] >= num_parameters, + CCS_RESULT_ERROR_INVALID_VALUE); + // Check duplicate entries + for (size_t j = i + 1; j < dim; j++) + CCS_REFUTE( + indexes[i] == indexes[j], + CCS_RESULT_ERROR_INVALID_VALUE); + } + + mem = (uintptr_t)malloc( + sizeof(void *) * num_parameters * 2 + + sizeof(size_t) * num_parameters); + CCS_REFUTE(!mem, CCS_RESULT_ERROR_OUT_OF_MEMORY); + + CCS_OBJ_WRLOCK(distribution_space); + cur_mem = mem; + p_dwrappers_to_del = (_ccs_distribution_wrapper_t **)cur_mem; + cur_mem += sizeof(_ccs_distribution_wrapper_t *) * num_parameters; + p_dwrappers_to_add = (_ccs_distribution_wrapper_t **)cur_mem; + cur_mem += sizeof(_ccs_distribution_wrapper_t *) * num_parameters; + parameters_without_distrib = (size_t *)cur_mem; + cur_mem += sizeof(size_t) * num_parameters; + + for (size_t i = 0; i < dim; i++) { + int add = 1; + pdist = pdists + indexes[i]; + for (size_t j = 0; j < to_del_count; j++) + if (p_dwrappers_to_del[j] == pdist->distribution) { + add = 0; + break; + } + if (add) + p_dwrappers_to_del[to_del_count++] = + pdist->distribution; + } + for (size_t i = 0; i < to_del_count; i++) { + for (size_t j = 0; j < p_dwrappers_to_del[i]->dimension; j++) { + parameters_without_distrib[without_distrib_count++] = + p_dwrappers_to_del[i]->parameter_indexes[j]; + } + } + + dmem = (uintptr_t)malloc( + sizeof(_ccs_distribution_wrapper_t) + sizeof(size_t) * dim); + CCS_REFUTE_ERR_GOTO(err, !dmem, CCS_RESULT_ERROR_OUT_OF_MEMORY, memory); + + dwrapper = (_ccs_distribution_wrapper_t *)dmem; + dwrapper->distribution = distribution; + dwrapper->dimension = dim; + dwrapper->parameter_indexes = + (size_t *)(dmem + sizeof(_ccs_distribution_wrapper_t)); + for (size_t i = 0; i < dim; i++) { + dwrapper->parameter_indexes[i] = indexes[i]; + size_t indx = 0; + for (size_t j = 0; j < without_distrib_count; j++, indx++) + if (parameters_without_distrib[j] == indexes[i]) + break; + for (size_t j = indx + 1; j < without_distrib_count; j++) + parameters_without_distrib[j - 1] = + parameters_without_distrib[j]; + without_distrib_count--; + } + CCS_VALIDATE_ERR_GOTO(err, ccs_retain_object(distribution), errdmem); + + p_dwrappers_to_add[0] = dwrapper; + to_add_count = 1; + for (size_t i = 0; i < without_distrib_count; i++) { + dmem = (uintptr_t)malloc( + sizeof(_ccs_distribution_wrapper_t) + sizeof(size_t)); + CCS_REFUTE_ERR_GOTO( + err, !dmem, CCS_RESULT_ERROR_OUT_OF_MEMORY, memory); + dwrapper = (_ccs_distribution_wrapper_t *)dmem; + dwrapper->parameter_indexes = + (size_t *)(dmem + sizeof(_ccs_distribution_wrapper_t)); + dwrapper->dimension = 1; + dwrapper->parameter_indexes[0] = parameters_without_distrib[i]; + hwrapper = (_ccs_parameter_wrapper_cs_t *)utarray_eltptr( + parameters, parameters_without_distrib[i]); + + CCS_VALIDATE_ERR_GOTO( + err, + ccs_parameter_get_default_distribution( + hwrapper->parameter, &(dwrapper->distribution)), + dwrappers); + p_dwrappers_to_add[to_add_count++] = dwrapper; + } + + for (size_t i = 0; i < to_del_count; i++) { + DL_DELETE( + distribution_space->data->distribution_list, + p_dwrappers_to_del[i]); + ccs_release_object(p_dwrappers_to_del[i]->distribution); + free(p_dwrappers_to_del[i]); + } + for (size_t i = 0; i < to_add_count; i++) { + DL_APPEND( + distribution_space->data->distribution_list, + p_dwrappers_to_add[i]); + for (size_t j = 0; j < p_dwrappers_to_add[i]->dimension; j++) { + pdist = pdists + + p_dwrappers_to_add[i]->parameter_indexes[j]; + pdist->distribution_index = j; + pdist->distribution = p_dwrappers_to_add[i]; + } + } + + free((void *)mem); + CCS_OBJ_UNLOCK(distribution_space); + return CCS_RESULT_SUCCESS; +dwrappers: + for (size_t i = 0; i < to_add_count; i++) { + ccs_release_object(p_dwrappers_to_add[i]->distribution); + free(p_dwrappers_to_add[i]); + } +errdmem: + if (dmem) + free((void *)dmem); +memory: + free((void *)mem); + CCS_OBJ_UNLOCK(distribution_space); + return err; +} + +extern ccs_result_t +ccs_distribution_space_get_parameter_distribution( + ccs_distribution_space_t distribution_space, + size_t index, + ccs_distribution_t *distribution_ret, + size_t *index_ret) +{ + ccs_result_t err = CCS_RESULT_SUCCESS; + CCS_CHECK_OBJ(distribution_space, CCS_OBJECT_TYPE_DISTRIBUTION_SPACE); + CCS_CHECK_PTR(distribution_ret); + CCS_CHECK_PTR(index_ret); + CCS_REFUTE( + index >= distribution_space->data->num_parameters, + CCS_RESULT_ERROR_OUT_OF_BOUNDS); + + CCS_OBJ_RDLOCK(distribution_space); + _ccs_parameter_distribution_t *pdist = + distribution_space->data->parameter_distributions + index; + *distribution_ret = pdist->distribution->distribution; + *index_ret = pdist->distribution_index; + CCS_OBJ_UNLOCK(distribution_space); + return err; +} diff --git a/src/distribution_space_deserialize.h b/src/distribution_space_deserialize.h new file mode 100644 index 00000000..68c2d04f --- /dev/null +++ b/src/distribution_space_deserialize.h @@ -0,0 +1,173 @@ +#ifndef _DISTRIBUTION_SPACE_DESERIALIZE_H +#define _DISTRIBUTION_SPACE_DESERIALIZE_H +#include "distribution_deserialize.h" + +struct _ccs_distribution_space_data_mock_s { + ccs_configuration_space_t configuration_space; + size_t num_parameters; + size_t num_distributions; + ccs_distribution_t *distributions; + size_t *dimensions; + size_t *distrib_parameter_indices; +}; +typedef struct _ccs_distribution_space_data_mock_s + _ccs_distribution_space_data_mock_t; + +static inline ccs_result_t +_ccs_deserialize_bin_ccs_distribution_space_data( + _ccs_distribution_space_data_mock_t *data, + uint32_t version, + size_t *buffer_size, + const char **buffer, + _ccs_object_deserialize_options_t *opts) +{ + uintptr_t mem; + + CCS_VALIDATE(_ccs_deserialize_bin_ccs_object( + (ccs_object_t *)&data->configuration_space, buffer_size, + buffer)); + + CCS_VALIDATE(_ccs_deserialize_bin_size( + &data->num_parameters, buffer_size, buffer)); + + CCS_VALIDATE(_ccs_deserialize_bin_size( + &data->num_distributions, buffer_size, buffer)); + + if (!(data->num_distributions)) + return CCS_RESULT_SUCCESS; + mem = (uintptr_t)calloc( + data->num_distributions * + (sizeof(ccs_distribution_t) + sizeof(size_t)) + + data->num_parameters * sizeof(size_t), + 1); + CCS_REFUTE(!mem, CCS_RESULT_ERROR_OUT_OF_MEMORY); + + data->distributions = (ccs_distribution_t *)mem; + mem += data->num_distributions * sizeof(ccs_distribution_t); + data->dimensions = (size_t *)mem; + mem += data->num_distributions * sizeof(size_t); + data->distrib_parameter_indices = (size_t *)mem; + mem += data->num_parameters * sizeof(size_t); + + size_t *indices; + indices = data->distrib_parameter_indices; + for (size_t i = 0; i < data->num_distributions; i++) { + CCS_VALIDATE(_ccs_distribution_deserialize( + data->distributions + i, CCS_SERIALIZE_FORMAT_BINARY, + version, buffer_size, buffer, opts)); + CCS_VALIDATE(_ccs_deserialize_bin_size( + data->dimensions + i, buffer_size, buffer)); + for (size_t j = 0; j < data->dimensions[i]; j++) { + CCS_VALIDATE(_ccs_deserialize_bin_size( + indices, buffer_size, buffer)); + indices++; + } + } + + return CCS_RESULT_SUCCESS; +} + +static inline ccs_result_t +_ccs_deserialize_bin_distribution_space( + ccs_distribution_space_t *distribution_space_ret, + uint32_t version, + size_t *buffer_size, + const char **buffer, + _ccs_object_deserialize_options_t *opts) +{ + CCS_CHECK_OBJ(opts->handle_map, CCS_OBJECT_TYPE_MAP); + _ccs_object_deserialize_options_t new_opts = *opts; + new_opts.map_values = CCS_FALSE; + new_opts.handle_map = NULL; + _ccs_object_internal_t obj; + ccs_datum_t d; + ccs_configuration_space_t cs; + ccs_object_t handle; + ccs_distribution_space_t distrib_space; + ccs_result_t res = CCS_RESULT_SUCCESS; + CCS_VALIDATE(_ccs_deserialize_bin_ccs_object_internal( + &obj, buffer_size, buffer, &handle)); + CCS_REFUTE( + obj.type != CCS_OBJECT_TYPE_DISTRIBUTION_SPACE, + CCS_RESULT_ERROR_INVALID_TYPE); + + _ccs_distribution_space_data_mock_t data = {NULL, 0, 0, + NULL, NULL, NULL}; + CCS_VALIDATE_ERR_GOTO( + res, + _ccs_deserialize_bin_ccs_distribution_space_data( + &data, version, buffer_size, buffer, &new_opts), + end); + + CCS_VALIDATE_ERR_GOTO( + res, + ccs_map_get( + opts->handle_map, ccs_object(data.configuration_space), + &d), + end); + CCS_REFUTE_ERR_GOTO( + res, d.type != CCS_DATA_TYPE_OBJECT, + CCS_RESULT_ERROR_INVALID_HANDLE, end); + cs = (ccs_configuration_space_t)(d.value.o); + + CCS_VALIDATE_ERR_GOTO( + res, ccs_create_distribution_space(cs, &distrib_space), end); + size_t *indices; + indices = data.distrib_parameter_indices; + for (size_t i = 0; i < data.num_distributions; i++) { + CCS_VALIDATE_ERR_GOTO( + res, + ccs_distribution_space_set_distribution( + distrib_space, data.distributions[i], indices), + err_distribution_space); + indices += data.dimensions[i]; + } + if (opts->map_values) + CCS_VALIDATE_ERR_GOTO( + res, + _ccs_object_handle_check_add( + opts->handle_map, handle, + (ccs_object_t)distrib_space), + err_distribution_space); + *distribution_space_ret = distrib_space; + goto end; + +err_distribution_space: + ccs_release_object(distrib_space); +end: + if (data.distributions) + for (size_t i = 0; i < data.num_distributions; i++) + if (data.distributions[i]) + ccs_release_object(data.distributions[i]); + if (data.distributions) + free(data.distributions); + return res; +} + +static ccs_result_t +_ccs_distribution_space_deserialize( + ccs_distribution_space_t *distribution_space_ret, + ccs_serialize_format_t format, + uint32_t version, + size_t *buffer_size, + const char **buffer, + _ccs_object_deserialize_options_t *opts) +{ + switch (format) { + case CCS_SERIALIZE_FORMAT_BINARY: + CCS_VALIDATE(_ccs_deserialize_bin_distribution_space( + distribution_space_ret, version, buffer_size, buffer, + opts)); + break; + default: + CCS_RAISE( + CCS_RESULT_ERROR_INVALID_VALUE, + "Unsupported serialization format: %d", format); + } + CCS_VALIDATE(_ccs_object_deserialize_user_data( + (ccs_object_t)*distribution_space_ret, format, version, + buffer_size, buffer, opts)); + return CCS_RESULT_SUCCESS; +} + +#endif //_DISTRIBUTION_SPACE_DESERIALIZE_H diff --git a/src/distribution_space_internal.h b/src/distribution_space_internal.h new file mode 100644 index 00000000..9a7a9915 --- /dev/null +++ b/src/distribution_space_internal.h @@ -0,0 +1,149 @@ +#ifndef _DISTRIBUTION_SPACE_INTERNAL_H +#define _DISTRIBUTION_SPACE_INTERNAL_H +#include "configuration_space_internal.h" +#include "utlist.h" + +struct _ccs_distribution_wrapper_s { + ccs_distribution_t distribution; + size_t dimension; + size_t *parameter_indexes; + _ccs_distribution_wrapper_t *prev; + _ccs_distribution_wrapper_t *next; +}; +typedef struct _ccs_distribution_wrapper_s _ccs_distribution_wrapper_t; + +struct _ccs_parameter_distribution_s { + size_t distribution_index; + _ccs_distribution_wrapper_t *distribution; +}; +typedef struct _ccs_parameter_distribution_s _ccs_parameter_distribution_t; + +struct _ccs_distribution_space_ops_s { + _ccs_object_ops_t obj_ops; +}; +typedef struct _ccs_distribution_space_ops_s _ccs_distribution_space_ops_t; + +struct _ccs_distribution_space_data_s; +typedef struct _ccs_distribution_space_data_s _ccs_distribution_space_data_t; + +struct _ccs_distribution_space_s { + _ccs_object_internal_t obj; + _ccs_distribution_space_data_t *data; +}; + +struct _ccs_distribution_space_data_s { + ccs_configuration_space_t configuration_space; + size_t num_parameters; + _ccs_parameter_distribution_t *parameter_distributions; + _ccs_distribution_wrapper_t *distribution_list; +}; + +static inline void +_ccs_distribution_space_del_no_release( + ccs_distribution_space_t distribution_space) +{ + _ccs_distribution_wrapper_t *dw, *tmp; + DL_FOREACH_SAFE(distribution_space->data->distribution_list, dw, tmp) + { + DL_DELETE(distribution_space->data->distribution_list, dw); + ccs_release_object(dw->distribution); + free(dw); + } +} + +static inline ccs_result_t +_ccs_get_distribution_wrapper( + ccs_configuration_space_t configuration_space, + size_t index, + _ccs_distribution_wrapper_t **distrib_wrapper_ret) +{ + ccs_parameter_t parameter; + ccs_distribution_t distribution; + ccs_result_t err = CCS_RESULT_SUCCESS; + _ccs_distribution_wrapper_t *distrib_wrapper; + CCS_VALIDATE(_ccs_context_get_parameter( + (ccs_context_t)configuration_space, index, ¶meter)); + CCS_VALIDATE(ccs_parameter_get_default_distribution( + parameter, &distribution)); + + uintptr_t dmem = (uintptr_t)malloc( + sizeof(_ccs_distribution_wrapper_t) + sizeof(size_t)); + + CCS_REFUTE_ERR_GOTO( + err, !dmem, CCS_RESULT_ERROR_OUT_OF_MEMORY, err_distrib); + distrib_wrapper = (_ccs_distribution_wrapper_t *)dmem; + distrib_wrapper->distribution = distribution; + distrib_wrapper->dimension = 1; + distrib_wrapper->parameter_indexes = + (size_t *)(dmem + sizeof(_ccs_distribution_wrapper_t)); + distrib_wrapper->parameter_indexes[0] = index; + *distrib_wrapper_ret = distrib_wrapper; + return CCS_RESULT_SUCCESS; +err_distrib: + ccs_release_object(distribution); + return err; +} + +static inline ccs_result_t +_ccs_create_distribution_space_no_retain( + ccs_configuration_space_t configuration_space, + _ccs_distribution_space_ops_t *ops, + ccs_distribution_space_t *distribution_space_ret) +{ + size_t num_parameters; + _ccs_distribution_wrapper_t *dw, *tmp; + ccs_result_t err = CCS_RESULT_SUCCESS; + CCS_VALIDATE(_ccs_context_get_num_parameters( + (ccs_context_t)configuration_space, &num_parameters)); + uintptr_t mem = (uintptr_t)calloc( + 1, sizeof(struct _ccs_distribution_space_s) + + sizeof(struct _ccs_distribution_space_data_s) + + sizeof(struct _ccs_parameter_distribution_s) * + num_parameters); + CCS_REFUTE(!mem, CCS_RESULT_ERROR_OUT_OF_MEMORY); + + ccs_distribution_space_t distrib_space; + distrib_space = (ccs_distribution_space_t)mem; + if (ops) { + _ccs_object_init( + &(distrib_space->obj), + CCS_OBJECT_TYPE_DISTRIBUTION_SPACE, + (_ccs_object_ops_t *)ops); + } + distrib_space->data = + (struct _ccs_distribution_space_data_s + *)(mem + sizeof(struct _ccs_distribution_space_s)); + distrib_space->data->num_parameters = num_parameters; + distrib_space->data->parameter_distributions = + (struct _ccs_parameter_distribution_s + *)(mem + sizeof(struct _ccs_distribution_space_s) + sizeof(struct _ccs_distribution_space_data_s)); + distrib_space->data->configuration_space = configuration_space; + for (size_t i = 0; i < num_parameters; i++) { + _ccs_distribution_wrapper_t *distrib_wrapper; + _ccs_parameter_distribution_t *pdist; + CCS_VALIDATE_ERR_GOTO( + err, + _ccs_get_distribution_wrapper( + configuration_space, i, &distrib_wrapper), + err_dis); + DL_APPEND( + distrib_space->data->distribution_list, + distrib_wrapper); + pdist = distrib_space->data->parameter_distributions + i; + pdist->distribution_index = 0; + pdist->distribution = distrib_wrapper; + } + *distribution_space_ret = distrib_space; + return CCS_RESULT_SUCCESS; +err_dis: + DL_FOREACH_SAFE(distrib_space->data->distribution_list, dw, tmp) + { + DL_DELETE(distrib_space->data->distribution_list, dw); + ccs_release_object(dw->distribution); + free(dw); + } + free((void *)mem); + return err; +} + +#endif //_DISTRIBUTION_SPACE_INTERNAL_H diff --git a/src/expression_deserialize.h b/src/expression_deserialize.h index 15ec6626..e423e4eb 100644 --- a/src/expression_deserialize.h +++ b/src/expression_deserialize.h @@ -218,6 +218,7 @@ _ccs_deserialize_bin_expression( return CCS_RESULT_SUCCESS; err_exp: ccs_release_object(*expression_ret); + *expression_ret = NULL; return res; } diff --git a/src/features_tuner_deserialize.h b/src/features_tuner_deserialize.h index 73a35e78..b98a86ae 100644 --- a/src/features_tuner_deserialize.h +++ b/src/features_tuner_deserialize.h @@ -315,6 +315,7 @@ _ccs_deserialize_bin_features_tuner( goto end; err_features_tuner: ccs_release_object(*features_tuner_ret); + *features_tuner_ret = NULL; end: ccs_release_object(new_opts.handle_map); return res; diff --git a/src/features_tuner_random.c b/src/features_tuner_random.c index 18598d80..dc5eeed0 100644 --- a/src/features_tuner_random.c +++ b/src/features_tuner_random.c @@ -170,7 +170,7 @@ _ccs_features_tuner_random_ask( return CCS_RESULT_SUCCESS; } CCS_VALIDATE(ccs_configuration_space_samples( - d->common_data.configuration_space, num_configurations, + d->common_data.configuration_space, NULL, num_configurations, configurations)); if (num_configurations_ret) *num_configurations_ret = num_configurations; diff --git a/src/parameter_deserialize.h b/src/parameter_deserialize.h index c7020215..4d228eeb 100644 --- a/src/parameter_deserialize.h +++ b/src/parameter_deserialize.h @@ -204,6 +204,7 @@ _ccs_deserialize_bin_parameter( return CCS_RESULT_SUCCESS; err_parameter: ccs_release_object(*parameter_ret); + *parameter_ret = NULL; return res; } diff --git a/src/tree_space_deserialize.h b/src/tree_space_deserialize.h index 69e02d39..b87ecdb1 100644 --- a/src/tree_space_deserialize.h +++ b/src/tree_space_deserialize.h @@ -154,6 +154,7 @@ _ccs_deserialize_bin_tree_space( return CCS_RESULT_SUCCESS; err_tree_space: ccs_release_object(*tree_space_ret); + *tree_space_ret = NULL; return res; } diff --git a/src/tree_tuner_deserialize.h b/src/tree_tuner_deserialize.h index 5126d68c..389900ef 100644 --- a/src/tree_tuner_deserialize.h +++ b/src/tree_tuner_deserialize.h @@ -295,6 +295,7 @@ _ccs_deserialize_bin_tree_tuner( goto end; err_tuner: ccs_release_object(*tuner_ret); + *tuner_ret = NULL; end: ccs_release_object(new_opts.handle_map); return res; diff --git a/src/tuner_deserialize.h b/src/tuner_deserialize.h index 468a24bf..9f9f99b7 100644 --- a/src/tuner_deserialize.h +++ b/src/tuner_deserialize.h @@ -294,6 +294,7 @@ _ccs_deserialize_bin_tuner( goto end; err_tuner: ccs_release_object(*tuner_ret); + *tuner_ret = NULL; end: ccs_release_object(new_opts.handle_map); return res; diff --git a/src/tuner_random.c b/src/tuner_random.c index a9e09f23..b7d75017 100644 --- a/src/tuner_random.c +++ b/src/tuner_random.c @@ -162,7 +162,7 @@ _ccs_tuner_random_ask( return CCS_RESULT_SUCCESS; } CCS_VALIDATE(ccs_configuration_space_samples( - d->common_data.configuration_space, num_configurations, + d->common_data.configuration_space, NULL, num_configurations, configurations)); if (num_configurations_ret) *num_configurations_ret = num_configurations; diff --git a/tests/Makefile.am b/tests/Makefile.am index 23ff7a8a..63735b9d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -22,6 +22,7 @@ CCONFIGSPACE_TESTS = \ test_discrete_parameter \ test_string_parameter \ test_configuration_space \ + test_distribution_space \ test_expression \ test_condition \ test_forbidden \ diff --git a/tests/test_condition.c b/tests/test_condition.c index 1882b4e8..ed27b198 100644 --- a/tests/test_condition.c +++ b/tests/test_condition.c @@ -44,7 +44,8 @@ test_simple(void) for (int i = 0; i < 100; i++) { ccs_float_t f; ccs_bool_t check; - err = ccs_configuration_space_sample(space, &configuration); + err = ccs_configuration_space_sample( + space, NULL, &configuration); assert(err == CCS_RESULT_SUCCESS); err = ccs_configuration_get_values( configuration, 2, values, NULL); @@ -64,7 +65,7 @@ test_simple(void) assert(err == CCS_RESULT_SUCCESS); } - err = ccs_configuration_space_samples(space, 100, configurations); + err = ccs_configuration_space_samples(space, NULL, 100, configurations); assert(err == CCS_RESULT_SUCCESS); for (int i = 0; i < 100; i++) { @@ -137,7 +138,8 @@ test_transitive(void) for (int i = 0; i < 100; i++) { ccs_float_t f; ccs_bool_t check; - err = ccs_configuration_space_sample(space, &configuration); + err = ccs_configuration_space_sample( + space, NULL, &configuration); assert(err == CCS_RESULT_SUCCESS); err = ccs_configuration_get_values( configuration, 3, values, NULL); @@ -168,7 +170,7 @@ test_transitive(void) assert(err == CCS_RESULT_SUCCESS); } - err = ccs_configuration_space_samples(space, 100, configurations); + err = ccs_configuration_space_samples(space, NULL, 100, configurations); assert(err == CCS_RESULT_SUCCESS); for (int i = 0; i < 100; i++) { diff --git a/tests/test_configuration_space.c b/tests/test_configuration_space.c index 4a677994..89ae1ccc 100644 --- a/tests/test_configuration_space.c +++ b/tests/test_configuration_space.c @@ -102,7 +102,7 @@ test_empty(void) assert(err == CCS_RESULT_SUCCESS); err = ccs_configuration_space_sample( - configuration_space, &configuration); + configuration_space, NULL, &configuration); assert(err == CCS_RESULT_SUCCESS); err = ccs_release_object(configuration); @@ -188,7 +188,7 @@ test_sample(void) assert(err == CCS_RESULT_SUCCESS); err = ccs_configuration_space_sample( - configuration_space, &configuration); + configuration_space, NULL, &configuration); assert(err == CCS_RESULT_SUCCESS); err = ccs_configuration_check(configuration, &check); @@ -196,7 +196,7 @@ test_sample(void) assert(check); err = ccs_configuration_space_samples( - configuration_space, 100, configurations); + configuration_space, NULL, 100, configurations); assert(err == CCS_RESULT_SUCCESS); for (size_t i = 0; i < 100; i++) { @@ -217,133 +217,6 @@ test_sample(void) assert(err == CCS_RESULT_SUCCESS); } -void -test_set_distribution(void) -{ - ccs_parameter_t parameters[3]; - ccs_distribution_t distribs[2]; - ccs_distribution_t distrib; - ccs_distribution_t distrib_ret; - size_t hindexes[2]; - size_t dindex_ret; - ccs_configuration_t configurations[100]; - ccs_configuration_space_t configuration_space; - ccs_result_t err; - ccs_bool_t check; - - parameters[0] = create_dummy_parameter("param1"); - parameters[1] = create_dummy_parameter("param2"); - parameters[2] = create_dummy_parameter("param3"); - - err = ccs_create_configuration_space( - "my_config_space", 3, parameters, &configuration_space); - assert(err == CCS_RESULT_SUCCESS); - - check_configuration(configuration_space, 3, parameters); - - err = ccs_create_uniform_distribution( - CCS_NUMERIC_TYPE_FLOAT, CCSF(-4.0), CCSF(4.0), - CCS_SCALE_TYPE_LINEAR, CCSF(0.0), distribs); - assert(err == CCS_RESULT_SUCCESS); - - err = ccs_create_uniform_distribution( - CCS_NUMERIC_TYPE_FLOAT, CCSF(-3.0), CCSF(3.0), - CCS_SCALE_TYPE_LINEAR, CCSF(0.0), distribs + 1); - assert(err == CCS_RESULT_SUCCESS); - - err = ccs_create_multivariate_distribution(2, distribs, &distrib); - assert(err == CCS_RESULT_SUCCESS); - - hindexes[0] = 0; - hindexes[1] = 1; - err = ccs_configuration_space_set_distribution( - configuration_space, distrib, hindexes); - assert(err == CCS_RESULT_SUCCESS); - - err = ccs_configuration_space_get_parameter_distribution( - configuration_space, 0, &distrib_ret, &dindex_ret); - assert(err == CCS_RESULT_SUCCESS); - assert(distrib_ret == distrib); - assert(dindex_ret == 0); - - err = ccs_configuration_space_get_parameter_distribution( - configuration_space, 1, &distrib_ret, &dindex_ret); - assert(err == CCS_RESULT_SUCCESS); - assert(distrib_ret == distrib); - assert(dindex_ret == 1); - - err = ccs_configuration_space_samples( - configuration_space, 100, configurations); - assert(err == CCS_RESULT_SUCCESS); - - for (size_t i = 0; i < 100; i++) { - ccs_datum_t values[3]; - err = ccs_configuration_check(configurations[i], &check); - assert(err == CCS_RESULT_SUCCESS); - assert(check); - err = ccs_configuration_get_values( - configurations[i], 3, values, NULL); - assert(err == CCS_RESULT_SUCCESS); - assert(values[0].value.f >= -4.0); - assert(values[0].value.f < 4.0); - assert(values[1].value.f >= -3.0); - assert(values[1].value.f < 3.0); - err = ccs_release_object(configurations[i]); - assert(err == CCS_RESULT_SUCCESS); - } - - hindexes[0] = 2; - hindexes[1] = 0; - err = ccs_configuration_space_set_distribution( - configuration_space, distrib, hindexes); - assert(err == CCS_RESULT_SUCCESS); - - err = ccs_configuration_space_get_parameter_distribution( - configuration_space, 0, &distrib_ret, &dindex_ret); - assert(err == CCS_RESULT_SUCCESS); - assert(distrib_ret == distrib); - assert(dindex_ret == 1); - - err = ccs_configuration_space_get_parameter_distribution( - configuration_space, 2, &distrib_ret, &dindex_ret); - assert(err == CCS_RESULT_SUCCESS); - assert(distrib_ret == distrib); - assert(dindex_ret == 0); - - err = ccs_configuration_space_samples( - configuration_space, 100, configurations); - assert(err == CCS_RESULT_SUCCESS); - - for (size_t i = 0; i < 100; i++) { - ccs_datum_t values[3]; - err = ccs_configuration_check(configurations[i], &check); - assert(err == CCS_RESULT_SUCCESS); - assert(check); - err = ccs_configuration_get_values( - configurations[i], 3, values, NULL); - assert(err == CCS_RESULT_SUCCESS); - assert(values[2].value.f >= -4.0); - assert(values[2].value.f < 4.0); - assert(values[0].value.f >= -3.0); - assert(values[0].value.f < 3.0); - err = ccs_release_object(configurations[i]); - assert(err == CCS_RESULT_SUCCESS); - } - - for (size_t i = 0; i < 2; i++) { - err = ccs_release_object(distribs[i]); - assert(err == CCS_RESULT_SUCCESS); - } - for (size_t i = 0; i < 3; i++) { - err = ccs_release_object(parameters[i]); - assert(err == CCS_RESULT_SUCCESS); - } - err = ccs_release_object(distrib); - assert(err == CCS_RESULT_SUCCESS); - err = ccs_release_object(configuration_space); - assert(err == CCS_RESULT_SUCCESS); -} - ccs_parameter_t create_numerical(const char *name) { @@ -378,7 +251,7 @@ test_configuration_deserialize(void) assert(err == CCS_RESULT_SUCCESS); err = ccs_configuration_space_sample( - configuration_space, &configuration_ref); + configuration_space, NULL, &configuration_ref); assert(err == CCS_RESULT_SUCCESS); err = ccs_create_map(&map); @@ -441,11 +314,6 @@ test_deserialize(void) ccs_parameter_t parameters[3]; ccs_configuration_space_t space, space_ref; ccs_expression_t expression, expressions[3]; - ccs_distribution_t distribs[2]; - ccs_distribution_t distrib; - size_t hindexes[2]; - ccs_distribution_t distrib_ret, distrib_ref; - size_t dindex_ret; char *buff; size_t buff_size; size_t count; @@ -461,25 +329,6 @@ test_deserialize(void) "my_config_space", 3, parameters, &space); assert(err == CCS_RESULT_SUCCESS); - err = ccs_create_uniform_distribution( - CCS_NUMERIC_TYPE_FLOAT, CCSF(-4.0), CCSF(4.0), - CCS_SCALE_TYPE_LINEAR, CCSF(0.0), distribs); - assert(err == CCS_RESULT_SUCCESS); - - err = ccs_create_uniform_distribution( - CCS_NUMERIC_TYPE_FLOAT, CCSF(-3.0), CCSF(3.0), - CCS_SCALE_TYPE_LINEAR, CCSF(0.0), distribs + 1); - assert(err == CCS_RESULT_SUCCESS); - - err = ccs_create_multivariate_distribution(2, distribs, &distrib); - assert(err == CCS_RESULT_SUCCESS); - - hindexes[0] = 2; - hindexes[1] = 0; - err = ccs_configuration_space_set_distribution( - space, distrib, hindexes); - assert(err == CCS_RESULT_SUCCESS); - err = ccs_create_binary_expression( CCS_EXPRESSION_TYPE_LESS, ccs_object(parameters[1]), ccs_float(0.0), &expression); @@ -507,12 +356,6 @@ test_deserialize(void) err = ccs_release_object(expression); assert(err == CCS_RESULT_SUCCESS); - for (size_t i = 0; i < 2; i++) { - err = ccs_release_object(distribs[i]); - assert(err == CCS_RESULT_SUCCESS); - } - err = ccs_release_object(distrib); - assert(err == CCS_RESULT_SUCCESS); for (size_t i = 0; i < 3; i++) { err = ccs_release_object(parameters[i]); assert(err == CCS_RESULT_SUCCESS); @@ -564,19 +407,6 @@ test_deserialize(void) assert(err == CCS_RESULT_SUCCESS); assert(count == 3); - err = ccs_configuration_space_get_parameter_distribution( - space, 0, &distrib_ret, &dindex_ret); - assert(err == CCS_RESULT_SUCCESS); - assert(distrib_ret); - assert(dindex_ret == 1); - distrib_ref = distrib_ret; - - err = ccs_configuration_space_get_parameter_distribution( - space, 2, &distrib_ret, &dindex_ret); - assert(err == CCS_RESULT_SUCCESS); - assert(distrib_ret == distrib_ref); - assert(dindex_ret == 0); - err = ccs_configuration_space_get_conditions( space, 3, expressions, NULL); assert(err == CCS_RESULT_SUCCESS); @@ -607,7 +437,6 @@ main(void) test_create(); test_empty(); test_sample(); - test_set_distribution(); test_deserialize(); test_configuration_deserialize(); ccs_clear_thread_error(); diff --git a/tests/test_distribution_space.c b/tests/test_distribution_space.c new file mode 100644 index 00000000..5dd91239 --- /dev/null +++ b/tests/test_distribution_space.c @@ -0,0 +1,432 @@ +#include +#include +#include +#include + +void +print_ccs_error_stack(void) +{ + ccs_error_stack_t err; + ccs_result_t code; + const char *msg; + size_t stack_depth; + ccs_error_stack_elem_t *stack_elems; + + err = ccs_get_thread_error(); + if (!err) + return; + ccs_error_stack_get_code(err, &code); + ccs_get_result_name(code, &msg); + fprintf(stderr, "CCS Error: %s (%d): ", msg, code); + ccs_error_stack_get_message(err, &msg); + fprintf(stderr, "%s\n", msg); + ccs_error_stack_get_elems(err, &stack_depth, &stack_elems); + for (size_t i = 0; i < stack_depth; i++) { + fprintf(stderr, "\t%s:%d:%s\n", stack_elems[i].file, + stack_elems[i].line, stack_elems[i].func); + } + ccs_release_object(err); +} + +double d = -2.0; + +ccs_parameter_t +create_dummy_parameter(const char *name) +{ + ccs_parameter_t parameter; + ccs_result_t err; + err = ccs_create_numerical_parameter( + name, CCS_NUMERIC_TYPE_FLOAT, CCSF(-5.0), CCSF(5.0), CCSF(0.0), + CCSF(d), ¶meter); + d += 1.0; + if (d >= 5.0) + d = -5.0; + assert(err == CCS_RESULT_SUCCESS); + return parameter; +} + +void +check_configuration( + ccs_configuration_space_t configuration_space, + size_t sz, + ccs_parameter_t *parameters) +{ + ccs_parameter_t parameter; + ccs_configuration_t configuration; + ccs_result_t err; + size_t sz_ret; + size_t index; + ccs_parameter_t *parameters_ret = + (ccs_parameter_t *)malloc(sizeof(ccs_parameter_t) * (sz + 1)); + const char *name; + ccs_bool_t check; + + err = ccs_configuration_space_get_num_parameters( + configuration_space, &sz_ret); + assert(err == CCS_RESULT_SUCCESS); + assert(sz_ret == sz); + + for (size_t i = 0; i < sz; i++) { + err = ccs_configuration_space_get_parameter( + configuration_space, i, ¶meter); + assert(err == CCS_RESULT_SUCCESS); + assert(parameter == parameters[i]); + err = ccs_configuration_space_get_parameter_index( + configuration_space, parameter, &index); + assert(err == CCS_RESULT_SUCCESS); + assert(index == i); + } + err = ccs_configuration_space_get_parameters( + configuration_space, sz + 1, parameters_ret, &sz_ret); + assert(err == CCS_RESULT_SUCCESS); + assert(sz_ret == sz); + for (size_t i = 0; i < sz; i++) + assert(parameters_ret[i] == parameters[i]); + assert(parameters_ret[sz] == NULL); + + for (size_t i = 0; i < sz; i++) { + err = ccs_parameter_get_name(parameters[i], &name); + assert(err == CCS_RESULT_SUCCESS); + err = ccs_configuration_space_get_parameter_by_name( + configuration_space, name, ¶meter); + assert(err == CCS_RESULT_SUCCESS); + assert(parameter == parameters[i]); + } + + err = ccs_configuration_space_get_default_configuration( + configuration_space, &configuration); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_configuration_check(configuration, &check); + assert(err == CCS_RESULT_SUCCESS); + assert(check); + for (size_t i = 0; i < sz; i++) { + ccs_datum_t datum; + ccs_datum_t hdatum; + err = ccs_configuration_get_value(configuration, i, &datum); + assert(err == CCS_RESULT_SUCCESS); + err = ccs_parameter_get_default_value(parameters[i], &hdatum); + assert(err == CCS_RESULT_SUCCESS); + assert(datum.type == hdatum.type); + assert(datum.value.f == hdatum.value.f); + } + err = ccs_release_object(configuration); + assert(err == CCS_RESULT_SUCCESS); + free(parameters_ret); +} + +void +test_create(void) +{ + ccs_parameter_t parameters[3]; + ccs_configuration_space_t configuration_space, cs_ret; + ccs_distribution_space_t distribution_space; + ccs_result_t err; + ccs_object_type_t type; + + parameters[0] = create_dummy_parameter("param1"); + parameters[1] = create_dummy_parameter("param2"); + parameters[2] = create_dummy_parameter("param3"); + + err = ccs_create_configuration_space( + "my_config_space", 3, parameters, &configuration_space); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_create_distribution_space( + configuration_space, &distribution_space); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_object_get_type(distribution_space, &type); + assert(err == CCS_RESULT_SUCCESS); + assert(type == CCS_OBJECT_TYPE_DISTRIBUTION_SPACE); + + err = ccs_distribution_space_get_configuration_space( + distribution_space, &cs_ret); + assert(err == CCS_RESULT_SUCCESS); + assert(configuration_space == cs_ret); + + err = ccs_release_object(configuration_space); + assert(err == CCS_RESULT_SUCCESS); + err = ccs_release_object(distribution_space); + assert(err == CCS_RESULT_SUCCESS); + for (size_t i = 0; i < 3; i++) { + err = ccs_release_object(parameters[i]); + assert(err == CCS_RESULT_SUCCESS); + } +} + +void +test_set_distribution(void) +{ + ccs_parameter_t parameters[3]; + ccs_distribution_space_t distribution_space; + ccs_distribution_t distribs[2]; + ccs_distribution_t distrib; + ccs_distribution_t distrib_ret; + size_t hindexes[2]; + size_t dindex_ret; + ccs_configuration_t configurations[100]; + ccs_configuration_space_t configuration_space; + ccs_result_t err; + ccs_bool_t check; + + parameters[0] = create_dummy_parameter("param1"); + parameters[1] = create_dummy_parameter("param2"); + parameters[2] = create_dummy_parameter("param3"); + + err = ccs_create_configuration_space( + "my_config_space", 3, parameters, &configuration_space); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_create_distribution_space( + configuration_space, &distribution_space); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_create_uniform_distribution( + CCS_NUMERIC_TYPE_FLOAT, CCSF(-4.0), CCSF(4.0), + CCS_SCALE_TYPE_LINEAR, CCSF(0.0), distribs); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_create_uniform_distribution( + CCS_NUMERIC_TYPE_FLOAT, CCSF(-3.0), CCSF(3.0), + CCS_SCALE_TYPE_LINEAR, CCSF(0.0), distribs + 1); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_create_multivariate_distribution(2, distribs, &distrib); + assert(err == CCS_RESULT_SUCCESS); + + hindexes[0] = 0; + hindexes[1] = 1; + err = ccs_distribution_space_set_distribution( + distribution_space, distrib, hindexes); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_distribution_space_get_parameter_distribution( + distribution_space, 0, &distrib_ret, &dindex_ret); + assert(err == CCS_RESULT_SUCCESS); + assert(distrib_ret == distrib); + assert(dindex_ret == 0); + + err = ccs_distribution_space_get_parameter_distribution( + distribution_space, 1, &distrib_ret, &dindex_ret); + assert(err == CCS_RESULT_SUCCESS); + assert(distrib_ret == distrib); + assert(dindex_ret == 1); + + err = ccs_configuration_space_samples( + configuration_space, distribution_space, 100, configurations); + assert(err == CCS_RESULT_SUCCESS); + + for (size_t i = 0; i < 100; i++) { + ccs_datum_t values[3]; + err = ccs_configuration_check(configurations[i], &check); + assert(err == CCS_RESULT_SUCCESS); + assert(check); + err = ccs_configuration_get_values( + configurations[i], 3, values, NULL); + assert(err == CCS_RESULT_SUCCESS); + assert(values[0].value.f >= -4.0); + assert(values[0].value.f < 4.0); + assert(values[1].value.f >= -3.0); + assert(values[1].value.f < 3.0); + err = ccs_release_object(configurations[i]); + assert(err == CCS_RESULT_SUCCESS); + } + + hindexes[0] = 2; + hindexes[1] = 0; + err = ccs_distribution_space_set_distribution( + distribution_space, distrib, hindexes); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_distribution_space_get_parameter_distribution( + distribution_space, 0, &distrib_ret, &dindex_ret); + assert(err == CCS_RESULT_SUCCESS); + assert(distrib_ret == distrib); + assert(dindex_ret == 1); + + err = ccs_distribution_space_get_parameter_distribution( + distribution_space, 2, &distrib_ret, &dindex_ret); + assert(err == CCS_RESULT_SUCCESS); + assert(distrib_ret == distrib); + assert(dindex_ret == 0); + + err = ccs_configuration_space_samples( + configuration_space, distribution_space, 100, configurations); + assert(err == CCS_RESULT_SUCCESS); + + for (size_t i = 0; i < 100; i++) { + ccs_datum_t values[3]; + err = ccs_configuration_check(configurations[i], &check); + assert(err == CCS_RESULT_SUCCESS); + assert(check); + err = ccs_configuration_get_values( + configurations[i], 3, values, NULL); + assert(err == CCS_RESULT_SUCCESS); + assert(values[2].value.f >= -4.0); + assert(values[2].value.f < 4.0); + assert(values[0].value.f >= -3.0); + assert(values[0].value.f < 3.0); + err = ccs_release_object(configurations[i]); + assert(err == CCS_RESULT_SUCCESS); + } + + for (size_t i = 0; i < 2; i++) { + err = ccs_release_object(distribs[i]); + assert(err == CCS_RESULT_SUCCESS); + } + for (size_t i = 0; i < 3; i++) { + err = ccs_release_object(parameters[i]); + assert(err == CCS_RESULT_SUCCESS); + } + err = ccs_release_object(distrib); + assert(err == CCS_RESULT_SUCCESS); + err = ccs_release_object(configuration_space); + assert(err == CCS_RESULT_SUCCESS); + err = ccs_release_object(distribution_space); + assert(err == CCS_RESULT_SUCCESS); +} + +ccs_parameter_t +create_numerical(const char *name) +{ + ccs_parameter_t parameter; + ccs_result_t err; + err = ccs_create_numerical_parameter( + name, CCS_NUMERIC_TYPE_FLOAT, CCSF(-5.0), CCSF(5.0), CCSF(0.0), + CCSF(0.0), ¶meter); + assert(err == CCS_RESULT_SUCCESS); + return parameter; +} + +void +test_deserialize(void) +{ + ccs_parameter_t parameters[3]; + ccs_configuration_space_t space; + ccs_distribution_space_t distrib_space; + ccs_distribution_t distribs[2]; + ccs_distribution_t distrib; + size_t hindexes[2]; + ccs_distribution_t distrib_ret, distrib_ref; + size_t dindex_ret; + char *buff; + size_t buff_size; + ccs_map_t map; + ccs_datum_t d; + ccs_result_t err; + + parameters[0] = create_numerical("param1"); + parameters[1] = create_numerical("param2"); + parameters[2] = create_numerical("param3"); + + err = ccs_create_configuration_space( + "my_config_space", 3, parameters, &space); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_create_distribution_space(space, &distrib_space); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_create_uniform_distribution( + CCS_NUMERIC_TYPE_FLOAT, CCSF(-4.0), CCSF(4.0), + CCS_SCALE_TYPE_LINEAR, CCSF(0.0), distribs); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_create_uniform_distribution( + CCS_NUMERIC_TYPE_FLOAT, CCSF(-3.0), CCSF(3.0), + CCS_SCALE_TYPE_LINEAR, CCSF(0.0), distribs + 1); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_create_multivariate_distribution(2, distribs, &distrib); + assert(err == CCS_RESULT_SUCCESS); + + hindexes[0] = 2; + hindexes[1] = 0; + err = ccs_distribution_space_set_distribution( + distrib_space, distrib, hindexes); + assert(err == CCS_RESULT_SUCCESS); + + for (size_t i = 0; i < 2; i++) { + err = ccs_release_object(distribs[i]); + assert(err == CCS_RESULT_SUCCESS); + } + err = ccs_release_object(distrib); + assert(err == CCS_RESULT_SUCCESS); + for (size_t i = 0; i < 3; i++) { + err = ccs_release_object(parameters[i]); + assert(err == CCS_RESULT_SUCCESS); + } + + err = ccs_object_serialize( + distrib_space, CCS_SERIALIZE_FORMAT_BINARY, + CCS_SERIALIZE_OPERATION_SIZE, &buff_size, + CCS_SERIALIZE_OPTION_END); + assert(err == CCS_RESULT_SUCCESS); + + buff = (char *)malloc(buff_size); + assert(buff); + + err = ccs_object_serialize( + distrib_space, CCS_SERIALIZE_FORMAT_BINARY, + CCS_SERIALIZE_OPERATION_MEMORY, buff_size, buff, + CCS_SERIALIZE_OPTION_END); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_create_map(&map); + assert(err == CCS_RESULT_SUCCESS); + err = ccs_release_object(distrib_space); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_object_deserialize( + (ccs_object_t *)&distrib_space, CCS_SERIALIZE_FORMAT_BINARY, + CCS_SERIALIZE_OPERATION_MEMORY, buff_size, buff, + CCS_DESERIALIZE_OPTION_HANDLE_MAP, map, + CCS_DESERIALIZE_OPTION_END); + assert(err == CCS_RESULT_ERROR_INVALID_HANDLE); + + d = ccs_object(space); + d.flags |= CCS_DATUM_FLAG_ID; + err = ccs_map_set(map, d, ccs_object(space)); + assert(err == CCS_RESULT_SUCCESS); + + assert(err == CCS_RESULT_SUCCESS); + err = ccs_object_deserialize( + (ccs_object_t *)&distrib_space, CCS_SERIALIZE_FORMAT_BINARY, + CCS_SERIALIZE_OPERATION_MEMORY, buff_size, buff, + CCS_DESERIALIZE_OPTION_HANDLE_MAP, map, + CCS_DESERIALIZE_OPTION_END); + assert(err == CCS_RESULT_SUCCESS); + + err = ccs_distribution_space_get_parameter_distribution( + distrib_space, 0, &distrib_ret, &dindex_ret); + assert(err == CCS_RESULT_SUCCESS); + assert(distrib_ret); + assert(dindex_ret == 1); + distrib_ref = distrib_ret; + + err = ccs_distribution_space_get_parameter_distribution( + distrib_space, 2, &distrib_ret, &dindex_ret); + assert(err == CCS_RESULT_SUCCESS); + assert(distrib_ret == distrib_ref); + assert(dindex_ret == 0); + + err = ccs_release_object(map); + assert(err == CCS_RESULT_SUCCESS); + err = ccs_release_object(space); + assert(err == CCS_RESULT_SUCCESS); + err = ccs_release_object(distrib_space); + assert(err == CCS_RESULT_SUCCESS); + free(buff); +} + +int +main(void) +{ + ccs_init(); + test_create(); + test_set_distribution(); + test_deserialize(); + ccs_clear_thread_error(); + ccs_fini(); + return 0; +} diff --git a/tests/test_forbidden.c b/tests/test_forbidden.c index 7c203c37..d8984033 100644 --- a/tests/test_forbidden.c +++ b/tests/test_forbidden.c @@ -44,7 +44,8 @@ test_simple(void) for (int i = 0; i < 100; i++) { ccs_float_t f; ccs_bool_t check; - err = ccs_configuration_space_sample(space, &configuration); + err = ccs_configuration_space_sample( + space, NULL, &configuration); assert(err == CCS_RESULT_SUCCESS); err = ccs_configuration_get_values( configuration, 2, values, NULL); @@ -62,7 +63,7 @@ test_simple(void) err = ccs_release_object(configuration); assert(err == CCS_RESULT_SUCCESS); } - err = ccs_configuration_space_samples(space, 100, configurations); + err = ccs_configuration_space_samples(space, NULL, 100, configurations); assert(err == CCS_RESULT_SUCCESS); for (int i = 0; i < 100; i++) { @@ -143,7 +144,8 @@ test_combined(void) for (int i = 0; i < 100; i++) { ccs_float_t f; ccs_bool_t check; - err = ccs_configuration_space_sample(space, &configuration); + err = ccs_configuration_space_sample( + space, NULL, &configuration); assert(err == CCS_RESULT_SUCCESS); err = ccs_configuration_get_values( configuration, 3, values, NULL); @@ -174,7 +176,7 @@ test_combined(void) assert(err == CCS_RESULT_SUCCESS); } - err = ccs_configuration_space_samples(space, 100, configurations); + err = ccs_configuration_space_samples(space, NULL, 100, configurations); assert(err == CCS_RESULT_SUCCESS); for (int i = 0; i < 100; i++) { diff --git a/tests/test_random_features_tuner.c b/tests/test_random_features_tuner.c index 665df3ca..ff13ae81 100644 --- a/tests/test_random_features_tuner.c +++ b/tests/test_random_features_tuner.c @@ -264,7 +264,7 @@ test_evaluation_deserialize(void) err = ccs_create_configuration_space("2dplane", 2, parameters, &cspace); assert(err == CCS_RESULT_SUCCESS); - err = ccs_configuration_space_sample(cspace, &configuration); + err = ccs_configuration_space_sample(cspace, NULL, &configuration); assert(err == CCS_RESULT_SUCCESS); parameter3 = create_numerical("z", -CCS_INFINITY, CCS_INFINITY); diff --git a/tests/test_random_tuner.c b/tests/test_random_tuner.c index 0d163a1f..b20a36fa 100644 --- a/tests/test_random_tuner.c +++ b/tests/test_random_tuner.c @@ -178,7 +178,7 @@ test_evaluation_deserialize(void) err = ccs_create_configuration_space("2dplane", 2, parameters, &cspace); assert(err == CCS_RESULT_SUCCESS); - err = ccs_configuration_space_sample(cspace, &configuration); + err = ccs_configuration_space_sample(cspace, NULL, &configuration); assert(err == CCS_RESULT_SUCCESS); parameter3 = create_numerical("z", -CCS_INFINITY, CCS_INFINITY); diff --git a/tests/test_user_defined_features_tuner.c b/tests/test_user_defined_features_tuner.c index b64ba24b..b68d1213 100644 --- a/tests/test_user_defined_features_tuner.c +++ b/tests/test_user_defined_features_tuner.c @@ -55,7 +55,7 @@ tuner_last_ask( if (err) return err; err = ccs_configuration_space_samples( - configuration_space, num_configurations, configurations); + configuration_space, NULL, num_configurations, configurations); if (err) return err; if (num_configurations_ret) diff --git a/tests/test_user_defined_tuner.c b/tests/test_user_defined_tuner.c index 9bcf00ea..d33f1563 100644 --- a/tests/test_user_defined_tuner.c +++ b/tests/test_user_defined_tuner.c @@ -52,7 +52,7 @@ tuner_last_ask( if (err) return err; err = ccs_configuration_space_samples( - configuration_space, num_configurations, configurations); + configuration_space, NULL, num_configurations, configurations); if (err) return err; if (num_configurations_ret)