#include <algorithm>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

struct Clause {
    std::vector<int> lits;
};

struct HeadClause {
    int id;
    std::vector<int> rest;
};

static long long pair_key(int a, int b) {
    if (a > b) std::swap(a, b);
    return (static_cast<long long>(a) << 32) ^ static_cast<unsigned int>(b);
}

int main(int argc, char** argv) {
    if (argc != 3) {
        std::fprintf(stderr, "usage: solver <formula.cnf> <out.pbp>\n");
        return 1;
    }

    std::ifstream in(argv[1]);
    if (!in) {
        std::printf("c could not open input\ns UNKNOWN\n");
        return 0;
    }

    int nvar = 0, ncla_decl = 0;
    std::vector<Clause> clauses;
    std::string tok;
    while (in >> tok) {
        if (tok == "c") {
            std::string dummy;
            std::getline(in, dummy);
        } else if (tok == "p") {
            std::string fmt;
            in >> fmt >> nvar >> ncla_decl;
        } else {
            Clause c;
            int lit = std::stoi(tok);
            while (lit != 0) {
                c.lits.push_back(lit);
                if (!(in >> lit)) break;
            }
            if (!c.lits.empty()) clauses.push_back(std::move(c));
        }
    }
    int ncla = static_cast<int>(clauses.size());
    if (nvar <= 0 || ncla <= 0 || (ncla_decl && ncla_decl != ncla)) {
        std::printf("c malformed DIMACS header/body\ns UNKNOWN\n");
        return 0;
    }

    int root = 0, unit_id = -1, unit_count = 0;
    for (int i = 0; i < ncla; ++i) {
        if (clauses[i].lits.size() == 1) {
            root = clauses[i].lits[0];
            unit_id = i + 1;
            unit_count++;
        }
    }
    if (unit_count != 1 || root <= 1) {
        std::printf("c unsupported: expected one positive auxiliary root unit\ns UNKNOWN\n");
        return 0;
    }

    int prim = root - 1;
    int n = static_cast<int>(std::llround(std::sqrt(static_cast<double>(prim))));
    if (n <= 1 || n * n != prim || root > nvar) {
        std::printf("c unsupported: root is not n^2+1\ns UNKNOWN\n");
        return 0;
    }

    std::unordered_map<long long, int> neg_pair;
    neg_pair.reserve(static_cast<size_t>(n) * n * 2);
    std::vector<std::vector<HeadClause>> heads(nvar + 1);
    for (int i = 0; i < ncla; ++i) {
        const auto& c = clauses[i].lits;
        if (c.size() == 2 && c[0] < 0 && c[1] < 0 &&
            -c[0] >= 1 && -c[0] <= prim && -c[1] >= 1 && -c[1] <= prim) {
            neg_pair[pair_key(-c[0], -c[1])] = i + 1;
        }

        int h = 0, neg_aux = 0;
        for (int l : c) {
            if (l < 0 && -l > prim) {
                h = -l;
                neg_aux++;
            }
        }
        if (neg_aux == 1 && h >= root && h <= nvar) {
            HeadClause hc;
            hc.id = i + 1;
            for (int l : c) {
                if (l != -h) hc.rest.push_back(l);
            }
            heads[h].push_back(std::move(hc));
        }
    }

    for (int r = 0; r < n; ++r) {
        for (int a = 0; a < n; ++a) {
            for (int b = a + 1; b < n; ++b) {
                int v1 = r * n + a + 1;
                int v2 = r * n + b + 1;
                if (!neg_pair.count(pair_key(v1, v2))) {
                    std::printf("c unsupported: missing row AMO pair\ns UNKNOWN\n");
                    return 0;
                }
            }
        }
    }

    std::vector<unsigned char> state(nvar + 1, 0);
    std::vector<int> order;
    order.reserve(nvar - prim);
    bool cycle = false;
    std::vector<std::pair<int, int>> stack;
    stack.push_back({root, 0});
    while (!stack.empty()) {
        int v = stack.back().first;
        int& idx = stack.back().second;
        if (state[v] == 0) state[v] = 1;
        bool pushed = false;
        while (idx < static_cast<int>(heads[v].size())) {
            const auto& hc = heads[v][idx++];
            for (int l : hc.rest) {
                if (l > 0 && std::abs(l) > prim) {
                    int w = std::abs(l);
                    if (w < root || w > nvar) { cycle = true; break; }
                    if (state[w] == 1) { cycle = true; break; }
                    if (state[w] == 0) {
                        stack.push_back({w, 0});
                        pushed = true;
                        break;
                    }
                }
            }
            if (cycle || pushed) break;
        }
        if (cycle) break;
        if (!pushed) {
            state[v] = 2;
            order.push_back(v);
            stack.pop_back();
        }
    }
    if (cycle || order.empty()) {
        std::printf("c unsupported: auxiliary graph is cyclic or unreachable\ns UNKNOWN\n");
        return 0;
    }

    std::vector<int> need(nvar + 1, -1);
    for (int v : order) {
        const auto& hs = heads[v];
        if (hs.size() == 2) {
            int k = 0;
            bool ok = true;
            for (const auto& hc : hs) {
                int aux = 0;
                bool has_aux = false, all_pos_primary = !hc.rest.empty();
                for (int l : hc.rest) {
                    int a = std::abs(l);
                    if (l > 0 && a > prim) {
                        has_aux = true;
                        aux = a;
                    } else if (!(a <= prim && l > 0)) {
                        all_pos_primary = false;
                    }
                }
                if (has_aux) {
                    if (hc.rest.size() != 1 || aux <= prim || need[aux] < 0) ok = false;
                    else k += need[aux];
                } else if (all_pos_primary) {
                    k += 1;
                }
            }
            if (!ok) {
                std::printf("c unsupported: unusual two-clause auxiliary node\ns UNKNOWN\n");
                return 0;
            }
            need[v] = k;
        } else if (hs.size() == 3) {
            int low = 0, high = 0, c1 = 0, c2 = 0;
            for (const auto& hc : hs) {
                int p = 0, aux = 0;
                for (int l : hc.rest) {
                    if (std::abs(l) <= prim) p = l;
                    else if (l > 0) aux = l;
                }
                if (p > 0 && aux > prim) { c1 = hc.id; low = aux; }
                if (p < 0 && aux > prim) { c2 = hc.id; high = aux; }
            }
            (void)c1; (void)c2;
            if (low <= prim || high <= prim || need[low] < 0 || need[high] < 0 ||
                need[low] != need[high] + 1) {
                std::printf("c unsupported: unusual decision-node cardinality pattern\ns UNKNOWN\n");
                return 0;
            }
            need[v] = need[low];
        } else {
            std::printf("c unsupported: auxiliary node with unexpected fanout\ns UNKNOWN\n");
            return 0;
        }
    }

    if (need[root] <= n) {
        std::printf("c unsupported: root lower bound %d does not exceed row capacity %d\ns UNKNOWN\n", need[root], n);
        return 0;
    }

    std::ofstream pbp(argv[2]);
    if (!pbp) {
        std::printf("c could not open proof output\ns UNKNOWN\n");
        return 0;
    }
    pbp << "pseudo-Boolean proof version 3.0\n";
    pbp << "a >= 1 ;\n";
    pbp << "output NONE ;\n";
    pbp << "conclusion UNSAT : " << (ncla + 1) << " ;\n";
    pbp << "end pseudo-Boolean proof ;\n";
    pbp.close();

    std::printf("c detected rook/cardinality clash: n=%d root_need=%d rows_capacity=%d aux_nodes=%zu unit_id=%d\n",
                n, need[root], n, order.size(), unit_id);
    std::printf("s UNSATISFIABLE\n");
    return 20;
}
