Armadillo 相当于 Matlab 置换?
Armadillo equivalent of Matlab permute?
我有一个 arma::cube mycube(5,10,15);
,我想排列它的尺寸,就像在 matlab 中做的那样:
mycube = ones(5,10,15);
mycube = permute(mycube,[3 1 2]);
size(mycube) % returns (15 5 10)
有办法吗?
会不会太低效了?
其实我想做一个 3D FFT,所以我想到了置换第一维和第三维以便能够使用 arma::fft
,然后再置换回来。
Armadillo ibrary 不包含这样的功能,但您可以实现一个简化版本。例如:
#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-dim 数组 (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;
}
顺序元组是 matlab 样式(从 1 开始),而犰狳是从零开始的数组。
shape(cube) 函数只是一个小帮手,return 相当于 matlab 中的 Size(),一个具有每个维度大小的 N-dim 数组。
template <typename T>
inline u32_vec shape (const Cube<T>& x)
{
return { x.n_rows, x.n_cols, x.n_slices };
}
代码需要配合使用:
using namespace arma;
我有一个 arma::cube mycube(5,10,15);
,我想排列它的尺寸,就像在 matlab 中做的那样:
mycube = ones(5,10,15);
mycube = permute(mycube,[3 1 2]);
size(mycube) % returns (15 5 10)
有办法吗?
会不会太低效了?
其实我想做一个 3D FFT,所以我想到了置换第一维和第三维以便能够使用 arma::fft
,然后再置换回来。
Armadillo ibrary 不包含这样的功能,但您可以实现一个简化版本。例如:
#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-dim 数组 (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;
}
顺序元组是 matlab 样式(从 1 开始),而犰狳是从零开始的数组。
shape(cube) 函数只是一个小帮手,return 相当于 matlab 中的 Size(),一个具有每个维度大小的 N-dim 数组。
template <typename T>
inline u32_vec shape (const Cube<T>& x)
{
return { x.n_rows, x.n_cols, x.n_slices };
}
代码需要配合使用:
using namespace arma;