1

I am investigating the suitability of SymPy for some of my projects and have come across an issue with the interaction between lambdify and IndexedBase.

In short, my applications make heavy use of functions that employ doubled summed array structures. I need to be able to compute both the function and the first through 3rd derivative of the function with respect to an array element.

My questions are thus:

  1. How do I make lambdify work with diff?
  2. How do I make a lambdify function where I can specify the index with respect to which I want the derivative?
  3. How do I extend the above to a second order derivative with a different index (i.e. second order with respect to index i and j)?

Simplified example:

from sympy import IndexedBase, Idx, lambdify, Sum, diff
from numpy import array


i = Idx("i", range=(0,1))
j = Idx("j", range=(0,1))
n = IndexedBase("n")
coefficients = IndexedBase("C")

double_sum = Sum(Sum(n[i]*n[j]*coefficients[i,j],(i,i.lower,i.upper)),(j,j.lower,j.upper))
first_derivative = diff(double_sum, n[i])
second_derivative = diff(first_derivative, n[j])

test_function_1 = lambdify((n,coefficients),double_sum)
test_function_2 = lambdify((n,coefficients,i),first_derivative)
test_function_3 = lambdify((n,coefficients,i,j),second_derivative)

test_vector = array([1, 2])
test_coefficients = array([[1,1],[2,3]])

test_value_1 = test_function_1(test_vector,test_coefficients)
print(test_value_1)

test_value_2 = test_function_2(test_vector,test_coefficients,1)
print(test_value_2)

test_value_3 = test_function_3(test_vector,test_coefficients)
print(test_value_3)

Execution of this code yields the error:

File "<lambdifygenerated-2>", line 9, in _lambdifygenerated
File "<lambdifygenerated-2>", line 9, in <genexpr>
NameError: name 'KroneckerDelta' is not defined 
4

1 回答 1

1

索引表达式很有用,但它们的派生词有时比它们应有的复杂得多,而且它们往往与lambdify. 这是不使用索引的大致等效代码。不同之处在于数组的大小是预先声明的,这使得可以使用 来创建普通(非索引)符号的显式数组symarray,操作它们,并对表达式进行lambdify。我以某种方式对它们进行了简化,以便将一阶导数作为 1 列矩阵返回,将二阶导数作为方阵返回(下面是另一种返回类型)。

from sympy import symarray, Add, lambdify, Matrix
from numpy import array

i_upper = 2
j_upper = 2
n = symarray("n", i_upper)
coefficients = symarray("C", (i_upper, j_upper))

double_sum = Add(*[n[i]*n[j]*coefficients[i, j] for i in range(i_upper) for j in range(j_upper)])
first_derivative = Matrix(i_upper, 1, lambda i, j: double_sum.diff(n[i]))
second_derivative = Matrix(i_upper, j_upper, lambda i, j: double_sum.diff(n[i], n[j]))

params = list(n) + list(coefficients.ravel())
test_function_1 = lambdify(params, double_sum)
test_function_2 = lambdify(params, first_derivative)
test_function_3 = lambdify(params, second_derivative)

test_vector = array([1, 2])
test_coefficients = array([[1, 1], [2, 3]])
test_params = list(test_vector) + list(test_coefficients.ravel())    
test_value_1 = test_function_1(*test_params)
test_value_2 = test_function_2(*test_params)
test_value_3 = test_function_3(*test_params)

测试值分别19[[8], [15]][[2, 3], [3, 6]]

或者,函数可以返回嵌套列表:

first_derivative = [double_sum.diff(n[i]) for i in range(i_upper)]
second_derivative = [[double_sum.diff(n[i], n[j]) for j in range(i_upper)] for i in range(i_upper)]

或 NumPy 数组:

first_derivative = array([double_sum.diff(n[i]) for i in range(i_upper)])
second_derivative = array([[double_sum.diff(n[i], n[j]) for j in range(i_upper)] for i in range(i_upper)])

这种方法的局限性: (a) 在形成表达式时必须知道符号的数量;(b) 不能接受索引ij作为lambdified 函数的参数。

于 2018-09-09T21:03:43.570 回答