Python 使用numexpr的Sympy lambdify ImmutableDensMatrix

Python 使用numexpr的Sympy lambdify ImmutableDensMatrix,python,sympy,numexpr,lambdify,Python,Sympy,Numexpr,Lambdify,我尝试使用lambdify加速对可变密度矩阵的求值。它与模块“numpy”一起工作Numexpr'应该更快(因为我需要评估来解决大型优化问题) 下面给出了我正在尝试做的一个小例子 from sympy import symbols, cos, Matrix, lambdify a11, a12, a21, a22, b11, b12, b21, b22, u = symbols("a11 a12 a21 a22 b11 b12 b21 b22 u") A = Matrix(

我尝试使用lambdify加速对可变密度矩阵的求值。它与模块“numpy”一起工作Numexpr'应该更快(因为我需要评估来解决大型优化问题)

下面给出了我正在尝试做的一个小例子

from sympy import symbols, cos, Matrix, lambdify

a11, a12, a21, a22, b11, b12, b21, b22, u = symbols("a11 a12 a21 a22 b11 b12 b21 b22 u")
A = Matrix([[a11, a12], [a21, a22]])
B = Matrix([[b11, b12], [b21, b22]])
expr = A * (B ** 2) * cos(u) + A ** (-3 / 2)
f = lambdify((A, B), expr, modules='numexpr')
这就产生了错误

TypeError: numexpr cannot be used with ImmutableDenseMatrix
有没有一种方法可以将lambdify用于密度矩阵?或者另一个如何加速评估的想法


提前谢谢

使用numexpr的一个可能解决方案是单独计算每个矩阵表达式。下面的代码应该输出一个python函数,该函数使用Numexpr计算所有矩阵表达式

Numexpr与矩阵

import numpy as np
import sympy

def lambdify_numexpr(args,expr,expr_name):
    from sympy.printing.lambdarepr import NumExprPrinter as Printer
    printer = Printer({'fully_qualified_modules': False, 'inline': True,'allow_unknown_functions': False})

    s=""
    s+="import numexpr as ne\n"
    s+="from numpy import *\n"
    s+="\n"

    #get arg_names
    arg_names=[]
    arg_names_str=""
    for i in range(len(args)):
        name=[ k for k,v in globals().items() if v is args[i]][0]
        arg_names_str+=name
        arg_names.append(name)

        if i< len(args)-1:
            arg_names_str+=","

    #Write header
    s+="def "+expr_name+"("+arg_names_str+"):\n"

    #unroll array
    for ii in range(len(args)):
        arg=args[ii]
        if arg.is_Matrix:
            for i in range(arg.shape[0]):
                for j in range(arg.shape[1]):
                    s+="    "+ str(arg[i,j])+" = " + arg_names[ii]+"["+str(i)+","+str(j)+"]\n"

    s+="    \n"
    #If the expr is a matrix
    if expr.is_Matrix:
        #write expressions
        for i in range(len(expr)):
            s+="    "+ "res_"+str(i)+" = ne."+printer.doprint(expr[i])+"\n"
            s+="    \n"

        res_counter=0
        #write array
        s+="    return concatenate(("
        for i in range(expr.shape[0]):
            s+="("
            for j in range(expr.shape[1]):
                s+="res_"+str(res_counter)+","
                res_counter+=1
            s+="),"
        s+="))\n"

    #If the expr is not a matrix
    else:
        s+="    "+ "return ne."+printer.doprint(expr)+"\n"
    return s
将numpy导入为np
进口交响乐
def lambdify_numexpr(参数、表达式、表达式名称):
从sympy.printing.lambdarepr导入NumExprPrinter作为打印机
打印机=打印机({'fully_qualified_modules':False,'inline':True,'allow_unknown_functions':False})
s=“”
s+=“将numexpr作为ne导入\n”
s+=“从numpy导入*\n”
s+=“\n”
#获取arg_名称
arg_name=[]
arg_names_str=“”
对于范围内的i(len(args)):
name=[k代表k,v在globals()中。如果v是args,则为items()[i][0]
arg_names_str+=名称
arg_names.append(名称)
如果i
使用numexpr的一个可能解决方案是单独计算每个矩阵表达式。下面的代码应该输出一个python函数,该函数使用Numexpr计算所有矩阵表达式

Numexpr与矩阵

import numpy as np
import sympy

def lambdify_numexpr(args,expr,expr_name):
    from sympy.printing.lambdarepr import NumExprPrinter as Printer
    printer = Printer({'fully_qualified_modules': False, 'inline': True,'allow_unknown_functions': False})

    s=""
    s+="import numexpr as ne\n"
    s+="from numpy import *\n"
    s+="\n"

    #get arg_names
    arg_names=[]
    arg_names_str=""
    for i in range(len(args)):
        name=[ k for k,v in globals().items() if v is args[i]][0]
        arg_names_str+=name
        arg_names.append(name)

        if i< len(args)-1:
            arg_names_str+=","

    #Write header
    s+="def "+expr_name+"("+arg_names_str+"):\n"

    #unroll array
    for ii in range(len(args)):
        arg=args[ii]
        if arg.is_Matrix:
            for i in range(arg.shape[0]):
                for j in range(arg.shape[1]):
                    s+="    "+ str(arg[i,j])+" = " + arg_names[ii]+"["+str(i)+","+str(j)+"]\n"

    s+="    \n"
    #If the expr is a matrix
    if expr.is_Matrix:
        #write expressions
        for i in range(len(expr)):
            s+="    "+ "res_"+str(i)+" = ne."+printer.doprint(expr[i])+"\n"
            s+="    \n"

        res_counter=0
        #write array
        s+="    return concatenate(("
        for i in range(expr.shape[0]):
            s+="("
            for j in range(expr.shape[1]):
                s+="res_"+str(res_counter)+","
                res_counter+=1
            s+="),"
        s+="))\n"

    #If the expr is not a matrix
    else:
        s+="    "+ "return ne."+printer.doprint(expr)+"\n"
    return s
将numpy导入为np
进口交响乐
def lambdify_numexpr(参数、表达式、表达式名称):
从sympy.printing.lambdarepr导入NumExprPrinter作为打印机
打印机=打印机({'fully_qualified_modules':False,'inline':True,'allow_unknown_functions':False})
s=“”
s+=“将numexpr作为ne导入\n”
s+=“从numpy导入*\n”
s+=“\n”
#获取arg_名称
arg_name=[]
arg_names_str=“”
对于范围内的i(len(args)):
name=[k代表k,v在globals()中。如果v是args,则为items()[i][0]
arg_names_str+=名称
arg_names.append(名称)
如果i
首先,可以看到Symphy导出的实际代码
inspect.getsource(f)
之后,有很多方法可以手动优化实现(Cython、Numba、Numexpr),或者也可以通过更好的矢量化策略(Numpy)进行优化。代码太长,无法在此处显示。它返回一个大小为(2,1)的数据数组。这两个条目是包含+、-、*、/、**和sqrt的长组合。我希望这能有所帮助。一个小例子(至少有相同的输入和输出)或一个完整的例子(pastebin?)会很好。使用numba或cython进行优化看起来很简单,但是可能需要一些手动编辑和一些必要的优化。s0、su、sv、suu、suv、svv、u和v是大小为383552的NDARRAY。非常感谢。这是一个正常工作的numexpr版本,包括基准测试(3700倍加速)。但是,最好添加一个具有较小MutableDenseMatrix的示例来编写关于这个问题的答案。这可能对其他人有用。我还发现了这个sympy.org/scipy-2017-codegen-tutorial,但在这个例子中,文本编辑就足够了。您的pastebin中也有代码错误(函数头位于第3118行的中间),首先,查看Symphy导出的实际代码可能是有意义的
inspect.getsource(f)
之后,有很多方法可以手动优化实现(Cython、Numba、Numexpr),或者也可以通过更好的矢量化策略(Numpy)进行优化。代码太长,无法在此处显示。它返回一个大小为(2,1)的数据数组。这两个条目是包含+、-、*、/、**和sqrt的长组合。我希望这能有所帮助。一个小例子(至少有相同的输入和输出)或一个完整的例子(pastebin?)会很好。使用numba或cython进行优化看起来非常简单,但可能需要一些手动编辑和一些优化