2016-03-04 3 views
0

У меня есть arma::cube mycube(5,10,15);, и я хочу, чтобы переставить его размеры, как можно было бы сделать в MATLAB:Армадилло эквивалент Matlab перестановочный?

mycube = ones(5,10,15); 
mycube = permute(mycube,[3 1 2]); 
size(mycube) % returns (15 5 10) 

Есть ли способ сделать это?
Было бы слишком неэффективно?

Я действительно хочу сделать 3D FFT, поэтому я подумал о том, чтобы перенести первый и третий измерения, чтобы использовать arma::fft, а затем переставлять назад.

ответ

1

Armadillo library не содержит такой функции, но вы можете реализовать упрощенную версию. Например, так:

#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); 
    } 
+0

Вы бы ожидать simplePermute работать на 'арма :: cx_cube' тоже? – dangom

+0

@ ДаниэльG, да, главное здесь - количество измерений. –

+0

На самом деле функция перестановки не работает должным образом. Он не дает те же результаты, что и matlab. В качестве простого примера, если матрица является идеальным кубом, 'simplePermute' ничего не сделает с ней. – dangom

3

Еще один простой способ сделать 3-тусклый массив (арма :: куб) перестановка ниже один. Это не очень элегантно, но легко понять.

Поскольку перестановка 3 уникальных чисел равна 6 (а точнее 5 без ссылочного порядка), быстро избежать алгоритмического метода.

Перестановка тусклым 1, 2, 3:

123 (основание) порядка 213 231 132 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; 
} 

Порядок tuple находится в стиле matlab (на основе 1), а armadillo - на основе нуля.

Функция формы (куба) - это лишь небольшой помощник, который возвращает эквивалент размера() в матрице Mlab, массив 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; 
Смежные вопросы