This expression returns zero, but it shouldn`t.
P = x^6-14x^4+49x^2-36
integrate(1/P, (x, 1/3, 1/2))
I also used expand on expression, without any result.
Am i doing something wrong or is this a bug?
This works:
from sympy import *
x = symbols('x')
P = x**6-14*x**4+49*x**2-36
I = integrate(1/expand(P), (x, S.One/3, S.One/2))
I get the result:
In [5]: I
Out[5]: -3*log(3)/80 - log(7)/48 - log(2)/48 - log(8)/240 + log(10)/240 + log(4)/48 + 3*log(5)/80
In [6]: I.n()
Out[6]: -0.00601350282195297
In alternative, you could run the command isympy -i, this will run a SymPy prompt that converts all Python integers to SymPy integers before the input gets evaluated by the SymPy parser.
Python integer division is different between Python 2 and Python 3, the first returns and integer, the second returns a floating point number. Both versions are different to SymPy integer division, which returns fractions. To use SymPy division, you need to make sure that at least one among the dividend and divisor are SymPy objects.
Related
How can I use scipy.interpolate.interp1d when my x array is an N-D array, instead of a 1-D array, without using a loop?
The function f from interp1d then needs to be used with numpy.percentile with one of the arrays as an input.
I think there should be a way to do it with a list comprehension or lambda function, but I am still learning these tools.
(Note that this is different than my recent question here because I mixed up the x and y arrays in the posted question, and this problem was not reproducible.)
Problem statement/example:
# a is y in interp1d docs
a = np.array([97,4809,4762,282,3879,17454,103,2376,40581,])
# b is x in interp1d docs
b = np.array([
[0.14,0.11,0.29,0.11,0.09,0.68,0.09,0.18,0.5,],
[0.32,0.25,0.67,0.25,0.21,1.56,1.60, 0.41,1.15,],]
)
Just trying this, below, fails with ValueError: x and y arrays must be equal in length along interpolation axis. The expected return is array(97, 2376). Using median here, but will need to consider 10th, 90th, etc. percentiles.
f = interpolate.interp1d(b, a, axis=0)
f(np.percentile(b, 50, axis=0))
However this, below, works and prints array(97.)
f = interpolate.interp1d(b[0,:], a, axis=0)
f(np.percentile(b[0,:], 50, axis=0))
A loop works, but I am wondering if there is a solution using list comprehensions, lambda functions, or some other technique.
l = []
for _i in range(b.shape[0]):
_f = interpolate.interp1d(b[_i,:], a, axis=0)
l.append(_f(np.percentile(b[_i,:], 50, axis=0)))
print(out)
# returns
# [array(97.), array(2376.)]
Efforts:
I understand I can loop through the b array with a list comprehension.
[b[i,:] for i in range(b.shape[0])]
# returns
# [array([0.14, 0.11, 0.29, 0.11, 0.09, 0.68, 0.09, 0.18, 0.5 ]),
# array([0.32, 0.25, 0.67, 0.25, 0.21, 1.56, 1.6 , 0.41, 1.15])]
And I also understand that I can use a list comprehension to create the scipy function f for each dimension in b:
[interpolate.interp1d(b[i, :], a, axis=0) for i in range(b.shape[0])]
# returns
# [<scipy.interpolate.interpolate.interp1d at 0x1b72e404360>,
# <scipy.interpolate.interpolate.interp1d at 0x1b72e404900>]
But I don't know how to combine these two list comprehensions to apply the np.percentile function.
Using Python 3.8.3, NumPy 1.18.5, SciPy 1.3.2
If you have large data arrays, you want to stay away from for loops, map, np.vectorize and comprehensions. They will all be slow. Instead, it's always better to use vectorized numpy or scipy operations whenever possible.
In this particular case, you can implement the vectorization pretty trivially yourself. interp1d defaults to a linear interpolation, which is very simple to code by hand. For a general interpolator, the first step would be to sort x and y, which is why scipy can't support multiple x for a given y. If the x rows all have different sort order, what do you do with the y?
Luckily, there are a couple of things you can do to make this much faster than having to build a full interpolator or argsort y multiple times. For example, start by argsorting x:
idx = b.argsort(axis=1)
idx is now an array such that b[np.arange(2)[:, None], idx] gives the sorted version of b along axis 1, and also, a[idx] is the corresponding y-values. Since you are taking the median (50th precentile), and the rows have an odd number of elements, the value of x is just the middle of each row, and y is given by
a[idx[:, len(a) // 2]]
If you had an even number of elements, you would have to average the elements surrounding the middle:
i = len(a) // 2 - 1
a[idx[:, i:i + 2]].mean(axis=1)
You can reduce algorithmic complexity by using np.argpartition instead of a full-blown np.argsort to get the middle element(s).
interp1d and other interpolators from scipy.interpolate only support 1D x arrays. So you'll need to loop over the dimensions of x manually.
I would like to evaluate the following integral using SymPy:
from sympy import *
x = symbols('x')
a = symbols('a', positive=True)
expr = sqrt(a**2 - x**2)
integrate(expr, (x, 0, pi/2))
What I would expect as an outcome is the area of the quarter circle (i.e., a^2*pi/4). Unfortunately, SymPy does not provide this result. When considering
integrate(expr, x)
I obtain the correct indefinite integral but when adding the limits it does not work.
Any ideas what I am doing wrong?
Thanks and all best,
VK88
The limit should be a if that is the radius and you are working in Cartesian coordinates:
from sympy import *
x = symbols('x')
a = symbols('a', positive=True)
expr = sqrt(a**2 - x**2)
integrate(expr, (x, 0, a))
That gives:
2
π⋅a
────
4
I am fairly new to sympy and hoping if someone could guide me on the right approach. As mentioned the following when integrated gives a NaN output. Is this a mathematics error, sympy limitation or user error?
Since NaN isn't a correct answer for that integral, it is a SymPy error. But it's caused by a suboptimal setup. SymPy finds it difficult to handle expressions with floating-point numbers, because floating-point arithmetics is different from mathematical rules of arithmetics (addition is not associative, for example). This is particularly true for expressions with such constants in an exponent.
For this reason, it's best to keep the floating point constants out of the computations, including them at the end. Instead of
integrate((0.2944/z**0.22+1.0)*(1.939*log(z/10) +17.7), z)
write
a, b, c, d, e = symbols('a b c d e', positive=True)
values = {a: 0.2944, b: 0.22, c: 1.0, d: 1.939, e: 17.7}
expr = integrate((a/z**b + c) * (d*log(z/10) + e), z)
print(expr.subs(values).simplify())
which prints
0.731848205128205*z**0.78*log(z) + 4.05720568750119*z**0.78 + 1.939*z**1.0*log(z) + 11.2962875046845*z**1.0
So I have the function integral(function, n=1000, start=0, stop=100) defined in nums.py:
def integral(function, n=1000, start=0, stop=100):
"""Returns integral of function from start to stop with 'n' rectangles"""
increment, num, x = float(stop - start) / n, 0, start
while x <= stop:
num += eval(function)
if x >= stop: break
x += increment
return increment * num
However, my teacher (for my Programming class) wants us to create a separate program that gets the input using input() and then returns it. So, I have:
def main():
from nums import integral # imports the function that I made in my own 'nums' module
f, n, a, b = get_input()
result = integral(f, n, a, b)
msg = "\nIntegration of " + f + " is: " + str(result)
print(msg)
def get_input():
f = str(input("Function (in quotes, eg: 'x^2'; use 'x' as the variable): ")).replace('^', '**')
# The above makes it Python-evaluable and also gets the input in one line
n = int(input("Numbers of Rectangles (enter as an integer, eg: 1000): "))
a = int(input("Start-Point (enter as an integer, eg: 0): "))
b = int(input("End-Point (enter as an integer, eg: 100): "))
return f, n, a, b
main()
When run in Python 2.7, it works fine:
>>>
Function (in quotes, eg: 'x^2'; use 'x' as the variable): 'x**2'
Numbers of Rectangles (enter as an integer, eg: 1000): 1000
Start-Point (enter as an integer, eg: 0): 0
End-Point (enter as an integer, eg: 100): 100
Integration of x**2 is: 333833.5
However, in Python 3.3 (which my teacher insists we use), it raises an error in my integral function, with the same exact input:
Traceback (most recent call last):
File "D:\my_stuff\Google Drive\documents\SCHOOL\Programming\Python\Programming Class\integration.py", line 20, in <module>
main()
File "D:\my_stuff\Google Drive\documents\SCHOOL\Programming\Python\Programming Class\integration.py", line 8, in main
result = integral(f, n, a, b)
File "D:\my_stuff\Google Drive\Modules\nums.py", line 142, in integral
num += eval(function)
TypeError: unsupported operand type(s) for +=: 'int' and 'str'
In addition, integral by itself (in Python 3.3) works fine:
>>> from nums import integral
>>> integral('x**2')
333833.4999999991
Because of that, I believe the fault is in my program for my class... Any and all help is appreciated. Thanks :)
The issue you're running into is that input works differently in Python 2 and Python 3. In Python 3, the input function works like the raw_input does in Python 2. Python 2's input function is equivalent to eval(input()) in Python 3.
You're getting into trouble because of the quoteation marks you're typing with the formula. When you type 'x**2' (with the quotes) as your formula when running on Python 2, the text gets evaled in the input function and you get a string with no quotation marks as the result. This works.
When you give the same string to Python 3's input function, it doesn't do an eval, so the quotation marks remain. When you later eval the formula as part of your integral calculation, you get the string x**2 (without any quotation marks) as the result, not the value of x squared. This results in an exception when you try the string to 0.
To fix this, I suggest either using just one version of Python, or putting the following code at the top of your file to get a Python 3 style input in both versions:
# ensure we have Python 3 semantics from input, even in Python 2
try:
input = raw_input
except NameError:
pass
Then just type in your formula without quotation marks and it should work correctly.
I am having a problem graphing a 3d function - when I enter data, I get a linear graph and the values don't add up if I perform the calculations by hand. I believe the problem is related to using matrices.
INITIAL_VALUE=999999;
INTEREST_RATE=0.1;
MONTHLY_INTEREST_RATE=INTEREST_RATE/12;
# ranges
down_payment=0.2*INITIAL_VALUE:0.1*INITIAL_VALUE:INITIAL_VALUE;
term=180:22.5:360;
[down_paymentn, termn] = meshgrid(down_payment, term);
# functions
principal=INITIAL_VALUE - down_payment;
figure(1);
plot(principal);
grid;
title("Principal (down payment)");
xlabel("down payment $");
ylabel("principal $ (amount borrowed)");
monthly_payment = (MONTHLY_INTEREST_RATE*(INITIAL_VALUE - down_paymentn))/(1 - (1 + MONTHLY_INTEREST_RATE)^-termn);
figure(2);
mesh(down_paymentn, termn, monthly_payment);
title("monthly payment (principal(down payment)) / term months");
xlabel("principal");
ylabel("term (months)");
zlabel("monthly payment");
The 2nd figure like I said doesn't plot like I expect. How can I change my formula for it to render properly?
I tried your script, and got the following error:
error: octave_base_value::array_value(): wrong type argument `complex matrix'
...
Your monthly_payment is a complex matrix (and it shouldn't be).
I guess the problem is the power operator ^. You should be using .^ for element-by-element operations.
From the documentation:
x ^ y
x ** y
Power operator. If x and y are both scalars, this operator returns x raised to the power y. If x is a scalar and y is a square matrix, the result is computed using an eigenvalue expansion. If x is a square matrix. the result is computed by repeated multiplication if y is an integer, and by an eigenvalue expansion if y is not an integer. An error results if both x and y are matrices.
The implementation of this operator needs to be improved.
x .^ y
x .** y
Element by element power operator. If both operands are matrices, the number of rows and columns must both agree.