/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2021 Willem Elbers (whe@willemelbers.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
******************************************************************************/
/* Config parameters. */
#include
/* Some standard headers */
#include
#include
/* Includes. */
#include "neutrino/Default/fermi_dirac.h"
#include "swift.h"
/* Riemann function zeta(3) and zeta(5) */
#define M_ZETA_3 1.2020569031595942853997
#define M_ZETA_5 1.0369277551433699263314
int main(int argc, char *argv[]) {
/* Exact integrals of x^n / (exp(x) + 1) on (0, infinity) */
double integral2 = M_ZETA_3 * 1.5;
double integral3 = M_PI * M_PI * M_PI * M_PI * 7.0 / 120.0;
double integral4 = M_ZETA_5 * 22.5;
double integral5 = M_PI * M_PI * M_PI * M_PI * M_PI * M_PI * 31. / 252.0;
/* Exact moments */
double mu = integral3 / integral2;
double mu2 = mu * mu;
double sigma2 = integral4 / integral2 - mu2;
double sigma = sqrt(sigma2);
double sigma3 = sigma2 * sigma;
double skewns = (integral5 / integral2 - 3 * mu * sigma2 - mu2 * mu) / sigma3;
/* Print FermiDirac(n) for n = 1, 2, 3 for external testing */
message("fermi_dirac(1) = %e", neutrino_seed_to_fermi_dirac(1));
message("fermi_dirac(2) = %e", neutrino_seed_to_fermi_dirac(2));
message("fermi_dirac(3) = %e\n", neutrino_seed_to_fermi_dirac(3));
/* Generate Fermi-Dirac numbers and compute the sum, min, and max */
int N = 1e7;
double sum = 0;
double min = FLT_MAX, max = 0;
long long seed = 290009001901;
for (int i = 0; i < N; i++) {
double x = neutrino_seed_to_fermi_dirac(seed + i);
sum += x;
if (x < min) min = x;
if (x > max) max = x;
}
/* Do a second pass for the sample variance and skewness */
double mean = sum / N;
double ss_sum = 0;
double sss_sum = 0;
/* We also construct a histogram */
int bins = 1000;
int *histogram1 = (int *)calloc(bins + 1, sizeof(int));
/* Generate the same numbers again and compute statistics and histogram */
for (int i = 0; i < N; i++) {
double x = neutrino_seed_to_fermi_dirac(seed + i);
ss_sum += (x - mean) * (x - mean);
sss_sum += (x - mean) * (x - mean) * (x - mean);
int bin = (int)((x - min) / (max - min) * bins);
histogram1[bin]++;
}
/* Sample statistics */
double var = ss_sum / (N - 1);
double sdev = sqrt(var);
double mu3 = sss_sum / (N - 2) / (var * sdev);
/* Relative errors with the exact moments */
double err_mu = mean / mu - 1.;
double err_sig = var / sigma2 - 1.;
double err_skew = mu3 / skewns - 1.;
message("Sample mean is %f, exact: %f (rel. %e).", mean, mu, err_mu);
message("Sample variance is %f, exact: %f (rel. %e).", var, sigma2, err_sig);
message("Sample skewness is %f, exact: %f (rel. %e).", mu3, skewns, err_skew);
assert(fabs(err_mu) < 1e-3);
assert(fabs(err_sig) < 1e-2);
assert(fabs(err_skew) < 1e-2);
/* Construct Kolmogorov-Smirnov statistic by integrating the histogram */
double sum_empirical = 0.;
double sum_analytical = 0.;
double KS_statistic = 0.;
double dx = (max - min) / bins;
for (int bin = 0; bin < bins; bin++) {
double x = min + (bin + 0.5) * dx;
sum_empirical += histogram1[bin] * 1. / N;
sum_analytical += fermi_dirac_density(x) * x * x * dx / integral2;
double delta = fabs(sum_empirical - sum_analytical);
if (delta > KS_statistic) {
KS_statistic = delta;
}
}
/* Can we reject the hypothesis that these numbers are FD distributed? */
double crit_val = 5.146991e-05 * sqrt(1e9 / N); // 99% confidence level
message("KS statistic = %e (99%% that KS < %e)\n", KS_statistic, crit_val);
/* We should not reject this */
assert(KS_statistic < crit_val);
free(histogram1);
message("Success.");
return 0;
}