SciPy Minimize with monotonically decreasing Xs constraint
<p>I am looking to do a strenuous optimization in which I use SciPy to optimize discount factors for bond cashflows (application less important, but if interested). So essentially I take multiple known values 'P', where P[i] is a function of C[i] known constant, and array X (X[j]=x(t) where x is a function of time). where the sum-product of C[i] and X = P.</p>

<p>Hope that makes some sense, but essentially in order for a sensible result, I want to put a constraint where X (my array of x values) has the constraint that x[j] &lt; x[j-1], that is, x's are monotonically decreasing.</p>

<p>Here is my code snippet for the optimization function:</p>

<p>In [400]:</p>

<pre><code>import numpy as np
import pandas as pd
import scipy as s

def MyOptimization(X):
     P=np.array([99.,100.,105.,110.]) #just example known "P" array, in reality closer to 40 values
     c=np.array([1.25,4.,3.1,2.5]) #Cash flows for each P
     t=np.array([[1.2,2.,4.,10.0],[0.5,1.],[2.3,5.,10.5],[1.7]])   #time t of each cash flow, multiple per 'P'
                                                        #remember P=X(t)*c[i] and x(t) where x[i+1]&lt;x[i]

     tlist=[] #t's will be used as index, so pulling individual values
     for i in t:
         for j in i:
             tlist.append(j)

     df=pd.DataFrame(data=X,index=tlist).drop_duplicates().sort() #dataframe to hold t (index) and x, x(t), and P(x,c) where c is known
     #print df
     sse=0
     for i in range(0,len(P)):
         pxi = np.sum(df.loc[t[i],0].values*c[i])+100*df.loc[t[i][-1],0]

         sse=sse+(pxi-P[i])**2 #want to minimize sum squared errors between calculated P(x,c) and known P
     return sse

cons=({'type':'ineq','fun': lambda x: x[1] &lt; x[0]}) #trying to define constraint that x is decreasing with t

opti=s.optimize.minimize(MyOptimization,x0=[0.90,0.89,0.88,0.87,0.86,0.85,0.84,0.83,0.82,0.81],bounds=([0,1],)*10,constraints=cons)
</code></pre>

<p>In [401]:</p>

<pre><code>opti
</code></pre>

<p>Out[401]:</p>

<pre><code>status: 0
success: True
njev: 4
nfev: 69
 fun: 5.445290696814009e-15
   x: array([ 0.90092322,  0.89092322,  0.88092322,  0.94478062,  0.86301329,
    0.92834564,  0.84444848,  0.83444848,  0.96794781,  1.07317073])
message: 'Optimization terminated successfully.'
 jac: array([ -7.50609263e-05,  -7.50609263e-05,  -7.50609263e-05,
    -5.92906077e-03,   3.46914830e-04,   9.17475767e-03,
    -4.89504256e-04,  -4.89504256e-04,  -1.61263312e-02,
     8.35321580e-03,   0.00000000e+00])
 nit: 4
</code></pre>

<p>And it is clear to see where in the results the x array is not decreasing. (tried adding (0,1) bounds as well but result failed, so focussing on this for now.</p>

<p>The important line here for the constraint that I'm really not sure about is:</p>

<p><code>cons=({'type':'ineq','fun': lambda x: x[1] &lt; x[0]})</code></p>

<p>I tried following the documentation, but clearly it hasn't worked.</p>

<p>Any ideas greatly appreciated.</p>

<p>Let's try </p>

<pre><code>def con(x):
    for i in range(len(x)-1):
        if x[i] &lt;= x[i+1]:
            return -1
    return 1

cons=({'type':'ineq','fun': con})
</code></pre>

<p>This should reject lists that aren't set up like you want, but I'm not sure is scipy is going to like it.</p>

python optimization scipy