Using fsolve with scipy function - python

I have encountered the following problem with scipy.fsolve, but I don't what to do:
U = 0.00043
ThC =1.19
Dist = 7
IncT = 0.2
pcw = 1180000
k = 1.19
B = U * pcw / (2 * k)
fugato = fsolve((((Ql/(2*math.pi* k))*math.exp(B * x)*special.kv(0, B * x))-IncT),0.01)
print fugato
I get the error TypeError: 'numpy.float64' object is not callable in fsolve.
How do I fix this problem?

The argument to fsolve must be a function.
I presume that you want to solve your equation for x? If so, writing:
fugato = fsolve(lambda x: Ql/(2*math.pi* k)*math.exp(B * x)*special.kv(0, B * x)-IncT,
0.01)
works.
To explain what's going on here, the construct lambda x: 2*x is a function definition. It is similar to writing:
def f(x):
return 2*x
The lambda construction is commonly used to define functions that you only need once. This is often the case when registering callbacks, or to represent a mathematical expression. For instance, if you wanted to integrate f(x) = 2*x, you could write:
from scipy.integrate import quad
integral = quad(lambda x: 2*x, 0., 3.)
Similarly, if you want to solve 2*x = 1, you can write:
from scipy.optimize import fsolve
fsolve(lambda x: 2*x-1, 0.)

Related

Differentiation of a multivariate function via SymPy and evaluation at a point

I want to take the derivative of a multivariable function using SymPy and then for a) the symbolic result to be printed and then b) the result of the derivative at a point to be printed. I'm using the following code
import math as m
import numpy
import scipy
#define constants
lambdasq = 0.09
Ca = 3
qOsq = 2
def f1(a,b,NN,ktsq,x):
return NN*x**(-a)*ktsq**b*m.exp(m.sqrt(16*Ca/9*m.log(1/x)*m.log((m.log(ktsq/lambdasq))/m.log(qOsq/lambdasq))))
from sympy import *
x = symbols('x')
def f2(NN,a,b,x,ktsq):
return -x*diff(m.log(f1),x)
This runs but I can't find a way to get the symbolic result to be printed and when I try to evaluate at a point, say e.g adding in print(f2(0.3,0.1,-0.2,0.1,3)) I get an error
TypeError: must be real number, not function
When I replace f1 with its symbolic representation, I get instead the error
ValueError:
Can't calculate 1st derivative wrt 0.100000000000000.
So I can summarise my question as follows
a) How to print out a symbolic derivative and its value at a point when I call diff(m.log(f1),x) (i.e without having to replace f1 by its actual representation)
b) If I have to use the symbolic representation in the differentiation (i.e use diff(m.log(NN*x**(-a)*ktsq**b*m.exp(m.sqrt(16*Ca/9*m.log(1/x)*m.log((m.log(ktsq\
/lambdasq))/m.log(qOsq/lambdasq))))),x) then how to print out the symbolic derivative and its value at a point?
New to Python so hopefully there is a relatively simple fix.
Thanks!
I'm posting this answer since this thread is #1 on my search engine when searching for 'simpy multivariate differentiation' and might help someone.
example 1
import sympy as sp
def f(u):
return (u[0]**2 + u[1]**10 + u[2] - 4)**2
u = sp.IndexedBase('u')
print(sp.diff(f(u), u[0]))
outputs
4*(u[0]**2 + u[1]**10 + u[2] - 4)*u[0]
This is the derivative of f(u) wrt u[0]
example 2
if we want the whole jacobian, we can do:
for i in range(3):
print(sp.diff(f(u), u[i]))
which outputs
4*(u[0]**2 + u[1]**10 + u[2] - 4)*u[0]
20*(u[0]**2 + u[1]**10 + u[2] - 4)*u[1]**9
2*u[0]**2 + 2*u[1]**10 + 2*u[2] - 8
we can define a temp function and copy paste these lines
def temp(u):
return np.array([
4*(u[0]**2 + u[1]**10 + u[2] - 4)*u[0],
20*(u[0]**2 + u[1]**10 + u[2] - 4)*u[1]**9,
2*u[0]**2 + 2*u[1]**10 + 2*u[2] - 8,
])
temp([1., 1., 1.])
this outputs array([ -4., -20., -2.])
and to verify
from autograd import grad
gradient = grad(f)
gradient([1., 1., 1.])
this outputs: [array(-4.), array(-20.), array(-2.)]
Note:This is just a simple showcase how you can do multivariate derivatives in sympy. I hope I can help someone with this
First, math functions are numeric, they cannot work with SymPy's symbols. Use the corresponding functions from SymPy (exp, log, sqrt) which you already imported with from sympy import *:
def f1(a, b, NN, ktsq, x):
return NN*x**(-a)*ktsq**b*exp(sqrt(16*Ca/9*log(1/x)*log((log(ktsq/lambdasq))/log(qOsq/lambdasq))))
Second, within f2 you are trying to differentiate f1. But f1 is a callable Python function, not a SymPy expression. You need to pass in some arguments to get a SymPy expression, which can then be differentiated.
def f2(NN, a, b, x0, ktsq):
return (-x*diff(log(f1(a, b, NN, ktsq, x)), x)).subs(x, x0)
Here the numeric arguments, except the value x0, are passed to f1, resulting in a SymPy expression containing x. That is a thing to be differentiated. After that, the numeric value x0 is substituted for x.
print(f2(0.3,0.1,-0.2,0.1,3)) # 0.366748952743614
A take-away point is that SymPy differentiates expressions, not functions. There is no concept of f' in SymPy, only f'(x).

How to put an integral in a function in python/matplotlib

So pretty much, I am aiming to achieve a function f(x)
My problem is that my function has an integral in it, and I only know how to construct definite integrals, so my question is how does one create an indefinite integral in a function (or there may be some other method I am currently unaware of)
My function is defined as :
(G is gravitational constant, although you can leave G out of your answer for simplicity, I'll add it in my code)
Here is the starting point, but I don't know how to do the integral portion
import numpy as np
def f(x):
rho = 5*(1/(1+((x**2)/(3**2))))
function_result = rho * 4 * np.pi * x**2
return function_result
Please let me know if I need to elaborate on something.
EDIT-----------------------------------------------------
I made some major progress, but I still have one little error.
Pretty much, I did this:
from sympy import *
x = Symbol('x')
rho = p0()*(1/(1+((x**2)/(rc()**2))))* 4 * np.pi * x**2
fooply = integrate(rho,x)
def f(rx):
function_result = fooply.subs({x:rx})
return function_result
Which works fine when I plug in one number for f; however, when I plug in an array (as I need to later), I get the error:
raise SympifyError(a)
sympy.core.sympify.SympifyError: SympifyError: [3, 3, 3, 3, 3]
(Here, I did print(f([3,3,3,3,3]))). Usually, the function returns an array of values. So if I did f([3,2]) it should return [f(3),f(2)]. Yet, for some reason, it doesn't for my function....
Thanks in advance
how about:
from sympy import *
x, p0, rc = symbols('x p0 rc', real=True, positive=True)
rho = p0*(1/(1+((x**2)/(rc))))* 4 * pi * x**2
fooply = integrate(rho,x)/x
rho, fooply
(4*pi*p0*x**2/(1 + x**2/rc),
4*pi*p0*rc*(-sqrt(rc)*atan(x/sqrt(rc)) + x)/x)
fooply = fooply.subs({p0: 2.0, rc: 3.0})
np_fooply = lambdify(x, fooply, 'numpy')
print(np_fooply(np.array([3,3,3,3,3])))
[ 29.81247362 29.81247362 29.81247362 29.81247362 29.81247362]
To plug in an array to a SymPy expression, you need to use lambdify to convert it to a NumPy function (f = lambdify(x, fooply)). Just using def and subs as you have done will not work.
Also, in general, when using symbolic computations, it's better to use sympy.pi instead of np.pi, as the former is symbolic and can simplify. It will automatically be converted to the numeric pi by lambdify.

How to Integrate Arc Lengths using python, numpy, and scipy?

On another thread, I saw someone manage to integrate the length of a arc using mathematica.They wrote:
In[1]:= ArcTan[3.05*Tan[5Pi/18]/2.23]
Out[1]= 1.02051
In[2]:= x=3.05 Cos[t];
In[3]:= y=2.23 Sin[t];
In[4]:= NIntegrate[Sqrt[D[x,t]^2+D[y,t]^2],{t,0,1.02051}]
Out[4]= 2.53143
How exactly could this be transferred to python using the imports of numpy and scipy? In particular, I am stuck on line 4 in his code with the "NIntegrate" function. Thanks for the help!
Also, if I already have the arc length and the vertical axis length, how would I be able to reverse the program to spit out the original paremeters from the known values? Thanks!
To my knowledge scipy cannot perform symbolic computations (such as symbolic differentiation). You may want to have a look at http://www.sympy.org for a symbolic computation package. Therefore, in the example below, I compute derivatives analytically (the Dx(t) and Dy(t) functions).
>>> from scipy.integrate import quad
>>> import numpy as np
>>> Dx = lambda t: -3.05 * np.sin(t)
>>> Dy = lambda t: 2.23 * np.cos(t)
>>> quad(lambda t: np.sqrt(Dx(t)**2 + Dy(t)**2), 0, 1.02051)
(2.531432761012828, 2.810454936566873e-14)
EDIT: Second part of the question - inverting the problem
From the fact that you know the value of the integral (arc) you can now solve for one of the parameters that determine the arc (semi-axes, angle, etc.) Let's assume you want to solve for the angle. Then you can use one of the non-linear solvers in scipy, to revert the equation quad(theta) - arcval == 0. You can do it like this:
>>> from scipy.integrate import quad
>>> from scipy.optimize import broyden1
>>> import numpy as np
>>> a = 3.05
>>> b = 2.23
>>> Dx = lambda t: -a * np.sin(t)
>>> Dy = lambda t: b * np.cos(t)
>>> arc = lambda theta: quad(lambda t: np.sqrt(Dx(t)**2 + Dy(t)**2), 0, np.arctan((a / b) * np.tan(np.deg2rad(theta))))[0]
>>> invert = lambda arcval: float(broyden1(lambda x: arc(x) - arcval, np.rad2deg(arcval / np.sqrt((a**2 + b**2) / 2.0))))
Then:
>>> arc(50)
2.531419526553662
>>> invert(arc(50))
50.000031008458365
If you prefer a pure numerical approach, you could use the following barebones solution. This worked well for me given that I had two input numpy.ndarrays, x and y with no functional form available.
import numpy as np
def arclength(x, y, a, b):
"""
Computes the arclength of the given curve
defined by (x0, y0), (x1, y1) ... (xn, yn)
over the provided bounds, `a` and `b`.
Parameters
----------
x: numpy.ndarray
The array of x values
y: numpy.ndarray
The array of y values corresponding to each value of x
a: int
The lower limit to integrate from
b: int
The upper limit to integrate to
Returns
-------
numpy.float64
The arclength of the curve
"""
bounds = (x >= a) & (y <= b)
return np.trapz(
np.sqrt(
1 + np.gradient(y[bounds], x[bounds])
) ** 2),
x[bounds]
)
Note: I spaced the return variables out that way just to make it more readable and clear to understand the operations taking place.
As an aside, recall that the arc-length of a curve is given by:

Math domain error due to disrespected constraint in scipy SLSQP minimize

Consider a simple problem:
max log(x)
subject to x >= 1e-4
To solve the problem with scipy.optimize.minimize:
import numpy as np
from scipy.optimize import minimize
from math import log
def func(x):
return log(x[0])
def func_deriv(x):
return np.array([1 / x[0]])
cons = ({'type': 'ineq',
'fun' : lambda x: x[0] - 1e-4,
'jac' : lambda x: np.array([1])})
minimize(func, [1.0], jac=func_deriv, constraints=cons, method='SLSQP')
The script encounters ValueError because log(x) is evaluated with negative x. It seems that the function value is evaluated even if the constraint is not satisfied.
I understand that using bounds in minimize() could avoid the problem, but this is just a simplification of my original problem. In my original problem, the constraint x >= 1e-4 cannot be represented easily as bounds of x, but rather of the form g(x) >= C, so bounds wouldn't help.
If we only care about the function value with x > ε, it is possible to define a safe function extending the domain.
Take the log function as an example. It is possible to extend log with another cubic function, while making the bridge point ε smooth:
safe_log(x) = log(x) if x > ε else a * (x - b)**3
To calculate a and b, we have to satisfy:
log(ε) = a * (ε - b)**3
1 / ε = 3 * a * (ε - b)**2
Hence the safe_log function:
eps = 1e-3
def safe_log(x):
if x > eps:
return log(x)
logeps = log(eps)
a = 1 / (3 * eps * (3 * logeps * eps)**2)
b = eps * (1 - 3 * logeps)
return a * (x - b)**3
And it looks like this:

Finding the maximum of a function

How do I find the maximum of a function in Python? I could try to hack together a derivative function and find the zero of that, but is there a method in numpy (or other library) that can do it for me?
You can use scipy.optimize.fmin on the negative of your function.
def f(x): return -2 * x**2 + 4 * x
max_x = scipy.optimize.fmin(lambda x: -f(x), 0)
# array([ 1.])
If your function is solvable analytically try SymPy. I'll use EMS's example above.
In [1]: from sympy import *
In [2]: x = Symbol('x', real=True)
In [3]: f = -2 * x**2 + 4*x
In [4]: fprime = f.diff(x)
In [5]: fprime
Out[5]: -4*x + 4
In [6]: solve(fprime, x) # solve fprime = 0 with respect to x
Out[6]: [1]
Of course, you'll still need to check that 1 is a maximizer and not a minimizer of f
In [7]: f.diff(x).diff(x) < 0
Out[7]: True
I think scipy.optimize.minimize_scalar and scipy.optimize.minimize are the preferred ways now, that give you access to the range of techniques, e.g.
solution = scipy.optimize.minimize_scalar(lambda x: -f(x), bounds=[0,1], method='bounded')
for a single variable function that must lie between 0 and 1.
You could try SymPy. SymPy might be able to provide you with the derivative symbolically, find its zeros, and so on.
Maximum of a function with parameters.
import scipy.optimize as opt
def get_function_max(f, *args):
"""
>>> round(get_function_max(lambda x, *a: 3.0-2.0*(x**2)), 2)
3.0
>>> round(get_function_max(lambda x, *a: 3.0-2.0*(x**2)-2.0*x), 2)
3.5
>>> round(get_function_max(lambda x, *a: a[0]-a[1]*(x**2)-a[1]*x, 3.0, 2.0), 2)
3.5
"""
def func(x, *arg):
return -f(x, *arg)
return f(opt.fmin(func, 0, args=args, disp=False)[0], *args)

Categories