/** * @brief Returns the best known value for indicator_name matching the given key if the key is found, and * throws a coco_error otherwise. */ static double suite_biobj_get_best_value(const char *indicator_name, const char *key) { size_t i, count; double best_value = 0; char *curr_key; if (strcmp(indicator_name, "hyp") == 0) { curr_key = coco_allocate_string(COCO_PATH_MAX); count = sizeof(suite_biobj_best_values_hyp) / sizeof(char *); for (i = 0; i < count; i++) { sscanf(suite_biobj_best_values_hyp[i], "%s %lf", curr_key, &best_value); if (strcmp(curr_key, key) == 0) { coco_free_memory(curr_key); return best_value; } } coco_free_memory(curr_key); coco_warning("suite_biobj_get_best_value(): best value of %s could not be found; set to 1.0", key); return 1.0; } else { coco_error("suite_biobj_get_best_value(): indicator %s not supported", indicator_name); return 0; /* Never reached */ } coco_error("suite_biobj_get_best_value(): unexpected exception"); return 0; /* Never reached */ }
/** * @brief Formatted string duplication, with va_list arguments. */ static char *coco_vstrdupf(const char *str, va_list args) { static char buf[COCO_VSTRDUPF_BUFLEN]; long written; /* apparently args can only be used once, therefore * len = vsnprintf(NULL, 0, str, args) to find out the * length does not work. Therefore we use a buffer * which limits the max length. Longer strings should * never appear anyway, so this is rather a non-issue. */ #if 0 written = vsnprintf(buf, COCO_VSTRDUPF_BUFLEN - 2, str, args); if (written < 0) coco_error("coco_vstrdupf(): vsnprintf failed on '%s'", str); #else /* less safe alternative, if vsnprintf is not available */ assert(strlen(str) < COCO_VSTRDUPF_BUFLEN / 2 - 2); if (strlen(str) >= COCO_VSTRDUPF_BUFLEN / 2 - 2) coco_error("coco_vstrdupf(): string is too long"); written = vsprintf(buf, str, args); if (written < 0) coco_error("coco_vstrdupf(): vsprintf failed on '%s'", str); #endif if (written > COCO_VSTRDUPF_BUFLEN - 3) coco_error("coco_vstrdupf(): A suspiciously long string is tried to being duplicated '%s'", buf); return coco_strdup(buf); }
void *coco_allocate_memory(const size_t size) { void *data; if (size == 0) { coco_error("coco_allocate_memory() called with 0 size."); return NULL; /* never reached */ } data = malloc(size); if (data == NULL) coco_error("coco_allocate_memory() failed."); return data; }
/** * The archive always contains the two extreme solutions */ coco_archive_t *coco_archive(const char *suite_name, const size_t function, const size_t dimension, const size_t instance) { coco_archive_t *archive = coco_archive_allocate(); int output_precision = 15; coco_suite_t *suite; char *suite_instance = coco_strdupf("instances: %lu", (unsigned long) instance); char *suite_options = coco_strdupf("dimensions: %lu function_indices: %lu", (unsigned long) dimension, (unsigned long) function); coco_problem_t *problem; char *text; int update; suite = coco_suite(suite_name, suite_instance, suite_options); if (suite == NULL) { coco_error("coco_archive(): cannot create suite '%s'", suite_name); return NULL; /* Never reached */ } problem = coco_suite_get_next_problem(suite, NULL); if (problem == NULL) { coco_error("coco_archive(): cannot create problem f%02lu_i%02lu_d%02lu in suite '%s'", (unsigned long) function, (unsigned long) instance, (unsigned long) dimension, suite_name); return NULL; /* Never reached */ } /* Store the ideal and nadir points */ archive->ideal = coco_duplicate_vector(problem->best_value, 2); archive->nadir = coco_duplicate_vector(problem->nadir_value, 2); /* Add the extreme points to the archive */ text = coco_strdupf("0\t%.*e\t%.*e\n", output_precision, archive->nadir[0], output_precision, archive->ideal[1]); update = coco_archive_add_solution(archive, archive->nadir[0], archive->ideal[1], text); coco_free_memory(text); assert(update == 1); text = coco_strdupf("0\t%.*e\t%.*e\n", output_precision, archive->ideal[0], output_precision, archive->nadir[1]); update = coco_archive_add_solution(archive, archive->ideal[0], archive->nadir[1], text); coco_free_memory(text); assert(update == 1); archive->extreme1 = archive->tree->head; archive->extreme2 = archive->tree->tail; assert(archive->extreme1 != archive->extreme2); coco_free_memory(suite_instance); coco_free_memory(suite_options); coco_suite_free(suite); return archive; }
/** * @brief Creates and returns a string with removed characters between from and to. * * If you wish to remove characters from the beginning of the string, set from to "". * If you wish to remove characters until the end of the string, set to to "". * * The caller is responsible for freeing the allocated memory using coco_free_memory(). */ static char *coco_remove_from_string(const char *string, const char *from, const char *to) { char *result, *start, *stop; result = coco_strdup(string); if (strcmp(from, "") == 0) { /* Remove from the start */ start = result; } else start = strstr(result, from); if (strcmp(to, "") == 0) { /* Remove until the end */ stop = result + strlen(result); } else stop = strstr(result, to); if ((start == NULL) || (stop == NULL) || (stop < start)) { coco_error("coco_remove_from_string(): failed to remove characters between %s and %s from string %s", from, to, string); return NULL; /* Never reached */ } memmove(start, stop, strlen(stop) + 1); return result; }
/** * @brief Sets the instances associated with years for the bbob suite. */ static const char *suite_bbob_get_instances_by_year(const int year) { if (year == 2009) { return "1-5,1-5,1-5"; } else if (year == 2010) { return "1-15"; } else if (year == 2012) { return "1-5,21-30"; } else if (year == 2013) { return "1-5,31-40"; } else if (year == 2015) { return "1-5,41-50"; } else if (year == 2016) { return "1-5,51-60"; } else { coco_error("suite_bbob_get_instances_by_year(): year %d not defined for suite_bbob", year); return NULL; } }
/** * Evaluates and logs the given solution (as the coco_evaluate_function), but does not return the evaluated * value. * * @note None of the observers implements this function yet! * @note x must point to a correctly sized allocated memory region. * @param problem The given COCO problem. * @param x The decision vector. */ void coco_recommend_solution(coco_problem_t *problem, const double *x) { assert(problem != NULL); if (problem->recommend_solution == NULL) { coco_error("coco_recommend_solutions(): No recommend solution function implemented for problem %s", problem->problem_id); } problem->recommend_solution(problem, x); }
/** * @note None of the problems implement this function yet! * @note Both x and y must point to correctly sized allocated memory regions. * * @param problem The given COCO problem. * @param x The decision vector. * @param y The vector of constraints that is the result of the evaluation. */ void coco_evaluate_constraint(coco_problem_t *problem, const double *x, double *y) { /* implements a safer version of problem->evaluate(problem, x, y) */ assert(problem != NULL); if (problem->evaluate_constraint == NULL) { coco_error("coco_evaluate_constraint(): No constraint function implemented for problem %s", problem->problem_id); } problem->evaluate_constraint(problem, x, y); }
static void lnd_evaluate_function(coco_problem_t *self, const double *x, double *y) { _log_nondominating_t *data; data = coco_get_transform_data(self); coco_evaluate_function(coco_get_transform_inner_problem(self), x, y); data->number_of_evaluations++; /* Open logfile if it is not alread open */ if (data->logfile == NULL) { data->logfile = fopen(data->path, "w"); if (data->logfile == NULL) { char *buf; const char *error_format = "lnd_evaluate_function() failed to open log file '%s'."; size_t buffer_size = snprintf(NULL, 0, error_format, data->path); buf = (char *)coco_allocate_memory(buffer_size); snprintf(buf, buffer_size, error_format, data->path); coco_error(buf); coco_free_memory(buf); /* Never reached */ } fprintf(data->logfile, "# %zu variables | %zu objectives | func eval number\n", coco_get_number_of_variables(coco_get_transform_inner_problem(self)), coco_get_number_of_objectives(coco_get_transform_inner_problem(self))); /*********************************************************************/ /* TODO: Temporary put it here, to check later */ /* Allocate memory for the archive */ mo_archive = (struct mococo_solutions_archive *) malloc(1 * sizeof(struct mococo_solutions_archive)); mococo_allocate_archive(mo_archive, data->max_size_of_archive, coco_get_number_of_variables(coco_get_transform_inner_problem(self)), coco_get_number_of_objectives(coco_get_transform_inner_problem(self)), 1); /*********************************************************************/ } /********************************************************************************/ /* Finish evaluations of 1 single solution of the pop, with nObj objectives, * now update the archive with this newly evaluated solution and check its nondomination. */ mococo_push_to_archive(&x, &y, mo_archive, 1, data->number_of_evaluations); mococo_pareto_filtering(mo_archive); /***** TODO: IMPROVE THIS ROUTINE *****/ mococo_mark_updates(mo_archive, data->number_of_evaluations); /* Write out a line for this newly evaluated solution if it is nondominated */ // write main info to the log file for pfront for (size_t i=0; i < mo_archive->updatesize; i++) { entry = mo_archive->update[i]; for (size_t j=0; j < coco_get_number_of_variables(coco_get_transform_inner_problem(self)); j++) // all decision variables of a solution fprintf(data->logfile, "%13.10e\t", entry->var[j]); for (size_t k=0; k < coco_get_number_of_objectives(coco_get_transform_inner_problem(self)); k++) // all objective values of a solution fprintf(data->logfile, "%13.10e\t", entry->obj[k]); fprintf(data->logfile, "%zu", entry->birth); // its timestamp (FEval) fprintf(data->logfile, "\n"); // go to the next line for another solution } /********************************************************************************/ /* Flush output so that impatient users can see progress. */ fflush(data->logfile); }
/** * @brief Sets the instances associated with years for the bbob-biobj suite. */ static const char *suite_biobj_get_instances_by_year(const int year) { if (year == 2016) { return "1-10"; } else { coco_error("suite_biobj_get_instances_by_year(): year %d not defined for suite_biobj", year); return NULL; } }
/** * Error when trying to create the file "path" */ static void logger_bbob2009_error_io(FILE *path, int errnum) { char *buf; const char *error_format = "Error opening file: %s\n "; /* "bbob2009_logger_prepare() failed to open log file '%s'.";*/ size_t buffer_size = (size_t) snprintf(NULL, 0, error_format, path); /* to silence warning */ buf = (char *) coco_allocate_memory(buffer_size); snprintf(buf, buffer_size, error_format, strerror(errnum), path); coco_error(buf); coco_free_memory(buf); }
/** * Formatted printing of a problem ID, mimicking * sprintf(coco_problem_get_id(problem), id, ...) while taking care * of memory (de-)allocations. * */ void coco_problem_set_id(coco_problem_t *problem, const char *id, ...) { va_list args; va_start(args, id); coco_free_memory(problem->problem_id); problem->problem_id = coco_vstrdupf(id, args); va_end(args); if (!coco_problem_id_is_fine(problem->problem_id)) { coco_error("Problem id should only contain standard chars, not like '%s'", coco_problem_get_id(problem)); } }
/* * Shift all variables of ${inner_problem} by ${offset}. */ static coco_problem_t *f_transform_vars_shift(coco_problem_t *inner_problem, const double *offset, const int shift_bounds) { transform_vars_shift_data_t *data; coco_problem_t *self; if (shift_bounds) coco_error("shift_bounds not implemented."); data = coco_allocate_memory(sizeof(*data)); data->offset = coco_duplicate_vector(offset, inner_problem->number_of_variables); data->shifted_x = coco_allocate_vector(inner_problem->number_of_variables); self = coco_transformed_allocate(inner_problem, data, transform_vars_shift_free); self->evaluate_function = transform_vars_shift_evaluate; return self; }
static coco_problem_t *logger_bbob2009(coco_problem_t *inner_problem, const char *alg_name) { logger_bbob2009_t *data; coco_problem_t *self; data = coco_allocate_memory(sizeof(*data)); data->alg_name = coco_strdup(alg_name); if (bbob2009_logger_is_open) coco_error("The current bbob2009_logger (observer) must be closed before a new one is opened"); /* This is the name of the folder which happens to be the algName */ data->path = coco_strdup(alg_name); data->index_file = NULL; data->fdata_file = NULL; data->tdata_file = NULL; data->rdata_file = NULL; data->number_of_variables = inner_problem->number_of_variables; if (inner_problem->best_value == NULL) { /* coco_error("Optimal f value must be defined for each problem in order for the logger to work properly"); */ /* Setting the value to 0 results in the assertion y>=optimal_fvalue being susceptible to failure */ coco_warning("undefined optimal f value. Set to 0"); data->optimal_fvalue = 0; } else { data->optimal_fvalue = *(inner_problem->best_value); } bbob2009_raisedOptValWarning = 0; data->idx_f_trigger = INT_MAX; data->idx_t_trigger = 0; data->idx_tdim_trigger = 0; data->f_trigger = DBL_MAX; data->t_trigger = 0; data->number_of_evaluations = 0; data->best_solution = coco_allocate_vector(inner_problem->number_of_variables); /* TODO: the following inits are just to be in the safe side and * should eventually be removed. Some fields of the bbob2009_logger struct * might be useless */ data->function_id = coco_problem_get_suite_dep_function_id(inner_problem); data->instance_id = coco_problem_get_suite_dep_instance_id(inner_problem); data->written_last_eval = 1; data->last_fvalue = DBL_MAX; data->is_initialized = 0; self = coco_transformed_allocate(inner_problem, data, logger_bbob2009_free); self->evaluate_function = logger_bbob2009_evaluate; bbob2009_logger_is_open = 1; return self; }
/** * @brief Creates the transformation. */ static coco_problem_t *transform_vars_shift(coco_problem_t *inner_problem, const double *offset, const int shift_bounds) { transform_vars_shift_data_t *data; coco_problem_t *problem; size_t i; if (shift_bounds) coco_error("shift_bounds not implemented."); data = (transform_vars_shift_data_t *) coco_allocate_memory(sizeof(*data)); data->offset = coco_duplicate_vector(offset, inner_problem->number_of_variables); data->shifted_x = coco_allocate_vector(inner_problem->number_of_variables); problem = coco_problem_transformed_allocate(inner_problem, data, transform_vars_shift_free, "transform_vars_shift"); problem->evaluate_function = transform_vars_shift_evaluate; /* Compute best parameter */ for (i = 0; i < problem->number_of_variables; i++) { problem->best_parameter[i] += data->offset[i]; } return problem; }
/** * @brief Returns the first index where seq occurs in base and -1 if it doesn't. * * @note If there is an equivalent standard C function, this can/should be removed. */ static long coco_strfind(const char *base, const char *seq) { const size_t strlen_seq = strlen(seq); const size_t last_first_idx = strlen(base) - strlen(seq); size_t i, j; if (strlen(base) < strlen(seq)) return -1; for (i = 0; i <= last_first_idx; ++i) { if (base[i] == seq[0]) { for (j = 0; j < strlen_seq; ++j) { if (base[i + j] != seq[j]) break; } if (j == strlen_seq) { if (i > 1e9) coco_error("coco_strfind(): strange values observed i=%lu, j=%lu, strlen(base)=%lu", (unsigned long) i, (unsigned long) j, (unsigned long) strlen(base)); return (long) i; } } } return -1; }
/** * @brief Returns the problem from the toy suite that corresponds to the given parameters. * * @param suite The COCO suite. * @param function_idx Index of the function (starting from 0). * @param dimension_idx Index of the dimension (starting from 0). * @param instance_idx Index of the instance (starting from 0). * @return The problem that corresponds to the given parameters. */ static coco_problem_t *suite_toy_get_problem(coco_suite_t *suite, const size_t function_idx, const size_t dimension_idx, const size_t instance_idx) { coco_problem_t *problem = NULL; const size_t function = suite->functions[function_idx]; const size_t dimension = suite->dimensions[dimension_idx]; const size_t instance = suite->instances[instance_idx]; if (function == 1) { problem = f_sphere_allocate(dimension); } else if (function == 2) { problem = f_ellipsoid_allocate(dimension); } else if (function == 3) { problem = f_rastrigin_allocate(dimension); } else if (function == 4) { problem = f_bueche_rastrigin_allocate(dimension); } else if (function == 5) { double xopt[40] = { 5.0 }; problem = f_linear_slope_allocate(dimension, xopt); } else if (function == 6) { problem = f_rosenbrock_allocate(dimension); } else { coco_error("suite_toy_get_problem(): function %lu does not exist in this suite", function); return NULL; /* Never reached */ } problem->suite_dep_function = function; problem->suite_dep_instance = instance; problem->suite_dep_index = coco_suite_encode_problem_index(suite, function_idx, dimension_idx, instance_idx); return problem; }
/** * @brief Initializes the indicator with name indicator_name. * * Opens files for writing and resets counters. */ static logger_biobj_indicator_t *logger_biobj_indicator(const logger_biobj_data_t *logger, const coco_problem_t *problem, const char *indicator_name) { coco_observer_t *observer; observer_biobj_data_t *observer_biobj; logger_biobj_indicator_t *indicator; char *prefix, *file_name, *path_name; int info_file_exists = 0; indicator = (logger_biobj_indicator_t *) coco_allocate_memory(sizeof(*indicator)); observer = logger->observer; observer_biobj = (observer_biobj_data_t *) observer->data; indicator->name = coco_strdup(indicator_name); indicator->best_value = suite_biobj_get_best_value(indicator->name, problem->problem_id); indicator->next_target_id = 0; indicator->target_hit = 0; indicator->current_value = 0; indicator->additional_penalty = 0; indicator->overall_value = 0; /* Prepare the info file */ path_name = coco_allocate_string(COCO_PATH_MAX); memcpy(path_name, observer->result_folder, strlen(observer->result_folder) + 1); coco_create_directory(path_name); file_name = coco_strdupf("%s_%s.info", problem->problem_type, indicator_name); coco_join_path(path_name, COCO_PATH_MAX, file_name, NULL); info_file_exists = coco_file_exists(path_name); indicator->info_file = fopen(path_name, "a"); if (indicator->info_file == NULL) { coco_error("logger_biobj_indicator() failed to open file '%s'.", path_name); return NULL; /* Never reached */ } coco_free_memory(file_name); coco_free_memory(path_name); /* Prepare the tdat file */ path_name = coco_allocate_string(COCO_PATH_MAX); memcpy(path_name, observer->result_folder, strlen(observer->result_folder) + 1); coco_join_path(path_name, COCO_PATH_MAX, problem->problem_type, NULL); coco_create_directory(path_name); prefix = coco_remove_from_string(problem->problem_id, "_i", "_d"); file_name = coco_strdupf("%s_%s.tdat", prefix, indicator_name); coco_join_path(path_name, COCO_PATH_MAX, file_name, NULL); indicator->tdat_file = fopen(path_name, "a"); if (indicator->tdat_file == NULL) { coco_error("logger_biobj_indicator() failed to open file '%s'.", path_name); return NULL; /* Never reached */ } coco_free_memory(file_name); coco_free_memory(path_name); /* Prepare the dat file */ path_name = coco_allocate_string(COCO_PATH_MAX); memcpy(path_name, observer->result_folder, strlen(observer->result_folder) + 1); coco_join_path(path_name, COCO_PATH_MAX, problem->problem_type, NULL); coco_create_directory(path_name); file_name = coco_strdupf("%s_%s.dat", prefix, indicator_name); coco_join_path(path_name, COCO_PATH_MAX, file_name, NULL); indicator->dat_file = fopen(path_name, "a"); if (indicator->dat_file == NULL) { coco_error("logger_biobj_indicator() failed to open file '%s'.", path_name); return NULL; /* Never reached */ } /* Output header information to the info file */ if (!info_file_exists) { /* Output algorithm name */ fprintf(indicator->info_file, "algorithm = '%s', indicator = '%s', folder = '%s'\n%% %s", observer->algorithm_name, indicator_name, problem->problem_type, observer->algorithm_info); } if (observer_biobj->previous_function != problem->suite_dep_function) { fprintf(indicator->info_file, "\nfunction = %2lu, ", problem->suite_dep_function); fprintf(indicator->info_file, "dim = %2lu, ", problem->number_of_variables); fprintf(indicator->info_file, "%s", file_name); } coco_free_memory(prefix); coco_free_memory(file_name); coco_free_memory(path_name); /* Output header information to the dat file */ fprintf(indicator->dat_file, "%%\n%% index = %ld, name = %s\n", problem->suite_dep_index, problem->problem_name); fprintf(indicator->dat_file, "%% instance = %ld, reference value = %.*e\n", problem->suite_dep_instance, logger->precision_f, indicator->best_value); fprintf(indicator->dat_file, "%% function evaluation | indicator value | target hit\n"); /* Output header information to the tdat file */ fprintf(indicator->tdat_file, "%%\n%% index = %ld, name = %s\n", problem->suite_dep_index, problem->problem_name); fprintf(indicator->tdat_file, "%% instance = %ld, reference value = %.*e\n", problem->suite_dep_instance, logger->precision_f, indicator->best_value); fprintf(indicator->tdat_file, "%% function evaluation | indicator value\n"); return indicator; }
static coco_problem_t *f_gallagher_bbob_problem_allocate(const size_t function, const size_t dimension, const size_t instance, const long rseed, const size_t number_of_peaks, const char *problem_id_template, const char *problem_name_template) { f_gallagher_data_t *data; /* problem_name and best_parameter will be overwritten below */ coco_problem_t *problem = coco_problem_allocate_from_scalars("Gallagher function", f_gallagher_evaluate, f_gallagher_free, dimension, -5.0, 5.0, 0.0); const size_t peaks_21 = 21; const size_t peaks_101 = 101; double fopt; size_t i, j, k, *rperm; double maxcondition = 1000.; /* maxcondition1 satisfies the old code and the doc but seems wrong in that it is, with very high * probability, not the largest condition level!!! */ double maxcondition1 = 1000.; double *arrCondition; double fitvalues[2] = { 1.1, 9.1 }; /* Parameters for generating local optima. In the old code, they are different in f21 and f22 */ double b, c; data = coco_allocate_memory(sizeof(*data)); /* Allocate temporary storage and space for the rotation matrices */ data->number_of_peaks = number_of_peaks; data->xopt = coco_allocate_vector(dimension); data->rotation = bbob2009_allocate_matrix(dimension, dimension); data->x_local = bbob2009_allocate_matrix(dimension, number_of_peaks); data->arr_scales = bbob2009_allocate_matrix(number_of_peaks, dimension); if (number_of_peaks == peaks_101) { if (gallagher_peaks != NULL) coco_free_memory(gallagher_peaks); gallagher_peaks = coco_allocate_vector(peaks_101 * dimension); maxcondition1 = sqrt(maxcondition1); b = 10.; c = 5.; } else if (number_of_peaks == peaks_21) { if (gallagher_peaks != NULL) coco_free_memory(gallagher_peaks); gallagher_peaks = coco_allocate_vector(peaks_21 * dimension); b = 9.8; c = 4.9; } else { coco_error("f_gallagher(): '%lu' is a bad number of peaks", number_of_peaks); } data->rseed = rseed; bbob2009_compute_rotation(data->rotation, rseed, dimension); /* Initialize all the data of the inner problem */ bbob2009_unif(gallagher_peaks, number_of_peaks - 1, data->rseed); rperm = (size_t *) coco_allocate_memory((number_of_peaks - 1) * sizeof(size_t)); for (i = 0; i < number_of_peaks - 1; ++i) rperm[i] = i; qsort(rperm, number_of_peaks - 1, sizeof(size_t), f_gallagher_compare_doubles); /* Random permutation */ arrCondition = coco_allocate_vector(number_of_peaks); arrCondition[0] = maxcondition1; data->peak_values = coco_allocate_vector(number_of_peaks); data->peak_values[0] = 10; for (i = 1; i < number_of_peaks; ++i) { arrCondition[i] = pow(maxcondition, (double) (rperm[i - 1]) / ((double) (number_of_peaks - 2))); data->peak_values[i] = (double) (i - 1) / (double) (number_of_peaks - 2) * (fitvalues[1] - fitvalues[0]) + fitvalues[0]; } coco_free_memory(rperm); rperm = (size_t *) coco_allocate_memory(dimension * sizeof(size_t)); for (i = 0; i < number_of_peaks; ++i) { bbob2009_unif(gallagher_peaks, dimension, data->rseed + (long) (1000 * i)); for (j = 0; j < dimension; ++j) rperm[j] = j; qsort(rperm, dimension, sizeof(size_t), f_gallagher_compare_doubles); for (j = 0; j < dimension; ++j) { data->arr_scales[i][j] = pow(arrCondition[i], ((double) rperm[j]) / ((double) (dimension - 1)) - 0.5); } } coco_free_memory(rperm); bbob2009_unif(gallagher_peaks, dimension * number_of_peaks, data->rseed); for (i = 0; i < dimension; ++i) { data->xopt[i] = 0.8 * (b * gallagher_peaks[i] - c); problem->best_parameter[i] = 0.8 * (b * gallagher_peaks[i] - c); for (j = 0; j < number_of_peaks; ++j) { data->x_local[i][j] = 0.; for (k = 0; k < dimension; ++k) { data->x_local[i][j] += data->rotation[i][k] * (b * gallagher_peaks[j * dimension + k] - c); } if (j == 0) { data->x_local[i][j] *= 0.8; } } } coco_free_memory(arrCondition); problem->data = data; /* Compute best solution */ f_gallagher_evaluate(problem, problem->best_parameter, problem->best_value); fopt = bbob2009_compute_fopt(function, instance); problem = f_transform_obj_shift(problem, fopt); coco_problem_set_id(problem, problem_id_template, function, instance, dimension); coco_problem_set_name(problem, problem_name_template, function, instance, dimension); coco_problem_set_type(problem, "5-weakly-structured"); return problem; }
/** * @brief Creates and returns a BBOB problem without needing the actual bbob suite. * * Useful for other suites as well (see for example suite_biobj.c). */ static coco_problem_t *coco_get_bbob_problem(const size_t function, const size_t dimension, const size_t instance) { coco_problem_t *problem = NULL; const char *problem_id_template = "bbob_f%03lu_i%02lu_d%02lu"; const char *problem_name_template = "BBOB suite problem f%lu instance %lu in %luD"; const long rseed = (long) (function + 10000 * instance); const long rseed_3 = (long) (3 + 10000 * instance); const long rseed_17 = (long) (17 + 10000 * instance); if (function == 1) { problem = f_sphere_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 2) { problem = f_ellipsoid_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 3) { problem = f_rastrigin_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 4) { problem = f_bueche_rastrigin_bbob_problem_allocate(function, dimension, instance, rseed_3, problem_id_template, problem_name_template); } else if (function == 5) { problem = f_linear_slope_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 6) { problem = f_attractive_sector_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 7) { problem = f_step_ellipsoid_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 8) { problem = f_rosenbrock_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 9) { problem = f_rosenbrock_rotated_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 10) { problem = f_ellipsoid_rotated_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 11) { problem = f_discus_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 12) { problem = f_bent_cigar_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 13) { problem = f_sharp_ridge_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 14) { problem = f_different_powers_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 15) { problem = f_rastrigin_rotated_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 16) { problem = f_weierstrass_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 17) { problem = f_schaffers_bbob_problem_allocate(function, dimension, instance, rseed, 10, problem_id_template, problem_name_template); } else if (function == 18) { problem = f_schaffers_bbob_problem_allocate(function, dimension, instance, rseed_17, 1000, problem_id_template, problem_name_template); } else if (function == 19) { problem = f_griewank_rosenbrock_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 20) { problem = f_schwefel_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 21) { problem = f_gallagher_bbob_problem_allocate(function, dimension, instance, rseed, 101, problem_id_template, problem_name_template); } else if (function == 22) { problem = f_gallagher_bbob_problem_allocate(function, dimension, instance, rseed, 21, problem_id_template, problem_name_template); } else if (function == 23) { problem = f_katsuura_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else if (function == 24) { problem = f_lunacek_bi_rastrigin_bbob_problem_allocate(function, dimension, instance, rseed, problem_id_template, problem_name_template); } else { coco_error("get_bbob_problem(): cannot retrieve problem f%lu instance %lu in %luD", (unsigned long) function, (unsigned long) instance, (unsigned long) dimension); return NULL; /* Never reached */ } return problem; }
/** * @brief Updates the archive and buffer trees with the given node. * * Checks for domination and updates the archive tree and the values of the indicators if the given node is * not weakly dominated by existing nodes in the archive tree. This is where the main computation of * indicator values takes place. * * @return 1 if the update was performed and 0 otherwise. */ static int logger_biobj_tree_update(logger_biobj_data_t *logger, const coco_problem_t *problem, logger_biobj_avl_item_t *node_item) { avl_node_t *node, *next_node, *new_node; int trigger_update = 0; int dominance; size_t i; int previous_unavailable = 0; /* Find the first point that is not worse than the new point (NULL if such point does not exist) */ node = avl_item_search_right(logger->archive_tree, node_item, NULL); if (node == NULL) { /* The new point is an extremal point */ trigger_update = 1; next_node = logger->archive_tree->head; } else { dominance = mo_get_dominance(node_item->y, ((logger_biobj_avl_item_t*) node->item)->y, logger->number_of_objectives); if (dominance > -1) { trigger_update = 1; next_node = node->next; if (dominance == 1) { /* The new point dominates the next point, remove the next point */ if (logger->compute_indicators) { for (i = 0; i < OBSERVER_BIOBJ_NUMBER_OF_INDICATORS; i++) { logger->indicators[i]->current_value -= ((logger_biobj_avl_item_t*) node->item)->indicator_contribution[i]; } } avl_item_delete(logger->buffer_tree, node->item); avl_node_delete(logger->archive_tree, node); } } else { /* The new point is dominated, nothing more to do */ trigger_update = 0; } } if (!trigger_update) { logger_biobj_node_free(node_item, NULL); } else { /* Perform tree update */ while (next_node != NULL) { /* Check the dominance relation between the new node and the next node. There are only two possibilities: * dominance = 0: the new node and the next node are nondominated * dominance = 1: the new node dominates the next node */ node = next_node; dominance = mo_get_dominance(node_item->y, ((logger_biobj_avl_item_t*) node->item)->y, logger->number_of_objectives); if (dominance == 1) { /* The new point dominates the next point, remove the next point */ if (logger->compute_indicators) { for (i = 0; i < OBSERVER_BIOBJ_NUMBER_OF_INDICATORS; i++) { logger->indicators[i]->current_value -= ((logger_biobj_avl_item_t*) node->item)->indicator_contribution[i]; } } next_node = node->next; avl_item_delete(logger->buffer_tree, node->item); avl_node_delete(logger->archive_tree, node); } else { break; } } new_node = avl_item_insert(logger->archive_tree, node_item); avl_item_insert(logger->buffer_tree, node_item); if (logger->compute_indicators) { logger_biobj_check_if_within_ROI(problem, new_node); if (node_item->within_ROI) { /* Compute indicator value for new node and update the indicator value of the affected nodes */ logger_biobj_avl_item_t *next_item, *previous_item; if (new_node->next != NULL) { next_item = (logger_biobj_avl_item_t*) new_node->next->item; if (next_item->within_ROI) { for (i = 0; i < OBSERVER_BIOBJ_NUMBER_OF_INDICATORS; i++) { logger->indicators[i]->current_value -= next_item->indicator_contribution[i]; if (strcmp(logger->indicators[i]->name, "hyp") == 0) { next_item->indicator_contribution[i] = (node_item->y[0] - next_item->y[0]) / (problem->nadir_value[0] - problem->best_value[0]) * (problem->nadir_value[1] - next_item->y[1]) / (problem->nadir_value[1] - problem->best_value[1]); } else { coco_error( "logger_biobj_tree_update(): Indicator computation not implemented yet for indicator %s", logger->indicators[i]->name); } logger->indicators[i]->current_value += next_item->indicator_contribution[i]; } } } previous_unavailable = 0; if (new_node->prev != NULL) { previous_item = (logger_biobj_avl_item_t*) new_node->prev->item; if (previous_item->within_ROI) { for (i = 0; i < OBSERVER_BIOBJ_NUMBER_OF_INDICATORS; i++) { if (strcmp(logger->indicators[i]->name, "hyp") == 0) { node_item->indicator_contribution[i] = (previous_item->y[0] - node_item->y[0]) / (problem->nadir_value[0] - problem->best_value[0]) * (problem->nadir_value[1] - node_item->y[1]) / (problem->nadir_value[1] - problem->best_value[1]); } else { coco_error( "logger_biobj_tree_update(): Indicator computation not implemented yet for indicator %s", logger->indicators[i]->name); } } } else { previous_unavailable = 1; } } else { previous_unavailable = 1; } if (previous_unavailable) { /* Previous item does not exist or is out of ROI, use reference point instead */ for (i = 0; i < OBSERVER_BIOBJ_NUMBER_OF_INDICATORS; i++) { if (strcmp(logger->indicators[i]->name, "hyp") == 0) { node_item->indicator_contribution[i] = (problem->nadir_value[0] - node_item->y[0]) / (problem->nadir_value[0] - problem->best_value[0]) * (problem->nadir_value[1] - node_item->y[1]) / (problem->nadir_value[1] - problem->best_value[1]); } else { coco_error( "logger_biobj_tree_update(): Indicator computation not implemented yet for indicator %s", logger->indicators[i]->name); } } } for (i = 0; i < OBSERVER_BIOBJ_NUMBER_OF_INDICATORS; i++) { logger->indicators[i]->current_value += node_item->indicator_contribution[i]; } } } } return trigger_update; }
/** * @brief Evaluates the function, increases the number of evaluations and outputs information based on the * observer options. */ static void logger_biobj_evaluate(coco_problem_t *problem, const double *x, double *y) { logger_biobj_data_t *logger; logger_biobj_avl_item_t *node_item; logger_biobj_indicator_t *indicator; avl_node_t *solution; int update_performed; size_t i; logger = (logger_biobj_data_t *) coco_problem_transformed_get_data(problem); /* Evaluate function */ coco_evaluate_function(coco_problem_transformed_get_inner_problem(problem), x, y); logger->number_of_evaluations++; /* Update the archive with the new solution, if it is not dominated by or equal to existing solutions in * the archive */ node_item = logger_biobj_node_create(x, y, logger->number_of_evaluations, logger->number_of_variables, logger->number_of_objectives); update_performed = logger_biobj_tree_update(logger, coco_problem_transformed_get_inner_problem(problem), node_item); /* If the archive was updated and you need to log all nondominated solutions, output the new solution to * nondom_file */ if (update_performed && (logger->log_nondom_mode == LOG_NONDOM_ALL)) { logger_biobj_tree_output(logger->archive_file, logger->buffer_tree, logger->number_of_variables, logger->number_of_objectives, logger->log_vars, logger->precision_x, logger->precision_f); avl_tree_purge(logger->buffer_tree); /* Flush output so that impatient users can see progress. */ fflush(logger->archive_file); } /* Perform output to the: * - dat file, if the archive was updated and a new target was reached for an indicator; * - tdat file, if the number of evaluations matches one of the predefined numbers. * * Note that a target is reached when the (best_value - current_value) <= relative_target_value * The relative_target_value is a target for indicator difference, not indicator value! */ if (logger->compute_indicators) { for (i = 0; i < OBSERVER_BIOBJ_NUMBER_OF_INDICATORS; i++) { indicator = logger->indicators[i]; indicator->target_hit = 0; /* If the update was performed, update the overall indicator value */ if (update_performed) { /* Compute the overall_value of an indicator */ if (strcmp(indicator->name, "hyp") == 0) { if (indicator->current_value == 0) { /* The additional penalty for hypervolume is the minimal distance from the nondominated set to the ROI */ indicator->additional_penalty = DBL_MAX; if (logger->archive_tree->tail) { solution = logger->archive_tree->head; while (solution != NULL) { double distance = mo_get_distance_to_ROI(((logger_biobj_avl_item_t*) solution->item)->y, problem->best_value, problem->nadir_value, problem->number_of_objectives); indicator->additional_penalty = coco_double_min(indicator->additional_penalty, distance); solution = solution->next; } } assert(indicator->additional_penalty >= 0); } else { indicator->additional_penalty = 0; } indicator->overall_value = indicator->best_value - indicator->current_value + indicator->additional_penalty; } else { coco_error("logger_biobj_evaluate(): Indicator computation not implemented yet for indicator %s", indicator->name); } /* Check whether a target was hit */ while ((indicator->next_target_id < MO_NUMBER_OF_TARGETS) && (indicator->overall_value <= mo_relateive_target_values[indicator->next_target_id])) { /* A target was hit */ indicator->target_hit = 1; if (indicator->next_target_id + 1 < MO_NUMBER_OF_TARGETS) indicator->next_target_id++; else break; } } /* Log to the dat file if a target was hit */ if (indicator->target_hit) { fprintf(indicator->dat_file, "%lu\t%.*e\t%.*e\n", logger->number_of_evaluations, logger->precision_f, indicator->overall_value, logger->precision_f, mo_relateive_target_values[indicator->next_target_id - 1]); } /* Log to the tdat file if the number of evaluations matches one of the predefined numbers */ if (coco_observer_evaluation_to_log(logger->number_of_evaluations, logger->number_of_variables)) { fprintf(indicator->tdat_file, "%lu\t%.*e\n", logger->number_of_evaluations, logger->precision_f, indicator->overall_value); } } } }
/** * @brief Initializes the biobjective logger. */ static coco_problem_t *logger_biobj(coco_observer_t *observer, coco_problem_t *inner_problem) { coco_problem_t *problem; logger_biobj_data_t *logger_biobj; observer_biobj_data_t *observer_biobj; const char nondom_folder_name[] = "archive"; char *path_name, *file_name = NULL, *prefix; size_t i; if (inner_problem->number_of_objectives != 2) { coco_error("logger_biobj(): The bi-objective logger cannot log a problem with %d objective(s)", inner_problem->number_of_objectives); return NULL; /* Never reached. */ } logger_biobj = (logger_biobj_data_t *) coco_allocate_memory(sizeof(*logger_biobj)); logger_biobj->observer = observer; logger_biobj->number_of_evaluations = 0; logger_biobj->number_of_variables = inner_problem->number_of_variables; logger_biobj->number_of_objectives = inner_problem->number_of_objectives; logger_biobj->suite_dep_instance = inner_problem->suite_dep_instance; observer_biobj = (observer_biobj_data_t *) observer->data; /* Copy values from the observes that you might need even if they do not exist any more */ logger_biobj->log_nondom_mode = observer_biobj->log_nondom_mode; logger_biobj->compute_indicators = observer_biobj->compute_indicators; logger_biobj->precision_x = observer->precision_x; logger_biobj->precision_f = observer->precision_f; if (((observer_biobj->log_vars_mode == LOG_VARS_LOW_DIM) && (inner_problem->number_of_variables > 5)) || (observer_biobj->log_vars_mode == LOG_VARS_NEVER)) logger_biobj->log_vars = 0; else logger_biobj->log_vars = 1; /* Initialize logging of nondominated solutions into the archive file */ if (logger_biobj->log_nondom_mode != LOG_NONDOM_NONE) { /* Create the path to the file */ path_name = coco_allocate_string(COCO_PATH_MAX); memcpy(path_name, observer->result_folder, strlen(observer->result_folder) + 1); coco_join_path(path_name, COCO_PATH_MAX, nondom_folder_name, NULL); coco_create_directory(path_name); /* Construct file name */ prefix = coco_remove_from_string(inner_problem->problem_id, "_i", "_d"); if (logger_biobj->log_nondom_mode == LOG_NONDOM_ALL) file_name = coco_strdupf("%s_nondom_all.adat", prefix); else if (logger_biobj->log_nondom_mode == LOG_NONDOM_FINAL) file_name = coco_strdupf("%s_nondom_final.adat", prefix); coco_join_path(path_name, COCO_PATH_MAX, file_name, NULL); if (logger_biobj->log_nondom_mode != LOG_NONDOM_NONE) coco_free_memory(file_name); coco_free_memory(prefix); /* Open and initialize the archive file */ logger_biobj->archive_file = fopen(path_name, "a"); if (logger_biobj->archive_file == NULL) { coco_error("logger_biobj() failed to open file '%s'.", path_name); return NULL; /* Never reached */ } coco_free_memory(path_name); /* Output header information */ fprintf(logger_biobj->archive_file, "%% instance = %ld, name = %s\n", inner_problem->suite_dep_instance, inner_problem->problem_name); if (logger_biobj->log_vars) { fprintf(logger_biobj->archive_file, "%% function evaluation | %lu objectives | %lu variables\n", inner_problem->number_of_objectives, inner_problem->number_of_variables); } else { fprintf(logger_biobj->archive_file, "%% function evaluation | %lu objectives \n", inner_problem->number_of_objectives); } } /* Initialize the AVL trees */ logger_biobj->archive_tree = avl_tree_construct((avl_compare_t) avl_tree_compare_by_last_objective, (avl_free_t) logger_biobj_node_free); logger_biobj->buffer_tree = avl_tree_construct((avl_compare_t) avl_tree_compare_by_time_stamp, NULL); problem = coco_problem_transformed_allocate(inner_problem, logger_biobj, logger_biobj_free); problem->evaluate_function = logger_biobj_evaluate; /* Initialize the indicators */ if (logger_biobj->compute_indicators) { for (i = 0; i < OBSERVER_BIOBJ_NUMBER_OF_INDICATORS; i++) logger_biobj->indicators[i] = logger_biobj_indicator(logger_biobj, inner_problem, observer_biobj_indicators[i]); observer_biobj->previous_function = (long) inner_problem->suite_dep_function; } return problem; }
/** * @brief Computes the instance number of the second problem/objective so that the resulting bi-objective * problem has more than a single optimal solution. * * Starts by setting instance2 = instance1 + 1 and increases this number until an appropriate instance has * been found (or until a maximum number of tries has been reached, in which case it throws a coco_error). * An appropriate instance is the one for which the resulting bi-objective problem (in any considered * dimension) has the ideal and nadir points apart enough in the objective space and the extreme optimal * points apart enough in the decision space. When the instance has been found, it is output through * coco_warning, so that the user can see it and eventually manually add it to suite_biobj_instances. */ static size_t suite_biobj_get_new_instance(coco_suite_t *suite, const size_t instance, const size_t instance1, const size_t num_bbob_functions, const size_t *bbob_functions) { size_t instance2 = 0; size_t num_tries = 0; const size_t max_tries = 1000; const double apart_enough = 1e-4; int appropriate_instance_found = 0, break_search, warning_produced = 0; coco_problem_t *problem1, *problem2, *problem = NULL; size_t d, f1, f2, i; size_t function1, function2, dimension; double norm; suite_biobj_t *data; assert(suite->data); data = (suite_biobj_t *) suite->data; while ((!appropriate_instance_found) && (num_tries < max_tries)) { num_tries++; instance2 = instance1 + num_tries; break_search = 0; /* An instance is "appropriate" if the ideal and nadir points in the objective space and the two * extreme optimal points in the decisions space are apart enough for all problems (all dimensions * and function combinations); therefore iterate over all dimensions and function combinations */ for (f1 = 0; (f1 < num_bbob_functions) && !break_search; f1++) { function1 = bbob_functions[f1]; for (f2 = f1; (f2 < num_bbob_functions) && !break_search; f2++) { function2 = bbob_functions[f2]; for (d = 0; (d < suite->number_of_dimensions) && !break_search; d++) { dimension = suite->dimensions[d]; if (dimension == 0) { if (!warning_produced) coco_warning("suite_biobj_get_new_instance(): remove filtering of dimensions to get generally acceptable instances!"); warning_produced = 1; continue; } problem1 = coco_get_bbob_problem(function1, dimension, instance1); problem2 = coco_get_bbob_problem(function2, dimension, instance2); if (problem) { coco_problem_stacked_free(problem); problem = NULL; } problem = coco_problem_stacked_allocate(problem1, problem2); /* Check whether the ideal and nadir points are too close in the objective space */ norm = mo_get_norm(problem->best_value, problem->nadir_value, 2); if (norm < 1e-1) { /* TODO How to set this value in a sensible manner? */ coco_debug( "suite_biobj_get_new_instance(): The ideal and nadir points of %s are too close in the objective space", problem->problem_id); coco_debug("norm = %e, ideal = %e\t%e, nadir = %e\t%e", norm, problem->best_value[0], problem->best_value[1], problem->nadir_value[0], problem->nadir_value[1]); break_search = 1; } /* Check whether the extreme optimal points are too close in the decision space */ norm = mo_get_norm(problem1->best_parameter, problem2->best_parameter, problem->number_of_variables); if (norm < apart_enough) { coco_debug( "suite_biobj_get_new_instance(): The extremal optimal points of %s are too close in the decision space", problem->problem_id); coco_debug("norm = %e", norm); break_search = 1; } } } } /* Clean up */ if (problem) { coco_problem_stacked_free(problem); problem = NULL; } if (break_search) { /* The search was broken, continue with next instance2 */ continue; } else { /* An appropriate instance was found */ appropriate_instance_found = 1; coco_info("suite_biobj_set_new_instance(): Instance %lu created from instances %lu and %lu", instance, instance1, instance2); /* Save the instance to new_instances */ for (i = 0; i < data->max_new_instances; i++) { if (data->new_instances[i][0] == 0) { data->new_instances[i][0] = instance; data->new_instances[i][1] = instance1; data->new_instances[i][2] = instance2; break; }; } } } if (!appropriate_instance_found) { coco_error("suite_biobj_get_new_instance(): Could not find suitable instance %lu in $lu tries", instance, num_tries); return 0; /* Never reached */ } return instance2; }