From 7e5f41a32a90ab10da5456b9f17582b3a6574972 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Sat, 4 Aug 2018 12:11:09 +0300 Subject: [PATCH 01/21] xtol_rel: L1 norm for whole-vector stopping criterion --- src/util/stop.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/util/stop.c b/src/util/stop.c index acf7c5b3..2d28ca57 100644 --- a/src/util/stop.c +++ b/src/util/stop.c @@ -29,6 +29,15 @@ /* utility routines to implement the various stopping criteria */ +static double vector_norm(unsigned n, double *vec, double *w) +{ + unsigned i; + double ret; + for (i = 0; i < n; i++) + ret += (w ? w[i] : 1) * fabs(vec[i]); /* this is L1 norm */ + return ret; +} + static int relstop(double vold, double vnew, double reltol, double abstol) { if (nlopt_isinf(vold)) @@ -49,6 +58,7 @@ int nlopt_stop_f(const nlopt_stopping * s, double f, double oldf) int nlopt_stop_x(const nlopt_stopping * s, const double *x, const double *oldx) { unsigned i; + /* TODO: iterative calculation of ‖Δx‖ */ for (i = 0; i < s->n; ++i) if (!relstop(oldx[i], x[i], s->xtol_rel, s->xtol_abs[i])) return 0; @@ -58,8 +68,10 @@ int nlopt_stop_x(const nlopt_stopping * s, const double *x, const double *oldx) int nlopt_stop_dx(const nlopt_stopping * s, const double *x, const double *dx) { unsigned i; + if (vector_norm(s->n, dx, NULL) <= s->xtol_rel * vector_norm(s->n, x, NULL)) + return 1; for (i = 0; i < s->n; ++i) - if (!relstop(x[i] - dx[i], x[i], s->xtol_rel, s->xtol_abs[i])) + if (!relstop(x[i] - dx[i], x[i], 0 /* may be not a good idea */ , s->xtol_abs[i])) return 0; return 1; } @@ -74,6 +86,7 @@ static double sc(double x, double smin, double smax) int nlopt_stop_xs(const nlopt_stopping * s, const double *xs, const double *oldxs, const double *scale_min, const double *scale_max) { unsigned i; + /* TODO: iterative calculation of ‖Δx‖ */ for (i = 0; i < s->n; ++i) if (!relstop(sc(oldxs[i], scale_min[i], scale_max[i]), sc(xs[i], scale_min[i], scale_max[i]), s->xtol_rel, s->xtol_abs[i])) return 0; From a92e4f5f9bed055eaf0af1edc2f3255813943216 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Sat, 18 Aug 2018 11:23:22 +0300 Subject: [PATCH 02/21] vector_norm: fix uninitialized ret, move branch outside for loop, make it const-correct --- src/util/stop.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/util/stop.c b/src/util/stop.c index 2d28ca57..139f722d 100644 --- a/src/util/stop.c +++ b/src/util/stop.c @@ -29,12 +29,16 @@ /* utility routines to implement the various stopping criteria */ -static double vector_norm(unsigned n, double *vec, double *w) +static double vector_norm(unsigned n, const double *vec, const double *w) { unsigned i; - double ret; - for (i = 0; i < n; i++) - ret += (w ? w[i] : 1) * fabs(vec[i]); /* this is L1 norm */ + double ret = 0; + if (w) + for (i = 0; i < n; i++) + ret += w[i] * fabs(vec[i]); + else + for (i = 0; i < n; i++) + ret += fabs(vec[i]); return ret; } From 02a2ab0be379b80e2acbcc4e24733fd76e5c8f9e Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Sat, 18 Aug 2018 11:24:05 +0300 Subject: [PATCH 03/21] diff_norm: like vector_norm, but for x-oldx --- src/util/stop.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/util/stop.c b/src/util/stop.c index 139f722d..90218dbb 100644 --- a/src/util/stop.c +++ b/src/util/stop.c @@ -42,6 +42,19 @@ static double vector_norm(unsigned n, const double *vec, const double *w) return ret; } +static double diff_norm(unsigned n, const double *x, const double *oldx, const double *w) +{ + unsigned i; + double ret = 0; + if (w) + for (i = 0; i < n; i++) + ret += w[i] * fabs(x[i] - oldx[i]); + else + for (i = 0; i < n; i++) + ret += fabs(x[i] - oldx[i]); + return ret; +} + static int relstop(double vold, double vnew, double reltol, double abstol) { if (nlopt_isinf(vold)) @@ -62,7 +75,8 @@ int nlopt_stop_f(const nlopt_stopping * s, double f, double oldf) int nlopt_stop_x(const nlopt_stopping * s, const double *x, const double *oldx) { unsigned i; - /* TODO: iterative calculation of ‖Δx‖ */ + if (diff_norm(s->n, x, oldx, NULL) <= s->xtol_rel * diff_norm(s->n, x, oldx, NULL)) + return 1; for (i = 0; i < s->n; ++i) if (!relstop(oldx[i], x[i], s->xtol_rel, s->xtol_abs[i])) return 0; @@ -90,7 +104,7 @@ static double sc(double x, double smin, double smax) int nlopt_stop_xs(const nlopt_stopping * s, const double *xs, const double *oldxs, const double *scale_min, const double *scale_max) { unsigned i; - /* TODO: iterative calculation of ‖Δx‖ */ + /* TODO: scale ‖Δx‖... but not with w */ for (i = 0; i < s->n; ++i) if (!relstop(sc(oldxs[i], scale_min[i], scale_max[i]), sc(xs[i], scale_min[i], scale_max[i]), s->xtol_rel, s->xtol_abs[i])) return 0; From 66f0c11c36eeafaa779a7a18144f05e25114019b Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Fri, 9 Nov 2018 00:49:07 +0300 Subject: [PATCH 04/21] xtol_abs: test directly when diff_norm tests for weighted xtol_rel --- src/util/stop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/stop.c b/src/util/stop.c index 90218dbb..39848667 100644 --- a/src/util/stop.c +++ b/src/util/stop.c @@ -78,7 +78,7 @@ int nlopt_stop_x(const nlopt_stopping * s, const double *x, const double *oldx) if (diff_norm(s->n, x, oldx, NULL) <= s->xtol_rel * diff_norm(s->n, x, oldx, NULL)) return 1; for (i = 0; i < s->n; ++i) - if (!relstop(oldx[i], x[i], s->xtol_rel, s->xtol_abs[i])) + if (fabs(x[i] - oldx[i]) > s->xtol_abs[i]) return 0; return 1; } @@ -89,7 +89,7 @@ int nlopt_stop_dx(const nlopt_stopping * s, const double *x, const double *dx) if (vector_norm(s->n, dx, NULL) <= s->xtol_rel * vector_norm(s->n, x, NULL)) return 1; for (i = 0; i < s->n; ++i) - if (!relstop(x[i] - dx[i], x[i], 0 /* may be not a good idea */ , s->xtol_abs[i])) + if (fabs(dx[i]) > s->xtol_abs[i]) return 0; return 1; } From 2108efb3d6afe9efc1e094469c7b605c353f3aca Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Fri, 9 Nov 2018 20:06:44 +0300 Subject: [PATCH 05/21] add double * x_weights to nlopt and nlopt_stopping structures - use the weights when checking relative x stopping criterion - allow setting the weights like it's implemented for xtol_abs - weights default to 1 --- src/api/nlopt-internal.h | 1 + src/api/optimize.c | 1 + src/api/options.c | 39 ++++++++++++++++++++++++++++++++++++++- src/util/nlopt-util.h | 1 + src/util/stop.c | 4 ++-- 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/api/nlopt-internal.h b/src/api/nlopt-internal.h index bf6fecc1..aed9cc89 100644 --- a/src/api/nlopt-internal.h +++ b/src/api/nlopt-internal.h @@ -57,6 +57,7 @@ extern "C" { double stopval; /* stop when f reaches stopval or better */ double ftol_rel, ftol_abs; /* relative/absolute f tolerances */ double xtol_rel, *xtol_abs; /* rel/abs x tolerances */ + double *x_weights; /* weights for relative x tolerance */ int maxeval; /* max # evaluations */ int numevals; /* number of evaluations */ double maxtime; /* max time (seconds) */ diff --git a/src/api/optimize.c b/src/api/optimize.c index c5c94460..43cb66ac 100644 --- a/src/api/optimize.c +++ b/src/api/optimize.c @@ -426,6 +426,7 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf) stop.ftol_abs = opt->ftol_abs; stop.xtol_rel = opt->xtol_rel; stop.xtol_abs = opt->xtol_abs; + stop.x_weights = opt->x_weights; opt->numevals = 0; stop.nevals_p = &(opt->numevals); stop.maxeval = opt->maxeval; diff --git a/src/api/options.c b/src/api/options.c index d0a90937..d03246c2 100644 --- a/src/api/options.c +++ b/src/api/options.c @@ -88,6 +88,7 @@ nlopt_opt NLOPT_STDCALL nlopt_create(nlopt_algorithm algorithm, unsigned n) opt->stopval = -HUGE_VAL; opt->ftol_rel = opt->ftol_abs = 0; opt->xtol_rel = 0; + opt->x_weights = NULL; opt->xtol_abs = NULL; opt->maxeval = 0; opt->numevals = 0; @@ -109,12 +110,16 @@ nlopt_opt NLOPT_STDCALL nlopt_create(nlopt_algorithm algorithm, unsigned n) opt->ub = (double *) calloc(n, sizeof(double)); if (!opt->ub) goto oom; + opt->x_weights = (double *) calloc(n, sizeof(double)); + if (!opt->x_weights) + 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); + nlopt_set_x_weights1(opt, 1); } } @@ -133,7 +138,7 @@ nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt) nlopt_munge munge; nopt = (nlopt_opt) malloc(sizeof(struct nlopt_opt_s)); *nopt = *opt; - nopt->lb = nopt->ub = nopt->xtol_abs = NULL; + nopt->lb = nopt->ub = nopt->xtol_abs = nopt->x_weights = NULL; nopt->fc = nopt->h = NULL; nopt->m_alloc = nopt->p_alloc = 0; nopt->local_opt = NULL; @@ -157,10 +162,14 @@ nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt) nopt->xtol_abs = (double *) malloc(sizeof(double) * (opt->n)); if (!opt->xtol_abs) goto oom; + nopt->x_weights = (double *) malloc(sizeof(double) * (opt->n)); + if (!opt->x_weights) + goto oom; 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)); + memcpy(nopt->x_weights, opt->x_weights, sizeof(double) * (opt->n)); } if (opt->m) { @@ -628,6 +637,34 @@ nlopt_result NLOPT_STDCALL nlopt_get_xtol_abs(const nlopt_opt opt, double *xtol_ return NLOPT_SUCCESS; } +nlopt_result NLOPT_STDCALL nlopt_set_x_weights(nlopt_opt opt, const double *x_weights) +{ + if (opt) { + nlopt_unset_errmsg(opt); + memcpy(opt->x_weights, x_weights, opt->n * sizeof(double)); + return NLOPT_SUCCESS; + } + return NLOPT_INVALID_ARGS; +} + +nlopt_result NLOPT_STDCALL nlopt_set_x_weights1(nlopt_opt opt, double x_weights) +{ + if (opt) { + unsigned i; + nlopt_unset_errmsg(opt); + for (i = 0; i < opt->n; ++i) + opt->x_weights[i] = x_weights; + return NLOPT_SUCCESS; + } + return NLOPT_INVALID_ARGS; +} + +nlopt_result NLOPT_STDCALL nlopt_get_x_weights(const nlopt_opt opt, double *x_weights) +{ + memcpy(x_weights, opt->x_weights, opt->n * sizeof(double)); + return NLOPT_SUCCESS; +} + GETSET(maxeval, int, maxeval) GET(numevals, int, numevals) diff --git a/src/util/nlopt-util.h b/src/util/nlopt-util.h index dbfdca29..e9c49f95 100644 --- a/src/util/nlopt-util.h +++ b/src/util/nlopt-util.h @@ -81,6 +81,7 @@ extern "C" { double ftol_abs; double xtol_rel; const double *xtol_abs; + const double *x_weights; int *nevals_p, maxeval; double maxtime, start; int *force_stop; diff --git a/src/util/stop.c b/src/util/stop.c index 39848667..9ceaa656 100644 --- a/src/util/stop.c +++ b/src/util/stop.c @@ -75,7 +75,7 @@ int nlopt_stop_f(const nlopt_stopping * s, double f, double oldf) int nlopt_stop_x(const nlopt_stopping * s, const double *x, const double *oldx) { unsigned i; - if (diff_norm(s->n, x, oldx, NULL) <= s->xtol_rel * diff_norm(s->n, x, oldx, NULL)) + if (diff_norm(s->n, x, oldx, s->x_weights) <= s->xtol_rel * diff_norm(s->n, x, oldx, s->x_weights)) return 1; for (i = 0; i < s->n; ++i) if (fabs(x[i] - oldx[i]) > s->xtol_abs[i]) @@ -86,7 +86,7 @@ int nlopt_stop_x(const nlopt_stopping * s, const double *x, const double *oldx) int nlopt_stop_dx(const nlopt_stopping * s, const double *x, const double *dx) { unsigned i; - if (vector_norm(s->n, dx, NULL) <= s->xtol_rel * vector_norm(s->n, x, NULL)) + if (vector_norm(s->n, dx, s->x_weights) <= s->xtol_rel * vector_norm(s->n, x, s->x_weights)) return 1; for (i = 0; i < s->n; ++i) if (fabs(dx[i]) > s->xtol_abs[i]) From 5ff10d34d4098b068b633da40f295069c7e63c5c Mon Sep 17 00:00:00 2001 From: aitap Date: Fri, 9 Nov 2018 23:41:23 +0300 Subject: [PATCH 06/21] don't forget to free the weights; actually declare the weight-related functions --- src/api/nlopt.h | 3 +++ src/api/options.c | 1 + 2 files changed, 4 insertions(+) diff --git a/src/api/nlopt.h b/src/api/nlopt.h index 062fd2cf..625c9730 100644 --- a/src/api/nlopt.h +++ b/src/api/nlopt.h @@ -243,6 +243,9 @@ NLOPT_EXTERN(double) nlopt_get_xtol_rel(const nlopt_opt opt); NLOPT_EXTERN(nlopt_result) nlopt_set_xtol_abs1(nlopt_opt opt, double tol); NLOPT_EXTERN(nlopt_result) nlopt_set_xtol_abs(nlopt_opt opt, const double *tol); NLOPT_EXTERN(nlopt_result) nlopt_get_xtol_abs(const nlopt_opt opt, double *tol); +NLOPT_EXTERN(nlopt_result) nlopt_set_x_weights1(nlopt_opt opt, double tol); +NLOPT_EXTERN(nlopt_result) nlopt_set_x_weights(nlopt_opt opt, const double *tol); +NLOPT_EXTERN(nlopt_result) nlopt_get_x_weights(const nlopt_opt opt, double *tol); NLOPT_EXTERN(nlopt_result) nlopt_set_maxeval(nlopt_opt opt, int maxeval); NLOPT_EXTERN(int) nlopt_get_maxeval(const nlopt_opt opt); diff --git a/src/api/options.c b/src/api/options.c index d03246c2..5f71fe9b 100644 --- a/src/api/options.c +++ b/src/api/options.c @@ -52,6 +52,7 @@ void NLOPT_STDCALL nlopt_destroy(nlopt_opt opt) free(opt->lb); free(opt->ub); free(opt->xtol_abs); + free(opt->x_weights); free(opt->fc); free(opt->h); nlopt_destroy(opt->local_opt); From 6c6430ef37f022463f65804a885a716d2ec1ac83 Mon Sep 17 00:00:00 2001 From: aitap Date: Sat, 10 Nov 2018 00:04:48 +0300 Subject: [PATCH 07/21] provide scale support for vector_norm and diff_norm --- src/util/stop.c | 65 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/src/util/stop.c b/src/util/stop.c index 9ceaa656..aaeb69f6 100644 --- a/src/util/stop.c +++ b/src/util/stop.c @@ -29,29 +29,52 @@ /* utility routines to implement the various stopping criteria */ -static double vector_norm(unsigned n, const double *vec, const double *w) +static double sc(double x, double smin, double smax) +{ + return smin + x * (smax - smin); +} + +static double vector_norm(unsigned n, const double *vec, const double *w, const double *scale_min, const double *scale_max) { unsigned i; double ret = 0; - if (w) - for (i = 0; i < n; i++) - ret += w[i] * fabs(vec[i]); - else - for (i = 0; i < n; i++) - ret += fabs(vec[i]); + if (scale_min && scale_max) { + if (w) + for (i = 0; i < n; i++) + ret += w[i] * fabs(sc(vec[i], scale_min[i], scale_max[i])); + else + for (i = 0; i < n; i++) + ret += fabs(sc(vec[i], scale_min[i], scale_max[i])); + } else { + if (w) + for (i = 0; i < n; i++) + ret += w[i] * fabs(vec[i]); + else + for (i = 0; i < n; i++) + ret += fabs(vec[i]); + } return ret; } -static double diff_norm(unsigned n, const double *x, const double *oldx, const double *w) +static double diff_norm(unsigned n, const double *x, const double *oldx, const double *w, const double *scale_min, const double *scale_max) { unsigned i; double ret = 0; - if (w) - for (i = 0; i < n; i++) - ret += w[i] * fabs(x[i] - oldx[i]); - else - for (i = 0; i < n; i++) - ret += fabs(x[i] - oldx[i]); + if (scale_min && scale_max) { + if (w) + for (i = 0; i < n; i++) + ret += w[i] * fabs(sc(x[i], scale_min[i], scale_max[i]) - sc(oldx[i], scale_min[i], scale_max[i])); + else + for (i = 0; i < n; i++) + ret += fabs(sc(x[i], scale_min[i], scale_max[i]) - sc(oldx[i], scale_min[i], scale_max[i])); + } else { + if (w) + for (i = 0; i < n; i++) + ret += w[i] * fabs(x[i] - oldx[i]); + else + for (i = 0; i < n; i++) + ret += fabs(x[i] - oldx[i]); + } return ret; } @@ -75,7 +98,7 @@ int nlopt_stop_f(const nlopt_stopping * s, double f, double oldf) 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) <= s->xtol_rel * diff_norm(s->n, x, oldx, s->x_weights)) + 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; for (i = 0; i < s->n; ++i) if (fabs(x[i] - oldx[i]) > s->xtol_abs[i]) @@ -86,7 +109,7 @@ int nlopt_stop_x(const nlopt_stopping * s, const double *x, const double *oldx) 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) <= s->xtol_rel * vector_norm(s->n, x, s->x_weights)) + 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; for (i = 0; i < s->n; ++i) if (fabs(dx[i]) > s->xtol_abs[i]) @@ -94,19 +117,15 @@ int nlopt_stop_dx(const nlopt_stopping * s, const double *x, const double *dx) return 1; } -static double sc(double x, double smin, double smax) -{ - return smin + x * (smax - smin); -} - /* some of the algorithms rescale x to a unit hypercube, so we need to scale back before we can compare to the tolerances */ int nlopt_stop_xs(const nlopt_stopping * s, const double *xs, const double *oldxs, const double *scale_min, const double *scale_max) { unsigned i; - /* TODO: scale ‖Δx‖... but not with w */ + 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; for (i = 0; i < s->n; ++i) - if (!relstop(sc(oldxs[i], scale_min[i], scale_max[i]), sc(xs[i], scale_min[i], scale_max[i]), s->xtol_rel, s->xtol_abs[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; return 1; } From a0e0040ea20317be979a7e8474a63e6f48e14048 Mon Sep 17 00:00:00 2001 From: aitap Date: Tue, 23 Apr 2019 23:15:34 +0300 Subject: [PATCH 08/21] add argument checks to nlopt_get_x_weights --- src/api/options.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/api/options.c b/src/api/options.c index 5f71fe9b..9581d23a 100644 --- a/src/api/options.c +++ b/src/api/options.c @@ -662,8 +662,12 @@ nlopt_result NLOPT_STDCALL nlopt_set_x_weights1(nlopt_opt opt, double x_weights) nlopt_result NLOPT_STDCALL nlopt_get_x_weights(const nlopt_opt opt, double *x_weights) { - memcpy(x_weights, opt->x_weights, opt->n * sizeof(double)); - return NLOPT_SUCCESS; + nlopt_unset_errmsg(opt); + if (opt && (opt->n == 0 || x_weights)) { + memcpy(x_weights, opt->x_weights, sizeof(double) * (opt->n)); + return NLOPT_SUCCESS; + } + return NLOPT_INVALID_ARGS; } GETSET(maxeval, int, maxeval) From 038affabe3e1b6127655bc1fbaa14861f3e6d6cc Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Wed, 24 Apr 2019 13:52:16 +0300 Subject: [PATCH 09/21] do not allocate x_weights unless requested by Unallocated (NULL) x_weights behave as if all weigths are set to 1. --- src/api/options.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/api/options.c b/src/api/options.c index 9581d23a..4c869146 100644 --- a/src/api/options.c +++ b/src/api/options.c @@ -111,16 +111,12 @@ nlopt_opt NLOPT_STDCALL nlopt_create(nlopt_algorithm algorithm, unsigned n) opt->ub = (double *) calloc(n, sizeof(double)); if (!opt->ub) goto oom; - opt->x_weights = (double *) calloc(n, sizeof(double)); - if (!opt->x_weights) - 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); - nlopt_set_x_weights1(opt, 1); } } @@ -163,14 +159,16 @@ nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt) nopt->xtol_abs = (double *) malloc(sizeof(double) * (opt->n)); if (!opt->xtol_abs) goto oom; - nopt->x_weights = (double *) malloc(sizeof(double) * (opt->n)); - if (!opt->x_weights) - goto oom; + if (opt->x_weights) { + nopt->x_weights = (double *) malloc(sizeof(double) * (opt->n)); + if (!opt->x_weights) + goto oom; + memcpy(nopt->x_weights, opt->x_weights, sizeof(double) * (opt->n)); + } 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)); - memcpy(nopt->x_weights, opt->x_weights, sizeof(double) * (opt->n)); } if (opt->m) { @@ -642,6 +640,12 @@ nlopt_result NLOPT_STDCALL nlopt_set_x_weights(nlopt_opt opt, const double *x_we { if (opt) { nlopt_unset_errmsg(opt); + if (!opt->x_weights) { + opt->x_weights = (double *) calloc(opt->n, sizeof(double)); + if (!opt->x_weights) { + return NLOPT_OUT_OF_MEMORY; + } + } memcpy(opt->x_weights, x_weights, opt->n * sizeof(double)); return NLOPT_SUCCESS; } @@ -653,6 +657,12 @@ nlopt_result NLOPT_STDCALL nlopt_set_x_weights1(nlopt_opt opt, double x_weights) if (opt) { unsigned i; nlopt_unset_errmsg(opt); + if (!opt->x_weights) { + opt->x_weights = (double *) calloc(opt->n, sizeof(double)); + if (!opt->x_weights) { + return NLOPT_OUT_OF_MEMORY; + } + } for (i = 0; i < opt->n; ++i) opt->x_weights[i] = x_weights; return NLOPT_SUCCESS; @@ -664,7 +674,13 @@ nlopt_result NLOPT_STDCALL nlopt_get_x_weights(const nlopt_opt opt, double *x_we { nlopt_unset_errmsg(opt); if (opt && (opt->n == 0 || x_weights)) { - memcpy(x_weights, opt->x_weights, sizeof(double) * (opt->n)); + if (opt->x_weights) { + memcpy(x_weights, opt->x_weights, sizeof(double) * (opt->n)); + } else { + unsigned i; + for (i = 0; i < opt->n; ++i) + x_weights[i] = 1; + } return NLOPT_SUCCESS; } return NLOPT_INVALID_ARGS; From caf1554c0c87737ebe2574c2670488a365f2dc6f Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Wed, 24 Apr 2019 20:49:52 +0300 Subject: [PATCH 10/21] start documenting the new functions TODO: add *_x_weights functions to C++, Fortran, Python interface, document those --- doc/docs/NLopt_Reference.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/docs/NLopt_Reference.md b/doc/docs/NLopt_Reference.md index 5f0d9a76..d230d1dc 100644 --- a/doc/docs/NLopt_Reference.md +++ b/doc/docs/NLopt_Reference.md @@ -239,8 +239,20 @@ nlopt_result nlopt_set_xtol_rel(nlopt_opt opt, double tol); double nlopt_get_xtol_rel(const nlopt_opt opt); ``` +Set relative tolerance on optimization parameters: stop when an optimization step (or an estimate of the optimum) causes a relative change in L1 norm of parameters by less than `tol`. (If there is any chance that an optimal parameter is close to zero, you might want to set an absolute tolerance with `nlopt_set_xtol_abs` as well.) Criterion is disabled if `tol` is non-positive. -Set relative tolerance on optimization parameters: stop when an optimization step (or an estimate of the optimum) changes every parameter by less than `tol` multiplied by the absolute value of the parameter. (If there is any chance that an optimal parameter is close to zero, you might want to set an absolute tolerance with `nlopt_set_xtol_abs` as well.) Criterion is disabled if `tol` is non-positive. +``` +nlopt_result nlopt_set_xtol_abs(nlopt_opt opt, const double* tol); +nlopt_result nlopt_get_xtol_abs(const nlopt_opt opt, double *tol); +``` + +Set weights used when computing L1 norm of parameters to check relative tolerance on optimization parameters. + +For convenience, the following function may be used to set the weights in all `n` optimization parameters to the same value: + +```c +nlopt_result nlopt_set_xtol_abs1(nlopt_opt opt, double tol); +``` ``` nlopt_result nlopt_set_xtol_abs(nlopt_opt opt, const double* tol); From a65b52ab966301af60ee1eee5d40d0b3d428898e Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Wed, 24 Apr 2019 16:41:13 -0400 Subject: [PATCH 11/21] fixes, add equations --- doc/docs/NLopt_Reference.md | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/doc/docs/NLopt_Reference.md b/doc/docs/NLopt_Reference.md index d230d1dc..c4761696 100644 --- a/doc/docs/NLopt_Reference.md +++ b/doc/docs/NLopt_Reference.md @@ -239,37 +239,25 @@ nlopt_result nlopt_set_xtol_rel(nlopt_opt opt, double tol); double nlopt_get_xtol_rel(const nlopt_opt opt); ``` -Set relative tolerance on optimization parameters: stop when an optimization step (or an estimate of the optimum) causes a relative change in L1 norm of parameters by less than `tol`. (If there is any chance that an optimal parameter is close to zero, you might want to set an absolute tolerance with `nlopt_set_xtol_abs` as well.) Criterion is disabled if `tol` is non-positive. +Set relative tolerance on optimization parameters: stop when an optimization step (or an estimate of the optimum) causes a relative change the parameters $x$ by less than `tol`, i.e. $\Vert \Delta x \Vert_w < \mbox{tol}\cdot\Vert x \Vert_w$ as measured by a weighted L₁ norm $\Vert x \Vert_w = \sum_i w_i |x_i|$, where the weights $w_i$ default to $1$. +(If there is any chance that the optimal $\Vert x \Vert$ is close to zero, you might want to set an absolute tolerance with `nlopt_set_xtol_abs` as well.) Criterion is disabled if `tol` is non-positive. ``` -nlopt_result nlopt_set_xtol_abs(nlopt_opt opt, const double* tol); -nlopt_result nlopt_get_xtol_abs(const nlopt_opt opt, double *tol); +nlopt_result nlopt_set_x_weights(nlopt_opt opt, const double *w); +nlopt_result nlopt_set_x_weights1(nlopt_opt opt, const double w); +nlopt_result nlopt_get_x_weights(const nlopt_opt opt, double *w); ``` -Set weights used when computing L1 norm of parameters to check relative tolerance on optimization parameters. - -For convenience, the following function may be used to set the weights in all `n` optimization parameters to the same value: - -```c -nlopt_result nlopt_set_xtol_abs1(nlopt_opt opt, double tol); -``` - -``` -nlopt_result nlopt_set_xtol_abs(nlopt_opt opt, const double* tol); -nlopt_result nlopt_get_xtol_abs(const nlopt_opt opt, double *tol); -``` - - -Set absolute tolerances on optimization parameters. `tol` is a pointer to an array of length `n` (the dimension from `nlopt_create`) giving the tolerances: stop when an optimization step (or an estimate of the optimum) changes every parameter `x[i]` by less than `tol[i]`. (Note that this function makes a copy of the `tol` array, so subsequent changes to the caller's `tol` have no effect on `opt`.) In `nlopt_get_xtol_abs`, `tol` must be an array of length `n`, which upon successful return contains a copy of the current tolerances. - -For convenience, the following function may be used to set the absolute tolerances in all `n` optimization parameters to the same value: +Set/get the weights used when the computing L₁ norm for the `xtol_rel` stopping criterion above, where `*w` must point to an array of length equal to the number of optimization parameters in `opt`. `nlopt_set_x_weights1` can be used to set all of the weights to the same value `w`. The weights default to `1`, but non-constant weights can be used to handle situations where the different parameters `x` have different units or importance, for example. ``` +nlopt_result nlopt_set_xtol_abs(nlopt_opt opt, const double *tol); nlopt_result nlopt_set_xtol_abs1(nlopt_opt opt, double tol); +nlopt_result nlopt_get_xtol_abs(const nlopt_opt opt, double *tol); ``` -Criterion is disabled if `tol` is non-positive. +Set absolute tolerances on optimization parameters. `tol` is a pointer to an array of length `n` (the dimension from `nlopt_create`) giving the tolerances: stop when an optimization step (or an estimate of the optimum) changes every parameter `x[i]` by less than `tol[i]`. (Note that `nlopt_set_xtol_abs` makes a copy of the `tol` array, so subsequent changes to the caller's `tol` have no effect on `opt`.) In `nlopt_get_xtol_abs`, `tol` must be an array of length `n`, which upon successful return contains a copy of the current tolerances. For convenience, the `nlopt_set_xtol_abs1` may be used to set the absolute tolerances in all `n` optimization parameters to the same value. Criterion is disabled if `tol` is non-positive. ``` nlopt_result nlopt_set_maxeval(nlopt_opt opt, int maxeval); From c31d1e75eb1a2a437f29deb4526343ca47879280 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Wed, 24 Apr 2019 16:41:34 -0400 Subject: [PATCH 12/21] Update NLopt_Reference.md --- doc/docs/NLopt_Reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/docs/NLopt_Reference.md b/doc/docs/NLopt_Reference.md index c4761696..e0745d2f 100644 --- a/doc/docs/NLopt_Reference.md +++ b/doc/docs/NLopt_Reference.md @@ -239,7 +239,7 @@ nlopt_result nlopt_set_xtol_rel(nlopt_opt opt, double tol); double nlopt_get_xtol_rel(const nlopt_opt opt); ``` -Set relative tolerance on optimization parameters: stop when an optimization step (or an estimate of the optimum) causes a relative change the parameters $x$ by less than `tol`, i.e. $\Vert \Delta x \Vert_w < \mbox{tol}\cdot\Vert x \Vert_w$ as measured by a weighted L₁ norm $\Vert x \Vert_w = \sum_i w_i |x_i|$, where the weights $w_i$ default to $1$. +Set relative tolerance on optimization parameters: stop when an optimization step (or an estimate of the optimum) causes a relative change the parameters $x$ by less than `tol`, i.e. $\Vert \Delta x \Vert_w < \mbox{tol}\cdot\Vert x \Vert_w$ as measured by a weighted L₁ norm $\Vert x \Vert_w = \sum_i w_i |x_i|$, where the weights $w_i$ default to 1. (If there is any chance that the optimal $\Vert x \Vert$ is close to zero, you might want to set an absolute tolerance with `nlopt_set_xtol_abs` as well.) Criterion is disabled if `tol` is non-positive. ``` From 00da0ee3c9f57260e2e3501f79f9ae0d7c7a6f9a Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Wed, 24 Apr 2019 16:44:06 -0400 Subject: [PATCH 13/21] param names --- src/api/nlopt.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/nlopt.h b/src/api/nlopt.h index 625c9730..6148bf32 100644 --- a/src/api/nlopt.h +++ b/src/api/nlopt.h @@ -243,9 +243,9 @@ NLOPT_EXTERN(double) nlopt_get_xtol_rel(const nlopt_opt opt); NLOPT_EXTERN(nlopt_result) nlopt_set_xtol_abs1(nlopt_opt opt, double tol); NLOPT_EXTERN(nlopt_result) nlopt_set_xtol_abs(nlopt_opt opt, const double *tol); NLOPT_EXTERN(nlopt_result) nlopt_get_xtol_abs(const nlopt_opt opt, double *tol); -NLOPT_EXTERN(nlopt_result) nlopt_set_x_weights1(nlopt_opt opt, double tol); -NLOPT_EXTERN(nlopt_result) nlopt_set_x_weights(nlopt_opt opt, const double *tol); -NLOPT_EXTERN(nlopt_result) nlopt_get_x_weights(const nlopt_opt opt, double *tol); +NLOPT_EXTERN(nlopt_result) nlopt_set_x_weights1(nlopt_opt opt, double w); +NLOPT_EXTERN(nlopt_result) nlopt_set_x_weights(nlopt_opt opt, const double *w); +NLOPT_EXTERN(nlopt_result) nlopt_get_x_weights(const nlopt_opt opt, double *w); NLOPT_EXTERN(nlopt_result) nlopt_set_maxeval(nlopt_opt opt, int maxeval); NLOPT_EXTERN(int) nlopt_get_maxeval(const nlopt_opt opt); From 91c262bb4d16e7e0de24f32ee605efb985b35c60 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Thu, 25 Apr 2019 12:56:31 +0300 Subject: [PATCH 14/21] check for w < 0 in set_x_weights --- src/api/options.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/api/options.c b/src/api/options.c index 4c869146..087d9723 100644 --- a/src/api/options.c +++ b/src/api/options.c @@ -640,6 +640,11 @@ nlopt_result NLOPT_STDCALL nlopt_set_x_weights(nlopt_opt opt, const double *x_we { if (opt) { nlopt_unset_errmsg(opt); + unsigned i; + for (i = 0; i < opt->n; i++) { + if (x_weights[i] <= 0) + return NLOPT_INVALID_ARGS; + } if (!opt->x_weights) { opt->x_weights = (double *) calloc(opt->n, sizeof(double)); if (!opt->x_weights) { @@ -654,7 +659,7 @@ nlopt_result NLOPT_STDCALL nlopt_set_x_weights(nlopt_opt opt, const double *x_we nlopt_result NLOPT_STDCALL nlopt_set_x_weights1(nlopt_opt opt, double x_weights) { - if (opt) { + if (opt && x_weights > 0) { unsigned i; nlopt_unset_errmsg(opt); if (!opt->x_weights) { From 98ef03cc43d15e3dd51a6b5fcb58ff3d48888c4a Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Thu, 25 Apr 2019 13:07:30 +0300 Subject: [PATCH 15/21] add x_weights to C++ interface and document them --- doc/docs/NLopt_C-plus-plus_Reference.md | 10 ++++++++++ src/api/nlopt-in.hpp | 1 + 2 files changed, 11 insertions(+) diff --git a/doc/docs/NLopt_C-plus-plus_Reference.md b/doc/docs/NLopt_C-plus-plus_Reference.md index 3fccf8fe..29f1a734 100644 --- a/doc/docs/NLopt_C-plus-plus_Reference.md +++ b/doc/docs/NLopt_C-plus-plus_Reference.md @@ -203,6 +203,16 @@ double nlopt::opt::get_xtol_rel() const; Set relative tolerance on optimization parameters. +``` +void nlopt::opt::set_x_weights(const std::vector`` &w); +void nlopt::opt::set_x_weights(double w); +void nlopt::opt::get_x_weights(std::vector`` &w) const; +std::vector`` nlopt::opt::get_x_weights() const; +``` + + +Set/get the weights used when the computing L₁ norm for the `xtol_rel` stopping criterion above. + ``` void nlopt::opt::set_xtol_abs(const std::vector`` &tol); void nlopt::opt::set_xtol_abs(double tol); diff --git a/src/api/nlopt-in.hpp b/src/api/nlopt-in.hpp index d742c0ad..a311c88a 100644 --- a/src/api/nlopt-in.hpp +++ b/src/api/nlopt-in.hpp @@ -462,6 +462,7 @@ namespace nlopt { NLOPT_GETSET(double, ftol_abs) NLOPT_GETSET(double, xtol_rel) NLOPT_GETSET_VEC(xtol_abs) + NLOPT_GETSET_VEC(x_weights) NLOPT_GETSET(int, maxeval) int get_numevals() const { From d45c58163e1da40c48871d55e53a0c2197ec6b79 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Thu, 25 Apr 2019 13:18:28 +0300 Subject: [PATCH 16/21] add x_weights to F77 interface and document them --- doc/docs/NLopt_Fortran_Reference.md | 9 +++++++++ src/api/f77funcs_.h | 1 + 2 files changed, 10 insertions(+) diff --git a/doc/docs/NLopt_Fortran_Reference.md b/doc/docs/NLopt_Fortran_Reference.md index 1c95e255..4bc2fb5b 100644 --- a/doc/docs/NLopt_Fortran_Reference.md +++ b/doc/docs/NLopt_Fortran_Reference.md @@ -241,6 +241,15 @@ call nlo_get_xtol_rel(tol, opt) Set relative tolerance on optimization parameters. +``` +call nlo_set_x_weights(ires, opt, w) +call nlo_set_x_weights1(ires, opt, w1) +call nlo_get_x_weights(ires, opt, w) +``` + + +Set/get the weights used when the computing L₁ norm for the `xtol_rel` stopping criterion above. + ``` call nlo_set_xtol_abs(ires, opt, tol) call nlo_set_xtol_abs1(ires, opt, tol1) diff --git a/src/api/f77funcs_.h b/src/api/f77funcs_.h index 3a0a3ec1..6528a3b0 100644 --- a/src/api/f77funcs_.h +++ b/src/api/f77funcs_.h @@ -152,6 +152,7 @@ F77_GETSET(stopval, STOPVAL, double) F77_GETSET(ftol_rel, FTOL_REL, double) F77_GETSET(ftol_abs, FTOL_ABS, double) F77_GETSET(xtol_rel, XTOL_REL, double) F77_GETSETA(xtol_abs, XTOL_ABS, double) F77_GETSET(maxeval, MAXEVAL, int) F77_GET(numevals, NUMEVALS, int) F77_GETSET(maxtime, MAXTIME, double) +F77_GETSETA(x_weights, X_WEIGHTS, double) F77_GETSET(force_stop, FORCE_STOP, int) NLOPT_EXTERN(void) F77_(nlo_force_stop, NLO_FORCE_STOP) (int *ret, nlopt_opt * opt) { From f8141bca2b75bf4c70da301e808cf1b36f1079fb Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Thu, 25 Apr 2019 13:28:42 +0300 Subject: [PATCH 17/21] add & document x_weights to SWIG-based interfaces This includes Guile and Python. --- doc/docs/NLopt_Guile_Reference.md | 8 ++++++++ doc/docs/NLopt_Python_Reference.md | 8 ++++++++ src/swig/nlopt-exceptions.i | 1 + 3 files changed, 17 insertions(+) diff --git a/doc/docs/NLopt_Guile_Reference.md b/doc/docs/NLopt_Guile_Reference.md index b8417519..31a08e30 100644 --- a/doc/docs/NLopt_Guile_Reference.md +++ b/doc/docs/NLopt_Guile_Reference.md @@ -178,6 +178,14 @@ Set relative tolerance on optimization parameters. Set absolute tolerances on optimization parameters. The `tol` input must be a vector or list of length `n` (the dimension specified in the `nlopt.opt` constructor); alternatively, you can pass a single number in order to set the same tolerance for all optimization parameters. `get-xtol-abs()` returns the tolerances as a vector. +``` +(nlopt-opt-set-x-weights opt x) +(nlopt-opt-get-x-weights opt x) +``` + + +Set the weights used when the computing L₁ norm for the `xtol_rel` stopping criterion above. + ``` (nlopt-opt-set-maxeval opt maxeval) (nlopt-opt-get-maxeval opt) diff --git a/doc/docs/NLopt_Python_Reference.md b/doc/docs/NLopt_Python_Reference.md index 620dde8e..aa1e9f66 100644 --- a/doc/docs/NLopt_Python_Reference.md +++ b/doc/docs/NLopt_Python_Reference.md @@ -223,6 +223,14 @@ opt.get_xtol_abs() Set absolute tolerances on optimization parameters. The `tol` input must be an array (NumPy array or Python list) of length `n` (the dimension specified in the `nlopt.opt` constructor); alternatively, you can pass a single number in order to set the same tolerance for all optimization parameters. `get_xtol_abs()` returns the tolerances as a NumPy array. +``` +opt.set_x_weights(w) +opt.get_x_weights() +``` + + +Set the weights used when the computing L₁ norm for the `xtol_rel` stopping criterion above. + ``` opt.set_maxeval(maxeval) opt.get_maxeval() diff --git a/src/swig/nlopt-exceptions.i b/src/swig/nlopt-exceptions.i index 625914a3..36ac0999 100644 --- a/src/swig/nlopt-exceptions.i +++ b/src/swig/nlopt-exceptions.i @@ -53,6 +53,7 @@ GETSET_EXCEPT(ftol_rel, double) GETSET_EXCEPT(ftol_abs, double) GETSET_EXCEPT(xtol_rel, double) GETSETVEC_EXCEPT(xtol_abs) +GETSETVEC_EXCEPT(x_weights) GETSET_EXCEPT(maxeval, int) GETSET_EXCEPT(maxtime, double) GETSET_EXCEPT(force_stop, int) From 64eedcc5f3a2315f6499a8a5da0a933044701f19 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Thu, 25 Apr 2019 13:43:06 +0300 Subject: [PATCH 18/21] add and document x_weights to Octave&Matlab --- doc/docs/NLopt_Matlab_Reference.md | 7 +++++++ src/octave/nlopt_optimize-mex.c | 2 ++ src/octave/nlopt_optimize-oct.cc | 6 ++++++ 3 files changed, 15 insertions(+) diff --git a/doc/docs/NLopt_Matlab_Reference.md b/doc/docs/NLopt_Matlab_Reference.md index 44b212c0..ef368135 100644 --- a/doc/docs/NLopt_Matlab_Reference.md +++ b/doc/docs/NLopt_Matlab_Reference.md @@ -101,6 +101,13 @@ opt.xtol_rel Set relative tolerance on optimization parameters. +``` +opt.x_weights +``` + + +Set the weights used when the computing L₁ norm for the `xtol_rel` stopping criterion above. The `opt.x_weights` value must be a vector of length `n` (the same length as the initial guess passed to `nlopt_optimize`). + ``` opt.xtol_abs ``` diff --git a/src/octave/nlopt_optimize-mex.c b/src/octave/nlopt_optimize-mex.c index eb374615..499ac76e 100644 --- a/src/octave/nlopt_optimize-mex.c +++ b/src/octave/nlopt_optimize-mex.c @@ -171,6 +171,8 @@ nlopt_opt make_opt(const mxArray *opts, unsigned n) nlopt_set_xtol_rel(opt, struct_val_default(opts, "xtol_rel", 0.0)); nlopt_set_xtol_abs(opt, struct_arrval(opts, "xtol_abs", n, fill(tmp, n, 0.0))); + nlopt_set_x_weights(opt, struct_arrval(opts, "x_weights", n, + fill(tmp, n, 1.0))); nlopt_set_maxeval(opt, struct_val_default(opts, "maxeval", 0.0) < 0 ? 0 : struct_val_default(opts, "maxeval", 0.0)); nlopt_set_maxtime(opt, struct_val_default(opts, "maxtime", 0.0)); diff --git a/src/octave/nlopt_optimize-oct.cc b/src/octave/nlopt_optimize-oct.cc index e7255bb3..6d162ab0 100644 --- a/src/octave/nlopt_optimize-oct.cc +++ b/src/octave/nlopt_optimize-oct.cc @@ -200,6 +200,12 @@ nlopt_opt make_opt(octave_map &opts, int n) CHECK1(n == xtol_abs.numel(), "stop.xtol_abs must have same length as x"); CHECK1(nlopt_set_xtol_abs(opt, xtol_abs.data())>0, "nlopt: out of memory"); } + { + Matrix ones(1, n, 1.0); + Matrix x_weights = struct_val_default(opts, "x_weights", ones); + CHECK1(n == x_weights.numel(), "stop.x_weights must have same length as x"); + CHECK1(nlopt_set_x_weights(opt, x_weights.data())>0, "nlopt: invalid x_weights or out of memory"); + } nlopt_set_maxeval(opt, struct_val_default(opts, "maxeval", 0) < 0 ? 0 : struct_val_default(opts, "maxeval", 0)); From 6f99d9e304a2baff2d98644491a6fe9144080db5 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Thu, 25 Apr 2019 13:47:48 +0300 Subject: [PATCH 19/21] set_x_weights: ISO C90 compatibility --- src/api/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/options.c b/src/api/options.c index 087d9723..94493e50 100644 --- a/src/api/options.c +++ b/src/api/options.c @@ -639,8 +639,8 @@ nlopt_result NLOPT_STDCALL nlopt_get_xtol_abs(const nlopt_opt opt, double *xtol_ nlopt_result NLOPT_STDCALL nlopt_set_x_weights(nlopt_opt opt, const double *x_weights) { if (opt) { - nlopt_unset_errmsg(opt); unsigned i; + nlopt_unset_errmsg(opt); for (i = 0; i < opt->n; i++) { if (x_weights[i] <= 0) return NLOPT_INVALID_ARGS; From 42ce76054b5fd5e7ec67546f961505b83b52a1d1 Mon Sep 17 00:00:00 2001 From: Ivan Krylov Date: Thu, 25 Apr 2019 19:44:34 +0300 Subject: [PATCH 20/21] set_x_weights: provide informative error on w <= 0 --- src/api/options.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/options.c b/src/api/options.c index 94493e50..485921ad 100644 --- a/src/api/options.c +++ b/src/api/options.c @@ -643,7 +643,7 @@ nlopt_result NLOPT_STDCALL nlopt_set_x_weights(nlopt_opt opt, const double *x_we nlopt_unset_errmsg(opt); for (i = 0; i < opt->n; i++) { if (x_weights[i] <= 0) - return NLOPT_INVALID_ARGS; + return ERR(NLOPT_INVALID_ARGS, opt, "invalid negative weight"); } if (!opt->x_weights) { opt->x_weights = (double *) calloc(opt->n, sizeof(double)); @@ -659,7 +659,8 @@ nlopt_result NLOPT_STDCALL nlopt_set_x_weights(nlopt_opt opt, const double *x_we nlopt_result NLOPT_STDCALL nlopt_set_x_weights1(nlopt_opt opt, double x_weights) { - if (opt && x_weights > 0) { + if (x_weights <= 0) return ERR(NLOPT_INVALID_ARGS, opt, "invalid negative weight"); + if (opt) { unsigned i; nlopt_unset_errmsg(opt); if (!opt->x_weights) { From 5484d29488a3968cc9129da604123a571db57a6d Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 25 Apr 2019 17:15:01 -0400 Subject: [PATCH 21/21] tweaks --- src/api/options.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/api/options.c b/src/api/options.c index 485921ad..829d17a4 100644 --- a/src/api/options.c +++ b/src/api/options.c @@ -641,36 +641,31 @@ nlopt_result NLOPT_STDCALL nlopt_set_x_weights(nlopt_opt opt, const double *x_we if (opt) { unsigned i; nlopt_unset_errmsg(opt); - for (i = 0; i < opt->n; i++) { - if (x_weights[i] <= 0) + for (i = 0; i < opt->n; i++) + if (x_weights[i] < 0) return ERR(NLOPT_INVALID_ARGS, opt, "invalid negative weight"); - } - if (!opt->x_weights) { + if (!opt->x_weights && opt->n > 0) { opt->x_weights = (double *) calloc(opt->n, sizeof(double)); - if (!opt->x_weights) { - return NLOPT_OUT_OF_MEMORY; - } + if (!opt->x_weights) return NLOPT_OUT_OF_MEMORY; } - memcpy(opt->x_weights, x_weights, opt->n * sizeof(double)); + if (opt->n > 0) memcpy(opt->x_weights, x_weights, opt->n * sizeof(double)); return NLOPT_SUCCESS; } return NLOPT_INVALID_ARGS; } -nlopt_result NLOPT_STDCALL nlopt_set_x_weights1(nlopt_opt opt, double x_weights) +nlopt_result NLOPT_STDCALL nlopt_set_x_weights1(nlopt_opt opt, double x_weight) { - if (x_weights <= 0) return ERR(NLOPT_INVALID_ARGS, opt, "invalid negative weight"); if (opt) { unsigned i; + if (x_weight < 0) return ERR(NLOPT_INVALID_ARGS, opt, "invalid negative weight"); nlopt_unset_errmsg(opt); - if (!opt->x_weights) { + if (!opt->x_weights && opt->n > 0) { opt->x_weights = (double *) calloc(opt->n, sizeof(double)); - if (!opt->x_weights) { - return NLOPT_OUT_OF_MEMORY; - } + if (!opt->x_weights) return NLOPT_OUT_OF_MEMORY; } for (i = 0; i < opt->n; ++i) - opt->x_weights[i] = x_weights; + opt->x_weights[i] = x_weight; return NLOPT_SUCCESS; } return NLOPT_INVALID_ARGS; @@ -678,8 +673,9 @@ nlopt_result NLOPT_STDCALL nlopt_set_x_weights1(nlopt_opt opt, double x_weights) nlopt_result NLOPT_STDCALL nlopt_get_x_weights(const nlopt_opt opt, double *x_weights) { - nlopt_unset_errmsg(opt); - if (opt && (opt->n == 0 || x_weights)) { + if (opt) { + if (opt->n > 0 && !x_weights) return ERR(NLOPT_INVALID_ARGS, opt, "invalid NULL weights"); + nlopt_unset_errmsg(opt); if (opt->x_weights) { memcpy(x_weights, opt->x_weights, sizeof(double) * (opt->n)); } else {