NyPy数组与特征C++库的矩阵/数组类之间的Cython接口

rmjarvis.eigenc的Python项目详细描述


[![构建状态](https://travis-ci.org/wouterboomsma/eigency.svg?branch=master)(https://travis ci.org/wouterboomsma/eigncy)


它旨在简化使用特征库编写c++扩展的
过程。特征是
设计用于在来回传递
数据时重用阵列的底层存储,因此将尽可能避免生成不必要的拷贝
。只有在C++代码显式请求拷贝的情况下,才会生成拷贝。

安装程序和这些不同用例的完整工作
示例可在此软件包附带的
`test`目录中找到。


setup
若要导入特征值功能,请将以下内容添加到`.pyx`文件中:
`````
from eigncy.core cimport*
```
此外,在"setup.py"文件中,include directories必须设置为包含特征包含。这可以通过调用'eigncy'模块中的'get-includes'函数来实现:
```
import-eigncy

extensions=[
extension("module dir name/module name",["module dir name/module name.pyx"],
include-dirs=[","module dir name"]+eigncy.get-includes()
]
````
eigency包含特征库的一个版本,而"get includes"函数将包含指向此目录的路径。如果您有自己版本的eign,只需将"include_eign"选项设置为false,然后添加自己的路径:

```
include_dirs=[","module dir name","path to own eign"]+eigncy.get_include(include_eign=false)
```

++函数:

``c++
void function_w_mat_arg(const eigen::map<;eigen::matrixd>&;mat){
std::cout<;<;mat<;"\n";
}
```

注意,我们使用"eigen::map"来确保可以重用numpy数组的存储空间,从而避免生成副本。假设c++代码
位于名为"functions.h"的文件中,则对应的`.pyx`条目可能如下:

```
c def extern from"functions.h":
c def void `>cdef extern from"function _w_mat_mat_mat_mat arg"函数(map[matrixxd]&;)

;这将暴露给python
def函数_mat arg(np.ndarrarray数组)函数
return六unction_w_u mat_u arg(map[matrixxd](array))
````


最后一行包含实际的转换。` map`是一个特征
类型,它派生自真实的特征映射,并负责
从numpy数组到相应特征类型的转换。



>我们现在可以直接从python直接调用c++函数:
``python
>gt>gt;import numpy as np
>gt;import特征值测试
>gt;x=np.数组([[1.1,2.2,[3.3,4.4]])
>gt>gt>gt;x=np.数组([[1.1,2.1,2.2.2,[3.4]])
>1.1 3.3.3
>2.2 4.2 4.2 4.2 4.4.4.2;x
>1.1.1 3.3.3.3.3
>2.2 4.2 4
```
(如果您想知道矩阵为什么是反式的摆姿势,请参见下面的存储布局部分)。这意味着在这个过程中,
我们需要明确我们要处理的数值类型。在上面的
函数中,我们指定需要一个特征矩阵,这意味着
numpy数组还必须包含两个(即float64)值。如果我们提供
一个整数的numpy数组,就会得到奇怪的结果。

`` python
>;>import numpy as np
>;>import eigncy_tests
>;>x=np.array([[1,2],[3,4]])
>;>eigncy_tests.function_w_mat_arg(x)
4.94066e-324 1.4822e-323
9.88131e-324 1.97626E-323
'BR/>这是因为我们明确地要求C++解释Python整数Br/>值作为浮点。

为了避免此类错误,您可以强制cython函数只接受特定类型的numpy数组:

````
cdef extern from"functions.h":
r/>def function__mat_arg(np.ndarray[np.float64_t,ndim=2]数组):
返回函数_w_mat_arg(map[matrixd](array))
`````

(注意,使用此技术选择类型时,还需要指定数组的维数(默认为1))。使用此新定义,当传递错误类型的数组时,

``python
>;>import numpy as np
>;>import eigncy_tests
>;>x=np.array([[1,2],[3,4]])
>;>eigncy_tests.function_w_mat_arg(x)
traceback(最近一次调用的最后一次):
文件"<;stdin>;",第1行,in<;module>;
文件"eigncy_tests/eigncy_tests.pyx",第87行,在eigncy_tests.eigncy_tests.function_w_mat_arg
值错误:缓冲区数据类型不匹配,预期为"float64_t",但得到"long"
````

令人惊讶的是,强烈建议在任何可能的情况下使用此技术
在cython代码中指定numpy数组的完整类型。




九[双,2,2]`。在大多数情况下,您不需要这样做,因为您只需使用特征值便利typedef,例如'map[vectorxd]`。如果需要完整规范的额外灵活性,可以使用"FlattedMap"类型,其中所有类型参数都可以在顶层指定,例如"FlattedMap[Matrix,Double,[U 2,[U 3]"或"FlattedMap[Matrix,Double,[U 2,DYNAMIC]"。注意,维度必须以下划线作为前缀。

动态]&;)

键入,
行和列。eigen支持其他一些模板参数,用于设置存储布局和映射跨步。由于cython不支持融合类型的默认模板参数,因此我们为此定义了单独的类型。它们分别被称为
"flattedMapWithOrder"和"flattedMapWithStride",其中有5个和8个
模板参数。有关其使用的详细信息,请参阅下面关于存储布局的部分。
BR/>从NUMPY到EGIN(坚持复制)
BR/> EIGITIONS将不会抱怨,如果您与C++接口的函数不使用特征映射对象,而是一个规则的特征矩阵或
数组。但是,在这种情况下,将制作一份副本。实际上,
过程与上述完全相同。在'.Pyx'文件中,您仍然
定义了与上面描述的地图完全相同的方法。例如,BR/> BR/>例如,给定以下C++函数:
‘C++BR/>无效函数WWVECARGARGNONOZMAP(const EGEN:VECRTRESD和VEC);
'BR/> BR/> Cython定义仍然是L。如下所示:

````
cdef extern from"functions.h":
cdef void ```
cdef void `>cdef void _-vec-argu-no-map"function _-vec-argu-no-map"(map[vectorxd]&;)

;这将暴露于python
def function _-vec-avc-argu-no-map(np.ndarray[np.float64-t]array数组数组)中:
br/>>返回函数_arg_no_映射(映射[vectorxd](数组))
``

声明中的参数类型(映射类型)与`.h'文件中的实际参数类型不同,只要其中一个可以分配给另一个。由于映射对象可以
分配给它们相应的矩阵/数组类型,因此这一工作
非常简单。但是记住,这个任务将复制一个
基础数据的拷贝。
BR/>对NUBY
BR/C++函数返回一个本征矩阵/数组的引用也可以将BR/>转移到NUPY数组,而不复制它们的内容。假设
我们有一个具有单个吸引子函数的类,它返回一个特征Br/>矩阵成员:
'C++BR/>类Myclass {BR/> MyClice():
矩阵(Eig::Matrix x3::常量(3)){{BR/> } BR/>特征::Matrix XXD和GETyMatrix(){Br/>返回这个-gt;矩阵;
}:BR/>本征::Matrix x3D矩阵;
};
'BR/> BR/>接口:通常指定:Cython C++类接口:
'BR/> CDEF CppCysMyCype MyCype:
MyCype"MyCype"(),除+
MyRIX3D和GETX Matrix()
'BR/> BR/>d对应的python包装器:

`` python
cdef class myclass:
cdef myclass*thisptr;

def cinit(self):
self.thisptr=new myclass()

def dealloc(self):
del self.thisptr

def get矩阵(self):
返回ndarray(self.thisptr.get_matrix())
```


最后一行包含实际的转换。同样,eigncy也有它自己的"ndarray"版本,它将负责
您的转换。


由于cython中的限制,eigncy不能处理完整的
矩阵/数组模板规范作为返回类型
(例如,"matrix[double,4,2]`)。但是,作为一种解决方法,在这种情况下(或者在所有情况下,如果您愿意的话)可以使用
`plainobjectbase`作为返回类型:

````
`plainobjectbase&;get撸matrix()
````

o根据返回类型,猜测您想要的是副本
还是视图。大多数时候,这可能是你想要的。但是,在某些情况下,您可能希望
覆盖此行为。例如,返回const
引用的函数将导致数组的副本,因为const
不能在python中强制执行。但是,您可以通过使用"NDARRAYORION"或"NDARRAYY VIEW"BR/>函数来重写
默认行为。
BR/>从以前扩展"MyClass"实例:
BR/> 'C++BR/>类Myclass {BR/> Pube:
…BR/> const EGEN::MatRXXD和GETYOXCONTYM MatRIX():{BR/>返回这个-g/t;

},
'BR/> BR/>对应的Cython接口规范BR/>通常指定Cython C++类接口:
BR/> 'BD/CCDF CppClasyMyClasyMyClase:MyClase:Br/>…_ matrix()
```

下面将返回一个副本

``python
cdef class myclass:

def get_const_matrix(self):
返回ndarray(self.thisptr.get_const_matrix())
```


cdef类myclass:

def get_const_matrix(self):
返回ndarray视图(self.thisptr.get_const_matrix())
````

哎呀。例如,给出以下C++函数:
'C++BR/>特征::MyRX3D函数,WyMataReTalvar(;
'BR/>< BR/> 'BR/> CDEF,从"函数H"中删去:
CDEF MaMatx3D函数,WyMatxReVALL函数"WyMatthReVALVE"()
BR/>S将是暴露于python
def function_w_mat_retval():
return ndarray_copy(_function_w_mat_retval())
```

没有关联的便利类型def。

请注意,我们使用"ndarray\u copy"而不是"ndarray"来显式地声明应创建副本。在C++ 11兼容编译器中,它
将检测RValk引用并自动复制,即使
您只使用"NDRAY"(见下一节),但为了确保其工作
也使用旧编译器,建议在返回新构造的EI时总是使用
'NDARRAYRAICOMIN ]。gen值。



例如,
从上一节中的"函数xWATMATRIVALVE"中,将从C++返回一个临时的
值,并且我们必须注意将该数据复制为
,而不是使所得的NUMPY数组
直接指向该内存。在C++ 11中,这种情况可以使用rValk引用直接检测到
,因此它将自动生成一个拷贝:
`BR/> DEF函数WYMATH-RATALVE():
这是在C++ 11中工作的,因为它检测到rValueBr.BR/>返回NDARRY(函数x WyMataReTalk())
```

但是,为了确保它与旧的编译器一起工作,建议使用"ndarray_copy"转换:

````
def function_w_mat_retval():
/>

numpy默认使用
行主布局(c样式),而eigen默认使用
列主布局(fortran样式)。在适当的情况下,我们优先考虑
尽可能避免复制数据,在某些情况下可能会有意想不到的
后果:当将值从B++传递到Python时,没有问题。我们只需调整返回的
NUMPY数组的存储布局,以匹配EGIN。但是,由于存储布局
被编码成特征数组的类型(或
映射类型),所以不能自动将Python中的布局更改为C++方向。因此,在
特征值中,我们选择在这种情况下返回转置数组/矩阵
。这为用户提供了在Python(使用BooSt=="f"时构建Br/>您的NUMPY数组)或在C++方面的灵活性:(1)显式定义您的
参数以具有行主存储布局,2)手动设置MAP
步幅,或3)只需调用"t"。transpose()`在接收的
数组/矩阵上)。< BR> > BR/>作为一个例子,考虑一个C++函数的例子,它既接收
并返回一个特征映射类型,从而充当过滤器:
'C++
本征::图AXXD和Gt;函数过滤器(EGIN:MAP& LT;ArayXXD和G.&Mat){BR/>返回垫;
` BR/> BR/> T。cython代码可以是:

```
cdef extern from"functions.h":

cdef map[arrayxd]&u function\u filter1"function\u filter1"(map[arrayxd]&;)

def function\u filter1(np.ndarray[np.float64,ndim=2]array):
return ndarray(\u function\u filter1(map[arrayx[BR/> BR/>‘BR/> BR/>如果我们以标准的方式从Python调用这个函数,我们将BR/>看到数组从Python到C++的方式被转置,并且
当它再次返回到Python时仍然是这样的:
Byth> Br/> & Gt;& gt;x=NP.数组([1,2,3,4),[5、6、7、8.]])
>;>y=功能过滤器1(x)
>;>print x
[[1.2。三. 4.]
[5.6。7。8.]]
>;>>打印y
[[1.5.]
[2.6.]
[3.7.]
[4.8.]]
```

避免这种情况的最简单方法是告诉numpy使用
列主数组布局,而不是默认的行主数组布局。这可以使用order='f'选项来完成:

`` python
>;>x=np.数组([[1,2,3,4.],[5,6,7,8.]],order='f')
>;>y=function\u filter1(x)
>;>print x
[[1]。2。三。4.]
[5.6。7。8.]]
>;>>打印y
[[1.2。三。4.]
[5.6。7。8.]]
```

这个< BR/>需要改变C++函数定义:< BR/> 'C++< BR/> typedef Eigen::map & lt;双:特征::动态,特征::RealMeave&Gt;RowMajorArrayMap;
RoMaMrRayaRaymap and ActudioField2(RoMaMrRayalaymap and Mat){Br/>返回垫;< BR/> }
```

要编写相应的cython定义,我们需要扩展版的
`flattedmap`称为'flattedmapwithorder`,它允许我们指定
存储顺序:

```
cdef extern from"functions.h":

lter2"函数过滤器2"(flattedMapWithOrder[array,double,dynamic,dynamic,rowMajor])

def函数过滤器2(np.ndarray[np.float64,ndim=2]数组):
返回ndarray(函数过滤器2(flattedMapWithOrder[array,double,dynamic,rowMajor],array))
````

她的替代方法是保持数组本身以RoWiar格式,
但使用不同的步幅值用于地图类型:
BR/> 'C++BR/> typedef Eigen::地图,ArrayXXd:,EGEN::不对齐,特征::步幅和lt;1:特征::动态& gt;CustomStrideMap。er3(customstreammap&;);
```

3"函数过滤器3"(FlattedMapWithStride[Array,Double,dynamic,dynamic,colMajor,unaligned,[u 1,dynamic])

Def函数过滤器3(np.ndarray[np.float64_t,ndim=2]数组):
返回ndarray(\u函数过滤器3(FlattedMapWithStride[Array,Double,dynamic,dynamic,colMajor,unaligned,u 1,dynamic(array))
```


在这三种情况下,返回的数组现在的形状都与原始数组相同。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
ByteArrayOutputStream的java解码属性   java S3 SDK在上载时更新单个对象,而不是创建新文件   java hibernate:无法从eclipse连接到DB   java如何在强制转换JComboBox之前检查其类型?   http从Java中的GETPOST请求方法捕获URI、资源名称,如开发人员工具中所示   java在Spring@Bean方法中返回接口的局限性   Java中的Web服务和客户端(使用Eclipse Apache Axis 2自底向上服务)某些代码会引发异常   java spring安全+rest不起作用   java将LinkedList添加到包含LinkedList的LinkedList并更改添加的LinkedList   java是否临时删除对象的属性?   java使用AnimatedGifEncoder类创建的gif图像的部分帧是不透明的   java如何高效地处理maven3时间戳快照?   java向集合对象添加另一项   java如何将动态参数传递给jquery函数   java使用libGdx桌面端口作为Android GLES20的仿真器