2014-11-03 13 views
5

Obecnie próbuję przekonwertować niektóre kodu Pythona do C++. Jednym "małym" problemem jest zmiana wymiarów matrycy. Czy można przekształcić macierz w C++ podobną do funkcji Python reshape?Jak przekształcić matrycę?

Na przykład w Pythonie mogę z łatwością utworzyć tablicę z numpy i łatwo zmienić wymiary.

a = np.array([[1,2,3],[4,5,6]]) 
>>> a.reshape(3,2) 
array([[1, 2], 
     [3, 4], 
     [5, 6]]) 

Jak mogę to zrobić w C++? Być może jest to proste pytanie, ale nie jestem w stanie tego zrobić. Widziałem to w bibliotece OpenCV zklasa here jednak okazuje się być szalenie trudne do pracy poprawnie z MinGW, nie wspominając o bardzo dużym dodatkiem dla jednej funkcji. Byłoby idealnie, gdyby było to możliwe dzięki funkcjom "podstawowym".

+0

To naprawdę bardzo trudne pytanie. W NumPy jest to łatwe, ponieważ tablice NumPy rzeczywiście śledzą ich postępy i kształt; [Ten artykuł] (http://arxiv.org/pdf/1102.1523) opisuje strukturę i może zapewnić inspirację nawet dla programów w C++. –

Odpowiedz

4

O ile pamięć układa ciągły (np tablice czystym C), można zinterpretować typ z różnymi indeksami:

int array[2][3] = { { 1, 2, 3 }, 
         { 4, 5, 6 } 
        }; 

// Reinterpret the array with different indices 
int(*array_pointer)[3][2] = reinterpret_cast<int(*)[3][2]>(array); 

for (int x = 0; x < 3; ++x) { 
    for (int y = 0; y < 2; ++y) 
     std::cout << (*array_pointer)[x][y] << " "; 
    std::cout << std::endl; 
} 
// Output: 
// 1 2 
// 3 4 
// 5 6 

Example

Powyższe to tylko przykład, aby pokazać że kwestia naprawdę sprowadza się do tego, jak pamięć jest ułożona w twojej macierzy klasy.

Jeśli twoja klasa używa wewnętrznie std::vector<int> z liniowymi wskaźnikami, wystarczy ponownie zinterpretować te wskaźniki, aby pasowały do ​​twoich wzorców dostępu.

+1

To jest dokładnie to, czego szukałem. Dziękuję Ci! – cdeterman

0

To zależy od klasy macierzy, której używasz. Jeśli piszesz swój własny: istnieją dwa popularne techniki wykonawcze: obraz std::vector<double>, z obliczeń indeksu aby znalazł mieszkanie indeksu i std::vector<std::vector<double>>, z klasą niezmiennego, że wszyscy członkowie zewnętrznej wektor musi mieć się ten sam rozmiar. Jeśli używasz pierwszego, zmiana kształtu jest łatwa, tak długo jak , ponieważ całkowity rozmiar się nie zmienia (i ciężko wyobrazić sobie, co by to było inaczej). Jeśli użyjesz drugiego, zmiana kształtu prawdopodobnie wymagałaby skonstruowania kopii o nowym kształcie.

0

Nie ma standardowej biblioteki macierzy w C++, więc jesteś sam, jeśli chodzi o Matrices. Jednym ze sposobów przechowywania danych macierzy jest prosta tablica. Następnie musisz wykonać własną arytmetykę wierszy i kolumn podczas uzyskiwania dostępu do poszczególnych wierszy i kolumn. W twoim przypadku przekształcenie przychodzi za darmo po prostu zamieniając rozmiary wierszy i kolumn.

Jeśli potrzebujesz biblioteki macierzy, spróbuj: GLM.

3

Poniżej przedstawiono przykład użycia boost::ublas:

#include <iostream> 
#include <boost/numeric/ublas/matrix.hpp> 

//... 

using namespace boost::numeric::ublas; 

matrix<double> a(2, 3); 
a(0, 0) = 1; 
a(0, 1) = 2; 
a(0, 2) = 3; 
a(1, 0) = 4; 
a(1, 1) = 5; 
a(1, 2) = 6; 
matrix<double> r(3, 2, a.data()); 

for (int i = 0;i < 3;++i) 
{ 
    for (int j = 0;j < 2;++j) 
    std::cout << r(i, j) << ", "; 
    std::cout << std::endl; 
} 

1, 2,

3, 4,

5, 6,

1

Bardzo lekkie, łatwe do wykorzystania biblioteki liniowej algebry C++ jest Armadillo i zapewnia funkcjonalność reshape.

#include <armadillo> 
using namespace arma; 
int main() 
{ 
    // C++11 
    // mat a = { { 1, 2, 3 }, 
    // { 4, 5, 6 } }; 

    // C++98 
    mat a; 
    a << 1 << 2 << 3 << endr 
     << 2 << 4 << 6 << endr; 

    a.reshape(3, 2); 
    a.print(); 

    return 0; 
} 

Uwaga: Sugeruję, aby nie zrobić using namespace arma; i zamiast zrobić arma::mat i arma::endr, itd. Zrobiłem to na przykładzie tak dla jasności.

Powiązane problemy