C++ Matlab permute的犰狳等价物?

C++ Matlab permute的犰狳等价物?,c++,matlab,armadillo,C++,Matlab,Armadillo,我有一个arma::立方体mycube5,10,15;我想改变它的尺寸,就像在matlab中一样: mycube = ones(5,10,15); mycube = permute(mycube,[3 1 2]); size(mycube) % returns (15 5 10) 有办法吗? 会不会效率太低 实际上我想做一个3D FFT,所以我想排列第一和第三维度,以便能够使用arma::FFT,然后再排列回来。犰狳图书馆不包含这样的函数,但您可以实现一个简化版本。例如: #include &

我有一个arma::立方体mycube5,10,15;我想改变它的尺寸,就像在matlab中一样:

mycube = ones(5,10,15);
mycube = permute(mycube,[3 1 2]);
size(mycube) % returns (15 5 10)
有办法吗? 会不会效率太低


实际上我想做一个3D FFT,所以我想排列第一和第三维度,以便能够使用arma::FFT,然后再排列回来。

犰狳图书馆不包含这样的函数,但您可以实现一个简化版本。例如:

#include <iostream>
#include <armadillo>
#include <tuple>
#include <algorithm>
#include <vector>

typedef std::tuple<std::size_t,std::size_t,std::size_t> D3tuple;

void printSize(const arma::cube &cube);
void simplePermute(arma::cube &cube, const D3tuple &order);
arma::uword getSize(const arma::cube &cube,
                    const std::size_t &n);
D3tuple get_coeff(arma::cube &cube, const D3tuple &order);

int main(int argc, char** argv)
  {

  arma::cube mycube = arma::randu<arma::cube>(2,2,2);
  std::cout<<mycube<<std::endl;
  printSize(mycube);

  simplePermute(mycube,D3tuple(3,1,2));
  printSize(mycube);
  std::cout<<mycube<<std::endl;
  return 0;
  }

void printSize(const arma::cube &cube)
    {
    std::cout<<cube.n_rows<<" "<<cube.n_cols<<" "<<cube.n_slices<<std::endl;
    }

void simplePermute(arma::cube &cube, const D3tuple &order)
    {
    auto first = std::get<0>(order),
        second = std::get<1>(order),
        third = std::get<2>(order);
    std::size_t cols = getSize(cube,first),
        rows = getSize(cube,second) ,
        slices = getSize(cube,third);

    arma::cube temp(cols,rows,slices);
    std::size_t c1,c2,c3;
    std::tie(c3,c2,c1) = get_coeff(cube,order);
    std::size_t index = 0;
    for(std::size_t i = 0;i<cols;i++)
        for(std::size_t j = 0;j<rows;j++)
            for(std::size_t k = 0;k<slices;k++)
                temp[index++] = cube[c1*i+c2*j+c3*k];

    cube = temp;
    }

arma::uword getSize(const arma::cube &cube,
                    const std::size_t &n)
    {
    switch (n)
        {
        case 1 : return cube.n_rows;
        case 2 : return cube.n_cols;
        case 3 : return cube.n_slices;
        }
    return 0;
    }

D3tuple get_coeff(arma::cube &cube, const D3tuple &order)
    {
    std::size_t c1,c2,c3;
    switch (std::get<0>(order))
        {
        case 1 : 
            c1 =  1;break;
        case 2 : 
            c1 =  cube.n_rows; break;
        case 3 : 
            c1 =  cube.n_rows*cube.n_cols; break;
        }
    switch (std::get<1>(order))
        {
        case 1 : 
            c2 =  1; break;
        case 2 : 
            c2 =  cube.n_rows; break;
        case 3 : 
            c2 =  cube.n_rows*cube.n_cols; break;
        }
    switch (std::get<2>(order))
        {
        case 1 : 
            c3 =  1; break;
        case 2 : 
            c3 =  cube.n_rows; break;
        case 3 : 
            c3 =  cube.n_rows*cube.n_cols; break;
        }
    return std::make_tuple(c1,c2,c3);
    }

犰狳库不包含这样的函数,但您可以实现一个简化版本。例如:

#include <iostream>
#include <armadillo>
#include <tuple>
#include <algorithm>
#include <vector>

typedef std::tuple<std::size_t,std::size_t,std::size_t> D3tuple;

void printSize(const arma::cube &cube);
void simplePermute(arma::cube &cube, const D3tuple &order);
arma::uword getSize(const arma::cube &cube,
                    const std::size_t &n);
D3tuple get_coeff(arma::cube &cube, const D3tuple &order);

int main(int argc, char** argv)
  {

  arma::cube mycube = arma::randu<arma::cube>(2,2,2);
  std::cout<<mycube<<std::endl;
  printSize(mycube);

  simplePermute(mycube,D3tuple(3,1,2));
  printSize(mycube);
  std::cout<<mycube<<std::endl;
  return 0;
  }

void printSize(const arma::cube &cube)
    {
    std::cout<<cube.n_rows<<" "<<cube.n_cols<<" "<<cube.n_slices<<std::endl;
    }

void simplePermute(arma::cube &cube, const D3tuple &order)
    {
    auto first = std::get<0>(order),
        second = std::get<1>(order),
        third = std::get<2>(order);
    std::size_t cols = getSize(cube,first),
        rows = getSize(cube,second) ,
        slices = getSize(cube,third);

    arma::cube temp(cols,rows,slices);
    std::size_t c1,c2,c3;
    std::tie(c3,c2,c1) = get_coeff(cube,order);
    std::size_t index = 0;
    for(std::size_t i = 0;i<cols;i++)
        for(std::size_t j = 0;j<rows;j++)
            for(std::size_t k = 0;k<slices;k++)
                temp[index++] = cube[c1*i+c2*j+c3*k];

    cube = temp;
    }

arma::uword getSize(const arma::cube &cube,
                    const std::size_t &n)
    {
    switch (n)
        {
        case 1 : return cube.n_rows;
        case 2 : return cube.n_cols;
        case 3 : return cube.n_slices;
        }
    return 0;
    }

D3tuple get_coeff(arma::cube &cube, const D3tuple &order)
    {
    std::size_t c1,c2,c3;
    switch (std::get<0>(order))
        {
        case 1 : 
            c1 =  1;break;
        case 2 : 
            c1 =  cube.n_rows; break;
        case 3 : 
            c1 =  cube.n_rows*cube.n_cols; break;
        }
    switch (std::get<1>(order))
        {
        case 1 : 
            c2 =  1; break;
        case 2 : 
            c2 =  cube.n_rows; break;
        case 3 : 
            c2 =  cube.n_rows*cube.n_cols; break;
        }
    switch (std::get<2>(order))
        {
        case 1 : 
            c3 =  1; break;
        case 2 : 
            c3 =  cube.n_rows; break;
        case 3 : 
            c3 =  cube.n_rows*cube.n_cols; break;
        }
    return std::make_tuple(c1,c2,c3);
    }

另一种制作3维数组arma::cube置换的简单方法如下。这不是很优雅,但很容易理解

因为3个唯一数字的排列是6,没有参考顺序,精确到5,所以很快就可以避免使用算法方法

dim 1、2、3的排列:

123基本订单132 213 231 312 321

因此,在不同排列之间进行简单切换:

template <typename T>
static Cube<T> permute (Cube<T>& cube, const std::tuple<uword,uword,uword>& order)
{
    uword idx1 = std::get<0>(order);
    uword idx2 = std::get<1>(order);
    uword idx3 = std::get<2>(order);

    u32_vec dimension = shape(cube);

    uword rows = dimension(idx1 - 1);
    uword cols = dimension(idx2 - 1);
    uword slis = dimension(idx3 - 1);

    Cube<T> output; 
    output.zeros(rows, cols, slis);

    uword perm = idx1*100 + idx2*10 + idx3;

    switch (perm)
    {
        case 123:
        {
            output = cube; // identity
        }
        break;
        case 132:
        {
            for (int c = 0; c < cube.n_cols; ++c)
                for (int r = 0; r < cube.n_rows; ++r)
                    for (int s = 0; s < cube.n_slices; ++s)
                        output(r, s, c) = cube(r, c, s);
        }
        break;
        case 213:
        {
            for (int c = 0; c < cube.n_cols; ++c)
                for (int r = 0; r < cube.n_rows; ++r)
                    for (int s = 0; s < cube.n_slices; ++s)
                        output(c, r, s) = cube(r, c, s);
        }
        break;
        case 231:
        {
            for (int c = 0; c < cube.n_cols; ++c)
                for (int r = 0; r < cube.n_rows; ++r)
                    for (int s = 0; s < cube.n_slices; ++s)
                        output(c, s, r) = cube(r, c, s);
        }
        break;
        case 312:
        {
            for (int c = 0; c < cube.n_cols; ++c)
                for (int r = 0; r < cube.n_rows; ++r)
                    for (int s = 0; s < cube.n_slices; ++s)
                        output(s, r, c) = cube(r, c, s);
        }
        break;
        case 321:
        {
            for (int c = 0; c < cube.n_cols; ++c)
                for (int r = 0; r < cube.n_rows; ++r)
                    for (int s = 0; s < cube.n_slices; ++s)
                        output(s, c, r) = cube(r, c, s);
        }
        break;
    }

    return output;
}

另一种制作3维数组arma::cube置换的简单方法如下。这不是很优雅,但很容易理解

因为3个唯一数字的排列是6,没有参考顺序,精确到5,所以很快就可以避免使用算法方法

dim 1、2、3的排列:

123基本订单132 213 231 312 321

因此,在不同排列之间进行简单切换:

template <typename T>
static Cube<T> permute (Cube<T>& cube, const std::tuple<uword,uword,uword>& order)
{
    uword idx1 = std::get<0>(order);
    uword idx2 = std::get<1>(order);
    uword idx3 = std::get<2>(order);

    u32_vec dimension = shape(cube);

    uword rows = dimension(idx1 - 1);
    uword cols = dimension(idx2 - 1);
    uword slis = dimension(idx3 - 1);

    Cube<T> output; 
    output.zeros(rows, cols, slis);

    uword perm = idx1*100 + idx2*10 + idx3;

    switch (perm)
    {
        case 123:
        {
            output = cube; // identity
        }
        break;
        case 132:
        {
            for (int c = 0; c < cube.n_cols; ++c)
                for (int r = 0; r < cube.n_rows; ++r)
                    for (int s = 0; s < cube.n_slices; ++s)
                        output(r, s, c) = cube(r, c, s);
        }
        break;
        case 213:
        {
            for (int c = 0; c < cube.n_cols; ++c)
                for (int r = 0; r < cube.n_rows; ++r)
                    for (int s = 0; s < cube.n_slices; ++s)
                        output(c, r, s) = cube(r, c, s);
        }
        break;
        case 231:
        {
            for (int c = 0; c < cube.n_cols; ++c)
                for (int r = 0; r < cube.n_rows; ++r)
                    for (int s = 0; s < cube.n_slices; ++s)
                        output(c, s, r) = cube(r, c, s);
        }
        break;
        case 312:
        {
            for (int c = 0; c < cube.n_cols; ++c)
                for (int r = 0; r < cube.n_rows; ++r)
                    for (int s = 0; s < cube.n_slices; ++s)
                        output(s, r, c) = cube(r, c, s);
        }
        break;
        case 321:
        {
            for (int c = 0; c < cube.n_cols; ++c)
                for (int r = 0; r < cube.n_rows; ++r)
                    for (int s = 0; s < cube.n_slices; ++s)
                        output(s, c, r) = cube(r, c, s);
        }
        break;
    }

    return output;
}

你希望simplePermute也能在arma::cx_cube上工作吗?@DanielG,是的,这里的主要问题是维度的数量。实际上,置换函数并没有像它应该的那样工作。它不会产生与matlab相同的结果。举个简单的例子,如果矩阵是一个完美的立方体,simplePermute不会对它做任何事情。@DanielG,你是对的。我会试着把它修好。对于其他维度,它应该如何工作?不,它不保留元素顺序。。。我认为它是有效的,因为我的测试矩阵是对称的。显然,它需要在维度之间循环,并按照newmatr,c,s=oldmatorder[permuteOrder1]*Ncol*Nrow+order[permuteOrder2]*Ncol+order[permuteOrder3]这样做。我正在试一试,但还没有得到正确的索引。你希望simplePermute也能在arma::cx_cube上工作吗?@DanielG,是的,这里的主要问题是维度的数量。实际上,排列函数并没有像它应该的那样工作。它不会产生与matlab相同的结果。举个简单的例子,如果矩阵是一个完美的立方体,simplePermute不会对它做任何事情。@DanielG,你是对的。我会试着把它修好。对于其他维度,它应该如何工作?不,它不保留元素顺序。。。我认为它是有效的,因为我的测试矩阵是对称的。显然,它需要在维度之间循环,并按照newmatr,c,s=oldmatorder[permuteOrder1]*Ncol*Nrow+order[permuteOrder2]*Ncol+order[permuteOrder3]这样做。我正在尝试一下,但还没有得到正确的指数。