Keywords

1 Introduction

The Boolean-Synthesis Problem [19] – a fundamental problem in computer-aided design – is the problem of taking in a declarative boolean relation between two sets of boolean variables – input and output – and generating boolean functions, called witness functions, that yield values to the output variables with respect to the input variables so as to satisfy the boolean relation. As a fundamental problem in computer-aided design, there are many applications of boolean synthesis in circuit design. For example, based on a circuit’s desired behavior, we can use boolean synthesis to automatically construct the missing components of the circuit [3]. In addition to being used in circuit design, boolean synthesis has recently found applications also in temporal synthesis [30, 31], where the goal is to construct a sequential circuit that responds to environment inputs in a way that is guaranteed to satisfy given temporal-logic specification.

Many approaches have been investigated for boolean synthesis, such as knowledge compilation [1], QBF solving [24], and machine learning [17, 18]. Here we build on previous work on boolean synthesis using Binary Decision Diagrams (BDDs) [28]. The main advantage of the decision-diagram approach is that it provides not just the synthesized witness functions, but also the realizability set of the specification, which is the set of inputs with respect to which the specification is realizable. In modular circuit design [19], where a system is composed of multiple modules that are independently constructed, it is imperative to confirm the realizability set of a module, as it has to match the output set of prior modules. Similarly, in the context of temporal synthesis [30, 31], the winning set is constructed iteratively by taking the union of realizability sets, where for each realizability set we construct a witness function. The winning strategy is then constructed by stitching together all these witness functions.

Motivated by applications that require the computation of both realizability sets and witness functions, we describe here a decision-diagram approach that can also handle partially realizable specifications, where the realizability set is neither empty nor necessarily universal. (Indeed, in our benchmark suit, about 30% of the benchmarks are partially realizable.) Our tool, DPSynth computes the realizability sets and witness functions with respects to these sets. While several recent synthesis tools do provide witnesses for partially-realizable specifications, cf. [1, 17, 18], not all of them directly output the realizability set, requiring it, instead, to be computed from the witnesses and the original formula.

The boolean-synthesis problem starts with a boolean formula \(\varphi (X,Y)\) over sets XY of input and output variables. The goal is to construct boolean formulas, called witness functions (sometimes called Skolem functions) [1, 18] – for the output variables expressed in terms of the input variables. The BDD-based approach to this problem [15] constructs the BDD \(B_\varphi (X,Y)\) for \(\varphi \), and then quantifies existentially over the Y variables to obtain a BDD over the X variables that captures the realizability set – the set of assignments \(\tau _X\) in \(2^X\) for which an assignment \(\tau _Y\) in \(2^Y\) exists where \(B_\varphi (\tau _X,\tau _y)=1\). The witness functions can then be constructed by iterating over the intermediate steps of the realizability computation [15].

A challenge of this BDD-based approach is that it is often infeasible to construct the BDD \(B_\varphi \). Factored Boolean Synthesis [28] assumes that the formula \(\varphi \) is given in conjunctive normal form (CNF), where the individual clauses are called factors. Rather than constructing the monolithic BDD \(B_\varphi \), this approach constructs a BDD for each factor, and then applies conjunction in a lazy way and existential quantification in an eager way, using various heuristics to order conjoining and quantifying. As shown in [28], the factored approach, Factored RSynth, is more scalable than the monolithic approach, RSynth. Thus, we use here Factored RSynth as the baseline for comparison in this paper.

By dynamic programming we refer to the approach that simplifies a complicated problem by breaking it down into simpler sub-problems in a recursive manner [5]. Unlike search-based approaches to Boolean reasoning, cf. [22], which directly manipulate truth assignments, we use data structure based on decision diagrams [7] that represents sets of truth assignments. This approach is referred to as symbolic, going back to [11].

The symbolic dynamic-programming approach we propose here is inspired by progress in weighted model counting, which is the problem of counting the number of satisfying (weighted) assignments of boolean formulas. Dudek, Phan, and Vardi proposed in [14], an approach based on Algebraic Decision Diagrams, which are the quantitative variants of BDDs [4]. Dudek et al. pointed out that a monolithic approach is not likely to be scalable, and proposed a factored approach, ADDMC, analogous to the approach in [28], in which conjunction is done lazily and quantification eagerly. In follow-up work [12], they proposed a more systematic way to order the quantification and conjunction operations, based on dynamic programming over project-join trees; the resulting tool, DPMC, was shown to scale better than ADDMC. In further follow-on work, they proposed graded project-join trees for projected model counting, where the input formula has two sets of variables – quantified variables and counting variables [13]. Graded project-join tree offers a recursive decomposition of the Boolean-Synthesis Problem into smaller tasks of projections and join.

We show here how symbolic dynamic programming over graded project-join trees can be applied to boolean synthesis. In our approach, realizability checking is done using a BDD-based bottom-up execution, analogous to the handling of counting quantifiers in [13]. This enables us to compute the realizability set and check its nonemptiness. We then present a novel algorithm for synthesizing the witness functions using top-down execution on graded project-join trees. (In contrast, [13] both types of quantifiers are handled bottom-up). We demonstrate the advantage of our bottom-up-top-down approach by developing a tool, DPSynth. For a fair evaluation, we compare its performance to Factored RSynth, which can also handle partially realizable specifications.

The main contributions of this work are as follows. First, we show how to adapt the framework of projected counting to Boolean synthesis. In projected counting there are two types of existential quantifiers – additive and disjunctive [13], while Boolean synthesis combine universal and existential quantifiers. Second, projected counting requires only a bottom-up pass over the graded project-join trees, while here we introduce an additional, top-down pass over the tree to perform the major part of boolean synthesis, which is, witness construction.

The organization of the paper is as follows. After preliminaries in Sect. 2, we show in Sect. 3 how to use graded project-join trees for boolean realizability checking, and show that DPSynth generally scales better than Factored RSynth. Then, in Sect. 4, we show how to extend this approach from realizability checking to witness-function construction. Experimental evaluation shows that DPSynth generally scales better than Factored RSynth also for witness-function construction. We offer concluding remarks in Sect. 6.

2 Preliminary Definitions

2.1 Boolean Formula and Synthesis Concepts

A boolean formula \(\varphi (X)\), over a set X of variables, represents a boolean function \(f: 2^{X} \rightarrow \mathbb {B}\), which selects subsets of \(2^{X}\). A truth assignment \(\tau \) satisfies \(\varphi \) iff \(\varphi (\tau ) = 1\). A boolean formula in conjunctive normal form (CNF) is a conjunction of clauses, where a clause is a disjunction of literals (a boolean variable or its negation). When \(\varphi \) is in CNF, we abuse notation and also use \(\varphi \) to denote its own set of clauses. Given a CNF formula \(\varphi (X,Y)\) over input and output variable X and Y, the realizability set of \(\varphi \), denoted \(R_\varphi (X) \subseteq 2^X\), is the set of assignments \(\sigma \in 2^X\) for which there exists an assignment \(\tau \in 2^Y\) such that \(\varphi (\sigma \cup \tau ) = 1\). When \(\varphi \) is clear from context, we simply denote the realizability set by R.

Definition 1

(Realizability). Let \(\varphi (X,Y)\) be a CNF formula with X and Y as input and output variables. We say that \(\varphi \) is fully realizable if \(R = 2^X\). We say that \(\varphi \) is partially realizable if \(R \ne \varnothing \). Finally, we say that \(\varphi \) is nullary realizable if \(R = \varnothing \).

Given the condition that the formula is at least partially realizable, the boolean synthesis problem asks for a set of witnesses for the output variables generated on top of given input values, such that the formula is satisfied. This sub-problem of constructing witnesses, is usually referred to as synthesis.

The motivation behind synthesizing partially-realizable specifications is that there are cases where a specification is not fully realizable, but it is still useful to synthesize a function that works for all inputs in the realizability set. An example is the factorization benchmark family, as discussed in the introduction of [3], which takes an integer and aims to factor it into two integers that are both not equal to 1. If the integer is prime, then there is no valid factorization for this particular input, but it would still be valuable to have a solution that works for all composite numbers. This is why our attention to partially-realizable cases is a contribution of the paper, while related works tend to focus mostly on fully-realizable instances.

Definition 2

(Witnesses in Boolean Synthesis Problem). Let \(\varphi (X,Y)\) denote a fully or partially realizable boolean formula with input variables in \(X=\{x_1,\ldots ,x_m\}\) and output variables \(Y =\{y_1,\ldots ,y_n\}\), and let \(R_{\varphi }(X) \ne \varnothing \) be its realizability set. A sequence \(g_1(X), \ldots , g_n(X)\) of boolean functions is a sequence of witness functions for the Y variables in \(\varphi (X,Y)\) if for every assignment \({x} \in R_{\varphi }(X)\), we have that \(\varphi [X \mapsto {x}][y_1 \mapsto g_1({x})]\ldots [y_n \mapsto g_n({x})]\) holds.

Definition 3

(Synthesis). Given a partially or fully realizable CNF formula \(\varphi (X,Y)\) with input and output variables X and Y, the synthesis problem asks to algorithmically construct a set of witness functions for the Y variables in terms of the X variables.

2.2 Dynamic Programming Concepts - Project-Join Trees

A binary decision diagrams (BDD) [7] is directed acyclic graphs with two terminals labeled by 0 and 1. A BDD provides a canonical representation of boolean functions (and, by extension, boolean formulas). A (reduced, ordered) BDD is constructed from a binary decision tree, using a uniform variable order, of a boolean function by merging identical sub-trees and suppressing redundant nodes (nodes where both children are the same). Each path from the root of the BDD to the 1-terminal represents a satisfying assignment of the boolean function it represents. Based on the combination of BDDs and project-join trees, which is to be defined below, our dynamic-programming algorithm solves the boolean synthesis problem.

Definition 4

(Project-Join Tree of a CNF formula). A project-join tree [12] for a CNF formula \(\varphi (X)\) is defined as a tuple \(\mathcal {T}= (T, r, \gamma , \pi )\), where

  1. 1.

    T is a tree with a set \(\mathcal {V}(T)\) of vertices, a set \(\mathcal {L}(T) \subseteq \mathcal {V}(T)\) of leaves, and a root \(r \in \mathcal {V}(T)\)

  2. 2.

    \(\gamma : \mathcal {L}(T) \rightarrow \varphi \) is a bijection that maps the leaves of T to the clauses of \(\varphi \)

  3. 3.

    \(\pi : \mathcal {V}(T) \setminus \mathcal {L}(T) \rightarrow 2^X\) is a function which labels internal nodes with variable sets, where the labels \(\{\pi (n) \mid n \in \mathcal {V}(T) \setminus \mathcal {L}(T)\}\) form a partition of X, and

  4. 4.

    If a clause \(c \in \varphi \) contains a variable x that belongs to the label \(\pi (n)\) of an internal node \(n \in \mathcal {V}(T) \setminus \mathcal {L}(T)\), then the associated leaf node \(\gamma ^{-1}(c)\) must descends from n.

A Graded Project-Join Tree [13] is a generalization of project-join trees.

Definition 5

(Graded Project-Join Tree of a CNF formula [13]). A project-join tree \(\mathcal {T}= (T, r, \gamma , \pi )\) of a CNF formula \(\varphi (X,Y)\) over variables \(X\cup Y\), where \(X\cap Y=\varnothing \), is (X, Y)-graded if there exist grades \(\mathcal {I}_X, \mathcal {I}_Y \subseteq \mathcal {V}(T)\) that partition the internal nodes \(\mathcal {V}(T) \setminus \mathcal {L}(T)\), such that:

  1. 1.

    For a node, its grade is always consistent with its labels. i.e., If \(n_X \in \mathcal {I}_X\) then \(\pi (n_X) \subseteq X\), and if \(n_Y \in \mathcal {I}_Y\) then \(\pi (n_Y) \subseteq Y\).

  2. 2.

    If \(n_X \in \mathcal {I}_X\) and \(n_Y \in \mathcal {I}_Y\), then \(n_X\) is not a descendant of \(n_Y\) in T.

Intuitively, in a graded project-join tree, the nodes are partitioned according to a partition (XY) of the variables, with nodes in the X block always appearing higher than nodes in the Y block. As we shall see, this is useful for formulas with two different types of quantifiers.

Figure 1 shows an example Graded Project-Join Tree for a CNF formula, along with intermediate trees produced in the course of the execution of our synthesis algorithm. In the upcoming sections we will refer back to this example to illustrate the individual steps of the algorithm related to each intermediate tree.

Fig. 1.
figure 1

Original and intermediate trees generated by our algorithms for the CNF example \((x_1 \vee y_4 \vee \lnot y_5) \wedge (\lnot x_3 \vee x_2 \vee \lnot y_5) \wedge (\lnot x_1 \vee x_2 \vee y_6) \wedge (\lnot x_3 \vee x_1 \vee \lnot y_4) \wedge (x_1 \vee \lnot x_2 \vee x_3 \vee y_5)\). The label for each internal node is denoted by e.

3 Realizability Checking

Proofs for All Lemmas and Theorems Can Be Found in the Appendix A.

Our overall approach has three phases: (1) planning – constructing graded project-join trees, (2) realizability checking, and (3) witness-function synthesis. The focus in this section is on realizability checking. We construct the realizability set \(R_\varphi (X)\) for an input formula \(\varphi (X,Y)\), and then use it to check for full and partial realizability, as described in Definition 1.

For the planning phase, we use the planner described in [13], which is based on tree decomposition [25]. Computing minimal tree decomposition is known to be an NP-hard problem [6], so planning may incur high computational overhead. Nevertheless, tree-decomposition tools are getting better and better. The planner uses an anytime tree-decomposition tool, cf. [16], which outputs tree decompositions of progressively lower width. Deciding when to quit planning and start executing is done heuristically. In contrast, Factored RSynth applies a fixed set of fast heuristics, which incurs relatively small overhead. We discuss the planning overhead further below.

3.1 Theoretical Basis and Valuations in Trees

The realizability set \(R_\varphi (X)\) can be interpreted as a constraint over the X variables stating the condition that there exists an assignment to the Y variables that satisfies \(\varphi \). In other words, \(R_\varphi (X) \equiv (\exists y_1)\ldots (\exists y_n)\varphi \), for \(Y = \{y_1, \ldots , y_n\}\).

Therefore, we can construct R from \(\varphi =\bigwedge _j \varphi _j\) by existentially quantifying all Y variables. As observed in [28], however, a clause that does not contain \(y_i\) can be moved outside the existential quantifier \((\exists y_i)\). In other words, \((\exists y_i)\bigwedge _j \varphi _j \equiv \bigwedge _{y_i \not \in AP(\varphi _j)}\varphi _j \wedge (\exists y_i)\bigwedge _{y_i \in AP(\varphi _j)}\varphi _j\), where AP stands for atomic propositions in a formula. This allows us to perform early quantification to compute R more efficiently, since applying quantification on the smaller formula \(\bigwedge _{y_i \in AP(\varphi _j)}(\varphi _j)\) is likely less expensive computationally than doing so on the full formula \(\varphi = \bigwedge _j(\varphi _j)\).

Inspired by a similar observation in [13], we use the insight that a graded project-join tree can be employed to guide early quantification. Consider the following definition, which allows us to interpret a node n in a project-join tree as a boolean formula:

Definition 6

(BDD-Valuations of Nodes in Project Join Tree). Let n be a node in a graded project-join tree \(\mathcal {T}= (T, r, \gamma , \pi )\) with a partition of internal nodes into two grades \(\mathcal {I}_X\) and \(\mathcal {I}_Y\), as defined in Sect. 2. Let the set of children nodes of n be denoted by C(n). Let \(\llbracket \alpha \rrbracket \) denote the BDD encoding a boolean expression \(\alpha \), and \(\exists _Z f\) denote the existential projection on f with respect to variables in Z. We now define a pair of mutually related valuation concepts for nodes in a project-join tree, interpreting their BDD representations.

The post-valuation of n is defined as

$$\texttt {BV}_{\texttt {post}}(\mathcal {T}, n)= \left\{ \begin{array}{ll} \llbracket \gamma (n) \rrbracket , &{}\text {if }n\text { is a leaf node}\\ \exists _{\pi (n)} \texttt {BV}_{\texttt {pre}}(\mathcal {T}, n), &{}\text {if }n\text { is an internal node.} \end{array}\right. $$

The pre-valuation of n is defined as

$$\texttt {BV}_{\texttt {pre}}(\mathcal {T}, n)= \left\{ \begin{array}{ll} \llbracket \gamma (n) \rrbracket , &{}\text {if }n\text { is a leaf node}\\ \mathop {\bigwedge }\nolimits _{n' \in C(n)} \texttt {BV}_{\texttt {post}}(\mathcal {T}, n'), &{}\text {if }n\text { is an internal node.} \end{array}\right. $$

Intuitively, we evaluate an internal node n by first taking the conjunction of post-valuations of its children and then existentially quantifying the variables \(\pi (n)\) in its label. The former step generates a pre-valuation, while the latter produces a post-valuation. We can safely perform quantification of the variables in the label of n after conjoining, because every internal node n must satisfy the property that all clauses containing variables in \(\pi (n)\) are descendants of n, by the definition of a project-join tree.

Furthermore, recall that, by the definition of a (XY)-graded project-join tree, all nodes in \(\mathcal {I}_Y\) occur below all nodes in \(\mathcal {I}_X\). This allows us to turn Definition 6 into a procedure for efficiently computing realizability of the CNF formula \(\varphi \) using a graded project-join tree as a guide:

  1. 1.

    First, apply Definition 6 to the \(\mathcal {I}_Y\) nodes of the tree, producing a project-join tree for \(R_\varphi (X) \equiv (\exists y_1) \ldots (\exists y_n) \varphi \).

  2. 2.

    Inspect this tree for full realizability (see below).

  3. 3.

    Apply Definition 6 again in order to check partial realizability (see below).

For the CNF with the graded project-join tree in Fig. 1a, the pre- and post-valuations for nodes 1, 4, 5, 2, 3 are equivalent to the BDDs representing their original clauses. \(\texttt {BV}_{\texttt {pre}}(\mathcal {T}, 6)=\llbracket (x_1 \vee y_4 \vee \lnot y_5) \wedge (\lnot x_3 \vee x_1 \vee \lnot y_4) \rrbracket , \texttt {BV}_{\texttt {post}}(\mathcal {T}, 6)=(\exists y_4)\texttt {BV}_{\texttt {pre}}(\mathcal {T}, 6) = (x_1 \vee \lnot y_5 \vee \lnot x_3), \texttt {BV}_{\texttt {pre}}(\mathcal {T}, 7)=(x_1 \vee \lnot x_2 \vee x_3 \vee y_5) \wedge (\lnot x_3 \vee x_2 \vee \lnot y_5) \wedge (x_1 \vee \lnot y_5 \vee \lnot x_3), \texttt {BV}_{\texttt {post}}(\mathcal {T}, 7)=(\exists y_5)\texttt {BV}_{\texttt {pre}}(\mathcal {T}, 7) = \llbracket 1 \rrbracket , \texttt {BV}_{\texttt {pre}}(\mathcal {T}, 9)= (\lnot x_1 \vee x_2 \vee y_6), and \texttt {BV}_{\texttt {post}}(\mathcal {T}, 9)=(\exists y_6)\texttt {BV}_{\texttt {pre}}(\mathcal {T}, 9) = \llbracket 1 \rrbracket \).

Notations. We denote the set of children nodes and the set of descendants of n by C(n) and D(n). Let \(\llbracket \cdot \rrbracket \) denote the BDD encoding of the enclosed expression, and use \(\texttt {projn}(B, Z)\) to denote a series of existential projections on BDD B with respect to variables in set Z.

figure a

Algorithm 1 presents a procedure to compute the pre and post-valuations of Definition 6. In this algorithm pre-valuations are intermediate BDDs used to compute the post-valuations, but their values are also used in Sect. 4 for witness-function synthesis. Post-valuations, meanwhile, are used in Sect. 3.2 to determine if a given instance has a fully, partially, or unrealizable domain.

Note that children nodes are always visited before parent nodes, per Algorithm 2. This guarantees that line 6 in GenericValuation is always viable. We now assert the correctness of the Algorithm 1 by the following theorem.

Theorem 1

If a graded project-join tree \(\mathcal {T}\) and a particular node n are given, then (i) \(\texttt {BV}_{\texttt {post}}(\mathcal {T}, n)\) and (ii) \(\texttt {BV}_{\texttt {pre}}(\mathcal {T}, n)\) returned by Algorithm 1 are as defined in Definition 6.

Theorem 2

Given a graded project-join tree \(\mathcal {T}\) of a CNF formula \(\varphi \), let \({{X_\texttt {leaves}}(\mathcal {T})}\) denote the set of highest level nodes \(n \in \mathcal {T}\) such that \(\pi (n) \subseteq Y_\varphi \). Then the realizability set \(R_\varphi (X)\) can be represented by the conjunction \(\bigwedge _{n \in {X_\texttt {leaves}}(\mathcal {T})} \texttt {BV}_{\texttt {pre}}(\mathcal {T}, n)\) of BDDs returned by Algorithm 1.

The pair of post and pre valuations defined in this section offer support for both realizability checking and synthesis, respectively. Section 3.2 applies \(\texttt {BV}_\texttt {post}\) for realizability checking, and we show in Sect. 4 how \(\texttt {BV}_\texttt {pre}\) is used in witnesses construction.

3.2 Determining Nullary, Partial and Full Realizability

Using the post-valuations of nodes computed in Algorithm 1 as the result of projecting variables on the conjunction of children nodes, we can construct the realizability set and determine if it is full, partial or empty. In practice, we represent the realizability set as a conjunction of BDDs, where an input is in the set if it satisfies all BDDs in the conjunction.

Notation Let \(\texttt {XLeaves}(\mathcal {T})\) denote the set of Y internal nodes whose parents are not in \(\mathcal {I}_Y\). This set is easily obtainable by means such as graph-search algorithms.

We start by applying the pair of valuations computed in Algorithm 1 to the first layer of \(\mathcal {I}_Y\) nodes in the graded tree; that is, all internal nodes in \(\mathcal {I}_Y\) whose parent is not in \(\mathcal {I}_Y\). By replacing these nodes with leaves labeled by their post-valuation, we obtain a project-join tree \(\mathcal {T}_X\) for the formula \((\exists y_1)\ldots (\exists y_n) \varphi \), which, as explained in Sect. 3.1, corresponds to the realizability set. This procedure is implemented in Algorithm 2.

In the case of the example formula in Fig. 1, once we obtain the pre- and post-valuations from Algorithm 1, \(B_{pureX}=\llbracket 1 \rrbracket \) and \(b=1\) from the post-valuations \(\texttt {BV}_{\texttt {post}}(\mathcal {T}, 7)\) (Fig. 1c) and \(\texttt {BV}_{\texttt {post}}(\mathcal {T}, 9)\) (Fig. 1d) on \(\texttt {XLeaves}\). Hence we get full realizability.

Note that the formula \(\varphi \) is fully realizable if and only if the conjunction of the leaves in \(\mathcal {T}_X\) is 1, which holds true if and only if all leaves are 1. Therefore, at the end of Algorithm 2 we are also able to answer whether \(\varphi \) is fully realizable. Note also that if any of the leaves is 0, then their conjunction is 0, meaning that \(\varphi \) is nullary realizable. Therefore, in some cases it might be possible to detect nullary realizability in this step. If the formula is not fully realizable and nullary realizability is not detected, then \(\mathcal {T}_X\) is passed to the next step to test partial realizability.

figure b

Theorem 3

Given a graded project-join tree \(\mathcal {T}\) for a CNF formula \(\varphi \), Algorithm 2 returns full realizability if and only if the formula \((\forall X)(\exists Y)\varphi (X,Y)\) is true. And the algorithm returns nullary realizability, if and only if the formula \((\exists X)(\exists Y)\varphi (X,Y)\) is false.

When the formula is not fully realizable, we proceed to pass the tree returned by Algorithm 2 to Algorithm 3, which then distinguishes partial realizability from nullary realizability. It does this by simply using Algorithm 1 to compute the post-valuation of the root of \(\mathcal {T}_X\).

In the case of the example in Fig. 1, for this formula, we do not need to check Algorithm 3 because by Algorithm 2 full realizability is returned.

figure c

Since this corresponds to taking the conjunction of the leaves (which are themselves the post-valuation of the first layer of Y nodes) and existentially quantifying the X variables, the result is 1 if \(\varphi \) is partially realizable, and 0 if not. Built on top of Theorem 2, we formulate the correctness of the algorithm:

Theorem 4

Given a CNF formula \(\varphi \) and its graded project-join tree \(\mathcal {T}\), if we generate \(\mathcal {T}_X\) by Algorithm 2, then Algorithm 3 returns the correct status of realizability of \(\varphi \).

4 Synthesis of Witness Functions

We now move to the third phase of our boolean-synthesis approach, where we construct boolean expressions for the output variables, which are the witness functions. More precisely, when the realizability set \(R_\varphi (X)\), as defined in Sect. 3, is nonempty, we proceed to witness construction. We now formally define the concept of witnesses, in the context where the boolean synthesis problem is given as a CNF specification and reduced ordered BDDs are used for boolean-function representations.

The following lemma describes the self-substitution method for witness construction.

Lemma 1

[15] Let X be a set of input variables and y a single output variable in a Boolean CNF formula \(\varphi (X, y)\) with \(R_\varphi (X) \ne \varnothing \). Then \(g(X) = \varphi (X, y)[y \mapsto 1]\) is a witness for y in \(\varphi (X, y)\).

We now show how to extend this method to multiple output variables, building towards an approach using graded project-join trees.

4.1 Monolithic Approach

The synthesis procedure here builds on the condition that partial realizability is known, provided by the algorithms in Section. 3. While solvers constructed by related works, as discussed in Sect. 1, apply only to fully realizable formulas, we show here that synthesis can also be performed to obtain witness functions in the case of partial realizability.

As a stepping stone towards graded-tree-based synthesis, we first explain how witness functions are constructed in the monolithic case. We review the basic framework in [15], where the realizability set \(R_{\varphi }(X)\) is obtained through iterative quantification on \(y_n\) to \(y_1\), while witnesses are obtained via iterative substitution on \(y_1\) to \(y_n\).

Denote the BDD encoding the original CNF formula \(\varphi (X,Y)\) to be \(B_\varphi (X,Y)\). Then, a series of intermediate BDDs can be defined on the way of obtaining the realizability sets \(R_\varphi (X)\):

$$\begin{aligned} &B_n(X, y_1, \ldots , y_n) \equiv B_\varphi , \\ &\ldots \\ &B_{i}(X, y_1, \ldots , y_i) \equiv (\exists y_{i+1}) B_{i+1},\\ &\ldots \\ &B_{0}(X) \equiv (\exists y_{1}) B_{1} \end{aligned}$$

Finally, the realizability set \(R_\varphi (X)\) is \(B_0(X)\).

Note that existential quantification proceeds here inside-out, since larger-indexed output variables are quantified before smaller-indexed output variables. Witness construction, on the other hand, proceeds outside-in: witnesses are constructed in the reverse direction starting from the smallest-indexed output variable \(y_1\). The witnesses for variables \(y_1, \ldots , y_{i-1}\) are substituted into \(B_{i}\), from which we then construct the next witness \(g_i\). Using the witness given by Lemma 1, we have:

\(g_1\) is computed from: \(B'_1(X,y_1)=B_1(X,y_1),\) via \(g_{1}=B'_1[y_1 \mapsto 1];\)

\(\ldots \)

\(g_{i}\) is computed from: \(B'_i(X,y_i)=B_i(X,y_1,\ldots ,y_i)[y_{1} \mapsto g_{1}]\) \(\ldots [y_{i-1}\mapsto g_{i-1}],\) via \(g_{i}=B'_i(X,y_i)[y_i \mapsto 1].\)

The following lemma is based on [15].

Lemma 2

If \(R_0(X)\not =\varnothing \), then the \(g_i\)’s above are witness functions for Y in \(\varphi (X,Y)\).

As the witnesses above are computed using the self-substitution method from Lemma 1, each formula can have potentially many different witnesses. The correctness of the procedure does not depend on which witness is used. RSynth [15] applies the SolveEqn function of the CUDD package to compute a block of witnesses at once by essentially the procedure above. The procedure produces several witnesses for each variable, from which we chose one witnesses (by setting a parameter to 1).

The above monolithic synthesis framework was generalized in [28] to the case where the formula \(\varphi \) is given as a conjunction of factors. A factor can be a formula, for example, a single clause or a conjunction of clauses (called a “cluster” in that work). In that case, the principle of early quantification mentioned in Sect. 3.1 can be applied. See Appendix B for details. As shown in [28], the tool, Factored RSynth, generally outperforms RSynth.

In the following section, we describe a factored approached to witness construction using graded project-join trees.

4.2 Synthesis Using Graded Project-Join Trees

As we saw above, in the monolithic setting we compute the realizability set by quantifying the Y variables inside out, and then computing the witness function for these variables outside in. In the graded project-tree framework, we saw that the realizability set is computing by quantifying the Y variables bottom-up.

Our framework works for both partial and fully realizable cases. We first compute realizability sets going bottom up the graded project-join tree for \(\varphi \) as in Sect. 3. We now show that the witness functions for the Y variables can then be constructed by iterated substitution top-down. In other words, we first compute the witnesses for the variables in the labels of internal nodes at higher levels, and then propagate those down toward the leaves. We compute witnesses from the pre-valuation \(\texttt {BV}_{\texttt {pre}}\) of a node in the tree, computed as in Algorithm 1. Note that, in contrast to the bottom-up realizability and top-down synthesis described here, in projected model counting, where graded project-join trees were introduced [13], the trees are processed fully in a bottom-up fashion.

The following lemma is crucial to our approach.

Lemma 3

Let m and n be two different internal nodes of a graded project-join tree \(\mathcal {T}\) such that n is not a descendant of m. Then no variable in \(\pi (m)\) appears in \(\texttt {BV}_{\texttt {pre}}(\mathcal {T}, n)\).

We can derive from Lemma 3 the essential relation among witness functions for different variables: since the witness for a variable \(y_i \in \pi (n)\) is computed from \(\texttt {BV}_{\texttt {pre}}(\mathcal {T}, n)\), this witness can only depend on the witnesses of output variables \(y_j \in \pi (m)\) such that n is a descendant of m.

Based on these insights, we present in Algorithm 4 our dynamic-programming synthesis algorithm for producing the witnesses \(g_y(X)\) for each output variable y, represented by a BDD \(W_y(X)\). The algorithm starts at the top-most layer of Y nodes, those whose parents are X nodes, represented by the set called XLeaves (line 1). For each node n in this set (line 3), we compute the set of witnesses \(\{W_y \mid y \in \pi (n)\}\) from \(\texttt {BV}_{\texttt {pre}}(\mathcal {T}, n)\) (line 9) using the monolithic procedure from Sect. 4.1 (represented by the CUDD function \(\texttt {SolveEqn}(\pi (n), \texttt {BV}_{\texttt {pre}}(\mathcal {T}, n))\), mentioned in that section). Note that, since the tree is graded, these nodes do not descend from any Y nodes. Therefore, by Lemma 3, these witnesses depend only on the X variables.

As we compute the witnesses for a node, we add all of its (non-leaf) children to the set of nodes to visit (line 6), representing the next layer of the tree. After all nodes in the current set have been processed, we repeat the process with the new layer (line 3).

figure d

This continues until the set of children is empty (line 2). Note that, since for each node n we apply the monolithic synthesis procedure only to the variables in \(\pi (n)\), the witnesses can be dependent on the Y variables of its ancestors. Therefore, we finish the algorithm by iterating over the new synthesized witnesses \(W_y\) and substituting each into the pre-valuation of descendant nodes that are computed later (lines 10-14). Note that this overapproximates the set of dependencies on \(y \in \pi (n)\) of the witnesses for \(y' \in \pi (n'')\) for \(n'' \in D(n)\), but since \(W_{y'}[y \mapsto W_y] \equiv W_{y'}\) when y does not appear in \(W_{y'}\), the result is still correct. At the end of this procedure, all \(W_y\) will be dependent only in the input variables X.

Continuing with the running example for the problem in Fig. 1, once full realizability is detected, we apply Algorithm 4 and construct the witnesses in top-down manner. First, we get the witness \(g_6=1\) for \(y_6\) by \(\texttt {BV}_{\texttt {pre}}(\mathcal {T}, 9)= \llbracket (\lnot x_1 \vee x_2 \vee y_6)\rrbracket \). Then we construct the witness \(g_5=(x_1 \wedge x_2) \vee \lnot x_3\) for \(y_5\) by substituting \(y_5=1\) in \(\texttt {BV}_{\texttt {pre}}(\mathcal {T}, 7)=\llbracket (x_1 \vee \lnot x_2 \vee x_3 \vee y_5) \wedge (\lnot x_3 \vee x_2 \vee \lnot y_5) \wedge (x_1 \vee \lnot y_5 \vee \lnot x_3)\rrbracket \). After that, we go to node 6 and get \(g_4 = x_1 \vee \lnot x_3\) from \(\texttt {BV}_{\texttt {pre}}(\mathcal {T}, 6)=\llbracket (x_1 \vee y_4 \vee \lnot y_5) \wedge (\lnot x_3 \vee x_1 \vee \lnot y_4) \rrbracket \). By the algorithm, we would need to substitute \(g_5\) into \(\texttt {BV}_{\texttt {pre}}(\mathcal {T}, 6)\) before computing \(g_4\), but since for this specific CNF \(g_4\) is not actually dependent on \(g_5\), this does not change the witness. The witnesses are correct by \(\varphi [y_4 \mapsto g_4][y_5 \mapsto g_5][y_6 \mapsto g_6]=1\).

The following theorem proves the correctness of witnesses constructed. First, it is easy to see by an inductive argument that a witness is synthesized for all output variables: all Y nodes that do not descend from other Y nodes are included in the set processed in the first iteration, and if a node is processed in one iteration, all of its children are included in the set for the next iteration. Since the tree is graded, we have processed all of the Y nodes, and since every output variable y is in the label of some node, a witness \(W_y\) is computed for every y. Then, the following theorem states the correctness of the witnesses constructed:

Theorem 5

Algorithm 4 returns a set of BDDs encoding the witness functions for output variables that satisfy the given CNF \(\varphi \), assuming that \(\texttt {SolveEqn}(\pi (n)\), \(\texttt {BV}_{\texttt {pre}}(\mathcal {T}, n))\) returns correct witnesses for the variables in \(\pi (n)\) in \(\texttt {BV}_{\texttt {pre}}(\mathcal {T}, n)\).

5 Experimental Evaluation

5.1 Realizability-Checking Phase

Methodology: To examine our dynamic-programming graded-project-join-tree-based approach for boolean realizability, we developed a software tool, DPSynth, which implements the theoretical framework described above. We choose to compare DPSynth to Factored RSynth, which as explained in the introduction is the closest existing tool, also being based on decision diagrams and outputting the realizability set along with the witnesses. Prior work [28] already demonstrated that RSynth practically never outperforms Factored RSynth, while Factored RSynth typically outperforms RSynth, so we compare in this paper to Factored RSynth. (See Sect. 5.4 for an additional comparison to a non-decision-diagram tool.) We measured the time and space performance for determining realizability on a set of mature benchmarks, described below. The experiments aim at answering the following research questions:

  • Does our DP-based solution improve execution time for realizability checking? Does the overhead of planning time investment in DPSynth get paid off?

  • How does the relative weight of planning overhead vary between small and large input instances?

  • How does DPSynth improve the scalability of realizability checking?

(Tree width is one of the critical parameters impacting the performance of the graded project-jointree-based approach in running time. We discuss this issue further in separate a subsection.)

We selected 318 benchmarks that are neither too easy (taking less than 1ms) not too hard (such that the whole benchmark family is not solvable by either solver) from the data set of forall-exists \(\varPi ^P_2\) CNFs from the QBFEVAL [23] datasets from 2016 to 2019, without any more selection criteria, as the editions of QBFEVAL in 2020 and 2022 do not include additional 2QBF instances or tracks other than those included by 2019. Families of benchmarks that our experiments run on include reduction-finding query, mutexP, qshifter, ranking functions, sorting networks, tree and fix-point detection families, and also two additional scalable families, consisting of parametric integer factorization and subtraction benchmarks from [2, 3].

Among the full benchmark suite, at least \(33\%\) of the 285 instances where realizability can be checked by either DPSynth or factored RSynth are partially realizable. In the benchmarks for which both tools are able to synthesize a complete group of witnesses, \(28\%\) are partially realizabile. (No benchmark in the suite is identified as nullary realizable). We conclude that partial realizability is a significant issue in Boolean synthesis. We now present the experimental results analyzed according to the research questions above.

For each benchmark instance, we run the FlowCutter-based planner until we obtain the first tree decomposition, and we declare timeout if no tree decomposition is generated within ten minutes, in which case, the instance is marked unsolved. Otherwise, we take the first tree generated, and proceed to the execution phase of DPSynth, which includes BDD compilation, realizability checking, and synthesis of witnesses. The maximal time limit for each instance is set to be two hours for the execution phase. We measure planning time, execution time, and end-to-end time.

Our implementation is based on the CUDD Library [27] with BDD operations, and the FlowCutter tree-decomposition tool [20]. In our implementation, BDD variables are in MCS order [28]. This ordering is based on the primal graph of the input clause set, and was also used by Factored RSynth.

We ran the experiments on Rice University NOTS cluster, which assigns the jobs simultaneously to a mix of HPE SL230s, HPE XL170r, and Dell PowerEdge C6420 nodes, each of which has 16–40 cores with 32–192 GB RAM that runs at 2.1–2.60 GHz. Each solver-benchmark combination ran on a single core.

Experimental Results: Our goal in this paper was to compare the performance of the fast, CSP-based, formula-partitioning techniques of Factored RSynth [28], to the heavier-duty formula-partitioning techniques based on tree decomposition described above. For a fair comparison, the charts do not include data points for those instances that timed out for one of the solvers. (In total, DPSynth was able to solve 126 instances end-to-end, and RSynth 111.) Thus, our experiments compare DPSynth to Factored RSynth. Our conjecture is that such heavier-duty techniques pay off for larger formulas, but not necessarily for smaller formulas.

Fig. 2.
figure 2

(a) Time Comparison. (b) Scalable Families Time Growth

Figure 2a shows overall running-time comparison between DPSynth and Factored RSynth for realizability checking. A clear pattern that emerges is there is a difference in relative performance between very small problems (solvable within 1 millisecond) and larger problems. DPSynth underperforms Factored RSynth on small instances, but outperforms on larger instances and the difference increases exponentially as input size grows. We conclude that planning overhead dominates on small input instances, but that effect fades off as instances get larger and the planning pays off. In memory usage comparisonFootnote 1 – using peak node count as a measurement – DPSynth uses less memory than Factored RSynth. Here the graded project-join-tree approach is advantageous, and planning incurs no overhead.

To evaluate scalability, we take the scalable benchmark families mentioned previously, and compare the logarithmic-scale slope in their running time as sizes of benchmarks increase. As indicated in Figure. 2b, DPSynth scales exponentially better than Factored RSynth, as the planning overhead fades in significance as instances grow. We see a steeper slope on the exponential scale in DPSynth trends over factored RSynth. Some data points for larger benchmarks in the families (horizontal coordinates 3, 4, 5 on chart) are missing because factored RSynth is not able to finish solving these instances in realizability-checking phase within the time limit.

5.2 Synthesis

The experiments on synthesis of witnesses answer the following research questions:

  • How does DPSynth compare in execution time to factored RSynth?

  • Does the influence of planning investment reduces as problem gets large?

  • What do we see in growth of tree widths and synthesis execution time?

Using the same set of benchmarks and setting under the methodology as in Sect. 5.1, we applied our synthesis procedure to both fully realizable and partially realizable benchmarks. This broadens the scope of Boolean synthesis beyond that of fully realizable benchmarks, which is the scope of earlier work, as discussed above. Regarding end-to-end synthesis (planning, realizability checking, and synthesis, combined) DPSynth outperforms Factored RSynth in running time as illustrated in Fig. 3a. As with realizability checking, planning overhead dominates for small instances, as discussed in Sect. 3, but DPSynth solves large benchmarks faster and shows significant advantage as problem size increases, once the planning overhead fades in significance. In memory usage there is consistent relative performance of DPSynth vs. Factored RSynth.

We again selected three scalable benchmark families, scaled based on a numerical parameter. As shown in Fig. 3b, DPSynth scales exponentially as benchmark size increases. Similarly to the case in realizability checking, the missing data points on larger benchmarks in the scalable families presented by the dashed lines are caused by the timeouts by factored RSynth.

While DPSynth shows performance advantage over Factored RSynth with respect to our benchmark suite, one cannot conclude that DPSynth always dominates Factored RSynth. This is because DPSynth involves computationally nontrivial planning phase, and it is not possible to say definitively that the planning overhead always pays off.

Fig. 3.
figure 3

(a) Synthesis Time: DPSynth vs. Factored RSynth. (b) Scalable Families Comparison

We can conclude, however, that DPSynth is an important addition to the portfolio of algorithms for boolean synthesis.

5.3 Tree Widths and Realizability

Graded project-join trees enable the computation of the realizability set in a way that minimizes the set of support of intermediate ADDs (Algebraic Decision Diagrams), saving time and memory. But computing these trees is a heavy computational task. In this section, we study the impact of tree width on realizability checking.

Fig. 4.
figure 4

(a) DPSynth Realizability Time as Widths Increases. (b) DPSynth/Factored RSynth Realizability Time Ratio as Widths Increases

Fig. 4a presents the range of realizability time run by DPSynth along increasing tree widths. As we see, increases in tree widths implies an increase in running time for realizability-checking. Figure 4b, depicts the ratio of realizability time, computed by that of DPSynth over Factored RSynth, with respect to tree width, for problem instances that can be solved by both solvers. As treewidth increases, the over-performance of DPSynth over Factored RSynth increases, as planning overhead decreases in significance for higher-treewidth instances.

Synthesis execution time has similar relation with tree widths.

5.4 Comparison with Non-BDD-Based Synthesis

To complement out evaluation, we include additional experiments to verify whether DPSynth is competitive with non-BDD-based synthesis solvers, as motivated in Sect. 1. We compare with Manthan [17], a leading tool that is not based on decision diagrams, and find that DPSynth performs favorably.

We present a general picture by the following table, which shows the overall strength of the dynamic-programming decision-diagram approach, by measuring the time and space usage of experiments on the dataset selected from QBFEVAL’16 to QBFEVAL’19. DPSynth and Manthan each is able to solve some benchmarks that the other does not solve.

In order to compare the running time, we compare against Manthan using the DPSynth end-to-end synthesis time, which is the sum of tree-decomposition time, compilation, realizability-checking time, and synthesis time.

As the overall picture of synthesis solving, DPSynth shows a better time performance on most instances. DPSynth and Manthan each has strength on some instances, but the number of benchmarks that only DPSynth solves is larger than those solved only by Manthan. On those that are solved by both, DPSynth takes less time in most of them. See Appendix D for more illustrative data on specific fully and partially-realizable benchmarks.

 

Number of benchmarks

solved by Manthan

79

solved by DPSynth

102

solved by both Manthan and DPSynth

70

solved by Manthan but not by DPSynth

9

solved by DPSynth but not by Manthan

32

6 Concluding Remarks

To summarize the contribution in this work, we propose a novel symbolic dynamic programming approach for realizability checking and witness construction in boolean synthesis, based on graded project-join trees. The algorithm we propose here combine a bottom-up realizability-checking phase with a top-down synthesis phase. We demonstrated experimentally that our approach, implemented in the DPSynth tool, is powerful and more scalable than the approach based on CSP heuristics (Factored RSynth). Another crucial contribution of this work is the inclusion of partial realizability checking, which applies to 30% of the total number of benchmarks. As we explain in introduction, this consideration is motivated by the need in modular circuit design and temporal synthesis to locate the scope of realizable inputs in iterative constructions.

There are many directions for future work. Variable ordering is a critical issue in decision-diagram algorithms, and should be explored further in the context of our approach. In particular, dynamic variable ordering should be investigated [26]. Also, in our work here we used high-level API of the BDD package CUDD, but it is possible that performance gains can be obtained by using also low-level BDD-manipulating APIs. The question of how to provide certificates of unrealizability also needs to be explored, c.f., [8, 9].

As mentioned earlier, quantifier elimination is a fundamental algorithmic component in temporal synthesis [31]. Tabajara and Vardi explored a factored approach for temporal synthesis [29]. It would be worthwhile to explore also the graded project-tree approach for boolean synthesis in the context of factored temporal synthesis. Finally, quantifier elimination is also a fundamental operation in symbolic model checking [11] and partitioning techniques have been explored in that context [10]. Therefore, exploring the applicability of our dynamic-programming approach in that setting is also a promising research direction.