C/C++

2011-03-24 19 views
5

मैं एक साथ गोंद करने पायथन के लिए कुछ सी ++ कोड (2.6) बड़ा घूँट उपयोग कर रहा हूँ Numpy सरणी के लिए वेक्टर, और कहा कि गोंद का हिस्सा की फास्ट रूपांतरण कोड का एक टुकड़ा है कि डेटा (मूल्यों के लाखों लोगों की बड़ी क्षेत्रों धर्मान्तरित शामिल) सी ++ तरफ से एक गूढ़ सरणी तक। सबसे अच्छा तरीका मैं औजार के साथ वर्ग के लिए पुनरावर्तक आ सकते हैं और फिर एक अजगर तरीका प्रदान करता है:C/C++

def __array__(self, dtype=float): 
    return np.fromiter(self, dtype, self.size()) 

समस्या यह है कि प्रत्येक इटरेटर next कॉल बहुत महंगा है, क्योंकि इसके बारे में तीन या चार के माध्यम से जाना है SWIG रैपर। यह बहुत लंबा लगता है। मैं गारंटी दे सकता हूं कि सी ++ डेटा संगत रूप से संग्रहीत किया जाता है (चूंकि वे एक std :: वेक्टर में रहते हैं), और ऐसा लगता है कि Numpy उस डेटा की शुरुआत में उस पॉइंटर को उस मूल्य की संख्या के साथ लेने में सक्षम होना चाहिए, जिसमें उसके मूल्य शामिल हैं, और इसे सीधे पढ़ें।

क्या internal_data_[0] पर पॉइंटर पास करने का कोई तरीका है और internal_data_.size() मूल्य को numpy करने के लिए कोई तरीका है ताकि वह सीधे पाइथन ओवरहेड के बिना डेटा को एक्सेस या कॉपी कर सके?

उत्तर

0

तो ऐसा लगता है कि pybuffer.i से कुछ आधार बनाने का एकमात्र असली समाधान है जो C++ से मौजूदा बफर में कॉपी कर सकता है। आप एक बड़ा घूँट को यह भी जोड़ते हैं तो फ़ाइल में शामिल हैं:

%insert("python") %{ 
import numpy as np 
%} 

/*! Templated function to copy contents of a container to an allocated memory 
* buffer 
*/ 
%inline %{ 
//==== ADDED BY numpy.i 
#include <algorithm> 

template < typename Container_T > 
void copy_to_buffer(
     const Container_T& field, 
     typename Container_T::value_type* buffer, 
     typename Container_T::size_type length 
     ) 
{ 
// ValidateUserInput(length == field.size(), 
//   "Destination buffer is the wrong size"); 
    // put your own assertion here or BAD THINGS CAN HAPPEN 

    if (length == field.size()) { 
     std::copy(field.begin(), field.end(), buffer); 
    } 
} 
//==== 

%} 

%define TYPEMAP_COPY_TO_BUFFER(CLASS...) 
%typemap(in) (CLASS::value_type* buffer, CLASS::size_type length) 
(int res = 0, Py_ssize_t size_ = 0, void *buffer_ = 0) { 

    res = PyObject_AsWriteBuffer($input, &buffer_, &size_); 
    if (res < 0) { 
     PyErr_Clear(); 
     %argument_fail(res, "(CLASS::value_type*, CLASS::size_type length)", 
       $symname, $argnum); 
    } 
    $1 = ($1_ltype) buffer_; 
    $2 = ($2_ltype) (size_/sizeof($*1_type)); 
} 
%enddef 


%define ADD_NUMPY_ARRAY_INTERFACE(PYVALUE, PYCLASS, CLASS...) 

TYPEMAP_COPY_TO_BUFFER(CLASS) 

%template(_copy_to_buffer_ ## PYCLASS) copy_to_buffer<CLASS>; 

%extend CLASS { 
%insert("python") %{ 
def __array__(self): 
    """Enable access to this data as a numpy array""" 
    a = np.ndarray(shape=(len(self),), dtype=PYVALUE) 
    _copy_to_buffer_ ## PYCLASS(self, a) 
    return a 
%} 
} 

%enddef 

तो आप

%template(DumbVectorFloat) DumbVector<double>; 
ADD_NUMPY_ARRAY_INTERFACE(float, DumbVectorFloat, DumbVector<double>); 

के साथ एक कंटेनर "Numpy" सुलभ बना सकते हैं तो फिर अजगर में, बस कार्य करें:

# dvf is an instance of DumbVectorFloat 
import numpy as np 
my_numpy_array = np.asarray(dvf) 

इसमें केवल एक पायथन < -> सी ++ अनुवाद कॉल का ओवरहेड है, न कि एन जो एक सामान्य लंबाई-एन सरणी के परिणामस्वरूप होगा। इस कोड के

एक से थोड़ा अधिक पूर्ण संस्करण मेरी PyTRT project at github का हिस्सा है।

2

आप __array_interface__() instead परिभाषित करना चाहते हैं जाएगा। यह आपको सूचक और आकार की जानकारी सीधे वापस करने देगा।

+0

क्या आप व्यावहारिक कार्यान्वयन के लिए थोड़ा और विवरण प्रदान कर सकते हैं? क्या मेरे प्रोजेक्ट को नम्पी हेडर फाइलों के विरुद्ध संकलित किए बिना ऐसा करने का कोई तरीका है? धन्यवाद। –

+0

यह भी कहता है कि यह एक विरासत इंटरफ़ेस है। –

+0

'__array_interface__' इसके अंदर सादे प्रकार के साथ सिर्फ एक सादा निर्देश है। किसी भी बेवकूफ हेडर के साथ संकलन करने की कोई ज़रूरत नहीं है। उस नोट को अनदेखा करें जो इसे "विरासत" कहता है। मैंने सोचा कि मैंने पहले ही इसे हटा दिया है। यदि आप चाहें, तो आप पीईपी 3118 बफर इंटरफ़ेस को कार्यान्वित कर सकते हैं, लेकिन यह आसान है। –

0

यदि आप अपने वेक्टर को किसी ऑब्जेक्ट में लपेटते हैं जो पाइथन Buffer Interface लागू करता है, तो आप इसे प्रारंभिक के लिए numpy सरणी में पास कर सकते हैं (docs, तीसरा तर्क देखें)। मैं शर्त लगाता हूं कि यह प्रारंभिकता अधिक तेज है, क्योंकि यह डेटा की प्रतिलिपि बनाने के लिए केवल memcpy का उपयोग कर सकती है।

+0

टिप के लिए धन्यवाद।क्या आपके पास 'pybuffer_mutable_binary' या अन्य इंटरफेस का उपयोग करने के लिए '__buffer__' इंटरफ़ेस को लागू करने के लिए उदाहरण हैं, उदाहरण के लिए, फ्लोट्स? –

+0

@ सेठ: क्षमा करें, मैं आपकी मदद नहीं कर सकता। –

+0

तो ऐसा लगता है कि मुझे इस वर्ग के लिए पूरे बफर इंटरफेस को स्क्रैच से हाथ में रखना होगा। एसडब्ल्यूआईजी केवल बफर कार्यों को निर्यात नहीं करते * अन्य बफर * पढ़ने की क्षमता प्रदान करता है। –

1

शायद यह बड़ा घूँट के बजाय f2py उपयोग करने के लिए संभव हो जाएगा। इसके नाम के बावजूद, यह सी के साथ-साथ फोरट्रान के साथ अजगर को इंटरफेस करने में सक्षम है। http://www.scipy.org/Cookbook/f2py_and_NumPy

देखें लाभ यह है कि रूपांतरण स्वचालित रूप से सरणियों Numpy को संभालती है।

दो चेतावनियां: अगर आप पहले से फोरट्रान पता नहीं है, आप थोड़ा f2py मिल सकता है अजीब; और मुझे नहीं पता कि यह सी ++ के साथ कितनी अच्छी तरह से काम करता है।

+0

प्रतिक्रिया के लिए धन्यवाद। मुझे कुछ फोरट्रान पता है, लेकिन मैं अपने कोड में बहुत सी 'सी ++' -ई फीचर्स का उपयोग कर रहा हूं: टेम्पलेट्स, टाइपिफ इत्यादि। मैं एक और निर्भरता भी पेश नहीं करूंगा। –

+0

पर्याप्त पर्याप्त सी ++ उचित है। आपको शायद इंटरमीडिएट सादे सी रैपर लिखना होगा, जो दर्द हो सकता है। दूसरी ओर, यह वास्तव में एक और निर्भरता नहीं है क्योंकि f2py numpy का हिस्सा है, जिसका आप पहले से उपयोग कर रहे हैं। आपको एक फर्मन कंपाइलर की आवश्यकता नहीं होगी। – deprecated

संबंधित मुद्दे