jump-dev / MathOptInterface.jl

A data structure for mathematical optimization problems
http://jump.dev/MathOptInterface.jl/
Other
392 stars 87 forks source link

Add support for nonlinear sign(x) #2448

Closed odow closed 7 months ago

odow commented 7 months ago

This has come up a few times.

It occurs in GasModels.jl, where they want signpower(x, p) = sign(x) * abs(x)^p, and a variant appeared in https://discourse.julialang.org/t/nonlinear-optimization-with-many-constraints-autodifferentiation-which-julia-solution/110678

We could either define Base.sign(x::AbstractJuMPScalar) = op_ifelse(op_strictly_greater_than(x, 0), 1, -1), or we could add direct support to JuMP and MOI.

odow commented 7 months ago

https://github.com/jump-dev/MathOptInterface.jl/pull/2444 is one option.

Another is to add documentation for:

function signpower(x::Number, p::Real)
    @assert p > 0
    return ifelse(x > 0, x^p, ifelse(x < 0, -(-x)^p, zero(x)))
end

function signpower(x::AbstractJuMPScalar, p::Real)
    @assert p > 0
    return op_ifelse(
        op_strictly_greater_than(x, 0),
        x^p,
        op_ifelse(op_strictly_less_than(x, 0), -(-x)^p, 0.0)
    )
end

and potentially a fallback like sign(x::AbstractJuMPScalar) = error("Use ifelse instead")

odow commented 7 months ago

Moving this to MOI because JuMP will automatically implement the new operator: https://github.com/jump-dev/JuMP.jl/blob/4be967cc9ecad56218929914308b7d4fbcd79678/src/nlp_expr.jl#L315-L338