2009-11-14 16 views
5

मैं सी ++ ublas लाइब्रेरी का उपयोग करके एक मैटलैब एक्सटेंशन लिख रहा हूं, और मैं मैटलैब इंटरपेटर द्वारा पारित सी सरणी से अपने यूब्ला वैक्टर को प्रारंभ करने में सक्षम होना चाहता हूं। मैं स्पष्ट रूप से डेटा की प्रतिलिपि बनाकर (दक्षता के लिए) बिना सी सरणी से ublas वेक्टर प्रारंभ कैसे कर सकता हूं। मैं कोड की निम्न पंक्तियों के साथ कुछ के लिए देख रहा हूँ:एक सी सरणी से एक ublas वेक्टर शुरू करना

using namespace boost::numeric::ublas; 

int pv[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; 
vector<int> v (pv); 

सामान्य तौर पर, यह एक सरणी से एक सी ++ std::vector प्रारंभ करने में हो सकता है? कुछ ऐसा:

#include <iostream> 
#include <vector> 
using namespace std; 

int main() 
{ 
    int pv[4] = { 4, 4, 4, 4}; 
    vector<int> v (pv, pv+4); 

    pv[0] = 0; 
    cout << "v[0]=" << v[0] << " " << "pv[0]=" << pv[0] << endl; 

    return 0; 
} 

लेकिन जहां प्रारंभिक डेटा की प्रतिलिपि नहीं करेगा। इस मामले में उत्पादन

v[0]=4 pv[0]=0 

है, लेकिन मैं उत्पादन ही, सी सरणी को अद्यतन करने में परिवर्तन जहां डाटा सी ++ वेक्टर द्वारा की ओर इशारा होना चाहता हूँ

v[0]=0 pv[0]=0 

उत्तर

6

दोनों std::vector और ublas::vector कंटेनर हैं। कंटेनरों का पूरा बिंदु उनकी निहित वस्तुओं के भंडारण और जीवनकाल का प्रबंधन करना है। यही कारण है कि जब आप उन्हें प्रारंभ करते हैं तो उन्हें मूल्यों को उस भंडारण में प्रतिलिपि बनाना चाहिए जो उनके पास है।

सी एरे आकार और स्थान में तय स्मृति के क्षेत्र हैं, इसलिए उनकी प्रकृति से आप केवल प्रतिलिपि बनाकर अपने मूल्य एक कंटेनर में प्राप्त कर सकते हैं।

आप सी एरे का उपयोग कई एल्गोरिदम कार्यों में इनपुट के रूप में कर सकते हैं ताकि शायद आप प्रारंभिक प्रति से बचने के लिए ऐसा कर सकें?

+2

इसके अलावा * सिद्धांत में * आप ublas :: वेक्टर का उप-वर्ग बना सकते हैं जिसने ऐसा किया। आपका सबक्लास एक कॉन्स ublas :: वेक्टर के रूप में व्यवहार कर सकता है जिसे कभी भी आकार में नहीं बदला जा सकता है, या आपको यह सुनिश्चित करने के लिए कंटेनर का आकार बदलने में शामिल सभी विधियों को ओवरराइड करना होगा कि स्मृति को मुक्त न करें जो इसके अंतर्गत नहीं है । केवल एक पूर्ण मासोचिस्ट इसका प्रयास करेगा। –

0

मुझे नहीं लगता कि सी ++ सी की तरह सम्मेलन की अनुमति देता है।

+1

बेशक यह करता है। पॉइंटर्स इटेटरेटर्स का एक विशिष्ट मामला है (एक पॉइंटर दिया गया है जिसे आप * के साथ सम्मानित कर सकते हैं और आप ++ के साथ अगला आइटम प्राप्त कर सकते हैं। आपको केवल std :: vector को प्रारंभ करने की आवश्यकता है)। –

4

आप एक सी सरणी आसानी से एक std :: वेक्टर प्रारंभ कर सकते हैं:

vector<int> v(pv, pv+10); 
+0

आपके उत्तर के लिए धन्यवाद, लेकिन यह डेटा कॉपी करेगा। मैं डेटा के उसी ब्लॉक को इंगित करने के लिए 'v' और' pv' चाहता हूं। – dzhelil

+1

आपके पास यह नहीं हो सकता है। std :: वेक्टर हमेशा इसकी याददाश्त का मालिक है। हालांकि आप अपना खुद का वेक्टर क्लास लिख सकते हैं ... – shoosh

9

मुझे यकीन नहीं है कि आपका प्रश्न MATLAB/MEX से कैसे संबंधित है, लेकिन एक साइड नोट, आप शायद यह जानना चाहें कि MATLAB प्रतिलिपि रणनीति लागू करता है।

इसका मतलब है कि जब आप उदाहरण के लिए एक सरणी की प्रतिलिपि बनाते हैं, तो केवल कुछ शीर्षलेखों की प्रतिलिपि बनाई जाती है, जबकि डेटा को दो सरणी के बीच साझा किया जाता है। और उनमें से एक बार संशोधित हो जाने पर, डेटा की एक प्रति वास्तव में बनाई जाती है।

निम्नलिखित क्या हुड (इस old post से उधार) के तहत हो रहा हो सकता है की एक simluation है:

----------------------------------------- 
>> a = [35.7 100.2 1.2e7]; 

mxArray a 
    pdata -----> 35.7 100.2 1.2e7 
    crosslink=0 

----------------------------------------- 
>> b = a; 

mxArray a 
    pdata -----> 35.7 100.2 1.2e7 
    crosslink /\ 
    |/\  | 
    | |  | 
    | |  | 
    \/|  | 
    crosslink  | 
mxArray b  | 
    pdata -------- 

----------------------------------------- 
>> a(1) = 1; 

mxArray a 
    pdata -----> (1) 100.2 1.2e7 
    crosslink=0 


    crosslink=0 
mxArray b 
    pdata ------> 35.7 100.2 1.2e7 ... 

मैं जानता हूँ कि यह वास्तव में आपके प्रश्न का उत्तर नहीं है, मैं तो बस आप अवधारणा मिल सकती है सोचा उपयोगी।

+11

आप इस मेटा-डेटा को MATLAB कमांड विंडो सेटिंग प्रारूप में 'प्रारूप डीबग' – Mikhail

+0

कूल चाल के साथ देख सकते हैं, – Amro

+0

साझा करने के लिए धन्यवाद आपके आरेख के बारे में एक मामूली बिंदु - आप इसे विचार के रूप में देखते हैं MATLAB डेटा की एक नई प्रति बनाता है, इसे इंगित करने के लिए 'b' को पुन: असाइन किया जाता है, और उस डेटा को म्यूट करता है जो' 'इंगित करता है। वास्तव में क्या होता है कि डेटा की एक नई प्रति बनाई जाती है और * 'a' * को इंगित करने के लिए पुन: असाइन किया जाता है, और फिर नया डेटा उत्परिवर्तित होता है। –

3

यहाँ (वैसे प्रारंभ नहीं) वाक्य रचना सुविधाजनक कार्य के लिए कार्य करता है के एक जोड़े हैं:

vector<int> v; 
setVector(v, 3, 
      1, 2, 3); 

matrix<int> m; 
setMatrix(m, 3, 4, 
      1, 2, 3, 4, 
      11, 22, 33, 44, 
      111, 222, 333, 444); 

कार्य:

/** 
* Resize a ublas vector and set its elements 
*/ 
template <class T> void setVector(vector<T> &v, int n, ...) 
{ 
    va_list ap; 
    va_start(ap, n); 
    v.resize(n); 
    for (int i = 0; i < n; i++) { 
     v[i] = va_arg(ap, T); 
    } 
    va_end(ap); 
} 

/** 
* Resize a ublas matrix and set its elements 
*/ 
template <class T> void setMatrix(matrix<T> &m, int rows, int cols ...) 
{ 
    va_list ap; 
    va_start(ap, cols); 
    m.resize(rows, cols); 
    for (int i = 0; i < rows; i++) { 
     for (int j = 0; j < cols; j++) { 
      m(i, j) = va_arg(ap, T); 
     } 
    } 
    va_end(ap); 
} 
2

uBLAS storage.hpp में दो गैर-दस्तावेजी वर्गों रहे हैं। आप इनमें से किसी एक के साथ ublas :: वेक्टर में डिफ़ॉल्ट स्टोरेज क्लास (unbounded_array) को बदल सकते हैं।

  • प्रथम श्रेणी, array_adaptor, आपके डेटा की एक प्रतिलिपि बनाता जब ublas :: वेक्टर, बहुत उपयोगी नहीं बिल्कुल वर्ग निर्माता कॉपी करने के लिए कहता है। मैं बस unbounded_array या bounded_array कक्षाओं में ऐसा करने के लिए उचित कन्स्ट्रक्टर की बजाय।
  • दूसरा, shallow_array_adaptor, केवल आपके डेटा का संदर्भ रखें, ताकि आप सीधे अपने सी सरणी को संशोधित करने के लिए वेक्टर का उपयोग कर सकें। दुर्भाग्यवश, इसमें कुछ बग हैं, जब आप एक अभिव्यक्ति निर्दिष्ट करते हैं तो यह मूल डेटा पॉइंटर को नुकसान पहुंचाता है। लेकिन आप एक व्युत्पन्न कक्षा बना सकते हैं जो इस समस्या को ठीक करे।
यहाँ

पैच और एक उदाहरण:

// BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR must be defined before include vector.hpp 
#define BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR 

#include <boost/numeric/ublas/vector.hpp> 
#include <algorithm> 
#include <iostream> 

// Derived class that fix base class bug. Same name, different namespace.  
template<typename T> 
class shallow_array_adaptor 
: public boost::numeric::ublas::shallow_array_adaptor<T> 
{ 
public: 
    typedef boost::numeric::ublas::shallow_array_adaptor<T> base_type; 
    typedef typename base_type::size_type     size_type; 
    typedef typename base_type::pointer      pointer; 

    shallow_array_adaptor(size_type n) : base_type(n) {} 
    shallow_array_adaptor(size_type n, pointer data) : base_type(n,data) {} 
    shallow_array_adaptor(const shallow_array_adaptor& c) : base_type(c) {} 

    // This function must swap the values ​​of the items, not the data pointers. 
    void swap(shallow_array_adaptor& a) { 
     if (base_type::begin() != a.begin()) 
     std::swap_ranges(base_type::begin(), base_type::end(), a.begin()); 
    } 
}; 

void test() { 
    using namespace boost::numeric; 
    typedef ublas::vector<double,shallow_array_adaptor<double> > vector_adaptor; 

    struct point { 
     double x; 
     double y; 
     double z; 
    }; 

    point p = { 1, 2, 3 }; 
    vector_adaptor v(shallow_array_adaptor<double>(3, &p.x)); 

    std::cout << p.x << ' ' << p.y << ' ' << p.z << std::endl; 
    v += v*2.0; 
    std::cout << p.x << ' ' << p.y << ' ' << p.z << std::endl; 
} 

आउटपुट:

1 2 3 
3 6 9 
2

उथले सरणी एडाप्टर का उपयोग करने के लिए सामान्य सुझाव मेरे लिए एक तरह से व्यंग्यात्मक लगता है - बस का उपयोग करने में सक्षम होने की एक पॉइंटर के माध्यम से एक सरणी जिसे आप इसे साझा करने के लिए सभी संदर्भ गणना शेबैंग के साथ साझा_एरे में डाल सकते हैं (जो कुछ भी नहीं आता है, क्योंकि आपके पास सरणी नहीं है) और डेटा-एलियासिंग के दुःस्वप्न के साथ और क्या है। दरअसल, यूबीएलएएस का भंडारण (array_adaptor) का पूर्ण कार्यान्वयन है जो बाहरी सी सरणी वाले वैक्टरों का उपयोग करने की अनुमति देता है। एकमात्र पकड़ वेक्टर कन्स्ट्रक्टर है जो एक प्रति बनाता है। क्यों यह अच्छा सुविधा पुस्तकालय में नहीं किया जाता है काफी मेरे से परे है, लेकिन वैसे भी, हम एक छोटे से एक्सटेंशन का उपयोग कर सकते हैं (यह वास्तव में है C++ ब्लोट सामान्य से घिरा कोड के 2 लाइनों)

template<class T> 
class extarray_vector : 
    public vector<T, array_adaptor<T> > 
{ 
    typedef vector<T, array_adaptor<T> > vector_type; 
public: 
    BOOST_UBLAS_INLINE 
    extarray_vector(size_type size, pointer p) 
    { data().resize(size, p); } 

    template <size_type N> 
    BOOST_UBLAS_INLINE 
    extarray_vector(T (&a)[N]) 
    { data().resize(N, a); } 

    template<class V> 
    BOOST_UBLAS_INLINE 
    extarray_vector& operator = (const vector<T, V>& v) 
    { 
     vector_type::operator = (v); 
     return *this; 
    } 

    template<class VC> 
    BOOST_UBLAS_INLINE 
    extarray_vector& operator = (const vector_container<VC>& v) 
    { 
     vector_type::operator = (v); 
     return *this; 
    } 

    template<class VE> 
    BOOST_UBLAS_INLINE 
    extarray_vector& operator = (const vector_expression<VE>& ae) 
    { 
     vector_type::operator = (ae); 
     return *this; 
    } 
}; 

आप इस तरह उपयोग कर सकते हैं :

int i[] = {1, 4, 9, 16, 25, 36, 49}; 
extarray_vector<int> iv(i); 
BOOST_ASSERT_MSG(i == &iv[0], "Vector should attach to external array\n"); 
iv[3] = 100; 
BOOST_ASSERT(i[3] == 100); 
iv.resize(iv.size() + 1, true); 
BOOST_ASSERT_MSG(i != &iv[0], "And detach from the array on resize\n"); 
iv[3] = 200; 
BOOST_ASSERT(i[3] == 100); 
iv.data().resize(7, i, 0); 
BOOST_ASSERT_MSG(i == &iv[0], "And attach back to the array\n"); 
BOOST_ASSERT(i[3] == 200); 

आप गतिशील रूप से देते हैं और array_adaptor के आकार विधि के माध्यम से बाहरी संग्रहण में वेक्टर अलग कर सकती हैं (रखने या डेटा को त्यागकर)। आकार बदलने पर यह स्वचालित रूप से भंडारण से अलग हो जाता है और नियमित वेक्टर बन जाता है। कंटेनरों से असाइनमेंट सीधे भंडारण में जाता है, लेकिन अस्थायी और वेक्टर के माध्यम से अभिव्यक्ति से असाइनमेंट किया जाता है, इसे रोकने के लिए noalias() का उपयोग करें। कन्स्ट्रक्टर में एक छोटा ओवरहेड है क्योंकि डेटा_ निजी सदस्य है और हमें इसे डिफ़ॉल्ट टी [0] के साथ प्रारंभ करना होगा, फिर बाहरी सरणी को फिर से सौंपना होगा। आप इसे संरक्षित में बदल सकते हैं और सीधे कन्स्ट्रक्टर में स्टोरेज को असाइन कर सकते हैं।

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