Trouble with taylor series in python (sympy) - python

I'm trying to get the Taylor series for this function
Which should be similar to this, considering that d is centered or around rs
However when I try to take the example of #Saullo for my problem,
As you can see the result is eliminating "d" from the series of Taylor, which should not be my goal.
Another additional info about the function in fact is:
I'm doing something wrong ??, is there a way to get my result without deleting "d" ??
Any help is appreciated
The code
Thank you for your response and interest in helping me, here is my code until nowdays #asmeurer
import sympy as sy
#import numpy as np
from sympy import init_printing
init_printing(use_latex=True)
# Define the variable and the function to approximate
z, d, r_s, N_e, r_t, r_s, r_b = sy.symbols('z d r_s N_e r_t r_s r_b')
# Define W_model
def W_model(r_t=r_t, r_b=r_b, r_s=r_s, z=z):
s_model = sy.sqrt(pow(r_t, 2) - pow(r_s*sy.sin(z), 2)) - sy.sqrt(pow(r_b, 2) - pow(r_s*sy.sin(z), 2))
d_model = r_t - r_b
STEC_approx = N_e * s_model
VTEC_approx = N_e * d_model
return STEC_approx/VTEC_approx
f = W_model()
# printing Standard model
f
# Some considerations for modify Standard model
rb = r_s - d/2
rt = r_s + d/2
f = W_model(r_b=rb, r_t=rt, r_s=r_s, z=z)
# printing My model
f
## Finding taylor series aproximmation for W_model
num_of_terms = 2
# creates a generator
taylor_series = f.series(x=d, n=None)
# takes the number of terms desired for your generator
taylor_series = sum([next(taylor_series) for i in range(num_of_terms)])
taylor_series

The issue is that your expression is complicated enough that series doesn't know that the odd order terms are zero (you get complicated expressions for them, but if you call simplify() on them, they go to 0). Consider
In [62]: s = f.series(d, n=None)
In [63]: a1 = next(s)
In [64]: a2 = next(s)
In [65]: simplify(a0)
Out[65]:
rₛ
────────────────
_____________
╱ 2 2
╲╱ rₛ ⋅cos (z)
In [66]: simplify(a1)
Out[66]: 0
If you print a0 and a1 they are both complicated expressions. In fact, you need to get several terms (up to a3) before series gets a term that doesn't cancel to 0:
In [73]: simplify(a3)
Out[73]:
_____________
2 ╱ 2 2 2
d ⋅╲╱ rₛ ⋅cos (z) ⋅sin (z)
───────────────────────────
3 6
8⋅rₛ ⋅cos (z)
If you do f.series(d, n=3), it gives the expansion up to d**2 (n=3 means + O(d**3)). You can simplify the expression quite a bit using
collect(expr.removeO(), d, simplify)
Internally, when you give series an explicit n, it uses the term-by-term generator to get as many terms as it needs to give the proper O(d**n) expansion. If you use the generator yourself (n=None), you need to do this manually.
In general, the iterator is not guaranteed to give you the next order term. If you want guarantees that you have all the terms, you need to provide an explicit n. The O term returned by series is always correct (meaning all the lower order terms are complete).

Related

Convert sympy to numpy

I have two NumPy array (two variables), which contains complex numbers. Since they have been defined in NumPy, so the complex notation is denoted by "j".
for i in range(0, 8):
cg1 = np.array(eigVal1[i])
det_eval = eval(det)
AA = det_eval[0:2,0:2]
bb = det_eval[0:2,2] * (-1)
roots = np.append(roots, solve(AA, bb))
a = np.append(a, roots[i])
b = np.append(b, roots[i+1])
Output:
a = array([-9.03839731e-04+0.00091541j, 3.02435614e-07-0.00043776j,
-9.03839731e-04-0.00091541j, 3.02435614e-07+0.00043776j,
9.03812649e-04+0.00092323j, 4.17553402e-07+0.00043764j,
9.03812649e-04-0.00092323j, 4.17553402e-07-0.00043764j])
b = array([ 3.02435614e-07-0.00043776j, -9.03839731e-04-0.00091541j,
3.02435614e-07+0.00043776j, 9.03812649e-04+0.00092323j,
4.17553402e-07+0.00043764j, 9.03812649e-04-0.00092323j,
4.17553402e-07-0.00043764j, -5.53769989e-05-0.00243369j])
I also have a long equation which some variables have been defined symbolic (y).
u_n = A0*y**(1322.5696672125 + 1317.38942049453*I) + A1*y**(1322.5696672125 - 1317.38942049453*I) + A2*y**(-1322.5696672125 + 1317.38942049453*I) + A3*y**(-1322.5696672125 - 1317.38942049453*I) + ..
My problem is when I want to substitute the two variables (a and b) into the equation, all complex numbers change to "I" and it makes the equation more complex, because I am not able to simplify the equation further.
Is there any solution to convert "I" to "j" in sympy.
for i in range(0, 8):
u_n = u_n.subs(A[i], (a[i] * C[i]))
The result is:
u_n = C0*y**(1322.5696672125 + 1317.38942049453*I)*(-0.000903839731101097 + 0.000915407724097998*I) + C1*y**(1322.5696672125 - 1317.38942049453*I)*(3.02435613673241e-7 - 0.000437760318205723*I) +..
As you see I can not simplify it further, even if I use simplify(u_n). However, in numpy for example,(2+3j)(5+6j) will be reduced to (-8+27j), but when a symbolic notation comes to my equation it won't be simplified further. y**(2+3j)(5+6j) -->> y**(2+3I)(5+6*I).
I would like to have y**(-8+27j) which y is symbolic.
I would appreciate it if someone help me with that.
From you last paragraph:
The python expression:
In [38]: (2+3j)*(5+6j)
Out[38]: (-8+27j)
sympy: (y is a sympy symbol):
In [39]: y**(2+3j)*(5+6j)
Out[39]:
With corrective () to group the multiply before the power:
In [40]: y**((2+3j)*(5+6j))
Out[40]:
Even in plain python the operator order matters:
In [44]: 1**(2+3j)*(5+6j)
Out[44]: (5+6j)
In [45]: 1**((2+3j)*(5+6j))
Out[45]: (1+0j)

Sympy : simplification with expression substitution

I have several expressions involving the norm or norm squared of a vector u. I'd like to simplify these expressions by substituting a known value for the norm of u. However, it seems that obvious expressions involving even simple multiples of the norm are not simplified.
As an example, this code does what I would expect :
import sympy as sp
u1,u2,u3 = sp.symbols('u_1, u_2, u_3',real=True,positive=True)
utu = u1**2 + u2**2 + u3**2
print("Ex. 1")
print(utu.subs(utu,1))
This produces the expected output
Ex. 1
1
However, 2*utu does not simplify in the way I would expect :
print("Ex 2")
print((2*utu).subs(utu,1))
Ex 2
2*u_1**2 + 2*u_2**2 + 2*u_3**2
I can explicitly force the substitution with this :
print("Ex 3")
print((2*utu).subs(2*utu,2))
which produces the expected output :
Ex 3
2
Ideally, I'd like to substitute under a norm function, but the run into the same issue.
u = sp.Matrix(3, 1, [u1,u2,u3])
print("Ex 4")
print(u.norm().subs(utu,1))
print("Ex 5")
print((2*u).norm().subs(utu,1))
print("Ex 6")
print((2*u).norm().subs(4*utu,4))
which produces
Ex 4
1
Ex 5
sqrt(4*u_1**2 + 4*u_2**2 + 4*u_3**2)
Ex 6
2
Are there tricks I am missing that will catch these obvious (to me at least - maybe not to Sympy?) simplifications? I've tried factor and expand, without much luck.
Let's analyze this expression:
expr = 2*utu
# out: 2*u_1**2 + 2*u_2**2 + 2*u_3**2
The multiplication has been evaluated. This is SymPy's default behavior: it evaluates things. We can work with the expression manipulation functions to achieve our goal.
For example:
expr = collect_const(expr)
# out: 2*(u_1**2 + u_2**2 + u_3**2)
expr.subs(utu, 1)
# out: 2
Another example:
expr = (2 * u).norm()
# out: sqrt(4*u_1**2 + 4*u_2**2 + 4*u_3**2)
expr = expr.simplify() # Note that expr.factor() produces the same result with this expression
# out: 2*sqrt(u_1**2 + u_2**2 + u_3**2)
expr.subs(utu, 1)
# out: 2
If you play (and modify) with these examples, you will realize that the same result can be achieved with different functions (factor, simplify, collect, collect_const, ...), but even one little change in the expression might prevent one function from "doing its work", while others might be able to. Expression manipulation is kind of an art that one should practice (a lot).
For completeness, I'm going to show you UnevaluatedExpr, which allows a particular expression to remain unevaluated during expression manipulation, though it might not always be the best choice:
n = UnevaluatedExpr(utu)
# out: u_1**2 + u_2**2 + u_3**2
expr = 4 * n
# out: 4*(u_1**2 + u_2**2 + u_3**2)
Note that SymPy didn't proceed with the full evaluation. Now:
expr.subs(utu, 1)
# out: 4*1
Why is there a 4*1 instead of 4? The 1 refers to the UnevaluateExpr object that we created earlier: to evaluate it we can use the doit() method:
expr.subs(utu, 1).doit()
# 4
Keep in mind that while using UnevaluateExpr, the expression becomes non-commutative (I think it's a bug with SymPy), which will prevent other functions to produce the expected results.
Substituting compound expressions is problematic. For the most part you should only expect subs to work if the expression to be replaced is known to always appear literally as part of the expression tree that you are substituting into. When possible then it is better to rearrange for a single symbol like:
In [10]: utu
Out[10]:
2 2 2
u₁ + u₂ + u₃
In [11]: (2*utu).subs(u1**2, 1 - u2**2 - u3**2)
Out[11]: 2
Even here we are substituting for a power of a symbol (u1**2) which is potentially fragile if we can't be sure that exactly that power will always appear in the expression. More generally there are functions that can simplify expressions based on knowing some polynomial relation e.g. ratsimpmodprime:
In [16]: e = (1 - u1**2) / (u1**2 + u2**2 + u3**2)
In [17]: e
Out[17]:
2
1 - u₁
───────────────
2 2 2
u₁ + u₂ + u₃
In [18]: ratsimpmodprime(e, [u1**2 + u2**2 + u3**2 - 1])
Out[18]:
2 2
u₂ + u₃
Other possibilities could be using resultants or Groebner bases to do similar things. Note that u.norm() has a square root which is symbolically awkward so it is better to work with the square of the norm (same as when working on pen and paper):
In [20]: ratsimpmodprime((2*u).norm()**2, [u1**2 + u2**2 + u3**2 - 1])
Out[20]: 4
Also if you just want a more powerful version of subs then you can use replace but with patterns:
In [21]: a = Wild('a')
In [22]: p = a*u1**2 + a*u2**2 + a*u3**2
In [23]: (2*utu).replace(p, a)
Out[23]: 2
In [24]: (2*u).norm().replace(p, a)
Out[24]: 2
Both solid answers already. If you have an arbitrary expression that you expect to be a factor in another, factor_terms is what I try first to make that factor appear. It will collect common factors without doing factoring. But if this doesn't work and you know you have a factor, div is a nice way to check and see the expression with the factor removed:
>>> expr = 2*(x + y)
>>> factor_terms(expr)
2*(x + y)
>>> e2 = expand(expr*(x -y)) # 2*x**2 - y**2
>>> factor_terms(e2)
2*(x**2 - y**2)
>>> div(_,-x-y)
(-2*x + 2*y, 0)
>>> _[0]*z # if you wanted to replace factor -x-y with z
z*(-2*x + 2*y)

issue with converting rate equation to python code

I am trying to convert these rate equations to python code, I have made I lot of research but can't seem to get any clear path to follow to achieve this, please any help will be appreciated
This is a newly updated code....i wrote using the quide from Tom10.....please what do you think?
import numpy as np
# import numpy as sum # not necessary, just for convenience, and replaces the builtin
# set N_core value
N_CORE = 0
# set the initial conditions appropriately (you need to set these correctly)
N = np.ones(8)
r = np.ones((8, 8))
dN = np.zeros(8) # the value here is not important for your equations
# set constant for equation 1
R_P1abs37 = 20
F_P1 = 20
R_P1abs47 = 40
W_3317 = 1.0
# set constant for equation 2
W_6142 = 90
W_5362 = 80
# Set you constants appropriately for equation 3
R_P2abs35 = 30
F_P2 = 40
R_L2se34 = 50
F_L2 = 90
# equation 4 constants
W_2214 = 20
#equation 5 constants
R_P1abs13 = 30
R_L2se32 = 20
F_L1 = 10
# equation 1 formular
dN[7] =sum(r[7,:]*N[7]) + (R_P1abs37*F_P1) + (R_P1abs47*F_P1) + (W_3317*N[3]**2)
# equation 2 formular
dN[6] = (r[7,6]*N[7]) - sum(r[6,:]*N[6]) - (W_6142*N[6]*N[1]) + (W_5362*N[5]*N[3])
#equation 3 formular
dN[5] = sum(r[:,5]*N) - sum(r[5,:]*N[5]) + R_P2abs35*F_P2 - R_L2se34*F_L2 - W_5362*N[5]*N[3]
# equation 4 formular
dN[4] = sum(r[:,4]*N) - sum(r[4,:]*N[4]) - (R_P1abs47*F_P1) + (R_L2se34*F_L2) + (W_2214*N[2]**2)+ (W_6142*N[6]*N[1])
#equation 5 formular
dN[3] = sum(r[:,3]*N) - sum(r[3,:]*N[3]) + (R_P1abs13*F_P1) - (R_P1abs37*F_P1) - (R_P2abs35*F_P2)
-(R_L2se32*F_L1) - ((2*W_3317)*N[3]**2) - (W_5362*N[5]*N[3])
#equation 6 formular
dN[2] = sum(r[:,2]*N) - (r[2,1]*N[2]) + (R_L2se32*F_L1) - ((2*W_2214)*N[2]**2) + (W_6142*N[6]*N[1])+(W_5362*N[5]*N[3])
#equation 7 formular
dN[1] = sum(r[:,1] * N) - (R_P1abs13*F_P1) + (W_2214*N[2]**2) + (W_3317+N[3]**2) - (W_6142+N[6]*N[1])
#equation for N CORE
N_CORE = sum(dN)
print(N_CORE)
Here is list of relevant issues based on your question and comments:
Usually if the summation is over i, then everything without an i subscript is constant for that sum. (Mathematically these constant terms can just be brought out of the sum; so the first equation is a bit odd where the N_7 could be moved out of the sum but I think they're keeping it in to show the symmetry with the other equations which all have an r*N term).
The capitol sigma symbol (Σ) means you need to do a sum, which you can do in a loop, but both Python list and numpy have a sum function. Numpy has the additional advantage that multiplication is interpreted as multiplication of the individual elements, making the expression easier. So for a[0]*[b0] + a[1]*b[1] + a[2]*b[2] and numpy arrays is simply sum(a*b) and for Python lists it's sum([a[i]*b[i] for in range(len(a))]
Therefore using numpy, the setup and your third equation would look like:
import numpy as np
import numpy.sum as sum # not necessary, just for convenience, and replaces the builtin
# set the initial conditions appropriately (you need to set these correctly)
N = np.ones(7, dtype=np.float)
# r seems to be a coupling matrix, and should be set according to your system
r = np.ones((7, 7), dtype = np.float)
# the values for dN are not important for your equations because dN only appears on the left side of the equations, so we just make a place to store the results
dN = np.zeros(7, dtype=np.float)
# Set you constants appropriate.y
R_P2abs35 = 1.0
F_P2 = 1.0
R_L2se34 = 1.0
F_L2 = 1.0
W_5362 = 1.0
dN[5] = sum(r[:,5]*N) - sum(r[5,:]*N[5]) + R_P2abs35*F_P2 - R_L2se34*F_L2 - W_5362*N[5]*N[3]
Note that although the expressions in the sums look similar, the first is essentially a dot product between two vectors and the second is a scalar times a vector so N[5] could be taken out of the sum (but I left it there to match the equation).
Final note: I see you're new to S.O. so I thought it would be helpful if I answered this question for you. In the future, please show some attempt at the code -- it really helps a lot.

SymPy does not recognize equal values

Simple calculations in SymPy quickly create unwieldy results like the three should_be values below.
Comparisons to the correct values give False (although math.isclose gives True).
from sympy import sqrt
phi = (1 + sqrt(5)) / 2
should_be_phi = -(1/2 + sqrt(5)/2)**2 + (1/2 + sqrt(5)/2)**3
should_be_half = -sqrt(5)/8 + 1/8 + (1/2 + sqrt(5)/2)**2/4
should_be_one = -sqrt(5)/4 + 1/4 + (1/2 + sqrt(5)/2)**2/2
print(should_be_phi == phi, should_be_half == 1/2, should_be_one == 1)
These are the same formulas formatted by Wolfram Alpha:
phi:
half:
one:
should_be_phi was created as phi**3 - phi**2 btw.
Currently I always copy these monstrosities to Wolfram Alpha to get decent formulas and to remove duplicates.
Do you also get False for each comparison? I use Python 3.6.8 and SymPy 1.4.
Is there a way do do symbolic calculations in Python that actually works?
SymPy seems to be unable to do the things it is supposedly made for.
I presume that what you want is for those expressions to be simplified so just use the simplify function:
In [6]: from sympy import *
In [7]: phi = (1 + sqrt(5)) / 2
In [8]: should_be_phi = -(S(1)/2 + sqrt(5)/2)**2 + (S(1)/2 + sqrt(5)/2)**3
In [9]: should_be_phi
Out[9]:
2 3
⎛1 √5⎞ ⎛1 √5⎞
- ⎜─ + ──⎟ + ⎜─ + ──⎟
⎝2 2 ⎠ ⎝2 2 ⎠
In [10]: simplify(should_be_phi)
Out[10]:
1 √5
─ + ──
2 2
Note that you should use S(1)/2 rather than 1/2 which gives a float.
If you want to compare expressions then the obvious way would be to use == but that is for "structural equality" in SymPy. What that means is that expr1 == expr2 will give True only when the expressions are in the exact same form. If you want to test for mathematical equality then you should use Eq(lhs, rhs) or simplify(lhs-rhs):
In [11]: should_be_phi == phi # Expressions are not in the same form
Out[11]: False
In [12]: Eq(should_be_phi, phi)
Out[12]: True
In [13]: simplify(should_be_phi - phi)
Out[13]: 0
Is there a way do do symbolic calculations in Python that actually works?
SymPy seems to be unable to do the things it is supposedly made for.
Unlike Wolfram Alpha, SymPy is not designed to be usable or understandable to someone who has not read any of the documentation. Your questions above would be answered if you had read the first few pages of the SymPy tutorial:
https://docs.sympy.org/latest/tutorial/index.html#tutorial

Derivative of summations

I am using sympy from time to time, but am not very good at it. At the moment I am stuck with defining a list of indexed variables, i.e. n1 to nmax and performing a summation on it. Then I want to be able to take the derivative:
So far I tried the following:
numSpecies = 10
n = IndexedBase('n')
i = symbols("i",cls=Idx)
nges = summation(n[i],[i,1,numSpecies])
However, if i try to take the derivative with respect to one variable, this fails:
diff(nges,n[5])
I also tried to avoid working with IndexedBase.
numSpecies = 10
n = symbols('n0:%d'%numSpecies)
k = symbols('k',integer=True)
ntot = summation(n[k],[k,0,numSpecies])
However, here already the summation fails because mixing python tuples and the sympy summation.
How I can perform indexedbase derivatives or some kind of workaround?
With SymPy's development version, your example works.
To install SymPy's development version, just pull it down with git:
git clone git://github.com/sympy/sympy.git
cd sympy
Then run python from that path or set the PYTHONPATH to include that directory before Python's default installation.
Your example on the development version:
In [3]: numSpecies = 10
In [4]: n = IndexedBase('n')
In [5]: i = symbols("i",cls=Idx)
In [6]: nges = summation(n[i],[i,1,numSpecies])
In [7]: nges
Out[7]: n[10] + n[1] + n[2] + n[3] + n[4] + n[5] + n[6] + n[7] + n[8] + n[9]
In [8]: diff(nges,n[5])
Out[8]: 1
You could also use the contracted form of summation:
In [9]: nges_uneval = Sum(n[i], [i,1,numSpecies])
In [10]: nges_uneval
Out[10]:
10
___
╲
╲ n[i]
╱
╱
‾‾‾
i = 1
In [11]: diff(nges_uneval, n[5])
Out[11]:
10
___
╲
╲ δ
╱ 5,i
╱
‾‾‾
i = 1
In [12]: diff(nges_uneval, n[5]).doit()
Out[12]: 1
Also notice that in the next SymPy version you will be able to derive symbols with symbolic indices:
In [13]: j = symbols("j")
In [13]: diff(n[i], n[j])
Out[13]:
δ
j,i
Where you get the Kronecker delta.
If you don't feel like installing the SymPy development version, just wait for the next full version (probably coming out this autumn), it will support derivatives of IndexedBase.
I don't know why the IndexedBase approach does not work (I would be interested to know also). You can, however, do the following:
import sympy as sp
numSpecies = 10
n = sp.symbols('n0:%d'%numSpecies) # note that n equals the tuple (n0, n1, ..., n9)
ntot = sum(n) # sum elements of n using the standard
# Python function for summing tuple elements
#ntot = sp.Add(*n) # same result using Sympy function
sp.diff(ntot, n[5])
I'm not clear about what you want to do. However, perhaps this will help. Edited in response to two comments received.
from sympy import *
nspecies = 10
[var('n%s'%_) for _ in range(nspecies)]
expr = sympify('+'.join(['n%s'%_ for _ in range(nspecies)]))
expr
print ( diff(expr,n1) )
expr = sympify('n0**n1+n1**n2')
expr
print ( diff(expr,n1) )
Only the first expression responds to the original question. This is the output.
1
n0**n1*log(n0) + n1**n2*n2/n1

Categories