So I want to integrate a double integral with constants in it, like a, b, etc where the user can asign the value of this constants:
The limits of the integral are x[0,1] and y[-1,2]
import numpy as np
import scipy.integrate as integrate
def g(y,x,a):
return a*x*y
a = int(input('Insert a value --> '))
result = integrate.dblquad(g, 0, 1, lambda x: -1, lambda x: 2, args=(a))[0]
print(result)
But I get this error and I don't understant why:
TypeError: integrate() argument after * must be an iterable, not int
I don't understand it. Because when I do the same but with quad() Python does it correctly:
import numpy as np
import scipy.integrate as integrate
def g(x,a):
return a*x
a = int(input('Insert a value --> '))
result = integrate.quad(g, 0, 1, args=(a))[0]
print(result)
With the result:
0.5
The problem here is that the value you provide in the optional argument args is a tuple. In the case of quad, it is what the function expects, but for dblquad, a sequence is required. Even though tuples are sequences (immutable ones), it seems that scipy makes a difference here and therefore it is why an error is raised. However it is misleading as a tuple is definitely an iterable. Anyway, this should work:
result = integrate.dblquad(g, 0, 1, lambda x: -1, lambda x: 2, args=[a])[0]
Related
I'm implementing this equation and using it for the set of frequencies nos:
The non vectorized code works:
import numpy as np
h = np.array([1,2,3])
nos = np.array([4, 5, 6, 7])
func = lambda h, no: np.sum([hk * np.exp(-1j * no * k) for k, hk in enumerate(h)])
# Not vectorized
resps = np.zeros(nos.shape[0], dtype='complex')
for i, no in enumerate(nos):
resps[i] = func(h, no)
print(resps)
> Out: array([-0.74378734-1.45446975j,
> -0.94989022+3.54991188j,
> 5.45190245+2.16854975j,
> 2.91801616-4.28579526j])
I'd like to vectorize the call in order to pass nos at once instead of explicitly iterating:
H = np.vectorize(func, excluded={'h'}, signature='(k),(n)->(n)')
resps = H(h, nos)
When calling H:
Error: ValueError: 0-dimensional argument does not have enough dimensions for all core dimensions ('n',)
I'm using the signature parameter but I'm not sure I use it in the correct way. Without this parameter there is an error in func:
TypeError: 'numpy.int32' object is not iterable
I don't understand where the problem is.
A list comprehension version of your loop:
In [15]: np.array([func(h,n) for n in nos])
Out[15]:
array([-0.74378734-1.45446975j, -0.94989022+3.54991188j,
5.45190245+2.16854975j, 2.91801616-4.28579526j])
vectorize - excluding the first argument (by position, not name), and scalar iteration on second.
In [16]: f=np.vectorize(func, excluded=[0])
In [17]: f(h,nos)
Out[17]:
array([-0.74378734-1.45446975j, -0.94989022+3.54991188j,
5.45190245+2.16854975j, 2.91801616-4.28579526j])
No need to use signature.
With true numpy vectorization (not the pseudo np.vectorize):
In [23]: np.sum(h * np.exp(-1j * nos[:,None] * np.arange(len(h))), axis=1)
Out[23]:
array([-0.74378734-1.45446975j, -0.94989022+3.54991188j,
5.45190245+2.16854975j, 2.91801616-4.28579526j])
I'm trying to make some program which involves typing formulas in input by a user.
My code for now looks like so:
import numpy as np
n = int(input('Dim = '))
g = np.zeros((n, n))
for a in range(0, n):
print('Define the metric. \n g_', a, a,'=')
metric_component = 'lambda x, y: ' + str(input())
g[a, a] = eval(metric_component)
print(g)
I tried to search for answers but those i found didn't work. eval() function gives me error there: float() argument must be a string or a number, not 'function': sympify() gives basically the same "can't convert expression to float"
Also i want to work on those constants not their numeric values, so i'm interesting to keep them through all program and have the final output expressed by them. Is it even possible?
input() will return a string
>>> type(input()) # I type 1
1
<class 'str'>
So if you are expecting numeric input from the user and it can be non-integer, then just wrap the input with float.
import numpy as np
n = int(input('Dim = '))
g = np.zeros((n, n))
for a in range(0, n):
print('Define the metric. \n g_', a, a,'=')
g[a, a] = float(input())
print(g)
It's hard to tell what you want to be able to interpret from the user. If the user is going to give some expression of x and y and you are going to replace both those values with a you would either have to build a lambda that could be evaluated or do a substitution into a sympified expression:
>>> eval('(lambda x,y:'+'x + 2*y'+')(%s,%s)'%(a,a))
3*a
>>> sympify('x+2*y').subs(dict(x=a,y=a))
3*a
If you want the user to input expressions and then do something to them later, SymPy is ideally suited for this. Here, the user is prompted to fill items in a list and then those items are differentiated wrt x. It's just a toy example:
>>> from sympy import S # shortcut for sympify
>>> from sympy.abc import x
>>> [S(input('?')) for i in range(2)]
?R**2
?R**2*sin(x)**2
[R**2, R**2*sin(x)**2]
>>> [i.diff(x) for i in _]
[0, 2*R**2*sin(x)*cos(x)]
I have a problem I'm working on where I have to produce a function which mirrors a mathematical one given:
Probability = e^beta / 1 + e^beta. So far I produced code that works when I feed it an integer, but I need to use the function to calculate the probabilities of an array.
My code so far:
import math
e = math.e
def likelihood(beta):
for i in range(beta):
return (e**(beta)/(1+ e**(beta)))
beta_candidate = np.random.uniform(-5, 5, 50)
likelihood_candidate = likelihood(beta_candidate)
Whenever I run the code I'm met with an error stating: only integer scalar arrays can be converted to a scalar index.
In [3]: import math
In [4]: e = math.e
In [5]: def likelihood(beta):
...: return [e**i/(1+e**i) for i in beta]
...:
In [7]: likelihood_candidate = likelihood(beta_candidate)
Since you have your beta_candidate as numpy array, you can just do vectorized numpy operations:
l = np.exp(beta_candidate)/(1+np.exp(beta_candidate))
So, I have this code
from __future__ import division, print_function
import sympy as sp
import numpy as np
from sympy.utilities.lambdify import *
u = np.random.uniform(4, 6, 500)
w, k = sp.symbols('w k')
f = sp.log((k - w) * sp.exp((k - w)**5))
l = sum(f.subs(dict(k=k)) for k in u)
And now I want to use l as a function of w. So I know of some options
z_lambdify = lambdify(w, l)
z_subs = lambda x: l.subs(w, x)
The first function gives an error
>>> z_lambdify(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <lambda>
OverflowError: math range error
>>> z_lambdify(4)
40.862695278600114
While the second gives answers
>>> z_subs(1)
11469.9130597554
>>> z_subs(4)
40.8626952786003
I would just use this, but it is very slow. Any way to get around this (fixing the lamdify error or a way of using l as a function that is not so slow)?
Version: Python 2.7.6, NumPy 1.8.1, SymPy 0.7.4.1
Answering your question:
The problem is that:
z_lambdify = lambdify(w, l)
tells the new function to perform the calculations using the built-in math functions, which you can check running with cProfile.run('z_lambdify(1)'); while doing z_subs(1) calls sympy functions. To get the same behavior you should tell lambdify() to use the same module:
z_lambdify = lambdify(w, l, "sympy")
Important suggestion:
You should simplify your function already at its definition and then useNumPy to perform the calculations much more efficiently. Using some simple algebra your function can be rewritten in a "non-overflowing" format as:
f = lambda k, w: np.log(k - w) + (k - w)**5
such that your desired answer can be achieved doing:
f(k=u, w=1).sum()
when you do f(k=u, w=1) you get an array with the same shape of u, where each value represents the result of the function evaluated with each value of u. You can use this function to simultaneously evaluate f() for different values of k and w, i.e. passing w as another array with the same shape of u instead of using a constant value.
Suppose I have a function whose range is a scalar but whose domain is a vector. For example:
def func(x):
return x[0] + 1 + x[1]**2
What's a good way to find the a root of this function? scipy.optimize.fsolve and scipy.optimize.root expect func to return a vector (rather than a scalar), and scipy.optimize.newton only takes scalar arguments. I can redefine func as
def func(x):
return [x[0] + 1 + x[1]**2, 0]
Then root and fsolve can find a root, but the zeros in the Jacobian means it won't always do a good job. For example:
fsolve(func, array([0,2]))
=> array([-5, 2])
It'll only vary the first parameter but not the second, meaning that it often finds a zero that's far away.
EDIT: it looks like the following redefinition of func works better:
def func(x):
fx = x[0] + 1 + x[1]**2
return [fx, fx]
fsolve(func, array([0,5]))
=>array([-16.27342781, 3.90812331])
So it's now willing to change both parameters. The code is still kind of ugly though.
Have you tried the minimization of the absolute value of your function using fmin?
For example:
>>> import scipy.optimize as op
>>> import numpy as np
>>> def func(x):
>>> return x[0] + 1 + x[1]**2
>>> func1 = lambda x: np.abs(func(x))
>>> tmp = op.fmin(func1, [10000., 10000.])
>>> func(tmp)
0.0
>>> print tmp
[-8346.12025122 91.35162971]
Since -- for my problem -- I have a good initial guess and a non-crazy function, Newton's method works well. For a scalar, multidimensional function, Newton's method becomes:
Here's a rough code example:
def func(x): #the function to find a root of
return x[0] + 1 + x[1]**2
def dfunc(x): #the gradient of that function
return array([1, 2*x[1]])
def newtRoot(x0, func, dfunc):
x = array(x0)
for n in xrange(100): # do at most 100 iterations
f = func(x)
df = dfunc(x)
if abs(f) < 1e-6: # exit function if we're close enough
break
x = x - df*f/norm(df)**2 # update guess
return x
In use:
nsolve([0,2],func,dfunc)
=> array([-1.0052546 , 0.07248865])
func([-1.0052546 , 0.07248865])
=> 4.3788225025098715e-09
Not bad! Of course, this function is very rough, but you get the idea. It also won't work well for "tricky" functions or where you don't have a good starting guess. I think I'll use something like this but then fall back to fsolve or root if Newton's method doesn't converge.