说我已经定义了以下表达式:
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
可以根据需要显示,但是在随后的计算中将无法正常工作(例如,导数将是抽象的,并且不进行评估)。
任何帮助将不胜感激!
答案 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函数有两个参数。如果需要,还可以在某些情况下使它返回显式值。例如,您可能希望它评估i
和j
是否为显式数字。
@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文档。