简体   繁体   English

使用 mpmath 和 sympy 模块时因指数函数而出错

[英]Error because of exponential function when using mpmath and sympy modules

I have the following code where I need to solve an expression to find the roots.我有以下代码,我需要解决一个表达式来找到根。 The expression needs to be solved for omega.需要为 omega 求解表达式。

import numpy as np
from sympy import Symbol,lambdify
import scipy
from mpmath import findroot, exp
eta = 1.5 
tau = 5 /1000
omega = Symbol("omega")
Tf = exp(1j * omega * tau)
symFun = 1 + Tf * (eta - 1) 
denom = lambdify((omega), symFun, "scipy")
Tf_high = 1j * 2 * np.pi * 1000 * tau
sol = findroot(denom, [0+1j,Tf_high])

The program gives an error and I am not able to correct.该程序出现错误,我无法更正。 The error is : TypeError: cannot create mpf from 0.005 I omega错误是:TypeError: cannot create mpf from 0.005 I omega

Edit 1 - I have tried to implement different approach based on comments.编辑 1 - 我试图根据评论实施不同的方法。 First approach was to use the sympy.solveset module.第一种方法是使用 sympy.solveset 模块。 Second approach was to use fsolve from scipy.optimise.第二种方法是使用 scipy.optimise 中的 fsolve。 Both are not giving proper output.两者都没有给出适当的输出。

For clarity, I am copying the relevant code to each approach along with the output I am getting.为清楚起见,我将相关代码与我得到的输出一起复制到每种方法中。

Approach 1 - Sympy方法 1 - Sympy


import numpy as np
from sympy import Symbol,exp
from sympy.solvers.solveset import solveset,solveset_real,solveset_complex
import matplotlib.pyplot as plt 

def denominator(eta,Tf):
    
    return 1 + Tf * (eta - 1)

if __name__ == "__main__":
    eta = 1.5 
    tau = 5 /1000
    omega = Symbol("omega")
    n = 1 
    Tf = exp(1j * omega * tau)
    denom = 1 + Tf * (eta - 1)
    symFun = denominator(eta,Tf)
    sol = solveset_real(denom,omega)
    sol1 = solveset_complex(denom,omega)
    print('In real domain', sol)
    print('In imaginary domain',sol1)

Output: 
In real domain EmptySet
In imaginary domain ImageSet(Lambda(_n, -200.0*I*(I*(2*_n*pi + pi) + 0.693147180559945)), Integers)

Approach 2 Scipy方法 2 Scipy


import numpy as np
from scipy.optimize import fsolve, root

def denominator(eta,tau,n, omega):
    
    Tf = n * np.exo(1j * omega * tau)
    return 1 + Tf * (eta - 1)

if __name__ == "__main__":
    eta = 1.5 
    tau = 5 /1000
    n = 1 
    func = lambda omega :  1 + (eta - 1) * (n * np.exp( 1j * omega * tau))
    sol = fsolve(func,10)
    print(sol)

Output: 
Cannot cast array data from dtype('complex128') to dtype('float64') according to the rule 'safe'

How do I correct the program?如何更正程序? Please suggest me the approach that will give proper results.请建议我将给出正确结果的方法。

SymPy is a computer algebra system and solves the equation like a human would. SymPy 是一个计算机代数系统,可以像人类一样求解方程。 SciPy uses numeric optimization. SciPy 使用数值优化。 If you want ALL the solutions, I suggest going with SymPy.如果您想要所有解决方案,我建议您使用 SymPy。 If you want one solution, I suggest going with SciPy.如果您想要一种解决方案,我建议使用 SciPy。

Approach 1 - SymPy方法 1 - SymPy

The solutions SymPy gives will be more "interactive" for you as the developer. SymPy 提供的解决方案对于作为开发人员的您来说将更具“交互性”。 But it will be perfectly correct almost all the time.但它几乎一直都是完全正确的。

from sympy import *

eta = S(3)/2
tau = S(5) / 1000
omega = Symbol("omega")
n = 1
Tf = exp(I * omega * tau)
denom = 1 + Tf * (eta - 1)
sol = solveset(denom, omega)
print(sol)

Giving给予

ImageSet(Lambda(_n, -200*I*(I*(2*_n*pi + pi) + log(2))), Integers)

This is the true mathematical solution.这是真正的数学解决方案。

Notice how I put S around an integer before dividing it.请注意在除以整数之前我是如何将S放在整数周围的。 When dividing integers in Python, it loses accuracy because it uses floating point numbers.在 Python 中对整数进行除法时,它会失去准确性,因为它使用浮点数。 Converting it to SymPy objects keep all the accuracy.将其转换为 SymPy 对象可保持所有准确性。

Since we know we have an ImageSet over integers, we can start listing a few solutions:由于我们知道我们有一个基于整数的ImageSet ,我们可以开始列出一些解决方案:

for n in range(-3, 3):
    print(complex(sol.lamda(n)))

Which gives这使

(-3141.5926535897934-138.62943611198907j)
(-1884.9555921538758-138.62943611198907j)
(-628.3185307179587-138.62943611198907j)
(628.3185307179587-138.62943611198907j)
(1884.9555921538758-138.62943611198907j)
(3141.5926535897934-138.62943611198907j)

With some experience, you could automate it so that the whole program only returns 1 solution no matter on the type of output returned by solveset .有了一些经验,您可以将其自动化,以便无论solveset返回的输出类型如何,整个程序都只返回 1 个解决方案。

Approach 2 - SciPy方法 2 - SciPy

The solutions SciPy gives will be more automated. SciPy 提供的解决方案将更加自动化。 You will never have a perfect answer and different choices of the initial conditions may not converge all the time.你永远不会有一个完美的答案,初始条件的不同选择可能不会一直收敛。

import numpy as np
from scipy.optimize import root

eta = 1.5
tau = 5 / 1000
n = 1
def f(omega: Tuple):
    omega_real, omega_imag = omega
    omega: complex = omega_real + omega_imag*1j
    result: complex = 1 + (eta - 1) * (n * np.exp(1j * omega * tau))
    return result.real, result.imag
sol = root(f, [100, 100])
print(sol)
print(sol.x[0]+sol.x[1]*1j)

Which gives这使

    fjac: array([[ 0.00932264,  0.99995654],
       [-0.99995654,  0.00932264]])
     fun: array([-2.13074003e-12, -8.86389816e-12])
 message: 'The solution converged.'
    nfev: 30
     qtf: array([ 2.96274855e-09, -6.82780898e-10])
       r: array([-0.00520194, -0.00085702, -0.00479143])
  status: 1
 success: True
       x: array([ 628.31853072, -138.62943611])

(628.3185307197314-138.62943611241522j)

Looks like that's one of the solutions SymPy found.看起来这是 SymPy 找到的解决方案之一。 So we must be doing something right.所以我们必须做正确的事情。 Note that there are many initial values that don't converge, for example, sol = root(f, [1, 1]) .请注意,有许多不收敛的初始值,例如, sol = root(f, [1, 1])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM