### Reshape vector

Hi, my task is to reshape a vector in order to build a matrix.
In particular, let say i have a vector of n elements.
Knowing that the number of element n = a*b, i would like to build a matrix with a rows and b columns.
As example, i have 120 elements, i would like to build a matrix of 12 rows and 10 columns.

Thank's
 ``1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950`` ``````#include #include #include #include template < typename T > std::vector< std::vector > to_2d( const std::vector& flat_vec, std::size_t ncols ) { // sanity check if( ncols == 0 || flat_vec.size()%ncols != 0 ) throw std::domain_error( "bad #cols" ) ; const auto nrows = flat_vec.size() / ncols ; std::vector< std::vector > mtx ; const auto begin = std::begin(flat_vec) ; for( std::size_t row = 0 ; row < nrows ; ++row ) mtx.push_back( { begin + row*ncols, begin + (row+1)*ncols } ) ; return mtx ; } int main() { std::vector flat(120) ; std::iota( std::begin(flat), std::end(flat), 100 ) ; for( const auto& row : to_2d( flat, 12 ) ) // 10 x 12 { for( int v : row ) std::cout << v << ' ' ; std::cout << '\n' ; } std::cout << "---------------------------\n" ; for( const auto& row : to_2d( flat, 20 ) ) // 6 x 20 { for( int v : row ) std::cout << v << ' ' ; std::cout << '\n' ; } std::cout << "---------------------------\n" ; try { for( const auto& row : to_2d( flat, 17 ) ) // bad ncols { for( int v : row ) std::cout << v << ' ' ; std::cout << '\n' ; } } catch( const std::exception& e ) { std::cerr << "*** error: " << e.what() << '\n' ; } }``````

http://coliru.stacked-crooked.com/a/526a926f498d10de
Thank you a lot for the explanation. I'm really new on C++, there is a way to describe more in detail the code?
Thank you.
Vittorio
 ``12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394`` ``````#include #include #include #include // split a flat vector containing nrows*ncols elements into a two dimensional matrix // T is (a placeholder for) the type of the values in the vector template < typename T > // for example, for std:vector, T would be int std::vector< std::vector > to_2d( const std::vector& flat_vec, std::size_t ncols ) { // ncols is the number of cols in the matrix // the size of the flat vector must be an integral multiple of some non-zero ncols // if the check fails, report an error (by throwing an exception) if( ncols == 0 || flat_vec.size()%ncols != 0 ) throw std::domain_error( "bad #cols" ) ; // compute the number of rows in the matrix ie. flat_vec.size() == nrows * ncols const auto nrows = flat_vec.size() / ncols ; // declare an empty matrix. eventually, we build this up to an nrows x ncols matrix // the final matrix would be a collection of nrows rows // exch row in the matrix would a collection (a vector) containing ncols elements std::vector< std::vector > mtx ; // get an iterator to the beginning of the flat vector // http://en.cppreference.com/w/cpp/iterator/begin // if you are unfamiliar with iterators, see: https://cal-linux.com/tutorials/STL.html const auto begin = std::begin(flat_vec) ; // add rows one by one to the matrix for( std::size_t row = 0 ; row < nrows ; ++row ) // for each row [0,nrows-1] in the matrix { // add the row (a vector of ncols elements) // for example, if ncols = 12, // row 0 would contain elements in positions 0, 1, 2, ...10, 11 ie. [0,12) // row 1 would contain elements in positions 12, 13, ...23 ie. [12,24) // row 2 would contain elements in positions 24, 25, ...35 ie. [24,36) // in general, row r would contain elements at positions [ r*12, (r+1)*12 ] mtx.push_back( { begin + row*ncols, begin + (row+1)*ncols } ) ; // the above as akin to: // construct the row containing elements at positions as described earlier // const std::vector this_row( begin + row*ncols, begin + (row+1)*ncols ) ; // mtx.push_back(this_row) ; // and add this row to the back of the vector } return mtx ; // return the fully populated matrix } int main() { std::vector flat(120) ; // vector containing 120 values // http://en.cppreference.com/w/cpp/algorithm/iota std::iota( std::begin(flat), std::end(flat), 100 ) ; // fill it with 100, 101, 102 etc. // to_2d( flat, 12 ) returns a 10 x 12 matrix // range based loop: http://www.stroustrup.com/C++11FAQ.html#for // auto: http://www.stroustrup.com/C++11FAQ.html#auto for( const auto& row : to_2d( flat, 12 ) ) // for each row in the returned matrix { // print each int in that row for( int v : row ) std::cout << v << ' ' ; std::cout << '\n' ; } // note: we could write the above as // const auto mtx = to_2d( flat, 12 ) ; // get the matrix returned by the function // for( const auto& row : mtx ) // for each row in the matrix // { etc... std::cout << "---------------------------\n" ; for( const auto& row : to_2d( flat, 20 ) ) // 6 x 20 { for( int v : row ) std::cout << v << ' ' ; std::cout << '\n' ; } std::cout << "---------------------------\n" ; try // 17 is an invalid value for the number of columns { // to_2d( flat, 17 ) would report an error by throwing an exception // when that happens, control would be transferred to the catch block for( const auto& row : to_2d( flat, 17 ) ) // bad ncols { for( int v : row ) std::cout << v << ' ' ; std::cout << '\n' ; } } catch( const std::exception& e ) // catch the error (exception) { // and print out an error messagr std::cerr << "*** error: " << e.what() << '\n' ; } }``````
Another thought for you:

You don’t actually have to change your data structure. You just need to implement a “view”. It can be simple or complex, however you prefer. Here is a fairly simple one, along with some code to play with it:

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101`` ``````#include #include #include #define EXPAND0(X) X ## 1 #define EXPAND(X) EXPAND0(X) // --- >8 snip ----------------------------------------- // A 1D to 2D view // Missing useful stuff like iterators, etc. template struct view_1D_to_2D_type { Container& container; view_1D_to_2D_type( Container& container ): container(container) { } typedef decltype(container[0]) value_type; std::size_t index( std::size_t row, std::size_t column ) const { return row * Columns + column; } std::size_t rows() const { return Rows; } std::size_t columns() const { return Columns; } value_type& operator () ( std::size_t row, std::size_t column ) const { return container [ index( row, column ) ]; } value_type& at ( std::size_t row, std::size_t column ) const { return container.at( index( row, column ) ); } }; template view_1D_to_2D_type view_1D_to_2D( Container& container ) { return view_1D_to_2D_type ( container ); } // --- snip 8< ----------------------------------------- // Here you can play with the const-ness of the source structures and // the reference type acceptable by the function. #define CONST //const template #if 0 void test( Container& container ) #elif 0 void test( const Container& container ) #elif 1 void test( Container&& container ) #else void test( const Container&& container ) #endif { for (auto r = 0U; r < container.rows(); r++) { for (auto c = 0U; c < container.columns(); c++) std::cout << " " << std::setw(2) << std::left << container( r, c ); std::cout << "\n"; } std::cout << "\n"; } int main() { { std::cout << "test an array\n"; CONST int xs[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; test( view_1D_to_2D <3, 4> ( xs ) ); test( view_1D_to_2D <2, 6> ( xs ) ); #if EXPAND(CONST) std::cout << "swapping (1,1) and (2,1):\n"; auto vs = view_1D_to_2D <4, 3> ( xs ); std::swap( vs( 1, 1 ), vs( 2, 1 ) ); test( vs ); test( view_1D_to_2D <3, 4> ( xs ) ); test( view_1D_to_2D <2, 6> ( xs ) ); #endif } { std::cout << "test a vector\n"; CONST std::vector xs { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; test( view_1D_to_2D <3, 4> ( xs ) ); test( view_1D_to_2D <2, 6> ( xs ) ); #if EXPAND(CONST) std::cout << "swapping (1,1) and (2,1):\n"; auto vs = view_1D_to_2D <4, 3> ( xs ); std::swap( vs( 1, 1 ), vs( 2, 1 ) ); test( vs ); test( view_1D_to_2D <3, 4> ( xs ) ); test( view_1D_to_2D <2, 6> ( xs ) ); #endif } }``````

There might be something in Boost that does this too.
(I haven’t looked lately.)
> There might be something in Boost that does this too

boost::multi_array_ref and boost::const_multi_array_ref have been around for a long time.
http://www.boost.org/doc/libs/1_66_0/libs/multi_array/doc/reference.html#multi_array_ref

C++17 : lines 35 and 47 uses class template argument deduction (legacy C++: change to matrix_view<int>)
 ``12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455`` ``````#include #include #include #include #include template < typename T > struct matrix_view : boost::multi_array_ref { using base = boost::multi_array_ref ; // construct from vector (size check elided for brevity) matrix_view( std::vector& seq, std::size_t nrows, std::size_t ncols ) : base( std::addressof( seq.front() ), boost::extents[nrows][ncols] ) {} template < std::size_t N > // construct from std array (size check elided for brevity) matrix_view( std::array& seq, std::size_t nrows, std::size_t ncols ) : base( std::addressof( seq.front() ), boost::extents[nrows][ncols] ) {} template < std::size_t N > // construct from c-style array (size check elided for brevity) matrix_view( T (&raw_array)[N], std::size_t nrows, std::size_t ncols ) : base( raw_array[0], boost::extents[nrows][ncols] ) {} matrix_view( T* ptr, std::size_t nrows, std::size_t ncols ) // construct from raw pointer : base( ptr, boost::extents[nrows][ncols] ) {} using base::base ; // other constructors are inherited }; int main() { std::vector vec(500) ; std::iota( std::begin(vec), std::end(vec), 100 ) ; { matrix_view mv( vec, 5, 8 ) ; // 5x8 view of the first 40 elements of the vector mv[1][2] = mv[2][3] = mv[3][4] = -99 ; for( const auto& row : mv ) { for( int v : row ) std::cout << v << ' ' ; std::cout << '\n' ; } } std::cout << '\n' ; { matrix_view mv( std::addressof(vec[10]), 6, 4 ) ; // 6x4 view of elements [10,33] of the vector for( const auto& row : mv ) { for( int v : row ) std::cout << v << ' ' ; std::cout << '\n' ; } } }``````

http://coliru.stacked-crooked.com/a/69055dffd6ae34e6
Thank you for the help! Very useful suggestions!
hopefully not repeating anything here but...
matlab's reshape is much easier to do if you use a 1-d container instead of 2-d.
then you just change your class rows/cols members, resize the vector if needed, and shuffle the data to its new locations. If its not too late, 1-d approach simplifies several operations that are a slow to execute and annoying to code in 2-d, including transpose, Identy-append-invert, AXB /RREF solve, reshape, and similar things that can affect the size of your matrix directly.

I know quite well matlab and for a fist test i used the function reshape that is really useful. Anyway for my application i have to use c++ program.
I was saying that to reproduce something like matlab's reshape, use a 1-d construct. In c++. Not that you should use matlab, its a 1/2 million dollar solution to a 10 cent problem :P

using 2-d constructs creates extra work for a number of common operations like this one. Take an extreme example of a 5 by 5 million matrix. To reshape that in 2d, you have to reallocate all the 5s to 5 million and reallocate all the 5 millions down to 5. In 1d, the number of cells is the same, only the way the data is stored is changed, so a O(N) pass doing some swaps and then swap num_rows and num_cols. No memory activity, much faster and cleaner.
Last edited on
> to reproduce something like matlab's reshape

boost::multi_array does support both reshape() and reindex()
http://www.boost.org/doc/libs/1_66_0/libs/multi_array/doc/reference.html#multi_array_class

Though, in well written code, reshape/reindex should be rarely used.

When it is easy to create any number of simultaneous multiple views of the same array, a component that requires a different shape should just create (and, if appropriate, keep) a custom view for its own use.

Instead of unilaterally reshaping the array; instead of insisting that every other component in the program must now start viewing the array in the same way that this anti-social component wants to look at it.
Or, (only in a single threaded program,) incurring the overhead of reshaping the array at the beginning of every function, and then restoring the original shape at the end, all done in an exception safe manner.

 ``123456789101112131415161718192021222324252627282930`` ``````#include #include int main() { int a[2][3][4][5] {} ; // original raw array: 2x3x4x5 auto p_first = std::addressof( a[0][0][0][0] ) ; // 1D view of the same array boost::multi_array_ref v120( p_first, boost::extents[120] ) ; v120[46] = 999 ; // different 2D views of the same array boost::multi_array_ref v15x8( p_first, boost::extents[15][8] ) ; boost::multi_array_ref v6x20( p_first, boost::extents[6][20] ) ; assert( v120[46] == 999 && v15x8[5][6] == v120[46] && v15x8[5][6] == v6x20[2][6] ) ; // different 3D views of the same array boost::multi_array_ref v5x4x6( p_first, boost::extents[5][4][6] ) ; boost::multi_array_ref v10x6x2( p_first, boost::extents[10][6][2] ) ; assert( v10x6x2[3][5][0] == 999 ) ; // different 4D views of the same array boost::multi_array_ref v4x3x5x2( p_first, boost::extents[4][3][5][2] ) ; boost::multi_array_ref v2x6x2x5( p_first, boost::extents[2][6][2][5] ) ; // different 5D views of the same array boost::multi_array_ref v2x3x2x5x2( p_first, boost::extents[2][3][2][5][2] ) ; boost::multi_array_ref v5x2x2x3x2( p_first, boost::extents[5][2][2][3][2] ) ; }``````

http://coliru.stacked-crooked.com/a/2eaaedc12e5b5390
Topic archived. No new replies allowed.