Combining Component Caching and Clause Learning for Effective Model Counting

While there has been very substantial progress in practical algorithms for satisfiability, there are many related logical problems where satisfiability alone is not enough. One particularly useful extension to satisfiability is the associated counting problem, #SAT, which requires computing the number of assignments that satisfy the input formula. #SAT’s practical importance stems in part from its very close relationship to the problem of general Bayesian inference. #SAT seems to be more computationally difficult than SAT since an algorithm for SAT can stop once it has found a single satisfying assignment, whereas #SAT requires finding all such assignments. In fact, #SAT is complete for the class #P which is at least as hard as the polynomial-time hierarchy [10]. Not only is #SAT intrinsically important, it is also an excellent test-bed for algorithmic ideas in propositional reasoning. One of these new ideas is formula caching [7, 1, 5] which seems particularly promising when performed in the form called component caching [1, 2]. In component caching, disjoint components of the formula, generated dynamically during a DPLL search, are cached so that they only have to be solved once. While formula caching in general may have theoretical value even in SAT solvers [5], component caching seems to hold great promise for the practical improvement of #SAT algorithms (and Bayes inference) where there is more of a chance to reuse cached results. In particular, Bacchus, Dalmao, and Pitassi [1] discuss three different caching schemes: simple caching, component caching, and linear-space caching and show that component caching is theoretically competitive with the best of current methods for Bayesian inference (and substantially better in some instances). It has not been clear, however, whether component caching can be as competitive in practice as it is theoretically. We provide significant evidence that it can, demonstrating that on many instances it can outperform existing algorithms for #SAT by orders of magnitude. The key to this success is carefully incorporating component caching with clause learning, one of the most important ideas used in modern SAT solvers. Although both component caching and clause learning involve recording information collected during search, the nature and use of the recorded information is radically different. In clause learning, a clause that captures the reason for failure is computed from every failed search path. Component caching, on the other hand, stores the result computed when solving a subproblem. When that subproblem is encountered again its value can be retrieved from the cache rather than having to solve it again. It is not immediately obvious how to maintain correctness as well as obtain the best performance from a combination of these techniques. In this paper we show how this combination can be achieved so as to obtain the performance improvements just mentioned. Our model-counting program is built on the ZChaff SAT solver [8, 11]. ZChaff already implements clause learning, and we have added new modules and modified many others to support #SAT and to integrate component caching with clause learning. Ours is the first implementation we are aware of that is able to benefit from both component caching and clause learning. We have tested our program against the relsat [4, 3] system, which also performs component analysis, but does not cache the computed values of these components. In most instances of both random and structured problems our new solver is significantly faster than relsat, often by up to several orders of magnitude. 3 We begin by reviewing DPLL with caching for #SAT [1], and DPLL with learning for SAT. We then outline a basic approach for efficiently integrating component caching and clause learning. With this basic