加快 Sympy 对大量变量的求解集计算

Speeding up Sympy's solveset calculation for a large array of variables

我正在尝试根据特定的不等式从特定点创建 space 中点的参数化。

我正在使用 Sympy.solevset 方法进行计算,而计算将 return 参数区间 t 代表我的数据框中那些点之间的所有点。

遗憾的是,执行 Sympy.solveset 超过 13 组值(即 13 次迭代)会导致总执行时间超过 20 秒,每组计算时间超过 1 秒。

代码:

from sympy import *
from sympy import S
from sympy.solvers.solveset import solveset, solveset_real
import pandas as pd
import time

t=symbols('t',positive=True)
p1x,p1y,p2x,p2y=symbols('p1x p1y p2x p2y')

centerp=[10,10]
radius=5

data={'P1X':[0,1,2,3,1,2,3,1,2,3,1,2,3],'P1Y':[3,2,1,0,1,2,3,1,2,3,1,2,3],'P2X':[3,8,2,4,1,2,3,1,2,3,1,2,3],'P2Y':[3,9,10,7,1,2,3,1,2,3,1,2,3],'result':[0,0,0,0,0,0,0,0,0,0,0,0,0]}
df=pd.DataFrame(data)

parameterized_x=p1x+t*(p2x-p1x)
parameterized_y=p1y+t*(p2y-p1y)

start_whole_process=time.time()

overall_time=0

for index,row in df.iterrows():
    
   parameterized_x.subs([[p1x,row['P1X']],[p2x,row['P2X']]])
   parameterized_y.subs([[p1y,row['P1Y']],[p2y,row['P2Y']]])
   expr=sqrt((parameterized_x-centerp[0])**2+(parameterized_y-centerp[1])**2)-radius
   
   start=time.time()

   df.at[index,'result']=solveset(expr>=0,t,domain=S.Reals)
   end=time.time()
   
   overall_time=overall_time+end-start
   
end_whole_process=time.time()

我需要知道是否有一种方法可以缩短计算时间,或者是否有另一个包可以对大量数据执行特定的不等式,而无需等待几分钟。

您当前的方法存在一个大错误,需要先修正。在你的 for 循环中你做了:

parameterized_x.subs([[p1x,row['P1X']],[p2x,row['P2X']]])
parameterized_y.subs([[p1y,row['P1Y']],[p2y,row['P2Y']]])
expr=sqrt((parameterized_x-centerp[0])**2+(parameterized_y-centerp[1])**2)-radius

这是错误的:SymPy 表达式不能就地修改。这导致您的 expr 每行完全相同,即:

# sqrt((p1x + t*(-p1x + p2x) - 10)**2 + (p1y + t*(-p1y + p2y) - 10)**2) - 5

然后,solveset 尝试在每一行上求解相同的表达式。因为此表达式包含 3 个符号,solveset 需要很长时间来尝试计算解决方案,最终为每一行生成相同的答案:

# ConditionSet(t, sqrt((p1x + t*(-p1x + p2x) - 10)**2 + (p1y + t*(-p1y + p2y) - 10)**2) - 5 >= 0, Complexes)

记住:您应用于 SymPy 表达式的每个操作都会创建一个新的 SymPy 表达式。所以,上面的代码要修改为:

px_expr = parameterized_x.subs([[p1x,row['P1X']],[p2x,row['P2X']]])
py_expr = parameterized_y.subs([[p1y,row['P1Y']],[p2y,row['P2Y']]])
expr=sqrt((px_expr-centerp[0])**2+(py_expr-centerp[1])**2)-radius

在这样做的过程中,expr 对于每一行都是不同的,正如预期的那样。然后,solveset 计算不同的解决方案,而且速度要快得多。

这是您的完整示例:

from sympy import *
from sympy.solvers.solveset import solveset, solveset_real
import pandas as pd
import time

t=symbols('t',positive=True)
p1x,p1y,p2x,p2y=symbols('p1x p1y p2x p2y')

centerp=[10,10]
radius=5

data={'P1X':[0,1,2,3,1,2,3,1,2,3,1,2,3],'P1Y':[3,2,1,0,1,2,3,1,2,3,1,2,3],'P2X':[3,8,2,4,1,2,3,1,2,3,1,2,3],'P2Y':[3,9,10,7,1,2,3,1,2,3,1,2,3],'result':[0,0,0,0,0,0,0,0,0,0,0,0,0]}
df=pd.DataFrame(data)

parameterized_x=p1x+t*(p2x-p1x)
parameterized_y=p1y+t*(p2y-p1y)

start_whole_process=time.time()

overall_time=0

for index,row in df.iterrows():
    px_expr = parameterized_x.subs([[p1x,row['P1X']],[p2x,row['P2X']]])
    py_expr = parameterized_y.subs([[p1y,row['P1Y']],[p2y,row['P2Y']]])
    expr=sqrt((px_expr-centerp[0])**2+(py_expr-centerp[1])**2)-radius
    df.at[index,'result']=solveset(expr>=0,t,domain=S.Reals)

end_whole_process=time.time()
print("end_whole_process - start_whole_process", end_whole_process - start_whole_process)