我正在努力研究sympy.MatrixSymbol的元素似乎与sympy的分化程序没有很好的互动。
我正在尝试使用sympy.MatrixSymbol的元素而不是“普通”的sympy符号这一事实是因为我想要自动包装一个大函数,这似乎是克服参数限制和启用的唯一方法输入单个数组。
为了让读者了解可能的解决方案的限制,我将首先概述我的意图;然而,仓促的读者可能会跳到下面的代码块,这说明了我的问题。
声明某种变量的向量或数组。
从前者的元素中构建一些表达式;这些表达式构成了所述向量的向量值函数的分量。除了这个功能,我想获得Jacobian w.r.t.向量。
使用autowrap(使用cython后端)获取向量函数及其雅可比行列式的数值实现。这对前面的步骤施加了一些限制:(a)希望函数的输入是作为矢量而不是符号列表给出的。 (两者都是因为似乎对自动包装函数的输入数量有限制,并且稍后可以简化与scipy的交互,即避免经常将numpy向量解包到列表中。
在我的旅程中,我遇到了两个问题:
sympy.Max
,我非常依赖它。 autowrap的“助手”kwarg似乎无法一次处理多个助手。(另见上文this question)
因为我宁愿给出一个向量而不是列表作为函数的输入,我想找到一种方法来让包装函数将numpy数组作为输入(与DeferredVector + lambdify相当)。似乎这样做的自然方式是sympy.MatrixSymbol。 (请参阅上面链接的主题。我不确定是否有替代方案,如果是,欢迎提出建议。)
我的最新问题从这里开始:我意识到sympy.MatrixSymbol的元素在很多方面都不像“其他”的同情符号。一个人必须单独分配属性真实和可交换,然后似乎工作正常。然而,当我试图获得雅可比人时,我真正的麻烦开始了;同情似乎没有立即获得元素的衍生物:
import sympy
X= sympy.MatrixSymbol("X",10,1)
for element in X:
element._assumptions.update({"real":True, "commutative":True})
X[0].diff(X[0])
Out[2]: Derivative(X[0, 0], X[0, 0])
X[1].diff(X[0])
Out[15]: Derivative(X[1, 0], X[0, 0])
以下块是我想做的最小例子,但这里使用的是普通符号: (我认为它捕获了我需要的所有内容,如果我忘记了以后我会添加的内容。)
import sympy
from sympy.utilities.autowrap import autowrap
X = sympy.symbols("X:2", real = True)
expr0 = X[1]*( (X[0] - abs(X[0]) ) /2)**2
expr1 = X[0]*( (X[1] - abs(X[1]) ) /2)**2
F = sympy.Matrix([expr0, expr1])
J = F.jacobian([X[0],X[1]])
J_num = autowrap(J, args = [X[0],X[1]], backend="cython")
这是我(目前)使用sympy.MatrixSymbol的最佳猜测,当然因为Derivative
中的J
- 表达式而导致失败:
X= sympy.MatrixSymbol("X",2,1)
for element in X:
element._assumptions.update({"real":True, "commutative":True, "complex":False})
expr0 = X[1]*( (X[0] - abs(X[0]) ) /2)**2
expr1 = X[0]*( (X[1] - abs(X[1]) ) /2)**2
F = sympy.Matrix([expr0, expr1])
J = F.jacobian([X[0],X[1]])
J_num = autowrap(J, args = [X], backend="cython")
以上是J
在运行上述内容后的样子:
J
Out[50]:
Matrix([
[(1 - Derivative(X[0, 0], X[0, 0])*X[0, 0]/Abs(X[0, 0]))*(-Abs(X[0, 0])/2 + X[0, 0]/2)*X[1, 0], (-Abs(X[0, 0])/2 + X[0, 0]/2)**2],
[(-Abs(X[1, 0])/2 + X[1, 0]/2)**2, (1 - Derivative(X[1, 0], X[1, 0])*X[1, 0]/Abs(X[1, 0]))*(-Abs(X[1, 0])/2 + X[1, 0]/2)*X[0, 0]]])
毫不奇怪,autowrap并不喜欢:
[...]
wrapped_code_2.c(4): warning C4013: 'Derivative' undefined; assuming extern returning int
[...]
wrapped_code_2.obj : error LNK2001: unresolved external symbol Derivative
如何告诉同情X[0].diff(X[0])=1
和X[0].diff(X[1])=0
?甚至可能是abs(X[0]).diff(X[0]) = sign(X[0])
。
或者有没有办法使用sympy.MatrixSymbol和still get a cythonized function,其中输入是单个向量而不是符号列表?
对于任何输入都会很有用,很可能是上述过程中任何步骤的解决方法。谢谢你的阅读!
编辑:
一句简短的评论:我能想出的一个解决方案是:
使用普通符号构造F
和J
;然后用一些sympy.MatrixSymbol的元素替换两个表达式中的符号。这似乎可以完成工作,但更换需要相当长的时间,因为J
可以达到~1000x1000及以上的尺寸。因此,我宁愿避免采用这种方法。
答案 0 :(得分:1)
经过更广泛的研究后,我上面描述的问题似乎已经在开发/ github版本中修复了。相应更新后,所有涉及Derivative
的{{1}}字词都会正确解析!
请参阅here以供参考。