简体   繁体   English

计算求解 100 个变量的非线性方程组

[英]Solving System of Nonlinear Equations in 100 variables Computationally

I have been trying to solve a system of 10,000 non-linear equations with 100 variables using Sympy/Numpy in Python.我一直在尝试在 Python 中使用 Sympy/Numpy 求解一个包含 10,000 个具有 100 个变量的非线性方程组。

Attempt so far:到目前为止的尝试:

I tried both nsolve and solve from Sympy, solve in numpy.linalg, all of which were still running after a 5-6 hour wait (and I ended up force-stopping them as I ran out of RAM).我尝试了 Sympy 的 nsolve 和 solve,在 numpy.linalg 中解决,所有这些在等待 5-6 小时后仍在运行(当我用完 RAM 时,我最终强行停止了它们)。

Generating the set of equations with Sympy itself took ~1 hour.使用 Sympy 本身生成方程组大约需要 1 小时。 I switched to SageMath (Windows native), which seemed to do equation generation itself way better (~3min), still, helpless with solving them.我切换到 SageMath(Windows 原生),它本身似乎可以更好地生成方程式(~3 分钟),但仍然无助于解决它们。

Is there a way to optimize the running using any specific languages or tricks in SageMath/Python itself or should I look for a more powerful system to run the code?有没有一种方法可以使用 SageMath/Python 本身中的任何特定语言或技巧来优化运行,或者我应该寻找更强大的系统来运行代码?

My system is i7-11300H/16GB RAM.我的系统是 i7-11300H/16GB 内存。

Edit: linalg.solve was a mistake as I initially thought it is a linear system, later realised that it is not.编辑:linalg.solve 是一个错误,因为我最初认为它是一个线性系统,后来意识到它不是。

Edit:编辑:

from sympy import *
x,t=symbols('x,t')
a11, a12, a13, a14, a15, a16, a17, a18, a19, a21, a22, a23, a24 = symbols('a11, a12, a13, a14, a15, a16, a17, a18, a19, a21, a22, a23, a24')
Coeffs = [a11, a12, a13, a14, a15, a16, a17, a18, a19, a21, a22, a23, a24]
#E = expression in x,t,aij, 0<i<11,0<j<11 (nonlinear in aij)
## Sample
E = 1/2*(9*(8*t + 1)*a11 + 3*(t**2 + 2*t + 1)*a21 + 4*(t**3 + 3*t**2 + 3*t + 1)*a12 + 5*(t**4 + 4*t**3)*a13 + 6*(t**5 + 5*t**4)*a14 + 7*(t**6 + 6*t**5 + 1)*a15 + 8*(t**7 + 7*t)*a16 + 2*a17*(t + 1) + a18)*x**2 + 1/48*(13860*(252*(t**10 + 10*t)*a19 + 1260*(t**2 + 2*t)*a21 + 840*(t**3 + 3*t**2 + 3*t)*a22 + 630*(t**4)*a23 + 504*(t**5 + 10*t**2 + 5*t))*a24)
Eqs = [E.subs({x:1/k,t:1/m}) for k in range(1,100) for m in range(1,100)]
sol = solve(Eqs, Coeffs)

Also tried nsolve with array of 0s as initial values.还尝试使用 0 数组作为初始值的 nsolve。

After you have updated your question I think I understand what you are doing but I think that you are not approaching the problem in the right way.在您更新问题后,我想我明白您在做什么,但我认为您没有以正确的方式解决问题。

Firstly the way you define the system of equations introduces floating point coefficients and polynomial equations with floats can be extremely ill-conditioned so make sure to use eg S(1)/2 or Rational(1, 2) rather than 1/2 like this:首先,您定义方程组的方式引入了浮点系数,并且带有浮点数的多项式方程可能非常病态,因此请确保使用例如S(1)/2Rational(1, 2)而不是像这样的1/2 :

from sympy import *
x,t=symbols('x,t')
Coeffs = symbols('a11, a12, a13, a14, a15, a16, a17, a18, a19, a21, a22, a23, a24')
a11, a12, a13, a14, a15, a16, a17, a18, a19, a21, a22, a23, a24 = Coeffs

#E = expression in x,t,aij, 0<i<11,0<j<11 (nonlinear in aij)
## Sample
E = (
      S(1)/2*(9*(8*t + 1)*a11
    + 3*(t**2 + 2*t + 1)*a21
    + 4*(t**3 + 3*t**2 + 3*t + 1)*a12
    + 5*(t** 4 + 4*t**3)*a13
    + 6*(t**5 + 5*t**4)*a14
    + 7*(t**6 + 6*t**5 + 1)*a15
    + 8*(t**7 + 7*t)*a16
    + 2*a17*(t + 1) + a18)*x**2
    + S(1)/48*(13860*(
          252*(t**10 + 10*t)*a19
        + 1260*(t**2 + 2*t)*a21
        + 840*(t**3 + 3*t**2 + 3*t)*a22
        + 630*(t**4)*a23
        + 504*(t**5 + 10*t**2 + 5*t) )*a24
        )
    )

So you have E which looks like this:所以你有E看起来像这样:

In [2]: E
Out[2]: 
    ⎛          ⎛     10         ⎞             ⎛      2         ⎞             ⎛     3         2     
a₂₄⋅⎝13860⋅a₁₉⋅⎝252⋅t   + 2520⋅t⎠ + 13860⋅a₂₁⋅⎝1260⋅t  + 2520⋅t⎠ + 13860⋅a₂₂⋅⎝840⋅t  + 2520⋅t  + 25
───────────────────────────────────────────────────────────────────────────────────────────────────
                                                                                48                 

    ⎞                4            5             2             ⎞      ⎛                     ⎛   3   
20⋅t⎠ + 8731800⋅a₂₃⋅t  + 6985440⋅t  + 69854400⋅t  + 34927200⋅t⎠    2 ⎜a₁₁⋅(72⋅t + 9)   a₁₂⋅⎝4⋅t  + 
─────────────────────────────────────────────────────────────── + x ⋅⎜────────────── + ────────────
                                                                     ⎝      2                      

    2           ⎞       ⎛   4       3⎞       ⎛   5       4⎞       ⎛   6       5    ⎞       ⎛   7   
12⋅t  + 12⋅t + 4⎠   a₁₃⋅⎝5⋅t  + 20⋅t ⎠   a₁₄⋅⎝6⋅t  + 30⋅t ⎠   a₁₅⋅⎝7⋅t  + 42⋅t  + 7⎠   a₁₆⋅⎝8⋅t  + 
───────────────── + ────────────────── + ────────────────── + ────────────────────── + ────────────
  2                         2                    2                      2                      2   

    ⎞                           ⎛   2          ⎞⎞
56⋅t⎠                 a₁₈   a₂₁⋅⎝3⋅t  + 6⋅t + 3⎠⎟
───── + a₁₇⋅(t + 1) + ─── + ────────────────────⎟
                       2             2          ⎠

The first term of E with a24 makes this nonlinear but only mildly so since it is quadratic and polynomial rather than say transcendental or something (you previously only described your equations as nonlinear which can mean anything). Ea24的第一项使这种非线性但只是温和的,因为它是二次和多项式而不是说超越或其他东西(你以前只将你的方程描述为非线性,这可以意味着任何东西)。

You are substituting 100 different values for each of x and t and then trying to solve the 10000 equations to make E zero for each of those values.您正在为每个xt替换 100 个不同的值,然后尝试求解 10000 个方程以使每个值的E为零。 It is almost guaranteed that the only possible solutions for these equations are those that make all of the coefficents of the x,t polynomial zero.几乎可以肯定,这些方程的唯一可能解是那些使x,t多项式的所有系数都为零的解。 I guess what you are actually trying to do is find the values of the ai symbols that make E zero for all x,t but we don't need 10000 equations to do that.我猜你实际上想做的是找到使所有x,tE为零的ai符号的值,但我们不需要 10000 个方程来做到这一点。 We can just extract the coefficients and solve those as equations:我们可以只提取系数并将它们求解为方程式:

In [3]: eqs = Poly(E, [x, t]).coeffs()

In [4]: eqs
Out[4]: 
⎡       7⋅a₁₅                  5⋅a₁₃                                   3⋅a₂₁                       
⎢4⋅a₁₆, ─────, 3⋅a₁₄ + 21⋅a₁₅, ───── + 15⋅a₁₄, 2⋅a₁₂ + 10⋅a₁₃, 6⋅a₁₂ + ─────, 36⋅a₁₁ + 6⋅a₁₂ + 28⋅a
⎣         2                      2                                       2                         

                  9⋅a₁₁           7⋅a₁₅         a₁₈   3⋅a₂₁                             363825⋅a₂₃⋅
₁₆ + a₁₇ + 3⋅a₂₁, ───── + 2⋅a₁₂ + ───── + a₁₇ + ─── + ─────, 72765⋅a₁₉⋅a₂₄, 145530⋅a₂₄, ───────────
                    2               2            2      2                                     2    

a₂₄                                                                                                
───, 242550⋅a₂₂⋅a₂₄, 363825⋅a₂₁⋅a₂₄ + 727650⋅a₂₂⋅a₂₄ + 1455300⋅a₂₄, 727650⋅a₁₉⋅a₂₄ + 727650⋅a₂₁⋅a₂₄
                                                                                                   

                              ⎤
 + 727650⋅a₂₂⋅a₂₄ + 727650⋅a₂₄⎥
                              ⎦

In [5]: %time [sol] = solve(eqs, Coeffs, dict=True)
CPU times: user 236 ms, sys: 8 ms, total: 244 ms
Wall time: 244 ms

In [6]: sol
Out[6]: 
⎧     a₁₈                                               -4⋅a₁₈                 ⎫
⎨a₁₁: ───, a₁₂: 0, a₁₃: 0, a₁₄: 0, a₁₅: 0, a₁₆: 0, a₁₇: ───────, a₂₁: 0, a₂₄: 0⎬
⎩      63                                                  7                   ⎭

In [7]: checksol(eqs, sol)
Out[7]: True

This shows that the system of equations was underdetermined so eg a18 can be arbitrary provided a11 = a18/63 etc. If one of the unknowns is not listed in the solution dict then it can take any arbitrary value independently of the others.这表明方程组是欠定的,例如a18可以是任意的,前提是a11 = a18/63等。如果其中一个未知数未在解字典中列出,那么它可以独立于其他任意值。

I added a %time in there to show that it takes 244 milliseconds to solve this on my not very fast computer (on the current sympy master branch -- it took ~0.5 seconds with sympy 1.8).我在其中添加了一个%time以表明在我不是非常快的计算机上解决这个问题需要 244 毫秒(在当前的 sympy master 分支上——使用 sympy 1.8 需要大约 0.5 秒)。 Note that I do have gmpy2 installed which can make various things faster in SymPy.请注意,我确实安装了 gmpy2,它可以使 SymPy 中的各种事情更快。 You might get a speed up from installing sympy 1.9rc1 and also gmpy2 ( pip install --pre --upgrade sympy and pip install gmpy2 ).安装 sympy 1.9rc1 和 gmpy2( pip install --pre --upgrade sympypip install gmpy2 )可能会加快速度。 It's also worth noting that some bugs for systems of this type were recently fixed in sympy so for other examples 1.9 might give more accurate results:还值得注意的是,这种类型的系统的一些错误最近在 sympy 中得到修复,因此对于其他示例 1.9 可能会给出更准确的结果:

https://github.com/sympy/sympy/pull/21883 https://github.com/sympy/sympy/pull/21883

You can use threading for your purposes.您可以根据自己的目的使用线程。

Here an explanation from Corey Schäfer --> https://youtu.be/IEEhzQoKtQU这是 Corey Schäfer 的解释 --> https://youtu.be/IEEhzQoKtQU

The core idea is to run code in paralellel, meaning your code doesn't go like "...compute first code block... (finished).... compute second code block... finished" and so on.核心思想是并行运行代码,这意味着您的代码不像 go “...计算第一个代码块...(完成)...计算第二个代码块...完成”等等。 With threading your code will run multiple code blocks at once.使用线程,您的代码将同时运行多个代码块。

A good python library is the multiprocessing library.一个好的 python 库是多处理库。

But first make sure how many processors you can utilize for your machine.但首先要确定您的机器可以使用多少个处理器。

import multiprocessing as mp
print("Number of processors: ", mp.cpu_count())

--> Number of processors:  4

For example my PC only has 4 processors available例如我的电脑只有 4 个处理器可用

And here an example of threading within python:这是 python 内的线程示例:

import requests
from multiprocessing.dummy import Pool as ThreadPool 

urls = ['https://www.python.org',
        'https://www.python.org/about/']

def get_status(url):
    r = requests.get(url)
    return r.status_code

if __name__ == "__main__":
    pool = ThreadPool(4)  # Make the Pool of workers
    results = pool.map(get_status, urls) #Open the urls in their own threads
    pool.close() #close the pool and wait for the work to finish 
    pool.join() 

This code above will loop through a list of URLs and outputs the status code of the URLs.上面的代码将遍历 URL 列表并输出 URL 的状态代码。 Without threading the code would do this in a iterative way.如果没有线程,代码将以迭代方式执行此操作。 First URL --> Status 200... NEXT... Second URL --> Status 200...NEXT... and so on.第一个 URL --> 状态 200... NEXT... 第二个 URL --> 状态 200...NEXT... 依此类推。

I hope I could help you out a bit.我希望我能帮助你一点。

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

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