1 Introduction

Treewidth [43] is a prominent structural parameter, originating from graph theory and is well-studied in the area of parameterized complexity [6, 18, 40]. For several problems hard for complexity class NP, there are results [12] showing so-called (fixed-parameter) tractability, which indicates a fixed-parameter tractable (FPT) algorithm running in polynomial time assuming that a given parameter (e.g., treewidth) is fixed. Practical implementations exploiting treewidth include generic frameworks [3, 5, 36], but also dedicated solvers that deal with problems ranging from (counting variants of) Boolean satisfiability (Sat) [25], over generalizations thereof [9, 10] based on Quantified Boolean Formulas (QBFs), to formalisms relevant to knowledge representation and reasoning [22]. For Sat, these solvers are of particular interest as there is a well-known correspondence between treewidth and resolution width [2]. QBFs extend Boolean logic by explicit universal and existential quantification over variables, which has applications in formal verification, synthesis, and AI problems such as planning [28]. Some of these parameterized solvers are particularly efficient for certain fragments [37], and even successfully participated in problem-specific competitions [42].

Most of these systems are based on dynamic programming (DP), where a tree decomposition (TD) is traversed in a post-order, i.e., from the leaves towards the root, and thereby for each TD node tables are computed. The size of these tables (and thus the computational efforts required) are bounded by a function in the treewidth of the instance. Although dedicated competitions [15] for treewidth advanced the state-of-the-art for efficiently computing treewidth and TDs  [1, 47], these DP approaches reach their limits when instances have higher treewidth; a situation which can even occur in structured real-world instances [38]. Nevertheless in the area of Boolean satisfiability, this approach proved to be successful for counting problems, such as, e.g., (weighted) model counting [24, 25, 44] and projected model counting [23].

To further increase the applicability of this paradigm, novel techniques are required which (1) rely on different levels of abstraction of the instance at hand; (2) treat subproblems originating in the abstraction by standard solvers whenever widths appear too high; and (3) use highly sophisticated data management in order to store and process tables obtained by dynamic programming.

Contributions. Above aspects are treated as follows.

  1. 1.

    To tame the beast of high treewidth, we propose nested dynamic programming, where only parts of an abstraction of a graph are decomposed. Then, each TD node also needs to solve a subproblem residing in the graph, but may involve vertices outside the abstraction. In turn, for solving such subproblems, the idea of nested DP is to subsequently repeat decomposing and solving more fine-grained graph abstractions in a nested fashion. This results not only in elegant DP algorithms, but also allows to deal with high treewidth. While candidates for obtaining abstractions often originate naturally from the problem, nested DP may require non-obvious sub-abstractions, for which we present a generic solution.

  2. 2.

    To further improve the capability of handling high treewidth, we show how to apply nested DP in the context of hybrid solving, where established, standard solvers (e.g., Sat solvers) and caching are incorporated in nested DP such that the best of two worlds are combined. Thereby, structured solving is applied to parts of the problem instance subject to counting or enumeration, while depending on results of subproblems. These subproblems (subject to search) reside in the abstraction only, and are solved via standard solvers.

  3. 3.

    We implemented a system based on a recently published tool called dpdb  [24] for using database management systems (DBMS) to efficiently perform table manipulation operations needed during DP. Our system uses and significantly extends this tool in order to perform hybrid solving, thereby combining nested DP and standard solvers. As a result, we use DBMS for efficiently implementing the handling of tables needed by nested DP. Preliminary experiments indicate that nested DP with hybrid solving can be fruitful.

We exemplify these ideas on the problem of Projected Model Counting (\(\textsc {\#}\exists \textsc {Sat}\)) and discuss adaptions for other problems.

2 Background

Projected Model Counting. We define Boolean formulas in the usual way, cf., [28]. A literal is a Boolean variable x or its negation \(\lnot x\). A (CNF) formula \(\varphi \) is a set of clauses interpreted as conjunction. A clause is a set of literals interpreted as disjunction. For a formula or clause X, we abbreviate by \({{\,\mathrm{var}\,}}(X)\) the variables that occur in X. An assignment of \(\varphi \) is a mapping \(I: {{\,\mathrm{var}\,}}(\varphi ) \rightarrow \{0,1\}\). The formula \(\varphi [I]\) under assignment I is obtained by removing every clause c from \(\varphi \) that contains a literal set to 1 by I, and removing from every remaining clause of \(\varphi \) all literals set to 0 by I. An assignment I is satisfying if \(\varphi [I]=\emptyset \). Problem #Sat asks to output the number of satisfying assignments of a formula. Projected Model Counting \(\textsc {\#}\exists \textsc {Sat}\) takes a formula \(\varphi \) and a set \(P\subseteq {{\,\mathrm{var}\,}}(\varphi )\) of projection variables, and asks for \(\textsc {\#}\exists \textsc {Sat} (\varphi , P)\,\mathrel {\mathop :}=|\{I^{-1}(1) \cap P\mid \varphi [I]=\emptyset \}|\). Consequently, \(\textsc {Sat} (\varphi )\,\mathrel {\mathop :}=\textsc {\#}\exists \textsc {Sat} (\varphi ,\emptyset )\), and \(\textsc {\#Sat} (\varphi )\,\mathrel {\mathop :}=\textsc {\#}\exists \textsc {Sat} (\varphi ,{{\,\mathrm{var}\,}}(\varphi ))\). \(\textsc {\#}\exists \textsc {Sat} \) is \(\#\cdot \)NP-complete [19] and thus probably harder than \(\textsc {\#Sat} \) (\(\#\)P-complete).

Fig. 1.
figure 1

Graph G (left), a TD \(\mathcal{T}\) of graph G (right).

Tree Decomposition and Treewidth. We assume familiarity with graph terminology, cf., [17]. A tree decomposition (TD) [43] of a given graph G is a pair \(\mathcal {T}=(T,\chi )\) where T is a rooted tree and \(\chi \) assigns to each node \(t\in V(T)\) a set \(\chi (t)\subseteq V(G)\), called bag, such that (i) \(V(G)=\bigcup _{t\in V(T)}\chi (t)\), (ii) \(E(G)\subseteq \{\,\{u,v\} \;{|}\;t\in V(T), \{u,v\}\subseteq \chi (t)\,\}\), and (iii) for each \(r, s, t\in V(T)\), such that s lies on the path from r to t, we have \(\chi (r) \cap \chi (t) \subseteq \chi (s)\). We let \({{\,\mathrm{width}\,}}(\mathcal {T}) \,\mathrel {\mathop :}=\max _{t\in V(T)}|\chi (t)|-1\). The treewidth \({{\,\mathrm{tw}\,}}(G)\) of G is the minimum \({{\,\mathrm{width}\,}}({\mathcal {T}})\) over all TDs \(\mathcal {T}\) of G. For a node \(t \in V(T)\), we say that \({{\,\mathrm{type}\,}}(t)\) is \(\textit{leaf}\) if t has no children and \(\chi (t)=\emptyset \); \(\textit{join}\) if t has children \(t'\) and \(t''\) with \(t'\ne t''\) and \(\chi (t) = \chi (t') = \chi (t'')\); \(\textit{intr}\) (“introduce”) if t has a single child \(t'\), \(\chi (t') \subseteq \chi (t)\) and \(|\chi (t)| = |\chi (t')| + 1\); \(\textit{rem}\) (“removal”) if t has a single child \(t'\), \(\chi (t') \supseteq \chi (t)\) and \(|\chi (t')| = |\chi (t)| + 1\). If for every node \(t\in V(T)\), \({{\,\mathrm{type}\,}}(t) \in \{ \textit{leaf}, \textit{join}, \textit{intr}, \textit{rem}\}\), the TD is called nice. A nice TD can be computed from a given TD \(\mathcal {T}\) in linear time without increasing the width [31], assuming the width of \(\mathcal {T}\) is fixed.

Example 1

Figure 1 depicts a graph G and a (non-nice) TD \(\mathcal {T}\) of G of width 2.

Relational Algebra. We formalize DP algorithms by means of relational algebra [11], similar to related work [24]. A table \(\tau \) is a finite set of rows r over a set \({{\,\mathrm{att}\,}}(\tau )\) of attributes. Each row \(r\in \tau \) is a set of pairs (av) with \(a\in {{\,\mathrm{att}\,}}(\tau )\) and v in domain \({{\,\mathrm{dom}\,}}(a)\) of a, s.t. for each \(a\in {{\,\mathrm{att}\,}}(\tau )\) there is exactly one \((a,v)\in r\). Notably, apart from counters we use mainly binary domains in this paper.

Selection of rows in \(\tau \) according to a Boolean formula \(\varphi \) is defined by \(\sigma _{\varphi }(\tau )\,\mathrel {\mathop :}=\{ r \mid r\in \tau , \varphi [{{\,\mathrm{ass}\,}}(r)]=\emptyset \}\), assuming that \({{\,\mathrm{ass}\,}}(r)\) refers to the truth assignment over the attributes of binary domain of a given row \(r\in \tau _{}\). Given a relation \(\tau '\) with \({{\,\mathrm{att}\,}}(\tau ')\cap {{\,\mathrm{att}\,}}(\tau )=\emptyset \), we refer to the cross-join by \(\tau \times \tau '\,\mathrel {\mathop :}=\{ r\cup r' \mid r\in \tau , r'\in \tau '\}\). Further, a join (using \(\varphi \)) corresponds to \(\tau \bowtie _\varphi \tau ' \,\mathrel {\mathop :}=\sigma _\varphi (\tau \times \tau ')\). We define renaming of \(\tau \), given a set A of attributes, and a bijective mapping \(m:{{\,\mathrm{att}\,}}(\tau ) \rightarrow A\) by \(\rho _m(\tau ) \,\mathrel {\mathop :}=\{(m(a),v) \mid (a,v)\in \tau \}\). \(\tau \) projected to \(A\subseteq {{\,\mathrm{att}\,}}(\tau )\) is given by \(\Pi _{A}(\tau )\,\mathrel {\mathop :}=\{r_A \mid r\in \tau \}\), where \(r_A \,\mathrel {\mathop :}=\{(a, v) \mid (a, v) \in r, a \in A\}\). This is lifted to extended projection \(\dot{\Pi }_{A,(a \leftarrow f)}\), assuming attribute \(a\in {{\,\mathrm{att}\,}}(\tau )\setminus A\) and arithmetic function \(f: \tau \rightarrow \mathbb {N}\). Formally, we define \(\dot{\Pi }_{A,(a \leftarrow f)}(\tau )\,\mathrel {\mathop :}=\{r_A \cup \{(a, f(r))\} \mid r\in \tau \}\). We use aggregation by grouping \(_A G_{(a\leftarrow g)}\), where we assume \(A\subseteq {{\,\mathrm{att}\,}}(\tau ), a\in {{\,\mathrm{att}\,}}(\tau )\setminus A\) and an aggregate function \(g: 2^\tau \rightarrow {{\,\mathrm{dom}\,}}(a)\). We define \(_A G_{(a\leftarrow g)}(\tau )\,\mathrel {\mathop :}=\{r\cup \{(a,g(\tau [r]))\} \mid r\in \Pi _{A}(\tau )\}\), where \(\tau [r]\,\mathrel {\mathop :}=\{r'\mid r'\in \tau , r'\supseteq r\}\).

3 Towards Nested Dynamic Programming

A solver based on dynamic programming (DP) evaluates a given input instance \(\mathcal {I}\) in parts along a given TD of a graph representation G of the instance. Thereby, for each node t of the TD, intermediate results are stored in a table \(\tau _{t}\). This is achieved by running a so-called table algorithm, which is designed for a certain graph representation, and stores in \(\tau _{t}\) results of problem parts of \(\mathcal {I}\), thereby considering tables \(\tau _{t'}\) for child nodes \(t'\) of t. DP works for many problems:

  1. 1.

    Construct a graph representation G of \(\mathcal {I}\).

  2. 2.

    Compute (some) tree decomposition \(\mathcal {T}=(T,\chi )\) of G.

  3. 3.

    Traverse the nodes of T in post-order (bottom-up tree traversal of T). At every node t of T during post-order traversal, execute a table algorithm that takes as input bag \(\chi (t)\), a certain bag instance \(\mathcal {I}_t\) depending on the problem, as well as previously computed child tables of t. Then, the results of this execution are stored in table \(\tau _{t}\).

  4. 4.

    Finally, interpret table \(\tau _{n}\) for the root node n of T in order to output the solution to the problem for instance \(\mathcal {I}\).

figure a

Having relational algebra and this paradigm at hand, we exemplarily show how to solve \(\textsc {\#Sat} \), required for solving \(\textsc {\#}\exists \textsc {Sat} \) later. To this end, we need the following graph representation for a given formula \(\varphi \). The primal graph \(G_\varphi \) [44] of a formula \(\varphi \) has as vertices its variables, where two variables are joined by an edge if they occur together in a clause of \(\varphi \). Given a TD \(\mathcal {T}=(T,\chi )\) of \(G_\varphi \) and a node t of T. Then, we let bag instance \(\varphi _t\) of \(\varphi \), called bag formula, be the clauses \(\{\,c \;{|}\;c \in \varphi , {{\,\mathrm{var}\,}}(c) \subseteq \chi (t)\,\}\) entirely covered by the bag \(\chi (t)\).

Now, the only ingredient that is still missing for solving \(\textsc {\#Sat} \) via dynamic programming along a given TD, is the table algorithm \(\textsc {\#}\textsc {Sat}_t\). For brevity, table algorithm \(\textsc {\#}\textsc {Sat}_t\) as presented in Listing 1 shows the four cases corresponding to the four node types of a nice TD, as any TD node forms just an overlap of these four cases. Each table \(\tau _{t}\) consists of rows using attributes \(\chi (t)\cup \{\text {cnt}\}\), representing an assignment of \(\varphi _t\) and \(\text {cnt}\) is a counter. Then, the table \(\tau _{t}\) for a leaf node t, where \({{\,\mathrm{type}\,}}(t)=\textit{leaf}\), consists of the empty assignment and counter 1, cf., Line 1. For nodes t with introduced variable \(a\in \chi (t)\), we guess in Line 3 for each assignment of the child table, whether a is set to true or to false, and ensure that \(\varphi _t\) is satisfied. When an atom a is removed in a remove node t, we project assignments of child tables to \(\chi (t)\), cf., Line 5, and sum up counters of the same assignments. For join nodes, counters of equal assignments are multiplied (Line 7).

Example 2

Let \(\varphi {:=}\{\overbrace{\{\lnot x, y, a\}}^{c_1}, \overbrace{\{x, \lnot y, \lnot a\}}^{c_2},\overbrace{\{x, b\}}^{c_3},\overbrace{\{x, \lnot b\}}^{c_4}\}\). Observe that G of Fig. 1 is the primal graph \(G_\varphi \) and that there are 6 satisfying assignments of \(\varphi \). We discuss selected cases of running algorithm \(\textsc {\#}\textsc {Sat}_t\) on each node t of TD \(\mathcal {T}_{\text {nice}}\) of Fig. 2 in post-order, thereby evaluating \(\varphi \) in parts. Observe that \({{\,\mathrm{type}\,}}(t_1)=\textit{leaf}\). Consequently, \(\tau _{1}=\{ \{{(\text {cnt}, 1)}\} \}\), cf., Line 1. Nodes \(t\in \{t_2, t_3, t_4\}\) are of \({{\,\mathrm{type}\,}}(t)=\textit{intr}\). Thus, we cross-join table \(\tau _{1}\) with \(\{\{(x,0)\}, \{(x,1)\}\}\) (two possible truth assignments for x), cf., Line 3, which is cross-joined with \(\{\{(a,0)\}, \{(a,1)\}\}\), and then with \(\{\{(y,0)\}, \{(y,1)\}\}\). Then, for node \(t_4\) we additionally filter, cf., Line 3, those rows, where \(\varphi _{t_4}=\{c_1,c_2\}\) is satisfied and obtain table \(\tau _{4}\). Node \(t_5\) is of \({{\,\mathrm{type}\,}}(t_5)=\textit{rem}\), where a is removed, i.e., by the properties of TDs, it is guaranteed that all clauses of \(\varphi \) using a are checked below \(t_5\) and that no clause involving a will occur above \(t_4\). Consequently, \(\tau _{5}\) is obtained from \(\tau _{4}\) by projecting to \(\{x,y\}\) and summing up the counters \(\text {cnt}\) of rows of equal assignments correspondingly, cf., Line 5. Similarly, one proceeds with \(\tau _{6}\) and the right part of the tree, obtaining tables \(\tau _{7}-\tau _{10}\). In node \(t_{11}\), we join common assignments of tables \(\tau _{6}\) and \(\tau _{10}\), and multiply counters \(\text {cnt}\) accordingly. Finally, we obtain 6 satisfying assignments, as expected. In all the tables the corresponding parts of assignment I, where xyb are set to 1 and a is set to 0 are highlighted.

Fig. 2.
figure 2

Tables obtained by \(\textsc {\#}\textsc {Sat}_t\) on \(\mathcal{T}_{\text {nice}}\) for \(\varphi \) of Example 2.

Although these tables obtained via table algorithms might be exponential in size, the size is bounded by the width of the given TD of the primal graph \(G_\varphi \). Still, practical results of such algorithms show competitive behaviour [3, 25] up to a certain width. As a result, instances with high (tree-)width seem out of reach. Even further, if we lift the table algorithm \(\textsc {\#Sat} _t\) in order to solve problem \(\textsc {\#}\exists \textsc {Sat} \), we are double exponential in the treewidth [23] and suffer from a rather complicated algorithm. To mitigate these issues, we present a novel approach to deal with high treewidth, by nesting of DP on abstractions of \(G_\varphi \). As we will see, this not only works for  \(\textsc {\#Sat} \), but also for \(\textsc {\#}\exists \textsc {Sat} \) with adaptions.

3.1 Essentials for Nested Dynamic Programming

Assume that a set U of variables of \(\varphi \), called nesting variables, appears uniquely in one TD node t. Then, one could do DP on the TD as before, but no truth value for any variable in U is stored. Instead, clauses involving U could be evaluated by nested DP within node t, since variables U appear uniquely in t. Indeed, for DP on the other (non-nesting) variables, only the result of this evaluation is essential. Now, before we can apply nested DP, we need abstractions with room for choosing nesting variables between the empty set and the set of all the variables. Inspired by related work [16, 20, 26, 29], we define the nested primal graph \(N_\varphi ^A\) for a given formula \(\varphi \) and a given set \(A\subseteq {{\,\mathrm{var}\,}}(\varphi )\) of abstraction variables. To this end, we say a path P in primal graph \(G_\varphi \) is a nesting path (between u and v) using A, if \(P=u, v_1, \ldots , v_\ell , v\) (\(\ell \ge 0\)), and every vertex \(v_i\) is a nesting variable, i.e., \(v_i\notin A\) for \(1\le i\le \ell \). Note that any path in \(G_\varphi \) is nesting using A if \(A=\emptyset \). Then, the vertices of nested primal graph \(N_\varphi ^A\) correspond to A and there is an edge between two vertices \(u,v\in A\) if there is a nesting path between u and v. Observe that the nested primal graph only consists of abstraction variables and, intuitively, “hides” nesting variables in nesting paths of primal graph \(G_\varphi \).

figure b

Example 3

Recall formula \(\varphi \) and primal graph \(G_\varphi \) of Example 2. Given abstraction variables \(A\,{=}\,\{x,y\}\), nesting paths of \(G_\varphi \) are, e.g., \(P_1\,{=}\,x\), \(P_2\,{=}\,x,b\), \(P_3\,{=}\,b,x\), \(P_4\,{=}\,x,y\), \(P_5\,{=}\,x,a,y\). However, neither path \(P_6\,{=}\,y,x,b\), nor path \(P_7\,{=}\,b,x,y,a\) is nesting using A. Nested primal graph \(N_\varphi ^A\) contains edge \(\{x,y\}\) over vertices A due to paths \(P_4, P_5\).

The nested primal graph provides abstractions of needed flexibility for nested DP. Indeed, if we set abstraction variables to \(A\,{=}\,{{\,\mathrm{var}\,}}(\varphi )\), we end up with full DP and zero nesting, whereas setting \(A\,{=}\,\emptyset \) results in full nesting, i.e., nesting of all variables. Intuitively, the nested primal graph ensures that clauses subject to nesting (containing nesting variables) can be safely evaluated in exactly one node of a TD of the nested primal graph. To formalize this, we let \( nestReach (U)\) for any set \(U\subseteq {{\,\mathrm{var}\,}}(\varphi )\) of variables containing nesting variables (\(U\not \subseteq A\)), be the set of vertices of all nesting paths of \(G_\varphi \) between vertices ab using A such that (i) both \(a,b\in U\), or (ii) \(a\in U\setminus A\). Intuitively, this definition ensures that from a given set U of variables, we obtain reachable (i) nesting and (ii) abstraction variables, needed to evaluate clauses over U. Then, assuming a TD \(\mathcal {T}\) of \(N_\varphi ^A\), we say a set \(U\subseteq {{\,\mathrm{var}\,}}(\varphi )\) of variables (“compatible set”) is compatible with a node t of \(\mathcal {T}\), and vice versa, if (I) \(U= nestReach (U)\), and (II) \(U\cap A\subseteq \chi (t)\).

Example 4

Assume again formula \(\varphi \), primal graph \(G_\varphi \) and abstraction variables \(A=\{x,y\}\) of the previous example. Further, consider any TD \((T,\chi )\) of \(N_\varphi ^A\). Observe that \( nestReach (\{b\})=\{b,x\}\) due to nesting path bx, i.e., \(\{b\}\) is not a compatible set. However, \(\{b,x\}\) is compatible with any node t of T where \(x\in \chi (t)\). Indeed, to evaluate clauses \(c_3,c_4\in \varphi \), we need to evaluate both b and x. Similarly, \(\{a,x\}\) is not a compatible set due to nesting path ay, but \(\{a,x,y\}\) is a compatible set. Also, \(\{a,b,x,y\}\) is a compatible set.

By construction any nesting variable is in at least one compatible set. However, (1) a nesting variable could be even in several compatible sets, and (2) a compatible set could be compatible with several nodes of \(\mathcal {T}\). Hence, to allow nested evaluation, we need to ensure that each nesting variable is evaluated only in one unique node t. As a result, we formalize for every compatible set U that is subset-minimal, a unique node t compatible with U, denoted by \({{\,\mathrm{comp}\,}}(U)\,\mathrel {\mathop :}=t\). For simplicity of our algorithms, we assume these unique nodes for U are introduce nodes, i.e., \({{\,\mathrm{type}\,}}(t)=\textit{intr}\). We denote the union of all compatible sets U where \({{\,\mathrm{comp}\,}}(U)=t\), by nested bag variables \(\chi _t^A\). Then, the nested bag formula \(\varphi _t^A\) for a node t of \(\mathcal {T}\) equals \(\varphi _t^A\,\mathrel {\mathop :}=\{c\mid c\in \varphi , {{\,\mathrm{var}\,}}(c)\subseteq \chi _t^A\}{\,\setminus \,}\varphi _t\), where formula \(\varphi _t\) is defined above.

Example 5

Recall formula \(\varphi \), TD \(\mathcal {T}=(T,\chi )\) of \(G_\varphi \), and abstraction variables \(A=\{x,y\}\) of Example 3. Consider TD \(\mathcal {T}'\,\mathrel {\mathop :}=(T,\chi ')\), where \(\chi '(t)\,\mathrel {\mathop :}=\chi (t)\cap \{x,y\}\) for each node t of T. Observe that \(\mathcal {T}'\) is \(\mathcal {T}\), but restricted to A and that \(\mathcal {T}'\) is a TD of \(N_\varphi ^A\) of width 1. Observe that only for compatible set \(U=\{b,x\}\) we have two nodes compatible with U, namely \(t_2\) and \(t_3\). We assume \({{\,\mathrm{comp}\,}}(U)=t_2\). Consequently, nested bag formulas are \(\varphi _{t_1}^A=\{c_1,c_2\}\), \(\varphi _{t_2}^A=\{c_3,c_4\}\), and \(\varphi _{t_3}^A\,{=}\,\emptyset \).

Assume any TD \(\mathcal {T}\) of \(N_\varphi ^A\) using any set A of abstraction variables. Observe that the definitions of nested primal graph and nested bag formula ensure that any set S of vertices connected via edges in \(G_\varphi \) will “appear” among nested bag variables of some node of \(\mathcal {T}\). Even more stringent, each variable \(a \in {{\,\mathrm{var}\,}}(\varphi ) \setminus A\) appears only in nested bag formula \(\varphi _t^A\) of node t unique for a. These unique variable appearances allow to nest evaluating \(\varphi _t^A\) under some assignment to \(\chi (t)\).

figure c

3.2 Hybrid Solving Based on Nested DP

Now, we have definitions at hand to discuss nested DP in the context of hybrid solving, which combines using both standard solvers and parameterized solvers exploiting treewidth. We first illustrate the ideas for the problem \(\textsc {\#}\exists \textsc {Sat}\) and then discuss possible generalizations in Sect. 3.3; a concrete implementation is presented in Sect. 4.

Listing 2 depicts our algorithm \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}}\) for solving \(\textsc {\#}\exists \textsc {Sat} \). Note that the recursion is indirect in Line 18 through Line 4 of Listing 3 (discussed later). Algorithm \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}}\) takes formula \(\varphi \), projection variables \(P'\) and abstraction variables \(A'\). The algorithm uses a global, but rather naive and simple \({{\,\mathrm{cache}\,}}\) mapping a formula to an integer, and consists of four subsequent blocks of code, separated by empty lines: (1) Preprocessing & Cache Consolidation, (2) Standard Solving, (3) Abstraction & Decomposition, and (4) Nested DP.

Block (1) spans Lines 1–3 and performs Boolean conflict propagation and preprocessing, thereby obtaining projection variables \(P\subseteq P'\) (preserving satisfying assignments w.r.t. \(P'\)), sets A to \(A'\cap P\) in Line 2, and consolidates \({{\,\mathrm{cache}\,}}\) with the updated formula \(\varphi \). If \(\varphi \) is not cached, we do standard solving if the width is out-of-reach for nested DP in Block (2), spanning Lines 4–10. More concretely, if \(\varphi \) does not contain projection variables, we employ a Sat solver returning integer 1 or 0. If \(\varphi \) contains projection variables and either the width obtained by heuristically decomposing \(G_\varphi \) is above \(\text {threshold}_{\text {hybrid}}\), or the nesting depth exceeds \(\text {threshold}_{\text {depth}}\), we use a standard #Sat or \(\textsc {\#}\exists \textsc {Sat}\) solver depending on \({{\,\mathrm{var}\,}}(\varphi )\cap P\). Block (3) spans Lines 11–13 and is reached if no cache entry was found in Block (1) and standard solving was skipped in Block (2). If the width of the computed decomposition is above \(\text {threshold}_{\text {abstr}}\), we need to use an abstraction in form of the nested primal graph. This is achieved by choosing suitable subsets \(E \subseteq A\) of abstraction variables and decomposing \(\varphi _t^{E}\) heuristically. Finally, Block (4) concerns nested DP, cf., Lines 14–20. This block relies on nested table algorithm \(\textsc {\#}\exists \textsc {Sat}_t\), which takes parameters similar to table algorithm \(\textsc {\#}\textsc {Sat}_t\), but additionally requires the nested bag formula for current node t, projection variables P and abstraction variables. Nested table algorithm \(\textsc {\#}\exists \textsc {Sat}_t\) is sketched in Listing 3 and recursively calls for each row \(r\in \tau _{t}\), \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}}\) on nested bag formula \(\varphi _t^A\) simplified by the assignment \({{\,\mathrm{ass}\,}}(r)\) of the current row r. This is implemented in Line 4 by using extended projection, cf., Listing 1, where the count cnt of the respective row r is updated by multiplying the result of the recursive call \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}}\). Notably, as the recursive call \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}}\) within extended projection of Line 4 implicitly takes a given current row r, the function occurrences \({{\,\mathrm{ass}\,}}\) in Line 4 implicitly take this row r as an argument. As a result, our approach deals with high treewidth by recursively finding and decomposing abstractions of the graph. If the treewidth is too high for some parts, TDs of abstractions are used to guide standard solvers.

Fig. 3.
figure 3

Selected tables obtained by nested DP on TD \(\mathcal{T}'\) of \(N_\varphi ^{\{x,y\}}\) (left) and on TD \(\mathcal {T}''\) of \(N_\varphi ^{\{x\}}\) (right) for \(\varphi \) and projection variables \(P=\{x,y\}\) of Example 6 via \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}_t}\).

Example 6

Recall formula \(\varphi \), set A of abstraction variables, and TD \(\mathcal {T}'\) of nested primal graph \(N_\varphi ^A\) given in Example 5. Restricted to projection set \(P\,\mathrel {\mathop :}=\{x,y\}\), \(\varphi \) has two satisfying assignments, namely \(\{x\mapsto 1, y\mapsto 0\}\) and \(\{x\mapsto 1, y\mapsto 1\}\). Consequently, the solution to \(\textsc {\#}\exists \textsc {Sat} \) is 2. Figure 3 (left) shows TD \(\mathcal {T}'\) of \(N_\varphi ^A\) and tables obtained by \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}_t}(\varphi ,P,A)\) for solving projected model counting on \(\varphi \) and P. Note that the same example easily works for \(\textsc {\#Sat} \), where \(P={{\,\mathrm{var}\,}}(\varphi )\).

Algorithm \(\textsc {\#}\exists \textsc {Sat}_t\) of Listing 3 works similar to algorithm \(\textsc {\#}\textsc {Sat}_t\), but uses attribute “cnt” for storing (projected) counts accordingly. We briefly discuss executing \(\textsc {\#}\exists \textsc {Sat}_{t_1}\) in the context of Line 18 of algorithm \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}_t}\) on node \(t_1\) of \(\mathcal {T}'\), resulting in table \(\tau _{1}\) as shown in Fig. 3 (left). Recall that \({{\,\mathrm{comp}\,}}(\{a,x,y\})=t_1\), and, consequently, \(\varphi _{t_1}^A=\{\{\lnot x, y, a\},\{x,\lnot y, \lnot a\}\}\). Then, in Line 4 of algorithm \(\textsc {\#}\exists \textsc {Sat}_t\), for each assignment \({{\,\mathrm{ass}\,}}(r)\) to \(\{x,y\}\) of each row r of \(\tau _{1}\), we compute \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}_t}(\psi , P\cap {{\,\mathrm{var}\,}}(\psi ), \emptyset )\) using \(\psi \,{=}\,\varphi _{t_1}^A[{{\,\mathrm{ass}\,}}(r)]\). Each of these recursive calls, however, is already solved by BCP and preprocessing, e.g., \(\varphi _{t_1}^A[\{x\mapsto 1, y \mapsto 0\}]\) of Row 2 simplifies to \(\{\{a\}\}\).

Figure 3 (right) shows TD \(\mathcal {T}''\) of \(N_\varphi ^{E}\) with \(E\,\mathrel {\mathop :}=\{x\}\), and tables obtained by \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}_t}(\varphi , P, E)\). Still, \(\varphi _{t_1}^E[{{\,\mathrm{ass}\,}}(r)]\) for a given assignment \({{\,\mathrm{ass}\,}}(r): \{x\}\rightarrow \{0,1\}\) of any row \(r\in \tau _{1}\) can be simplified. Concretely, \(\varphi _{t_1}^E[\{x\mapsto 0\}]\) evaluates to \(\emptyset \) and \(\varphi _{t_1}^E[\{x\mapsto 1\}]\) evaluates to two variable-distinct clauses, namely \(\{\lnot b\}\) and \(\{y, a\}\). Thus, there are 2 satisfying assignments \(\{y\mapsto 0\}\), \(\{y\mapsto 1\}\) of \(\varphi _{t_1}^E[\{x\mapsto 1\}]\) restricted to P.

figure d

Theorem 1

Given formula \(\varphi \), projection variables \(P\subseteq {{\,\mathrm{var}\,}}(\varphi )\), and abstraction variables \(A'\subseteq {{\,\mathrm{var}\,}}(\varphi )\). Then, \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}}(\varphi , P, A')\) correctly returns \(\textsc {\#}\exists \textsc {Sat} (\varphi , P)\).

Proof

(Sketch). Observe that (A): \((T,\chi )\) is a TD of nested primal graph \(N_\varphi ^A\) such that \(A\subseteq A'\cap P\). The interesting part of algorithm \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}}\) lies in Block (3), in particular in Lines 11–13. The proof proceeds by structural induction on \(\varphi \). By construction, we have (B): Every variable of \({{\,\mathrm{var}\,}}(\varphi )\setminus A\) occurs in some nested bag formula \(\varphi _{t}^A\) as used in the call to \(\textsc {\#}\exists \textsc {Sat}_t\) in Line 18 for a unique node t of T. Observe that \(\textsc {\#}\exists \textsc {Sat}_t\) corresponds to \(\textsc {\#}\textsc {Sat}_t\), whose correctness is established via invariants, cf., [24, 44], only Line 4 differs. In Line 4 of \(\textsc {\#}\exists \textsc {Sat}_t\), \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}}\) is called recursively on subformulas \(\varphi _t^A[{{\,\mathrm{ass}\,}}(r)]\) for each \(r\in \tau _{t}\). By induction hypothesis, we have (C): these calls result to \(\textsc {\#}\exists \textsc {Sat} (\varphi _t^A[{{\,\mathrm{ass}\,}}(r)], P\cap {{\,\mathrm{var}\,}}(\varphi _t^A[{{\,\mathrm{ass}\,}}(r)]))\) for each \(r\in \tau _{t}\). By (A), \(\textsc {\#}\exists \textsc {Sat}_t\) as called in Line 18 stores only table attributes in \(\chi _t\subseteq A\subseteq P\). Thus, by (C), recursive calls can be subsequently multiplied to cnt for each \(r\in \tau _{t}\).

3.3 Generalizing Nested DP to Other Formalisms

Nested DP as proposed above is by far not restricted to (projected) model counting, or counting problems in general. In fact, one can easily generalize nested DP to other relevant formalisms, briefly sketched for the QBF formalism.

Quantified Boolean Formulas (QBFs). We assume QBFs of the form \(\varphi =\exists V_1. \forall V_2. \ldots \) \(\exists V_\ell . \gamma \) using quantifiers \(\exists , \forall \), where \(\gamma \) is a CNF formula and \({{\,\mathrm{var}\,}}(\varphi )={{\,\mathrm{var}\,}}(\gamma )=V_1\cup V_2 \cdots \cup V_\ell \). Given QBF \(\varphi =Q\ V. \psi \) with \(Q\in \{\exists , \forall \}\), we let \({{\,\mathrm{qvar}\,}}(\varphi )\,\mathrel {\mathop :}=V\). For an assignment \(I: V' \rightarrow \{0,1\}\) with \(V'\subseteq V\), we let \(\varphi [I] \,\mathrel {\mathop :}=\psi [I]\) if \(V'\,{=}\,V\), and \(\varphi [I]\,\mathrel {\mathop :}=Q(V\setminus V'). \psi [I]\) if \(V'{\subsetneq }V\). Validity of \(\varphi \) (\(\textsc {QSat}\)) is recursively defined: \(\exists V.\varphi \) is valid if there is \(I{:}~V \rightarrow \{0,1\}\) where \(\varphi [I]\) is valid; \(\forall V. \varphi \) is valid if for every \(I{:}~V\rightarrow \{0,1\}\), \(\varphi [I]\) is valid.

Hybrid solving by nested DP can be extended to problem \(\textsc {QSat}\). To the end of using this approach for QBFs, we define the primal graph \(G_\varphi \) for a QBF \(\varphi =\exists V_1. \forall V_2. \ldots \exists V_\ell . \gamma \) analogously to the primal graph of a Boolean formula, i.e., \(G_\varphi \,\mathrel {\mathop :}=G_\gamma \). Consequently, also the nested primal graph is defined for a given set \(A\subseteq {{\,\mathrm{var}\,}}(\varphi )\) by \(N_\varphi ^A\,\mathrel {\mathop :}=N_\gamma ^A\). Now, let \(A\subseteq {{\,\mathrm{var}\,}}(\varphi )\) be a set of abstraction variables, and \(\mathcal {T}=(T,\chi )\) be a TD of \(N_\varphi ^A\) and t be a node of T. Then, the bag QBF \(\varphi _t\) is given by \(\varphi _t\,\mathrel {\mathop :}=\exists V_1. \forall V_2. \ldots \exists V_\ell . \gamma _t\) and the nested bag QBF \(\varphi _t^A\) for a set \(A\subseteq {{\,\mathrm{var}\,}}(\varphi )\) amounts to \(\varphi _t^A\,\mathrel {\mathop :}=\exists V_1. \forall V_2. \ldots \exists V_\ell . \gamma _t^A\).

Algorithm \(\mathtt {HybDP}_{\textsc {QSat}}\) is similar to \(\mathtt {HybDP}_{\textsc {\#}\exists \textsc {Sat}}\) of Listing 2, where the projection variables parameter \(P'\) is removed since \(P'\) constantly coincides with variables \({{\,\mathrm{qvar}\,}}(\varphi )\) of the outermost quantifier. Further, Line 4 is removed, Lines 8 and 9 are replaced by calling a \(\textsc {QSat}\) solver and nested table algorithm \(\textsc {\#}\exists \textsc {Sat}_t\) of Line 18 is replaced by nested table algorithm \(\textsc {QSat}_t\) as presented in Listing 4. Algorithm \(\textsc {QSat}_t\) is of similar shape as algorithm \(\textsc {\#}\exists \textsc {Sat}_t\), cf., Listing 3, but does not maintain counts \(\text {cnt}\). Further, Line 4 of algorithm \(\textsc {QSat}_t\) intuitively filters \(\tau _{t}\) fulfilling the outer-most quantifier, and keeps those rows r of \(\tau _{t}\), where the recursive call to \(\mathtt {HybDP}_{\textsc {QSat}}\) on nested bag formula simplified by the assignment \({{\,\mathrm{ass}\,}}(r)\) of r succeeds. For ensuring that the outer-most quantifier Q is fulfilled, we are either in the situation that \(Q=\exists \), which immediately is fulfilled for every row r in \(\tau _{t}\) since r itself serves as a witness. If \(Q=\forall \), we need to check that \(\tau _{t}\) contains \(2^{|\chi (t)|}\) many (all) rows. The cardinality of table \(\tau _{t}\) can be computed via a sub-expression of relational algebra as hinted in the footnote of Listing 4. Notably, if \(Q=\forall \), we do not need to check in Line 8 of Listing 4, whether all rows sustain in table \(\tau _{t}\) since this is already ensured for both child tables \(\tau _{1},\tau _{2}\) of t. Then, if in the end the table for the root node of \(\mathcal {T}\) is not empty, it is guaranteed that either the table contains some (if \(Q=\exists \)) or all (if \(Q=\forall \)) rows and that \(\varphi \) is valid. Note that algorithm \(\textsc {QSat}_t\) can be extended to also consider more fine-grained quantifier dependency schemes.

Compared to other algorithms for \(\textsc {QSat}\) using treewidth [9, 10], hybrid solving based on nested DP is quite compact without the need of nested tables. Instead of rather involved data structures (nested tables), we use here plain tables that can be handled by modern database systems efficiently.

4 Implementation and Preliminary Results

We implemented a hybrid solver nestHDBFootnote 1 based on nested DP in Python3 and using table manipulation techniques by means of SQL and the database management system (DBMS) Postgres. Our solver builds upon the recently published prototype dpdb  [24], which applied a DBMS for plain dynamic programming algorithms. However, we used the most-recent version 12 of Postgres and we let it operate on a tmpfs-ramdisk. In our solver, the DBMS serves the purpose of extremely efficient in-memory table manipulations and query optimization required by nested DP, and therefore nestHDB benefits from database technology.

Nested DP & Choice of Standard Solvers. We implemented dedicated nested DP algorithms for solving #Sat and \(\textsc {\#}\exists \textsc {Sat}\), where we do (nested) DP up to \(\text {threshold}_{\text {depth}}=2\). Further, we set \(\text {threshold}_{\text {hybrid}}=1000\) and therefore we do not “fall back” to standard solvers based on the width (cf., Line 7 of Listing 2), but based on the nesting depth.

Also, the evaluation of the nested bag formula is “shifted” to the database if it uses at most 40 abstraction variables, since Postgres efficiently handles these small-sized Boolean formulas. Thereby, further nesting is saved by executing optimized SQL statements within the TD nodes. A value of 40 seems to be a nice balance between the overhead caused by standard solvers for small formulas and exponential growth counteracting the advantages of the DBMS. For hybrid solving, we use #Sat solver sharpSAT  [48] and for \(\textsc {\#}\exists \textsc {Sat}\) we employ the recently published \(\textsc {\#}\exists \textsc {Sat}\) solver projMC  [35], solver sharpSAT and Sat solver picosat  [4]. Observe that our solver immediately benefits from better standard solvers and further improvements of the solvers above.

Choosing Non-nesting Variables & Compatible Nodes. TDs are computed by means of heuristics via decomposition library htd  [1]. For finding good abstractions (crucial), i.e., abstraction variables for the nested primal graph, we use encodings for solver clingo  [27], which is based on logic programming (ASP) and therefore perfectly suited for solving reachability via nesting paths. There, among a reasonably sized subset of vertices of smallest degree, we aim for a preferably large (maximal) set A of abstraction variables such that at the same time the resulting graph \(N_\varphi ^A\) is reasonably sparse, which is achieved by minimizing the number of edges of \(N_\varphi ^A\). To this end, we use built-in (cost) optimization, where we take the best results obtained by clingo after running at most 35 s. For the concrete encodings used in nestHDB, we refer to the online repository as stated above. We expect that this initial approach can be improved and that extending by problem-specific as well as domain-specific information might help in choosing promising abstraction variables A.

As rows of tables during (nested) DP can be independently computed and parallelized [25], hybrid solver nestHDB potentially calls standard solvers for solving subproblems in parallel using a thread pool. Thereby, the uniquely compatible node for relevant compatible sets U, as denoted in this paper by \({{\,\mathrm{comp}\,}}(U)\), is decided during runtime among compatible nodes on a first-come-first-serve basis.

Fig. 4.
figure 4

Cactus plot of instances for #Sat, where instances (x-axis) are ordered for each solver individually by runtime[seconds] (y-axis). \(\text {threshold}_{\text {abstr}}=38\).

Benchmarked Solvers & Instances. We benchmarked nestHDB and 16 other publicly available #Sat solvers on 1,494 instances recently considered [24]. Among those solvers are single-core solvers miniC2D [41], d4 [34], c2d [13], ganak [46], sharpSAT [48], sdd [14], sts [21], dsharp [39], cnf2eadt [32], cachet [45], sharpCDCL [30], approxmc3 [8], and bdd_minisat [49]. We also included multi-core solvers dpdb  [24], gpusat2 [25], as well as countAntom [7]. While nestHDB itself is a multi-core solver, we additionally included in our comparison nestHDB(sc), which is nestHDB, but restricted to a single core only. The instances [24] we took are already preprocessed by pmc  [33] using recommended options -vivification -eliminateLit -litImplied -iterate=10 -equiv -orGate -affine for preserving model counts. However, nestHDB still uses pmc with these options also in Line 1 of Listing 2.

Further, we considered the problem \(\textsc {\#}\exists \textsc {Sat}\), where we compare solvers projMC  [35], clingo  [27], ganak  [46], nestHDB (see footnote 1), and nestHDB(sc) on 610 publicly available instancesFootnote 2 from projMC (consisting of 15 planning, 60 circuit, and 100 random instances) and Fremont, with 170 symbolic-markov applications, and 265 misc instances. For preprocessing in Line 1 of Listing 2, nestHDB uses pmc as before, but without options -equiv -orGate -affine to ensure preservation of models (equivalence).

Fig. 5.
figure 5

Number of solved \(\textsc {\#}\exists \textsc {Sat}\) insts., grouped by upper bound intervals of treewidth (left), cactus plot (right). time[h] is cumulated wall clock time, timeouts count as 900 s. \(\text {threshold}_{\text {abstr}}\,{=}\,8\).

Benchmark Setup. Solvers ran on a cluster of 12 nodes. Each node of the cluster is equipped with two Intel Xeon E5-2650 CPUs consisting of 12 physical cores each at 2.2 GHz clock speed, 256 GB RAM. For dpdb and nestHDB, we used Postgres 12 on a tmpfs-ramdisk (/tmp) that could grow up to at most 1 GB per run. Results were gathered on Ubuntu 16.04.1 LTS machines with disabled hyperthreading on kernel 4.4.0-139. We mainly compare total wall clock time and number of timeouts. For parallel solvers (dpdb, countAntom, nestHDB) we allow 12 physical cores. Timeout is 900 s and RAM is limited to 16 GB per instance and solver. Results for gpusat2 are taken from [24].

Benchmark Results. The results for #Sat showing the best 14 solvers are summarized in the cactus plot of Fig. 4. Overall it shows nestHDB among the best solvers, solving 1,273 instances. The reason for this is, compared to dpdb, that nestHDB can solve instances using TDs of primal graphs of widths larger than 44, up to width 266. This limit is even slightly larger than the width of 264 that sharpSAT on its own can handle. We also tried using minic2d instead of sharpSAT as standard solver for solvers nestHDB and nestHDB(sc), but we could only solve one instance more. Notably, nestHDB(sc) has about the same performance as nestHDB, indicating that parallelism does not help much on the instances. Further, we observed that the employed simple cache as used in Listing 2, provides only a marginal improvement.

Figure 5 (left) depicts a table of results on \(\textsc {\#}\exists \textsc {Sat}\), where we observe that nestHDB does a good job on instances with low widths below \(\text {threshold}_{\text {abstr}}=8\) (containing ideas of dpdb), but also on widths well above 8 (using nested DP). Notably, nestHDB is also competitive on widths well above 50. Indeed, nestHDB and nestHDB(sc) perform well on all benchmark sets, whereas on some sets the solvers projMC, clingo and ganak are faster. Overall, parallelism provides a significant improvement here, but still nestHDB(sc) shows competitive performance, which is also visualized in the cactus plot of Fig. 5 (right). Figure 6 shows scatter plots comparing nestHDB to projMC (left) and to ganak (right). Overall, both plots show that nestHDB solves more instances, since in both cases the y-axis shows more black dots at 900 s than the x-axis. Further, the bottom left of both plots shows that there are plenty easy instances that can be solved by projMC and ganak in well below 50 s, where nestHDB needs up to 200 s. Similarly, the cactus plot given in Fig. 5 (right) shows that nestHDB can have some overhead compared to the three standard solvers, which is not surprising. This indicates that there is still room for improvement if, e.g., easy instances are easily detected, and if standard solvers are used for those instances. Alternatively, one could also just run a standard solver for at most 50 s and if not solved within 50 s, the heavier machinery of nested dynamic programming is invoked. Apart from these instances, Fig. 6 shows that nestHDB solves harder instances faster, where standard solvers struggle.

Fig. 6.
figure 6

Scatter plot of instances for \(\textsc {\#}\exists \textsc {Sat}\), where the x-axis shows runtime in seconds of nestHDB compared to the y-axis showing runtime of projMC (left) and of ganak (right). \(\text {threshold}_{\text {abstr}}=8\).

5 Conclusion

We presented nested dynamic programming (nested DP) using different levels of abstractions, which are subsequently refined and solved recursively. This approach is complemented with hybrid solving, where (search-intense) subproblems are solved by standard solvers. We provided nested DP algorithms for problems related to Boolean satisfiability, but the idea can be easily applied for other formalisms. We implemented some of these algorithms and our benchmark results are promising. For future work, we plan deeper studies of problem-specific abstractions, in particular for \(\textsc {QSat}\). We want to further tune our solver parameters (e.g., thresholds, timeouts, sizes), deepen interleaving with solvers like projMC, and to use incremental solving for obtaining abstractions and evaluating nested bag formulas, where intermediate solver references are kept during dynamic programming and formulas are iteratively added and (re-)solved.