Commit 4cf115a6 authored by Brice Videau's avatar Brice Videau
Browse files

Added a demonstration random tuner.

parent 19783d8e
......@@ -76,6 +76,7 @@ enum ccs_object_type_e {
CCS_CONFIGURATION,
CCS_OBJECTIVE_SPACE,
CCS_EVALUATION,
CCS_TUNER,
CCS_OBJECT_TYPE_MAX,
CCS_OBJECT_TYPE_FORCE_32BIT = INT_MAX
};
......
......@@ -53,9 +53,9 @@ ccs_configuration_hash(ccs_configuration_t configuration,
ccs_hash_t *hash_ret);
extern ccs_error_t
ccs_configuration_equal(ccs_configuration_t configuration,
ccs_configuration_t other_configuration,
ccs_bool_t *equal_ret);
ccs_configuration_cmp(ccs_configuration_t configuration,
ccs_configuration_t other_configuration,
int *equal_ret);
#ifdef __cplusplus
}
#endif
......
......@@ -5,6 +5,16 @@
extern "C" {
#endif
enum ccs_comparison_e {
CCS_BETTER = -1,
CCS_EQUIVALENT = 0,
CCS_WORSE = 1,
CCS_NOT_COMPARABLE = 2,
CCS_COMPARISON_MAX,
CCS_COMPARISON_FORCE_32BIT = INT_MAX
};
typedef enum ccs_comparison_e ccs_comparison_t;
extern ccs_error_t
ccs_create_evaluation(ccs_objective_space_t objective_space,
ccs_configuration_t configuration,
......@@ -55,6 +65,22 @@ ccs_evaluation_get_value_by_name(ccs_evaluation_t evaluation,
const char *name,
ccs_datum_t *value_ret);
extern ccs_error_t
ccs_evaluation_get_objective_value(ccs_evaluation_t evaluation,
size_t index,
ccs_datum_t *value_ret);
extern ccs_error_t
ccs_evaluation_get_objective_values(ccs_evaluation_t evaluation,
size_t num_values,
ccs_datum_t *values,
size_t *num_values_ret);
extern ccs_error_t
ccs_evaluation_cmp(ccs_evaluation_t evaluation,
ccs_evaluation_t other_evaluation,
ccs_comparison_t *result_ret);
#ifdef __cplusplus
}
#endif
......
......@@ -5,6 +5,22 @@
extern "C" {
#endif
extern ccs_error_t
ccs_tuner_get_name(ccs_tuner_t tuner,
const char **name_ret);
extern ccs_error_t
ccs_tuner_get_user_data(ccs_tuner_t tuner,
void **user_data_ret);
extern ccs_error_t
ccs_tuner_get_configuration_space(ccs_tuner_t tuner,
ccs_configuration_space_t *configuration_space_ret);
extern ccs_error_t
ccs_tuner_get_objective_spce(ccs_tuner_t tuner,
ccs_objective_space_t *objective_space_ret);
extern ccs_error_t
ccs_tuner_ask(ccs_tuner_t tuner,
size_t num_configurations,
......@@ -17,9 +33,23 @@ ccs_tuner_tell(ccs_tuner_t tuner,
ccs_evaluation_t *evaluations);
extern ccs_error_t
ccs_tuner_get_optimal(ccs_tuner_t tuner,
ccs_configuration_t *configuration_ret);
ccs_tuner_get_optimums(ccs_tuner_t tuner,
size_t num_evaluations,
ccs_evaluation_t *evaluations,
size_t *num_evaluations_ret);
extern ccs_error_t
ccs_tuner_get_history(ccs_tuner_t tuner,
size_t num_evaluations,
ccs_evaluation_t *evaluations,
size_t *num_evaluations_ret);
extern ccs_error_t
ccs_create_random_tuner(const char *name,
ccs_configuration_space_t configuration_space,
ccs_objective_space_t objective_space,
void *user_data,
ccs_tuner_t *tuner_ret);
#ifdef __cplusplus
}
#endif
......
......@@ -34,6 +34,9 @@ libcconfigspace_la_SOURCES = \
objective_space.c \
objective_space_internal.h \
evaluation.c \
evaluation_internal.h
evaluation_internal.h \
tuner.c \
tuner_internal.h \
tuner_random.c
@VALGRIND_CHECK_RULES@
......@@ -183,27 +183,33 @@ ccs_configuration_hash(ccs_configuration_t configuration,
}
ccs_error_t
ccs_configuration_equal(ccs_configuration_t configuration,
ccs_configuration_t other_configuration,
ccs_bool_t *equal_ret) {
ccs_configuration_cmp(ccs_configuration_t configuration,
ccs_configuration_t other_configuration,
int *cmp_ret) {
if (!configuration || !configuration->data)
return -CCS_INVALID_OBJECT;
if (!other_configuration || !other_configuration->data)
return -CCS_INVALID_OBJECT;
if (!equal_ret)
if (!cmp_ret)
return -CCS_INVALID_VALUE;
if (configuration == other_configuration) {
*cmp_ret = 0;
return CCS_SUCCESS;
}
_ccs_configuration_data_t *data = configuration->data;
_ccs_configuration_data_t *other_data = other_configuration->data;
*equal_ret = CCS_FALSE;
if (data->configuration_space != other_data->configuration_space)
*cmp_ret = data->configuration_space < other_data->configuration_space ? -1 :
data->configuration_space > other_data->configuration_space ? 1 : 0;
if (*cmp_ret)
return CCS_SUCCESS;
if (data->num_values != other_data->num_values)
*cmp_ret = data->num_values < other_data->num_values ? -1 :
data->num_values > other_data->num_values ? 1 : 0;
if (*cmp_ret)
return CCS_SUCCESS;
for (size_t i = 0; i < data->num_values; i++) {
if (_datum_cmp(data->values + i, other_data->values + i))
if ( (*cmp_ret = _datum_cmp(data->values + i, other_data->values + i)) )
return CCS_SUCCESS;
}
*equal_ret = CCS_TRUE;
return CCS_SUCCESS;
}
......@@ -2,7 +2,7 @@
#define _DATUM_HASH_H
#define HASH_NONFATAL_OOM 1
#define HASH_FUNCTION(s,len,hashv) (hashv) = _hash_datum((ccs_datum_t *)(s))
#define HASH_FUNCTION(s,len,hashv) do { (hashv) = _hash_datum((ccs_datum_t *)(s)); } while(0)
#define HASH_KEYCMP(a,b,len) (_datum_cmp((ccs_datum_t *)a, (ccs_datum_t *)b))
#include "uthash.h"
......
......@@ -193,3 +193,133 @@ ccs_evaluation_get_value_by_name(ccs_evaluation_t evaluation,
*value_ret = evaluation->data->values[index];
return CCS_SUCCESS;
}
ccs_error_t
ccs_evaluation_get_objective_value(ccs_evaluation_t evaluation,
size_t index,
ccs_datum_t *value_ret) {
if (!evaluation || !evaluation->data)
return -CCS_INVALID_OBJECT;
ccs_expression_t expression;
ccs_objective_type_t type;
ccs_error_t err;
err = ccs_objective_space_get_objective(evaluation->data->objective_space,
index, &expression, &type);
if (err)
return err;
return ccs_expression_eval(expression,
(ccs_context_t)evaluation->data->objective_space,
evaluation->data->values, value_ret);
}
ccs_error_t
ccs_evaluation_get_objective_values(ccs_evaluation_t evaluation,
size_t num_values,
ccs_datum_t *values,
size_t *num_values_ret) {
if (!evaluation || !evaluation->data)
return -CCS_INVALID_OBJECT;
if (num_values && !values)
return -CCS_INVALID_VALUE;
if (!values && !num_values_ret)
return -CCS_INVALID_VALUE;
size_t count;
ccs_error_t err;
err = ccs_objective_space_get_objectives(evaluation->data->objective_space,
0, NULL, NULL, &count);
if (err)
return err;
if (values) {
if (count < num_values)
return -CCS_INVALID_VALUE;
for (size_t i = 0; i < count; i++) {
ccs_expression_t expression;
ccs_objective_type_t type;
err = ccs_objective_space_get_objective(
evaluation->data->objective_space, i, &expression, &type);
if (err)
return err;
err = ccs_expression_eval(expression,
(ccs_context_t)evaluation->data->objective_space,
evaluation->data->values, values + i);
if (err)
return err;
}
for (size_t i = count; i < num_values; i++)
values[i] = ccs_none;
}
if (num_values_ret)
*num_values_ret = count;
return CCS_SUCCESS;
}
static inline int
_numeric_compare(const ccs_datum_t *a, const ccs_datum_t *b) {
if (a->type == CCS_FLOAT) {
return a->value.f < b->value.f ? -1 : a->value.f > b->value.f ? 1 : 0;
} else {
return a->value.i < b->value.i ? -1 : a->value.i > b->value.i ? 1 : 0;
}
}
//Could be using memoization here.
ccs_error_t
ccs_evaluation_cmp(ccs_evaluation_t evaluation,
ccs_evaluation_t other_evaluation,
ccs_comparison_t *result_ret) {
if (!evaluation || !evaluation->data || evaluation->data->error)
return -CCS_INVALID_OBJECT;
if (!other_evaluation || !other_evaluation->data || other_evaluation->data->error)
return -CCS_INVALID_OBJECT;
if (evaluation->data->objective_space != other_evaluation->data->objective_space)
return -CCS_INVALID_OBJECT;
if (!result_ret)
return -CCS_INVALID_VALUE;
size_t count;
ccs_error_t err;
err = ccs_objective_space_get_objectives(evaluation->data->objective_space,
0, NULL, NULL, &count);
if (err)
return err;
*result_ret = CCS_EQUIVALENT;
for (size_t i = 0; i < count; i++) {
ccs_expression_t expression;
ccs_objective_type_t type;
ccs_datum_t values[2];
int cmp;
err = ccs_objective_space_get_objective(
evaluation->data->objective_space, i, &expression, &type);
if (err)
return err;
err = ccs_expression_eval(expression,
(ccs_context_t)evaluation->data->objective_space,
evaluation->data->values, values);
if (err)
return err;
err = ccs_expression_eval(expression,
(ccs_context_t)evaluation->data->objective_space,
other_evaluation->data->values, values + 1);
if (err)
return err;
if ((values[0].type != CCS_INTEGER && values[0].type != CCS_FLOAT) ||
values[0].type != values[1].type) {
*result_ret = CCS_NOT_COMPARABLE;
return CCS_SUCCESS;
}
cmp = _numeric_compare(values, values + 1);
if (cmp) {
if (type == CCS_MAXIMIZE)
cmp = -cmp;
if (*result_ret == CCS_EQUIVALENT)
*result_ret = (ccs_comparison_t)cmp;
else if (*result_ret != cmp) {
*result_ret = CCS_NOT_COMPARABLE;
return CCS_SUCCESS;
}
}
}
return CCS_SUCCESS;
}
......@@ -157,7 +157,7 @@ ccs_create_numerical_hyperparameter(const char *name,
default_value.f < lower.f ||
default_value.f >= upper.f ) )
return -CCS_INVALID_VALUE;
uintptr_t mem = (uintptr_t)calloc(1, sizeof(struct _ccs_hyperparameter_s) + sizeof(_ccs_hyperparameter_numerical_data_t)+strlen(name) + 1);
uintptr_t mem = (uintptr_t)calloc(1, sizeof(struct _ccs_hyperparameter_s) + sizeof(_ccs_hyperparameter_numerical_data_t) + strlen(name) + 1);
if (!mem)
return -CCS_ENOMEM;
......
#include "cconfigspace_internal.h"
#include "tuner_internal.h"
static inline _ccs_tuner_ops_t *
ccs_tuner_get_ops(ccs_tuner_t tuner) {
return (_ccs_tuner_ops_t *)tuner->obj.ops;
}
ccs_error_t
ccs_tuner_get_name(ccs_tuner_t tuner,
const char **name_ret) {
if (!tuner || !tuner->data)
return -CCS_INVALID_OBJECT;
if (!name_ret)
return -CCS_INVALID_VALUE;
_ccs_tuner_common_data_t *d = (_ccs_tuner_common_data_t *)tuner->data;
*name_ret = d->name;
return CCS_SUCCESS;
}
ccs_error_t
ccs_tuner_get_user_data(ccs_tuner_t tuner,
void **user_data_ret) {
if (!tuner || !tuner->data)
return -CCS_INVALID_OBJECT;
if (!user_data_ret)
return -CCS_INVALID_VALUE;
_ccs_tuner_common_data_t *d = (_ccs_tuner_common_data_t *)tuner->data;
*user_data_ret = d->user_data;
return CCS_SUCCESS;
}
ccs_error_t
ccs_tuner_get_configuration_space(ccs_tuner_t tuner,
ccs_configuration_space_t *configuration_space_ret) {
if (!tuner || !tuner->data)
return -CCS_INVALID_OBJECT;
if (!configuration_space_ret)
return -CCS_INVALID_VALUE;
_ccs_tuner_common_data_t *d = (_ccs_tuner_common_data_t *)tuner->data;
*configuration_space_ret = d->configuration_space;
return CCS_SUCCESS;
}
ccs_error_t
ccs_tuner_get_objective_spce(ccs_tuner_t tuner,
ccs_objective_space_t *objective_space_ret) {
if (!tuner || !tuner->data)
return -CCS_INVALID_OBJECT;
if (!objective_space_ret)
return -CCS_INVALID_VALUE;
_ccs_tuner_common_data_t *d = (_ccs_tuner_common_data_t *)tuner->data;
*objective_space_ret = d->objective_space;
return CCS_SUCCESS;
}
ccs_error_t
ccs_tuner_ask(ccs_tuner_t tuner,
size_t num_configurations,
ccs_configuration_t *configurations,
size_t *num_configurations_ret) {
if (!tuner || !tuner->data)
return -CCS_INVALID_OBJECT;
if (num_configurations && !configurations)
return -CCS_INVALID_VALUE;
if (!configurations && !num_configurations_ret)
return -CCS_INVALID_VALUE;
_ccs_tuner_ops_t *ops = ccs_tuner_get_ops(tuner);
return ops->ask(tuner->data, num_configurations, configurations, num_configurations_ret);
}
ccs_error_t
ccs_tuner_tell(ccs_tuner_t tuner,
size_t num_evaluations,
ccs_evaluation_t *evaluations) {
if (!tuner || !tuner->data)
return -CCS_INVALID_OBJECT;
if (num_evaluations && !evaluations)
return -CCS_INVALID_VALUE;
_ccs_tuner_ops_t *ops = ccs_tuner_get_ops(tuner);
return ops->tell(tuner->data, num_evaluations, evaluations);
}
ccs_error_t
ccs_tuner_get_optimums(ccs_tuner_t tuner,
size_t num_evaluations,
ccs_evaluation_t *evaluations,
size_t *num_evaluations_ret) {
if (!tuner || !tuner->data)
return -CCS_INVALID_OBJECT;
if (num_evaluations && !evaluations)
return -CCS_INVALID_VALUE;
if (!evaluations && !num_evaluations_ret)
return -CCS_INVALID_VALUE;
_ccs_tuner_ops_t *ops = ccs_tuner_get_ops(tuner);
return ops->get_optimums(tuner->data, num_evaluations, evaluations, num_evaluations_ret);
}
ccs_error_t
ccs_tuner_get_history(ccs_tuner_t tuner,
size_t num_evaluations,
ccs_evaluation_t *evaluations,
size_t *num_evaluations_ret) {
if (!tuner || !tuner->data)
return -CCS_INVALID_OBJECT;
if (num_evaluations && !evaluations)
return -CCS_INVALID_VALUE;
if (!evaluations && !num_evaluations_ret)
return -CCS_INVALID_VALUE;
_ccs_tuner_ops_t *ops = ccs_tuner_get_ops(tuner);
return ops->get_history(tuner->data, num_evaluations, evaluations, num_evaluations_ret);
}
#ifndef _TUNER_INTERNAL_H
#define _TUNER_INTERNAL_H
struct _ccs_tuner_data_s;
typedef struct _ccs_tuner_data_s _ccs_tuner_data_t;
struct _ccs_tuner_ops_s {
_ccs_object_ops_t obj_ops;
ccs_error_t (*ask)(
_ccs_tuner_data_t *data,
size_t num_configurations,
ccs_configuration_t *configurations,
size_t *num_configurations_ret);
ccs_error_t (*tell)(
_ccs_tuner_data_t *data,
size_t num_evaluations,
ccs_evaluation_t *evaluations);
ccs_error_t (*get_optimums)(
_ccs_tuner_data_t *data,
size_t num_evaluations,
ccs_evaluation_t *evaluations,
size_t *num_evaluations_ret);
ccs_error_t (*get_history)(
_ccs_tuner_data_t *data,
size_t num_evaluations,
ccs_evaluation_t *evaluations,
size_t *num_evaluations_ret);
};
typedef struct _ccs_tuner_ops_s _ccs_tuner_ops_t;
struct _ccs_tuner_s {
_ccs_object_internal_t obj;
_ccs_tuner_data_t *data;
};
struct _ccs_tuner_common_data_s {
const char *name;
void *user_data;
ccs_configuration_space_t configuration_space;
ccs_objective_space_t objective_space;
};
typedef struct _ccs_tuner_common_data_s _ccs_tuner_common_data_t;
#endif //_TUNER_INTERNAL_H
#include "cconfigspace_internal.h"
#include "tuner_internal.h"
#include "utarray.h"
struct _ccs_random_tuner_data_s {
_ccs_tuner_common_data_t common_data;
UT_array *history;
UT_array *optimums;
UT_array *old_optimums;
};
typedef struct _ccs_random_tuner_data_s _ccs_random_tuner_data_t;
static ccs_error_t
_ccs_tuner_random_del(ccs_object_t o) {
_ccs_random_tuner_data_t *d = (_ccs_random_tuner_data_t *)((ccs_tuner_t)o)->data;
ccs_release_object(d->common_data.configuration_space);
ccs_release_object(d->common_data.objective_space);
ccs_evaluation_t *e = NULL;
while ( (e = (ccs_evaluation_t *)utarray_next(d->history, e)) ) {
ccs_release_object(*e);
}
utarray_free(d->history);
utarray_free(d->optimums);
utarray_free(d->old_optimums);
return CCS_SUCCESS;
}
static ccs_error_t
_ccs_tuner_random_ask(_ccs_tuner_data_t *data,
size_t num_configurations,
ccs_configuration_t *configurations,
size_t *num_configurations_ret) {
_ccs_random_tuner_data_t *d = (_ccs_random_tuner_data_t *)data;
if (!configurations) {
*num_configurations_ret = 1;
return CCS_SUCCESS;
}
ccs_error_t err;
err = ccs_configuration_space_samples(d->common_data.configuration_space,
num_configurations, configurations);
if (err)
return err;
if (num_configurations_ret)
*num_configurations_ret = num_configurations;
return CCS_SUCCESS;
}
#undef utarray_oom
#define utarray_oom() { \
ccs_release_object(evaluations[i]); \
return -CCS_ENOMEM; \
}
static ccs_error_t
_ccs_tuner_random_tell(_ccs_tuner_data_t *data,
size_t num_evaluations,
ccs_evaluation_t *evaluations) {
_ccs_random_tuner_data_t *d = (_ccs_random_tuner_data_t *)data;
UT_array *history = d->history;
ccs_error_t err;
for (size_t i = 0; i < num_evaluations; i++) {
ccs_error_t error;
err = ccs_evaluation_get_error(evaluations[i], &error);
if (err)
return err;
if (!error) {
int discard = 0;
UT_array *tmp;
ccs_retain_object(evaluations[i]);
utarray_push_back(history, evaluations + i);
tmp = d->old_optimums;
d->old_optimums = d->optimums;
d->optimums = tmp;
utarray_clear(d->optimums);
ccs_evaluation_t *eval = NULL;
#undef utarray_oom
#define utarray_oom() { \
d->optimums = d->old_optimums; \
return -CCS_ENOMEM; \
}
while ( (eval = (ccs_evaluation_t *)utarray_next(d->old_optimums, eval)) ) {
if (!discard) {
ccs_comparison_t cmp;
err = ccs_evaluation_cmp(evaluations[i], *eval, &cmp);
if (err)
discard = 1;
else switch (cmp) {
case CCS_EQUIVALENT:
case CCS_WORSE:
discard = 1;
utarray_push_back(d->optimums, eval);
break;
case CCS_BETTER:
break;
case CCS_NOT_COMPARABLE:
default:
utarray_push_back(d->optimums, eval);
break;
}
} else {
utarray_push_back(d->optimums, eval);
}
}
if(!discard)
utarray_push_back(d->optimums, evaluations + i);
}
}
return CCS_SUCCESS;
}
static ccs_error_t
_ccs_tuner_random_get_optimums(_ccs_tuner_data_t *data,
size_t num_evaluations,
ccs_evaluation_t *evaluations,
size_t *num_evaluations_ret) {
_ccs_random_tuner_data_t *d = (_ccs_random_tuner_data_t *)data;
size_t count = utarray_len(d->optimums);
if (evaluations) {
if (count < num_evaluations)
return -CCS_INVALID_VALUE;
ccs_evaluation_t *eval = NULL;
size_t index = 0;
while ( (eval = (ccs_evaluation_t *)utarray_next(d->optimums, eval)) )
evaluations[index++] = *eval;
for (size_t i = count; i <num_evaluations; i++)
evaluations[i] = NULL;
}
if (num_evaluations_ret)
*num_evaluations_ret = count;
return CCS_SUCCESS;
}