Search code examples
c++boostboost-multi-array

How to take subarray from 2d Boost.MultiArray?


I am working on a program where I need to use 2d Boost.MultiArray. I managed to initialize it and fill it with data. But I don't understand how to take subarray of size i,j if multiarray is of size m,n. Where i<=m and j<=n. Can anyone help me?
Code:

matrix_type matrix(boost::extents[width][height]);
        read_matrix_from_file(file_content, matrix);
for (int rank = 1; rank < workers; rank++) {
            auto subarray_size = (rest > 0) ? lines_per_worker + 1 : lines_per_worker;
            rest--;

            typedef boost::multi_array_types::index_range range;


            size_t finish_line = subarray_size + bias - 1;
            finish_line = (finish_line==bias)? finish_line+1:finish_line;


            matrix_type::array_view<2>::type
                    current_process_batch = matrix[boost::indices[range(bias, subarray_size + bias - 1)][range(0, width)]];
}

Solution

  • Documentation https://www.boost.org/doc/libs/1_73_0/libs/multi_array/doc/user.html#sec_generators

    Boost.MultiArray provides the facilities for creating a sub-view of an already existing array component. It allows you to create a sub-view that retains the same number of dimensions as the original array or one that has less dimensions than the original as well.

    Sub-view creation occurs by placing a call to operator[], passing it an index_gen type. The index_gen is populated by passing index_range objects to its operator[]. The index_range and index_gen types are defined in the multi_array_types namespace and as nested members of every array type. Similar to boost::extents, the library by default constructs the object boost::indices. You can suppress this object by defining BOOST_MULTI_ARRAY_NO_GENERATORS before including the library header. A simple sub-view creation example follows.

    Sample:

    Live On Coliru

    #include <boost/multi_array.hpp>
    #include <iostream>
    
    template <typename Ma>
    auto dump(Ma const& r) -> std::enable_if_t<1 == Ma::dimensionality> {
        for (auto c: r)
            std::cout << " " << c;
        std::cout << "\n";
    }
    
    template <typename Ma>
    auto dump(Ma const& ma) -> std::enable_if_t<2 == Ma::dimensionality> {
        for (auto const& r: ma)
            dump(r);
    }
    
    int main() {using range = boost::multi_array_types::index_range;
        using boost::extents;
        using boost::indices;
    
        auto mn = extents[7][4];
        boost::multi_array<int, 2> ma(mn);
    
        // fill with numbers from 10..37
        std::iota(ma.data(), ma.data() + ma.num_elements(), 10);
    
        dump(ma);
    
        std::cout << "Slice [3..5][1..3]\n";
        dump(ma[ indices[range(3,5)][range(1,3)] ]);
    
        std::cout << "Slice [2..4][2..3]\n";
        dump(ma[ indices[range(2,4)][range(2,3)] ]);
    
        std::cout << "Slice [1,3,5][2..3]\n";
        dump(ma[ indices[range(1,7,2)][range(2,3)] ]);
    
        std::cout << "Degenerate views (reduced dimensionality):\n";
        std::cout << "Slice [1,3,5][2]\n";
        dump(ma[ indices[range(1,7,2)][2] ]);
    
        std::cout << "Slice [0][1,3]\n";
        dump(ma[ indices[0][range(1,4,2)] ]);
    }
    

    Prints

     10 11 12 13
     14 15 16 17
     18 19 20 21
     22 23 24 25
     26 27 28 29
     30 31 32 33
     34 35 36 37
    Slice [3..5][1..3]
     23 24
     27 28
    Slice [2..4][2..3]
     20
     24
    Slice [1,3,5][2..3]
     16
     24
     32
    Degenerate views (reduced dimensionality):
    Slice [1,3,5][2]
     16 24 32
    Slice [0][1,3]
     11 13
    

    UPDATE

    Re. Comment:

    if you want to avoid the degenerate dimensions, here's how:

    Live On Coliru

    std::cout << "Degenerate views (reduced dimensionality):\n";
    std::cout << "Slice [1,3,5][2]\n";
    dump(ma[ indices[range(1,7,2)][2] ]);
    
    std::cout << "Slice [0][1,3]\n";
    dump(ma[ indices[0][range(1,4,2)] ]);
    
    // RE: Comment
    std::cout << "NON-Degenerate views (reduced dimensionality):\n";
    std::cout << "Slice [1,3,5][2]\n";
    dump(ma[ indices[range(1,7,2)][range(2,3)] ]);
    
    std::cout << "Slice [0][1,3]\n";
    dump(ma[ indices[range(0,1)][range(1,4,2)] ]);
    

    Prints

    Degenerate views (reduced dimensionality):
    Slice [1,3,5][2]
     16 24 32
    Slice [0][1,3]
     11 13
    NON-Degenerate views (reduced dimensionality):
    Slice [1,3,5][2]
     16
     24
     32
    Slice [0][1,3]
     11 13
    

    Basically, don't use literals [i][j] but [range(i,i+1)][range(j,j+1)]