sympy.MatrixSymbol:分化问题

时间:2017-06-05 21:22:42

标签: python cython sympy

我正在努力研究sympy.MatrixSymbol的元素似乎与sympy的分化程序没有很好的互动。

我正在尝试使用sympy.MatrixSymbol的元素而不是“普通”的sympy符号这一事实是因为我想要自动包装一个大函数,这似乎是克服参数限制和启用的唯一方法输入单个数组。

为了让读者了解可能的解决方案的限制,我将首先概述我的意图;然而,仓促的读者可能会跳到下面的代码块,这说明了我的问题。

  1. 声明某种变量的向量或数组。

  2. 从前者的元素中构建一些表达式;这些表达式构成了所述向量的向量值函数的分量。除了这个功能,我想获得Jacobian w.r.t.向量。

  3. 使用autowrap(使用cython后端)获取向量函数及其雅可比行列式的数值实现。这对前面的步骤施加了一些限制:(a)希望函数的输入是作为矢量而不是符号列表给出的。 (两者都是因为似乎对自动包装函数的输入数量有限制,并且稍后可以简化与scipy的交互,即避免经常将numpy向量解包到列表中。

  4. 在我的旅程中,我遇到了两个问题:

    • Cython似乎不喜欢一些同情功能,其中包括sympy.Max,我非常依赖它。 autowrap的“助手”kwarg似乎无法一次处理多个助手。
    • 这本身并不是什么大问题,因为我学会了使用abs()或sign()绕过它,cython很容易理解。

    (另见上文this question

    • 如前所述,autowrap / cython不接受超过509个符号形式的参数,至少在我的编译器设置中是这样。 (另见here
    • 因为我宁愿给出一个向量而不是列表作为函数的输入,我想找到一种方法来让包装函数将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])=1X[0].diff(X[1])=0?甚至可能是abs(X[0]).diff(X[0]) = sign(X[0])

    或者有没有办法使用sympy.MatrixSymbol和still get a cythonized function,其中输入是单个向量而不是符号列表?

    对于任何输入都会很有用,很可能是上述过程中任何步骤的解决方法。谢谢你的阅读!

    编辑:
    一句简短的评论:我能想出的一个解决方案是: 使用普通符号构造FJ;然后用一些sympy.MatrixSymbol的元素替换两个表达式中的符号。这似乎可以完成工作,但更换需要相当长的时间,因为J可以达到~1000x1000及以上的尺寸。因此,我宁愿避免采用这种方法。

1 个答案:

答案 0 :(得分:1)

经过更广泛的研究后,我上面描述的问题似乎已经在开发/ github版本中修复了。相应更新后,所有涉及Derivative的{​​{1}}字词都会正确解析!

请参阅here以供参考。