Sympy: solving non linear equation - python

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.

Related

Solving an equation with large exponents with python

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

Can we replace the 'Derivative' terms in sympy coming from the differentiation of sympy.Function variables?

When the following code is run Derivative(Ksi(uix, uiy), uix)) and Derivative(Ksi(uix, uiy), uiy)) terms appear:
In [4]: dgN
Out[4]:
Matrix([
[-(x1x - x2x)*(-x1y + x2y)*((x1x - x2x)**2 + (-x1y + x2y)**2)**(-0.5)*Derivative(Ksi(uix, uiy), uix) + (-x1y + x2y)*(-(-x1x + x2x)*Derivative(Ksi(uix, uiy), uix) + 1)*((x1x - x2x)**2 + (-x1y + x2y)**2)**(-0.5)],
[-(-x1x + x2x)*(-x1y + x2y)*((x1x - x2x)**2 + (-x1y + x2y)**2)**(-0.5)*Derivative(Ksi(uix, uiy), uiy) + (x1x - x2x)*(-(-x1y + x2y)*Derivative(Ksi(uix, uiy), uiy) + 1)*((x1x - x2x)**2 + (-x1y + x2y)**2)**(-0.5)]])
I would like to replace this Derivative terms by, let's say, the symbolic expression of the derivative of a function that I know for example, I would like to set Derivative(Ksi(uix,uiy), uix) = 2 * uix.
Is there a neat way to do this substitution and to get a symbolic expression for dgN with Derivative(Ksi(uix,uiy), uix) set to 2 * uix? Here is my code:
import sympy as sp
sp.var("kPenN, Xix, Xiy, uix, uiy, Alpha, x1x, x1y, x2x, x2y, x3x, x3y ", real = True)
Ksi = sp.Function('Ksi')(uix,uiy)
Xi = sp.Matrix([Xix, Xiy])
ui = sp.Matrix([uix, uiy])
xix = Xix + uix
xiy = Xiy + uiy
xi = sp.Matrix([xix, xiy])
x1 = sp.Matrix([x1x, x1y])
x2 = sp.Matrix([x2x, x2y])
N = sp.Matrix([x2 - x1, sp.zeros(1)]).cross(sp.Matrix([sp.zeros(2,1) , sp.ones(1)]))
N = sp.Matrix(2,1, sp.flatten(N[0:2]))
N = N / (N.dot(N))**(0.5)
xp = x1 + (x2 - x1)*Ksi
# make it scalar (in agreement with 9.231)
gN = (xi - xp).dot(N)
dgN = sp.Matrix([gN.diff(uix), gN.diff(uiy)])
The substitution you want can be achieved with
dgN_subbed = dgN.subs(sp.Derivative(Ksi, uix), 2*uix)
Here Ksi is without arguments (uix,uiy) since those were already declared when Ksi was created.
The syntax would be a little more intuitive if you defined Ksi as Ksi = sp.Function('Ksi'), leaving the arguments -- whatever they may be -- to be supplied later. Then sp.Derivative(Ksi(uix, uiy), uix) would be the way to reference the derivative.

Fit several functions with lmfit with shared parameters, no datasets- in Python

I would like to find the parameters E_u, tau_max, and G from these 3 functions.
The functions are the following:
Function 1:
0=0.009000900090009*E_u*(0.000103939092728486*exp(1500000.0/tau_max) + 0.000157703794137242*exp(2999000.0/tau_max) + 0.00017784012*exp(4500000.0/tau_max) + 0.00025534696*exp(6000000.0/tau_max) + 0.00027086158*exp(7500000.0/tau_max) + 0.000280826592271819*exp(9000000.0/tau_max) + 0.0004132622*exp(10501000.0/tau_max))*exp(-10501000.0/tau_max) + 1000000.0*G*(0.000467438377626028*exp(2999000.0/tau_max) + 0.00117770839577636*exp(4500000.0/tau_max) + 0.00197826966391473*exp(6000000.0/tau_max) + 0.00312798328672298*exp(7500000.0/tau_max) + 0.00434787369844519*exp(9000000.0/tau_max) + 0.00561383708066149*exp(10501000.0/tau_max))*exp(-10501000.0/tau_max)/tau_max
Function 2:
1.13624775718=0.09000900090009*E_u*(0.000103939092728486*exp(15000.0/tau_max) + 0.000157703794137242*exp(29990.0/tau_max) + 0.00017784012*exp(45000.0/tau_max) + 0.00025534696*exp(60000.0/tau_max) + 0.00027086158*exp(75000.0/tau_max) + 0.000280826592271819*exp(90000.0/tau_max) + 0.0004132622*exp(105010.0/tau_max))*exp(-105010.0/tau_max) + 10000.0*G*(0.000467438377626028*exp(29990.0/tau_max) + 0.00117770839577636*exp(45000.0/tau_max) + 0.00197826966391473*exp(60000.0/tau_max) + 0.00312798328672298*exp(75000.0/tau_max) + 0.00434787369844519*exp(90000.0/tau_max) + 0.00561383708066149*exp(105010.0/tau_max))*exp(-105010.0/tau_max)/tau_max
Function 3:
1.13106678093=0.9000900090009*E_u*(0.000103939092728486*exp(150.0/tau_max) + 0.000157703794137242*exp(299.9/tau_max) + 0.00017784012*exp(450.0/tau_max) + 0.00025534696*exp(600.0/tau_max) + 0.00027086158*exp(750.0/tau_max) + 0.000280826592271819*exp(900.0/tau_max) + 0.0004132622*exp(1050.1/tau_max))*exp(-1050.1/tau_max) + 100.0*G*(0.000467438377626028*exp(299.9/tau_max) + 0.00117770839577636*exp(450.0/tau_max) + 0.00197826966391473*exp(600.0/tau_max) + 0.00312798328672298*exp(750.0/tau_max) + 0.00434787369844519*exp(900.0/tau_max) + 0.00561383708066149*exp(1050.1/tau_max))*exp(-1050.1/tau_max)/tau_max
You have 3 non-linear equations and 3 unknowns in a set of transcendental equations. There will not be a closed-form solution, but you can get numerical values for the parameters. I know this is in the python section, but you should look into Mathematica for this. There is a good example here: https://mathematica.stackexchange.com/questions/9875/numerically-solving-two-dependent-transcendental-equations

Algorithm to invert strings of algebraic expressions in Python

Is there an easy way to make a function to inverse an algorithm for example like this:
>>> value = inverse("y = 2*x+3")
>>> print(value)
"x = (y-3)/2"
If you can't make actual code for the function, please recommend me tools that would make this task easier. The function would be only used to inverse algorithms with +, -, * and /
You should try SymPy for doing that:
from sympy import solve
from sympy.abc import x, y
e = 2*x+3-y
solve(e,x)
#[y/2 - 3/2]
solve(e,y)
#[2*x + 3]
Based on this, you can build your inverse() like (works for two variables):
def inverse(string, left_string=None):
from sympy import solve, Symbol, sympify
string = '-' + string
e = sympify(string.replace('=','+'))
if left_string:
ans = left_string + ' = ' + str(solve(e, sympify(left_string))[0])
else:
left = sympify(string.split('=')[0].strip().replace('-',''))
symbols = e.free_symbols
symbols.remove( left )
right = list(symbols)[0]
ans = str(right) + ' = ' + str(solve(e, right)[0])
return ans
Examples:
inverse(' x = 4*y/2')
#'y = x/2'
inverse(' y = 100/x + x**2')
#'x = -y/(3*(sqrt(-y**3/27 + 2500) + 50)**(1/3)) - (sqrt(-y**3/27 + 2500) + 50)**(1/3)'
inverse("screeny = (isox+isoy)*29/2.0344827586206895", "isoy")
#'isoy = -isox + 0.0701545778834721*screeny'
This is a little long for a comment, but here's the sort of thing I had in mind:
import sympy
def inverse(s):
terms = [sympy.sympify(term) for term in s.split("=")]
eqn = sympy.Eq(*terms)
var_to_solve_for = min(terms[1].free_symbols)
solns = sympy.solve(eqn, var_to_solve_for)
output_eqs = [sympy.Eq(var_to_solve_for, soln) for soln in solns]
return output_eqs
After which we have
>>> inverse("y = 2*x+3")
[x == y/2 - 3/2]
>>> inverse("x = 100/z + z**2")
[z == -x/(3*(sqrt(-x**3/27 + 2500) + 50)**(1/3)) - (sqrt(-x**3/27 + 2500) + 50)**(1/3), z == -x/(3*(-1/2 - sqrt(3)*I/2)*(sqrt(-x**3/27 + 2500) + 50)**(1/3)) - (-1/2 - sqrt(3)*I/2)*(sqrt(-x**3/27 + 2500) + 50)**(1/3),
z == -x/(3*(-1/2 + sqrt(3)*I/2)*(sqrt(-x**3/27 + 2500) + 50)**(1/3)) - (-1/2 + sqrt(3)*I/2)*(sqrt(-x**3/27 + 2500) + 50)**(1/3)]
etc.

Factor/collect expression in Sympy

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

Categories