Funkcja sumowania dla Boost.MultiArray w C ++

Oct 29 2020

To jest pytanie uzupełniające dla funkcji sumowania dla implementacji arbitralnego zagnieżdżonego wektora w C ++ i funkcji sumowania dla różnych typów zagnieżdżonych implementacji w języku C ++ . Próbuję zaimplementować recursive_sumfunkcję dla Boost Multidimensional Array Library . Celem tej recursive_sumfunkcji jest podsumowanie każdego elementu w boost::multi_arraydanych wejściowych . Struktura rekurencyjna w tym miejscu jest podobna do poprzedniej implementacji for std::vectori innego typu zagnieżdżonego iterowalnego. Co więcej, okazało się, że istnieje kilka rodzajów w tym boost::multi_array, boost::detail::multi_array::sub_arraya boost::detail::multi_array::const_sub_arrayw bibliotece Boost.MultiArray. Próbuję obsłużyć te typy z wieloma funkcjami przeciążenia, jak poniżej.

template<class T> requires is_summable<T>
auto recursive_sum(const T& input)
{
    return input;
}

//  Deal with the boost::multi_array case
template<class T, std::size_t Dims> requires is_summable<T>
auto recursive_sum(const boost::detail::multi_array::const_sub_array<T, Dims>& input)
{
    T sum_output{};
    for (typename boost::multi_array<T, Dims>::index i = 0; i < input.shape()[0]; i++)
    {
        sum_output += recursive_sum(input[i]);
    }
    return sum_output;
}

//  Deal with the boost::multi_array case
template<class T, std::size_t Dims> requires is_summable<T>
auto recursive_sum(const boost::detail::multi_array::sub_array<T, Dims>& input)
{
    T sum_output{};
    for (typename boost::multi_array<T, Dims>::index i = 0; i < input.shape()[0]; i++)
    {
        sum_output += recursive_sum(input[i]);
    }
    return sum_output;
}

//  Deal with the boost::multi_array case
template<class T, std::size_t Dims> requires is_summable<T>
auto recursive_sum(boost::multi_array<T, Dims>& input)
{
    T sum_output{};
    for (typename boost::multi_array<T, Dims>::index i = 0; i < input.shape()[0]; i++)
    {
        sum_output += recursive_sum(input[i]);
    }
    return sum_output;
}

Zastosowana is_summablekoncepcja:

template<typename T>
concept is_summable = requires(T x) { x + x; };

Test dla tej recursive_sumfunkcji:

int main()
{
    // Create a 3D array that is 3 x 4 x 2
    typedef boost::multi_array<double, 3> array_type;
    typedef array_type::index index;
    array_type A(boost::extents[3][4][2]);

    // Assign values to the elements
    int values = 0;
    for (index i = 0; i != 3; ++i)
        for (index j = 0; j != 4; ++j)
            for (index k = 0; k != 2; ++k)
                A[i][j][k] = values++;
    
    auto recursive_sum_output = recursive_sum(A);
    std::cout << "recursive_sum_output: " << recursive_sum_output;
    
    return 0;
}

Wszelkie sugestie są mile widziane.

  • Które pytanie jest kontynuacją?

    Funkcja sumowania dla implementacji dowolnego zagnieżdżonego wektora w C ++ i

    Funkcja sumowania dla różnego typu, arbitralnie zagnieżdżonych, iterowalnych implementacji w C ++

  • Jakie zmiany wprowadzono w kodzie od ostatniego pytania?

    Poprzednie pytanie dotyczy typowych kontenerów w języku C ++ STL, takich jak std::vector. Główną ideą w tym pytaniu jest próba zaimplementowania innej funkcji sumowania, która może sobie poradzić boost::multi_array.

  • Dlaczego prosi się o nową recenzję?

    Okazało się, że istnieją trzy rodzaje konstrukcji tablicy w bibliotece Boost.MultiArray które są boost::multi_array, boost::detail::multi_array::sub_arrayi boost::detail::multi_array::const_sub_array. Aby obsłużyć te różne klasy typów, istnieją trzy funkcje przeciążenia, które recursive_sumobsługują każdy typ osobno. Nie jestem pewien, czy istnieje lepszy sposób na uproszczenie tych funkcji przeciążenia. Ponadto, jeśli jest możliwe ulepszenie tego kodu, daj mi znać.

Odpowiedzi

3 G.Sliepen Oct 29 2020 at 23:59

Zaimplementuj rekurencyjny std::reduce()

Nie powinieneś potrzebować specjalnych przypadków boost::multi_arrayi powiązanych typów, ponieważ te typy działają już jak kontenery STL (zapewniają begin()i end()na przykład). Główny problem polega jednak na tym, jak wydedukować typ zwracanego pliku recursive_sum(). Twoje funkcje wydają się działać, ponieważ wywnioskują Tz a boost::multi_array<T, Dims>, ale czy naprawdę? Twój recursive_sum()powtarza się w wymiarach a multi_array, ale w rzeczywistości nie obsługuje zagnieżdżonych multi_arrays, jak na przykład:

boost::multi_array<boost::multi_array<double, 2>, 3> array;

Powodem jest to, że w powyższym przypadku wywołanie recursive_sum(array)spowoduje, Tże będzie a boost::multi_array<double, 2>zamiast a double.

Aby rozwiązać ten problem, zrobiłbym to, co std::reduce()robi, i omijałby problem, wymagając podania początkowej wartości sumy. Typ tej wartości początkowej będzie również typem zwracanym. Na przykład:

template<class T, class ValueType, class Function = std::plus<ValueType>>
auto recursive_reduce(const T& input, ValueType init, const Function& f)
{
    return f(init, input);
}

template<class Container, class ValueType, class Function = std::plus<ValueType>>
requires is_iterable<Container>
auto recursive_reduce(const Container& input, ValueType init, const Function& f = std::plus<ValueType>())
{
    for (const auto &element: input) {
        auto result = recursive_reduce(element, ValueType{}, f);
        init = f(init, result);
    }

    return init;
}

Następnie możesz to nazwać tak:

boost::multi_array<...> array(...);
std::cout << recursive_reduce(array, 0.0) << "\n";

Być może mógłbyś napisać jakiś szablon, aby znaleźć najbardziej wewnętrzny typ wartości, aby móc go użyć jako wartości domyślnej dla parametru szablonu ValueTypew recursive_reduce(), a następnie użyć {}jako wartości domyślnej dla initi móc pisać:

std::cout << recursive_reduce(array) << "\n";