feat: add plots for n m k trends

This commit is contained in:
2026-04-27 20:43:23 +02:00
parent 84c0b2b797
commit f6521aeb1c
12 changed files with 226 additions and 71 deletions
+3 -3
View File
@@ -15,8 +15,8 @@ target_include_directories(bloom_filter PUBLIC include)
# doesn't matter for this specific project though
target_compile_features(bloom_filter PUBLIC cxx_std_20)
add_executable(stats_basic_bloom_filter
example/stats_basic_bloom_filter.cpp
add_executable(bloom_filter_stats_csv
plots/data/bloom_filter_stats_csv.cpp
)
target_link_libraries(stats_basic_bloom_filter PRIVATE bloom_filter)
target_link_libraries(bloom_filter_stats_csv PRIVATE bloom_filter)
+11
View File
@@ -127,3 +127,14 @@ bits filled fraction is P(any arbitrary bit is 1)
False positive = all of those bits end up being 1 for some hash = P^k
This has the same independence issue in assumption though.
# Plotting stuff
Found out about gnuplot which I guess is a bit of an overkill having a binary for the whole thing
but fine the plotting itself is easier. In the end the plots came out in line with theoretical which
was great.
# Links
There are many variations for bloom filters that I'll get to implementing and testing _eventually_ which
I hope is soon enough.
-68
View File
@@ -1,68 +0,0 @@
#include "bloom_filter/bloom_filter.hpp"
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <random>
#include <set>
#include <string>
int main(int argc, char *argv[]) {
if (argc != 4) { // REM: 0th ars it the program name
std::cerr << "need args n(number of keys inserted) m(filter size in "
"num bits) k(num hash funcs)";
return 1;
}
uint n = std::stoul(argv[1]);
uint m = std::stoul(argv[2]);
uint k = std::stoul(argv[3]);
// std::random_device rd; you can uncomment and pass it in here to randomise
std::mt19937_64 rng{}; // no seed so this is deterministic
const uint TOTAL_TRIALS = 20;
double sum_theorital_approx_fp_rate = 0;
double sum_filter_approx_fp_rate = 0;
double sum_actual_fp_rate = 0;
for (int _t = 0; _t < TOTAL_TRIALS; _t++) {
uint64_t seed1 = rng(), seed2 = rng();
BloomFilter filter{m, k, seed1, seed2};
std::set<uint64_t> actual_inserts;
for (int i = 0; i < n; i++) {
uint64_t num = rng();
actual_inserts.insert(num);
filter.put(&num, sizeof(num));
}
const uint ELEMS_CHECK = 10000;
uint fp_count = 0;
for (int i = 0; i < ELEMS_CHECK; i++) {
uint64_t test = rng();
bool actually_present = actual_inserts.count(test);
bool filter_contains = filter.may_contain(&test, sizeof(test));
fp_count += !actually_present && filter_contains;
}
double theoretical_approx_fp_rate =
std::pow(1 - std::exp(-static_cast<double>(k) * n / m), k);
double filter_approx_fp_rate = filter.false_positive_probability();
double actual_fp_rate = static_cast<double>(fp_count) / ELEMS_CHECK;
sum_theorital_approx_fp_rate += theoretical_approx_fp_rate;
sum_filter_approx_fp_rate += filter_approx_fp_rate;
sum_actual_fp_rate += actual_fp_rate;
}
std::printf("simple bloom filter with n = %d, m = %d, k = %d\n", n, m, k);
std::printf("theoretical fp probs : %.8f\n",
sum_theorital_approx_fp_rate / TOTAL_TRIALS);
std::printf("filter reported fp probs : %.8f\n",
sum_filter_approx_fp_rate / TOTAL_TRIALS);
std::printf("actual fp rate : %.8f\n", sum_actual_fp_rate / TOTAL_TRIALS);
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
n,m,k,theoretical_fpp,filter_fpp,actual_fpp
10000,100000,2,0.03285854,0.03289392,0.03292500
10000,100000,3,0.01741059,0.01743016,0.01755500
10000,100000,4,0.01181327,0.01185258,0.01231500
10000,100000,5,0.00943093,0.00940946,0.00898000
10000,100000,6,0.00843621,0.00844959,0.00851000
10000,100000,7,0.00819372,0.00818934,0.00823000
10000,100000,8,0.00845547,0.00843888,0.00853000
10000,100000,9,0.00912699,0.00915585,0.00945500
10000,100000,10,0.01018589,0.01023808,0.01031500
10000,100000,11,0.01164950,0.01163213,0.01149000
10000,100000,12,0.01356057,0.01344405,0.01366000
10000,100000,13,0.01598020,0.01592878,0.01558500
10000,100000,14,0.01898380,0.01903601,0.01829000
10000,100000,15,0.02265812,0.02262230,0.02297000
1000,100000,5,0.00000028,0.00000028,0.00000000
2000,100000,5,0.00000780,0.00000782,0.00001500
3000,100000,5,0.00005244,0.00005258,0.00004000
4000,100000,5,0.00019571,0.00019651,0.00019500
5000,100000,5,0.00052956,0.00053070,0.00050500
7500,100000,5,0.00299029,0.00298418,0.00307500
10000,100000,5,0.00943093,0.00944119,0.00924000
15000,100000,5,0.04089419,0.04091604,0.04042500
20000,100000,5,0.10092519,0.10124248,0.10181000
30000,100000,5,0.28297059,0.28242511,0.28079500
40000,100000,5,0.48332436,0.48360202,0.48378500
60000,100000,5,0.77464850,0.77395500,0.77450000
80000,100000,5,0.91171555,0.91254904,0.91244000
10000,50000,5,0.10092519,0.10099464,0.10038000
10000,60000,5,0.05778111,0.05778597,0.05903000
10000,70000,5,0.03465784,0.03474584,0.03495000
10000,80000,5,0.02167922,0.02172916,0.02183500
10000,90000,5,0.01407034,0.01406240,0.01391000
10000,100000,5,0.00943093,0.00943771,0.00954000
10000,125000,5,0.00389460,0.00388819,0.00400500
10000,150000,5,0.00183031,0.00183603,0.00199000
10000,175000,5,0.00094805,0.00094767,0.00087000
10000,200000,5,0.00052956,0.00053068,0.00055500
10000,250000,5,0.00019571,0.00019591,0.00028500
10000,300000,5,0.00008527,0.00008530,0.00009500
10000,400000,5,0.00002240,0.00002242,0.00001500
10000,600000,5,0.00000327,0.00000327,0.00000500
1 n m k theoretical_fpp filter_fpp actual_fpp
2 10000 100000 2 0.03285854 0.03289392 0.03292500
3 10000 100000 3 0.01741059 0.01743016 0.01755500
4 10000 100000 4 0.01181327 0.01185258 0.01231500
5 10000 100000 5 0.00943093 0.00940946 0.00898000
6 10000 100000 6 0.00843621 0.00844959 0.00851000
7 10000 100000 7 0.00819372 0.00818934 0.00823000
8 10000 100000 8 0.00845547 0.00843888 0.00853000
9 10000 100000 9 0.00912699 0.00915585 0.00945500
10 10000 100000 10 0.01018589 0.01023808 0.01031500
11 10000 100000 11 0.01164950 0.01163213 0.01149000
12 10000 100000 12 0.01356057 0.01344405 0.01366000
13 10000 100000 13 0.01598020 0.01592878 0.01558500
14 10000 100000 14 0.01898380 0.01903601 0.01829000
15 10000 100000 15 0.02265812 0.02262230 0.02297000
16 1000 100000 5 0.00000028 0.00000028 0.00000000
17 2000 100000 5 0.00000780 0.00000782 0.00001500
18 3000 100000 5 0.00005244 0.00005258 0.00004000
19 4000 100000 5 0.00019571 0.00019651 0.00019500
20 5000 100000 5 0.00052956 0.00053070 0.00050500
21 7500 100000 5 0.00299029 0.00298418 0.00307500
22 10000 100000 5 0.00943093 0.00944119 0.00924000
23 15000 100000 5 0.04089419 0.04091604 0.04042500
24 20000 100000 5 0.10092519 0.10124248 0.10181000
25 30000 100000 5 0.28297059 0.28242511 0.28079500
26 40000 100000 5 0.48332436 0.48360202 0.48378500
27 60000 100000 5 0.77464850 0.77395500 0.77450000
28 80000 100000 5 0.91171555 0.91254904 0.91244000
29 10000 50000 5 0.10092519 0.10099464 0.10038000
30 10000 60000 5 0.05778111 0.05778597 0.05903000
31 10000 70000 5 0.03465784 0.03474584 0.03495000
32 10000 80000 5 0.02167922 0.02172916 0.02183500
33 10000 90000 5 0.01407034 0.01406240 0.01391000
34 10000 100000 5 0.00943093 0.00943771 0.00954000
35 10000 125000 5 0.00389460 0.00388819 0.00400500
36 10000 150000 5 0.00183031 0.00183603 0.00199000
37 10000 175000 5 0.00094805 0.00094767 0.00087000
38 10000 200000 5 0.00052956 0.00053068 0.00055500
39 10000 250000 5 0.00019571 0.00019591 0.00028500
40 10000 300000 5 0.00008527 0.00008530 0.00009500
41 10000 400000 5 0.00002240 0.00002242 0.00001500
42 10000 600000 5 0.00000327 0.00000327 0.00000500
+85
View File
@@ -0,0 +1,85 @@
#include "bloom_filter/bloom_filter.hpp"
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <random>
#include <sstream>
#include <string>
#include <unordered_set>
int main(int argc, char *argv[]) {
if (argc != 2) {
std::cerr << "usage: " << argv[0] << " plots/cases.csv\n";
return 1;
}
std::ifstream csv{argv[1]};
std::string line;
std::getline(csv, line); // skipping header n,m,k
std::mt19937_64 rng{}; // no seed so this is deterministic
constexpr uint32_t TOTAL_TRIALS = 20;
constexpr uint32_t ELEMS_CHECK = 10000;
std::printf("n,m,k,theoretical_fpp,filter_fpp,actual_fpp\n");
while (std::getline(csv, line)) {
if (line.empty()) {
continue;
}
std::stringstream ss(line);
std::string n_str, m_str, k_str;
std::getline(ss, n_str, ',');
std::getline(ss, m_str, ',');
std::getline(ss, k_str, ',');
uint64_t n = std::stoull(n_str);
uint64_t m = std::stoull(m_str);
uint32_t k = std::stoul(k_str);
double sum_theoretical_fpp = 0;
double sum_filter_fpp = 0;
double sum_actual_fpp = 0;
for (uint32_t trial = 0; trial < TOTAL_TRIALS; trial++) {
uint64_t seed1 = rng(), seed2 = rng();
BloomFilter filter{static_cast<size_t>(m), k, seed1, seed2};
std::unordered_set<uint64_t> actual_inserts;
for (uint64_t i = 0; i < n; i++) {
uint64_t num = rng();
actual_inserts.insert(num);
filter.put(&num, sizeof(num));
}
uint32_t fp_count = 0;
for (uint32_t i = 0; i < ELEMS_CHECK; i++) {
uint64_t test = rng();
bool actually_present = actual_inserts.count(test);
bool filter_contains = filter.may_contain(&test, sizeof(test));
fp_count += !actually_present && filter_contains;
}
double theoretical_fpp =
std::pow(1 - std::exp(-static_cast<double>(k) * n / m), k);
double filter_fpp = filter.false_positive_probability();
double actual_fpp = static_cast<double>(fp_count) / ELEMS_CHECK;
sum_theoretical_fpp += theoretical_fpp;
sum_filter_fpp += filter_fpp;
sum_actual_fpp += actual_fpp;
}
std::printf("%llu,%llu,%u,%.8f,%.8f,%.8f\n",
static_cast<unsigned long long>(n),
static_cast<unsigned long long>(m), k,
sum_theoretical_fpp / TOTAL_TRIALS,
sum_filter_fpp / TOTAL_TRIALS,
sum_actual_fpp / TOTAL_TRIALS);
}
return 0;
}
+42
View File
@@ -0,0 +1,42 @@
n,m,k
10000,100000,2
10000,100000,3
10000,100000,4
10000,100000,5
10000,100000,6
10000,100000,7
10000,100000,8
10000,100000,9
10000,100000,10
10000,100000,11
10000,100000,12
10000,100000,13
10000,100000,14
10000,100000,15
1000,100000,5
2000,100000,5
3000,100000,5
4000,100000,5
5000,100000,5
7500,100000,5
10000,100000,5
15000,100000,5
20000,100000,5
30000,100000,5
40000,100000,5
60000,100000,5
80000,100000,5
10000,50000,5
10000,60000,5
10000,70000,5
10000,80000,5
10000,90000,5
10000,100000,5
10000,125000,5
10000,150000,5
10000,175000,5
10000,200000,5
10000,250000,5
10000,300000,5
10000,400000,5
10000,600000,5
1 n m k
2 10000 100000 2
3 10000 100000 3
4 10000 100000 4
5 10000 100000 5
6 10000 100000 6
7 10000 100000 7
8 10000 100000 8
9 10000 100000 9
10 10000 100000 10
11 10000 100000 11
12 10000 100000 12
13 10000 100000 13
14 10000 100000 14
15 10000 100000 15
16 1000 100000 5
17 2000 100000 5
18 3000 100000 5
19 4000 100000 5
20 5000 100000 5
21 7500 100000 5
22 10000 100000 5
23 15000 100000 5
24 20000 100000 5
25 30000 100000 5
26 40000 100000 5
27 60000 100000 5
28 80000 100000 5
29 10000 50000 5
30 10000 60000 5
31 10000 70000 5
32 10000 80000 5
33 10000 90000 5
34 10000 100000 5
35 10000 125000 5
36 10000 150000 5
37 10000 175000 5
38 10000 200000 5
39 10000 250000 5
40 10000 300000 5
41 10000 400000 5
42 10000 600000 5
+13
View File
@@ -0,0 +1,13 @@
set datafile separator comma
set terminal pngcairo size 1000,700 enhanced font "Arial,12"
set output "plots/png/fpp_vs_k.png"
set title "Bloom filter false-positive rate vs k (n=10000, m=100000)"
set xlabel "hash functions (k)"
set ylabel "false-positive rate"
set grid
set key outside
plot "plots/data/bloom_filter_stats.csv" using (($1 == 10000 && $2 == 100000) ? $3 : 1/0):4 every ::1 with linespoints title "theoretical", \
"plots/data/bloom_filter_stats.csv" using (($1 == 10000 && $2 == 100000) ? $3 : 1/0):5 every ::1 with linespoints title "filter estimate", \
"plots/data/bloom_filter_stats.csv" using (($1 == 10000 && $2 == 100000) ? $3 : 1/0):6 every ::1 with linespoints title "observed"
+16
View File
@@ -0,0 +1,16 @@
set datafile separator comma
set terminal pngcairo size 1000,700 enhanced font "Arial,12"
set output "plots/png/fpp_vs_m.png"
set title "Bloom filter false-positive rate vs m (n=10000, k=5)"
set xlabel "filter size in bits (m)"
set ylabel "false-positive rate"
set logscale x 10
set logscale y 10
set yrange [1e-5:0.2]
set grid
set key outside
plot "plots/data/bloom_filter_stats.csv" using (($1 == 10000 && $3 == 5) ? $2 : 1/0):4 every ::1 with linespoints title "theoretical", \
"plots/data/bloom_filter_stats.csv" using (($1 == 10000 && $3 == 5) ? $2 : 1/0):5 every ::1 with linespoints title "filter estimate", \
"plots/data/bloom_filter_stats.csv" using (($1 == 10000 && $3 == 5) ? $2 : 1/0):6 every ::1 with linespoints title "observed"
+14
View File
@@ -0,0 +1,14 @@
set datafile separator comma
set terminal pngcairo size 1000,700 enhanced font "Arial,12"
set output "plots/png/fpp_vs_n.png"
set title "Bloom filter false-positive rate vs n (m=100000, k=5)"
set xlabel "inserted keys (n)"
set ylabel "false-positive rate"
set logscale x 10
set grid
set key outside
plot "plots/data/bloom_filter_stats.csv" using (($2 == 100000 && $3 == 5) ? $1 : 1/0):4 every ::1 with linespoints title "theoretical", \
"plots/data/bloom_filter_stats.csv" using (($2 == 100000 && $3 == 5) ? $1 : 1/0):5 every ::1 with linespoints title "filter estimate", \
"plots/data/bloom_filter_stats.csv" using (($2 == 100000 && $3 == 5) ? $1 : 1/0):6 every ::1 with linespoints title "observed"
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB