How can I make all low values in a SymPy expression zero? For example, my result is:
1.0*a1*cos(q1) - 6.12e-17*(a2*sin(q2) + a3*sin(q2 + q3) + a4*sin(q2 + q3 + q4))*sin(q1) + 1.0*(a2*cos(q2) + a3*cos(q2 + q3) + a4*cos(q2 + q3 + q4))*cos(q1)
and I want to change second term (starting with 6.12e-17) to zero.
A direct way to do this is to replace such numbers with 0. A naive eq.subs(small, 0) will fail because small that you enter is not likely to be exactly the same as the number. But eq.atoms(Float) will give you the set of such numbers:
>>> eq.xreplace(dict([(n,0) for n in eq.atoms(Float) if abs(n) < 1e-12]))
1.0*a1*cos(q1) + (1.0*a2*cos(q2) + 1.0*a3*cos(q2 + q3) + 1.0*a4*cos(q2 + q3 + q4))*cos(q1)
Probably there are much more efficient ways(I am not familiar with that library) but I tried to do with regex. If e- exist in a part of the equation it replaces it to 0(you can remove directly if you want). But to be able to do this, I had to remove to spaces between +- operators inside the parentheses, so I could make a list by splitting from the other +- operators.
import re
result='''1.0*a1*cos(q1) - 6.12e-17*(a2*sin(q2) + a3*sin(q2+q3)
+ a4*sin(q2+q3+q4))sin(q1) + 1.0(a2*cos(q2)
+ a3*cos(q2+q3) + a4*cos(q2+q3+q4))*cos(q1)'''
too_small='e-'
mylist=re.split(r"\s+", result)
for i in range(len(mylist)):
if too_small in mylist[i]:
mylist[i]='0'
new_result=''.join(mylist)
print(new_result)
And this is the output:
1.0*a1*cos(q1)-0+a3*sin(q2+q3)+a4*sin(q2+q3+q4))sin(q1)+1.0(a2*cos(q2)+a3*cos(q2+q3)+a4*cos(q2+q3+q4))*cos(q1)
As I said, there are probably much better ways than this.
What about more details? I guess you want replace part of a symbolic calculation string, Regular expression in Python could be helpful, you can code like this:
In [1]: import re
In [2]: s = '1.0*a1*cos(q1) - 6.12e-17*(a2*sin(q2) + a3*sin(q2 + q3) + ' \
...: 'a4*sin(q2 + q3 + q4))sin(q1) + 1.0(a2*cos(q2) + ' \
...: 'a3*cos(q2 + q3) + a4*cos(q2 + q3 + q4))*cos(q1)'
In [3]: s = re.sub(r'[+-/*/]\s\S*e-[1-9]\d+\S*\s', '', s)
In [4]: s
Out[4]: '1.0*a1*cos(q1) + a3*sin(q2 + q3) + a4*sin(q2 + q3 + q4))sin(q1) + 1.0(a2*cos(q2) + a3*cos(q2 + q3) + a4*cos(q2 + q3 + q4))*cos(q1)'
First argument of re.sub() function decide what you want to reduce, e-[1-9]\d+ represent a number lower than e-10 which you can modify, I hope it helps.
SymPy’s nsimplify function with the rational=True argument converts floats within an expression to rational numbers (within a given tolerance). Something like 6.12e-17 will be converted to 0 if below the threshold. So, in your case:
from sympy import sin, cos, symbols, nsimplify
a1, a2, a3, a4 = symbols("a1, a2, a3, a4")
q1, q2, q3, q4 = symbols("q1, q2, q3, q4")
expr = (
1.0*a1*cos(q1)
- 6.12e-17*(a2*sin(q2) + a3*sin(q2 + q3) + a4*sin(q2 + q3 + q4))*sin(q1)
+ 1.0*(a2*cos(q2) + a3*cos(q2 + q3) + a4*cos(q2 + q3 + q4))*cos(q1)
)
nsimplify(expr,tolerance=1e-10,rational=True)
# a1*cos(q1) + (a2*cos(q2) + a3*cos(q2 + q3) + a4*cos(q2 + q3 + q4))*cos(q1)
Related
I am trying to compute the Yield to Maturity of a bond using the following equation, considering the current price, number of periods, coupons and face value are all known.
I have created a SymPy expression using the following code:
expr = coupon/pow((1+ytm), exp)
exp= exp+0.5
for x in range(1, periods):
expr = expr + coupon/pow((1+ytm), exp)
exp = exp+0.5
exp = exp-0.5
expr = expr+100/pow((1+ytm), exp)
The expression looks like this once computed:
Out[3]: 104.375*(ytm + 1)**(-28.7356164383562) + 4.375*(ytm + 1)**(-28.2356164383562) + ..... + 4.375*(ytm + 1)**(-0.735616438356164) + 4.375*(ytm + 1)**(-0.235616438356164)
Tried to solve with the SymPy solve() method:
from sympy.solvers import solve
but it doesn't seem to work. Any help on how I should approach this problem is appreciated a lot.
Numerical solutions can be obtained easily with nsolve. Demonstrating with an expression derived from what you gave:
>>> print(filldedent(eq))
104.375*(ytm + 1)**(-28.7356164383562) + 4.375*(ytm +
1)**(-28.2356164383562) + 4.375*(ytm + 1)**(-0.735616438356164) +
4.375*(ytm + 1)**(-0.235616438356164)
>>> nsolve(eq-5, 1)
2.49587148297981
I want to solve this non linear equation:
f100 = omega_nf_eq
where:
f100 : numerical costant, defined as a variable for now.
omega_nf_eq: equation.
Firstly I've tried to solve it sybolically and my code was:
import sympy as sym
K_u, K_m = sym.symbols('K_u, K_m', real = True)
J_p1, J_p2, J_g1, J_g2, J_r, J_u, J_m, J_p12, J_g12, J_gb, J_2, J_1, J_p = sym.symbols('J_p1, J_p2, J_g1, J_g2, J_r, J_u, J_m, J_p12, J_g12, J_gb, J_2, J_1, J_p', real = True)
tau_1, tau_2 = sym.symbols('tau_1, tau_2', real = True)
omega_nf, f100 = sym.symbols('omega_nf, f100', real = True)
omega_nf_eq = sym.Eq(omega_nf, sym.sqrt(2)*sym.sqrt(K_m/(J_g2*tau_2**2 + J_p1 + J_p2) + K_u/(J_g2*tau_2**2 + J_p1 + J_p2) + K_u/(tau_2**2*(J_g1 + J_u)) + K_m/J_m - sym.sqrt(J_m**2*K_m**2*tau_2**4*(J_g1 + J_u)**2 + 2*J_m**2*K_m*K_u*tau_2**4*(J_g1 + J_u)**2 - 2*J_m**2*K_m*K_u*tau_2**2*(J_g1 + J_u)*(J_g2*tau_2**2 + J_p1 + J_p2) + J_m**2*K_u**2*tau_2**4*(J_g1 + J_u)**2 + 2*J_m**2*K_u**2*tau_2**2*(J_g1 + J_u)*(J_g2*tau_2**2 + J_p1 + J_p2) + J_m**2*K_u**2*(J_g2*tau_2**2 + J_p1 + J_p2)**2 + 2*J_m*K_m**2*tau_2**4*(J_g1 + J_u)**2*(J_g2*tau_2**2 + J_p1 + J_p2) - 2*J_m*K_m*K_u*tau_2**4*(J_g1 + J_u)**2*(J_g2*tau_2**2 + J_p1 + J_p2) - 2*J_m*K_m*K_u*tau_2**2*(J_g1 + J_u)*(J_g2*tau_2**2 + J_p1 + J_p2)**2 + K_m**2*tau_2**4*(J_g1 + J_u)**2*(J_g2*tau_2**2 + J_p1 + J_p2)**2)/(J_m*tau_2**2*(J_g1 + J_u)*(J_g2*tau_2**2 + J_p1 + J_p2)))/2)
solution = sym.solve(f100 - omega_nf_eq.args[1], J_u, dict = True)
But this gave me just this result: [ ].
I've also tried to substitute all variable value except for J_u, which is the one i want. So now the omega_nf equation is:
omega_nf_eq = sym.Eq(omega_nf, sym.sqrt(2)*sym.sqrt(76019006.3529542 - 84187769.0684942*sym.sqrt(0.813040126459949*J_u**2 - 4.69199504596906e-5*J_u + 1.03236146920168e-9)/J_u + 2704.98520837442/J_u)/2)
So to solve now i've tried:
solution = sym.solve( 942.5 - omega_nf_eq.args[1], J_u,, dict = True, force=True, manual=True, set=True)
It works now, but it requires a couple of minutes.
So I've tried to solve it numerically, to speed up the process, with sympy.nsolve(); this is the code:
omega_nf_eq = sym.Eq(omega_nf, sym.sqrt(2)*sym.sqrt(76019006.3529542 - 84187769.0684942*sym.sqrt(0.813040126459949*J_u**2 - 4.69199504596906e-5*J_u + 1.03236146920168e-9)/J_u + 2704.98520837442/J_u)/2)
eq_solution = sym.nsolve(942.5 - omega_nf_eq, J_u, 0.0071, verify=False)
But i do not obtain the right result, which is: J_u = 0.00717865789803973.
What I'm doing wrong?
There's a smarter way to use sympy?
There is not J_u in your first symbolic equation so that's why you got [] for the solution. When you attempted a numerical solution you used omega_nf_eq (which is an Equality); I think you meant 'nsolve(942.5 - omega_nf_eq.rhs, J_u, .0071)'. But even still, that won't find a solution for you since the equation, as written, is ill-behaved with J_u in the denominator. If you use sympy.solvers.solvers.unrad to give you to radical-free expression whose roots will contain, as a subset, those you are interested in you will find that you need only solve a quadratic in J_u...and that will be fast.
>>> unrad(942.5 - omega_nf_eq.rhs)
(1.0022170762796e+15*J_u**2 - 2936792314038.5*J_u + 2.04890966415405e-7, [])
>>> solve(_[0])
[6.97669240810738e-20, 0.00293029562511584]
I would recommend that you revist your first symbolic expression and unrad that -- or even just try solve that -- after identifying which variable corresponds to J_u.
I have solved using :
sympy.solveset(942.5 - omega_nf_eq.rhs, J_u)
I link the sympy.solveset() docs :
Now is pretty fast.
aa = list(symbols('a0:2'))
q1= series(aa[0]/(1-x) + aa[1]/(1-x**2),x,n=6)
q1.subs(aa[0],1)
print(q1)
Output: x**2*(a0 + a1) + x**4*(a0 + a1) + a1 + a0 + a0*x + a0*x**3 + a0*x**5 + O(x**6)
But what I would like for all the a0's in the series to be substitued by the value of 1:
Output: x**2*(1 + a1) + x**4*(1 + a1) + a1 + 1 + 1*x + 1*x**3 + 1*x**5 + O(x**6)
My understanding is that:
q1.subs(aa[0],1)
would do exactly that. Is there any other way to do the same ? Thanks!
With the exception of mutable matrices, SymPy objects are immutable. Their methods do not modify them; a new object is returned instead. This object needs to be assigned to something (or printed, or returned):
q2 = q1.subs(...)
print(q1.subs(...))
return q1.subs(...)
all make sense; the lonely q1.subs(...) is useless.
This is covered in the "Gotchas and Pitfalls" article under Immutability of Expressions; I recommend reading the rest of that page too.
I am trying to factor a polynomial of booleans to get the minimal form of a logic net. My variables are a1, a2, a3 ... and the negative counterparts na1, na2, na3 ...
If would expect a function
f = a1*a2*b2*nb1 + a1*b1*na2*nb2 + a1*b1*na2 + a2*b2*na1*nb1
to be factored like this (at least) :
f = a1*b1*(b2*nb1 + na2*(nb2 + 1)) + a2*b2*na1*nb1
I run this script:
import sympy
a1,a2,b1,b2,b3,na1,na2,na3,nb1,nb2,nb3 = \
sympy.symbols("a1:3, b1:4, na1:4, nb1:4", bool=True)
f = "a1*na2*b1 + a1*a2*nb1*b2 + a1*na2*b1*nb2 + na1*a2*nb1*b2"
sympy.init_printing(use_unicode=True)
sympy.factor(f)
and this returns me the same function, not factored.
a1*a2*b2*nb1 + a1*b1*na2*nb2 + a1*b1*na2 + a2*b2*na1*nb1
What am I doing wrong ?
Your expected output
f = a1*b1*(b2*nb1 + na2*(nb2 + 1)) + a2*b2*na1*nb1
is not a factorization of f, so factor is not going to produce it. To factor something means to write it as a product, not "a product plus some other stuff".
If you give a polynomial that can actually be factored, say f = a1*na2*b1 + a1*a2*nb1*b2 + a1*na2*b1*nb2, then factor(f) has an effect.
What you are looking for is closer to collecting the terms with the same variable, which is done with collect.
f = a1*na2*b1 + a1*a2*nb1*b2 + a1*na2*b1*nb2 + na1*a2*nb1*b2
collect(f, a1)
outputs
a1*(a2*b2*nb1 + b1*na2*nb2 + b1*na2) + a2*b2*na1*nb1
The method coeff also works in that direction, e.g., f.coeff(a1) returns the contents of the parentheses in the previous formula.
I have an equation like:
R₂⋅V₁ + R₃⋅V₁ - R₃⋅V₂
i₁ = ─────────────────────
R₁⋅R₂ + R₁⋅R₃ + R₂⋅R₃
defined and I'd like to split it into factors that include only single variable - in this case V1 and V2.
So as a result I'd expect
-R₃ (R₂ + R₃)
i₁ = V₂⋅───────────────────── + V₁⋅─────────────────────
R₁⋅R₂ + R₁⋅R₃ + R₂⋅R₃ R₁⋅R₂ + R₁⋅R₃ + R₂⋅R₃
But the best I could get so far is
-R₃⋅V₂ + V₁⋅(R₂ + R₃)
i₁ = ─────────────────────
R₁⋅R₂ + R₁⋅R₃ + R₂⋅R₃
using equation.factor(V1,V2). Is there some other option to factor or another method to separate the variables even further?
If it was possible to exclude something from the factor algorithm (the denominator in this case) it would have been easy. I don't know a way to do this, so here is a manual solution:
In [1]: a
Out[1]:
r₁⋅v₁ + r₂⋅v₂ + r₃⋅v₂
─────────────────────
r₁⋅r₂ + r₁⋅r₃ + r₂⋅r₃
In [2]: b,c = factor(a,v2).as_numer_denom()
In [3]: b.args[0]/c + b.args[1]/c
Out[3]:
r₁⋅v₁ v₂⋅(r₂ + r₃)
───────────────────── + ─────────────────────
r₁⋅r₂ + r₁⋅r₃ + r₂⋅r₃ r₁⋅r₂ + r₁⋅r₃ + r₂⋅r₃
You may also look at the evaluate=False options in Add and Mul, to build those expressions manually. I don't know of a nice general solution.
In[3] can be a list comprehension if you have many terms.
You may also check if it is possible to treat this as multivariate polynomial in v1 and v2. It may give a better solution.
Here I have sympy 0.7.2 installed and the sympy.collect() works for this purpose:
import sympy
i1 = (r2*v1 + r3*v1 - r3*v2)/(r1*r2 + r1*r3 + r2*r3)
sympy.pretty_print(sympy.collect(i1, (v1, v2)))
# -r3*v2 + v1*(r2 + r3)
# ---------------------
# r1*r2 + r1*r3 + r2*r3