Reduction operations#

Demonstrates use of custom reduction functions.

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
#include <mpl/mpl.hpp>

// calculate the least common multiple of two arguments
template<typename T>
class lcm {
  // helper: calculate greatest common divisor
  T gcd(T a, T b) {
    constexpr T zero{};
    if (a < zero)
      a = -a;
    if (b < zero)
      b = -b;
    while (b > zero) {
      const T t{a % b};
      a = b;
      b = t;
    }
    return a;
  }

public:
  T operator()(T a, T b) {
    constexpr T zero{};
    const T t{(a / gcd(a, b)) * b};
    if (t < zero)
      return -t;
    return t;
  }
};

int main() {
  const mpl::communicator &comm_world{mpl::environment::comm_world()};
  // generate data
  std::mt19937_64 g(std::time(nullptr) * comm_world.rank());  // random seed
  std::uniform_int_distribution uniform{1, 12};
  const int n{8};
  // populate vector with random data
  std::vector<int> v(n);
  std::generate(v.begin(), v.end(), [&g, &uniform]() { return uniform(g); });
  // calculate the least common multiple and send result to rank 0
  mpl::contiguous_layout<int> layout(n);
  if (comm_world.rank() == 0) {
    std::vector<int> result(n);
    // calculate the least common multiple
    comm_world.reduce(lcm<int>(), 0, v.data(), result.data(), layout);
    // to check the result display data from all ranks
    std::cout << "Arguments:\n";
    for (int r{0}; r < comm_world.size(); ++r) {
      if (r > 0)
        comm_world.recv(v.data(), layout, r);
      for (auto i : v)
        std::cout << i << '\t';
      std::cout << '\n';
    }
    // display results of global reduction
    std::cout << "\nResults:\n";
    for (auto i : result)
      std::cout << i << '\t';
    std::cout << '\n';
  } else {
    // calculate the least common multiple
    comm_world.reduce(lcm<int>(), 0, v.data(), layout);
    // send data to rank 0 for display
    comm_world.send(v.data(), layout, 0);
  }
  return EXIT_SUCCESS;
}

Demonstrates use of reduction functions for std::pair to determine a minimum as its location.

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <random>
#include <mpl/mpl.hpp>

// data type to store the data and the position of the global minimum
using pair_t = std::pair<double, int>;

int main() {
  const mpl::communicator &comm_world{mpl::environment::comm_world()};
  // generate data
  std::mt19937_64 g(std::time(nullptr) * comm_world.rank());  // random seed
  std::uniform_real_distribution<> uniform;
  const int n{8};
  // populate vector with random data
  std::vector<pair_t> v(n);
  std::generate(v.begin(), v.end(), [&comm_world, &g, &uniform]() {
    return std::make_pair(uniform(g), comm_world.rank());
  });
  // calculate minimum and its location and send result to rank root
  const int root {0};
  mpl::contiguous_layout<pair_t> layout(n);
  if (comm_world.rank() == root) {
    std::vector<pair_t> result(n);
    // calculate minimum
    comm_world.reduce(mpl::min<pair_t>(), root, v.data(), result.data(), layout);
    // display data from all ranks
    std::cout << "arguments:\n";
    for (int r{0}; r < comm_world.size(); ++r) {
      if (r > 0)
        comm_world.recv(v.data(), layout, r);
      for (auto i : v)
        std::cout << std::fixed << std::setprecision(5) << i.first << ' ' << i.second << '\t';
      std::cout << '\n';
    }
    // display results of global reduction
    std::cout << "\nresults:\n";
    for (const pair_t &i : result)
      std::cout << std::fixed << std::setprecision(5) << i.first << ' ' << i.second << '\t';
    std::cout << '\n';
  } else {
    // calculate minimum and its location and send result to rank 0
    comm_world.reduce(mpl::min<pair_t>(), root, v.data(), layout);
    // send data to rank 0 for display
    comm_world.send(v.data(), layout, root);
  }
  return EXIT_SUCCESS;
}