I have been trying to solve a system of 10,000 non-linear equations with 100 variables using Sympy/Numpy in Python.
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).
Generating the set of equations with Sympy itself took ~1 hour. I switched to SageMath (Windows native), which seemed to do equation generation itself way better (~3min), still, helpless with solving them.
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?
My system is i7-11300H/16GB RAM.
Edit: linalg.solve was a mistake as I initially thought it is a linear system, later realised that it is not.
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.
CodePudding user response:
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 e.g. S(1)/2
or Rational(1, 2)
rather than 1/2
like this:
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:
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).
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. 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. 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. 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 e.g. 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.
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). Note that I do have gmpy2 installed which can make various things faster in SymPy. You might get a speed up from installing sympy 1.9rc1 and also gmpy2 (pip install --pre --upgrade sympy
and pip 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:
https://github.com/sympy/sympy/pull/21883
CodePudding user response:
You can use threading for your purposes.
Here an explanation from 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. With threading your code will run multiple code blocks at once.
A good python library is the multiprocessing library.
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
And here an example of threading within 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. Without threading the code would do this in a iterative way. First URL --> Status 200 ... NEXT ... Second URL --> Status 200 ...NEXT ... and so on.
I hope I could help you out a bit.