How to apply Particle Swarm Optimization using SKO.pso python - python

I find a package on the Github, it contains various algorithms about evolution. The link is below:
https://github.com/guofei9987/scikit-opt
However, I got confused when using the package. When I try to do as the example, setting the dim as one, and lower bound as zero when upper bound is ten, focusing on the non negative for x, it got wrong answer, here is my code:
def demo_func(x):
# Sphere
x1= x
return ((10-4*x1)/(4*x1+3))*x1
from sko.PSO import PSO
pso = PSO(func=demo_func, n_dim=1, pop=40, max_iter=150, lb=[0], ub=[10], w=0.8, c1=0.5, c2=0.5)
pso.run()
print('best_x is ', pso.gbest_x, 'best_y is', pso.gbest_y)
import matplotlib.pyplot as plt
plt.plot(pso.gbest_y_hist)
plt.show()
the result are below:result
best_x is [10.] best_y is [-6.97674419]
However, it is a wrong answer. the right answer for x is between 0.5 to 1. Does anybody has suggestions?

PSO optimize the minimum value of function. add a negative sign to get the max.
def demo_func(x):
x1,= x
return -((10-4*x1)/(4*x1+3))*x1
from sko.PSO import PSO
pso = PSO(func=demo_func, n_dim=1, pop=40, max_iter=150, lb=[0], ub=[10], w=0.8, c1=0.5, c2=0.5)
pso.run()
print('best_x is ', pso.gbest_x, 'best_y is', pso.gbest_y)
import matplotlib.pyplot as plt
plt.plot(pso.gbest_y_hist)
plt.show()

Related

least square method for finding unknown variables

I need to compute two unknown variable with least square method , I have got the experimental data which are produced ( simiulated ) by a few line of code at first. so at the beginning two variable which are phase and width are known to simulate the data. in the second part these two variable are considered unknown and with the help of data and least squares method I am going to compute them. but there is a problem!. if the phase is between 0 to pi the code gives the right value and when it is between pi to 2*pi wrong value is retuned. I need to compute these two variables for any arbitrary value with high precision that is entered in the first part.
Thanks to those who would help in advance.
this is the code bellow:
from numpy import sin,cos,pi,linspace,sqrt,zeros,arccos
from scipy.special import fresnel as f
import matplotlib.pyplot as plt
from scipy.optimize import least_squares as lst
import numpy as np
# first part to simulate data
m=500
l=632.8e-9
z=.25
a=0.3e-3
b=6e-3
p=(1.7)*pi
q=sqrt(2/(l*z))
x=linspace(-b,b,m)
v2=-q*(x-a)
v1=-q*(x+a)
s,c,I=zeros(m),zeros(m),zeros(m)
for i in range(m):
s[i]=f(v2[i])[0]-f(v1[i])[0]
c[i]=f(v2[i])[1]-f(v1[i])[1]
for j in range(m):
I[j]=1+(1-cos(p))*((c[j]**2 +s[j]**2 )-(c[j]+s[j]))+sin(p)*(c[j]-s[j])
# second part to compute a and p
def model(y,x):
w=sqrt(2/(l*z))
C=f(w*(y[1]-x))[1]-f(w*(-y[1]-x))[1]
S=f(w*(y[1]-x))[0]-f(w*(-y[1]-x))[0]
return 1+(1-cos(y[0])) *(C**2 -C +S**2 -S)+sin(y[0])*(C-S)
def func(y,x,z):
return (z-model(y,x))
ExI=I
y0=np.array([0.5,50e-6])
reslm = lst(func, y0,method='lm',args=(x, ExI),verbose=2)
print('Real phase and channel width : ',p , a)
print(' lm method ')
print('Estimated phase : ' ,reslm.x[0] if reslm.x[0]>=0 else 2*pi+reslm.x[0])
print('channel width' , reslm.x[1])

Errors using curve_fit for Guassian fit of data

I'm trying to do a guassian fit for some experimental data but I keep running into error after error. I've followed a few different threads online but either the fit isn't good (it's just a horizontal line) or the code just won't run. I'm following this code from another thread. Below is my code.
I apologize if my code seems a bit messy. There are some bits from other attempts when I tried making it work. Hence the "astropy" import.
import math as m
import matplotlib.pyplot as plt
import numpy as np
from scipy import optimize as opt
import pandas as pd
import statistics as stats
from astropy import modeling
def gaus(x,a,x0,sigma, offset):
return a*m.exp(-(x-x0)**2/(2*sigma**2)) + offset
# Python program to get average of a list
def Average(lst):
return sum(lst) / len(lst)
wavelengths = [391.719, 391.984, 392.248, 392.512, 392.777, 393.041, 393.306, 393.57, 393.835, 394.099, 391.719, 391.455, 391.19, 390.926, 390.661, 390.396]
intensities = [511.85, 1105.85, 1631.85, 1119.85, 213.85, 36.85, 10.85, 6.85, 13.85, 7.85, 511.85, 200.85, 80.85, 53.85, 14.85, 24.85]
n=sum(intensities)
mean = sum(wavelengths*intensities)/n
sigma = m.sqrt(sum(intensities*(wavelengths-mean)**2)/n)
def gaus(x,a,x0,sigma):
return a*m.exp(-(x-x0)**2/(2*sigma**2))
popt,pcov = opt.curve_fit(gaus,wavelengths,intensities,p0=[1,mean,sigma])
print(popt)
plt.scatter(wavelengths, intensities)
plt.title("Helium Spectral Line Peak 1")
plt.xlabel("Wavelength (nm)")
plt.ylabel("Intensity (a.u.)")
plt.show()
Thanks to the kind user, my curve seems to be working more reasonably well. However, one of the points seems to be back connecting to an earlier point? Screenshot below:
There are two problems with your code. The first is that you are performing vector operation on list which gives you the first error in the line mean = sum(wavelengths*intensities)/n. Therefore, you should use np.array instead. The second is that you take math.exp on python list which again throws an error as it takes a real number, so you should use np.exp here instead.
The following code solves your problem:
import matplotlib.pyplot as plt
import numpy as np
from scipy import optimize as opt
wavelengths = [391.719, 391.984, 392.248, 392.512, 392.777, 393.041,
393.306, 393.57, 393.835, 394.099, 391.719, 391.455,
391.19, 390.926, 390.661, 390.396]
intensities = [511.85, 1105.85, 1631.85, 1119.85, 213.85, 36.85, 10.85, 6.85,
13.85, 7.85, 511.85, 200.85, 80.85, 53.85, 14.85, 24.85]
wavelengths_new = np.array(wavelengths)
intensities_new = np.array(intensities)
n=sum(intensities)
mean = sum(wavelengths_new*intensities_new)/n
sigma = np.sqrt(sum(intensities_new*(wavelengths_new-mean)**2)/n)
def gaus(x,a,x0,sigma):
return a*np.exp(-(x-x0)**2/(2*sigma**2))
popt,pcov = opt.curve_fit(gaus,wavelengths_new,intensities_new,p0=[1,mean,sigma])
print(popt)
plt.scatter(wavelengths_new, intensities_new, label="data")
plt.plot(wavelengths_new, gaus(wavelengths_new, *popt), label="fit")
plt.title("Helium Spectral Line Peak 1")
plt.xlabel("Wavelength (nm)")
plt.ylabel("Intensity (a.u.)")
plt.show()

Boundary value problem for natural convection by shooting method

I am trying to resolve a special case of boundary value problem which is the boundary layer's equations for natural convection :
Thanks to a contributor of this forum #LutzLehmann, this set of equations is solved by using the function solve_bvp from the scipy library.
Unfortunately, I don't obtain the right result with these particular boundary conditions :
It seems that the initial guess for the solver doesn't work in this case and I wonder what could suit better.
Here is the code :
import numpy as np
from scipy.integrate import solve_bvp
import matplotlib.pyplot as plt
Pr = 5
def odesys(t,u):
F,dF,ddF,θ,dθ = u
return [dF, ddF, θ-0.25/Pr*(2*dF*dF-3*F*ddF), dθ, 0.75*F*dθ]
def bcs(u0,u1): return [u0[0], u0[1], u1[1], u0[3]-1, u1[3]]
x = np.linspace(0,8,25)
u = [x*x, np.exp(-x), 0*x+1, 1-x, 0*x-1]
res = solve_bvp(odesys,bcs,x,u, tol=1e-5)
print(res.message)
plt.subplot(2,1,1)
plt.plot(res.x,res.y[3], color='#801010', label='$\Delta T$')
plt.legend()
plt.grid()
plt.subplot(2,1,2)
plt.plot(res.x,res.y[1], '-', color='C0', label="$F'$")
plt.legend()
plt.grid()
And here are the wrong plots obtained :
Could someone help me by suggesting a better initial case for this problem ?
Thank you for your help,
PS : For the proposition :
u = [0.5*x*x*np.exp(-x), x*np.exp(-x), np.exp(-x), np.exp(-x), -np.exp(-x)]
I got this :
Compared to the literature, I am expecting this result (where g is here theta in the set of equations) :

Plotting 2D integral function in python

Here is my first steps within the NumPy world.
As a matter of fact the target is plotting below 2-D function as a 3-D mesh:
N = \frac{n}{2\sigma\sqrt{\pi}}\exp^{-\frac{n^{2}x^{2}}{4\sigma^{2}}}
That could been done as a piece a cake in Matlab with below snippet:
[x,n] = meshgrid(0:0.1:20, 1:1:100);
mu = 0;
sigma = sqrt(2)./n;
f = normcdf(x,mu,sigma);
mesh(x,n,f);
But the bloody result is ugly enough to drive me trying Python capabilities to generate scientific plots.
I searched something and found that the primary steps to hit above mark in Pyhton might be acquired by below snippet:
from matplotlib.patches import Polygon
import numpy as np
from scipy.integrate import quad
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
sigma = 1
def integrand(x,n):
return (n/(2*sigma*np.sqrt(np.pi)))*np.exp(-(n**2*x**2)/(4*sigma**2))
t = np.linespace(0, 20, 0.01)
n = np.linespace(1, 100, 1)
lower_bound = -100000000000000000000 #-inf
upper_bound = t
tt, nn = np.meshgrid(t,n)
real_integral = quad(integrand(tt,nn), lower_bound, upper_bound)
Axes3D.plot_trisurf(real_integral, tt,nn)
Edit: With due attention to more investigations on Greg's advices, above code is the most updated snippet.
Here is the generated exception:
RuntimeError: infinity comparisons don't work for you
It is seemingly referring to the quad call...
Would you please helping me to handle this integrating-plotting problem?!...
Best
Just a few hints to get you in the right direction.
numpy.meshgrid can do the same as MatLABs function:
http://docs.scipy.org/doc/numpy/reference/generated/numpy.meshgrid.html
When you have x and n you can do math just like in matlab:
sigma = numpy.sqrt(2)/n
(in python multiplication/division is default index by index - no dot needed)
scipy has a lot more advanced functions, see for example How to calculate cumulative normal distribution in Python for a 1D case.
For plotting you can use matplotlibs pcolormesh:
import matplotlib.pyplot as plt
plt.pcolormesh(x,n,real_integral)
Hope this helps until someone can give you a more detailed answer.

What's the correct usage of matplotlib.mlab.normpdf()?

I intend for part of a program I'm writing to automatically generate Gaussian distributions of various statistics over multiple raw text sources, however I'm having some issues generating the graphs as per the guide at:
python pylab plot normal distribution
The general gist of the plot code is as follows.
import numpy as np
import matplotlib.mlab as mlab
import matplotlib.pyplot as pyplot
meanAverage = 222.89219487179491 # typical value calculated beforehand
standardDeviation = 3.8857889432054091 # typical value calculated beforehand
x = np.linspace(-3,3,100)
pyplot.plot(x,mlab.normpdf(x,meanAverage,standardDeviation))
pyplot.show()
All it does is produce a rather flat looking and useless y = 0 line!
Can anyone see what the problem is here?
Cheers.
If you read documentation of matplotlib.mlab.normpdf, this function is deprycated and you should use scipy.stats.norm.pdf instead.
Deprecated since version 2.2: scipy.stats.norm.pdf
And because your distribution mean is about 222, you should use np.linspace(200, 220, 100).
So your code will look like:
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as pyplot
meanAverage = 222.89219487179491 # typical value calculated beforehand
standardDeviation = 3.8857889432054091 # typical value calculated beforehand
x = np.linspace(200, 220, 100)
pyplot.plot(x, norm.pdf(x, meanAverage, standardDeviation))
pyplot.show()
It looks like you made a few small but significant errors. You either are choosing your x vector wrong or you swapped your stddev and mean. Since your mean is at 222, you probably want your x vector in this area, maybe something like 150 to 300. This way you get all the good stuff, right now you are looking at -3 to 3 which is at the tail of the distribution. Hope that helps.
I see that, for the *args which are sending meanAverage, standardDeviation, the correct thing to be sent is:
mu : a numdims array of means of a
sigma : a numdims array of atandard deviation of a
Does this help?

Categories