为什么 Sympy signum 函数在求解方程组时在雅可比矩阵中不起作用?

Why do Sympy signum functions not work in Jacobian matrices when solving a system of equations?

我正在尝试求解由 2 个非线性方程组成的系统。这些方程式自己求解得很好,但是,当我将 Sympy 的 sign 函数添加到它们中的任何一个时,它们都无法求解。原系统如下:

修改后的系统(与原始系统相同,但在等式 1 中添加了符号)为:

我使用的求解器是我自己创建的,它适用于我尝试过的其他几个方程组。基于牛顿法的矩阵求解器根据 while 循环运行,该循环将猜测的输出残差(称为 A0guessVariance)与指定的容差进行比较。

关于系统的一些注意事项,以防系统在任何评论中被抢购一空:

这是原始的最小化代码没有符号函数:

import sympy as sp
from sympy.interactive import printing 
printing.init_printing(use_latex = True)
from sympy import Matrix 
from sympy.functions import sign

x_1, x_2 = sp.symbols('x_1 x_2')

#Input each equation into the "A0Function Matrix"
Equation1 = Matrix([((5*10**-5)*x_1**3 + +0.0035*x_1**2 + 0.6134*x_1 - 183.6 - x_2)])
#Equation1 = Matrix([((5*10**-5)*x_1**3 + +0.0035*x_1**2 + 0.6134*x_1 - 183.6 - x_2) * sign(x_1 - x_2)]) #UNCOMMENT FOR ERROR
Equation2 = Matrix([-0.0005*x_1**2 - 0.0028*x_1 + 62.765 - x_2])
A0FunctionMatrix = Matrix([Equation1, Equation2])
print('The System Function Matrix is')
#display(A0FunctionMatrix)
print(repr(A0FunctionMatrix))

#Variable Definitions
A0VariableMatrix = Matrix([x_1, x_2])

# The initial guesses must first be defined
guessx_1, guessx_2 = sp.symbols('guessx_1 guessx_2')
guessx_1 = 125
guessx_2 = 50

#Broad Loop Solver Conditions
tolerance = 0.05
max_iter = 5

print('SOLVER:')
dof = abs(A0VariableMatrix.shape[0] - A0FunctionMatrix.shape[0])
if dof == 0:
    A0guessmatrix = A0VariableMatrix.subs(([x_1, guessx_1], [x_2, guessx_2]))
    A0iter_n = 0
    A0tolerance = Matrix.ones(A0FunctionMatrix.shape[0], 1) * tolerance
    A0guessVariance = Matrix.ones(A0FunctionMatrix.shape[0], 1) * 10
    A0JacobianMatrix = A0FunctionMatrix.jacobian(A0VariableMatrix)
    print('placeholder 0 (displays the original Jacobian Matrix)')
    print(repr(A0JacobianMatrix))
    
    while (A0guessVariance[0,0] > A0tolerance[0,0]) and (A0guessVariance[1,0] > A0tolerance[1,0]):
        #print('Placeholder 1 (displays "A0fsolve", the function matrix with guess values substituted)')
        A0fsolve = A0FunctionMatrix.subs(([x_1, guessx_1], [x_2, guessx_2]))
        #display(A0fsolve)
        #print(repr(A0fsolve))
        print('Placeholder 2 (displays "A0jsolve", the jacobian matrix with guess values substituted)')
        A0jsolve = A0JacobianMatrix.subs(([x_1, guessx_1], [x_2, guessx_2]))
        #display(A0jsolve)
        print(repr(A0jsolve))
        A0delta_x0, fv = A0jsolve.gauss_jordan_solve(-1*A0fsolve)
        A0guessmatrix = A0VariableMatrix.subs(([x_1, guessx_1], [x_2, guessx_2]))
        A0nextguessmatrix = A0delta_x0 + A0guessmatrix
        guessx_1 = A0nextguessmatrix[0]
        guessx_2 = A0nextguessmatrix[1] 
        A0guessVariance = abs(A0nextguessmatrix - A0guessmatrix)
        A0guessmatrix = A0nextguessmatrix
        A0iter_n += 1
        print(f'{A0iter_n} iterations have been completed so far. Moving onto the next iteration...')
        if A0iter_n >= max_iter:
            print('The maximum Number of iterations has been reached')
            break
        
    if (A0guessVariance[0,0] <= A0tolerance[0,0]) and (A0guessVariance[1,0] <= A0tolerance[1,0]):
        print('The solution Matrix is')
        #display(A0nextguessmatrix)
        print(repr(A0nextguessmatrix))
        print(f'Which was achieved after {A0iter_n} iterations with a tolerance of {tolerance}.')
        print(f'Displayed as integers, the solutions for variable x and y converge at {sp.Float(A0nextguessmatrix[0])} and {sp.Float(A0nextguessmatrix[1])} as floats respectively.')
    else:
        print('The Equation set has no solution or the initial guesses are too far from the solution.')
        
elif dof !=0:
    print(f'This system has {A0FunctionMatrix.shape[0]} equations and {A0VariableMatrix.shape[0]} variables which represents a d.o.f value of {dof} which ≠ 0. Therefore, the system cannot be solved.')    

当 运行 我的代码通常没有符号函数正确答案时,(x_1, x_2) = (127, 54) 可以在输出中看到下面:

The System Function Matrix is
Matrix([
[5.0e-5*x_1**3 + 0.0035*x_1**2 + 0.6134*x_1 - x_2 - 183.6],
[              -0.0005*x_1**2 - 0.0028*x_1 - x_2 + 62.765]])
SOLVER:
placeholder 0 (displays the original Jacobian Matrix)
Matrix([
[0.00015*x_1**2 + 0.007*x_1 + 0.6134, -1],
[                -0.001*x_1 - 0.0028, -1]])
Placeholder 2 (displays "A0jsolve", the jacobian matrix with guess values substituted)
Matrix([
[3.83215, -1],
[-0.1278, -1]])
1 iterations have been completed so far. Moving onto the next iteration...
Placeholder 2 (displays "A0jsolve", the jacobian matrix with guess values substituted)
Matrix([
[  3.93615930824608, -1],
[-0.130119158070178, -1]])
2 iterations have been completed so far. Moving onto the next iteration...
The solution Matrix is
Matrix([
[127.288913112303],
[54.3073578000086]])
Which was achieved after 2 iterations with a tolerance of 0.05.
Displayed as integers, the solutions for variable x and y converge at 127.288913112303 and 54.3073578000086 as floats respectively.

但是,当公式 1 添加符号函数时,求解器无法执行。最终答案应该使符号 return 为正值,我不确定为什么这是一个问题。下面是相同的示例代码,但在等式 1 中添加了符号:

import sympy as sp
from sympy.interactive import printing 
printing.init_printing(use_latex = True)
from sympy import Matrix 
from sympy.functions import sign

x_1, x_2 = sp.symbols('x_1 x_2')

#Input each equation into the "A0Function Matrix"
#Equation1 = Matrix([((5*10**-5)*x_1**3 + +0.0035*x_1**2 + 0.6134*x_1 - 183.6 - x_2)])
Equation1 = Matrix([((5*10**-5)*x_1**3 + +0.0035*x_1**2 + 0.6134*x_1 - 183.6 - x_2) * sign(x_1 - x_2)]) #UNCOMMENT FOR ERROR
Equation2 = Matrix([-0.0005*x_1**2 - 0.0028*x_1 + 62.765 - x_2])
A0FunctionMatrix = Matrix([Equation1, Equation2])
print('The System Function Matrix is')
#display(A0FunctionMatrix)
print(repr(A0FunctionMatrix))

#Variable Definitions
A0VariableMatrix = Matrix([x_1, x_2])

# The initial guesses must first be defined
guessx_1, guessx_2 = sp.symbols('guessx_1 guessx_2')
guessx_1 = 125
guessx_2 = 50

#Broad Loop Solver Conditions
tolerance = 0.05
max_iter = 5

print('SOLVER:')
dof = abs(A0VariableMatrix.shape[0] - A0FunctionMatrix.shape[0])
if dof == 0:
    A0guessmatrix = A0VariableMatrix.subs(([x_1, guessx_1], [x_2, guessx_2]))
    A0iter_n = 0
    A0tolerance = Matrix.ones(A0FunctionMatrix.shape[0], 1) * tolerance
    A0guessVariance = Matrix.ones(A0FunctionMatrix.shape[0], 1) * 10
    A0JacobianMatrix = A0FunctionMatrix.jacobian(A0VariableMatrix)
    print('placeholder 0 (displays the original Jacobian Matrix)')
    print(repr(A0JacobianMatrix))
    
    while (A0guessVariance[0,0] > A0tolerance[0,0]) and (A0guessVariance[1,0] > A0tolerance[1,0]):
        #print('Placeholder 1 (displays "A0fsolve", the function matrix with guess values substituted)')
        A0fsolve = A0FunctionMatrix.subs(([x_1, guessx_1], [x_2, guessx_2]))
        #display(A0fsolve)
        #print(repr(A0fsolve))
        print('Placeholder 2 (displays "A0jsolve", the jacobian matrix with guess values substituted)')
        A0jsolve = A0JacobianMatrix.subs(([x_1, guessx_1], [x_2, guessx_2]))
        #display(A0jsolve)
        print(repr(A0jsolve))
        A0delta_x0, fv = A0jsolve.gauss_jordan_solve(-1*A0fsolve)
        A0guessmatrix = A0VariableMatrix.subs(([x_1, guessx_1], [x_2, guessx_2]))
        A0nextguessmatrix = A0delta_x0 + A0guessmatrix
        guessx_1 = A0nextguessmatrix[0]
        guessx_2 = A0nextguessmatrix[1] 
        A0guessVariance = abs(A0nextguessmatrix - A0guessmatrix)
        A0guessmatrix = A0nextguessmatrix
        A0iter_n += 1
        print(f'{A0iter_n} iterations have been completed so far. Moving onto the next iteration...')
        if A0iter_n >= max_iter:
            print('The maximum Number of iterations has been reached')
            break
        
    if (A0guessVariance[0,0] <= A0tolerance[0,0]) and (A0guessVariance[1,0] <= A0tolerance[1,0]):
        print('The solution Matrix is')
        #display(A0nextguessmatrix)
        print(repr(A0nextguessmatrix))
        print(f'Which was achieved after {A0iter_n} iterations with a tolerance of {tolerance}.')
        print(f'Displayed as integers, the solutions for variable x and y converge at {sp.Float(A0nextguessmatrix[0])} and {sp.Float(A0nextguessmatrix[1])} as floats respectively.')
    else:
        print('The Equation set has no solution or the initial guesses are too far from the solution.')
        
elif dof !=0:
    print(f'This system has {A0FunctionMatrix.shape[0]} equations and {A0VariableMatrix.shape[0]} variables which represents a d.o.f value of {dof} which ≠ 0. Therefore, the system cannot be solved.')    

这 return 是以下输出和错误:

The System Function Matrix is
Matrix([
[(5.0e-5*x_1**3 + 0.0035*x_1**2 + 0.6134*x_1 - x_2 - 183.6)*sign(x_1 - x_2)],
[                                -0.0005*x_1**2 - 0.0028*x_1 - x_2 + 62.765]])
SOLVER:
placeholder 0 (displays the original Jacobian Matrix)
Matrix([
[(0.00015*x_1**2 + 0.007*x_1 + 0.6134)*sign(x_1 - x_2) + (5.0e-5*x_1**3 + 0.0035*x_1**2 + 0.6134*x_1 - x_2 - 183.6)*Derivative(sign(x_1 - x_2), x_1), (5.0e-5*x_1**3 + 0.0035*x_1**2 + 0.6134*x_1 - x_2 - 183.6)*Derivative(sign(x_1 - x_2), x_2) - sign(x_1 - x_2)],
[                                                                                                                                -0.001*x_1 - 0.0028,                                                                                                            -1]])
Placeholder 2 (displays "A0jsolve", the jacobian matrix with guess values substituted)
Matrix([
[3.83215 - 4.58125*Subs(Derivative(sign(x_1 - 50), x_1), x_1, 125), -4.58125*Subs(Derivative(sign(125 - x_2), x_2), x_2, 50) - 1],
[                                                          -0.1278,                                                           -1]])
1 iterations have been completed so far. Moving onto the next iteration...
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-193820857f4b> in <module>
     39     print(repr(A0JacobianMatrix))
     40 
---> 41     while (A0guessVariance[0,0] > A0tolerance[0,0]) and (A0guessVariance[1,0] > A0tolerance[1,0]):
     42         #print('Placeholder 1 (displays "A0fsolve", the function matrix with guess values substituted)')
     43         A0fsolve = A0FunctionMatrix.subs(([x_1, guessx_1], [x_2, guessx_2]))

C:\ProgramData\Anaconda3\lib\site-packages\sympy\core\relational.py in __bool__(self)
    396 
    397     def __bool__(self):
--> 398         raise TypeError("cannot determine truth value of Relational")
    399 
    400     def _eval_as_set(self):

TypeError: cannot determine truth value of Relational

注意 第一个和第二个输出之间的主要区别似乎是占位符 0 处的 A0JacobianMatrix。在第一个输出中,它全是数字,但在第二个输出中它不是;这似乎是一个 Sympy 错误。任何想法或帮助将不胜感激!

我收到了一份 similar issue which I posted on Stack Overflow with a larger system of equations 尚未得到最终答复的邮件。

非常感谢@OscarBenjamin 帮助解答! (已经几天了,我想我的声誉很低,我无法将他的评论标记为答案?)

问题是变量没有被声明为真正的符号。我假设 Sympy 默认假定符号既是实数又是复数。

明确地说,当每个符号都像这样声明为真实时,这个问题就解决了:

x_1, x_2 = sp.symbols('x_1 x_2', real = True)

之前是这样的:

x_1, x_2 = sp.symbols('x_1 x_2')