Skip to content

Instantly share code, notes, and snippets.

@valmat
Created February 8, 2022 11:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save valmat/6a737cc3783449c4f7a829e77c77393e to your computer and use it in GitHub Desktop.
Save valmat/6a737cc3783449c4f7a829e77c77393e to your computer and use it in GitHub Desktop.
Entropies benchmark
#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