title: SciPy optimizer ignores one of the constraints
body: <p>I am trying to solve an optimization problem where I need to create a portfolio that with a minimum tracking error from benchmark portfolio and it's subject to some constraints:</p>
  
  <pre><code>import scipy.optimize as opt
  import numpy as np
  
  def random_portfolio(n):
      a = np.random.random(n)
      a /= a.sum()
      return a
  
  portfolio_weights = [1 for i in range(20)]
  portfolio_weights = [i/len(portfolio_weights) for i in portfolio_weights]
  
  def tracking_error_function(W, port_weights):
      weight_diff = list(np.array(port_weights)-np.array(W))
      weight_diff = sum([i**2 for i in weight_diff])
      return weight_diff
  
  def total_max_weight_constraint(weights):
      max_weights_share = sum([i for i in weights if i &gt; 0.045])
      max_ineq = 0.36 - max_weights_share
      return max_ineq
  
  def gen_initial_weights(n):
      max_weights = [0.089 for i in range(4)]
      rest_of_n = n - 4
      rest_of_weight = 1 - sum(max_weights)
      other_weights = [rest_of_weight/rest_of_n for i in range(rest_of_n)]
      all_weights = max_weights + other_weights
      return all_weights
  
  initial_weights = np.asarray(gen_initial_weights(len(portfolio_weights)))
  
  tr_err = tracking_error_function(initial_weights, portfolio_weights)  
  b_ = [(0.0, 0.09) for i in range(len(initial_weights))]
  c_ = ({'type': 'eq', 'fun': lambda W: sum(W) - 1},
    {'type': 'ineq', 'fun': total_max_weight_constraint})
  
  optimized = opt.minimize(tracking_error_function, initial_weights, args=(portfolio_weights), method='SLSQP', constraints=c_, bounds=b_, options={'maxiter': 100000 })
  </code></pre>
  
  <p>So my initial guess abides the constraints and the benchmark is equally-weighted. When I run it, the result is exactly equally-weighted portfolio although it is clearly violating the second constraint. Moreover, the status is success. Any ideas what i do wrong?</p>
  
  <p><strong>Update:</strong>
  This is a solution that seems to work in my case</p>
  
  <pre><code>import scipy.optimize as opt
  import numpy as np
  import random
  import matplotlib.pyplot as plt
  
  
  def random_portfolio(n):
      #random.seed(123)
      a = np.random.random(n)
      a /= a.sum()
      return a
  
  def continous_step_function(x, cutoff):
      return x / (1 + safe_exp(-(x - cutoff) * 200000))
  
  def safe_exp(x):
      try:
          ans = np.math.exp(x)
      except OverflowError:
          ans = float('inf')
      return ans
  
  def gen_initial_weights(n):
      max_weights = [0.0899999 for i in range(4)]
      rest_of_n = n - 4
      rest_of_weight = 1 - sum(max_weights)
      other_weights = [rest_of_weight/rest_of_n for i in range(rest_of_n)]
      all_weights = max_weights + other_weights
      return all_weights
  
  def tracking_error_function(W, port_weights):
      weight_diff = port_weights - W
      weight_diff = np.sum(weight_diff ** 2)
  
      excessive_weight = max(0,(sum([continous_step_function(i,0.045) for i in W]) - 0.36))
  
      return weight_diff + excessive_weight
  
  def total_max_weight_constraint(weights):
      max_weights_share = sum([continous_step_function(i,0.045) for i in weights])
      max_ineq = 0.36 - max_weights_share
      return max_ineq
  
  def run():
      portfolio_weights = sorted(random_portfolio(20))
  
      initial_weights = np.asarray(gen_initial_weights(len(portfolio_weights)))
      initial_weights = sorted(initial_weights)
  
      b_ = [(0.0, 0.09) for i in range(len(initial_weights))]
      c_ = ({'type': 'eq', 'fun': lambda W: sum(W) - 1},
            {'type': 'ineq', 'fun': total_max_weight_constraint}
            )
  
      optimized = opt.minimize(tracking_error_function, initial_weights, args=(portfolio_weights), constraints=c_,
                               bounds=b_, options={'eps': 0.00000001, 'ftol' : 0.00000001, 'iprint': 0, 'disp': 0, 'maxiter': 10000})
  
      result = optimized.x
  
      if tracking_error_function(result, portfolio_weights) &gt; 0.05:
          print('Excessive tracking error: ')
          print('Residual error: {}'.format(tracking_error_function(result, portfolio_weights)))
          print('Target: {} {}'.format(sum(portfolio_weights), portfolio_weights))
          print('Result: {} {}'.format(sum(result), result))
  
      if sum([i for i in result if i &gt; 0.045]) &gt; 0.36:
          print('Excessive weight &gt; .045: ')
          print('Percentage &gt; .045: {}'.format(sum([x for x in result if x &gt; 0.045])))
          print('Target: {} {}'.format(sum(portfolio_weights), portfolio_weights))
          print('Result: {} {}'.format(sum(result), result))
  
      if not all(b &gt;= (a - 0.001) for a, b in zip(result, result[1:])):
          print('Result not continously rising: ')
          print('Target: {} {}'.format(sum(portfolio_weights), portfolio_weights))
          print('Result: {} {}'.format(sum(result), result))
  
  def plot_output(result, target):
      plt.bar(range(len(result)), result,  color='b', width = 0.3)
      plt.plot(range(len(target)), target, color='r')
      plt.show()
  </code></pre>