nx_fof_tseitin.nx
buildroot/runtime/nx_fof_tseitin.nx
about
nx_fof_tseitin.nx -- linear-size FOF -> CNF via Tseitin encoding.
Per Vampire-displacement roadmap Phase 2. The naive distribution
step in nx_fof_cnf can produce 2^n clauses for n-deep alternations
of & and |. Tseitin 1968 introduces a fresh propositional variable
p_G for each non-atomic subformula G and asserts the equivalence
p_G <-> G as 2-3 clauses. Result: O(n) clauses.
Pre-condition: input formula is in NNF and quantifier-free (i.e.
post-Skolemize + post-drop_forall). Tseitin doesn't handle IFF or
IMP directly -- caller must run elim_iff + elim_imp first (those
are also pre-conditions of the existing distribute step).
Algorithm:
ts_walk(F) returns a Literal that is "true iff F is true".
ATOM -> POS atom
NEG ATOM-> NEG atom (no fresh var needed)
NEG G -> introduce p; emit p <-> ~ts_walk(G)
AND L R -> introduce p; recurse on L,R; emit p <-> l_lit & r_lit
OR L R -> introduce p; recurse on L,R; emit p <-> l_lit | r_lit
Top-level: emit a unit clause asserting ts_walk(F) is true.
Equivalence clauses (each ↔ becomes 2-3 clauses):
p ↔ ~q : (p ∨ q) ∧ (~p ∨ ~q)
p ↔ q ∧ r : (~p ∨ q) ∧ (~p ∨ r) ∧ (p ∨ ~q ∨ ~r)
p ↔ q ∨ r : (~p ∨ q ∨ r) ∧ (p ∨ ~q) ∧ (p ∨ ~r)
Bits-up nx_int. Tseitin variables get sym_ids in their own range.
dependencies 7 imports · 2 importers
imports: nx_syscalls.nxnx_runtime.nxnx_tier.nxnx_result.nxnx_unify.nxnx_resolution.nxnx_fof.nx
imported by: nx_fof_tseitin_test.nxnx_tptp_load_any.nx
structs
| 53 | struct TseitinCtx |
consts
| 51 | const NX_TPTP_TS_BASE: nx_int = 800000 |
| 61 | const NX_TS_CTX_BYTES: nx_int = 40 |
functions
| 63 | func nx_ts_ctx_new(out: *Clause, cap: nx_int) -> *TseitinCtx |
| 74 | func nx_ts_emit(ctx: *TseitinCtx, lits: *Literal, n_lits: nx_int) |
| 90 | func nx_ts_fresh(ctx: *TseitinCtx) -> *Term |
| 97 | func nx_ts_pos(atom: *Term) -> *Literal { return nx_lit_make(NX_LIT_POS, atom) } |
| 98 | func nx_ts_neg(atom: *Term) -> *Literal { return nx_lit_make(NX_LIT_NEG, atom) } |
| 101 | func nx_ts_flip(l: *Literal) -> *Literal |
| 108 | func nx_ts_pair(a: *Literal, b: *Literal) -> *Literal |
| 118 | func nx_ts_triple(a: *Literal, b: *Literal, c: *Literal) -> *Literal |
| 130 | func nx_ts_single(a: *Literal) -> *Literal |
| 138 | func nx_ts_walk(ctx: *TseitinCtx, f: *Fof) -> *Literal called by 2: nx_ts_walknx_fof_to_cnf_tseitin calls 8: nx_ts_posnx_ts_negnx_ts_walknx_ts_freshnx_ts_flipnx_ts_emit+2 |
| 195 | func nx_fof_to_cnf_tseitin(f: *Fof, out_clauses: *Clause, out_n: *nx_int, |