I was trying to use the newton raphson method to compute the derivative of a function and I got the following error:
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
acc = 10**-4
x = sym.Symbol('x')
def p(x): #define the function
return 924*x**6 - 2772*x**5 + 3150*x**4 - 1680*x**3 + 420*x**2 - 42*x + 1
p_prime = sym.diff(p(x))
def newton(p,p_prime, acc, start_val):
x= start_val
delta = p(x)/p_prime(x)
while abs(delta) > acc:
delta = p(x)/p_prime(x)
print(abs(delta))
x =x- delta;
return round(x, acc);
a = newton(p, p_prime,-4, 0)
The error was:
delta = p(x)/p_prime(x)
TypeError: 'Add' object is not callable
There are a few mistakes in your code, correcting them as pointed out in the following modified code snippet, it works fine:
def p_prime(xval): # define as a function and substitute the value of x
return sym.diff(p(x)).subs(x, xval)
def newton(p, p_prime, prec, start_val): # rename the output precision variable
x = start_val # otherwise it's shadowing acc tolerance
delta = p(x) / p_prime(x) # call the function p_prime()
while abs(delta) > acc:
delta = p(x) / p_prime(x)
x = x - delta
return round(x, prec) # return when the while loop terminates
a = newton(p, p_prime,4, 0.1)
a
# 0.0338
The following animation shows how Newton-Raphson converges to a root of the polynomial p(x).
Your main problem is to call something which is not callable.
Functions are callable
Sympy expressions are not callable
import sympy as sym
def f(x):
return x**2
x = sym.Symbol("x")
g = 2*x
print(callable(f)) # True
print(callable(g)) # False
print(f(0)) # print(0)
print(g(0)) # error
So, in your case
def p(x):
return 924*x**6 - 2772*x**5 + 3150*x**4 - 1680*x**3 + 420*x**2 - 42*x + 1
print(p(0)) # p is callable, gives the result 1
print(p(1)) # p is callable, gives the result 1
print(p(2)) # p is callable, gives the result 8989
print(callable(p)) # True
And now, if you use a symbolic variable from sympy you get:
x = sym.Symbol("x")
myp = p(x)
print(callable(myp)) # False
print(myp(0)) # gives an error, because myp is an expression, which is not callable
So, if you use diff to get the derivative of the function, you will get a sympy expression. You must transform this expression to a callable function. To do it, you can use the lambda function:
def p(x):
return 924*x**6 - 2772*x**5 + 3150*x**4 - 1680*x**3 + 420*x**2 - 42*x + 1
x = sym.Symbol("x")
myp = p(x)
mydpdx = sym.diff(myp, x) # get the derivative, once myp is an expression
dpdx = lambda x0: mydpdx.subs(x, x0) # dpdx is callable
print(dpdx(0)) # gives '-42'
Another way to make a sympy expression callable is to use lambdify from sympy:
dpdx = sym.lambdify(x, mydpdx)
In sympy functions usually are represented as expressions. Therefore, sym.diff() returns an expression and not a callable function. It makes sense to also represent p as an expression involving x.
To "call" a function p on x, p.subs(x, value) is used. To get a numeric answer, use p.subs(x, value).evalf().
import sympy as sym
acc = 10 ** -4
x = sym.Symbol('x')
p = 924 * x ** 6 - 2772 * x ** 5 + 3150 * x ** 4 - 1680 * x ** 3 + 420 * x ** 2 - 42 * x + 1
p_prime = sym.diff(p)
def newton(p, p_prime, acc, start_val):
xi = start_val
delta = sym.oo
while abs(delta) > acc:
delta = (p / p_prime).subs(x, xi).evalf()
print(xi, delta)
xi -= delta
return xi
a = newton(p, p_prime, 10**-4, 0)
Intermediate values:
0 -0.0238095238095238
0.0238095238095238 -0.00876459050881560
0.0325741143183394 -0.00117130331903862
0.0337454176373780 -1.98196463560775e-5
0.0337652372837341
PS: To plot a function represented as an expression:
sym.plot(p, (x, -0.03, 1.03), ylim=(-0.5, 1.5))
Related
In the code below, inside WKB, I'm trying to pass the function "integrand" as an argument of the function int_gauss (like this: int_gauss(integrand(E,x0,m1,x),xp,wp)) and it returns me an error.
TypeError: 'numpy.ndarray' object is not callable
Thanks in advance for your help.
x0=1
m1=1
h=1
e=100
import numpy as np
import matplotlib.pyplot as plt
def gaussxw(N):
a = np.linspace(3,4*N-1,N)/(4*N+2)
x = np.cos(np.pi*a+1/(8*N*N*np.tan(a)))
# Find roots using Newton's method
epsilon = 1e-15
delta = 1.0
while delta>epsilon:
p0 = np.ones(N,float)
p1 = np.copy(x)
for k in range(1,N):
p0,p1 = p1,((2*k+1)*x*p1-k*p0)/(k+1)
dp = (N+1)*(p0-x*p1)/(1-x*x)
dx = p1/dp
x -= dx
delta = max(abs(dx))
# Calculate the weights
w = 2*(N+1)*(N+1)/(N*N*(1-x*x)*dp*dp)
return x,w
def gaussxwab(N,a,b):
x,w = gaussxw(N)
return 0.5*(b-a)*x+0.5*(b+a),0.5*(b-a)*w
N = 50
x, w = gaussxw(N)
def integrand(E,x0,m1,x):
return np.sqrt((2*m1*(E- (e*( ((x0/x)**12) -2*((x0/x)**6) ) ))))
def WKB(E,x0,e):
a, b = x0*(1+np.sqrt(1+(E/e)))**(-1/6), x0*(1-np.sqrt(1+(E/e)))**(-1/6)
xp = 0.5*(b - a)*x + 0.5*(b + a)
wp = 0.5*(b - a)*w
return int_gauss(integrand(E,x0,m1,x),xp,wp)
def int_gauss(f,nodes, weights):
result = 0.0
for x, w in zip(nodes, weights):
result += w *f(x)
return result
plt.close()
En=np.linspace(-100,-1,496)
W=[WKB(i,x0,e) for i in En]
plt.figure()
plt.plot(En,W)
plt.grid()
plt.axis()
plt.show()
I find the desired result when I explicitly compute the desired function "integrand" inside int_gauss like this but I'd like to be able to call int_gauss with the integrand function as a parameter int_gauss(integrand(E,x0,m1,x),xp,wp) inside WKB:
def WKB(E,x0,e):
a, b = x0*(1+np.sqrt(1+(E/e)))**(-1/6), x0*(1-np.sqrt(1+(E/e)))**(-1/6)
xp = 0.5*(b - a)*x + 0.5*(b + a)
wp = 0.5*(b - a)*w
return int_gauss(E,x0,m1,xp,wp)
def int_gauss(E,x0,m1,nodes, weights):
result = 0.0
for x, w in zip(nodes, weights):
result += w * np.sqrt((2*m1*(E- (e*( ((x0/x)**12) -2*((x0/x)**6) ) ))))
return result
I am trying to solve a function in an annular domain that has a change of phase with respect to the angular direction of the annulus.
My attempt to solve it is the following:
import numpy as np
from scipy import integrate
def f(x0, y0):
r = np.sqrt(x0**2 + y0**2)
if r >= rIn and r <= rOut:
theta = np.arctan(y0 / x0)
R = np.sqrt((x - x0)**2 + (y - y0)**2 + z**2)
integrand = (np.exp(-1j * (k*R + theta))) / R
return integrand
else:
return 0
# Test
rIn = 0.5
rOut = 1.5
x = 1
y = 1
z = 1
k = 3.66
I = integrate.dblquad(f, -rOut, rOut, lambda x0: -rOut, lambda x0: rOut)
My problem is that I don't know how to get rid of the division by zero occuring when I evaluate theta.
Any help will be more than appreciated!
Use numpy.arctan2 instead, it will have problems only if both x and y are zero, in which case the angle is undetermined.
Also I see you that your integrand is complex, in this case you will probably have to handle real and imaginary part separately, as done here.
I am trying to fit a function cav=p(T,x) with the condition that the derivation after x of cav for constant T is always positive dp/dx (for constant T) > 0. The data of x, T and p are from excel sheets. z are my coefficients I am trying to get.
I've used the solution from here Fitting with constraints on derivative Python as a template. Here is my code as it is right now with the providing error message:
import pandas as pd
import os
from scipy.optimize import minimize
import numpy as np
df = pd.read_excel(os.path.join(os.path.dirname(__file__), "./data.xlsx"))
T = np.array(df['T'], dtype=float)
x = np.array(df['x'], dtype=float)
p = np.array(df['p'], dtype=float)
p_s = 67
def cav(z,T,x): #my function
return x * p_s + x * (1 - x) * (z[0] + z[1] * T + z[2] * T ** 2 + z[3] * x + z[4] * x * T + z[5] * x * T ** 2) * p_s
def resid(p,T,x):
return ((p-cav(T,x))**2).sum()
def constr(z):
return np.gradient(cav(z,x,T))
con1 = {'type': 'ineq', 'fun': constr}
z0 = np.array([0,0,0,0,0,0], dtype=float)
res = minimize(resid,z0, args=(p,T,x), method='cobyla',options={'maxiter':50000}, constraints=con1)
And the Error:
TypeError: resid() takes 3 positional arguments but 4 were given
I don't understand what exactly do I have to put in as arguments for the three def. Thanks for any help!
The error is because you are passing 3 arguments to resid in addition to the initial guess z0.
Thus, the line which has to change is:
res = minimize(resid,z0, args=(T,x), method='cobyla',options={'maxiter':50000}, constraints=con1)
Another issue in your code is:
def resid(p,T,x):
return ((p-cav(T,x))**2).sum()
Your method cav takes three arguments but you pass only two. So this probably should be changed to:
def resid(p,T,x):
return ((p-cav(p,T,x))**2).sum()
I am new to python and don't understand how to use the libraries properly. I am trying to write a program to compute the Taylor Series Approximation of a function centered at 0 at a given x and n.
def fact(n): #function to calculate n!
if n <= 0:
return 1
else:
return n * fact(n - 1)
#h= 0.00000000001
#def derivative(f,x,n): #function that calculates the derivative of a
function at a specified x
# return (f(x + h) - f(x - h)) /(2 * h)
from sympy import *
x = symbols('x')
def taylor(f,x,n):
for i in range(0,n):
t = 0
t = t + ((diff(f,x,n))/(fact(n))) * (x ** n)
return t
taylor(sin(x),1/32,1)
Here is what works for me after I fixed stuff from your code. I used sympy factorial.
from sympy import *
x = symbols('x')
def taylor(f,x,x0, n):
t = 0
for i in range(0,n):
t = t + ((diff(f,x,i).subs(x,x0))/(factorial(i))) * (x ** i)
return t
pprint(taylor(sin(x),x,Rational(1,32),4))
and the answer I get is
3 2
x ⋅cos(1/32) x ⋅sin(1/32)
- ──────────── - ──────────── + x⋅cos(1/32) + sin(1/32)
6 2
I'm trying to fit a piecewise function with absolute values using Numpy.
The mathematical function is
x < p[1]: y = 1 + p[0] * abs((size + x - p[1]) / size - size / 2)
x >= p[1]: y = 1 + p[0] * abs((x - p[1]) / size - size / 2)
Here's my Python function:
fitfunc = lambda p, x: \
x < p[1] and\
1 + p[0] * abs((data['n1'].size + x - p[1]) / data['n1'].size - data['n1'].size / 2) or\
1 + p[0] * abs((x - p[1]) / data['n1'].size - data['n1'].size / 2)
Though, I'm getting the error:
The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
However, any and all evaluate an entire list to a single boolean value.
More info:
I've used lambdas to fit data to a sine wave by using the following:
fitfunc = lambda p, x: 1 + p[0] * sin(pi * x / data['n1'].size + p[1])
errfunc = lambda p, x, y: fitfunc(p, x) - y # Distance to the target function
Then in a loop:
data = np.genfromtxt(dataFileName, names=('n1', 'n2'))
xAxisSeries = scipy.linspace(0., data['n1'].max(), data['n1'].size)
p0 = [489., 123.] # Initial guess for the parameters
p1, success = scipy.optimize.leastsq(errfunc, p0[:], args=(xAxisSeries, data['n2']))
#time says which points from the sine wave will be plotted
time = scipy.linspace(0., data['n1'].max(), 100)
pylab.plot(time, fitfunc(p1, time), 'r-')
I'm trying to use a lambda function because optimize.leastsq requires one. I'm using the exact same code with the exception of fitfunc being changed.
The code above does not look idiomatic and is making life harder than it should be. :)
If you're trying to define a function and give it a name at the same time, the conventional approach is to use def, not lambda.
fitfunc = lambda p, x: ... ## you're making a named function, so just do...
def fitfunc(p, x): ...
And once you have that, you don't have to simulate short-circuiting branches with 'and' and 'or': you can just use if. You're getting into trouble trying to simulate if.
Truely speaking, it is not clear what you are trying to do with your lambda function.
But maybe it is the time of the day on my side of the globe...
In anycase, do note, that any(somelist) and np.array().any() are the same, but can be called differently.
In [2]: a=np.ones(4)
In [3]: a
Out[3]: array([ 1., 1., 1., 1.])
In [4]: a.any()
Out[4]: True
In [8]: a[1]=0
In [9]: a.all()
Out[9]: False
In [11]: somelist=["1","1","a","3"]
In [12]: any(somelist)
Out[12]: True
Do note also comment, how do you call this function? Can you please post more code?
Use def and scipy.optimize.curve_fit().
import scipy.optimize as so
def fitfunc(p, x):
'''Define fit function'''
if x < p[1]:
return 1 + p[0] * abs((data['n1'].size + x - p[1]) / data['n1'].size - data['n1'].size / 2)
else:
return 1 + p[0] * abs((x - p[1]) / data['n1'].size - data['n1'].size / 2)
popt, pcov = so.curve_fit(fitfunc, x, y)