// Paso 6, con filtro de Bloom: mide los falsos positivos. Agrega una línea de cada dos del
// archivo y pregunta por las otras: esas no están, así que todo sí es un falso positivo.
// Uso: bloom_measure palabras.txt
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

#include "bloom.h"

namespace {

void print_row(const std::vector<std::string>& words, std::size_t bits_per_key, int k) {
    std::size_t keys = (words.size() + 1) / 2;
    BloomFilter filter(keys * bits_per_key, k);
    for (std::size_t i = 0; i < words.size(); i += 2) {
        filter.add(words[i]);
    }
    std::size_t asked = 0;
    std::size_t positives = 0;
    for (std::size_t i = 1; i < words.size(); i += 2) {
        asked++;
        positives += filter.possibly_contains(words[i]) ? 1 : 0;
    }
    std::cout << std::fixed << std::setw(14) << bits_per_key << std::setw(4) << k << std::setprecision(2) << std::setw(8)
              << static_cast<double>(filter.bit_count()) / 8e6 << std::setw(11) << positives << std::setprecision(3)
              << std::setw(9) << 100.0 * static_cast<double>(positives) / asked << " %" << std::setprecision(1)
              << std::setw(16) << 100.0 * static_cast<double>(filter.bits_on()) / filter.bit_count() << " %\n";
}

}  // namespace

int main(int argc, char* argv[]) {
    if (argc != 2) {
        std::cerr << "uso: bloom_measure palabras.txt\n";
        return 2;
    }
    std::ifstream file(argv[1]);
    std::vector<std::string> words;
    std::string word;
    while (file >> word) {
        words.push_back(word);
    }
    std::cout << "agregadas: " << (words.size() + 1) / 2 << ", preguntadas: " << words.size() / 2 << "\n";
    std::cout << "bits por clave   k      MB  positivos     tasa  bits encendidos\n";
    for (std::size_t bits_per_key : {2, 4, 8, 10, 16}) {
        print_row(words, bits_per_key, 1);
        print_row(words, bits_per_key, 4);
    }
    std::cout << "con 10 bits por clave, cambiando k:\n";
    for (int k : {1, 2, 3, 5, 7, 10, 15, 25}) {
        print_row(words, 10, k);
    }
    return 0;
}
