/** * @brief Creates a rounded normalized version of the given solution w.r.t. the given ROI. * * If the solution seems to be better than the extremes it is corrected (2 objectives are assumed). * The caller is responsible for freeing the allocated memory using coco_free_memory(). */ static double *mo_normalize(const double *y, const double *ideal, const double *nadir, const size_t num_obj) { size_t i; double *normalized_y = coco_allocate_vector(num_obj); for (i = 0; i < num_obj; i++) { assert((nadir[i] - ideal[i]) > mo_discretization); normalized_y[i] = (y[i] - ideal[i]) / (nadir[i] - ideal[i]); normalized_y[i] = coco_double_round(normalized_y[i] / mo_discretization) * mo_discretization; if (normalized_y[i] < 0) { coco_debug("Adjusting %.15e to %.15e", y[i], ideal[i]); normalized_y[i] = 0; } } for (i = 0; i < num_obj; i++) { assert(num_obj == 2); if (coco_double_almost_equal(normalized_y[i], 0, mo_precision) && (normalized_y[1-i] < 1)) { coco_debug("Adjusting %.15e to %.15e", y[1-i], nadir[1-i]); normalized_y[1-i] = 1; } } return normalized_y; }
/** * @brief Creates the transformation. */ static coco_problem_t *transform_vars_affine(coco_problem_t *inner_problem, const double *M, const double *b, const size_t number_of_variables) { /* * TODO: * - Calculate new smallest/largest values of interest? * - Resize bounds vectors if input and output dimensions do not match */ coco_problem_t *problem; transform_vars_affine_data_t *data; size_t entries_in_M; entries_in_M = inner_problem->number_of_variables * number_of_variables; data = (transform_vars_affine_data_t *) coco_allocate_memory(sizeof(*data)); data->M = coco_duplicate_vector(M, entries_in_M); data->b = coco_duplicate_vector(b, inner_problem->number_of_variables); data->x = coco_allocate_vector(inner_problem->number_of_variables); problem = coco_problem_transformed_allocate(inner_problem, data, transform_vars_affine_free, "transform_vars_affine"); problem->evaluate_function = transform_vars_affine_evaluate; if (coco_problem_best_parameter_not_zero(inner_problem)) { coco_debug("transform_vars_affine(): 'best_parameter' not updated, set to NAN"); coco_vector_set_to_nan(inner_problem->best_parameter, inner_problem->number_of_variables); } 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; }