Inizializzazione di un vettore ublas da un array C

Sto scrivendo un’estensione Matlab usando la libreria ublas di C ++, e mi piacerebbe essere in grado di inizializzare i miei vettori ublas dai C array passati dall’interpeter Matlab. Come posso inizializzare il vettore ublas da un array C senza (per motivi di efficienza) copiando esplicitamente i dati. Sto cercando qualcosa lungo le seguenti righe di codice:

using namespace boost::numeric::ublas; int pv[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; vector v (pv); 

In generale, è ansible inizializzare un C ++ std::vector da un array? Qualcosa come questo:

 #include  #include  using namespace std; int main() { int pv[4] = { 4, 4, 4, 4}; vector v (pv, pv+4); pv[0] = 0; cout << "v[0]=" << v[0] << " " << "pv[0]=" << pv[0] << endl; return 0; } 

ma dove l’inizializzazione non avrebbe copiato i dati. In questo caso l’output è

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

ma voglio che l’output sia lo stesso, dove l’aggiornamento dell’array C cambia i dati puntati dal vettore C ++

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

Sia std::vector che ublas::vector sono contenitori. L’intero punto dei contenitori è gestire lo spazio di archiviazione e la vita dei loro oggetti contenuti. Questo è il motivo per cui quando si inizializzano, devono copiare i valori nello spazio di cui sono proprietari.

I matrici di C sono aree di memoria fissate in dimensioni e posizione, quindi per loro natura è ansible copiare i loro valori in un contenitore.

Puoi utilizzare i C array come input per molte funzioni dell’algoritmo, quindi forse puoi farlo per evitare la copia iniziale?

Non sono sicuro di come la tua domanda si riferisca a MATLAB / MEX, ma una nota a margine, potresti voler sapere che MATLAB implementa una strategia copy-on-write .

Ciò significa che quando si copia una matrice, ad esempio, solo alcune intestazioni vengono effettivamente copiate, mentre i dati stessi vengono condivisi tra i due array. E una volta che uno di questi viene modificato, viene effettivamente eseguita una copia dei dati.

Quello che segue è una simulazione di ciò che potrebbe accadere sotto il cofano (preso in prestito da questo vecchio post ):

 ----------------------------------------- >> 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 ... 

So che questo non risponde alla tua domanda, ho solo pensato che potresti trovare utile il concetto.

È ansible inizializzare facilmente un vettore std :: da un array C:

 vector v(pv, pv+10); 

Esistono due classi non documentate in uBLAS storage.hpp. È ansible modificare la class di archiviazione predefinita (unbounded_array) in ublas :: vector con uno di questi.

  • La prima class, array_adaptor, crea una copia dei dati quando ublas :: vector chiama copy constructor, class non molto utile. Preferirei semplicemente il costruttore appropriato per farlo nelle classi unbounded_array o bounded_array.
  • Il secondo, shallow_array_adaptor , contiene solo un riferimento ai tuoi dati, quindi puoi usare il vettore per modificare direttamente l’array C. Sfortunatamente, ha alcuni bug, quando assegni un’espressione perde il puntatore dei dati originale. Ma puoi creare una class derivata che risolva questo problema.

Ecco la patch e un esempio:

 // BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR must be defined before include vector.hpp #define BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR #include  #include  #include  // Derived class that fix base class bug. Same name, different namespace. template class shallow_array_adaptor : public boost::numeric::ublas::shallow_array_adaptor { public: typedef boost::numeric::ublas::shallow_array_adaptor 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 > vector_adaptor; struct point { double x; double y; double z; }; point p = { 1, 2, 3 }; vector_adaptor v(shallow_array_adaptor(3, &p.x)); std::cout << px << ' ' << py << ' ' << pz << std::endl; v += v*2.0; std::cout << px << ' ' << py << ' ' << pz << std::endl; } 

Produzione:

 1 2 3 3 6 9 

Qui ci sono un paio di funzioni per l’incarico sintatticamente conveniente (certamente non l’inizializzazione):

 vector v; setVector(v, 3, 1, 2, 3); matrix m; setMatrix(m, 3, 4, 1, 2, 3, 4, 11, 22, 33, 44, 111, 222, 333, 444); 

Le funzioni:

 /** * Resize a ublas vector and set its elements */ template  void setVector(vector &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  void setMatrix(matrix &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); } 

Il solito suggerimento di usare un adattatore per array superficiale mi sembra abbastanza sarcastico: essere in grado di accedere semplicemente a un array attraverso un puntatore che dovresti mettere in un array condiviso con tutto il codice di conteggio di riferimento (che non arriva a nulla, dato che tu non possedere la matrice) e cosa c’è di più con un incubo di data aliasing. In realtà, uBLAS ha un’implementazione completa dello storage ( array_adaptor ) che consente di utilizzare i vettori con i c array esterni. L’unica presa è il costruttore vettoriale che ne fa una copia. Perché questa bella funzione non è utilizzata nella libreria è al di là di me, ma comunque, possiamo usare una piccola estensione (in realtà sono 2 righe di codice circondate dal solito c ++ bloat)

 template class extarray_vector : public vector > { typedef vector > vector_type; public: BOOST_UBLAS_INLINE extarray_vector(size_type size, pointer p) { data().resize(size, p); } template  BOOST_UBLAS_INLINE extarray_vector(T (&a)[N]) { data().resize(N, a); } template BOOST_UBLAS_INLINE extarray_vector& operator = (const vector& v) { vector_type::operator = (v); return *this; } template BOOST_UBLAS_INLINE extarray_vector& operator = (const vector_container& v) { vector_type::operator = (v); return *this; } template BOOST_UBLAS_INLINE extarray_vector& operator = (const vector_expression& ae) { vector_type::operator = (ae); return *this; } }; 

puoi usarlo in questo modo:

 int i[] = {1, 4, 9, 16, 25, 36, 49}; extarray_vector 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); 

È ansible colbind e scolbind dynamicmente il vettore allo storage esterno tramite il metodo di ridimensionamento di array_adaptor (mantenendo o scartando i dati). Al ridimensionamento si stacca automaticamente dallo spazio di archiviazione e diventa vettore normale. L’assegnazione dai contenitori passa direttamente allo storage, ma l’assegnazione dall’espressione avviene tramite un temporaneo e il vettore viene staccato dalla memoria, usare noalias() per impedirlo. C’è un piccolo overhead nel costruttore dato che data_ è membro privato e dobbiamo inizializzarlo con la nuova T [0], quindi riassegnare alla matrice esterna. Puoi cambiarlo in protetto e assegnarlo allo storage direttamente nel costruttore.