Sélectionner une révision Git
Bifurcation depuis
Alexandre MORIGNOT / PlayBot
Le projet source a une visibilité limitée.
-
Alexandre Morignot a rédigéAlexandre Morignot a rédigé
experiment.c 9,18 Kio
/**
* An example of benchmarking random search on a COCO suite. A grid search optimizer is also
* implemented and can be used instead of random search.
*
* Set the global parameter BUDGET_MULTIPLIER to suit your needs.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "coco/coco.h"
#include "ibea/ibea.h"
/**
* The maximal budget for evaluations done by an optimization algorithm equals dimension * BUDGET_MULTIPLIER.
* Increase the budget multiplier value gradually to see how it affects the runtime.
*/
static const size_t BUDGET_MULTIPLIER = 40;
/**
* The maximal number of independent restarts allowed for an algorithm that restarts itself.
*/
static const size_t INDEPENDENT_RESTARTS = 1e5;
/**
* The random seed. Change if needed.
*/
static const uint32_t RANDOM_SEED = 0xdeadbeef;
/**
* A function type for evaluation functions, where the first argument is the vector to be evaluated and the
* second argument the vector to which the evaluation result is stored.
*/
typedef void (*evaluate_function_t)(const double *x, double *y);
/**
* A pointer to the problem to be optimized (needed in order to simplify the interface between the optimization
* algorithm and the COCO platform).
*/
static coco_problem_t *PROBLEM;
/**
* The function that calls the evaluation of the first vector on the problem to be optimized and stores the
* evaluation result in the second vector.
*/
static void evaluate_function(const double *x, double *y) {
coco_evaluate_function(PROBLEM, x, y);
}
/* Declarations of all functions implemented in this file (so that their order is not important): */
void experiment(const char *suite_name,
const char *observer_name,
coco_random_state_t *random_generator);
/* Structure and functions needed for timing the experiment */
typedef struct {
size_t number_of_dimensions;
size_t current_idx;
char **output;
size_t previous_dimension;
size_t cumulative_evaluations;
time_t start_time;
time_t overall_start_time;
} timing_data_t;
static timing_data_t *timing_data_initialize(coco_suite_t *suite);
static void timing_data_time_problem(timing_data_t *timing_data, coco_problem_t *problem);
static void timing_data_finalize(timing_data_t *timing_data);
/**
* The main method initializes the random number generator and calls the example experiment on the
* bi-objective suite.
*/
int main(void) {
coco_random_state_t *random_generator = coco_random_new(RANDOM_SEED);
/* Change the log level to "warning" to get less output */
coco_set_log_level("info");
printf("Running the example experiment... (might take time, be patient)\n");
fflush(stdout);
experiment("bbob-biobj", "bbob-biobj", random_generator);
/* Uncomment the line below to run the same example experiment on the bbob suite
example_experiment("bbob", "bbob", random_generator); */
printf("Done!\n");
fflush(stdout);
coco_random_free(random_generator);
return 0;
}
/**
* A simple example of benchmarking random search on a suite with instances from 2016 that can serve also as
* a timing experiment.
*
* @param suite_name Name of the suite (use "bbob" for the single-objective and "bbob-biobj" for the
* bi-objective suite).
* @param observer_name Name of the observer (use "bbob" for the single-objective and "bbob-biobj" for the
* bi-objective observer).
* @param random_generator The random number generator.
*/
void experiment(const char *suite_name,
const char *observer_name,
coco_random_state_t *random_generator) {
size_t run;
coco_suite_t *suite;
coco_observer_t *observer;
timing_data_t *timing_data;
/* Set some options for the observer. See documentation for other options. */
char *observer_options =
coco_strdupf("result_folder: RS_on_%s "
"algorithm_name: RS "
"algorithm_info: \"A simple random search algorithm\"", suite_name);
/* Initialize the suite and observer */
suite = coco_suite(suite_name, "year: 2016", "dimensions: 2,3,5,10,20,40");
observer = coco_observer(observer_name, observer_options);
coco_free_memory(observer_options);
/* Initialize timing */
timing_data = timing_data_initialize(suite);
/* Iterate over all problems in the suite */
while ((PROBLEM = coco_suite_get_next_problem(suite, observer)) != NULL) {
size_t dimension = coco_problem_get_dimension(PROBLEM);
/* Run the algorithm at least once */
for (run = 1; run <= 1 + INDEPENDENT_RESTARTS; run++) {
size_t evaluations_done = coco_problem_get_evaluations(PROBLEM);
long evaluations_remaining = (long) (dimension * BUDGET_MULTIPLIER) - (long) evaluations_done;
/* Break the loop if the target was hit or there are no more remaining evaluations */
if (coco_problem_final_target_hit(PROBLEM) || (evaluations_remaining <= 0))
break;
/* Call the optimization algorithm for the remaining number of evaluations */
ibea(evaluate_function,
dimension,
coco_problem_get_number_of_objectives(PROBLEM),
coco_problem_get_smallest_values_of_interest(PROBLEM),
coco_problem_get_largest_values_of_interest(PROBLEM),
(size_t) evaluations_remaining,
random_generator);
/* Break the loop if the algorithm performed no evaluations or an unexpected thing happened */
if (coco_problem_get_evaluations(PROBLEM) == evaluations_done) {
printf("WARNING: Budget has not been exhausted (%lu/%lu evaluations done)!\n",
(unsigned long) evaluations_done, (unsigned long) dimension * BUDGET_MULTIPLIER);
break;
}
else if (coco_problem_get_evaluations(PROBLEM) < evaluations_done)
coco_error("Something unexpected happened - function evaluations were decreased!");
}
/* Keep track of time */
timing_data_time_problem(timing_data, PROBLEM);
}
/* Output and finalize the timing data */
timing_data_finalize(timing_data);
coco_observer_free(observer);
coco_suite_free(suite);
}
/**
* Allocates memory for the timing_data_t object and initializes it.
*/
static timing_data_t *timing_data_initialize(coco_suite_t *suite) {
timing_data_t *timing_data = (timing_data_t *) coco_allocate_memory(sizeof(*timing_data));
size_t function_idx, dimension_idx, instance_idx, i;
/* Find out the number of all dimensions */
coco_suite_decode_problem_index(suite, coco_suite_get_number_of_problems(suite) - 1, &function_idx,
&dimension_idx, &instance_idx);
timing_data->number_of_dimensions = dimension_idx + 1;
timing_data->current_idx = 0;
timing_data->output = (char **) coco_allocate_memory(timing_data->number_of_dimensions * sizeof(char *));
for (i = 0; i < timing_data->number_of_dimensions; i++) {
timing_data->output[i] = NULL;
}
timing_data->previous_dimension = 0;
timing_data->cumulative_evaluations = 0;
time(&timing_data->start_time);
time(&timing_data->overall_start_time);
return timing_data;
}
/**
* Keeps track of the total number of evaluations and elapsed time. Produces an output string when the
* current problem is of a different dimension than the previous one or when NULL.
*/
static void timing_data_time_problem(timing_data_t *timing_data, coco_problem_t *problem) {
double elapsed_seconds = 0;
if ((problem == NULL) || (timing_data->previous_dimension != coco_problem_get_dimension(problem))) {
/* Output existing timing information */
if (timing_data->cumulative_evaluations > 0) {
time_t now;
time(&now);
elapsed_seconds = difftime(now, timing_data->start_time) / (double) timing_data->cumulative_evaluations;
timing_data->output[timing_data->current_idx++] = coco_strdupf("d=%lu done in %.2e seconds/evaluation\n",
timing_data->previous_dimension, elapsed_seconds);
}
if (problem != NULL) {
/* Re-initialize the timing_data */
timing_data->previous_dimension = coco_problem_get_dimension(problem);
timing_data->cumulative_evaluations = coco_problem_get_evaluations(problem);
time(&timing_data->start_time);
}
} else {
timing_data->cumulative_evaluations += coco_problem_get_evaluations(problem);
}
}
/**
* Outputs and finalizes the given timing data.
*/
static void timing_data_finalize(timing_data_t *timing_data) {
/* Record the last problem */
timing_data_time_problem(timing_data, NULL);
if (timing_data) {
size_t i;
double elapsed_seconds;
time_t now;
int hours, minutes, seconds;
time(&now);
elapsed_seconds = difftime(now, timing_data->overall_start_time);
printf("\n");
for (i = 0; i < timing_data->number_of_dimensions; i++) {
if (timing_data->output[i]) {
printf("%s", timing_data->output[i]);
coco_free_memory(timing_data->output[i]);
}
}
hours = (int) elapsed_seconds / 3600;
minutes = ((int) elapsed_seconds % 3600) / 60;
seconds = (int)elapsed_seconds - (hours * 3600) - (minutes * 60);
printf("Total elapsed time: %dh%02dm%02ds\n", hours, minutes, seconds);
coco_free_memory(timing_data->output);
coco_free_memory(timing_data);
}
}