/** * @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; }
/** * Currently, three observers are supported: * - "bbob" is the observer for single-objective (both noisy and noiseless) problems with known optima, which * creates *.info, *.dat, *.tdat and *.rdat files and logs the distance to the optimum. * - "bbob-biobj" is the observer for bi-objective problems, which creates *.info and *.dat files for the * given indicators, as well as an archive folder with *.dat files containing nondominated solutions. * - "toy" is a simple observer that logs when a target has been hit. * * @param observer_name A string containing the name of the observer. Currently supported observer names are * "bbob", "bbob-biobj", "toy". "no_observer", "" or NULL return NULL. * @param observer_options A string of pairs "key: value" used to pass the options to the observer. Some * observer options are general, while others are specific to some observers. Here we list only the general * options, see observer_bbob, observer_biobj and observer_toy for options of the specific observers. * - "result_folder: NAME" determines the output folder. If the folder with the given name already exists, * first NAME_001 will be tried, then NAME_002 and so on. The default value is "results". * - "algorithm_name: NAME", where NAME is a short name of the algorithm that will be used in plots (no * spaces are allowed). The default value is "ALG". * - "algorithm_info: STRING" stores the description of the algorithm. If it contains spaces, it must be * surrounded by double quotes. The default value is "" (no description). * - "precision_x: VALUE" defines the precision used when outputting variables and corresponds to the number * of digits to be printed after the decimal point. The default value is 8. * - precision_f: VALUE defines the precision used when outputting f values and corresponds to the number of * digits to be printed after the decimal point. The default value is 15. * @return The constructed observer object or NULL if observer_name equals NULL, "" or "no_observer". */ coco_observer_t *coco_observer(const char *observer_name, const char *observer_options) { coco_observer_t *observer; char *result_folder, *algorithm_name, *algorithm_info; int precision_x, precision_f; if (0 == strcmp(observer_name, "no_observer")) { return NULL; } else if (strlen(observer_name) == 0) { coco_warning("Empty observer_name has no effect. To prevent this warning use 'no_observer' instead"); return NULL; } result_folder = (char *) coco_allocate_memory(COCO_PATH_MAX); algorithm_name = (char *) coco_allocate_memory(COCO_PATH_MAX); algorithm_info = (char *) coco_allocate_memory(5 * COCO_PATH_MAX); /* Read result_folder, algorithm_name and algorithm_info from the observer_options and use * them to initialize the observer */ if (coco_options_read_string(observer_options, "result_folder", result_folder) == 0) { strcpy(result_folder, "exdata-default"); } coco_create_unique_path(&result_folder); coco_info("Results will be output to folder %s", result_folder); if (coco_options_read_string(observer_options, "algorithm_name", algorithm_name) == 0) { strcpy(algorithm_name, "ALG"); } if (coco_options_read_string(observer_options, "algorithm_info", algorithm_info) == 0) { strcpy(algorithm_info, ""); } precision_x = 8; if (coco_options_read_int(observer_options, "precision_x", &precision_x) != 0) { if ((precision_x < 1) || (precision_x > 32)) precision_x = 8; } precision_f = 15; if (coco_options_read_int(observer_options, "precision_f", &precision_f) != 0) { if ((precision_f < 1) || (precision_f > 32)) precision_f = 15; } observer = coco_observer_allocate(result_folder, algorithm_name, algorithm_info, precision_x, precision_f); coco_free_memory(result_folder); coco_free_memory(algorithm_name); coco_free_memory(algorithm_info); /* Here each observer must have an entry */ if (0 == strcmp(observer_name, "toy")) { observer_toy(observer, observer_options); } else if (0 == strcmp(observer_name, "bbob")) { observer_bbob(observer, observer_options); } else if (0 == strcmp(observer_name, "bbob-biobj")) { observer_biobj(observer, observer_options); } else { coco_warning("Unknown observer!"); return NULL; } return observer; }