Skip to content

Stop ORIG_DIRECT, StoGO and CRS2 promptly after a forced stop - #655

Open
inayatku wants to merge 1 commit into
stevengj:masterfrom
inayatku:force-stop-orig-direct-stogo-crs
Open

inayatku wants to merge 1 commit into
stevengj:masterfrom
inayatku:force-stop-orig-direct-stogo-crs

Conversation

@inayatku

Copy link
Copy Markdown
Contributor

After nlopt_force_stop (or opt.force_stop(), or an exception in a C++ objective), three algorithms did not stop.

  • GN_ORIG_DIRECT and GN_ORIG_DIRECT_L crashed with an access violation when the stop came at the first evaluation. direct_dirinit_ returned before it set minpos, and direct_direct_ then read the point at that index after L100. The check now comes after *minf and *minpos are set, so the evaluated point is returned. (The SciPy version of this code in direct: diff from SciPy #615 avoids the crash by initializing minpos = 1 in direct_direct_.)
  • GD_STOGO and GD_STOGO_RAND ignored the stop. Global::InTime() and the two checks in local() tested only maxeval and maxtime, so the run went on to maxeval and returned NLOPT_SUCCESS. They now also test nlopt_stop_forced, and nlopt_optimize_ returns NLOPT_FORCED_STOP.
  • GN_CRS2_LM evaluated the rest of its initial population, because crs_init did not test nlopt_stop_forced. In 2-D, a stop at evaluation 1 gave 30 more evaluations. crs_init now returns NLOPT_FORCED_STOP, and crs_minimize still reports the best point found.

New test test/t_force_stop_evals.cxx: the objective calls force_stop() at evaluation 1, 2, 5, 15 and 40. The test checks that the run ends with nlopt::forced_stop, that there are no further evaluations, and that a finite reported optimum equals the objective at the returned x. It runs for the five algorithms above and for MMA, COBYLA, BOBYQA, ISRES and ESCH, which already pass.

On master: ORIG_DIRECT and ORIG_DIRECT_L crash; StoGO and StoGO-rand run all 1000 evaluations and do not report the stop; CRS2 runs 31 evaluations for a stop at evaluation 1 to 15. With the change, all pass. ctest: 98 of 98 pass (MSVC 2022).

I also ran every algorithm through the C API (2-D, stop at evaluation 1, 2, 5, 15, 40 and 100). Apart from these five, every algorithm returns NLOPT_FORCED_STOP. A few evaluate one or two more points after the stop: the DIRECT variants and PRAXIS for a stop at evaluation 1, the Luksan algorithms (LBFGS, VAR1, VAR2, TNEWTON) at evaluation 2 or 5, and AGS at evaluation 1 or 2. I left those alone. Runs without a forced stop gave the same number of evaluations and the same result codes before and after the change.

- ORIG_DIRECT: a forced stop at the first evaluation returned from
  direct_dirinit_ before minpos was set, and direct_direct_ then read
  the point at an uninitialized index. Check the stop after minpos is set.
- StoGO: InTime() and the checks in local() tested only maxeval and
  maxtime, so a forced stop was ignored. Test nlopt_stop_forced too and
  return NLOPT_FORCED_STOP.
- CRS2: crs_init evaluated the whole initial population after a forced
  stop. Return NLOPT_FORCED_STOP from crs_init and keep the best point.

New test t_force_stop_evals: no evaluations after force_stop() at
evaluation 1, 2, 5, 15 and 40.
@inayatku

Copy link
Copy Markdown
Contributor Author

@stevengj, a reminder in case this one was missed: it is ready for review, and the checks pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant