Namespaces
Variants

std::transform_reduce

De fr.cppreference.net
 
 
Bibliothèque d'algorithmes
Algorithmes contraints et algorithmes sur les plages (C++20)
Algorithmes contraints, p. ex. ranges::copy, ranges::sort, ...
Opérations de séquence non modificatrices    
Opérations par lots
(C++17)
Opérations de recherche
Opérations de séquence modificatrices
Opérations de copie
(C++11)
(C++11)
Opérations d'échange
Opérations de transformation
Opérations de génération
Opérations de suppression
Opérations de changement d'ordre
(jusqu'à C++17)(C++11)
(C++20)(C++20)
Opérations d'échantillonnage
(C++17)

Opérations de tri et apparentées
Opérations de partitionnement
(C++11)    

Opérations de tri
Opérations de recherche binaire
(sur des plages partitionnées)
Opérations d'ensemble (sur des plages triées)
Opérations de fusion (sur des plages triées)
Opérations de tas
Opérations de minimum/maximum
(C++11)
(C++17)
Opérations de comparaison lexicographique
Opérations de permutation


 
 
Défini dans l'en-tête <numeric>
template< class InputIt1, class InputIt2, class T >
T transform_reduce( InputIt1 first1, InputIt1 last1,
                    InputIt2 first2, T init );
(1) (depuis C++17)
(constexpr depuis C++20)
template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2, class T >
T transform_reduce( ExecutionPolicy&& policy,
                    ForwardIt1 first1, ForwardIt1 last1,
                    ForwardIt2 first2, T init );
(2) (depuis C++17)
template< class InputIt1, class InputIt2, class T,
          class BinaryOp1, class BinaryOp2 >
T transform_reduce( InputIt1 first1, InputIt1 last1,
                    InputIt2 first2, T init,
                    BinaryOp1 reduce, BinaryOp2 transform );
(3) (depuis C++17)
(constexpr depuis C++20)
template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2, class T,
          class BinaryOp1, class BinaryOp2 >
T transform_reduce( ExecutionPolicy&& policy,
                    ForwardIt1 first1, ForwardIt1 last1,
                    ForwardIt2 first2, T init,
                    BinaryOp1 reduce, BinaryOp2 transform );
(4) (depuis C++17)
template< class InputIt, class T,
          class BinaryOp, class UnaryOp >
T transform_reduce( InputIt first, InputIt last, T init,
                    BinaryOp reduce, UnaryOp transform );
(5) (depuis C++17)
(constexpr depuis C++20)
template< class ExecutionPolicy,
          class ForwardIt, class T,
          class BinaryOp, class UnaryOp >
T transform_reduce( ExecutionPolicy&& policy,
                    ForwardIt first, ForwardIt last, T init,
                    BinaryOp reduce, UnaryOp transform );
(6) (depuis C++17)
1) Équivalent à
transform_reduce(first1, last1, first2, init,
                 std::plus<>(), std::multiplies<>())
, version effectivement parallélisée du std::inner_product.
3) Applique transform à chaque paire d'éléments des plages [first1last1) et de la plage de std::distance(first1, last1) éléments commençant à first2 et réduit les résultats (éventuellement permutés et agrégés de manière non spécifiée) avec la valeur initiale init sur reduce.
Le résultat est non déterministe si le reduce n'est pas associatif ou commutatif (comme l'addition en virgule flottante).
Si l'une des valeurs suivantes n'est pas convertible en T, le programme est mal formé :
  • reduce(init, init)
  • reduce(init, transform(*first1, *first2))
  • reduce(transform(*first1, *first2), init)
  • reduce(transform(*first1, *first2), transform(*first1, *first2))
Étant donné last2 comme le std::distance(first1, last1)ième itérateur suivant de first2, si l'une des conditions suivantes est satisfaite, le comportement est indéfini :
  • T n'est pas MoveConstructible.
  • transform ou reduce modifie un élément de [first1last1) ou [first2last2).
  • transform ou reduce invalide tout itérateur ou sous-plage de [first1last1] ou [first2last2].
5) Applique transform à chaque élément de la plage [firstlast) et réduit les résultats (éventuellement permutés et agrégés de manière non spécifiée) avec la valeur initiale init sur reduce.
Le résultat est non déterministe si le reduce n'est pas associatif ou commutatif (comme l'addition en virgule flottante).
Si l'une des valeurs suivantes n'est pas convertible en T, le programme est mal formé :
  • reduce(init, init)
  • reduce(init, transform(*first))
  • reduce(transform(*first), init)
  • reduce(transform(*first), transform(*first))
Si l'une des conditions suivantes est satisfaite, le comportement est indéfini :
  • T n'est pas MoveConstructible.
  • transform ou reduce modifie un élément de [firstlast).
  • transform ou reduce invalide tout itérateur ou sous-plage de [firstlast].
2,4,6) Identique à (1,3,5), mais exécutée selon policy.
Ces surcharges participent à la résolution de surcharge uniquement si la valeur de l'expression suivante est true :

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>

(jusqu'à C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>

(depuis C++20)

Paramètres

first1, last1 - la paire d'itérateurs définissant l'intervalle des éléments à prendre comme opérande gauche de transform
first2 - le début de l'intervalle des éléments à prendre comme opérande droit de transform
first, last - la paire d'itérateurs définissant l'intervalle des éléments à prendre comme opérande de transform
init - la valeur initiale de la somme généralisée
policy - la politique d'exécution à utiliser
reduce - le FunctionObject binaire qui sera appliqué dans un ordre non spécifié aux résultats de transform , aux résultats d'autres reduce et à init .
transform - le FunctionObject unaire ou binaire qui sera appliqué à chaque élément du/des intervalle(s) d'entrée. Le type de retour doit être acceptable en entrée de reduce .
Exigences de type
-
InputIt1, InputIt2, InputIt doivent satisfaire aux exigences de LegacyInputIterator .
-
ForwardIt1, ForwardIt2, ForwardIt doivent satisfaire aux exigences de LegacyForwardIterator .

Valeur de retour

1,2) La somme généralisée de init et values sur std:: plus <> ( ) , où values sont les valeurs transformées par std:: multiplies <> ( ) , chaque valeur étant transformée à partir d'une paire d'éléments des deux plages d'entrée.
3,4) La somme généralisée de init et values sur reduce , où values sont les valeurs transformées par transform , chaque valeur étant transformée à partir d'une paire d'éléments des deux plages d'entrée.
5,6) La somme généralisée de init et values sur reduce , où values sont les valeurs transformées par transform , chaque valeur étant transformée à partir d'un élément de la plage d'entrée.

La somme généralisée d'un groupe d'éléments sur une opération binaire binary_op est définie comme suit :

  • Si le groupe ne contient qu'un seul élément, la somme est la valeur de cet élément.
  • Sinon, effectue les opérations suivantes dans l'ordre :
  1. Prend deux éléments quelconques elem1 et elem2 du groupe.
  2. Calcule binary_op ( elem1, elem2 ) et replace le résultat dans le groupe.
  3. Répète les étapes 1 et 2 jusqu'à ce qu'il ne reste qu'un seul élément dans le groupe.

Complexité

Étant donné N comme std:: distance ( first1, last1 ) (ou std:: distance ( first, last ) pour les surcharges (5,6) ):

1,2) O(N) applications de std:: plus <> ( ) et std:: multiplies <> ( ) respectivement.
3-6) O(N) applications de reduce et transform respectivement.

Exceptions

Les surcharges avec un paramètre de modèle nommé ExecutionPolicy signalent les erreurs comme suit :

  • Si l'exécution d'une fonction invoquée dans le cadre de l'algorithme lève une exception et que ExecutionPolicy fait partie des politiques standard , std::terminate est appelée. Pour tout autre ExecutionPolicy , le comportement est défini par l'implémentation.
  • Si l'algorithme ne parvient pas à allouer de la mémoire, std::bad_alloc est levée.

Notes

transform n'est jamais appliqué à init .

Si first == last ou first1 == last1 , init est retourné, non modifié.

Exemple

transform_reduce peut être utilisé pour paralléliser std::inner_product . Certains systèmes peuvent nécessiter un support supplémentaire pour tirer parti de l'exécution parallèle. Par exemple, sur GNU/Linux, Intel TBB doit être installé et l'option - ltbb doit être fournie au compilateur gcc/clang.

#if PARALLEL
#include <execution>
#define PAR std::execution::par,
#else
#define PAR
#endif
#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <locale>
#include <numeric>
#include <vector>
// to parallelize non-associate accumulative operation, you'd better choose
// transform_reduce instead of reduce; e.g., a + b * b != b + a * a
void print_sum_squared(long const num)
{
    std::cout.imbue(std::locale{"en_US.UTF8"});
    std::cout << "num = " << num << '\n';
    // create an immutable vector filled with pattern: 1,2,3,4, 1,2,3,4 ...
    const std::vector<long> v{[n = num * 4] {
        std::vector<long> v;
        v.reserve(n);
        std::generate_n(std::back_inserter(v), n,
            [i = 0]() mutable { return 1 + i++ % 4; });
        return v;
    }()};
    auto squared_sum = [](auto sum, auto val) { return sum + val * val; };
    auto sum1 = std::accumulate(v.cbegin(), v.cend(), 0L, squared_sum);
    std::cout << "accumulate(): " << sum1 << '\n';
    auto sum2 = std::reduce(PAR v.cbegin(), v.cend(), 0L, squared_sum);
    std::cout << "reduce(): " << sum2 << '\n';
    auto sum3 = std::transform_reduce(PAR v.cbegin(), v.cend(), 0L, std::plus{},
                                      [](auto val) { return val * val; });
    std::cout << "transform_reduce(): " << sum3 << "\n\n";
}
int main()
{
    print_sum_squared(1);
    print_sum_squared(1'000);
    print_sum_squared(1'000'000);
}

Sortie possible :

num = 1
accumulate(): 30
reduce(): 30
transform_reduce(): 30
num = 1,000
accumulate(): 30,000
reduce(): -7,025,681,278,312,630,348
transform_reduce(): 30,000
num = 1,000,000
accumulate(): 30,000,000
reduce(): -5,314,886,882,370,003,032
transform_reduce(): 30,000,000
// Compile-options for parallel execution on POSIX:
// g++ -O2 -std=c++17 -Wall -Wextra -pedantic -DPARALLEL ./example.cpp -ltbb -o tr; ./tr

Voir aussi

additionne ou plie une plage d'éléments
(modèle de fonction)
applique une fonction à une plage d'éléments et stocke les résultats dans une plage de destination
(modèle de fonction & objet fonction d'algorithme)
(C++17)
similaire à std::accumulate, mais sans ordre
(modèle de fonction)