From 5cac37602dfa44e74cbff061a0a5817e52596a88 Mon Sep 17 00:00:00 2001 From: aitap Date: Tue, 23 Apr 2019 23:48:06 +0300 Subject: [PATCH 1/9] do not allocate xtol_abs unless needed As discussed in #183, it is beneficial to avoid allocating potentially huge buffers of size `n` unless `x`-tolerance criteria are used. --- src/api/options.c | 32 +++++++++++++++++++++++--------- src/util/stop.c | 3 +++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/api/options.c b/src/api/options.c index c917977c..703e11ba 100644 --- a/src/api/options.c +++ b/src/api/options.c @@ -111,12 +111,8 @@ nlopt_opt NLOPT_STDCALL nlopt_create(nlopt_algorithm algorithm, unsigned n) opt->ub = (double *) calloc(n, sizeof(double)); if (!opt->ub) goto oom; - opt->xtol_abs = (double *) calloc(n, sizeof(double)); - if (!opt->xtol_abs) - goto oom; nlopt_set_lower_bounds1(opt, -HUGE_VAL); nlopt_set_upper_bounds1(opt, +HUGE_VAL); - nlopt_set_xtol_abs1(opt, 0.0); } } @@ -156,9 +152,11 @@ nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt) nopt->ub = (double *) malloc(sizeof(double) * (opt->n)); if (!opt->ub) goto oom; - nopt->xtol_abs = (double *) malloc(sizeof(double) * (opt->n)); - if (!opt->xtol_abs) - goto oom; + if (opt->xtol_abs) { + nopt->xtol_abs = (double *) malloc(sizeof(double) * (opt->n)); + if (!opt->xtol_abs) + goto oom; + } if (opt->x_weights) { nopt->x_weights = (double *) malloc(sizeof(double) * (opt->n)); if (!opt->x_weights) @@ -168,7 +166,9 @@ nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt) memcpy(nopt->lb, opt->lb, sizeof(double) * (opt->n)); memcpy(nopt->ub, opt->ub, sizeof(double) * (opt->n)); - memcpy(nopt->xtol_abs, opt->xtol_abs, sizeof(double) * (opt->n)); + if (opt->xtol_abs) { + memcpy(nopt->xtol_abs, opt->xtol_abs, sizeof(double) * (opt->n)); + } } if (opt->m) { @@ -612,6 +612,10 @@ GETSET(ftol_rel, double, ftol_rel) GETSET(ftol_abs, double, ftol_abs) GETSET(xto { if (opt) { nlopt_unset_errmsg(opt); + if (!opt->xtol_abs && opt->n > 0) { + opt->xtol_abs = (double *) calloc(opt->n, sizeof(double)); + if (!opt->xtol_abs) return NLOPT_OUT_OF_MEMORY; + } memcpy(opt->xtol_abs, xtol_abs, opt->n * sizeof(double)); return NLOPT_SUCCESS; } @@ -623,6 +627,10 @@ nlopt_result NLOPT_STDCALL nlopt_set_xtol_abs1(nlopt_opt opt, double xtol_abs) if (opt) { unsigned i; nlopt_unset_errmsg(opt); + if (!opt->xtol_abs && opt->n > 0) { + opt->xtol_abs = (double *) calloc(opt->n, sizeof(double)); + if (!opt->xtol_abs) return NLOPT_OUT_OF_MEMORY; + } for (i = 0; i < opt->n; ++i) opt->xtol_abs[i] = xtol_abs; return NLOPT_SUCCESS; @@ -634,7 +642,13 @@ nlopt_result NLOPT_STDCALL nlopt_get_xtol_abs(const nlopt_opt opt, double *xtol_ { nlopt_unset_errmsg(opt); if (opt && (opt->n == 0 || xtol_abs)) { - memcpy(xtol_abs, opt->xtol_abs, opt->n * sizeof(double)); + if (opt->xtol_abs) { + memcpy(xtol_abs, opt->xtol_abs, sizeof(double) * (opt->n)); + } else { + unsigned i; + for (i = 0; i < opt->n; ++i) + xtol_abs[i] = 0; + } return NLOPT_SUCCESS; } return NLOPT_INVALID_ARGS; diff --git a/src/util/stop.c b/src/util/stop.c index 1ba32eea..bf21c38e 100644 --- a/src/util/stop.c +++ b/src/util/stop.c @@ -100,6 +100,7 @@ int nlopt_stop_x(const nlopt_stopping * s, const double *x, const double *oldx) unsigned i; if (diff_norm(s->n, x, oldx, s->x_weights, NULL, NULL) < s->xtol_rel * vector_norm(s->n, x, s->x_weights, NULL, NULL)) return 1; + if (!s->xtol_abs) return 0; for (i = 0; i < s->n; ++i) if (fabs(x[i] - oldx[i]) >= s->xtol_abs[i]) return 0; @@ -111,6 +112,7 @@ int nlopt_stop_dx(const nlopt_stopping * s, const double *x, const double *dx) unsigned i; if (vector_norm(s->n, dx, s->x_weights, NULL, NULL) < s->xtol_rel * vector_norm(s->n, x, s->x_weights, NULL, NULL)) return 1; + if (!s->xtol_abs) return 0; for (i = 0; i < s->n; ++i) if (fabs(dx[i]) >= s->xtol_abs[i]) return 0; @@ -124,6 +126,7 @@ int nlopt_stop_xs(const nlopt_stopping * s, const double *xs, const double *oldx unsigned i; if (diff_norm(s->n, xs, oldxs, s->x_weights, scale_min, scale_max) < s->xtol_rel * vector_norm(s->n, xs, s->x_weights, scale_min, scale_max)) return 1; + if (!s->xtol_abs) return 0; for (i = 0; i < s->n; ++i) if (fabs(sc(xs[i], scale_min[i], scale_max[i]) - sc(oldxs[i], scale_min[i], scale_max[i])) >= s->xtol_abs[i]) return 0; From 8d5f2721db1a17ec4177b49625cbed926120b3a5 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Fri, 26 Apr 2019 15:02:11 +0300 Subject: [PATCH 2/9] bobyqa: handle xtol_abs == NULL --- src/algs/bobyqa/bobyqa.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/algs/bobyqa/bobyqa.c b/src/algs/bobyqa/bobyqa.c index 04ef89da..32204210 100644 --- a/src/algs/bobyqa/bobyqa.c +++ b/src/algs/bobyqa/bobyqa.c @@ -3123,9 +3123,11 @@ nlopt_result bobyqa(int n, int npt, double *x, /* SGJ, 2009: compute rhoend from NLopt stop info */ rhoend = stop->xtol_rel * (rhobeg); - for (j = 0; j < n; ++j) - if (rhoend < stop->xtol_abs[j] / fabs(s[j])) - rhoend = stop->xtol_abs[j] / fabs(s[j]); + if (stop->xtol_abs) { + for (j = 0; j < n; ++j) + if (rhoend < stop->xtol_abs[j] / fabs(s[j])) + rhoend = stop->xtol_abs[j] / fabs(s[j]); + } /* This subroutine seeks the least value of a function of many variables, */ From 28b9825801380a4ac208e20b1f9de5ad37d4ca00 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Fri, 26 Apr 2019 15:10:34 +0300 Subject: [PATCH 3/9] cdirect: handle xtol_abs == NULL --- src/algs/cdirect/cdirect.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/algs/cdirect/cdirect.c b/src/algs/cdirect/cdirect.c index d4d1cd50..de0337f7 100644 --- a/src/algs/cdirect/cdirect.c +++ b/src/algs/cdirect/cdirect.c @@ -383,7 +383,7 @@ static int small(double *w, params *p) { int i; for (i = 0; i < p->n; ++i) - if (w[i] > p->stop->xtol_abs[i] && + if (w[i] > (p->stop->xtol_abs ? p->stop->xtol_abs[i] : 0) && w[i] > (p->ub[i] - p->lb[i]) * p->stop->xtol_rel) return 0; return 1; @@ -575,21 +575,24 @@ nlopt_result cdirect(int n, nlopt_func f, void *f_data, { cdirect_uf_data d; nlopt_result ret; - const double *xtol_abs_save; + const double *xtol_abs_save = NULL; int i; d.f = f; d.f_data = f_data; d.lb = lb; d.ub = ub; - d.x = (double *) malloc(sizeof(double) * n*4); + d.x = (double *) malloc(sizeof(double) * n * (stop->xtol_abs ? 4 : 3)); if (!d.x) return NLOPT_OUT_OF_MEMORY; for (i = 0; i < n; ++i) { x[i] = (x[i] - lb[i]) / (ub[i] - lb[i]); d.x[n+i] = 0; d.x[2*n+i] = 1; - d.x[3*n+i] = stop->xtol_abs[i] / (ub[i] - lb[i]); } - xtol_abs_save = stop->xtol_abs; - stop->xtol_abs = d.x + 3*n; + if (stop->xtol_abs) { + for (i = 0; i < n; ++i) + d.x[3*n+i] = stop->xtol_abs[i] / (ub[i] - lb[i]); + xtol_abs_save = stop->xtol_abs; + stop->xtol_abs = d.x + 3*n; + } ret = cdirect_unscaled(n, cdirect_uf, &d, d.x+n, d.x+2*n, x, minf, stop, magic_eps, which_alg); stop->xtol_abs = xtol_abs_save; From 20f9398c54339a5e63f4f796bb8870c4ce15acae Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Fri, 26 Apr 2019 18:04:55 +0300 Subject: [PATCH 4/9] cdirect/hybrid: handle xtol_abs == NULL --- src/algs/cdirect/hybrid.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/algs/cdirect/hybrid.c b/src/algs/cdirect/hybrid.c index 1bfb0b60..3900b320 100644 --- a/src/algs/cdirect/hybrid.c +++ b/src/algs/cdirect/hybrid.c @@ -152,7 +152,7 @@ static nlopt_result divide_largest(params *p) /* check xtol */ for (i = 0; i < n; ++i) if (w[i] > p->stop->xtol_rel * (ub[i] - lb[i]) - && w[i] > p->stop->xtol_abs[i]) + && w[i] > (p->stop->xtol_abs ? p->stop->xtol_abs[i] : 0)) break; if (i == n) return NLOPT_XTOL_REACHED; @@ -316,21 +316,24 @@ nlopt_result cdirect_hybrid(int n, nlopt_func f, void *f_data, { cdirect_uf_data d; nlopt_result ret; - const double *xtol_abs_save; + const double *xtol_abs_save = NULL; int i; d.f = f; d.f_data = f_data; d.lb = lb; d.ub = ub; - d.x = (double *) malloc(sizeof(double) * n*4); + d.x = (double *) malloc(sizeof(double) * n * (stop->xtol_abs ? 4 : 3)); if (!d.x) return NLOPT_OUT_OF_MEMORY; for (i = 0; i < n; ++i) { x[i] = (x[i] - lb[i]) / (ub[i] - lb[i]); d.x[n+i] = 0; d.x[2*n+i] = 1; - d.x[3*n+i] = stop->xtol_abs[i] / (ub[i] - lb[i]); } - xtol_abs_save = stop->xtol_abs; - stop->xtol_abs = d.x + 3*n; + if (stop->xtol_abs) { + for (i = 0; i < n; ++i) + d.x[3*n+i] = stop->xtol_abs[i] / (ub[i] - lb[i]); + xtol_abs_save = stop->xtol_abs; + stop->xtol_abs = d.x + 3*n; + } ret = cdirect_hybrid_unscaled(n, cdirect_uf, &d, d.x+n, d.x+2*n, x, minf, stop, local_alg, local_maxeval, randomized_div); From c202f42695b1dbe6b6dae5e362664ca6b034b679 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Fri, 26 Apr 2019 18:06:12 +0300 Subject: [PATCH 5/9] cobyla: handle xtol_abs == NULL --- src/algs/cobyla/cobyla.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/algs/cobyla/cobyla.c b/src/algs/cobyla/cobyla.c index 012bd009..6dc7e625 100644 --- a/src/algs/cobyla/cobyla.c +++ b/src/algs/cobyla/cobyla.c @@ -219,9 +219,10 @@ nlopt_result cobyla_minimize(unsigned n, nlopt_func f, void *f_data, /* SGJ, 2008: compute rhoend from NLopt stop info */ rhobeg = fabs(dx[0] / s.scale[0]); rhoend = stop->xtol_rel * (rhobeg); - for (j = 0; j < n; ++j) - if (rhoend < stop->xtol_abs[j] / fabs(s.scale[j])) - rhoend = stop->xtol_abs[j] / fabs(s.scale[j]); + if (stop->xtol_abs) + for (j = 0; j < n; ++j) + if (rhoend < stop->xtol_abs[j] / fabs(s.scale[j])) + rhoend = stop->xtol_abs[j] / fabs(s.scale[j]); /* each equality constraint gives two inequality constraints */ m = nlopt_count_constraints(m, fc) + 2 * nlopt_count_constraints(p, h); From 85f587d90cbd6487075f7dac8a85229ff8dde087 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Fri, 26 Apr 2019 18:43:39 +0300 Subject: [PATCH 6/9] sbplx: handle xtol_abs == NULL --- src/algs/neldermead/sbplx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algs/neldermead/sbplx.c b/src/algs/neldermead/sbplx.c index 9286dc6a..b748e308 100644 --- a/src/algs/neldermead/sbplx.c +++ b/src/algs/neldermead/sbplx.c @@ -195,7 +195,7 @@ nlopt_result sbplx_minimize(int n, nlopt_func f, void *f_data, the step size is too large (in early iterations), the inner Nelder-Mead may not make much progress */ for (j = 0; j < n; ++j) - if (fabs(xstep[j]) * psi > stop->xtol_abs[j] + if (fabs(xstep[j]) * psi > (stop->xtol_abs ? stop->xtol_abs[j] : 0) && fabs(xstep[j]) * psi > stop->xtol_rel * fabs(x[j])) break; if (j == n) { From 73514f5baf9a6bbb0c878c5ff0d4e7c0500dc386 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Fri, 26 Apr 2019 18:44:08 +0300 Subject: [PATCH 7/9] newuoa: handle xtol_abs == NULL --- src/algs/newuoa/newuoa.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/algs/newuoa/newuoa.c b/src/algs/newuoa/newuoa.c index a27017b8..c53cdccf 100644 --- a/src/algs/newuoa/newuoa.c +++ b/src/algs/newuoa/newuoa.c @@ -1626,9 +1626,10 @@ static nlopt_result newuob_(int *n, int *npt, double *x, /* SGJ, 2008: compute rhoend from NLopt stop info */ rhoend = stop->xtol_rel * (*rhobeg); - for (j = 0; j < *n; ++j) - if (rhoend < stop->xtol_abs[j]) - rhoend = stop->xtol_abs[j]; + if (stop->xtol_abs) + for (j = 0; j < *n; ++j) + if (rhoend < stop->xtol_abs[j]) + rhoend = stop->xtol_abs[j]; /* The arguments N, NPT, X, RHOBEG, RHOEND, IPRINT and MAXFUN are identical */ /* to the corresponding arguments in SUBROUTINE NEWUOA. */ From 3b216f5fdbfb3c7da85dc7bd2278b9038b105284 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Fri, 26 Apr 2019 18:45:00 +0300 Subject: [PATCH 8/9] praxis: handle xtol_abs == NULL --- src/algs/praxis/praxis.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/algs/praxis/praxis.c b/src/algs/praxis/praxis.c index e6ce82e3..9d664419 100644 --- a/src/algs/praxis/praxis.c +++ b/src/algs/praxis/praxis.c @@ -189,7 +189,8 @@ nlopt_result praxis_(double t0, double machep, double h0, t_old = small + t0; else { t_old = 0; - for (i__ = 0; i__ < n; ++i__) + if (stop->xtol_abs) + for (i__ = 0; i__ < n; ++i__) if (stop->xtol_abs[i__] > t_old) t_old = stop->xtol_abs[i__]; t_old += small; From ceed32843aebd1ea36c7504893eb82163acc02ab Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Fri, 26 Apr 2019 18:49:02 +0300 Subject: [PATCH 9/9] optimize.c: handle xtol_abs == NULL --- src/api/optimize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/optimize.c b/src/api/optimize.c index 43cb66ac..aa8d4ebc 100644 --- a/src/api/optimize.c +++ b/src/api/optimize.c @@ -619,7 +619,7 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf) } if (opt->dx) nlopt_set_initial_step(local_opt, opt->dx); - for (i = 0; i < n && stop.xtol_abs[i] > 0; ++i); + for (i = 0; i < n && stop.xtol_abs && stop.xtol_abs[i] > 0; ++i); if (local_opt->ftol_rel <= 0 && local_opt->ftol_abs <= 0 && local_opt->xtol_rel <= 0 && i < n) { /* it is not sensible to call MLSL without *some* nonzero tolerance for the local search */