Tôi có một dự án nhỏ hoạt động tốt với SWIG. Cụ thể, một số chức năng của tôi trả về std::vector
s, được dịch thành các bộ dữ liệu bằng Python. Bây giờ, tôi làm rất nhiều số, vì vậy tôi chỉ có SWIG chuyển đổi chúng thành các mảng numpy sau khi chúng được trả về từ mã C++. Để làm điều này, tôi sử dụng một cái gì đó như sau trong SWIG.Có cách nào để sử dụng pythonappend với tính năng nội trang mới của SWIG không?
%feature("pythonappend") My::Cool::Namespace::Data() const %{ if isinstance(val, tuple) : val = numpy.array(val) %}
(Trên thực tế, có một số chức năng có tên Data, một số trong đó trở nổi, đó là lý do tôi kiểm tra xem val
thực sự là một tuple). Điều này hoạt động giống đẹp.
Nhưng, tôi cũng muốn sử dụng cờ -builtin
hiện có sẵn. Các cuộc gọi đến các chức năng Dữ liệu này rất hiếm và chủ yếu là tương tác, do đó sự chậm chạp của chúng không phải là vấn đề, nhưng có các vòng chậm khác tăng tốc đáng kể với tùy chọn dựng sẵn.
Vấn đề là khi tôi sử dụng cờ đó, tính năng pythonappend sẽ bị bỏ qua. Bây giờ, dữ liệu chỉ trả về một tuple một lần nữa. Có cách nào tôi vẫn có thể trở lại mảng numpy? Tôi đã thử sử dụng các bản đồ, nhưng nó biến thành một mớ hỗn độn khổng lồ.
Chỉnh sửa:
Borealid đã trả lời câu hỏi rất độc đáo. Chỉ cần cho đầy đủ, tôi bao gồm một vài bản đồ có liên quan nhưng tinh tế khác nhau mà tôi cần bởi vì tôi trở lại bằng tham chiếu const và tôi sử dụng vectơ của vectơ (không bắt đầu!). Đây là đủ khác nhau mà tôi sẽ không muốn bất cứ ai khác stumbling xung quanh cố gắng tìm ra sự khác biệt nhỏ.
%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);
}
Sửa 2:
Mặc dù không hoàn toàn những gì tôi đang tìm kiếm, các vấn đề tương tự cũng có thể được giải quyết bằng phương pháp @ Monk (explained here).
Tôi không nghĩ rằng bạn có thể làm điều này mà không cần viết một typemap và làm nó ở phía C, chính xác vì -builtin loại bỏ mã nơi pythonappend bình thường được đặt. Bạn có chắc chắn -builtin là nhanh hơn nhiều (tức là đã profiling dẫn bạn sử dụng nó?) Tôi muốn bị cám dỗ để sử dụng hai mô-đun, một với và một mà không -builtin. – Flexo
Tôi ngạc nhiên không có cảnh báo rằng '-builtin' bỏ qua pythonappend. Tôi không phải là thách thức của việc đánh máy 'std :: vector' vào mảng numpy. Tôi đã làm hồ sơ, và nó đáng kể tăng tốc vòng lặp gây phiền nhiễu nhất trong giao diện của tôi (không đủ dài để nghỉ ngơi, quá lâu để chờ đợi thường xuyên). Nhưng tôi cũng nhận ra rằng tôi có thể di chuyển vòng lặp này vào mã C++ của tôi - mặc dù hơi lúng túng. Vì vậy, đó là cách tôi sẽ đi. Tuy nhiên, đề xuất 'hai mô-đun' của bạn thú vị và có thể hữu ích trong các trường hợp khác. – Mike
Bạn có gọi SWIG bằng -Wall không? Tôi cho rằng nó sẽ cảnh báo trong trường hợp đó. – Flexo