wiki

VSIDS

VSIDS (Variable State Independent Decaying Sum) is the heuristic by which CDCL solvers choose the variable to branch on[1]. Every variable carries an activity score. When the solver analyzes a conflict, it bumps the activity of the variables involved, and all activities decay slowly as further conflicts occur, so that the score measures how often, and how recently, a variable has taken part in conflicts. Each decision picks the unassigned variable with the highest activity. The name records the two properties that made it successful: the score is independent of the variable state, the current assignment, so it costs nothing to maintain during propagation and backtracking, and it is a decaying sum that favours recent conflicts. The Chaff solver introduced VSIDS in 2001[1], and MiniSat's variant[2] is used in most solvers today.

§ 01

The scores

Let be the activity of variable and a global increment, initially 1. After the -th conflict, each variable that appears in a clause used by conflict analysis is bumped, and the increment grows by a constant factor[2]:

Increasing the increment has the same effect as multiplying every score by , without touching them. Relative to the current increment, the activity is an exponential moving average of the variable's participation in conflicts,

so a bump from conflicts ago counts as much as a fresh one. MiniSat uses , a half-life of about 14 conflicts, and rescales all scores when they exceed to avoid overflow[2]. Chaff's original version bumped the literals of each learned clause and periodically halved all counters[1]. The unassigned variable of highest activity is found with a binary heap, which only needs updating when a score changes or a variable is unassigned.

Recording the activities of a CDCL solver during a run on an unsatisfiable graph-colouring formula. The solver bumps every variable of every clause resolved during analysis.

(* Record the activity scores, divided by the current increment so that
a score of 1 means "bumped just now", every 50 conflicts. *)
let colouring ~vertices ~edges ~colours =
let x v c = (v * colours) + c + 1 in
Cnf.of_clauses
(List.init vertices (fun v -> List.init colours (x v))
@ List.concat_map (fun (u, v) -> List.init colours (fun c -> [ - (x u c); - (x v c) ])) edges)
let random_graph n m =
let rec go acc = if List.length acc = m then acc else
let u = Random.int n and v = Random.int n in
if u = v || List.mem (min u v, max u v) acc then go acc else go ((min u v, max u v) :: acc) in
go []

Every fifth snapshot of the output.

conflict x214 (late burst) x144 (busy early)
250 0.857 8.903
500 0.000 8.337
750 0.003 10.062
1000 0.784 16.212
1250 0.001 13.115
1500 0.000 9.417
1750 0.000 13.392
2000 1.006 15.443
2250 0.000 14.051
2500 0.666 9.619
2750 0.032 10.095
3000 0.011 0.000
04812160500100015002000250030003500conflictsactivity / incrementx144x214
Two variables' activity during the run. One takes part in conflicts throughout the first part of the run and then fades to nothing once the search moves on. The other is idle for most of the run, flares up briefly when the conflicts reach it, and decays again within a few hundred conflicts.
§ 02

Effect

The same CDCL solver with VSIDS and with a fixed order that always branches on the lowest-numbered unassigned variable.

(* The same CDCL solver with VSIDS and with a fixed variable order. *)
let colouring ~vertices ~edges ~colours =
let x v c = (v * colours) + c + 1 in
Cnf.of_clauses
(List.init vertices (fun v -> List.init colours (x v))
@ List.concat_map (fun (u, v) -> List.init colours (fun c -> [ - (x u c); - (x v c) ])) edges)
let random_graph n m =
let rec go acc = if List.length acc = m then acc else
let u = Random.int n and v = Random.int n in
if u = v || List.mem (min u v, max u v) acc then go acc else go ((min u v, max u v) :: acc) in
go []

Conflicts needed.

instance result VSIDS conflicts fixed order
random 3-SAT, 100 vars UNSAT 420 2281
random 3-SAT, 120 vars UNSAT 645 3624
pigeonhole, 8 in 7 UNSAT 4164 322
4-colouring, 60 vertices UNSAT 535 2565
4-colouring, 70 vertices UNSAT 3062 27192

On random and graph-colouring formulas, VSIDS needs between four and nine times fewer conflicts. On the pigeonhole formula the fixed order is better, because it happens to follow the structure of the formula, pigeon by pigeon, while VSIDS spreads its attention over the symmetric variables. Heuristics are not uniformly better; VSIDS wins because on the large structured formulas that solvers are used for, it concentrates on a small set of variables that are closely related through recent conflicts.

Why it works so well has been studied empirically. Liang and co-authors found that VSIDS favours variables that bridge the communities of the formula's variable-incidence graph, and that the variables it picks are strongly correlated with those that will appear in future conflicts[4]. Because decisions follow conflicts, the search tends to stay in one region of the formula until it has learned what it needs there, which suits the locality of learned clauses.

§ 03

Phases and restarts

VSIDS chooses a variable, not a value. Most solvers use phase saving: a variable is assigned the value it had when it was last unassigned[6]. Combined with restarts, which undo all decisions but keep the activities and the saved phases, this lets the solver rebuild much the same assignment in a new variable order, and restarts become cheap enough to be frequent.

§ 04

Variants

Before VSIDS, DPLL solvers chose variables by static counts over the current formula, such as the Jeroslow–Wang weights[9], which must be recomputed as the formula changes and do not use conflicts at all. BerkMin bumped all clauses involved in a conflict and restricted decisions to the variables of the most recent learned clause that is not yet satisfied[8]. VMTF, variable move-to-front, keeps the variables in a list and moves the bumped ones to the front, which gives similar behaviour with simpler data structures[7]; Biere and Fröhlich compared it with the VSIDS variants and found them close[3]. The learning-rate branching heuristic LRB treats the choice as a reinforcement-learning problem and rewards variables in proportion to how often they appear in learned clauses while assigned[5]. Modern solvers often switch between VSIDS and one of these alternatives during a run.

§ 05

History

Chaff, developed at Princeton by Moskewicz, Madigan, Zhao, Zhang and Malik and published in 2001, introduced VSIDS together with watched literals; the combination made it one to two orders of magnitude faster than the solvers before it on industrial benchmarks[1]. BerkMin refined the idea in 2002[8], and MiniSat's exponential version of 2003, which bumps variables during conflict analysis and grows the increment, became the standard[2]. Phase saving was added in 2007[6], and the heuristic has since been analyzed and challenged by VMTF and LRB[3][5].

see also

further reading

  1. [1]M. W. Moskewicz, C. F. Madigan, Y. Zhao, L. Zhang, S. Malik, “Chaff: engineering an efficient SAT solver”, DAC (2001).
  2. [2]N. Eén, N. Sörensson, “An extensible SAT-solver”, SAT, Lecture Notes in Computer Science 2919 (2004).
  3. [3]A. Biere, A. Fröhlich, “Evaluating CDCL variable scoring schemes”, SAT, Lecture Notes in Computer Science 9340 (2015).
  4. [4]J. H. Liang, V. Ganesh, E. Zulkoski, A. Zaman, K. Czarnecki, “Understanding VSIDS branching heuristics in conflict-driven clause-learning SAT solvers”, Haifa Verification Conference (2015).
  5. [5]J. H. Liang, V. Ganesh, P. Poupart, K. Czarnecki, “Learning rate based branching heuristic for SAT solvers”, SAT, Lecture Notes in Computer Science 9710 (2016).
  6. [6]K. Pipatsrisawat, A. Darwiche, “A lightweight component caching scheme for satisfiability solvers”, SAT, Lecture Notes in Computer Science 4501 (2007).
  7. [7]L. Ryan, Efficient Algorithms for Clause-Learning SAT Solvers, MSc thesis, Simon Fraser University (2004).
  8. [8]E. Goldberg, Y. Novikov, “BerkMin: a fast and robust SAT-solver”, DATE (2002).
  9. [9]R. G. Jeroslow, J. Wang, “Solving propositional satisfiability problems”, Annals of Mathematics and Artificial Intelligence 1 (1990).

last updated