从C数组初始化的uBLAS矢量从C数组初始化的uBLAS矢量(Initializing a ubla

2019-05-12 02:59发布

我写使用C ++的uBLAS库Matlab的延伸,我希望能够通过Matlab的interpeter通过C数组初始化我的uBLAS向量。 如何可以初始化从C阵列的uBLAS矢量不具有(为了效率起见)明确地复制数据。 我找了沿以下几行代码的东西:

using namespace boost::numeric::ublas;

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

一般情况下,是有可能初始化一个C ++ 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

但我想输出是相同的,在这里更新C数组改变数据由C ++矢量指向

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

Answer 1:

双方std::vectorublas::vector是容器。 容器的整点是管理其包含的对象的存储和寿命。 这就是为什么当你初始化它们就必须值复制到他们自己的存储。

C数组的存储区域固定的大小和位置,以便根据其性质,你只能得到其价值的通过复制一个容器。

您可以使用C数组作为输入到许多算法功能,因此,或许你可以做到这一点,以避免最初的副本?



Answer 2:

我不知道你的问题是如何与MATLAB / MEX,但一个侧面说明,你可能想知道,MATLAB实现写入时复制策略。

这意味着,当复制的阵列,例如,只有一些标头实际复制,而数据本身的两个阵列之间共享。 一旦其中的一个被修改,数据的副本实际上是由。

下面是什么可能的引擎盖下发生的(从这个借了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 ...

我知道这并没有真正回答你的问题,我只是想你可能会觉得这个概念有帮助的。



Answer 3:

您可以从初始化C数组容易一个std ::向量:

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


Answer 4:

有两个无证班的uBLAS storage.hpp。 您可以更改的uBLAS默认存储类(unbounded_array)::向量的其中之一。

  • 第一类,array_adaptor,使您的数据的副本时的uBLAS :: vector的调用拷贝构造函数,而不是非常有用的类的。 我宁愿只是适当的构造函数执行此操作在unbounded_array或bounded_array类。
  • 第二,shallow_array_adaptor,只保存数据的参考,所以你可以使用矢量直接修改你的C数组。 不幸的是,有一些错误,当你分配一个表达式它损失的原始数据的指针。 但是你可以创建一个派生类解决这个问题。

这里的补丁和一个例子:

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


Answer 5:

这里有一对夫妇的语法为方便分配功能(当然不是初始化):

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


Answer 6:

通常建议使用浅阵列适配器似乎有点讥讽我的话 - 能够简单地通过指针访问数组你应该把它变成一个shared_array与所有的引用计数家当(即都落了空,因为你没有自己的阵列),更重要的是与数据走样的噩梦。 实际上,uBLAS库具有完全成熟的实施存储(的array_adaptor ),其允许使用与外部C阵列载体。 唯一的缺点是向量的构造,这使得副本。 为什么这个不错的功能是不是在图书馆使用的是远远超出我的,但无论如何,我们可以用一个小的扩展(它实际上是两行代码与通常所包围的C ++膨胀)

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()以防止这一点。 有一个在构造一个小的开销,因为data_中是私有成员,我们不得不默认了新T [0],然后重新分配给外部阵列初始化。 你可以把它变成保护,直接在构造函数中分配给存储。



文章来源: Initializing a ublas vector from a C array