SciML / Optimization.jl

Mathematical Optimization in Julia. Local, global, gradient-based and derivative-free. Linear, Quadratic, Convex, Mixed-Integer, and Nonlinear Optimization in one simple, fast, and differentiable interface.
https://docs.sciml.ai/Optimization/stable/
MIT License
688 stars 75 forks source link

FORCED_STOP from OptimizationNLopt callback returns best point PRIOR to callback, making it unuseful for custom stopping criteria. Is that intended? #767

Open donboyd5 opened 1 month ago

donboyd5 commented 1 month ago

Question❓

An OptimizationNLopt solve that results in FORCED_STOP from a callback will return not the point that generated the stop, but the previous best point. Perhaps this is intended, but it means defining stopping criteria in the callback will not be useful. (For related background see this issue).

For example, suppose the callback function defines complex stopping criteria, and those criteria are met on iteration 4, at which point the callback function returns true. Suppose the objective function values on iterations 1 through 4 are 1000, 10, 100, and 1. The callback will return the sol.u values from iteration 2, when the objective value was 10, not the sol.u values from iteration 4 when the objective value was 1.

This means we do not recover the point at which the complex stopping criteria were met - a point we likely want.

The test code lines 75-84, copied below, seems to recognize this and suggest that this behavior results from NLopt rather than Optimization.NLopt -- see the comment "#nlopt gives the last best not the one where callback stops" on line 82, copied below. (Incidentally, the test does not appear to call the callback.)

Is this desirable, and if not, is there a way to work around it? At least in my case, it is not desired - I'd like to be able to get the point that generated the FORCED_STOP, because it met my stoppping criteria.

Many thanks.

    @testset "callback" begin
        cbstopping = function(state, loss)
            println(state.iter, " ", state.u, " ", state.objective)
            return state.objective < 0.7
        end

        sol = solve(prob, NLopt.LD_LBFGS())
        #nlopt gives the last best not the one where callback stops
        @test sol.objective < 0.8
    end
Vaibhavdixit02 commented 1 month ago

This is an upstream issue I am not sure if we can handle it here unfortunately. I'll try to ask if someone knows how to make NLopt not do this 😅

donboyd5 commented 1 month ago

Thank you!

On Wed, May 29, 2024 at 4:45 PM Vaibhav Kumar Dixit < @.***> wrote:

This is an upstream issue I am not sure if we can handle it here unfortunately. I'll try to ask if someone knows how to make NLopt not do this 😅

— Reply to this email directly, view it on GitHub https://github.com/SciML/Optimization.jl/issues/767#issuecomment-2138233846, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABR4JGGHNW6YAF343PHNGOTZEY47BAVCNFSM6AAAAABIPOUULSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMZYGIZTGOBUGY . You are receiving this because you authored the thread.Message ID: @.***>