#define main solver_main_disabled
#include "../solver.cpp"
#undef main

static bool recover_full(int nvars, const vector<vector<int>> &target,
                         uint64_t &product, string &kind,
                         vector<int> &mp, vector<int> &orig_inputs) {
    vector<vector<int>> target_gates;
    vector<int> unit_by_var(nvars + 1, 0);
    for (const auto &cl : target) {
        if (cl.size() == 1) unit_by_var[abs(cl[0])] = cl[0];
        else target_gates.push_back(cl);
    }
    auto mapped_lit = [](int lit, const vector<int> &m) {
        int r = m[abs(lit)];
        return lit > 0 ? r : -r;
    };
    for (int bits = 2; bits < 63; ++bits) {
        uint64_t dummy = 1ull << (bits - 1);
        for (const string k : {"nc", "nw", "fw"}) {
            PurdomGen g;
            vector<int> outs, inputs;
            if (!generate_purdom(dummy, 1, 1, k, g, &inputs, &outs)) continue;
            if (g.next_var - 1 != nvars || g.clauses.size() != target.size()) continue;
            vector<vector<int>> gen_gates;
            for (const auto &cl : g.clauses) if (cl.size() != 1) gen_gates.push_back(cl);
            vector<int> m;
            if (!signed_literal_map(nvars, gen_gates, target_gates, m)) continue;
            uint64_t prod = 0;
            bool ok = true;
            for (int i = 0; i < (int)outs.size(); ++i) {
                int tlit = mapped_lit(outs[i], m);
                int unit = unit_by_var[abs(tlit)];
                if (!unit) { ok = false; break; }
                bool bit = (unit > 0) == (tlit > 0);
                if (bit) prod |= 1ull << i;
            }
            if (!ok || prod < 2 || (int)bits_u64(prod).size() != bits) continue;
            product = prod;
            kind = k;
            mp.swap(m);
            orig_inputs.swap(inputs);
            return true;
        }
    }
    return false;
}

static bool up_conflict(const vector<vector<int>> &clauses, int nvars, const vector<int> &assumps) {
    vector<int8_t> asn(nvars + 1, 0);
    vector<vector<int>> occ(2 * (nvars + 1) + 2);
    for (int i = 0; i < (int)clauses.size(); ++i) {
        for (int lit : clauses[i]) occ[lit_index(lit)].push_back(i);
    }
    vector<int> q;
    auto enq = [&](int lit) {
        int v = abs(lit);
        int8_t val = lit > 0 ? 1 : -1;
        if (asn[v]) return asn[v] == val;
        asn[v] = val;
        q.push_back(lit);
        return true;
    };
    for (const auto &cl : clauses) {
        if (cl.size() == 1 && !enq(cl[0])) return true;
    }
    for (int lit : assumps) if (!enq(lit)) return true;
    size_t head = 0;
    while (head < q.size()) {
        int lit = q[head++];
        for (int ci : occ[lit_index(-lit)]) {
            const auto &cl = clauses[ci];
            int un = 0, last = 0;
            bool sat = false;
            for (int l : cl) {
                int8_t a = asn[abs(l)];
                if (!a) { un++; last = l; }
                else if ((l > 0 && a > 0) || (l < 0 && a < 0)) { sat = true; break; }
            }
            if (sat) continue;
            if (un == 0) return true;
            if (un == 1 && !enq(last)) return true;
        }
    }
    return false;
}

int main(int argc, char **argv) {
    if (argc < 2 || argc > 3) return 2;
    int nvars = 0;
    vector<vector<int>> clauses;
    if (!parse_dimacs(argv[1], nvars, clauses)) return 3;
    uint64_t product = 0;
    string kind;
    vector<int> mp, inputs;
    if (!recover_full(nvars, clauses, product, kind, mp, inputs)) {
        cerr << "recover failed\n";
        return 4;
    }
    int bits = (int)bits_u64(product).size();
    int input1 = bits - 1;
    int input2 = (bits + 1) / 2;
    cerr << "product=" << product << " kind=" << kind << " bits=" << bits
         << " input1=" << input1 << " input2=" << input2 << "\n";
    vector<int> bvars;
    for (int i = 0; i < input2; ++i) bvars.push_back(mp[inputs[input1 + i]]);
    int ok = 0, fail = 0;
    uint64_t lim = 1ull << input2;
    if (argc == 3) lim = min<uint64_t>(lim, strtoull(argv[2], nullptr, 10));
    for (uint64_t b = 0; b < lim; ++b) {
        vector<int> assumps;
        for (int i = 0; i < input2; ++i) {
            int l = bvars[i];
            bool bit = (b >> i) & 1;
            assumps.push_back(bit ? l : -l);
        }
        bool c = up_conflict(clauses, nvars, assumps);
        if (c) ok++;
        else {
            fail++;
            if (fail <= 20) cerr << "no UP conflict b=" << b << "\n";
        }
    }
    cerr << "up-conflict " << ok << " fail " << fail << "\n";
    return fail ? 1 : 0;
}
