stevengj / nlopt

library for nonlinear optimization, wrapping many algorithms for global and local, constrained or unconstrained, optimization
Other
1.9k stars 591 forks source link

Anonymous functions in Octave-6.2.0 #384

Closed octave-user closed 3 years ago

octave-user commented 3 years ago

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.

$ diff -uwbNr nlopt_optimize-oct.cc~ nlopt_optimize-oct.cc
--- nlopt_optimize-oct.cc~      2021-03-28 17:00:17.171791100 +0000
+++ nlopt_optimize-oct.cc       2021-03-28 17:13:36.457262700 +0000
@@ -80,7 +80,7 @@
 }

 typedef struct {
-  octave_function *f;
+  octave_value f;
   int neval, verbose;
   nlopt_opt opt;
 } user_function_data;
@@ -265,14 +265,14 @@
     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 {
stevengj commented 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?

stevengj commented 3 years ago

(Note that the constraints are also functions, and presumably need a similar patch.)

octave-user commented 3 years ago

What I can tell you is, that the new syntax will work at least for version 5.2 of octave.

octave-user commented 3 years ago

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-user commented 3 years ago

OK, I have created a pull request: https://github.com/stevengj/nlopt/pull/385

pierre-haessig commented 1 year ago

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?

octave-user commented 1 year ago

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: @.***>

pierre-haessig commented 1 year ago

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.