odow / SDDP.jl

A JuMP extension for Stochastic Dual Dynamic Programming
https://sddp.dev
Other
309 stars 61 forks source link

Provide more flexible options for stopping rules #664

Closed Thiago-NovaesB closed 1 year ago

Thiago-NovaesB commented 1 year ago

From what I understand, we can pass an array of stopping criteria to SDDP.jl, but they always works as OR, in the sense that if 1 of them is met, the algorithm stops. I would like to create a stopping criterion that is met when 2 stopping criteria that I have already implemented are met simultaneously. At the moment I don't see how to do this without re-implementing.

Can you explain to me if it is possible to do this? If not, could you make this part more flexible?

It would be interesting to be able to choose between OR and AND. Or maybe we can even choose a number of minimum criteria that must be met, or something even more general that you can think of.

"""
    convergence_test(
        model::PolicyGraph,
        log::Vector{Log},
        ::AbstractStoppingRule,
    )::Bool

Return a `Bool` indicating if the algorithm should terminate the training.
"""
function convergence_test(
    graph::PolicyGraph,
    log::Vector{Log},
    stopping_rules::Vector{AbstractStoppingRule},
)
    for stopping_rule in stopping_rules
        if convergence_test(graph, log, stopping_rule)
            return true, stopping_rule_status(stopping_rule)
        end
    end
    return false, :not_solved
end
Thiago-NovaesB commented 1 year ago

I realized that I can create a stopping criterion that receives 2 other stopping criteria. It actually seems to be something easy to deal with. I don't know if you think it makes sense to modify SDDP.jl @odow

# ======================= And Stopping Rule ======================= #

"""
    AndStoppingRules(stopping_rules::Vector{SDDP.AbstractStoppingRule})

Condition is met when all conditions 'stopping_rules' are met.
"""
mutable struct AndStoppingRules <: SDDP.AbstractStoppingRule
    stopping_rules::Vector{SDDP.AbstractStoppingRule}
end

SDDP.stopping_rule_status(::AndStoppingRules) = :and_stopping_rules

function SDDP.convergence_test(graph::SDDP.PolicyGraph{T}, log::Vector{SDDP.Log},
                          rule::AndStoppingRules) where T
    for stopping_rule in rule.stopping_rules
        if !SDDP.convergence_test(graph, log, stopping_rule)
            return false
        end
    end
    return true
end
andrewrosemberg commented 1 year ago

Is this of similar capability: SDDP.StoppingChain ?

Thiago-NovaesB commented 1 year ago

Oops, my fault, I didn't realize it was already implemented