Repeated queries and scopes#

A Primo process can handle several queries while retaining the active assertions and declarations. The default rebuild engine creates fresh solving state per query; it still supports interactive sessions and scopes.

Add and retract an assertion#

(set-logic QF_LRA)
(declare-const x Real)
(assert (>= x 0))
(check-sat)
(push 1)
(assert (< x 0))
(check-sat)
(pop 1)
(check-sat)
(exit)
./build/primo --quiet docs/examples/session.smt2

Expected output:

sat
unsat
sat

The base context permits a nonnegative x. The pushed assertion contradicts it. Popping removes that assertion, so the base context is satisfiable again. Primo also accepts this file on stdin, or commands typed one at a time:

./build/primo --quiet

Each completed command is processed without waiting for EOF. exit ends the session. Successful declarations and assertions are silent by default; (set-option :print-success true) enables acknowledgments.

Scope rules#

push n creates n levels; pop n removes them. Popping beyond the current depth is an error. Declarations and definitions made inside a pushed scope are removed with that scope, as are its assertions. Global declarations are not supported; :global-declarations true returns unsupported.

reset-assertions clears assertions, scoped declarations/definitions and the base-level declarations/definitions too, returning the assertion depth to zero. It retains the selected logic and session options. reset also clears the logic and restores SMT-LIB model/acknowledgment options to their defaults; choose a logic again afterwards. Command-line settings remain process settings.

An assertion, declaration, scope operation or reset invalidates the previous query’s model. Obtain a fresh sat result before calling get-model again. See Request a model.

Optional reuse between queries#

For the admitted QF_LRA and QF_UF inputs, try:

./build/primo --quiet --incremental-mode=assumptions docs/examples/session.smt2

The sample produces the same sat, unsat, sat responses. This opt-in mode retains SAT and prepared theory structures between checks. It does not support other logics or quantified formulas, and it does not implement the SMT-LIB check-sat-assuming command.

Use its default companion options initially. Assumptions mode accepts --preprocessing-mode=auto or off; it rejects strong/basic preprocessing, portfolios, Boolean splitting, fixed-variable elimination, preprocess-only, custom CaDiCaL options and assertion-dependent preprocessing. QF_UF additionally requires incremental EUF, auto/online/conflict propagation, and no experimental Ackermann modes. Forced pure-theory filtering is rejected; auto resolves it to off. These restrictions protect the retained state and are checked by src/smt/smt_session.cpp.

Assumptions mode is not promised to be faster for every input. Historical qualification and timing limits are recorded separately for QF_LRA and QF_UF. Keep the default rebuild mode as the starting point unless your workload calls for the opt-in route.

Implementation and evidence#

The session’s public boundary is src/smt/smt_session.hpp; the command loop is in src/main.cpp. The existing implementation chapter records replay, lifetime and scope invariants. Its historical gates apply to the revisions they measured, not automatically to every subsequent checkout.