1

I am trying to write an optimization code with constraints using SLSQP method. But I can't understand it enough to write the proper codes for constraints.

Lets say we have a function f, with p parameters, all with the same starting values (0.1) and arg is the array of these parameters:

arg = [.1] * p

Here I want sum(arg[2:]) to be less than 1, and arg[i] > 0 for the optimization. How can i write the constraints/boundaries for scipy.optimize.minimize:

from scipy.optimize import minimize

minimize( fun = f,
          x0  = arg,
          method = 'SLSQP',
          constraints = ?,
          bounds = ?
)
Erdem Şen
  • 97
  • 1
  • 10

1 Answers1

2

First of all, you can't use strict inequality constraints like g(x) < 1 or x > 0. Instead, you can model them by g(x) ≥ 1 - ε and x ≤ ε, where ε is a sufficiently small positive constant. In addition, if args is your starting point, i.e. the vector consisting of 1s only, then there's no constraint as sum(c) doesn't depend on your any optimization variable. I take it you'd like to add the constraint that the sum of all the optimization variables (except the first two ones) is smaller than 1:

Note that scipy expects each equality constraint in the form g(x) = 0 and each inequality constraint in the form g(x) ≥ 0. Therefore, you can define your first constraint by

def con_fun(x, eps = 1.0e-8):
    # np.sum(x[2:]) ≤ 1 - eps
    # (np.sum(x[2:]) - 1 + eps ≤ 0
    # 1 - eps - np.sum(x[2:]) ≥ 0
    return 1 - eps - np.sum(x[2:])

constrs = [{'type': 'ineq', 'fun': con_fun})

Your second constraints are simple bounds on the optimization variables, thus

eps = 1.0e-8
# 0 + eps <= x[i] < ∞
bounds = [(0 + eps, None) for _ in range(p)]

Finally, you can can call the minimize method:

minimize(your_obj_fun, x0=x0, method='SLSQP', constraints=constrs, bounds=bounds)
joni
  • 6,840
  • 2
  • 13
  • 20
  • At first, I accepted this answer because it seemed ok. However after a research I learnt there is actually no need for an epsilon. The standard and simplest way to write this constraint is: `constrs = [{'type': 'ineq', 'fun': lambda x: 1 - sum(arg[2:])}]` So your answer is ok but this "*you can't use strict inequality constraints*" statement is not true. – Erdem Şen Aug 06 '23 at 17:20
  • @ErdemŞen Well, your 'standard' way models `sum(arg[2:])) ≤ 1`, not the **strict** inequality `sum(arg[2:])) < 1` as asked in your initial question. If you really wanted the former, there's indeed no need for an epsilon. However, in that case your question was misleading since "*Here I want sum(arg[2:]) to be less than 1, and arg[i] > 0*" both ask for **strict** inequalities. There's a huge difference between `<` and `≤` (resp. less-than and less-than-or-equal) from a mathematical point of view. That being said, my statement regarding strict inequalities is still true. – joni Aug 06 '23 at 21:20
  • I see. it is my question, misleading. A fix on that (reediting my question) would also make your answer seem wrong, though. So i will keep it as it is. Thank you – Erdem Şen Aug 10 '23 at 11:07