代码之家  ›  专栏  ›  技术社区  ›  Commoner

在Cython中将复杂的numpy数组传递给C++

  •  1
  • Commoner  · 技术社区  · 6 年前

    我想把 pyx 涉及使用复数numpy数组的脚本。python脚本的相关部分如下所示:

    M = np.dot(N , Q)
    

    在我的工作中, N , Q M 是具有复数项的numpy数组。

    具体来说,我想转移矩阵 N Q 到a C++ 在中编码并执行矩阵乘法 C++ .

    虽然我知道使用指向 C++ 脚本,然后使用cython,对于如何处理具有复杂值的numpy数组,我有点困惑。

    这就是我尝试从 pyx公司 C++ 目前

    import numpy as np
    cimport numpy as np
    
    cdef extern from "./matmult.h" nogil:
        void mult(double* M, double* N, double* Q)
    
    def sim():    
        cdef:
            np.ndarray[np.complex128_t,ndim=2] N = np.zeros(( 2 , 2 ), dtype=np.float64)
            np.ndarray[np.complex128_t,ndim=2] Q = np.zeros(( 2 , 2 ), dtype=np.float64)  
            np.ndarray[np.complex128_t,ndim=2] M = np.zeros(( 2 , 2 ), dtype=np.float64)          
    
        N = np.array([[1.1 + 2j,2.2],[3.3,4.4]])
        Q = np.array([[3.3,4.4+5j],[5.5,6.6]])  
    
        mult(&M[0,0], &N[0,0], &Q[0,0])
        print M
    

    这是我的C++代码:

    #include "matmult.h"
    using namespace std;
    
    int main(){}
    
    void mult(double *M, double *N, double *Q)
    {
      double P[2][2], A[2][2], B[2][2];
    
      for (int i=0; i<2; i++)
      {
        for (int j=0; j<2; j++)
        {
          A[i][j] = *( N + ((2*i) + j) );
          B[i][j] = *( Q + ((2*i) + j) );
          P[i][j] = 0;      
        }
      }
    
      for (int i=0; i<2; i++)
      {
        for (int j=0; j<2; j++)
        {
          for (int k=0; k<2; k++)
          {
             P[i][j] += A[i][k]*B[k][i];  
          }
        }
      }  
    
      for (int i=0; i<2; i++)
      {
        for (int j=0; j<2; j++)
        {
          *( M + ((2*i) + j) ) = P[i][j];      
        }
      }
    }
    

    当我使用cython编译这个时,我得到以下错误

    mat.pyx:17:27: Cannot assign type 'double complex *' to 'double *'
    

    如果能在这里得到一些帮助,我将不胜感激。

    2 回复  |  直到 6 年前
        1
  •  1
  •   evamicur    6 年前

    此错误消息告诉您发生了什么问题:

    小地毯pyx:17:27:无法将类型“double complex*”分配给“double*”

    也就是说,您有一个来自numpy的双复数指针(指向complex128 numpy dtype的指针),您试图使用双指针将其传递到C++函数中。C++需要能够处理复数,因此如果您更改double*->复杂这应该可以解决你的问题

    void mult(double *M, double *N, double *Q)
    

    成为

    #include <complex>
    void mult(std::complex<double> *M, std::complex<double> *N, std::complex<double> *Q)
    

    numpy矩阵乘法是否不足以满足您的用例?Cython可能有点过头了。

    编辑:好的,我终于找到了一些东西,处理C++std::复杂和C double \u复杂类型有点奇怪。

    cppmul公司。pyx:

    import numpy as np
    cimport numpy as np
    
    cdef extern from "./matmult.h" nogil:
        void mult(np.complex128_t* M, np.complex128_t* N, np.complex128_t* Q)
    
    def sim():
        cdef:
            np.ndarray[np.complex128_t,ndim=2] N = np.zeros(( 2 , 2 ), dtype=np.complex128)
            np.ndarray[np.complex128_t,ndim=2] Q = np.zeros(( 2 , 2 ), dtype=np.complex128)
            np.ndarray[np.complex128_t,ndim=2] M = np.zeros(( 2 , 2 ), dtype=np.complex128)
    
        N = np.array([[1.1 + 2j,2.2],[3.3,4.4]])
        Q = np.array([[3.3,4.4+5j],[5.5,6.6]])
    
        mult(&M[0,0], &N[0,0], &Q[0,0])
        print M
    

    马特穆尔。c:

    #include "matmult.h"
    
    void mult(complex_t *M, complex_t *N, complex_t *Q)
    {
      complex_t P[2][2], A[2][2], B[2][2];
    
      for (int i=0; i<2; i++)
      {
        for (int j=0; j<2; j++)
        {
          A[i][j] = *( N + ((2*i) + j) );
          B[i][j] = *( Q + ((2*i) + j) );
          P[i][j] = 0;
        }
      }
    
      for (int i=0; i<2; i++)
      {
        for (int j=0; j<2; j++)
        {
          for (int k=0; k<2; k++)
          {
             P[i][j] += A[i][k]*B[k][i];
          }
        }
      }
    
      for (int i=0; i<2; i++)
      {
        for (int j=0; j<2; j++)
        {
          *( M + ((2*i) + j) ) = P[i][j];
        }
      }
    }
    

    马特穆特。h:

    #include <complex.h>
    
    typedef double _Complex complex_t;
    void mult(complex_t *M, complex_t *N, complex_t *Q);
    

    设置。py:

    from distutils.core import setup
    from Cython.Build import cythonize
    from distutils.extension import Extension
    import numpy as np
    
    sourcefiles = ['cppmul.pyx', 'matmult.c']
    
    extensions = [Extension("cppmul",
                            sourcefiles,
                            include_dirs=[np.get_include()],
                            extra_compile_args=['-O3']
    )]
    
    setup(
        ext_modules = cythonize(extensions)
    )
    

    运行后 python setup.py build_ext --inplace 它按预期导入和运行

    import cppmul
    cppmul.sim()
    

    结果:

    [[15.73 +6.6j 15.73 +6.6j]
     [43.56+16.5j 43.56+16.5j]]
    
        2
  •  0
  •   user5928768 user5928768    6 年前

    试试这个

        #include "matmult.h"
     using namespace std;
    
    int main(){}
    
    void mult(double *M, double *N, double *Q)
    {
     double P[2][2], A[2][2], B[2][2];
    
     for (int i=0; i<2; i++)
     {
    for (int j=0; j<2; j++)
    {
      A[i][j] = *( N + ((2*i) + j) );
      B[i][j] = *( Q + ((2*i) + j) );
      P[i][j] = 0;      
      }
      }
    
      for (int i=0; i<2; i++)
      {
        for (int j=0; j<2; j++)
        {
        for (int k=0; k<2; k++)
        {
           P[i][j] += A[i][k]*B[k][i];  
         }
     }
    }  
    
    for (int i=0; i<2; i++)
     {
      for (int j=0; j<2; j++)
      {
      *(  ((2*i) + j) )+ M = P[i][j];      
      }
     }
    }
    
    推荐文章