1

I've tried to use transform_reduce from hpx as given in the Answer https://stackoverflow.com/a/54481320/11008404 but I can't compile it. My code so far:

#include <hpx/hpx_main.hpp>
#include <hpx/hpx.hpp>
#include <hpx/include/parallel_transform_reduce.hpp>
#include <hpx/include/iostreams.hpp>

#include <vector>

class A {
public:
  double residual() {
    // Calculate actual local residual
    double i = 1.0;
    return i;
  }
};

int main() {

  std::vector<A> vec(300);
  double res = hpx::parallel::transform_reduce(hpx::parallel::execution::par,        
                      vec.begin(), vec.end(),                         // (1)
                      [](A& a_ref){ return a_ref.residual(); },       // (2)
                      0, [](double a, double b){ return a + b; });    // (3)

  hpx::cout << "residual: " << res << hpx::endl;

  return 0;
}

The compiler throws this errors:

hpx.cpp:23:65: error: no matching function for call to ‘transform_reduce(const hpx::parallel::execution::parallel_policy&, std::vector<A>::iterator, std::vector<A>::iterator, main()::<lambda(A&)>, int, main()::<lambda(double, double)>)’
                   0, [](double a, double b){ return a + b; });    // (3)

.../include/hpx/parallel/algorithms/transform_reduce.hpp:255:22: error: no type named ‘type’ in ‘struct hpx::util::invoke_result<main()::<lambda(double, double)>, A>’

Has someone a suggestion what is wrong or another solution for the question asked in Parallel reduce (e.g. sum) a vector of hpx::futures<double>?

R2D2
  • 23
  • 6

3 Answers3

2

The signature of transform_reduce has changed several times during the process of its standardization (see here for what got actually standardized: https://en.cppreference.com/w/cpp/algorithm/transform_reduce). I think that in order to compile you just have to get the sequence of arguments right:

#include <hpx/hpx_main.hpp>
#include <hpx/hpx.hpp>
#include <hpx/include/parallel_transform_reduce.hpp>
#include <hpx/include/iostreams.hpp>

#include <vector>

class A {
public:
  double residual() {
    // Calculate actual local residual
    double i = 1.0;
    return i;
  }
};

int main() {

  std::vector<A> vec(300);
  double res = hpx::parallel::transform_reduce(hpx::parallel::execution::par,        
                      vec.begin(), vec.end(),
                      0.,
                      [](double a, double b){ return a + b; },
                      [](A& a_ref){ return a_ref.residual(); });

  hpx::cout << "residual: " << res << hpx::endl;

  return 0;
}
hkaiser
  • 11,403
  • 1
  • 30
  • 35
  • I've tested this solution but it doesn't compile either. I got with both hpx1.2 and hpx1.3 the same error as with the first code. Maybe the note: template argument deduction/substitution failed, in transform_reduce.hpp:265:5 is somehow helpful, but I can't figure it out. – R2D2 Feb 04 '19 at 07:24
  • Sorry, I (again) fell victim to MSVC's glorious problem that it binds const references to non-const references without issuing an error. – hkaiser Feb 04 '19 at 13:04
1

If I change hkaiser's answer to

#include <hpx/hpx_main.hpp>
#include <hpx/hpx.hpp>
#include <hpx/include/parallel_transform_reduce.hpp>
#include <hpx/include/iostreams.hpp>

#include <vector>

class A {
public:
  double residual() const {
    // Calculate actual local residual
    double i = 1.0;
    return i;
  }
};

int main() {

  std::vector<A> vec(300);
  double res = hpx::parallel::transform_reduce(hpx::parallel::execution::par,        
                      vec.begin(), vec.end(),
                      0.,
                      [](double a, double b){ return a + b; },
                      [](const A& a_ref){ return a_ref.residual(); }); // note: const!

  hpx::cout << "residual: " << res << hpx::endl;

  return 0;
}

the code compiles. It also compiles if you pass A by value or as a pointer.

I don't know if this behaviour is intended so i opened an issue on HPX's github (https://github.com/STEllAR-GROUP/hpx/issues/3651)

breyerml
  • 267
  • 2
  • 14
  • N4687 (the last draft of C++17) says in 29.8.5 [transform.reduce]: "Neither unary_op nor binary_op shall invalidate subranges, or modify elements in the range [first, last]." – hkaiser Feb 04 '19 at 13:08
0

I'd like to add that the parallel STL has made it's way into gcc 9 with -std=c++17, just requiring linking with -ltbb (that is Intel's Thread Building Blocks, easily installable on Linux for example using apt).

#include <numeric>
#include <execution>
#include <vector>

class A {
public:
  double residual() {
    // Calculate actual local residual
    double i = 1.0;
    return i;
  }
};

int main() {

  std::vector<A> vec(300);
  double res = std::transform_reduce(std::execution::par,        
                      vec.begin(), vec.end(),
                      0.,
                      [](double a, double b){ return a + b; },
                      [](A& a_ref){ return a_ref.residual(); });

  std::cout << "residual: " << res << std::endl;

  return 0;
}
Romeo Valentin
  • 1,276
  • 1
  • 16
  • 22