// Copyright (C) 2026 Kiyotsugu Arai
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// example_random.cpp
// Random engines, probability distributions (pdf/cdf/quantile/moments +
// sampling), and quasi-random (Halton) low-discrepancy sequences.

#include <math/random/random.hpp>
#include <math/random/distributions.hpp>
#include <math/random/quasi_random.hpp>
#include <iomanip>
#include <iostream>
#include <random>

using namespace sangi;

int main() {
    std::cout << std::setprecision(15);

    std::cout << "=== RandomEngine (reproducible) ===\n";
    RandomEngine eng(42);
    std::cout << "  uniform()       = " << eng.uniform() << "\n";
    std::cout << "  uniform(2,5)    = " << eng.uniform(2.0, 5.0) << "\n";
    std::cout << "  uniformInt(1,6) = " << eng.uniformInt(1, 6) << "\n";

    std::cout << "\n=== NormalDistribution N(0,1): closed-form values ===\n";
    NormalDistribution<double> nd(0.0, 1.0);
    std::cout << "  mean/var   = " << nd.mean() << " / " << nd.variance() << "\n";
    std::cout << "  pdf(0)     = " << nd.pdf(0.0) << "\n";
    std::cout << "  cdf(0)     = " << nd.cdf(0.0) << "\n";
    std::cout << "  quantile(0.975) = " << nd.quantile(0.975) << "\n";

    std::cout << "\n=== discrete distributions ===\n";
    PoissonDistribution<double> pd(3.0);
    BinomialDistribution<double> bd(10, 0.5);
    std::cout << "  Poisson(3)  mean/var = " << pd.mean() << " / " << pd.variance() << "\n";
    std::cout << "  Binom(10,.5) mean/var = " << bd.mean() << " / " << bd.variance()
              << ", pmf(5) = " << bd.pmf(5) << "\n";

    std::cout << "\n=== sampling (Monte Carlo) ===\n";
    std::mt19937 gen(12345);
    NormalDistribution<double> g(2.0, 0.5);
    double s = 0.0;
    const int N = 100000;
    for (int i = 0; i < N; ++i) s += g.sample(gen);
    std::cout << "  N(2,0.5) sample mean (N=1e5) ~ " << (s / N) << "\n";

    std::cout << "\n=== quasi-random: Halton (bases 2,3) ===\n";
    HaltonSequence<2> h;
    for (int i = 0; i < 4; ++i) {
        auto p = h.next();
        std::cout << "  p" << i << " = (" << p[0] << ", " << p[1] << ")\n";
    }

    return 0;
}
