I have 2 columns of arrays. I also have an equation(integration) that uses 2 columns. I need to have the integral values, using two columns values. In the sense that, for each s there is c.
add the third column which would be the integration result based on a specific index number as an upper and under the limit.
As an example, take a look at the values below:
ID=50
s = np.arange(0,100)
c = np.arange(200,300)
lanr=-4.56
lani=-2.33
and the integration that I need to be solved is c(s) * exp(lanr * s) * sin (lani * s). Now my problem is adding the third column with the result of the integration between 0,s[ID], which means that and I need to have the integral with detail that I mentioned in the question between s=0 to s=ID.
I have written something below which does not work:
from scipy.integrate import quad
import numpy as np
from sympy import *
def f(s):
return c*(s) * exp(lanr * s) * sin (lani * s)
integ = []
for i in enumerate(s):
g = c * np.exp(lanr * s) * np.sin(lani * s)
integrate( f(s), s,0,ID)
Maybe the following is similar to what you're looking for?
At the start, we can try to only work symbolically. s is the basic variable. c is a function of s, in this case writing c = s + 200 makes c such a function.
f=c*exp(lanr*s)*sin(lani*s) is a more complicated function of s. print(f) gives -(s+200)*exp(-4.56*s)*sin(2.33*s).
Now, you seem to be interested in the integral of f for s going from 0 till some value. Let's call that value t. Then, that integral would be a function g of t.
from sympy import exp, sin, symbols, integrate, lambdify
s, t = symbols('s t')
lanr = -4.56
lani = -2.33
c = s + 200
f = c * exp(lanr * s) * sin (lani * s)
g = integrate(f, (s, 0, t))
If only 101 values are needed, we can stay inside sympy:
values = [g.subs(t, ti).evalf() for ti in range(0, 101)]
If more numeric calculations are needed, lambdify() can convert g from sympy to numpy.
Then numpy can also calculate the first 101 values (this works much faster than in sympy, but that is only important if many more calculations are needed):
g_np = lambdify(t, g)
import numpy as np
x = np.arange(0,100)
y = g_np(x)
In this case the result would be
array([ 0. , -17.66531171, -17.80584637, -17.80185932,
-17.8019015 , -17.80190133, -17.80190133, -17.80190133,
-17.80190133, -17.80190133, -17.80190133, -17.80190133,
-17.80190133, -17.80190133, -17.80190133, -17.80190133,
...
This looks quite strange. Maybe there is some misunderstanding somewhere? Or maybe the original formula has some mistake?
Related
Is it possible to solve Cubic equation without using sympy?
Example:
import sympy as sp
xp = 30
num = xp + 4.44
sp.var('x, a, b, c, d')
Sol3 = sp.solve(0.0509 * x ** 3 + 0.0192 * x ** 2 + 3.68 * x - num, x)
The result is:
[6.07118098358257, -3.2241955998463 - 10.0524891203436*I, -3.2241955998463 + 10.0524891203436*I]
But I want to find a way to do it with numpy or without 3 part lib at all
I tried with numpy:
import numpy as np
coeff = [0.0509, 0.0192, 3.68, --4.44]
print(np.roots(coeff))
But the result is :
[ 0.40668245+8.54994773j 0.40668245-8.54994773j -1.19057511+0.j]
In your numpy method you are making two slight mistakes with the final coefficient.
In the SymPy example your last coefficient is - num, this is, according to your code: -num = - (xp + 4.44) = -(30 + 4.44) = -34.44
In your NumPy example yout last coefficient is --4.44, which is 4.44 and does not equal -34.33.
If you edit the NumPy code you will get:
import numpy as np
coeff = [0.0509, 0.0192, 3.68, -34.44]
print(np.roots(coeff))
[-3.2241956 +10.05248912j -3.2241956 -10.05248912j
6.07118098 +0.j ]
The answer are thus the same (note that NumPy uses j to indicate a complex number. SymPy used I)
You could implement the cubic formula
this Youtube video from mathologer could help understand it.
Based on that, the cubic function for ax^3 + bx^2 + cx + d = 0 can be written like this:
def cubic(a,b,c,d):
n = -b**3/27/a**3 + b*c/6/a**2 - d/2/a
s = (n**2 + (c/3/a - b**2/9/a**2)**3)**0.5
r0 = (n-s)**(1/3)+(n+s)**(1/3) - b/3/a
r1 = (n+s)**(1/3)+(n+s)**(1/3) - b/3/a
r2 = (n-s)**(1/3)+(n-s)**(1/3) - b/3/a
return (r0,r1,r2)
The simplified version of the formula only needs to get c and d as parameters (aka p and q) and can be implemented like this:
def cubic(p,q):
n = -q/2
s = (q*q/4+p**3/27)**0.5
r0 = (n-s)**(1/3)+(n+s)**(1/3)
r1 = (n+s)**(1/3)+(n+s)**(1/3)
r2 = (n-s)**(1/3)+(n-s)**(1/3)
return (r0,r1,r2)
print(cubic(-15,-126))
(5.999999999999999, 9.999999999999998, 2.0)
I'll let you mix in complex number operations to properly get all 3 roots
Through using the ways and obtaining help from Stackoverflow users, I could find half of the solution and I need to complete it.
Through using Sympy I could produce my function parametrically and it became 100 different items similar to 0.03149536*exp(-4.56*s)*sin(2.33*s) 0.03446408*exp(-4.56*s)*sin(2.33*s). By using f = lambdify(s,f) I converted it to a NumPy function and I needed to do integral of in the different sthat I already have. The upper limit of the integral is a constant value and the lower limit must be done through afor loop`.
When I try to do, I get some error which I post below. The code that I wrote is below, but for being a reproducible question I have to put a generated data. TypeError: cannot determine truth value of Relational
from sympy import exp, sin, symbols, integrate, lambdify
import pandas as pd
import matplotlib.pyplot as plt
from scipy import integrate
import numpy as np
S = np.linspace(0,1000,100)
C = np.linspace(0,1,100)
s, t = symbols('s t')
lanr = -4.56
lani = -2.33
ID = S[-1]
result=[]
f = C * exp(lanr * s) * sin (lani * s)
f = lambdify(s,f)
#vff = np.vectorize(f)
for i in (S):
I = integrate.quad(f,s,(i,ID))
result.append(I)
print(result)
EDIT
I tried to do the same without havingSympy by using just Scipy and wrote the code below and again I could not solve the problem.
from scipy.integrate import quad
import numpy as np
lanr = -6.55
lani = -4.22
def integrand(c,s):
return c * np.exp(lanr * s) * np.sin (lani * s)
def self_integrate(c,s):
return quad(integrand,s,1003,1200)
import pandas as pd
file = pd.read_csv('1-100.csv',sep="\s+",header=None)
s = np.linspace(0,1000,100)
c = np.linspace(0,1,100)
ID = s[-1]
for i in s:
I = self_integrate(integrand,c,s)
print(I)
and I got this TypeError: self_integrate() takes 2 positional arguments but 3 were given
Assuming you want to integrate over s, and use c as a fixed parameter (for a given quad call), define:
In [198]: lanr = 1
...: lani = 2
...: def integrand(s, c):
...: return c * np.exp(lanr * s) * np.sin (lani * s)
...:
test it by itself:
In [199]: integrand(10,1.23)
Out[199]: 24734.0175253505
and test it in quad:
In [200]: quad(integrand, 0, 10, args=(1.23,))
Out[200]: (524.9015616747192, 3.381048596651226e-08)
doing the same for a range of c values:
In [201]: alist = []
...: for c in range(0,10):
...: x,y = quad(integrand, 0, 10, args=(c,))
...: alist.append(x)
...:
In [202]: alist
Out[202]:
[0.0,
426.74923713391905,
853.4984742678381,
1280.2477114017531,
1706.9969485356762,
2133.7461856695877,
2560.4954228035062,
2987.244659937424,
3413.9938970713524,
3840.743134205258]
From the quad docs:
quad(func, a, b, args=(),...)
func : {function, scipy.LowLevelCallable}
A Python function or method to integrate. If `func` takes many
arguments, it is integrated along the axis corresponding to the
first argument.
and an example:
>>> f = lambda x,a : a*x
>>> y, err = integrate.quad(f, 0, 1, args=(1,))
The docs are a bit long, but the basics should be straight forward.
I was tempted to say you were stuck on the sympy calling pattern, but the second argument for that is either the integration symbol, or a tuple.
>>> integrate(log(x), (x, 1, a))
a*log(a) - a + 1
So I'm puzzled as to why you were stuck on using
quad(integrand,s,1003,1200)
The s, whether a sympy variable or a linspace array does not make sense.
Good day!
I am using python v3.8 and I want to calculate the value range (minimum and maximum) of a given formula with (also given) bounds e.g.:
formula1: a * sqrt(b/c)
formula2: a^2 * b/1000 + 3 * (a+b)
formula3: (1/(2 * PI * (a * 1000) * (b * 1000)) * 10^12
..with a=[0,5], b=[10,20], c=[30,40]
I am not too familiar with scipy, numpy, sympy.. and I wonder if there is an "easy" way to just calculate the formula with different values, write it into an array and get the min/max from that? The problem I have with "writing into an array and get min/max" is, that there are some bounds [-100000, 100000] with given float numbers and that would generate way too much values.
I do not need the information with which values the minimum/maximum was reached, but only which min/max values can be reached.
Try SymPy solvers, they have solveset that can do the following:
>>> solveset(Eq(x**2, 1), x)
{-1, 1}
Symbolic:
Maximum and minimum points are called critical points. To find a critical point you need to a partial derivative respect every variable (f'_a = df/da, f'_b = df/db, f'_c = df/dc), and solve the system of equations where all of them are equal to 0. We can do this with sympy.
import sympy as sp
a = sp.Symbol('a', real=True)
b = sp.Symbol('b', real=True)
c = sp.Symbol('c', real=True)
functions = [
a * sp.sqrt(b / c),
a**2 * b/1000 + 3*(a+b),
10**6 / (2 * sp.pi * a * b),
]
for f in functions:
f_a, f_b, f_c = f.diff(a), f.diff(b), f.diff(c)
print(f"f(a, b, c) = {f}")
print(f"f'_a(a, b, c) = {f_a} = 0")
print(f"f'_b(a, b, c) = {f_b} = 0")
print(f"f'_c(a, b, c) = {f_c} = 0")
print("Critical points:", sp.solve([f_a, f_b, f_c], a, b, c))
print()
As you can see if you execute this code, there is no critical point, so no absolute maximum nor minimum value for any of these funtions in the Real domain (there are two critical points for the second equation in the Imaginary domain).
Numeric approach:
Using numpy and pandas we can create a matrix with all the possible combinations and then apply each of our functions. The maximum and minimum values are per column, they are not related between the columns. As expected, the max and min values for the a, b and c columns are the range lower and upper bounds.
import pandas as pd
from pandas.core.reshape.util import cartesian_product
import numpy as np
# Number of values per range
N = 21
# Functions
functions = [
lambda row: row['a'] * np.sqrt(row['b'] / row['c']),
lambda row: row['a']**2 * row['b']/1000 + 3*(row['a']+row['b']),
lambda row: 10**6 / (2 * np.pi * row['a'] * row['b']),
]
# Lower and upper bounds
a_lower, a_upper = 0, 5
b_lower, b_upper = 10, 20
c_lower, c_upper = 30, 40
def min_max(col):
return pd.Series(index=['min', 'max'], data=[col.min(), col.max()])
values = [
np.linspace(a_lower, a_upper, N),
np.linspace(b_lower, b_upper, N),
np.linspace(c_lower, c_upper, N),
]
df = pd.DataFrame(cartesian_product(values), index=['a', 'b', 'c']).T
for i, f in enumerate(functions):
df[f'f_{i + 1}'] = df.apply(f, axis=1)
print(df.apply(min_max))
Output:
a b c f_1 f_2 f_3
min 0.0 10.0 30.0 0.000000 30.0 1591.549431
max 5.0 20.0 40.0 4.082483 75.5 inf
N = 101 has exactly the same output (it takes a bit to process as it has to compute the formulas 101^3 > 1M times)
I'm a student of mechanical engineering, and this is the first year I've met with the Python environment, or the distribution of it Anaconda.
I was given a task to find the zeroes of this function:
π·β
sin(πΌ)cos(πΌ)+πβ
cos(πΌ)sin(πΌ)2βπβ
cos(πΌ)βββ
sin(πΌ)=0
With the parameters:
D = 220mm,
h = 1040mm,
l = 1420mm,where
n = 81
is the number of equally distanced points on the function
and the function is limited to :
πΌβ[0,2π] where πΌ is a np.array.
plotted function
The issue is, when I try to insert the function in bisect(fun, a, b), the error says
'numpy.ndarray' object is not callable
Can someone aid a noob programer ? Thanks.
The question is not clear, you should share your code and the title should say scipy, not simpy, if I am correct.
Apart from this, I do not get the same plot of the function, can you check if it is correct?
If you want to use the bisection method you should do something like this:
import numpy as np
from scipy.optimize import bisect
def fun(x, D, h, l):
return D * np.sin(x) * np.cos(x) + l * np.cos(x) * np.sin(x) * 2 - l * np.cos(x) - h * np.sin(x)
D = 220
h = 1040
l = 1420
print(bisect(lambda x: fun(x, D, h, l), 0, 2*np.pi))
Note that the bisection method only finds one zero, and this does not work at all because the two extremes of the function have the same sign. For this particular function, you could run the bisect in the intervals (0, pi) and (pi, 2pi) to find both zeros.
I need to partially derivate my equation and form a matrix out of the derivatives. My equation is:
While this conditions must be met:
For doing this I've used the sympy module and its diff() function. My code so far is:
from sympy import*
import numpy as np
init_printing() #delete if you dont have LaTeX installed
logt_r, logt_a, T, T_a, a_0, a_1, a_2, logS, Taa_0, Taa_1, Taa_2 = symbols('logt_r, logt_a, T, T_a, a_0, a_1, a_2, logS, Taa_0, Taa_1, Taa_2')
A = (logt_r - logt_a - (T - T_a) * (a_0 + a_1 * logS + a_2 * logS**2) )**2
parametri = [logt_a, a_0, Taa_0, a_1, Taa_1, a_2, Taa_2]
M = expand(A)
M = M.subs(T_a*a_0, Taa_0)
M = M.subs(T_a*a_1, Taa_1)
M = M.subs(T_a*a_2, Taa_2)
K = zeros(len(parametri), len(parametri))
O = []
def odv(par):
for j in range(len(par)):
for i in range(len(par)):
P = diff(M, par[i])/2
B = P.coeff(par[j])
K[i,j] = B
return K
odv(parametri)
My result:
My problem
The problem that I'm having is in the partial derivatives of products (T_aa_0, T_aa_1 and T_a*a_2), because by using the diff() function, you cannot derivate a function with a product (obviously), else you get an error:
ValueError:
Can't calculate 1-th derivative wrt T_a*a_0.
To solve this I substitued this products with coefficients, like:
M = M.subs(T_a*a_0, Taa_0)
M = M.subs(T_a*a_1, Taa_1)
M = M.subs(T_a*a_2, Taa_2)
But as you can see in the final result, this works only in some cases. I would like to know if there is a better way of doing this where I wouldn't need to substitude the products and that it would work in all cases.
ADDITIONAL INFORMATION
Let me rephrase my question. Is it possible to symbolically derive an equation with a function by using python or in that matter, to use the sympy module?
So I've managed to solve my problem on my own. The main question was how to symbolically derive a function or equation with another function. As I've gone again slowly over the sympy documentation, I saw a little detail, that I've missed before.
In order to derive a function with a function you need to change the settings of the function, that will be used to derive. For example:
x, y, z = symbols('x, y, z')
A = x*y*z
B = x*y
# This is the detail:
type(B)._diff_wrt = True
diff(A, B)
Or in my case, the code looks like:
koef = [logt_a, a_0, T_a*a_0, a_1, T_a*a_1, a_2, T_a*a_2]
M = expand(A)
K = zeros(len(koef), len(koef))
def odvod_mat(par):
for j in range(len(par)):
for i in range(len(par)):
type(par[i])._diff_wrt = True
P = diff(M, par[i])/2
B = P.coeff(par[j])
K[i,j] = B
#Removal of T_a
K[i,j] = K[i,j].subs(T_a, 0)
return K
odvod_mat(koef)
Thanks again to all that were taking their time to read this. I hope this helps to anyone, who will have the same problem as I did.