diff --git a/c/include/prima/prima.h b/c/include/prima/prima.h index bc8ce3c729..6a041816d8 100644 --- a/c/include/prima/prima.h +++ b/c/include/prima/prima.h @@ -245,6 +245,9 @@ int prima_init_options(prima_options_t *const options); // Structure to hold the result +// prima_minimize will allocate the memory for x and nlconstr (if needed), +// and as such the user is expected to free the memory using prima_free_result +// once they are done using the contents of the result (or have saved the contents). typedef struct { // x: returned point @@ -277,11 +280,14 @@ int prima_free_result(prima_result_t *const result); /* - * The function that does the minimization using a PRIMA solver - * algorithm : optimization algorithm (see prima_algorithm) - * problem : optimization problem (see prima_problem) - * options : optimization options (see prima_options) - * result : optimization result (see prima_result) + * The function that does the minimization using a PRIMA solver. + * After using (or saving) the result, the user is expected to call + * prima_free_result, regardless of the return value of prima_minimize, + * in order to avoid memory leaks. + * algorithm : optimization algorithm (see prima_algorithm_t) + * problem : optimization problem (see prima_problem_t) + * options : optimization options (see prima_options_t) + * result : optimization result (see prima_result_t) * return : see prima_rc_t enum for return codes */ PRIMAC_API diff --git a/c/prima.c b/c/prima.c index 8cea9e7c78..ce16e276da 100644 --- a/c/prima.c +++ b/c/prima.c @@ -93,32 +93,12 @@ int prima_init_result(prima_result_t *const result, const prima_problem_t proble memset(result, 0, sizeof(prima_result_t)); - // x: returned point - result->x = (double*)malloc(problem.n * sizeof(double)); - if (!result->x) - return PRIMA_MEMORY_ALLOCATION_FAILS; - for (int i = 0; i < problem.n; i++) - result->x[i] = problem.x0[i]; - // f: objective function value at the returned point result->f = NAN; // cstrv: constraint violation at the returned point (COBYLA and LINCOA only) result->cstrv = NAN; - // nlconstr: nonlinear constraint values at the returned point, of size m_nlcon (COBYLA only) - if (problem.m_nlcon <= 0) - result->nlconstr = NULL; - else { - result->nlconstr = (double*)malloc(problem.m_nlcon * sizeof(double)); - if (!result->nlconstr) { - free(result->x); - return PRIMA_MEMORY_ALLOCATION_FAILS; - } - for (int i = 0; i < problem.m_nlcon; i++) - result->nlconstr[i] = NAN; - } - // nf: number of function evaluations result->nf = INT_MIN; @@ -128,6 +108,22 @@ int prima_init_result(prima_result_t *const result, const prima_problem_t proble // message: exit message result->message = NULL; + // x: returned point + result->x = (double*)malloc(problem.n * sizeof(double)); + if (!result->x) + return PRIMA_MEMORY_ALLOCATION_FAILS; + for (int i = 0; i < problem.n; i++) + result->x[i] = NAN; + + // nlconstr: nonlinear constraint values at the returned point, of size m_nlcon (COBYLA only) + result->nlconstr = (double*)malloc(problem.m_nlcon * sizeof(double)); + if (!result->nlconstr) { + free(result->x); + return PRIMA_MEMORY_ALLOCATION_FAILS; + } + for (int i = 0; i < problem.m_nlcon; i++) + result->nlconstr[i] = NAN; + return 0; } @@ -238,12 +234,19 @@ int prima_minimize(const prima_algorithm_t algorithm, const prima_problem_t prob { int use_constr = (algorithm == PRIMA_COBYLA); - int info = prima_check_problem(problem, use_constr, algorithm); + int info = prima_init_result(result, problem); if (info == 0) - info = prima_init_result(result, problem); + info = prima_check_problem(problem, use_constr, algorithm); if (info == 0) { + // We copy x0 into result->x only after prima_check_problem has succeeded, + // so that if prima_check_problem failed, result->x will not contained a + // seemingly valid value. + for (int i = 0; i < problem.n; i++) { + result->x[i] = problem.x0[i]; + } + switch (algorithm) { case PRIMA_BOBYQA: bobyqa_c(problem.calfun, options.data, problem.n, result->x, &(result->f), problem.xl, problem.xu, &(result->nf), options.rhobeg, options.rhoend, options.ftarget, options.maxfun, options.npt, options.iprint, options.callback, &info); @@ -275,10 +278,10 @@ int prima_minimize(const prima_algorithm_t algorithm, const prima_problem_t prob default: return PRIMA_INVALID_INPUT; } - - result->status = info; - result->message = prima_get_rc_string(info); } + result->status = info; + result->message = prima_get_rc_string(info); + return info; }