feat: allow bv_decide users to configure the SAT solver (#11847)

This PR adds a new `solverMode` field to `bv_decide`'s configuration,
allowing users to configure
the SAT solver for different kinds of workloads.
This commit is contained in:
Henrik Böving 2025-12-30 14:17:20 +01:00 committed by GitHub
parent bba35e4532
commit 2a28cd98fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 79 additions and 10 deletions

View file

@ -8,6 +8,7 @@ module
prelude
public import Std.Tactic.BVDecide.LRAT.Parser
public import Lean.CoreM
public import Std.Tactic.BVDecide.Syntax
public section
@ -146,7 +147,7 @@ solvers the solver is run with `timeout` in seconds as a maximum time limit to s
Note: This function currently assume that the solver has the same CLI as CaDiCal.
-/
def satQuery (solverPath : System.FilePath) (problemPath : System.FilePath) (proofOutput : System.FilePath)
(timeout : Nat) (binaryProofs : Bool) :
(timeout : Nat) (binaryProofs : Bool) (mode : Frontend.SolverMode) :
CoreM SolverResult := do
let cmd := solverPath.toString
let mut args := #[
@ -156,17 +157,12 @@ def satQuery (solverPath : System.FilePath) (problemPath : System.FilePath) (pro
s!"--binary={binaryProofs}",
"--quiet",
/-
This sets the magic parameters of cadical to optimize for UNSAT search.
Given the fact that we are mostly interested in proving things and expect user goals to be
provable this is a fine value to set
-/
"--unsat",
/-
Bitwuzla sets this option and it does improve performance practically:
https://github.com/bitwuzla/bitwuzla/blob/0e81e616af4d4421729884f01928b194c3536c76/src/sat/cadical.cpp#L34
-/
"--shrink=0"
]
args := args ++ solverModeFlags mode
-- We implement timeouting ourselves because cadicals -t option is not available on Windows.
let out? ← runInterruptible timeout { cmd, args, stdin := .piped, stdout := .piped, stderr := .null }
@ -190,6 +186,12 @@ def satQuery (solverPath : System.FilePath) (problemPath : System.FilePath) (pro
throwError s!"Error {err} while parsing:\n{stdout}"
else
throwError s!"The external prover produced unexpected output, stdout:\n{stdout}stderr:\n{stderr}"
where
solverModeFlags (mode : Frontend.SolverMode) : Array String :=
match mode with
| .proof => #["--unsat"]
| .counterexample => #["--sat"]
| .default => #["--default"]
end External

View file

@ -344,7 +344,14 @@ def lratBitblaster (goal : MVarId) (ctx : TacticContext) (reflectionResult : Ref
let res ←
withTraceNode `Meta.Tactic.sat (fun _ => return "Obtaining external proof certificate") do
runExternal cnf ctx.solver ctx.lratPath ctx.config.trimProofs ctx.config.timeout ctx.config.binaryProofs
runExternal
cnf
ctx.solver
ctx.lratPath
ctx.config.trimProofs
ctx.config.timeout
ctx.config.binaryProofs
ctx.config.solverMode
match res with
| .ok cert =>

View file

@ -131,7 +131,7 @@ Run an external SAT solver on the `CNF` to obtain an LRAT proof.
This will obtain an `LratCert` if the formula is UNSAT and throw errors otherwise.
-/
def runExternal (cnf : CNF Nat) (solver : System.FilePath) (lratPath : System.FilePath)
(trimProofs : Bool) (timeout : Nat) (binaryProofs : Bool) :
(trimProofs : Bool) (timeout : Nat) (binaryProofs : Bool) (solverMode : Frontend.SolverMode) :
CoreM (Except (Array (Bool × Nat)) LratCert) := do
IO.FS.withTempFile fun cnfHandle cnfPath => do
withTraceNode `Meta.Tactic.sat (fun _ => return "Serializing SAT problem to DIMACS file") do
@ -141,7 +141,7 @@ def runExternal (cnf : CNF Nat) (solver : System.FilePath) (lratPath : System.Fi
let res ←
withTraceNode `Meta.Tactic.sat (fun _ => return "Running SAT solver") do
External.satQuery solver cnfPath lratPath timeout binaryProofs
External.satQuery solver cnfPath lratPath timeout binaryProofs solverMode
if let .sat assignment := res then
return .error assignment

View file

@ -14,6 +14,23 @@ set_option linter.missingDocs true -- keep it documented
namespace Lean.Elab.Tactic.BVDecide.Frontend
/--
The various kinds of configurations offered for the SAT solver.
-/
inductive SolverMode where
/--
Set SAT solver options to improve proof search.
-/
| proof
/--
Set SAT solver options to improve counterexample search.
-/
| counterexample
/--
Don't set additional SAT solver flags.
-/
| default
/--
The configuration options for `bv_decide`.
-/
@ -70,6 +87,11 @@ structure BVDecideConfig where
if matching multiplications are not needed to proof a goal.
-/
shortCircuit : Bool := false
/--
The SAT solver configuration to use. Defaults to `.proof` as that is the most relevant use case
for `bv_decide`.
-/
solverMode : SolverMode := .proof
end Lean.Elab.Tactic.BVDecide.Frontend

View file

@ -0,0 +1,38 @@
import Std.Tactic.BVDecide
/--
error: The prover found a counterexample, consider the following assignment:
x = 4294967295#32
y = 4294967295#32
-/
#guard_msgs in
example (x y : BitVec 32) : x * y = y + x := by
bv_decide
/--
error: The prover found a counterexample, consider the following assignment:
x = 4294967295#32
y = 4294967295#32
-/
#guard_msgs in
example (x y : BitVec 32) : x * y = y + x := by
bv_decide (config := { solverMode := .counterexample })
/--
error: The prover found a counterexample, consider the following assignment:
x = 4294967295#32
y = 4294967295#32
-/
#guard_msgs in
example (x y : BitVec 32) : x * y = y + x := by
bv_decide (config := { solverMode := .default })
/--
error: The prover found a counterexample, consider the following assignment:
x = 4294967295#32
y = 4294967295#32
-/
#guard_msgs in
example (x y : BitVec 32) : x * y = y + x := by
bv_decide (config := { solverMode := .proof })