簡體   English   中英

計算求解 100 個變量的非線性方程組

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

我一直在嘗試在 Python 中使用 Sympy/Numpy 求解一個包含 10,000 個具有 100 個變量的非線性方程組。

到目前為止的嘗試:

我嘗試了 Sympy 的 nsolve 和 solve,在 numpy.linalg 中解決,所有這些在等待 5-6 小時后仍在運行(當我用完 RAM 時,我最終強行停止了它們)。

使用 Sympy 本身生成方程組大約需要 1 小時。 我切換到 SageMath(Windows 原生),它本身似乎可以更好地生成方程式(~3 分鍾),但仍然無助於解決它們。

有沒有一種方法可以使用 SageMath/Python 本身中的任何特定語言或技巧來優化運行,或者我應該尋找更強大的系統來運行代碼?

我的系統是 i7-11300H/16GB 內存。

編輯:linalg.solve 是一個錯誤,因為我最初認為它是一個線性系統,后來意識到它不是。

編輯:

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)

還嘗試使用 0 數組作為初始值的 nsolve。

在您更新問題后,我想我明白您在做什么,但我認為您沒有以正確的方式解決問題。

首先,您定義方程組的方式引入了浮點系數,並且帶有浮點數的多項式方程可能非常病態,因此請確保使用例如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
        )
    )

所以你有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          ⎠

Ea24的第一項使這種非線性但只是溫和的,因為它是二次和多項式而不是說超越或其他東西(你以前只將你的方程描述為非線性,這可以意味着任何東西)。

您正在為每個xt替換 100 個不同的值,然后嘗試求解 10000 個方程以使每個值的E為零。 幾乎可以肯定,這些方程的唯一可能解是那些使x,t多項式的所有系數都為零的解。 我猜你實際上想做的是找到使所有x,tE為零的ai符號的值,但我們不需要 10000 個方程來做到這一點。 我們可以只提取系數並將它們求解為方程式:

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

這表明方程組是欠定的,例如a18可以是任意的,前提是a11 = a18/63等。如果其中一個未知數未在解字典中列出,那么它可以獨立於其他任意值。

我在其中添加了一個%time以表明在我不是非常快的計算機上解決這個問題需要 244 毫秒(在當前的 sympy master 分支上——使用 sympy 1.8 需要大約 0.5 秒)。 請注意,我確實安裝了 gmpy2,它可以使 SymPy 中的各種事情更快。 安裝 sympy 1.9rc1 和 gmpy2( pip install --pre --upgrade sympypip install gmpy2 )可能會加快速度。 還值得注意的是,這種類型的系統的一些錯誤最近在 sympy 中得到修復,因此對於其他示例 1.9 可能會給出更准確的結果:

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

您可以根據自己的目的使用線程。

這是 Corey Schäfer 的解釋 --> https://youtu.be/IEEhzQoKtQU

核心思想是並行運行代碼,這意味着您的代碼不像 go “...計算第一個代碼塊...(完成)...計算第二個代碼塊...完成”等等。 使用線程,您的代碼將同時運行多個代碼塊。

一個好的 python 庫是多處理庫。

但首先要確定您的機器可以使用多少個處理器。

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

--> Number of processors:  4

例如我的電腦只有 4 個處理器可用

這是 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() 

上面的代碼將遍歷 URL 列表並輸出 URL 的狀態代碼。 如果沒有線程,代碼將以迭代方式執行此操作。 第一個 URL --> 狀態 200... NEXT... 第二個 URL --> 狀態 200...NEXT... 依此類推。

我希望我能幫助你一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM