GRATgen

This page lists some of the heuristics used by gratgen

gratgen uses some heuristics to speed up checking. Some of them originate from drat-trim and have been refined, improved, and adopted to teh multi-threaded setting, others have been newly developed. Here, we describe the most important ones:

Backwards checking

Backwards checking has already been used in drat-trim. Our version of backwards checking is almost the same, except that we run multiple threads in parallel, each of which is performing a backwards pass.

The main idea of backwards checking is to first run a forward pass, which adds all lemmas without verifying, and then does unit propagation to derive the final conflict. All lemmas required to derive the final conflict are marked. Then, one (or multiple) threads run over the proof in backwards order. A lemma is removed, and if it is marked, it is verified. After sucecssful verification, all lemmas required for verification are marked. For multiple threads, a thread only verifies a lemma if it can acquire it. This ensures that no lemma is verified multiple times.

Synchronization of marked clauses between threads

Each thread keeps track of a local set of marked clauses, which is periodically synchronized with a global set of marked clauses. This ensures that marked clauses are communicated between threads, but a query for a clause to be marked causes no congestion.

Core-first unit propagation

Core first unit propagation was already included in drat-trim. The main idea is to prefer marked lemmas over unmarked ones during unit propagation, trying to reduce the number of newly marked lemmas.

Separate watchlists

While drat-trim iterates over the watchlist and filters the lemmas by core/noncore (i.e., marked/unmarked), gratgen uses two separate watchlists, one for the core and one for the non-core lemmas. Whenever a lemma is marked, it is moved from the non-core to the core watchlists. Our benchmarks show that this yields a significant speedup compared to a single watchlist, as iteration over watchlists is in the inner loop, and thus executed very often.

RAT-run heuristics

There are some proofs that contain many RAT lemmas. Searching for RAT-candidates is implemented by brute-force search, iterating over the watchlists. This implementation has been adopted from drat-trim. However, experiments show that proofs often contain sequences of adjacent RAT lemmas over the same pivot literal. Thus, we store the result of a RAT-candidate search until the pivot literal changes, and re-use the stored result if another RAT-proof on the same pivot literal occurs.

For some examples, this heuristics leads to three to four times faster checking times. The overhead of this heuristics is negligible, as RAT candidate lists tend to be short.

Run-wise lemma acquisition in multi-threading

To make this heuristics effective in multi-threaded mode, a thread will try to acquire all marked lemmas of a same-pivot run, before verifying the first lemma. This decreases the probability that a RAT-run is distributed over multiple threads, each thread searching the candidate list.