Inconsistent Objective Value when solving NLP - optimization

The objective is a quadratic function.
final = np.zeros_like(m.time)
final[-1] = 1
final = m.Param(final)
final_obj = ((m.Cs_n_avg[0]*final-0.0226981-0.25)*100)**2
m.Obj(final_obj)
m.options.IMODE = 6
m.options.SOLVER = 3
m.options.MAX_ITER = 500
m.solve(disp=True)
m.options.OBJ
3718.2126872
m.Cs_n_avg[0]
[0.0226981, 0.059400736803, 0.093924942354, 0.13029876847, 0.17044062163, 0.21694119575, 0.27269809999]
If plug in the value of m.Cs_n_avg[0] into the objective function, the value is 0.

Here is a related problem (see Problem 1b) from the Dynamic Optimization course where the final value is minimized. The current question is incomplete because the code is missing several dependencies. Please update the question or else use the following as an example to help.
import numpy as np
import matplotlib.pyplot as plt
from gekko import GEKKO
m = GEKKO()
nt = 101
m.time = np.linspace(0,1,nt)
# Variables
x1 = m.Var(value=1)
x2 = m.Var(value=0)
u = m.Var(value=-0.48)
p = np.zeros(nt)
p[-1] = 1.0
final = m.Param(value=p)
# Equations
m.Equation(x1.dt()==u)
m.Equation(x2.dt()==x1**2 + u**2)
m.Equation(final*(x1-1)==0)
# Objective Function
m.Minimize(x2*final)
m.options.IMODE = 6
m.solve()
plt.figure(1)
plt.plot(m.time,x1.value,'k:',lw=2,label=r'$x_1$')
plt.plot(m.time,x2.value,'b-',lw=2,label=r'$x_2$')
plt.plot(m.time,u.value,'r--',lw=2,label=r'$u$')
plt.legend(loc='best')
plt.xlabel('Time')
plt.ylabel('Value')
plt.show()

Related

Can't divide by function for use in ordinary differential equations

I'm a first year maths and physics student and have next to no experience in python and this is my first time working with SciPy.
This is why I ran into some trouble when trying to handle ODEs;
My Problem is that I'm not able to divide by a previously defined function for use in another ODE.
I tried replacing dvdt with the code from the return statement in the previously defined function dvdt but that doesn't work since v is not defined inside dxdt.
Casting dvdt to float also doesn't work, since I can't cast to a function.
I'm absolutely clueless about what to do, so I turned to StackOverflow in hopes of getting some suggestions :O).
This is my code:
from scipy import integrate
import numpy as np
import matplotlib.pyplot as plt
import math
def dvdt(t, v):
k = 0.3
Fs = 200000
m0 = 10000
lam = 200
return (Fs + k*v**2) / (m0 - lam*t)
v0 = 0
def dxdt(t, x):
k = 0.3
Fs = 200000
m0 = 10000
lam = 200
# This is where the Problem arises.
return math.sqrt(Fs / (dvdt*k))
# Inserting ((Fs + k*v**2) / (m0 - lam*t)) for dvdt didn't help either, since v is not defined inside dxdt :/
x0 = 0
t = np.linspace(0, 30, 100)
sol_v = integrate.solve_ivp(dvdt, t_span = (0, max(t)), y0=[v0], t_eval=t)
v_sol = sol_v.y[0]
sol_x = integrate.solve_ivp(dxdt, t_span = (0, max(t)), y0=[x0], t_eval=t)
x_sol = sol_x.y[0]
plt.plot(t, v_sol)
plt.ylabel('$v(t)$', fontsize=22)
plt.xlabel('$t$', fontsize=22)
plt.plot(t, x_sol)
plt.ylabel('$x(t)$', fontsize=22)
plt.xlabel('$t$', fontsize=22)
plt.show()
Corrected code:
from scipy import integrate
import numpy as np
import matplotlib.pyplot as plt
import math
def dvdt(t, v):
k = 0.3
Fs = 200000
m0 = 10000
lam = 200
return (Fs + k*v**2) / (m0 - lam*t)
v0 = 0
def dxdt(t, x):
k = 0.3
Fs = 200000
m0 = 10000
lam = 200
return math.sqrt(Fs / (dvdt(t, 0)*k))
x0 = 0
t = np.linspace(0, 30, 100)
sol_v = integrate.solve_ivp(dvdt, t_span = (0, max(t)), y0=[v0], t_eval=t)
v_sol = sol_v.y[0]
sol_x = integrate.solve_ivp(dxdt, t_span = (0, max(t)), y0=[x0], t_eval=t)
x_sol = sol_x.y[0]
plt.plot(t, v_sol, label="v(t)")
plt.plot(t, x_sol, label="x(t)")
plt.ylabel('Geschwindigkeit', fontsize=15)
plt.xlabel('Zeit', fontsize=15)
plt.legend(["v(t) - Geschwindigkeit", "x(t) - Höhe"])
plt.title("Verhalten der Rakete")
plt.show()

Lambdify a function in two variables and plot a surface

I have a function f(x,y) where t is a parameter. I'm trying to plot the function where t = 1 for x and y values ranging from -5 to 5. The plot doesn't render.
import sympy as sp
import numpy as np
import matplotlib.pyplot as plt
%matplotlib notebook
C = sv.CoordSys3D("")
x, y, z = C.base_scalars()
t = sp.symbols("t")
f = sp.sin(2*sp.pi*t)*sp.exp(-(x-3*sp.sin(sp.pi*t))**2 -(y-3*sp.cos(sp.pi*t))**2)
fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot(projection='3d')
X = np.linspace(-5,5,100)
Y = np.linspace(-5,5,100)
xvals, yvals = np.meshgrid(X,Y)
zvals = sp.lambdify((x,y),f.subs(t,1),"numpy")(xvals,yvals)
ax.plot_surface(xvals,yvals,zvals)
plt.show()
I get an error 'int' object has no attribute 'ndim' which I don't know how to solve.
The problem is that when you execute f.subs(t,1) it returns a number (zero in this case). So, f=0 is the expression that you are going to lambdify. Let's see the function generated by lambdify:
import inspect
print(inspect.getsource(sp.lambdify((x,y),f.subs(t,1),"numpy")))
# def _lambdifygenerated(Dummy_25, Dummy_24):
# return 0
So, no matter the values and shape of xvals and yvals, that numerical function will always return 0, which is an integer number.
However, ax.plot_surface requires zvals to have the same shape as xvals or yval. Luckily, we can easily fix that with a simple if statement:
import sympy as sp
import sympy.vector as sv
import numpy as np
import matplotlib.pyplot as plt
C = sv.CoordSys3D("")
x, y, z = C.base_scalars()
t = sp.symbols("t")
f = sp.sin(2*sp.pi*t)*sp.exp(-(x-3*sp.sin(sp.pi*t))**2 -(y-3*sp.cos(sp.pi*t))**2)
fig = plt.figure(figsize=(6, 6))
ax = fig.add_subplot(projection='3d')
X = np.linspace(-5,5,100)
Y = np.linspace(-5,5,100)
xvals, yvals = np.meshgrid(X,Y)
zvals = sp.lambdify((x,y),f.subs(t,1),"numpy")(xvals,yvals)
# if zvals is just a number, create a proper matrix
if not isinstance(zvals, np.ndarray):
zvals = zvals * np.ones_like(xvals)
ax.plot_surface(xvals,yvals,zvals)
plt.show()
The fact that this doesn't render is bug in lambdify that it doesn't work well for constant expressions.
Your real problem though is that the expression you are trying to plot is just zero:
In [5]: f
Out[5]:
2 2
- (x_ - 3⋅sin(π⋅t)) - (y_ - 3⋅cos(π⋅t))
ℯ ⋅sin(2⋅π⋅t)
In [6]: f.subs(t, 1)
Out[6]: 0

How to calculate the confidence intervals for prediction in Regression? and also how to plot it in python

Fig 7.1, An Introduction To Statistical Learning
I am currently studying a book named Introduction to Statistical Learning with applications in R, and also converting the solutions to python language.
I am not able to get how to get the confidence intervals and plot them as shown in the above image(dashed lines).
I have plotted the line. Here's my code for that -
(I am using polynomial regression with predictiors - 'age' and response - 'wage',degree is 4)
poly = PolynomialFeatures(4)
X = poly.fit_transform(data['age'].to_frame())
y = data['wage']
# X.shape
model = sm.OLS(y,X).fit()
print(model.summary())
# So, what we want here is not only the final line, but also the standart error related to the line
# TO find that we need to calcualte the predictions for some values of age
test_ages = np.linspace(data['age'].min(),data['age'].max(),100)
X_test = poly.transform(test_ages.reshape(-1,1))
pred = model.predict(X_test)
plt.figure(figsize = (12,8))
plt.scatter(data['age'],data['wage'],facecolors='none', edgecolors='darkgray')
plt.plot(test_ages,pred)
Here data is WAGE data which is available in R.
This is the resulting graph i get -
I have used bootstraping to calculate the confidence intervals, for this i have used a self customed module -
import numpy as np
import pandas as pd
from tqdm import tqdm
class Bootstrap_ci:
def boot(self,X_data,y_data,R,test_data,model):
predictions = []
for i in tqdm(range(R)):
predictions.append(self.alpha(X_data,y_data,self.get_indices(X_data,200),test_data,model))
return np.percentile(predictions,2.5,axis = 0),np.percentile(predictions,97.5,axis = 0)
def alpha(self,X_data,y_data,index,test_data,model):
X = X_data.loc[index]
y = y_data.loc[index]
lr = model
lr.fit(pd.DataFrame(X),y)
return lr.predict(pd.DataFrame(test_data))
def get_indices(self,data,num_samples):
return np.random.choice(data.index, num_samples, replace=True)
The above module can be used as -
poly = PolynomialFeatures(4)
X = poly.fit_transform(data['age'].to_frame())
y = data['wage']
X_test = np.linspace(min(data['age']),max(data['age']),100)
X_test_poly = poly.transform(X_test.reshape(-1,1))
from bootstrap import Bootstrap_ci
bootstrap = Bootstrap_ci()
li,ui = bootstrap.boot(pd.DataFrame(X),y,1000,X_test_poly,LinearRegression())
This will give us the lower confidence interval, and upper confidence interval.
To plot the graph -
plt.scatter(data['age'],data['wage'],facecolors='none', edgecolors='darkgray')
plt.plot(X_test,pred,label = 'Fitted Line')
plt.plot(X_test,ui,linestyle = 'dashed',color = 'r',label = 'Confidence Intervals')
plt.plot(X_test,li,linestyle = 'dashed',color = 'r')
The resultant graph is
Following code results in the 95% confidence interval
from scipy import stats
confidence = 0.95
squared_errors = (<<predicted values>> - <<true y_test values>>) ** 2
np.sqrt(stats.t.interval(confidence, len(squared_errors) - 1,
loc=squared_errors.mean(),
scale=stats.sem(squared_errors)))

Implementing minimization in SciPy

I am trying to implement the 'Iterative hessian Sketch' algorithm from https://arxiv.org/abs/1411.0347 page 12. However, I am struggling with step two which needs to minimize the matrix-vector function.
Imports and basic data generating function
import numpy as np
import scipy as sp
from sklearn.datasets import make_regression
from scipy.optimize import minimize
import matplotlib.pyplot as plt
%matplotlib inline
from numpy.linalg import norm
def generate_data(nsamples, nfeatures, variance=1):
'''Generates a data matrix of size (nsamples, nfeatures)
which defines a linear relationship on the variables.'''
X, y = make_regression(n_samples=nsamples, n_features=nfeatures,\
n_informative=nfeatures,noise=variance)
X[:,0] = np.ones(shape=(nsamples)) # add bias terms
return X, y
To minimize the matrix-vector function, I have tried implementing a function which computes the quanity I would like to minimise:
def f2min(x, data, target, offset):
A = data
S = np.eye(A.shape[0])
#S = gaussian_sketch(nrows=A.shape[0]//2, ncols=A.shape[0] )
y = target
xt = np.ravel(offset)
norm_val = (1/2*S.shape[0])*norm(S#A#(x-xt))**2
#inner_prod = (y - A#xt).T#A#x
return norm_val - inner_prod
I would eventually like to replace S with some random matrices which can reduce the dimensionality of the problem, however, first I need to be confident that this optimisation method is working.
def grad_f2min(x, data, target, offset):
A = data
y = target
S = np.eye(A.shape[0])
xt = np.ravel(offset)
S_A = S#A
grad = (1/S.shape[0])*S_A.T#S_A#(x-xt) - A.T#(y-A#xt)
return grad
x0 = np.zeros((X.shape[0],1))
xt = np.zeros((2,1))
x_new = np.zeros((2,1))
for it in range(1):
result = minimize(f2min, x0=xt,args=(X,y,x_new),
method='CG', jac=False )
print(result)
x_new = result.x
I don't think that this loop is correct at all because at the very least there should be some local convergence before moving on to the next step. The output is:
fun: 0.0
jac: array([ 0.00745058, 0.00774882])
message: 'Desired error not necessarily achieved due to precision loss.'
nfev: 416
nit: 0
njev: 101
status: 2
success: False
x: array([ 0., 0.])
Does anyone have an idea if:
(1) Why I'm not achieving convergence at each step
(2) I can implement step 2 in a better way?

How to drop connecting lines where the function is discontinuous

I'm plotting some functions that have several discontinuities. Each function is given as a list. I want to connect points with lines only where the function is continuous.
Here is a simplified example of what plot is doing.
x=linspace(0,1,100)
y=zeros(100)
y[x<0.5] = x[x<0.5]
y[x>=0.5] = 1 + x[x>=0.5]
plot(x, y, '-o')
There is a discontinuity at x=0.5, but plot connects all points with lines regardless.
My functions are different of course. They typically have several discontinuities in different places. The criterion for the discontinuity is simple. Say, if the function jumps by more than 0.5, I assume it is discontinuous at that point.
Is there an option in plot to tell it to drop the connecting lines between the points where the function is discontinuous? I recall being able to do that easily with gnuplot.
use nan to break the line into multiple segments:
import numpy as np
from pylab import *
x=linspace(0,1,100)
y=zeros(100)
y[x<0.5] = x[x<0.5]
y[x>=0.5] = 1 + x[x>=0.5]
pos = np.where(np.abs(np.diff(y)) >= 0.5)[0]
x[pos] = np.nan
y[pos] = np.nan
plot(x, y, '-o')
Edit:
to insert nan at discontinuities:
pos = np.where(np.abs(np.diff(y)) >= 0.5)[0]+1
x = np.insert(x, pos, np.nan)
y = np.insert(y, pos, np.nan)
Here is my suggestion for plotting tan(x):
import matplotlib.pyplot as plt
from math import *
x_lim = 3*pi/2
y_lim = 5
n = 1000
X = []
Y = []
Z = []
for i in range(0,2*n):
x = -x_lim + i*x_lim/n
y = tan(x)
if y<y_lim and y>-y_lim:
X.append(x)
Y.append(y)
else:
if len(X)>0 and len(Y)>0:
Z.append([X,Y])
del X,Y
X = []
Y = []
for i in range(0, len(Z)):
plt.plot(Z[i][0],Z[i][1])
plt.grid(True)
plt.show()