创建多阵列的任意视图 我编写了一个C++函数来计算边际概率密度函数(概率密度函数)。这基本上意味着我得到了多维数据(PDF),这些数据是沿着一个由许多变量组成的网格定义的。我想在未定义的维度上集成数据,以保持函数的通用性

创建多阵列的任意视图 我编写了一个C++函数来计算边际概率密度函数(概率密度函数)。这基本上意味着我得到了多维数据(PDF),这些数据是沿着一个由许多变量组成的网格定义的。我想在未定义的维度上集成数据,以保持函数的通用性,c++,arrays,boost,multidimensional-array,generic-programming,C++,Arrays,Boost,Multidimensional Array,Generic Programming,PDF的维度可以是任意的,边缘PDF的维度也可以是任意的。无法定义输入数据的维度顺序,因此我向函数发送了一个向量,该向量表示需要保留哪些变量。其他变量需要整合 例如: 变量数量:5(a,b,c,d,e),PDF数据维度5,计算(a,c,d)的边际PDF。这意味着变量/维度0,2,3需要保留,其他变量/维度需要积分(通过定积分)。 so:PDF[a][b][c][d][e]->MARGPDF[a][c][d](其中包含其他值) 对于每个[a][c][d],我需要对其他维度[b][e]中的数据执行操

PDF的维度可以是任意的,边缘PDF的维度也可以是任意的。无法定义输入数据的维度顺序,因此我向函数发送了一个向量,该向量表示需要保留哪些变量。其他变量需要整合

例如: 变量数量:5(a,b,c,d,e),PDF数据维度5,计算(a,c,d)的边际PDF。这意味着变量/维度0,2,3需要保留,其他变量/维度需要积分(通过定积分)。 so:PDF[a][b][c][d][e]->MARGPDF[a][c][d](其中包含其他值) 对于每个[a][c][d],我需要对其他维度[b][e]中的数据执行操作。我可以通过创建视图来实现这一点,但是我现在不知道如何动态实现这一点。所谓动态,我的意思是,我希望维度的数量和保留的维度可以自由选择

基本上,我想要的是创建维度b和e中所有值的视图,并为a、c、d的每个(循环)值执行此操作。但是,我希望函数是通用的,这样输入可以是任何多数组,输出变量可以自由选择。因此,它也可以是:PDF[a][b][c][d]>MARGPDF[c]或PDF[a][b][c][d][e][f]>MARGPDF[b][d]

我有以下想法: 我按维度对PDF多数组进行排序,以便创建最后一个维度数的视图,因此: PDF[a][b][c][d][e]变为PDF[a][c][d][b][e]。然后我在每个a、c、d上循环,并创建剩余2个维度b和e的视图。我使用此视图执行计算,并将值保存到PDF[a][c][d]

执行此类操作时,我需要知道的是: 如何切换boost::multi_阵列的维度/索引顺序? 当尺寸是自由的时,如何创建视图? 或者你有其他想法来完成同样的事情吗

下面提供了我的代码的开头:

template<class DataType, int Dimension, int ReducedDimension>
boost::multi_array<DataType, ReducedDimension> ComputeMarginalPDF(boost::multi_array<DataType, Dimension> PDF,
                                                           std::vector< std::vector<DataType> > Variables , std::vector<int> VarsToKeep ){
// check input dimensions
if (VarsToKeep.size() != ReducedDimension ){
    std::cout << "Dimensions do not match" << std::endl;
}

std::vector< std::vector<double> > NewVariables(0) ;

// Construct reduced array with proper dimensions
typedef boost::multi_array< DataType , ReducedDimension > ReducedArray ;
boost::array< ReducedArray::index , ReducedDimension > dimensions;

// get dimensions from array and insert into dimensions ;
// set Marginal PDF dimensions
for(int i = 0 ; i < VarsToKeep.size() ; i++){
    dimensions[i] = PDF.shape()[ VarsToKeep[i] ] ;
    NewVariables.push_back( Variables[ VarsToKeep[i] ] );
}

ReducedArray Marginal(dimensions) ;

// to be filled with code
模板
boost::multi_array ComputeMarginalPDF(boost::multi_array PDF,
std::vector变量,std::vector varstokep){
//检查输入尺寸
if(varstokep.size()!=缩减尺寸){
std::cout-reducedaray;
boost::arraydimensions;
//从数组中获取维度并插入到维度中;
//设置边缘PDF维度
对于(int i=0;i

我希望不要混淆。欢迎提出任何改进问题的建议。

几个月前我遇到过类似的问题,但我只需要计算一维边缘。这是对我有效的解决方案的概述,我想它也可以适用于多维边缘:

我基本上是将pdf存储在一维数组/向量中(可以随意使用):

然后我用它来存储一个二维数组
a[width][height]
作为一个一维数组
b[width*height]
并访问任何元素
a[x][y]
作为
b[width*x+y]
。您可以将此公式推广到任意尺寸,并正确使用模/整数除法,还可以计算逆

使用模板,从一维索引到N维索引的计算以及从N维索引到一维索引的计算都非常简单。这允许您将取决于维度的符号
PDF[a][b][c][d][e]
转换为类似
PDF(std::vector{a,b,c,d,e})的符号
它很容易扩展到任意维度,因为您可以在循环中提前填充向量

如果您认为这种方法可能对您有所帮助,我可以尝试掌握我的实现的一些关键功能,并将它们添加到这里

编辑:

template <size_t DIM>
inline void posToPosN(const size_t& pos,
    const size_t* const size,
    size_t* const posN){
    size_t r = pos;

    for (size_t i = DIM; i > 0; --i){
        posN[i - 1] = r % size[i - 1];
        r /= size[i - 1];
    }
}

template <size_t DIM>
inline void posNToPos(size_t& pos,
    const size_t* const size,
    const size_t* const posN){
    pos = 0;
    size_t mult = 1;

    for (size_t i = DIM; i > 0; --i){
        pos += mult * posN[i - 1];
        mult *= size[i - 1];
    }
}

template<typename type, size_t DIM>
class Iterator{
private:
    type* const _data; //pointer to start of Array
    size_t _pos; //1-dimensional position
    size_t _posN[DIM]; //n-dimensional position
    size_t const * const _size; //pointer to the _size-Member of Array
    size_t _total;

private:

public:
    Iterator(type* const data, const size_t* const size, size_t total, size_t pos)
        : _data(data), _pos(pos), _size(size), _total(total)
    {
        if (_pos > _total || _pos < 0) _pos = _total;
        posToPosN<DIM>(_pos, _size, _posN);
    }

    bool operator!= (const Iterator& other) const
    {
        return _pos != other._pos;
    }

    type& operator* () const{
        if (_pos >= _total)
            std::cout << "ERROR, dereferencing too high operator";
        return *(_data + _pos);
    }

    const Iterator& operator++ ()
    {
        ++_pos;
        if (_pos > _total) _pos = _total;

        posToPosN<DIM>(_pos, _size, _posN);
        return *this;
    }

    Iterator& operator +=(const size_t& b)
    {
        _pos += b;
        if (_pos > _total) _pos = _total;

        posToPosN<DIM>(_pos, _size, _posN);
        return *this;
    }

    const Iterator& operator-- ()
    {
        if (_pos == 0)
            _pos = _total;
        else
            --_pos;

        posToPosN<DIM>(_pos, _size, _posN);
        return *this;
    }

    //returns position in n-th dimension
    size_t operator[](size_t n){
        return _posN[n];
    }

    //returns a new iterator, advanced by n steps in the dim Dimension
    Iterator advance(size_t dim, int steps = 1){
        if (_posN[dim] + steps < 0 || _posN[dim] + steps >= _size[dim]){
            return Iterator(_data, _size, _total, _total);
        }

        size_t stride = 1;
        for (size_t i = DIM - 1; i > dim; --i){
            stride *= _size[i];
        }

        return Iterator(_data, _size, _total, _pos + steps*stride);
    }
};


template <typename type, size_t DIM>
class Array{
    type* _data;
    size_t _size[DIM];
    size_t _total;

    void init(const size_t* const dimensions){
        _total = 1;
        for (int i = 0; i < DIM; i++){
            _size[i] = dimensions[i];
            _total *= _size[i];
        }

        _data = new type[_total];
    }

public:
    Array(const size_t* const dimensions){
        init(dimensions);
    }

    Array(const std::array<size_t, DIM>& dimensions){
        init(&dimensions[0]);
    }

    ~Array(){
        delete _data;
    }
    Iterator<type, DIM> begin(){
        return Iterator<type, DIM>(_data, _size, _total, 0);
    }
    Iterator<type, DIM> end(){
        return Iterator<type, DIM>(_data, _size, _total, _total);
    }
    const size_t* const size(){
        return _size;
    }
};


//for projections of the PDF
void calc_marginals(size_t dir, double* p_xPos, double* p_yPos){
    assert(dir < N_THETA);

    std::lock_guard<std::mutex> lock(calcInProgress);

    //reset to 0
    for (size_t i = 0; i < _size[dir]; ++i){
        p_yPos[i] = 0;
    }

    //calc projection
    double sum = 0;
    for (auto it = _p_theta.begin(); it != _p_theta.end(); ++it){

        p_yPos[it[dir]] += (*it);
        sum += (*it);
    }

    if (abs(sum - 1) > 0.001){ cout << "Warning: marginal[" << dir << "] not normalized" << endl; }
    //calc x-Axis
    for (size_t i = 0; i < _size[dir]; ++i){
        p_xPos[i] = _p[dir].start + double(i) / double(_size[dir] - 1)*(_p[dir].stop - _p[dir].start);
    }
}
模板
内联空心桩号(施工尺寸和桩号),
常量大小\u t*常量大小,
尺寸(常数位置){
尺寸=位置;
对于(尺寸i=DIM;i>0;--i){
posN[i-1]=r%大小[i-1];
r/=尺寸[i-1];
}
}
模板
内联空隙位置(尺寸和位置),
常量大小\u t*常量大小,
常数大小(常数位置){
pos=0;
尺寸乘以=1;
对于(尺寸i=DIM;i>0;--i){
pos+=mult*posN[i-1];
mult*=尺寸[i-1];
}
}
模板
类迭代器{
私人:
type*const _data;//指向数组开头的指针
大小\u t\u pos;//一维位置
大小_t _posN[DIM];//n维位置
size\t const*const\u size;//指向数组的_size-Member的指针
总尺寸;
私人:
公众:
迭代器(类型*常量数据、常量大小*常量大小、大小总和、大小位置)
:_数据(数据),_位置(位置),_大小(大小),_总数(总数)
{
如果(_pos>_total | | _pos<0)_pos=_total;
postopsn(_pos,_size,_posN);
}
布尔运算符!=(常量迭代器和其他)常量
{
返回_pos!=其他。_pos;
}
类型和运算符*()常量{
如果(\u位置>=\u总数)
标准::cout _total)_pos=_total;
postopsn(_pos,_size,_posN);
归还*这个;
}
迭代器和运算符+=(常量大小t&b)
{
_pos+=b;
如果(\u pos>\u total)\u pos=\u total;
postopsn(_pos,_size,_posN);
归还*这个;
}
常量迭代器和运算符--()
{
如果(_pos==0)
_pos=总计;
其他的
--_pos;
postopsn(_pos,_size,_posN);
归还*这个;
}
//返回第n个位置
template <size_t DIM>
inline void posToPosN(const size_t& pos,
    const size_t* const size,
    size_t* const posN){
    size_t r = pos;

    for (size_t i = DIM; i > 0; --i){
        posN[i - 1] = r % size[i - 1];
        r /= size[i - 1];
    }
}

template <size_t DIM>
inline void posNToPos(size_t& pos,
    const size_t* const size,
    const size_t* const posN){
    pos = 0;
    size_t mult = 1;

    for (size_t i = DIM; i > 0; --i){
        pos += mult * posN[i - 1];
        mult *= size[i - 1];
    }
}

template<typename type, size_t DIM>
class Iterator{
private:
    type* const _data; //pointer to start of Array
    size_t _pos; //1-dimensional position
    size_t _posN[DIM]; //n-dimensional position
    size_t const * const _size; //pointer to the _size-Member of Array
    size_t _total;

private:

public:
    Iterator(type* const data, const size_t* const size, size_t total, size_t pos)
        : _data(data), _pos(pos), _size(size), _total(total)
    {
        if (_pos > _total || _pos < 0) _pos = _total;
        posToPosN<DIM>(_pos, _size, _posN);
    }

    bool operator!= (const Iterator& other) const
    {
        return _pos != other._pos;
    }

    type& operator* () const{
        if (_pos >= _total)
            std::cout << "ERROR, dereferencing too high operator";
        return *(_data + _pos);
    }

    const Iterator& operator++ ()
    {
        ++_pos;
        if (_pos > _total) _pos = _total;

        posToPosN<DIM>(_pos, _size, _posN);
        return *this;
    }

    Iterator& operator +=(const size_t& b)
    {
        _pos += b;
        if (_pos > _total) _pos = _total;

        posToPosN<DIM>(_pos, _size, _posN);
        return *this;
    }

    const Iterator& operator-- ()
    {
        if (_pos == 0)
            _pos = _total;
        else
            --_pos;

        posToPosN<DIM>(_pos, _size, _posN);
        return *this;
    }

    //returns position in n-th dimension
    size_t operator[](size_t n){
        return _posN[n];
    }

    //returns a new iterator, advanced by n steps in the dim Dimension
    Iterator advance(size_t dim, int steps = 1){
        if (_posN[dim] + steps < 0 || _posN[dim] + steps >= _size[dim]){
            return Iterator(_data, _size, _total, _total);
        }

        size_t stride = 1;
        for (size_t i = DIM - 1; i > dim; --i){
            stride *= _size[i];
        }

        return Iterator(_data, _size, _total, _pos + steps*stride);
    }
};


template <typename type, size_t DIM>
class Array{
    type* _data;
    size_t _size[DIM];
    size_t _total;

    void init(const size_t* const dimensions){
        _total = 1;
        for (int i = 0; i < DIM; i++){
            _size[i] = dimensions[i];
            _total *= _size[i];
        }

        _data = new type[_total];
    }

public:
    Array(const size_t* const dimensions){
        init(dimensions);
    }

    Array(const std::array<size_t, DIM>& dimensions){
        init(&dimensions[0]);
    }

    ~Array(){
        delete _data;
    }
    Iterator<type, DIM> begin(){
        return Iterator<type, DIM>(_data, _size, _total, 0);
    }
    Iterator<type, DIM> end(){
        return Iterator<type, DIM>(_data, _size, _total, _total);
    }
    const size_t* const size(){
        return _size;
    }
};


//for projections of the PDF
void calc_marginals(size_t dir, double* p_xPos, double* p_yPos){
    assert(dir < N_THETA);

    std::lock_guard<std::mutex> lock(calcInProgress);

    //reset to 0
    for (size_t i = 0; i < _size[dir]; ++i){
        p_yPos[i] = 0;
    }

    //calc projection
    double sum = 0;
    for (auto it = _p_theta.begin(); it != _p_theta.end(); ++it){

        p_yPos[it[dir]] += (*it);
        sum += (*it);
    }

    if (abs(sum - 1) > 0.001){ cout << "Warning: marginal[" << dir << "] not normalized" << endl; }
    //calc x-Axis
    for (size_t i = 0; i < _size[dir]; ++i){
        p_xPos[i] = _p[dir].start + double(i) / double(_size[dir] - 1)*(_p[dir].stop - _p[dir].start);
    }
}