#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

struct Scanner {
    static constexpr size_t BUFSZ = 1 << 20;
    FILE* f = nullptr;
    vector<char> buf;
    size_t pos = 0, len = 0;
    explicit Scanner(const char* path) : f(fopen(path, "rb")), buf(BUFSZ) {}
    ~Scanner() { if (f) fclose(f); }
    int get() {
        if (pos >= len) {
            len = f ? fread(buf.data(), 1, BUFSZ, f) : 0;
            pos = 0;
            if (!len) return EOF;
        }
        return (unsigned char)buf[pos++];
    }
    void skip_line() {
        int c;
        while ((c = get()) != EOF && c != '\n') {}
    }
    int next_non_ws() {
        while (true) {
            int c = get();
            if (c == EOF) return EOF;
            if (isspace(c)) continue;
            if (c == 'c') {
                skip_line();
                continue;
            }
            return c;
        }
    }
    bool read_word_raw(string& out) {
        out.clear();
        int c;
        do {
            c = get();
            if (c == EOF) return false;
        } while (isspace(c));
        while (c != EOF && !isspace(c)) {
            out.push_back((char)c);
            c = get();
        }
        return true;
    }
    bool read_int(int& out) {
        int c = next_non_ws();
        if (c == EOF) return false;
        int sign = 1;
        if (c == '-') {
            sign = -1;
            c = get();
        }
        int x = 0;
        while (c != EOF && isdigit(c)) {
            x = x * 10 + (c - '0');
            c = get();
        }
        out = sign * x;
        return true;
    }
    bool read_header(int& n, int& m) {
        int c;
        while ((c = next_non_ws()) != EOF) {
            if (c != 'p') {
                skip_line();
                continue;
            }
            string fmt;
            if (!read_word_raw(fmt)) return false;
            return fmt == "cnf" && read_int(n) && read_int(m);
        }
        return false;
    }
};

static vector<signed char> read_model(const char* path, int nvars) {
    vector<signed char> val((size_t)nvars + 1, 0);
    FILE* f = fopen(path, "rb");
    if (!f) {
        cerr << "cannot open model\n";
        exit(2);
    }
    char line[1 << 20];
    while (fgets(line, sizeof(line), f)) {
        if (line[0] != 'v') continue;
        char* p = line + 1;
        while (*p) {
            while (*p && isspace((unsigned char)*p)) p++;
            if (!*p) break;
            int lit = (int)strtol(p, &p, 10);
            if (lit == 0) continue;
            int v = abs(lit);
            if (v <= nvars) val[(size_t)v] = lit > 0 ? 1 : -1;
        }
    }
    fclose(f);
    return val;
}

int main(int argc, char** argv) {
    if (argc != 3) {
        cerr << "usage: cover_analyze formula.cnf model.out\n";
        return 2;
    }
    int nvars = 0, nclauses = 0;
    {
        Scanner sc(argv[1]);
        if (!sc.f || !sc.read_header(nvars, nclauses)) return 2;
    }
    auto val = read_model(argv[2], nvars);
    vector<int> true_occ((size_t)nvars + 1, 0);
    vector<unsigned char> mandatory((size_t)nvars + 1, 0);
    vector<long long> true_hist(16, 0), size_hist(16, 0);
    long long bad = 0, mandatory_clauses = 0, clauses = 0, true_lits_total = 0;
    {
        Scanner sc(argv[1]);
        int hn = 0, hm = 0;
        sc.read_header(hn, hm);
        vector<int> true_vars;
        true_vars.reserve(16);
        int lit;
        int len = 0;
        while (sc.read_int(lit)) {
            if (lit == 0) {
                clauses++;
                int tc = (int)true_vars.size();
                true_lits_total += tc;
                if (tc == 0) bad++;
                if (tc == 1) {
                    mandatory[(size_t)true_vars[0]] = 1;
                    mandatory_clauses++;
                }
                true_hist[(size_t)min<int>(tc, (int)true_hist.size() - 1)]++;
                size_hist[(size_t)min<int>(len, (int)size_hist.size() - 1)]++;
                true_vars.clear();
                len = 0;
            } else {
                len++;
                int v = abs(lit);
                signed char a = val[(size_t)v] ? val[(size_t)v] : -1;
                if ((lit > 0 && a > 0) || (lit < 0 && a < 0)) {
                    true_vars.push_back(v);
                    true_occ[(size_t)v]++;
                }
            }
        }
    }
    long long mandatory_vars = 0;
    vector<int> occs;
    occs.reserve((size_t)nvars);
    for (int v = 1; v <= nvars; ++v) {
        if (mandatory[(size_t)v]) mandatory_vars++;
        if (true_occ[(size_t)v]) occs.push_back(true_occ[(size_t)v]);
    }
    sort(occs.begin(), occs.end());
    auto pct = [&](double p) {
        if (occs.empty()) return 0;
        size_t idx = min<size_t>(occs.size() - 1, (size_t)(p * (occs.size() - 1)));
        return occs[idx];
    };
    cout << "vars " << nvars << " clauses " << clauses << " bad " << bad << "\n";
    cout << "true_lits_total " << true_lits_total << " avg " << (double)true_lits_total / max<long long>(1, clauses) << "\n";
    cout << "mandatory_clauses " << mandatory_clauses << " mandatory_vars " << mandatory_vars << "\n";
    cout << "true_count_hist";
    for (size_t i = 0; i < true_hist.size(); ++i) cout << ' ' << i << ':' << true_hist[i];
    cout << "\nsize_hist";
    for (size_t i = 0; i < size_hist.size(); ++i) cout << ' ' << i << ':' << size_hist[i];
    cout << "\ntrue_occ_nonzero " << occs.size()
         << " p50 " << pct(0.50) << " p75 " << pct(0.75)
         << " p90 " << pct(0.90) << " p95 " << pct(0.95)
         << " p99 " << pct(0.99) << " max " << (occs.empty() ? 0 : occs.back()) << "\n";
    for (int t : {2,3,4,5,6,8,10,12,16,24,32,48,64,96,128}) {
        long long c = 0;
        for (int x : occs) if (x >= t) c++;
        cout << "occ_ge_" << t << ' ' << c << "\n";
    }
    return 0;
}
