未验证 提交 f10bb695 编写于 作者: S Steven G. Johnson 提交者: GitHub

add generic algorithm parameters API (#365)

* implement generic algorithm paameters

* add test of generic params

* check return value of test

* more const info in param functions

* docs

* python docs

* python and MMA/CCSA param docs

* whoops
上级 13fc60ae
......@@ -311,6 +311,13 @@ At each point **x**, MMA forms a local approximation using the gradient of *f* a
I also implemented another CCSA algorithm from the same paper, `NLOPT_LD_CCSAQ`: instead of constructing local MMA approximations, it constructs simple quadratic approximations (or rather, affine approximations plus a quadratic penalty term to stay conservative). This is the ccsa_quadratic code. It seems to have similar convergence rates to MMA for most problems, which is not surprising as they are both essentially similar. However, for the quadratic variant I implemented the possibility of [preconditioning](NLopt_Reference.md#preconditioning-with-approximate-hessians): including a user-supplied Hessian approximation in the local model. It is easy to incorporate this into the proof in Svanberg's paper, and to show that global convergence is still guaranteed as long as the user's "Hessian" is positive semidefinite, and it practice it can greatly improve convergence if the preconditioner is a good approximation for the real Hessian (at least for the eigenvectors of the largest eigenvalues).
The `NLOPT_LD_MMA` and `NLOPT_LD_CCSAQ` algorithms support the following internal parameters, which can be
specified using the [`nlopt_set_param` API](NLopt_Reference#Algorithm-specific_parameters.md):
* `inner_maxeval`: If ≥ 0, gives maximum number of "inner" iterations of the algorithm where it tries to ensure that its approximatations are "conservative"; defaults to `0` (no limit). It can be useful to specify a finite number (e.g. `5` or `10`) for this parameter if inaccuracies in your gradient or objective function are preventing the algorithm from making progress.
* `dual_algorithm` (defaults to `NLOPT_LD_MMA`), `dual_ftol_rel` (defaults to `1e-14`), `dual_ftol_abs` (defaults to `0`), `dual_xtol_rel` (defaults to `0`), `dual_xtol_abs` (defaults to `0`), `dual_maxeval` (defaults to `100000`): These specify how the algorithm internally solves the "dual" optimization problem for its approximate objective. Because this subsidiary solve requires no evaluations of the user's objective function, it is typically fast enough that we can solve it to high precision without worrying too much about the details. Howeve,r in high-dimensional problems you may notice that MMA/CCSA is taking a long time between optimization steps, in which case you may want to increase `dual_ftol_rel` or make other changes. If these parameters are not specified, NLopt takes them from the [subsidiary-optimizer algorithm](NLopt_Reference#localsubsidiary-optimization-algorithm) if that has been specified, and otherwise uses the defaults indicated here.
* `verbosity`: If ≥ 0, causes the algorithm to print internal status information on each iteration.
### SLSQP
Specified in NLopt as `NLOPT_LD_SLSQP`, this is a sequential quadratic programming (SQP) algorithm for nonlinearly constrained gradient-based optimization (supporting both inequality and equality constraints), based on the implementation by Dieter Kraft and described in:
......
......@@ -250,6 +250,21 @@ Request the number of evaluations.
In certain cases, the caller may wish to *force* the optimization to halt, for some reason unknown to NLopt. For example, if the user presses Ctrl-C, or there is an error of some sort in the objective function. You can do this by throwing *any* exception inside your objective/constraint functions: the exception will be caught, the optimization will be halted gracefully, and another exception (possibly not the same one) will be rethrown. See [Exceptions](#Exceptions.md), below. The C++ equivalent of `nlopt_forced_stop` from the [C API](NLopt_Reference#Forced_termination.md) is to throw an `nlopt::forced_stop` exception.
Algorithm-specific parameters
-----------------------------
Certain NLopt optimization algorithms allow you to specify additional parameters by calling
```
nlopt_result nlopt::opt::set_param(const char *name, double val);
bool nlopt::opt::has_param(const char *name);
double nlopt::opt::get_param(const char *name, double defaultval);
unsigned nlopt::opt::num_params();
const char *nlopt::opt::nth_param(unsigned n);
```
where the string `name` is the name of an algorithm-specific parameter and `val` is the value you are setting the parameter to. These functions are equivalent to the [C API](NLopt_Reference#Algorithm-specific_parameters.md) functions of the corresponding names.
Performing the optimization
---------------------------
......
......@@ -236,6 +236,20 @@ Request the number of evaluations.
In certain cases, the caller may wish to *force* the optimization to halt, for some reason unknown to NLopt. For example, if the user presses Ctrl-C, or there is an error of some sort in the objective function. You can do this by raising *any* exception inside your objective/constraint functions:the optimization will be halted gracefully, and the same exception will be raised to the caller. See [Exceptions](#exceptions), below. The Python equivalent of `nlopt_forced_stop` from the [C API](NLopt_Reference.md#forced-termination) is to throw an `nlopt.ForcedStop` exception.
Algorithm-specific parameters
-----------------------------
Certain NLopt optimization algorithms allow you to specify additional parameters by calling
```py
opt.set_param("name", val);
opt.has_param("name");
opt.get_param("name", defaultval);
opt.num_params();
opt.nth_param(n);
```
where the string `"name"` is the name of an algorithm-specific parameter and `val` is the value you are setting the parameter to. These functions are equivalent to the [C API](NLopt_Reference#Algorithm-specific_parameters.md) functions of the corresponding names.
Performing the optimization
---------------------------
......
......@@ -300,6 +300,32 @@ int nlopt_get_force_stop(nlopt_opt opt)
which returns the last force-stop value that was set since the last `nlopt_optimize`. The force-stop value is reset to zero at the beginning of `nlopt_optimize`. Passing `val=0` to `nlopt_set_force_stop` tells NLopt *not* to force a halt.
Algorithm-specific parameters
-----------------------------
Certain NLopt optimization algorithms allow you to specify additional parameters by calling
```c
nlopt_result nlopt_set_param(nlopt_opt opt, const char *name, double val);
```
where the string `name` is the name of an algorithm-specific parameter and `val` is the value you are setting the parameter to. For example, the MMA algorithm has a parameter `"inner_maxeval"`, an upper bound on the number of "inner" iterations of the algorithm, which you can set via `nlopt_set_param(opt, "inner_maxeval", 100)`.
You can also check whether a parameter is set or get the current value of a parameter with
```c
double nlopt_has_param(const nlopt_opt opt, const char *name);
double nlopt_get_param(const nlopt_opt opt, const char *name, double defaultval);
```
where `defaultval` is returned by `nlopt_get_param` if the parameter `name` has not been set.
To inspect the list of currently set parameters, you can use:
```c
unsigned nlopt_num_params(const nlopt_opt opt);
const char *nlopt_nth_param(const nlopt_opt opt, unsigned n);
```
which return the number of set parameters and the name of the `n`-th set parameters (from `0` to `num_params-1`), respectively.
Performing the optimization
---------------------------
......
......@@ -7,17 +7,17 @@
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* In this file we implement Svanberg's CCSA algorithm with the
......@@ -26,7 +26,7 @@
We also allow the user to specify an optional "preconditioner": an
approximate Hessian (which must be symmetric & positive
semidefinite) that can be added into the approximation. [X. Liang
and I went through the convergence proof in Svanberg's paper
and I went through the convergence proof in Svanberg's paper
and it does not seem to be modified by such preconditioning, as
long as the preconditioner eigenvalues are bounded above for all x.]
......@@ -80,7 +80,7 @@ static double dual_func(unsigned m, const double *y, double *grad, void *d_)
{
dual_data *d = (dual_data *) d_;
unsigned n = d->n;
const double *x = d->x, *lb = d->lb, *ub = d->ub, *sigma = d->sigma,
const double *x = d->x, *lb = d->lb, *ub = d->ub, *sigma = d->sigma,
*dfdx = d->dfdx;
const double *dfcdx = d->dfcdx;
double rho = d->rho, fval = d->fval;
......@@ -94,7 +94,7 @@ static double dual_func(unsigned m, const double *y, double *grad, void *d_)
val = d->gval = fval;
d->wval = 0;
for (i = 0; i < m; ++i)
for (i = 0; i < m; ++i)
val += y[i] * (gcval[i] = fcval[i]);
for (j = 0; j < n; ++j) {
......@@ -128,7 +128,7 @@ static double dual_func(unsigned m, const double *y, double *grad, void *d_)
if (xcur[j] > ub[j]) xcur[j] = ub[j];
else if (xcur[j] < lb[j]) xcur[j] = lb[j];
dx = xcur[j] - x[j];
/* function value: */
dx2 = dx * dx;
val += v * dx + 0.5 * u * dx2 / sigma2;
......@@ -152,7 +152,7 @@ static double dual_func(unsigned m, const double *y, double *grad, void *d_)
/* compute g(x - x0) and its gradient */
static double gfunc(unsigned n, double f, const double *dfdx,
double rho, const double *sigma,
const double *x0,
const double *x0,
nlopt_precond pre, void *pre_data, double *scratch,
const double *x, double *grad)
{
......@@ -199,7 +199,7 @@ static void gi(unsigned m, double *result,
result[i] = gfunc(n, d->fcval[i], d->dfcdx + i*n, d->rhoc[i],
d->sigma,
d->x,
d->prec ? d->prec[i] : NULL,
d->prec ? d->prec[i] : NULL,
d->prec_data ? d->prec_data[i] : NULL,
d->scratch,
x, grad);
......@@ -212,13 +212,13 @@ nlopt_result ccsa_quadratic_minimize(
unsigned n, nlopt_func f, void *f_data,
unsigned m, nlopt_constraint *fc,
nlopt_precond pre,
nlopt_precond pre,
const double *lb, const double *ub, /* bounds */
double *x, /* in: initial guess, out: minimizer */
double *minf,
nlopt_stopping *stop,
nlopt_opt dual_opt)
nlopt_opt dual_opt, int inner_maxeval, unsigned verbose)
{
nlopt_result ret = NLOPT_SUCCESS;
double *xcur, rho, *sigma, *dfdx, *dfdx_cur, *xprev, *xprevprev, fcur;
......@@ -233,6 +233,8 @@ nlopt_result ccsa_quadratic_minimize(
unsigned no_precond;
nlopt_opt pre_opt = NULL;
verbose = MAX(ccsa_verbose, verbose);
m = nlopt_count_constraints(mfc = m, fc);
if (nlopt_get_dimension(dual_opt) != m) {
nlopt_stop_msg(stop, "dual optimizer has wrong dimension %d != %d",
......@@ -302,7 +304,7 @@ nlopt_result ccsa_quadratic_minimize(
pre_ub = pre_lb + n;
pre_opt = nlopt_create(nlopt_get_algorithm(dual_opt), n);
if (!pre_opt) {
if (!pre_opt) {
nlopt_stop_msg(stop, "failure creating precond. optimizer");
ret = NLOPT_FAILURE;
goto done;
......@@ -318,7 +320,7 @@ nlopt_result ccsa_quadratic_minimize(
ret = nlopt_set_maxeval(pre_opt, nlopt_get_maxeval(dual_opt));
if (ret < 0) goto done;
}
for (j = 0; j < n; ++j) {
if (nlopt_isinf(ub[j]) || nlopt_isinf(lb[j]))
sigma[j] = 1.0; /* arbitrary default */
......@@ -355,7 +357,7 @@ nlopt_result ccsa_quadratic_minimize(
constraint weighted by 1e40 -- basically, minimizing the
unfeasible constraint until it becomes feasible or until we at
least obtain a step towards a feasible point.
Svanberg suggested a different approach in his 1987 paper, basically
introducing additional penalty variables for unfeasible constraints,
but this is easier to implement and at least as efficient. */
......@@ -370,11 +372,12 @@ nlopt_result ccsa_quadratic_minimize(
nlopt_remove_equality_constraints(dual_opt);
while (1) { /* outer iterations */
int inner_nevals = 0;
double fprev = fcur;
if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP;
else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED;
else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED;
else if (feasible && *minf < stop->minf_max)
else if (feasible && *minf < stop->minf_max)
ret = NLOPT_MINF_MAX_REACHED;
if (ret != NLOPT_SUCCESS) goto done;
if (++k > 1) memcpy(xprevprev, xprev, sizeof(double) * n);
......@@ -393,15 +396,15 @@ nlopt_result ccsa_quadratic_minimize(
ccsa_verbose = 0; /* no recursive verbosity */
reti = nlopt_optimize_limited(dual_opt, y, &min_dual,
0,
stop->maxtime
- (nlopt_seconds()
stop->maxtime
- (nlopt_seconds()
- stop->start));
ccsa_verbose = save_verbose;
if (reti < 0 || reti == NLOPT_MAXTIME_REACHED) {
ret = reti;
goto done;
}
dual_func(m, y, NULL, &dd); /* evaluate final xcur etc. */
}
else {
......@@ -432,17 +435,18 @@ nlopt_result ccsa_quadratic_minimize(
gi(m, dd.gcval, n, xcur, NULL, &dd);
}
if (ccsa_verbose) {
if (verbose) {
printf("CCSA dual converged in %d iters to g=%g:\n",
dd.count, dd.gval);
for (i = 0; i < MIN(ccsa_verbose, m); ++i)
for (i = 0; i < MIN(verbose, m); ++i)
printf(" CCSA y[%u]=%g, gc[%u]=%g\n",
i, y[i], i, dd.gcval[i]);
}
fcur = f(n, xcur, dfdx_cur, f_data);
++ *(stop->nevals_p);
if (nlopt_stop_forced(stop)) {
++inner_nevals;
if (nlopt_stop_forced(stop)) {
ret = NLOPT_FORCED_STOP; goto done; }
feasible_cur = 1; infeasibility_cur = 0;
inner_done = dd.gval >= fcur;
......@@ -450,24 +454,26 @@ nlopt_result ccsa_quadratic_minimize(
nlopt_eval_constraint(fcval_cur + i, dfcdx_cur + i*n,
fc + ifc, n, xcur);
i += fc[ifc].m;
if (nlopt_stop_forced(stop)) {
if (nlopt_stop_forced(stop)) {
ret = NLOPT_FORCED_STOP; goto done; }
}
for (i = ifc = 0; ifc < mfc; ++ifc) {
unsigned i0 = i, inext = i + fc[ifc].m;
for (; i < inext; ++i) {
feasible_cur = feasible_cur
feasible_cur = feasible_cur
&& fcval_cur[i] <= fc[ifc].tol[i-i0];
inner_done = inner_done &&
inner_done = inner_done &&
(dd.gcval[i] >= fcval_cur[i]);
if (fcval_cur[i] > infeasibility_cur)
infeasibility_cur = fcval_cur[i];
}
}
inner_done = inner_done || (inner_maxeval > 0 && inner_nevals == inner_maxeval);
if ((fcur < *minf && (inner_done || feasible_cur || !feasible))
|| (!feasible && infeasibility_cur < infeasibility)) {
if (ccsa_verbose && !feasible_cur)
if (verbose && !feasible_cur)
printf("CCSA - using infeasible point?\n");
dd.fval = *minf = fcur;
infeasibility = infeasibility_cur;
......@@ -475,7 +481,7 @@ nlopt_result ccsa_quadratic_minimize(
memcpy(x, xcur, sizeof(double)*n);
memcpy(dfdx, dfdx_cur, sizeof(double)*n);
memcpy(dfcdx, dfcdx_cur, sizeof(double)*n*m);
/* once we have reached a feasible solution, the
algorithm should never make the solution infeasible
again (if inner_done), although the constraints may
......@@ -493,7 +499,7 @@ nlopt_result ccsa_quadratic_minimize(
if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP;
else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED;
else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED;
else if (feasible && *minf < stop->minf_max)
else if (feasible && *minf < stop->minf_max)
ret = NLOPT_MINF_MAX_REACHED;
if (ret != NLOPT_SUCCESS) goto done;
......@@ -503,14 +509,14 @@ nlopt_result ccsa_quadratic_minimize(
rho = MIN(10*rho, 1.1 * (rho + (fcur-dd.gval) / dd.wval));
for (i = 0; i < m; ++i)
if (fcval_cur[i] > dd.gcval[i])
rhoc[i] =
MIN(10*rhoc[i],
1.1 * (rhoc[i] + (fcval_cur[i]-dd.gcval[i])
rhoc[i] =
MIN(10*rhoc[i],
1.1 * (rhoc[i] + (fcval_cur[i]-dd.gcval[i])
/ dd.wval));
if (ccsa_verbose)
if (verbose)
printf("CCSA inner iteration: rho -> %g\n", rho);
for (i = 0; i < MIN(ccsa_verbose, m); ++i)
for (i = 0; i < MIN(verbose, m); ++i)
printf(" CCSA rhoc[%u] -> %g\n", i,rhoc[i]);
}
......@@ -519,14 +525,14 @@ nlopt_result ccsa_quadratic_minimize(
if (nlopt_stop_x(stop, xcur, xprev))
ret = NLOPT_XTOL_REACHED;
if (ret != NLOPT_SUCCESS) goto done;
/* update rho and sigma for iteration k+1 */
rho = MAX(0.1 * rho, CCSA_RHOMIN);
if (ccsa_verbose)
if (verbose)
printf("CCSA outer iteration: rho -> %g\n", rho);
for (i = 0; i < m; ++i)
rhoc[i] = MAX(0.1 * rhoc[i], CCSA_RHOMIN);
for (i = 0; i < MIN(ccsa_verbose, m); ++i)
for (i = 0; i < MIN(verbose, m); ++i)
printf(" CCSA rhoc[%u] -> %g\n", i, rhoc[i]);
if (k > 1) {
for (j = 0; j < n; ++j) {
......@@ -540,8 +546,8 @@ nlopt_result ccsa_quadratic_minimize(
sigma[j] = MAX(sigma[j], 1e-8*(ub[j]-lb[j]));
}
}
for (j = 0; j < MIN(ccsa_verbose, n); ++j)
printf(" CCSA sigma[%u] -> %g\n",
for (j = 0; j < MIN(verbose, n); ++j)
printf(" CCSA sigma[%u] -> %g\n",
j, sigma[j]);
}
}
......
......@@ -7,17 +7,17 @@
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
......@@ -60,7 +60,7 @@ static double dual_func(unsigned m, const double *y, double *grad, void *d_)
{
dual_data *d = (dual_data *) d_;
unsigned n = d->n;
const double *x = d->x, *lb = d->lb, *ub = d->ub, *sigma = d->sigma,
const double *x = d->x, *lb = d->lb, *ub = d->ub, *sigma = d->sigma,
*dfdx = d->dfdx;
const double *dfcdx = d->dfcdx;
double rho = d->rho, fval = d->fval;
......@@ -74,7 +74,7 @@ static double dual_func(unsigned m, const double *y, double *grad, void *d_)
val = d->gval = fval;
d->wval = 0;
for (i = 0; i < m; ++i)
for (i = 0; i < m; ++i)
val += y[i] * (gcval[i] = nlopt_isnan(fcval[i]) ? 0 : fcval[i]);
for (j = 0; j < n; ++j) {
......@@ -112,7 +112,7 @@ static double dual_func(unsigned m, const double *y, double *grad, void *d_)
if (xcur[j] > x[j]+0.9*sigma[j]) xcur[j] = x[j]+0.9*sigma[j];
else if (xcur[j] < x[j]-0.9*sigma[j]) xcur[j] = x[j]-0.9*sigma[j];
dx = xcur[j] - x[j];
/* function value: */
dx2 = dx * dx;
denominv = 1.0 / (sigma2 - dx2);
......@@ -124,7 +124,7 @@ static double dual_func(unsigned m, const double *y, double *grad, void *d_)
* denominv;
d->wval += 0.5 * dx2 * denominv;
for (i = 0; i < m; ++i) if (!nlopt_isnan(fcval[i]))
gcval[i] += (dfcdx[i*n+j] * c + (fabs(dfcdx[i*n+j])*sigma[j]
gcval[i] += (dfcdx[i*n+j] * c + (fabs(dfcdx[i*n+j])*sigma[j]
+ 0.5*rhoc[i]) * dx2)
* denominv;
}
......@@ -148,7 +148,7 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
double *x, /* in: initial guess, out: minimizer */
double *minf,
nlopt_stopping *stop,
nlopt_opt dual_opt)
nlopt_opt dual_opt, int inner_maxeval, unsigned verbose)
{
nlopt_result ret = NLOPT_SUCCESS;
double *xcur, rho, *sigma, *dfdx, *dfdx_cur, *xprev, *xprevprev, fcur;
......@@ -160,6 +160,8 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
double infeasibility;
unsigned mfc;
verbose = MAX(mma_verbose, verbose);
m = nlopt_count_constraints(mfc = m, fc);
if (nlopt_get_dimension(dual_opt) != m) {
nlopt_stop_msg(stop, "dual optimizer has wrong dimension %d != %d",
......@@ -231,7 +233,7 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
constraint weighted by 1e40 -- basically, minimizing the
unfeasible constraint until it becomes feasible or until we at
least obtain a step towards a feasible point.
Svanberg suggested a different approach in his 1987 paper, basically
introducing additional penalty variables for unfeasible constraints,
but this is easier to implement and at least as efficient. */
......@@ -246,11 +248,12 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
nlopt_remove_equality_constraints(dual_opt);
while (1) { /* outer iterations */
int inner_nevals = 0;
double fprev = fcur;
if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP;
else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED;
else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED;
else if (feasible && *minf < stop->minf_max)
else if (feasible && *minf < stop->minf_max)
ret = NLOPT_MINF_MAX_REACHED;
if (ret != NLOPT_SUCCESS) goto done;
if (++k > 1) memcpy(xprevprev, xprev, sizeof(double) * n);
......@@ -269,7 +272,7 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
mma_verbose = 0; /* no recursive verbosity */
reti = nlopt_optimize_limited(dual_opt, y, &min_dual,
0,
stop->maxtime - (nlopt_seconds()
stop->maxtime - (nlopt_seconds()
- stop->start));
mma_verbose = save_verbose;
if (reti < 0 || reti == NLOPT_MAXTIME_REACHED) {
......@@ -278,17 +281,18 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
}
dual_func(m, y, NULL, &dd); /* evaluate final xcur etc. */
if (mma_verbose) {
if (verbose) {
printf("MMA dual converged in %d iterations to g=%g:\n",
dd.count, dd.gval);
for (i = 0; i < MIN(mma_verbose, m); ++i)
for (i = 0; i < MIN(verbose, m); ++i)
printf(" MMA y[%u]=%g, gc[%u]=%g\n",
i, y[i], i, dd.gcval[i]);
}
fcur = f(n, xcur, dfdx_cur, f_data);
++ *(stop->nevals_p);
if (nlopt_stop_forced(stop)) {
++inner_nevals;
if (nlopt_stop_forced(stop)) {
ret = NLOPT_FORCED_STOP; goto done; }
feasible_cur = 1; infeasibility_cur = 0;
new_infeasible_constraint = 0;
......@@ -297,17 +301,17 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
nlopt_eval_constraint(fcval_cur + i, dfcdx_cur + i*n,
fc + ifc, n, xcur);
i += fc[ifc].m;
if (nlopt_stop_forced(stop)) {
if (nlopt_stop_forced(stop)) {
ret = NLOPT_FORCED_STOP; goto done; }
}
for (i = ifc = 0; ifc < mfc; ++ifc) {
unsigned i0 = i, inext = i + fc[ifc].m;
for (; i < inext; ++i)
if (!nlopt_isnan(fcval_cur[i])) {
feasible_cur = feasible_cur
feasible_cur = feasible_cur
&& (fcval_cur[i] <= fc[ifc].tol[i-i0]);
if (!nlopt_isnan(fcval[i]))
inner_done = inner_done &&
inner_done = inner_done &&
(dd.gcval[i] >= fcval_cur[i]);
else if (fcval_cur[i] > 0)
new_infeasible_constraint = 1;
......@@ -316,9 +320,11 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
}
}
inner_done = inner_done || (inner_maxeval > 0 && inner_nevals == inner_maxeval);
if ((fcur < *minf && (inner_done || feasible_cur || !feasible))
|| (!feasible && infeasibility_cur < infeasibility)) {
if (mma_verbose && !feasible_cur)
if (verbose && !feasible_cur)
printf("MMA - using infeasible point?\n");
dd.fval = *minf = fcur;
infeasibility = infeasibility_cur;
......@@ -326,7 +332,7 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
memcpy(x, xcur, sizeof(double)*n);
memcpy(dfdx, dfdx_cur, sizeof(double)*n);
memcpy(dfcdx, dfcdx_cur, sizeof(double)*n*m);
/* once we have reached a feasible solution, the
algorithm should never make the solution infeasible
again (if inner_done), although the constraints may
......@@ -345,7 +351,7 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP;
else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED;
else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED;
else if (feasible && *minf < stop->minf_max)
else if (feasible && *minf < stop->minf_max)
ret = NLOPT_MINF_MAX_REACHED;
if (ret != NLOPT_SUCCESS) goto done;
......@@ -355,14 +361,14 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
rho = MIN(10*rho, 1.1 * (rho + (fcur-dd.gval) / dd.wval));
for (i = 0; i < m; ++i)
if (!nlopt_isnan(fcval_cur[i]) && fcval_cur[i] > dd.gcval[i])
rhoc[i] =
MIN(10*rhoc[i],
1.1 * (rhoc[i] + (fcval_cur[i]-dd.gcval[i])
rhoc[i] =
MIN(10*rhoc[i],
1.1 * (rhoc[i] + (fcval_cur[i]-dd.gcval[i])
/ dd.wval));
if (mma_verbose)
if (verbose)
printf("MMA inner iteration: rho -> %g\n", rho);
for (i = 0; i < MIN(mma_verbose, m); ++i)
for (i = 0; i < MIN(verbose, m); ++i)
printf(" MMA rhoc[%u] -> %g\n", i,rhoc[i]);
}
......@@ -371,14 +377,14 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
if (nlopt_stop_x(stop, xcur, xprev))
ret = NLOPT_XTOL_REACHED;
if (ret != NLOPT_SUCCESS) goto done;
/* update rho and sigma for iteration k+1 */
rho = MAX(0.1 * rho, MMA_RHOMIN);
if (mma_verbose)
if (verbose)
printf("MMA outer iteration: rho -> %g\n", rho);
for (i = 0; i < m; ++i)
rhoc[i] = MAX(0.1 * rhoc[i], MMA_RHOMIN);
for (i = 0; i < MIN(mma_verbose, m); ++i)
for (i = 0; i < MIN(verbose, m); ++i)
printf(" MMA rhoc[%u] -> %g\n", i, rhoc[i]);
if (k > 1) {
for (j = 0; j < n; ++j) {
......@@ -390,8 +396,8 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
sigma[j] = MAX(sigma[j], 0.01*(ub[j]-lb[j]));
}
}
for (j = 0; j < MIN(mma_verbose, n); ++j)
printf(" MMA sigma[%u] -> %g\n",
for (j = 0; j < MIN(verbose, n); ++j)
printf(" MMA sigma[%u] -> %g\n",
j, sigma[j]);
}
}
......
......@@ -7,17 +7,17 @@
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MMA_H
......@@ -32,6 +32,7 @@ extern "C"
#endif /* __cplusplus */
extern unsigned mma_verbose;
extern unsigned ccsa_verbose;
nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
unsigned m, nlopt_constraint *fc,
......@@ -39,7 +40,7 @@ nlopt_result mma_minimize(unsigned n, nlopt_func f, void *f_data,
double *x, /* in: initial guess, out: minimizer */
double *minf,
nlopt_stopping *stop,
nlopt_opt dual_opt);
nlopt_opt dual_opt, int inner_maxeval, unsigned verbose);
nlopt_result ccsa_quadratic_minimize(
unsigned n, nlopt_func f, void *f_data,
......@@ -51,7 +52,7 @@ nlopt_result ccsa_quadratic_minimize(
double *x, /* in: initial guess, out: minimizer */
double *minf,
nlopt_stopping *stop,
nlopt_opt dual_opt);
nlopt_opt dual_opt, int inner_maxeval, unsigned verbose);
#ifdef __cplusplus
} /* extern "C" */
......
......@@ -7,17 +7,17 @@
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// C++ style wrapper around NLopt API
......@@ -57,7 +57,7 @@ namespace nlopt {
std::vector<double> &grad, void *data);
//////////////////////////////////////////////////////////////////////
// NLopt-specific exceptions (corresponding to error codes):
class roundoff_limited : public std::runtime_error {
public:
......@@ -74,7 +74,7 @@ namespace nlopt {
class opt {
private:
nlopt_opt o;
void mythrow(nlopt_result ret) const {
switch (ret) {
case NLOPT_FAILURE: throw std::runtime_error(get_errmsg() ? get_errmsg() : "nlopt failure");
......@@ -94,7 +94,7 @@ namespace nlopt {
} myfunc_data;
// free/destroy f_data in nlopt_destroy and nlopt_copy, respectively
static void *free_myfunc_data(void *p) {
static void *free_myfunc_data(void *p) {
myfunc_data *d = (myfunc_data *) p;
if (d) {
if (d->f_data && d->munge_destroy) d->munge_destroy(d->f_data);
......@@ -206,12 +206,12 @@ namespace nlopt {
public:
// Constructors etc.
opt() : o(NULL), xtmp(0), gradtmp(0), gradtmp0(0),
opt() : o(NULL), xtmp(0), gradtmp(0), gradtmp0(0),
last_result(nlopt::FAILURE), last_optf(HUGE_VAL),
forced_stop_reason(NLOPT_FORCED_STOP) {}
~opt() { nlopt_destroy(o); }
opt(algorithm a, unsigned n) :
o(nlopt_create(nlopt_algorithm(a), n)),
opt(algorithm a, unsigned n) :
o(nlopt_create(nlopt_algorithm(a), n)),
xtmp(0), gradtmp(0), gradtmp0(0),
last_result(nlopt::FAILURE), last_optf(HUGE_VAL),
forced_stop_reason(NLOPT_FORCED_STOP) {
......@@ -229,7 +229,7 @@ namespace nlopt {
if (!o) throw std::bad_alloc();
nlopt_set_munge(o, free_myfunc_data, dup_myfunc_data);
}
opt(const opt& f) : o(nlopt_copy(f.o)),
opt(const opt& f) : o(nlopt_copy(f.o)),
xtmp(f.xtmp), gradtmp(f.gradtmp), gradtmp0(0),
last_result(f.last_result), last_optf(f.last_optf),
forced_stop_reason(f.forced_stop_reason) {
......@@ -355,13 +355,13 @@ namespace nlopt {
mythrow(nlopt_add_inequality_constraint(o, myvfunc, d, tol));
alloc_tmp();
}
void add_inequality_mconstraint(mfunc mf, void *f_data,
void add_inequality_mconstraint(mfunc mf, void *f_data,
const std::vector<double> &tol) {
myfunc_data *d = new myfunc_data;
if (!d) throw std::bad_alloc();
d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
d->munge_destroy = d->munge_copy = NULL;
mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d,
mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d,
tol.empty() ? NULL : &tol[0]));
}
......@@ -384,18 +384,18 @@ namespace nlopt {
mythrow(nlopt_add_equality_constraint(o, myvfunc, d, tol));
alloc_tmp();
}
void add_equality_mconstraint(mfunc mf, void *f_data,
void add_equality_mconstraint(mfunc mf, void *f_data,
const std::vector<double> &tol) {
myfunc_data *d = new myfunc_data;
if (!d) throw std::bad_alloc();
d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
d->munge_destroy = d->munge_copy = NULL;
mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d,
mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d,
tol.empty() ? NULL : &tol[0]));
}
// For internal use in SWIG wrappers (see also above)
void add_inequality_constraint(func f, void *f_data,
void add_inequality_constraint(func f, void *f_data,
nlopt_munge md, nlopt_munge mc,
double tol=0) {
myfunc_data *d = new myfunc_data;
......@@ -404,7 +404,7 @@ namespace nlopt {
d->munge_destroy = md; d->munge_copy = mc;
mythrow(nlopt_add_inequality_constraint(o, myfunc, d, tol));
}
void add_equality_constraint(func f, void *f_data,
void add_equality_constraint(func f, void *f_data,
nlopt_munge md, nlopt_munge mc,
double tol=0) {
myfunc_data *d = new myfunc_data;
......@@ -413,27 +413,33 @@ namespace nlopt {
d->munge_destroy = md; d->munge_copy = mc;
mythrow(nlopt_add_equality_constraint(o, myfunc, d, tol));
}
void add_inequality_mconstraint(mfunc mf, void *f_data,
void add_inequality_mconstraint(mfunc mf, void *f_data,
nlopt_munge md, nlopt_munge mc,
const std::vector<double> &tol) {
myfunc_data *d = new myfunc_data;
if (!d) throw std::bad_alloc();
d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
d->munge_destroy = md; d->munge_copy = mc;
mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d,
mythrow(nlopt_add_inequality_mconstraint(o, tol.size(), mymfunc, d,
tol.empty() ? NULL : &tol[0]));
}
void add_equality_mconstraint(mfunc mf, void *f_data,
void add_equality_mconstraint(mfunc mf, void *f_data,
nlopt_munge md, nlopt_munge mc,
const std::vector<double> &tol) {
myfunc_data *d = new myfunc_data;
if (!d) throw std::bad_alloc();
d->o = this; d->mf = mf; d->f_data = f_data; d->f = NULL; d->vf = NULL;
d->munge_destroy = md; d->munge_copy = mc;
mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d,
mythrow(nlopt_add_equality_mconstraint(o, tol.size(), mymfunc, d,
tol.empty() ? NULL : &tol[0]));
}
void set_param(const char *name, double val) { mythrow(nlopt_set_param(o, name, val)); }
double get_param(const char *name, double defaultval) const { return nlopt_get_param(o, name, defaultval); }
bool has_param(const char *name) const { return bool(nlopt_has_param(o, name)); }
const char *nth_param(unsigned n) const { return nlopt_nth_param(o, n); }
unsigned num_params() const { return nlopt_num_params(o); }
#define NLOPT_GETSET_VEC(name) \
void set_##name(double val) { \
mythrow(nlopt_set_##name##1(o, val)); \
......@@ -486,7 +492,7 @@ namespace nlopt {
NLOPT_GETSET(int, force_stop)
void force_stop() { set_force_stop(1); }
const char *get_errmsg() const {
const char *get_errmsg() const {
if (!o) throw std::runtime_error("uninitialized nlopt::opt");
return nlopt_get_errmsg(o);
}
......@@ -503,7 +509,7 @@ namespace nlopt {
NLOPT_GETSET_VEC(initial_step)
void set_default_initial_step(const std::vector<double> &x) {
nlopt_result ret
nlopt_result ret
= nlopt_set_default_initial_step(o, x.empty() ? NULL : &x[0]);
mythrow(ret);
}
......
......@@ -7,17 +7,17 @@
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NLOPT_INTERNAL_H
......@@ -32,6 +32,11 @@ extern "C" {
/*********************************************************************/
typedef struct {
char *name;
double val;
} nlopt_opt_param;
struct nlopt_opt_s {
nlopt_algorithm algorithm; /* the optimization algorithm (immutable) */
unsigned n; /* the dimension of the problem (immutable) */
......@@ -41,6 +46,9 @@ extern "C" {
nlopt_precond pre; /* optional preconditioner for f (NULL if none) */
int maximize; /* nonzero if we are maximizing, not minimizing */
nlopt_opt_param *params;
unsigned nparams;
double *lb, *ub; /* lower and upper bounds (length n) */
unsigned m; /* number of inequality constraints */
......
......@@ -216,6 +216,12 @@ NLOPT_EXTERN(unsigned) nlopt_get_dimension(const nlopt_opt opt);
NLOPT_EXTERN(const char *) nlopt_get_errmsg(nlopt_opt opt);
/* generic algorithm parameters: */
NLOPT_EXTERN(nlopt_result) nlopt_set_param(nlopt_opt opt, const char *name, double val);
NLOPT_EXTERN(double) nlopt_get_param(const nlopt_opt opt, const char *name, double defaultval);
NLOPT_EXTERN(int) nlopt_has_param(const nlopt_opt opt, const char *name);
NLOPT_EXTERN(unsigned) nlopt_num_params(const nlopt_opt opt);
NLOPT_EXTERN(const char *) nlopt_nth_param(const nlopt_opt opt, unsigned n);
/* constraints: */
......
......@@ -441,7 +441,7 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf)
case NLOPT_GN_DIRECT_L_RAND:
if (!finite_domain(n, lb, ub))
RETURN_ERR(NLOPT_INVALID_ARGS, opt, "finite domain required for global algorithm");
return cdirect(ni, f, f_data, lb, ub, x, minf, &stop, 0.0, (algorithm != NLOPT_GN_DIRECT) + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
return cdirect(ni, f, f_data, lb, ub, x, minf, &stop, nlopt_get_param(opt, "magic_eps", 0.0), (algorithm != NLOPT_GN_DIRECT) + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
+ 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
case NLOPT_GN_DIRECT_NOSCAL:
......@@ -449,7 +449,7 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf)
case NLOPT_GN_DIRECT_L_RAND_NOSCAL:
if (!finite_domain(n, lb, ub))
RETURN_ERR(NLOPT_INVALID_ARGS, opt, "finite domain required for global algorithm");
return cdirect_unscaled(ni, f, f_data, lb, ub, x, minf, &stop, 0.0, (algorithm != NLOPT_GN_DIRECT) + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
return cdirect_unscaled(ni, f, f_data, lb, ub, x, minf, &stop, nlopt_get_param(opt, "magic_eps", 0.0), (algorithm != NLOPT_GN_DIRECT) + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT))
+ 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT)));
case NLOPT_GN_ORIG_DIRECT:
......@@ -464,7 +464,10 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf)
dret = direct_optimize(f_direct, opt, ni, lb, ub, x, minf,
stop.maxeval, -1,
stop.start, stop.maxtime,
0.0, 0.0, pow(stop.xtol_rel, (double) n), -1.0, stop.force_stop, stop.minf_max, 0.0, NULL, algorithm == NLOPT_GN_ORIG_DIRECT ? DIRECT_ORIGINAL : DIRECT_GABLONSKY);
nlopt_get_param(opt, "magic_eps", 0.0), nlopt_get_param(opt, "magic_eps_abs", 0.0),
pow(stop.xtol_rel, (double) n), nlopt_get_param(opt, "sigma_reltol", -1.0), stop.force_stop,
stop.minf_max, nlopt_get_param(opt, "fglobal_reltol", 0.0),
NULL, algorithm == NLOPT_GN_ORIG_DIRECT ? DIRECT_ORIGINAL : DIRECT_GABLONSKY);
free(opt->work);
opt->work = NULL;
switch (dret) {
......@@ -567,7 +570,7 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf)
double step;
if (initial_step(opt, x, &step) != NLOPT_SUCCESS)
return NLOPT_OUT_OF_MEMORY;
return praxis_(0.0, DBL_EPSILON, step, ni, x, f_bound, opt, &stop, minf);
return praxis_(nlopt_get_param(opt, "t0_tol", 0.0), DBL_EPSILON, step, ni, x, f_bound, opt, &stop, minf);
}
case NLOPT_LD_LBFGS:
......@@ -640,18 +643,21 @@ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf)
nlopt_opt dual_opt;
nlopt_result ret;
#define LO(param, def) (opt->local_opt ? opt->local_opt->param : (def))
dual_opt = nlopt_create(LO(algorithm, nlopt_local_search_alg_deriv), nlopt_count_constraints(opt->m, opt->fc));
dual_opt = nlopt_create((nlopt_algorithm)nlopt_get_param(opt, "dual_algorithm", LO(algorithm, nlopt_local_search_alg_deriv)),
nlopt_count_constraints(opt->m, opt->fc));
if (!dual_opt)
RETURN_ERR(NLOPT_FAILURE, opt, "failed creating dual optimizer");
nlopt_set_ftol_rel(dual_opt, LO(ftol_rel, 1e-14));
nlopt_set_ftol_abs(dual_opt, LO(ftol_abs, 0.0));
nlopt_set_maxeval(dual_opt, LO(maxeval, 100000));
nlopt_set_ftol_rel(dual_opt, nlopt_get_param(opt, "dual_ftol_rel", LO(ftol_rel, 1e-14)));
nlopt_set_ftol_abs(dual_opt, nlopt_get_param(opt, "dual_ftol_abs", LO(ftol_abs, 0.0)));
nlopt_set_xtol_rel(dual_opt, nlopt_get_param(opt, "dual_xtol_rel", 0.0));
nlopt_set_xtol_abs1(dual_opt, nlopt_get_param(opt, "dual_xtol_abs", 0.0));
nlopt_set_maxeval(dual_opt, nlopt_get_param(opt, "dual_maxeval", LO(maxeval, 100000)));
#undef LO
if (algorithm == NLOPT_LD_MMA)
ret = mma_minimize(n, f, f_data, opt->m, opt->fc, lb, ub, x, minf, &stop, dual_opt);
ret = mma_minimize(n, f, f_data, opt->m, opt->fc, lb, ub, x, minf, &stop, dual_opt, (int)nlopt_get_param(opt, "inner_maxeval",0), (unsigned)nlopt_get_param(opt, "verbosity",0));
else
ret = ccsa_quadratic_minimize(n, f, f_data, opt->m, opt->fc, opt->pre, lb, ub, x, minf, &stop, dual_opt);
ret = ccsa_quadratic_minimize(n, f, f_data, opt->m, opt->fc, opt->pre, lb, ub, x, minf, &stop, dual_opt, (int)nlopt_get_param(opt, "inner_maxeval",0), (unsigned)nlopt_get_param(opt, "verbosity",0));
nlopt_destroy(dual_opt);
return ret;
}
......
......@@ -49,6 +49,9 @@ void NLOPT_STDCALL nlopt_destroy(nlopt_opt opt)
free(opt->fc[i].tol);
for (i = 0; i < opt->p; ++i)
free(opt->h[i].tol);
for (i = 0; i < opt->nparams; ++i)
free(opt->params[i].name);
free(opt->params);
free(opt->lb);
free(opt->ub);
free(opt->xtol_abs);
......@@ -85,6 +88,8 @@ nlopt_opt NLOPT_STDCALL nlopt_create(nlopt_algorithm algorithm, unsigned n)
opt->fc = NULL;
opt->p = opt->p_alloc = 0;
opt->h = NULL;
opt->params = NULL;
opt->nparams = 0;
opt->stopval = -HUGE_VAL;
opt->ftol_rel = opt->ftol_abs = 0;
......@@ -143,6 +148,8 @@ nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt)
nopt->work = NULL;
nopt->errmsg = NULL;
nopt->force_stop_child = NULL;
nopt->params = NULL;
nopt->nparams = 0;
munge = nopt->munge_on_copy;
if (munge && nopt->f_data)
......@@ -217,6 +224,19 @@ nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt)
}
}
if (opt->nparams) {
nopt->nparams = opt->nparams;
nopt->params = (nlopt_opt_param *) calloc(opt->nparams, sizeof(nlopt_opt_param));
if (!nopt->params) goto oom;
for (i = 0; i < opt->nparams; ++i) {
size_t len = strlen(opt->params[i].name) + 1;
nopt->params[i].name = (char *) malloc(len);
if (!nopt->params[i].name) goto oom;
memcpy(nopt->params[i].name, opt->params[i].name, len);
nopt->params[i].val = opt->params[i].val;
}
}
if (opt->local_opt) {
nopt->local_opt = nlopt_copy(opt->local_opt);
if (!nopt->local_opt)
......@@ -238,6 +258,65 @@ nlopt_opt NLOPT_STDCALL nlopt_copy(const nlopt_opt opt)
return NULL;
}
/*************************************************************************/
/* generic algorithm parameters, implemented as a simple array of (name,val)
pairs that can interpreted as needed by individual algorithms.
(No point in a fancier data structure since only a handful of these
should be set in practice). */
nlopt_result nlopt_set_param(nlopt_opt opt, const char *name, double val) {
size_t len;
unsigned i;
if (!opt) RETURN_ERR(NLOPT_INVALID_ARGS, opt, "invalid NULL opt");
if (!name) RETURN_ERR(NLOPT_INVALID_ARGS, opt, "invalid NULL parameter name");
len = strnlen(name, 1024) + 1;
if (len > 1024) RETURN_ERR(NLOPT_INVALID_ARGS, opt, "parameter name must be < 1024 bytes");
for (i = 0; i < opt->nparams; ++i)
if (!strcmp(name, opt->params[i].name))
break;
if (i == opt->nparams) { /* allocate new parameter */
opt->nparams++;
opt->params = (nlopt_opt_param *) realloc(opt->params, sizeof(nlopt_opt_param) * opt->nparams);
if (!opt->params) return NLOPT_OUT_OF_MEMORY;
opt->params[i].name = (char *) malloc(len);
if (!opt->params[i].name) return NLOPT_OUT_OF_MEMORY;
memcpy(opt->params[i].name, name, len);
}
opt->params[i].val = val;
return NLOPT_SUCCESS;
}
double nlopt_get_param(const nlopt_opt opt, const char *name, double defaultval)
{
unsigned i;
if (!opt || !name || strnlen(name, 1024) == 1024) return defaultval;
for (i = 0; i < opt->nparams; ++i)
if (!strcmp(name, opt->params[i].name))
return opt->params[i].val;
return defaultval;
}
int nlopt_has_param(const nlopt_opt opt, const char *name)
{
unsigned i;
if (!opt || !name || strnlen(name, 1024) == 1024) return 0;
for (i = 0; i < opt->nparams; ++i)
if (!strcmp(name, opt->params[i].name))
return 1;
return 0;
}
unsigned nlopt_num_params(const nlopt_opt opt)
{
return opt ? opt->nparams : 0;
}
const char *nlopt_nth_param(const nlopt_opt opt, unsigned n)
{
return opt && n < opt->nparams ? opt->params[n].name : NULL;
}
/*************************************************************************/
nlopt_result NLOPT_STDCALL nlopt_set_precond_min_objective(nlopt_opt opt, nlopt_func f, nlopt_precond pre, void *f_data)
......
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
#include <iomanip>
#include <nlopt.hpp>
......@@ -39,6 +41,15 @@ int main() {
opt.add_inequality_constraint(myvconstraint, &data[0], 1e-8);
opt.add_inequality_constraint(myvconstraint, &data[1], 1e-8);
opt.set_xtol_rel(1e-4);
// try setting an algorithm parameter: */
opt.set_param("inner_maxeval", 123);
if (opt.get_param("inner_maxeval", 1234) != 123 || opt.get_param("not a param", 1234) != 1234 ||
opt.num_params() != 1 || std::string(opt.nth_param(0)) != "inner_maxeval") {
std::cerr << "failed to retrieve nlopt parameter" << std::endl;
return EXIT_FAILURE;
}
std::vector<double> x(2);
x[0] = 1.234; x[1] = 5.678;
double minf;
......@@ -47,10 +58,10 @@ int main() {
opt.optimize(x, minf);
std::cout << "found minimum at f(" << x[0] << "," << x[1] << ") = "
<< std::setprecision(10) << minf <<std::endl;
return EXIT_SUCCESS;
return std::fabs(minf - 0.5443310474) < 1e-3 ? EXIT_SUCCESS : EXIT_FAILURE;
}
catch(std::exception &e) {
std::cout << "nlopt failed: " << e.what() << std::endl;
std::cerr << "nlopt failed: " << e.what() << std::endl;
return EXIT_FAILURE;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册