Search code examples
pythonoptimizationscipyboundary

How to define discontinuous boundaries in SciPy.optimize.minimize


I'm using scipy.optimize.minimize 'SLSQP' method, according to the documentation:

bounds : sequence, optional

Bounds for variables (only for L-BFGS-B, TNC and SLSQP). (min, max) pairs for >each element in x, defining the bounds on that parameter. Use None for one of min >or max when there is no bound in that direction.

I'd like to know whether it is possible to define a boundary which is NOT continuous for a variable x like (0,15) & (30,50); (x is between 0 and 15 and between 30 and 50)

Or are there any other better methods to achieve this?

Thank you guys in advance!


Solution

  • x is between 0 and 15 and between 30 and 50

    This would make the model infeasible. There is no such x. You probably mean:

    x is between 0 and 15 OR between 30 and 50

    This is non-convex, so standard local solvers have troubles with this. It is often modeled with an extra binary variable:

    30 δ ≤ x ≤ 15(1-δ) + 50 δ  
    δ ∈ {0,1}
    

    Of course, this assumes you can handle binary variables (SLSQP can't). Models with binary variables and nonlinear constraints (or objective function) are called MINLP models (Mixed Integer Non-linear Programming). Solvers for these type of models are readily available.

    Some other approaches that may work:

    • Solve the problem twice. Once with 0 ≤ x ≤ 15 and once with 30 ≤ x ≤ 50. Then pick the best solution.
    • Use the scipy.optimize.basinhopping global solver to help your way out of a local optimum. This is not a rigorous algorithm (no guarantees), but it can help.

    Some approaches that typically don't work:

    • instead of a binary variable δ ∈ {0,1} use a continuous variable δ ∈ [0,1] and add the constraint δ(1-δ)=0. Typically this will get you stuck.
    • The polynomial approach in the other answer: this is also non-convex and not really suited for SLSQP. You will get stuck in a local optimum.
    • Add a penalty to the objective if x ∈ [15,30]. This also does not work with a local solver.