Inicializando un vector ublas desde una matriz C

Estoy escribiendo una extensión de Matlab utilizando la biblioteca ublas de C ++, y me gustaría poder inicializar mis vectores ublas de las matrices C pasadas por el interperador de Matlab. ¿Cómo puedo inicializar el vector ublas desde una matriz C sin (por el bien de la eficiencia) copiar explícitamente los datos. Estoy buscando algo a lo largo de las siguientes líneas de código:

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

En general, ¿es posible inicializar un estándar C ++ std::vector de una matriz? Algo como esto:

 #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; } 

pero donde la inicialización no copiaría los datos. En este caso, la salida es

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

pero quiero que la salida sea la misma, donde actualizar la matriz C cambia los datos apuntados por el vector C ++

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

Tanto std::vector como ublas::vector son contenedores. El objective de los contenedores es administrar el almacenamiento y la duración de sus objetos contenidos. Es por eso que cuando los inicializas deben copiar los valores en el almacenamiento que poseen.

Las matrices C son áreas de memoria fijadas en tamaño y ubicación, por lo que, por su naturaleza, solo se pueden copiar sus valores en un contenedor.

Puede usar arrays en C como entrada para muchas funciones de algoritmo, entonces quizás pueda hacer eso para evitar la copia inicial.

No estoy seguro de cómo se relaciona su pregunta con MATLAB / MEX, pero una nota al margen, es posible que desee saber que MATLAB implementa una estrategia de copia sobre escritura .

Esto significa que cuando copia una matriz, por ejemplo, solo se copian algunos encabezados, mientras que los datos en sí se comparten entre las dos matrices. Y una vez que se modifica uno de ellos, se realiza una copia de los datos.

La siguiente es una simulación de lo que podría estar sucediendo bajo el capó (tomado de esta publicación anterior ):

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

Sé que esto realmente no responde a tu pregunta, solo pensé que podrías encontrar el concepto útil.

Puede inicializar un std :: vector desde una matriz C fácilmente:

 vector v(pv, pv+10); 

Hay dos clases no documentadas en uBLAS storage.hpp. Puede cambiar la clase de almacenamiento predeterminada (unbounded_array) en ublas :: vector con uno de estos.

  • La primera clase, array_adaptor, hace una copia de tus datos cuando ublas :: vector llama para copiar el constructor, clase no muy útil en absoluto. Prefiero simplemente el constructor apropiado para hacer esto en las clases unbounded_array o bounded_array.
  • El segundo, shallow_array_adaptor , solo contiene una referencia de sus datos, por lo que puede usar el vector para modificar directamente su matriz C. Desafortunadamente, tiene algunos errores, cuando asigna una expresión pierde el puntero de datos original. Pero puede crear una clase derivada que solucione este problema.

Aquí el parche y un ejemplo:

 // 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; } 

Salida:

 1 2 3 3 6 9 

Aquí hay un par de funciones para la asignación sintácticamente conveniente (es decir, no la inicialización):

 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); 

Las funciones:

 /** * 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); } 

La sugerencia habitual de utilizar un adaptador de matriz superficial me parece sarcástica: para poder acceder simplemente a una matriz mediante un puntero, se supone que debes ponerla en una matriz compartida con toda la referencia de conteo de shebang (eso no sirve para nada, ya que no es dueño de la matriz) y lo que es más con una pesadilla de alias de datos. En realidad, uBLAS tiene una implementación completa de almacenamiento ( array_adaptor ) que permite usar vectores con matrices c externas. La única trampa es el constructor vectorial que hace una copia. El por qué esta linda función no se usa en la biblioteca me supera, pero de todos modos, podemos usar una pequeña extensión (en realidad se trata de 2 líneas de código rodeadas con la hinchazón habitual de c ++)

 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; } }; 

puedes usarlo así:

 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); 

Puede vincular y desconectar dinámicamente vector a almacenamiento externo a través del método de ajuste de tamaño de array_adaptor (conservar o descartar datos). Al cambiar el tamaño, se separa del almacenamiento automáticamente y se convierte en un vector regular. La asignación desde los contenedores va directamente al almacenamiento, pero la asignación de la expresión se realiza a través de un temporal y el vector se separa del almacenamiento, use noalias() para evitar eso. Hay una pequeña sobrecarga en el constructor ya que data_ es un miembro privado y tenemos que inicializarlo por defecto con la nueva T [0], luego reasignar a la matriz externa. Puede cambiarlo a protegido y asignarlo al almacenamiento directamente en el constructor.