Created
February 8, 2022 11:32
-
-
Save valmat/6a737cc3783449c4f7a829e77c77393e to your computer and use it in GitHub Desktop.
Entropies benchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <cmath> | |
#include <chrono> | |
struct BenchResult | |
{ | |
std::chrono::nanoseconds duration; | |
double sum; | |
}; | |
double entropyShannon(double p) noexcept | |
{ | |
double q = 1.0 - p; | |
return (p > 0.0 && p < 1.0) ? -(p * log(p) + q * log(q)) : 0.0; | |
} | |
double entropyRenyi_1_2(double p) noexcept | |
{ | |
double q = 1.0 - p; | |
return (p > 0.0 && p < 1.0) ? 2.0 * log(sqrt(p) + sqrt(q)) : 0.0; | |
} | |
double entropyRenyi_1_4(double p) noexcept | |
{ | |
double q = 1.0 - p; | |
return (p > 0.0 && p < 1.0) ? 4.0 / 3.0 * log(sqrt(sqrt(p)) + sqrt(sqrt(q))) : 0.0; | |
} | |
double entropyRenyi_1_8(double p) noexcept | |
{ | |
double q = 1.0 - p; | |
return (p > 0.0 && p < 1.0) ? 8.0 / 7.0 * log(sqrt(sqrt(sqrt(p))) + sqrt(sqrt(sqrt(q)))) : 0.0; | |
} | |
double entropyRenyi_3_4(double p) noexcept | |
{ | |
double q = 1.0 - p; | |
return (p > 0.0 && p < 1.0) ? 4.0 * log(sqrt(sqrt(p*p*p)) + sqrt(sqrt(q*q*q))) : 0.0; | |
} | |
double entropyRenyi_2(double p) noexcept | |
{ | |
double q = 1.0 - p; | |
return (p > 0.0 && p < 1.0) ? -log(p*p + q*q) : 0.0; | |
} | |
double entropyRenyi_5(double p) noexcept | |
{ | |
double q = 1.0 - p; | |
double pp = p*p, qq = q*q; | |
return (p > 0.0 && p < 1.0) ? -0.25 * log(pp*pp*p + qq*qq*q) : 0.0; | |
} | |
double entropyRenyi_10(double p) noexcept | |
{ | |
double q = 1.0 - p; | |
return (p > 0.0 && p < 1.0) ? -1.0/9.0 * log(p*p*p*p*p*p*p*p*p*p + q*q*q*q*q*q*q*q*q*q) : 0.0; | |
} | |
using ent_t = double (*)(double) noexcept; | |
template<ent_t fun> | |
[[gnu::noinline]] | |
BenchResult benchmark(size_t count) noexcept | |
{ | |
auto before = std::chrono::high_resolution_clock::now(); | |
double h = 1.0 / (count - 1); | |
double sum = 0.0; | |
for (size_t i = 0; i < count; ++i) { | |
sum += fun(h * i); | |
} | |
auto after = std::chrono::high_resolution_clock::now(); | |
return BenchResult{after - before, sum / count}; | |
} | |
std::ostream& operator<<(std::ostream& stream, BenchResult result) | |
{ | |
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(result.duration).count(); | |
std::cout << result.duration.count() << "ns \t(" << ms << "ms)\t\t sum: " << result.sum; | |
return stream; | |
} | |
int main() { | |
size_t count = 1000000000; | |
std::cout << "samples : " << count << std::endl; | |
std::cout << "Shannon : " << benchmark<entropyShannon> (count) << std::endl; | |
std::cout << "Renyi_1_2 : " << benchmark<entropyRenyi_1_2> (count) << std::endl; | |
std::cout << "Renyi_1_4 : " << benchmark<entropyRenyi_1_4> (count) << std::endl; | |
std::cout << "Renyi_1_8 : " << benchmark<entropyRenyi_1_8> (count) << std::endl; | |
std::cout << "Renyi_3_4 : " << benchmark<entropyRenyi_3_4> (count) << std::endl; | |
std::cout << "Renyi_2 : " << benchmark<entropyRenyi_2> (count) << std::endl; | |
std::cout << "Renyi_5 : " << benchmark<entropyRenyi_5> (count) << std::endl; | |
std::cout << "Renyi_10 : " << benchmark<entropyRenyi_10> (count) << std::endl; | |
return 0; | |
} | |
// g++ -std=c++17 -pedantic -Wall -Wextra -O3 entropy_benchmark.cpp -o entropy_benchmark.bin | |
// Results: | |
// samples : 1000000000 | |
// Shannon : 10249895206ns (10249ms) sum: 0.5 | |
// Renyi_1_2 : 8677368472ns (8677ms) sum: 0.570796 | |
// Renyi_1_4 : 10421639934ns (10421ms) sum: 0.624029 | |
// Renyi_1_8 : 13235709810ns (13235ms) sum: 0.65659 | |
// Renyi_3_4 : 11403406522ns (11403ms) sum: 0.530643 | |
// Renyi_2 : 7245386547ns (7245ms) sum: 0.429204 | |
// Renyi_5 : 7771674801ns (7771ms) sum: 0.363444 | |
// Renyi_10 : 10809162384ns (10809ms) sum: 0.336404 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment