8
votes

Transformer et accumuler

Avez-vous écrit quelqu'un d'un algorithme compatible C ++ stl qui combine std :: transformer et std :: accumule dans un algorithme de passage unique soutenant à la fois les unaires, binaires et peut-être Même (N-Ary!) Variante, disons std :: transformé_accumulez ? Je le souhaite parce que j'ai trouvé ce modèle très réutilisable dans l'exemple de l'algèbre linéaire par exemple dans les calculs de la norme (L1). La norme L1 calcule la somme des valeurs absolues des éléments.


1 commentaires

Si je ne me trompe pas, vous demandez à Mapreduce.


5 Réponses :


11
votes

uhm ... mon pari est que vous pouvez le faire en incorporant votre transformation en prédicat binaire, transmettant l'élément et accumulez après la transformation.

template <typename Transform>
struct transform_accumulator_t {
    Transform t;
    transform_accumulator_t( Transform t ) : t(t) {}
    int operator()( int oldvalue, int newvalue ) const {
        return oldvalue + t(newvalue);
    }
};
// syntactic sugar:
template <typename T>
transform_accumulator_t<T> transform_accumulator( T t ) {
    return transform_accumulator_t<T>(t);
}
int r = std::accumulate(v.begin(), v.end(), 0, transform_accumulator(times2));


2 commentaires

Clever ... Peut-on peut-être simplifier cela en utilisant C ++ 11 Expressions Lambda?


@ Nordlöw: Bien sûr, si votre compilateur les prend en charge :)



2
votes

Bien que cela puisse ne pas correspondre exactement à l'intention d'origine, std :: inner_product code> est fondamentalement votre version binaire. Vous le transmettez une valeur initiale, deux gammes et deux foncteurs, et il les applique comme: xxx pré>

Donc, pour votre L1, vous feriez quelque chose sur cet ordre général: P> xxx pré>

seulement qui ne fonctionne pas tout à fait fonctionner - maintenant, il essaie de passer std :: ABS code> où vous avez vraiment besoin d'une fonction binaire qui combine les deux entrées , mais je ne suis pas sûr de savoir comment les deux entrées sont vraiment censées être combinées. p>

std :: partiel_sum code> est assez proche de votre version unaire, sauf que cela accumule une Résultat, il (tente de) écrire chaque résultat intermédiaire, pas seulement le résultat final. Pour obtenir le résultat final, vous devez écrire (et passer une instance de) une sorte d'itérateur de rien qui ne contient que la valeur unique: p> xxx pré>

avec Ceci, votre normalisation L1 ressemblerait à ceci comme suit: P>

int main(){ 
    double result=0.0;
    double inputs[] = {1, -2, 3, -4, 5, -6};

    std::partial_sum(
        inputs, inputs+6, 
        make_res(result),
        [](double acc, double v) {return acc + std::abs(v);});

    std::cout << result << "\t";
    return 0;
}


5 commentaires

Merci encore plus pour les références pertinentes à d'autres algorithmes stl réutilisables.


Est std :: ajoute () une partie de la norme?


@ Nordlöw: Oups - devrait être std :: plus . Désolé pour ça.


Si les lambdas sont disponibles, je préfère utiliser, disons, [] (t x, t y) {retour x + y; } sur std :: plus ?


@ Nordlöw: Je vais le plus avec ce qui est le plus simple. Dans ce cas, cela semble être plus . L'exception serait si vous utilisez un lot de Lambdas de toute façon, auquel cas un mélange dans quelques foncteurs pré-conçus pourrait conduire à une confusion.



1
votes

Si vous souhaitez utiliser un parallélisme, j'ai fait une version rapide à l'aide d'OpenMP:

double val = MapReduce_n(in, size, 0.0, [] (fftw_complex val)
    {
        return std::pow(val[0], 2.0) + std::pow(val[1], 2.0);
    }, std::plus<double>());


2 commentaires

Agréable! Une chose si ... est std :: pow (X, 2.0) vraiment plus rapide que x * x ?!


Selon celui-ci devrait être inllinée à l'autre Stackoverflow.com/questions/6321170/... . Cependant, je préfère écrire pow car il ressemble plus à la formule, et parce qu'il y a beaucoup d'autres pow dans le logiciel, j'ai suivi ce code source. "Looks" sont cohérents.



1
votes

Je suis surpris que personne a dit comment faire cela avec boost.Range: xxx

où v est un plage de cartes SINGE (c'est-à-dire n'importe quel conteneur STL). La surcharge des ABS doit être spécifiée, sinon cela serait aussi élégant que HASKELLL.


0 commentaires

1
votes

AS de C ++ 17 Il y a aussi std :: transform_reduce , qui bénéficie également d'être parallélizable.

https://fr.cppreference.com/w/cpp/algorithm/transform_reduce


0 commentaires