2012-02-14 8 views
75

SWIG에서 아름답게 작동하는 작은 프로젝트가 있습니다. 특히, 일부 함수는 std::vector을 반환하는데, 이것은 파이썬의 튜플로 변환됩니다. 자, 나는 많은 수치를 처리하기 때문에, SWIG가 이들을 C++ 코드에서 반환 된 후에 numpy 배열로 변환합니다. 이를 위해 SWIG에서 다음과 같은 것을 사용합니다.SWIG의 새로운 내장 기능과 함께 pythonappend를 사용할 수있는 방법이 있습니까?

%feature("pythonappend") My::Cool::Namespace::Data() const %{ if isinstance(val, tuple) : val = numpy.array(val) %} 

는 (사실, 난 val 실제로 튜플 있는지 확인 이유입니다, 수레를 돌려 일부 데이터라는 이름의 몇 가지 기능이 있습니다.) 이건 그냥 아름답게 작동합니다.

그러나 현재 사용할 수있는 -builtin 플래그도 사용하고 싶습니다. 이러한 데이터 함수에 대한 호출은 거의없고 대화식이기 때문에 느려짐이 문제는 아니지만 내장 옵션을 사용하여 속도가 크게 느린 다른 느린 루프가 있습니다.

문제는 그 플래그를 사용하면 pythonappend 기능이 자동으로 무시된다는 것입니다. 이제, 데이터는 튜플을 다시 반환합니다. 여전히 numpy 배열을 반환 할 수있는 방법이 있습니까? 나는 typemaps를 사용하여 시도했지만 거대한 엉망으로 바뀌었다.

편집 :

보레 올리 드는 질문에 매우 만족했습니다. 완전성을 위해 const 참조로 돌아 왔고 벡터 벡터 (시작하지 마라!)를 사용하기 때문에 필요한 몇 가지 미묘한 다른 typemaps를 포함합니다. 이것들은 다른 사람들이 사소한 차이점을 찾아 내려고 노력하는 것을 원하지 않기에 충분히 다릅니다.

%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 :

나는 비슷한 문제가 스님의 접근 방식 (explained here) @ 사용하여 해결 될 수 찾고 있었다 꽤 무엇을 비록.

+4

필자는 typemap을 작성하지 않고 C 측에서이 작업을 수행 할 수 없다고 생각합니다. -builtin이 pythonappend가 정상적으로 배치 된 코드를 제거하기 때문입니다. 빌더 인이 훨씬 빠릅니다 (즉 프로파일 링으로 사용하게 만들었습니까?) 저는 두 개의 모듈을 사용하고 하나는 -builtin을 사용하지 않으려 고합니다. – Flexo

+0

'-builtin'이 pythonappend를 무시한다는 경고는 없습니다. numpy 배열에'std :: vector'를 typing하는 것에 대한 도전이 아닙니다. 나는 프로필을 작성했으며, 인터페이스에서 가장 귀찮은 루프를 상당히 빠르게 시작했습니다 (휴식을 취하기에는 너무 길지 않고 자주 기다리기에는 너무 길었습니다). 그러나 나는 또한이 루프를 내 C++ 코드로 옮길 수 있음을 깨달았다. 다소 어색하지만. 그래서 그것이 내가 갈 방법입니다. 그럼에도 불구하고 '두 모듈'제안은 흥미롭고 다른 경우 유용 할 수 있습니다. – Mike

+0

SWIG를 -Wall과 통화 했습니까? 나는 그것이 그 경우에 경고 할 것이라고 생각했다. – Flexo

답변

6

나는 typemap을 사용하는 것이 약간 지저분하지만,이 작업을 수행하는 올바른 방법이라고 동의합니다. 또한 SWIG 문서가 과 호환되지 않는다고 직접적으로 말하지는 않겠지 만 그것은 매우 암시됩니다. %pythonappend은 Python 프록시 클래스에 추가되며 Python 프록시 클래스는 -builtin과 함께 전혀 존재하지 않습니다 깃발.

이전에 SWIG가 C++ std::vector 개체를 파이썬 튜플로 변환 한 다음 해당 튜플을 numpy으로 다시 전달하여 다시 변환했습니다.

정말로 원하는 것은 C 수준에서 한 번 변환하는 것입니다.

%{ 
#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와 정수 배열로 모든 std::vector<int> 객체를 설정하는 몇 가지 코드입니다.위해서는 :

  • 은 파이썬 모듈이로드 될 때
  • 원인 import_array 어떤
  • 지도 (그렇지 않으면 모든 NumPy와 방법이 세그 폴트 것)를 호출 할 NumPy와의 arrayobject.h 파일은 C++ 출력 파일에 포함되어 보장 typemap

와 NumPy와 배열에 std::vector<int>의 수익률이 코드는 헤더 ㅁ 당신에게 전에 %import을 배치해야 함수는 std::vector<int>을 반환합니다. 그 제한 이외에, 그것은 완전히 자체 포함되어 있으므로 코드베이스에 너무 많은 주관적인 "엉망"을 추가해서는 안됩니다.

다른 벡터 유형이 필요하면 NPY_INT 및 모든 int*int 비트를 변경하거나 위 기능을 복제하면됩니다.

+0

최고! 나는 당신이 typemap을 가지고있는 모든 요소들을 가지고 있었지만, 나는 그것들을 적절히 조합하지 못했습니다. 아직 공식적으로이 프로젝트를 진행하지는 않지만 간단한 모듈을 작성하여 철저한 테스트를 수행했습니다. 매우 감사합니다! – Mike

관련 문제