Sympy-重命名表达式的一部分

时间:2019-02-28 09:21:33

标签: python sympy

说我已经定义了以下表达式:

from sympy import *
N, D, i, j, d = symbols("N D i j d", integer=True)
beta, gamma = symbols(r'\beta \gamma')
X = IndexedBase("X", shape=(N, D))

# r(i, j) = euclidian distance between X[i] and X[j]
r = lambda i, j: sqrt(Sum((X[i, d] - X[j, d])**2, (d, 1, D)))
expr = r(i, j)**2 + r(i, j)

expr变量现在显示如下:

尽管对于这个最小的示例来说这很好,但是在较大的表达式中却变得非常混乱。这确实阻碍了我查看以后计算所有r(i,j),导数等的和时会发生什么的能力。

我的问题:有没有办法向SymPy告知r(i, j),以便可以将其显示为以下内容:

在后续表达式中仍然表现出与以往相同的行为吗?

我知道我可以将r设为Function,该PositionA 8 PostionB 12 PostionC 13 可以根据需要显示,但是在随后的计算中将无法正常工作(例如,导数将是抽象的,并且不进行评估)。

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:2)

我真的不知道这是否对您有帮助,但是呢:

from sympy import *
from sympy.utilities.lambdify import lambdify, implemented_function
N, D, i, j, d = symbols("N D i j d", integer=True)
beta, gamma = symbols(r'\beta \gamma')
X = IndexedBase("X", shape=(N, D))

r = implemented_function('r', lambda i, j: sqrt(Sum((X[i, d] - X[j, d])**2, (d, 1, D))));
expr = r(i, j)**2 + r(i, j)
print(expr)
r = lambdify((i,j), r(i,j))
print(diff(r(i,j), X[i,j]))

您可以根据需要显示表达式,然后使用lambdify()使其表现出应有的状态。只是猜测,可能对您没有用,因为您可能更喜欢在代码中始终保持相同表达式的方式。

答案 1 :(得分:2)

您可以创建一个默认情况下不求值的自定义Function子类:

class r(Function):
    @classmethod
    def eval(cls, i, j):
        return

    def doit(self, **kwargs):
        i, j = self.args
        return sqrt(Sum((X[i, d] - X[j, d])**2, (d, 1, D)))

eval告诉它何时进行评估。因为它总是返回None,所以它永远不会求值。它还告诉SymPy函数有两个参数。如果需要,还可以在某些情况下使它返回显式值。例如,您可能希望它评估ij是否为显式数字。

@classmethod
def eval(cls, i, j):
    if i.is_Number and j.is_Number:
        return sqrt(Sum((X[i, d] - X[j, d])**2, (d, 1, D)))

您可以根据需要使用它,并在需要评估时调用expr.doit()。您还可以为某些功能专门定义评估以避免doit。例如,衍生工具:

def _eval_derivative(self, x):
    return self.doit()._eval_derivative(x)

这将使r(i, j).diff(i)可以立即进行评估,而不必致电doit

其他函数具有可以定义的相似方法。请参阅SymPy文档。