在SymPy

时间:2018-03-28 12:29:18

标签: python sympy calculus hessian-matrix

我目前正在研究多变量函数演算的一些练习,并且我认为我可以自己创建函数来确定任何函数的定义点处的梯度和粗糙度。我在尝试用任意函数的坐标值替换结果矩阵时遇到了问题。我已经设法解决了具体的例子,但我尝试使用函数来解决用户定义的函数是不能正常工作的。

def multivariable_function(function, variables, substitute=(0,0)):
"""Determines Gradient and Hessian vectors for multivariable function.

  Args:
    function: Enter the multivariable function
    variables: Enter list of variable names
    substitute: Default = (0,0)

  Returns:
    gradient/hessian matrices for given coordinate 

  To do:
    Include sympy symbol() generation within function
  """

  #derive_by_array returns a gradient matrix for multivariable function
  Gradient = simplify(derive_by_array(function, variables))

  #derive_by_array returns a Hessian matrix for multivariable function                   
  Hessian = simplify(derive_by_array(derive_by_array(function, variables), variables))

  #Line currently isn't doing anything
  Gradient.subs(zip(variables, substitute))

  return Gradient, Hessian

这是迄今为止的基本功能。

multivariable_function((x**2)*(y**3) + exp(2*x + x*y - 1) - (x**3 + 3*y**2)**2, (x,y))`

产生以下result,但我的目标是将所需的值替换为梯度和粗糙矩阵以实现以下desired result。我设法使用以下内容实现了预期的结果。

from sympy import *

x, y, z, K, T, r, σ, h, a, f, μ, c, t, m, x1, x2, x3 = symbols('x, y, z, K, T, r, σ, h, a, f, μ, c, t, m, x1, x2, x3') # Variables used must be defined in sympy.
init_printing(use_unicode=False) #Print the answers in unicode characters

function = (x**2)*(y**3) + exp(2*x + x*y - 1) - (x**3 + 3*y**2)**2

Gradient_1 = simplify(derive_by_array(function, (x, y)))
Hessian_1 = simplify(derive_by_array(derive_by_array(function, (x, y)), (x, y)))

Gradient_1.subs(x, 0).subs(y,0), Hessian_1.subs(x,0).subs(y,0)

在查看问题here之后,似乎压缩两个列表应该使subs()函数能够工作,但它目前不适合我。我试图循环'变量'和'替换'来顺序地应用.subs(),但是我发现只有当方法被链接到所有替换变量时,该函数才有效,如上例所示。

有没有人知道如何为给定坐标应用.subs()n次以产生相关的梯度/粗糙矩阵?

1 个答案:

答案 0 :(得分:1)

变量Gradient的类型为

sympy.tensor.array.dense_ndim_array.ImmutableDenseNDimArray

与几乎所有SymPy对象一样,除了可变矩阵之外,它是不可变的。方法subs不会对其进行修改;它返回一个需要分配的新对象。

  Gradient = Gradient.subs(zip(variables, substitute))
  Hessian = Hessian.subs(zip(variables, substitute))

然后该函数按预期工作,返回

([2*exp(-1), 0], [[4*exp(-1), exp(-1)], [exp(-1), 0]])

但我建议不要将生成器传递给subs;有涉及到这一点的突出问题。首先转换为列表或字典,以确保安全。 (那里也有区别:替换应该是连续的还是同时的,尽管用数字代替符号无关紧要。)

  subs_dict = dict(zip(variables, substitute))
  Gradient = Gradient.subs(subs_dict)
  Hessian = Hessian.subs(subs_dict)