Closed octave-user closed 3 years ago
A PR would be welcome; but we also need to support older versions of octave. In what octave version did the function_value
method appear?
(Note that the constraints are also functions, and presumably need a similar patch.)
What I can tell you is, that the new syntax will work at least for version 5.2 of octave.
Below you can find the patch considering also the constraints.
--- nlopt_optimize-oct.cc~ 2021-03-28 17:00:17.171791100 +0000 +++ nlopt_optimize-oct.cc 2021-03-28 17:55:21.637637100 +0000 @@ -80,7 +80,7 @@ }
typedef struct {
octave_function *f;
octave_value f; int neval, verbose; nlopt_opt opt; } user_functiondata; @@ -131,7 +131,7 @@ double gradient, / NULL if not needed / void data) {
octave_function f = (octave_function ) data_;
octave_value f = static_cast<octave_value>(data_); octave_value_list args(1, 0); Matrix xm(1,n); for (unsigned i = 0; i < n; ++i) @@ -139,7 +139,7 @@ args(0) = xm; octave_value_list res
= octave::feval(f, args, gradient ? 2 : 1);
= octave::feval(*f, args, gradient ? 2 : 1);
= f->do_multi_index_op(gradient ? 2 : 1, args);
@@ -265,23 +265,25 @@ CHECK(opts.contents("min_objective").numel() == 1 && (opts.contents("min_objective"))(0).is_function_handle(), "opt.min_objective must be a function");
d.f = (opts.contents("min_objective"))(0).function_value();
d.f = (opts.contents("min_objective"))(0); nlopt_set_min_objective(opt, user_function, &d); } else if (opts.contains("max_objective")) { CHECK(opts.contents("max_objective").numel() == 1 && (opts.contents("max_objective"))(0).is_function_handle(), "opt.max_objective must be a function");
d.f = (opts.contents("max_objective"))(0).function_value();
d.f = (opts.contents("max_objective"))(0); nlopt_set_max_objective(opt, user_function, &d); } else { CHECK(0,"either opt.min_objective or opt.max_objective must exist"); }
Cell fc, h;
if (opts.contains("fc") && opts.contents("fc").numel() == 1) { CHECK((opts.contents("fc"))(0).iscell(), "opt.fc must be cell array");
Cell fc = (opts.contents("fc"))(0).cell_value();
fc = (opts.contents("fc"))(0).cell_value(); Matrix zeros(1, fc.numel(), 0.0); Matrix fc_tol = struct_val_default(opts, "fc_tol", zeros); CHECK(fc_tol.numel() == fc.numel(), @@ -290,7 +292,7 @@ CHECK(fc(i).is_function() || fc(i).is_function_handle(), "opt.fc must be a cell array of function handles"); CHECK(nlopt_add_inequality_constraint(opt, user_function1,
fc(i).function_value(),
&fc(i), fc_tol(i)) > 0, "nlopt error adding inequality constraint"); } @@ -298,7 +300,7 @@
if (opts.contains("h") && opts.contents("h").numel() == 1) { CHECK((opts.contents("h"))(0).iscell(), "opt.h must be cell array");
Cell h = (opts.contents("h"))(0).cell_value();
h = (opts.contents("h"))(0).cell_value(); Matrix zeros(1, h.numel(), 0.0); Matrix h_tol = struct_val_default(opts, "h_tol", zeros); CHECK(h_tol.numel() == h.numel(), @@ -307,7 +309,7 @@ CHECK(h(i).is_function() || h(i).is_function_handle(), "opt.h must be a cell array of function handles"); CHECK(nlopt_add_equality_constraint(opt, user_function1,
h(i).function_value(),
&h(i), h_tol(i)) > 0, "nlopt error adding equality constraint"); }
OK, I have created a pull request: https://github.com/stevengj/nlopt/pull/385
Dear @octave-user, I'd like to get more info on this issue with anonymous functions.
Here is a minimal example (with Octave 6.2 and nlopt 2.7.0 from Debian stable):
a = 1;
f = @(x) (x-a)^2;
opt.algorithm = NLOPT_GN_DIRECT;
opt.min_objective = f;
opt.lower_bounds = [0];
opt.upper_bounds = [10];
opt.xtol_rel = 1e-3;
[xopt, fmin, retcode] = nlopt_optimize(opt, [5]);
Running this yields an error as if a
was undefined or out of scope:
error: 'a' undefined near line 1, column 1
error: called from
@<anonymous> at line 1 column 15
Was this the issued that #385 fixed?
Dear Pierre Haessig,
As far as I remember, that issue happened only for a specific version of Octave because the anonymous function was not evaluated in the right context. I don't remember the exact circumstances which triggered that issue, but what you wrote about the "out of scope error" is correct. The workaround for this issue was, to store the anonymous function as an "octave_value" object instead of a "octave_function" pointer. In the meantime, I think this issue was fixed in Octave itself and the workaround should not be needed. But the workaround seems to be in release 2.7.1 of nlopt as you can see in the picture below. Please let me know if you need any further information!
Best regards,
Reinhard
On 06.04.23 16:13, Pierre Haessig wrote:
Dear @octave-user https://github.com/octave-user, I'd like to get more info on this issue with anonymous functions.
Here is a minimal example (with Octave 6.2 and nlopt 2.7.0 from Debian stable):
a= 1; f= @(x) (x-a)^2;
opt.algorithm= NLOPT_GN_DIRECT; opt.min_objective= f; opt.lower_bounds= [0]; opt.upper_bounds= [10]; opt.xtol_rel= 1e-3;
[xopt,fmin,retcode]= nlopt_optimize(opt, [5]);
Running this yields an error as if |a| was undefined or out of scope:
|error: 'a' undefined near line 1, column 1 error: called from @
at line 1 column 15 | Was this the issued that #385 https://github.com/stevengj/nlopt/pull/385 fixed?
— Reply to this email directly, view it on GitHub https://github.com/stevengj/nlopt/issues/384#issuecomment-1499131025, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOYIORQ3DUMW3HJNPRTTA43W73FO3ANCNFSM4Z6HU3ZA. You are receiving this because you were mentioned.Message ID: @.***>
Thanks for the feedback. For the reference, I've found a relevant bug reports in Octave's tracker: bug #60237: Differente behaviour in anonymous function handling.
On my side, I won't dig in further, because my main work computer is under Ubuntu 22.04 with Octave 6.4 and Nlopt 2.7.1 and it works. And for my Debian stable system, well, I'll just wait a few months for the next release... Also, unfortunately, the objective function I want to optimize runs 500x slower in Octave compared to Matlab, so that I won't be able to use Octave as I wanted.
Dear Steven G. Johnson,
Because of internal changes in GNU Octave 6.2.0, anonymous functions do not work any longer with nlopt. The patch below fixes the problem, and it should work also for older versions of Octave.