SWIG의 새로운 내장 기능과 함께 pythonappend를 사용하는 방법이 있습니까?
SWIG와 아름답게 작동하는 작은 프로젝트가 있습니다. 특히 내 함수 중 일부는 std::vector
s를 반환 하는데, 이는 Python에서 튜플로 변환됩니다. 이제 저는 많은 숫자를 수행하므로 C ++ 코드에서 반환 된 후 SWIG가이를 numpy 배열로 변환하도록합니다. 이를 위해 SWIG에서 다음과 같은 것을 사용합니다.
%feature("pythonappend") My::Cool::Namespace::Data() const %{ if isinstance(val, tuple) : val = numpy.array(val) %}
(사실, Data라는 이름의 함수가 여러 개 있는데, 그중 일부는 float를 반환하기 때문에 val
실제로 튜플 인지 확인합니다 .) 이것은 아름답게 작동합니다.
하지만 -builtin
현재 사용 가능한 플래그 도 사용하고 싶습니다 . 이러한 데이터 함수에 대한 호출은 드물고 대부분 대화 형이므로 느림은 문제가되지 않지만 내장 옵션을 사용하면 속도가 크게 빨라지는 다른 느린 루프가 있습니다.
문제는 해당 플래그를 사용할 때 pythonappend 기능이 자동으로 무시된다는 것입니다. 이제 데이터는 튜플을 다시 반환합니다. 여전히 numpy 배열을 반환 할 수있는 방법이 있습니까? 나는 typemap을 사용해 보았지만 그것은 거대한 혼란으로 바뀌었다.
편집하다:
Borealid는 질문에 매우 훌륭하게 대답했습니다. 완전성을 위해 저는 const 참조로 반환하고 벡터의 벡터를 사용하기 때문에 필요한 몇 가지 관련되지만 미묘하게 다른 typemap을 포함합니다 (시작하지 마세요!). 이것들은 다른 사람이 사소한 차이점을 알아 내려고 애쓰는 것을 원하지 않을 정도로 충분히 다릅니다.
%typemap(out) std::vector<int>& {
npy_intp result_size = $1->size();
npy_intp dims[1] = { result_size };
PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_INT);
int* dat = (int*) PyArray_DATA(npy_arr);
for (size_t i = 0; i < result_size; ++i) { dat[i] = (*$1)[i]; }
$result = PyArray_Return(npy_arr);
}
%typemap(out) std::vector<std::vector<int> >& {
npy_intp result_size = $1->size();
npy_intp result_size2 = (result_size>0 ? (*$1)[0].size() : 0);
npy_intp dims[2] = { result_size, result_size2 };
PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(2, dims, NPY_INT);
int* dat = (int*) PyArray_DATA(npy_arr);
for (size_t i = 0; i < result_size; ++i) { for (size_t j = 0; j < result_size2; ++j) { dat[i*result_size2+j] = (*$1)[i][j]; } }
$result = PyArray_Return(npy_arr);
}
편집 2 :
내가 찾던 내용은 아니지만 @MONK의 접근 방식을 사용하여 유사한 문제를 해결할 수도 있습니다 ( 여기에서 설명 ).
사용 typemap
하는 것이 약간 지저분 하다는 데 동의 하지만이 작업을 수행하는 올바른 방법입니다. 또한 SWIG 문서가과 %pythonappend
호환 되지 않는다고 직접 말하지 는 -builtin
않지만 강력하게 암시 %pythonappend
되어 있습니다. Python 프록시 클래스에 추가 하고 Python 프록시 클래스가 -builtin
플래그 와 함께 전혀 존재하지 않습니다 .
이전에는 SWIG에서 C ++ std::vector
객체를 Python 튜플으로 변환 한 다음 해당 튜플을 다시 numpy
변환 된 위치로 다시 전달했습니다.
정말로 원하는 것은 C 레벨에서 한 번 변환하는 것입니다.
다음은 모든 std::vector<int>
객체를 NumPy 정수 배열로 바꾸는 코드입니다 .
%{
#include "numpy/arrayobject.h"
%}
%init %{
import_array();
%}
%typemap(out) std::vector<int> {
npy_intp result_size = $1.size();
npy_intp dims[1] = { result_size };
PyArrayObject* npy_arr = (PyArrayObject*)PyArray_SimpleNew(1, dims, NPY_INT);
int* dat = (int*) PyArray_DATA(npy_arr);
for (size_t i = 0; i < result_size; ++i) {
dat[i] = $1[i];
}
$result = PyArray_Return(npy_arr);
}
이것은 C 수준의 numpy 함수를 사용하여 배열을 구성하고 반환합니다. 순서대로 :
- NumPy의
arrayobject.h
파일이 C ++ 출력 파일에 포함되도록합니다. - 원인
import_array
파이썬 모듈이로드 될 때 호출 할 (그렇지 않으면 모든 NumPy와 방법은 세그 폴트합니다) - 모든 반환
std::vector<int>
을 NumPy 배열에 매핑합니다.typemap
이 코드는 배치해야 하기 전에 당신이 %import
반환하는 기능을 포함하는 헤더를 std::vector<int>
. 그 제한 외에는 완전히 독립적이므로 코드베이스에 너무 많은 주관적인 "메쉬"를 추가해서는 안됩니다.
If you need other vector types, you can just change the NPY_INT
and all the int*
and int
bits, otherwise duplicating the function above.
'code' 카테고리의 다른 글
Code Golf : Excel 열 이름에 해당하는 숫자 (0) | 2020.10.15 |
---|---|
dequeueBuffer : 버퍼 수를 설정하지 않고 여러 버퍼를 대기열에서 빼낼 수 없습니다. (0) | 2020.10.15 |
"효과보다 더 강력한 모나드 트랜스포머"-예? (0) | 2020.10.15 |
SRC, OBJ 및 BIN 하위 디렉토리가있는 C 프로젝트 용 Makefile을 어떻게 만들 수 있습니까? (0) | 2020.10.15 |
Mavericks로 느린 IOS 시뮬레이터 (0) | 2020.10.15 |