Commit 0e2df867 authored by Brice Videau's avatar Brice Videau
Browse files

Compiles with g++ and gcc (without -Wpedantic).

parent 570ffe5a
#ifndef _CCS_BASE_H
#define _CCS_BASE_H
#include <limits.h>
#include <math.h>
#ifdef __cplusplus
extern "C" {
#endif
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
typedef double ccs_float_t;
typedef int64_t ccs_int_t;
typedef int32_t ccs_bool_t;
#define CCS_TRUE ((ccs_bool_t)(1))
#define CCS_FALSE ((ccs_bool_t)(0))
#define CCS_INT_MAX LLONG_MAX
#define CCS_INT_MIN LLONG_MIN
#define CCS_INFINITY INFINITY
typedef struct _ccs_rng_s *ccs_rng_t;
typedef struct _ccs_distribution_s *ccs_distribution_t;
......@@ -50,6 +63,7 @@ enum ccs_data_type_e {
CCS_FLOAT,
CCS_STRING,
CCS_OBJECT,
CCS_NONE,
CCS_DATA_TYPE_MAX,
CCS_DATA_TYPE_FORCE_32BIT = INT_MAX
};
......@@ -66,6 +80,17 @@ union ccs_object_u {
ccs_expression_t expression;
ccs_condition_t condition;
ccs_forbidden_clause_t forbidden_clause;
#ifdef __cplusplus
ccs_object_u(void *v) : ptr(v) {}
ccs_object_u(ccs_rng_t v) : rng(v) {}
ccs_object_u(ccs_configuration_space_t v) : configuration_space(v) {}
ccs_object_u(ccs_configuration_t v) : configuration(v) {}
ccs_object_u(ccs_distribution_t v) : distribution(v) {}
ccs_object_u(ccs_hyperparameter_t v) : hyperparameter(v) {}
ccs_object_u(ccs_expression_t v) : expression(v) {}
ccs_object_u(ccs_condition_t v) : condition(v) {}
ccs_object_u(ccs_forbidden_clause_t v) : forbidden_clause(v) {}
#endif
};
typedef union ccs_object_u ccs_object_t;
......@@ -74,8 +99,15 @@ typedef union ccs_object_u ccs_object_t;
union ccs_value_u {
ccs_float_t f;
ccs_int_t i;
const char *s;
char *s;
ccs_object_t o;
#ifdef __cplusplus
ccs_value_u() : i(0L) {}
ccs_value_u(ccs_float_t v) : f(v) {}
ccs_value_u(ccs_int_t v) : i(v) {}
ccs_value_u(char *v) : s(v) {}
ccs_value_u(ccs_object_t v) : o(v) {}
#endif
};
typedef union ccs_value_u ccs_value_t;
......@@ -84,6 +116,9 @@ typedef union ccs_value_u ccs_value_t;
struct ccs_datum_u {
ccs_value_t value;
ccs_data_type_t type;
#ifdef __cplusplus
ccs_datum_u() : value(0L), type(CCS_NONE) {}
#endif
};
typedef struct ccs_datum_u ccs_datum_t;
......
......@@ -109,6 +109,13 @@ ccs_distribution_get_parameters(ccs_distribution_t distribution,
ccs_datum_t *parameters,
size_t *num_parameters_ret);
extern ccs_error_t
ccs_distribution_get_bounds(ccs_distribution_t distribution,
ccs_datum_t *lower,
ccs_bool_t *lower_included,
ccs_datum_t *upper,
ccs_bool_t *upper_included);
extern ccs_error_t
ccs_normal_distribution_get_parameters(ccs_distribution_t distribution,
ccs_datum_t *mu_ret,
......
......@@ -17,11 +17,17 @@ typedef enum ccs_hyperparameter_type_e ccs_hyperparameter_type_t;
// Hyperparameter Interface
extern ccs_error_t
ccs_create_numerical_hyperparameter(const char *name,
void *user_data,
ccs_distribution_t distribution,
ccs_datum_t default_value,
ccs_hyperparameter_t *hyperparameter_ret);
_ccs_create_numerical_hyperparameter(const char *name,
ccs_data_type_t data_type,
ccs_value_t lower,
ccs_value_t upper,
ccs_value_t quantization,
ccs_value_t default_value,
ccs_distribution_t distribution,
void *user_data,
ccs_hyperparameter_t *hyperparameter_ret);
#define ccs_create_numerical_hyperparameter(n, t, l, u, q, d, dis, us, h) \
_ccs_create_numerical_hyperparameter(n, t, (ccs_value_t)(l), (ccs_value_t)(u), (ccs_value_t)(q), (ccs_value_t)(d), dis, us, h)
extern ccs_error_t
ccs_create_categorical_hyperparameter(const char *name,
......@@ -41,17 +47,24 @@ ccs_create_ordinal_hyperparameters(const char *name,
// Accessors
extern ccs_error_t
ccs_hyperparameter_get_type(ccs_hyperparameter_t hyperparameter,
ccs_hyperparameter_type_t *type_ret);
extern ccs_error_t
ccs_hyperparameters_get_default_value(ccs_hyperparameter_t hyperparameter,
ccs_datum_t *value);
ccs_datum_t *value_ret);
extern ccs_error_t
ccs_hyperparameters_get_name(ccs_hyperparameter_t hyperparameter,
const char **name);
const char **name_ret);
extern ccs_error_t
ccs_hyperparameters_get_user_data(ccs_hyperparameter_t hyperparameter,
void **user_data);
void **user_data_ret);
extern ccs_error_t
ccs_hyperparameter_get_distribution(ccs_hyperparameter_t hyperparameter,
ccs_distribution_t *distribution);
// Sampling Interface
extern ccs_error_t
ccs_hyperparameters_sample(ccs_hyperparameter_t hyperparameter,
......
AM_CPPFLAGS = -I$(top_srcdir)/include
AM_CFLAGS = -Wall -Werror -pedantic
AM_CFLAGS = -Wall -Werror -Wpedantic
lib_LTLIBRARIES = libcconfigspace.la
......@@ -12,6 +12,9 @@ libcconfigspace_la_SOURCES = \
distribution.c \
distribution_internal.h \
distribution_uniform.c \
distribution_normal.c
distribution_normal.c \
hyperparameter.c \
hyperparameter_internal.h \
hyperparameter_numerical.c
@VALGRIND_CHECK_RULES@
......@@ -76,6 +76,20 @@ ccs_distribution_get_parameters(ccs_distribution_t distribution,
return ops->get_parameters(distribution->data, num_parameters, parameters, num_parameters_ret);
}
ccs_error_t
ccs_distribution_get_bounds(ccs_distribution_t distribution,
ccs_datum_t *lower,
ccs_bool_t *lower_included,
ccs_datum_t *upper,
ccs_bool_t *upper_included) {
if (!distribution || !distribution->data)
return -CCS_INVALID_OBJECT;
if (!lower && !lower_included && !upper && !upper_included)
return -CCS_INVALID_VALUE;
_ccs_distribution_ops_t *ops = ccs_distribution_get_ops(distribution);
return ops->get_bounds(distribution->data, lower, lower_included, upper, upper_included);
}
ccs_error_t
ccs_distribution_sample(ccs_distribution_t distribution,
ccs_rng_t rng,
......@@ -95,7 +109,7 @@ ccs_distribution_samples(ccs_distribution_t distribution,
ccs_value_t *values) {
if (!distribution || !distribution->data)
return -CCS_INVALID_OBJECT;
if (num_values && !values)
if (!num_values || !values)
return -CCS_INVALID_VALUE;
_ccs_distribution_ops_t *ops = ccs_distribution_get_ops(distribution);
return ops->samples(distribution->data, rng, num_values, values);
......
......@@ -22,7 +22,14 @@ struct _ccs_distribution_ops_s {
ccs_rng_t rng,
size_t num_values,
ccs_value_t *values);
ccs_error_t (*get_bounds)(
_ccs_distribution_data_t *distribution,
ccs_datum_t *lower,
ccs_bool_t *lower_included,
ccs_datum_t *upper,
ccs_bool_t *upper_included);
};
typedef struct _ccs_distribution_ops_s _ccs_distribution_ops_t;
......
......@@ -28,6 +28,13 @@ _ccs_distribution_normal_get_parameters(_ccs_distribution_data_t *data,
ccs_datum_t *parameters,
size_t *num_parameters_ret);
static ccs_error_t
_ccs_distribution_normal_get_bounds(_ccs_distribution_data_t *data,
ccs_datum_t *lower,
ccs_bool_t *lower_included,
ccs_datum_t *upper,
ccs_bool_t *upper_included);
static ccs_error_t
_ccs_distribution_normal_samples(_ccs_distribution_data_t *data,
ccs_rng_t rng,
......@@ -38,7 +45,8 @@ _ccs_distribution_ops_t _ccs_distribution_normal_ops = {
{ &_ccs_distribution_del },
&_ccs_distribution_normal_get_num_parameters,
&_ccs_distribution_normal_get_parameters,
&_ccs_distribution_normal_samples
&_ccs_distribution_normal_samples,
&_ccs_distribution_normal_get_bounds
};
static ccs_error_t
......@@ -70,81 +78,186 @@ _ccs_distribution_normal_get_parameters(_ccs_distribution_data_t *data,
}
static ccs_error_t
_ccs_distribution_normal_samples(_ccs_distribution_data_t *data,
ccs_rng_t rng,
size_t num_values,
ccs_value_t *values) {
_ccs_distribution_normal_get_bounds(_ccs_distribution_data_t *data,
ccs_datum_t *lower,
ccs_bool_t *lower_included,
ccs_datum_t *upper,
ccs_bool_t *upper_included) {
_ccs_distribution_normal_data_t *d = (_ccs_distribution_normal_data_t *)data;
size_t i;
const ccs_data_type_t data_type = d->common_data.data_type;
const ccs_scale_type_t scale_type = d->common_data.scale_type;
const ccs_value_t quantization = d->common_data.quantization;
const ccs_float_t mu = d->mu;
const ccs_float_t sigma = d->sigma;
const int quantize = d->quantize;
gsl_rng *grng;
ccs_error_t err = ccs_rng_get_gsl_rng(rng, &grng);
if (err)
return err;
if (data_type == CCS_FLOAT)
if (scale_type == CCS_LOGARITHMIC && quantize) {
double lq = log(quantization.f*0.5);
if (mu - lq >= 0.0)
//at least 50% chance to get a valid value
for (i = 0; i < num_values; i++)
do {
values[i].f = gsl_ran_gaussian(grng, sigma) + mu;
} while (values[i].f < lq);
else
//use tail distribution
for (i = 0; i < num_values; i++)
values[i].f = gsl_ran_gaussian_tail(grng, lq - mu, sigma) + mu;
ccs_datum_t l;
ccs_bool_t li;
ccs_datum_t u;
ccs_bool_t ui;
l.type = data_type;
u.type = data_type;
if (scale_type == CCS_LOGARITHMIC) {
if (data_type == CCS_FLOAT) {
if (quantize) {
l.value.f = quantization.f;
li = CCS_TRUE;
} else {
l.value.f = 0.0;
li = CCS_FALSE;
}
u.value.f = CCS_INFINITY;
ui = CCS_FALSE;
} else {
if (quantize) {
l.value.i = quantization.i;
u.value.i = (CCS_INT_MAX/quantization.i)*quantization.i;
} else {
l.value.i = 1;
u.value.i = CCS_INT_MAX;
}
li = CCS_TRUE;
ui = CCS_TRUE;
}
else
for (i = 0; i < num_values; i++)
values[i].f = gsl_ran_gaussian(grng, sigma) + mu;
else {
if (scale_type == CCS_LOGARITHMIC) {
double lq;
if (quantize)
lq = log(quantization.i*0.5);
else
lq = log(0.5);
if (mu - lq >= 0.0)
for (i = 0; i < num_values; i++)
do {
values[i].f = gsl_ran_gaussian(grng, sigma) + mu;
} while (values[i].f < lq);
else
for (i = 0; i < num_values; i++)
values[i].f = gsl_ran_gaussian_tail(grng, lq - mu, sigma) + mu;
} else {
if (data_type == CCS_FLOAT) {
l.value.f = -CCS_INFINITY;
li = CCS_FALSE;
u.value.f = CCS_INFINITY;
ui = CCS_FALSE;
} else {
if (quantize) {
l.value.i = (CCS_INT_MIN/quantization.i)*quantization.i;
u.value.i = (CCS_INT_MAX/quantization.i)*quantization.i;
} else {
l.value.i = CCS_INT_MIN;
u.value.i = CCS_INT_MAX;
}
li = CCS_TRUE;
ui = CCS_TRUE;
}
else
for (i = 0; i < num_values; i++)
values[i].f = gsl_ran_gaussian(grng, sigma) + mu;
}
if (lower)
*lower = l;
if (lower_included)
*lower_included = li;
if (upper)
*upper = u;
if (upper_included)
*upper_included = ui;
return CCS_SUCCESS;
}
static inline ccs_error_t
_ccs_distribution_normal_samples_float(gsl_rng *grng,
const ccs_scale_type_t scale_type,
const ccs_float_t quantization,
const ccs_float_t mu,
const ccs_float_t sigma,
const int quantize,
size_t num_values,
ccs_float_t *values) {
size_t i;
if (scale_type == CCS_LOGARITHMIC && quantize) {
ccs_float_t lq = log(quantization*0.5);
if (mu - lq >= 0.0)
//at least 50% chance to get a valid value
for (i = 0; i < num_values; i++)
do {
values[i] = gsl_ran_gaussian(grng, sigma) + mu;
} while (values[i] < lq);
else
//use tail distribution
for (i = 0; i < num_values; i++)
values[i] = gsl_ran_gaussian_tail(grng, lq - mu, sigma) + mu;
} else
for (i = 0; i < num_values; i++)
values[i] = gsl_ran_gaussian(grng, sigma) + mu;
if (scale_type == CCS_LOGARITHMIC)
for (i = 0; i < num_values; i++)
values[i].f = exp(values[i].f);
if (data_type == CCS_FLOAT) {
if (quantize) {
ccs_float_t rquantization = 1.0 / quantization.f;
values[i] = exp(values[i]);
if (quantize) {
ccs_float_t rquantization = 1.0 / quantization;
for (i = 0; i < num_values; i++)
values[i].f = round(values[i].f * rquantization) * quantization.f;
}
} else {
if (quantize) {
ccs_float_t rquantization = 1.0 / quantization.i;
values[i] = round(values[i] * rquantization) * quantization;
}
return CCS_SUCCESS;
}
static inline ccs_error_t
_ccs_distribution_normal_samples_int(gsl_rng *grng,
const ccs_scale_type_t scale_type,
const ccs_int_t quantization,
const ccs_float_t mu,
const ccs_float_t sigma,
const int quantize,
size_t num_values,
ccs_value_t *values) {
size_t i;
ccs_float_t q;
if (quantize)
q = quantization*0.5;
else
q = 0.5;
if (scale_type == CCS_LOGARITHMIC) {
ccs_float_t lq = log(q);
if (mu - lq >= 0.0)
for (i = 0; i < num_values; i++)
values[i].i = (ccs_int_t)round(values[i].f * rquantization) * quantization.i;
} else
do {
do {
values[i].f = gsl_ran_gaussian(grng, sigma) + mu;
} while (values[i].f < lq);
values[i].f = exp(values[i].f);
} while (unlikely(values[i].f - q > CCS_INT_MAX));
else
for (i = 0; i < num_values; i++)
values[i].i = round(values[i].f);
do {
values[i].f = gsl_ran_gaussian_tail(grng, lq - mu, sigma) + mu;
values[i].f = exp(values[i].f);
} while (unlikely(values[i].f - q > CCS_INT_MAX));
}
else
for (i = 0; i < num_values; i++)
do {
values[i].f = gsl_ran_gaussian(grng, sigma) + mu;
} while (unlikely(values[i].f - q > CCS_INT_MAX || values[i].f + q < CCS_INT_MIN));
if (quantize) {
ccs_float_t rquantization = 1.0 / quantization;
for (i = 0; i < num_values; i++)
values[i].i = (ccs_int_t)round(values[i].f * rquantization) * quantization;
} else
for (i = 0; i < num_values; i++)
values[i].i = round(values[i].f);
return CCS_SUCCESS;
}
static ccs_error_t
_ccs_distribution_normal_samples(_ccs_distribution_data_t *data,
ccs_rng_t rng,
size_t num_values,
ccs_value_t *values) {
_ccs_distribution_normal_data_t *d = (_ccs_distribution_normal_data_t *)data;
const ccs_data_type_t data_type = d->common_data.data_type;
const ccs_scale_type_t scale_type = d->common_data.scale_type;
const ccs_value_t quantization = d->common_data.quantization;
const ccs_float_t mu = d->mu;
const ccs_float_t sigma = d->sigma;
const int quantize = d->quantize;
gsl_rng *grng;
ccs_error_t err = ccs_rng_get_gsl_rng(rng, &grng);
if (err)
return err;
if (data_type == CCS_FLOAT)
return _ccs_distribution_normal_samples_float(grng, scale_type,
quantization.f, mu,
sigma, quantize,
num_values,
(ccs_float_t*) values);
else
return _ccs_distribution_normal_samples_int(grng, scale_type,
quantization.i, mu,
sigma, quantize,
num_values, values);
}
extern ccs_error_t
_ccs_create_normal_distribution(ccs_data_type_t data_type,
ccs_float_t mu,
......
......@@ -31,6 +31,13 @@ _ccs_distribution_uniform_get_parameters(_ccs_distribution_data_t *data,
ccs_datum_t *parameters,
size_t *num_parameters_ret);
static ccs_error_t
_ccs_distribution_uniform_get_bounds(_ccs_distribution_data_t *data,
ccs_datum_t *lower,
ccs_bool_t *lower_included,
ccs_datum_t *upper,
ccs_bool_t *upper_included);
static ccs_error_t
_ccs_distribution_uniform_samples(_ccs_distribution_data_t *data,
ccs_rng_t rng,
......@@ -41,7 +48,8 @@ _ccs_distribution_ops_t _ccs_distribution_uniform_ops = {
{ &_ccs_distribution_del },
&_ccs_distribution_uniform_get_num_parameters,
&_ccs_distribution_uniform_get_parameters,
&_ccs_distribution_uniform_samples
&_ccs_distribution_uniform_samples,
&_ccs_distribution_uniform_get_bounds
};
static ccs_error_t
......@@ -72,6 +80,36 @@ _ccs_distribution_uniform_get_parameters(_ccs_distribution_data_t *data,
return CCS_SUCCESS;
}
static ccs_error_t
_ccs_distribution_uniform_get_bounds(_ccs_distribution_data_t *data,
ccs_datum_t *lower,
ccs_bool_t *lower_included,
ccs_datum_t *upper,
ccs_bool_t *upper_included) {
_ccs_distribution_uniform_data_t *d = (_ccs_distribution_uniform_data_t *)data;
const ccs_data_type_t data_type = d->common_data.data_type;
ccs_datum_t l;
ccs_bool_t li;
ccs_datum_t u;
ccs_bool_t ui;
l.type = data_type;
l.value = d->lower;
li = CCS_TRUE;
u.type = data_type;
u.value = d->upper;
ui = CCS_FALSE;
if (lower)
*lower = l;
if (lower_included)
*lower_included = li;
if (upper)
*upper = u;
if (upper_included)
*upper_included = ui;
return CCS_SUCCESS;
}
static ccs_error_t
_ccs_distribution_uniform_samples(_ccs_distribution_data_t *data,
ccs_rng_t rng,
......
#include "cconfigspace_internal.h"
#include "hyperparameter_internal.h"
static inline _ccs_hyperparameter_ops_t *
ccs_hyperparameter_get_ops(ccs_hyperparameter_t hyperparameter) {
return (_ccs_hyperparameter_ops_t *)hyperparameter->obj.ops;
}
ccs_error_t
ccs_hyperparameter_get_type(ccs_hyperparameter_t hyperparameter,
ccs_hyperparameter_type_t *type_ret) {
if (!hyperparameter || !hyperparameter->data)
return -CCS_INVALID_OBJECT;
if (!type_ret)
return -CCS_INVALID_VALUE;
*type_ret = ((_ccs_hyperparameter_common_data_t *)(hyperparameter->data))->type;
return CCS_SUCCESS;
}
ccs_error_t
ccs_hyperparameter_get_default_value(ccs_hyperparameter_t hyperparameter,
ccs_datum_t *value_ret) {
if (!hyperparameter || !hyperparameter->data)
return -CCS_INVALID_OBJECT;
if (!value_ret)
return -CCS_INVALID_VALUE;
*value_ret = ((_ccs_hyperparameter_common_data_t *)(hyperparameter->data))->default_value;
return CCS_SUCCESS;
}
ccs_error_t
ccs_hyperparameter_get_name(ccs_hyperparameter_t hyperparameter,
const char **name_ret) {
if (!hyperparameter || !hyperparameter->data)
return -CCS_INVALID_OBJECT;
if (!name_ret)
return -CCS_INVALID_OBJECT;
*name_ret = ((_ccs_hyperparameter_common_data_t *)(hyperparameter->data))->name;
return CCS_SUCCESS;
}
ccs_error_t
ccs_hyperparameter_get_user_data(ccs_hyperparameter_t hyperparameter,
void **user_data_ret) {
if (!hyperparameter || !hyperparameter->data)
return -CCS_INVALID_OBJECT;
if (!user_data_ret)
return -CCS_INVALID_OBJECT;
*user_data_ret = ((_ccs_hyperparameter_common_data_t *)(hyperparameter->data))->user_data;
return CCS_SUCCESS;
}
ccs_error_t
ccs_hyperparameter_get_distribution(ccs_hyperparameter_t hyperparameter,
ccs_distribution_t *distribution) {
if (!hyperparameter || !hyperparameter->data)
return -CCS_INVALID_OBJECT;
if (!distribution)
return -CCS_INVALID_OBJECT;
*distribution = ((_ccs_hyperparameter_common_data_t *)(hyperparameter->data))->distribution;
return CCS_SUCCESS;
}
ccs_error_t
ccs_hyperparameter_sample(ccs_hyperparameter_t hyperparameter,
ccs_rng_t rng,
ccs_datum_t *value) {
if (!hyperparameter || !hyperparameter->data)
return -CCS_INVALID_OBJECT;
if (!value)
return -CCS_INVALID_VALUE;
_ccs_hyperparameter_ops_t *ops = ccs_hyperparameter_get_ops(hyperparameter);