#include "mpi.h"

#include <algorithm>
#include <format>
#include <iostream>
#include <numeric>
#include <random>
#include <vector>

auto makeRandomVector(size_t size) -> std::vector< double >
{
    static auto prng   = std::mt19937{std::random_device{}()};
    static auto dist   = std::uniform_real_distribution< double >{-1., 1.};
    auto        retval = std::vector< double >{};
    retval.reserve(size);
    std::ranges::generate_n(std::back_inserter(retval), size, [&] { return dist(prng); });
    return retval;
}

int main(int argc, char* argv[])
{
    MPI_Init(&argc, &argv);

    constexpr auto local_size    = 1000uz;
    const auto     x             = makeRandomVector(local_size);
    const auto     y             = makeRandomVector(local_size);
    const auto     local_product = std::inner_product(x.begin(), x.end(), y.begin(), 0.);

    double global_product;
    MPI_Allreduce(&local_product, &global_product, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);

    int comm_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &comm_rank);
    std::cout << std::format("Rank {}: local: {:.6f}, global: {:.6f}\n", comm_rank, local_product, global_product);

    MPI_Finalize();
}
