1 Introduction

There has been a lot of recent progress in the automatic synthesis of reactive systems from specifications in temporal logic [4, 6, 7, 9, 12]. From a theoretical point of view, the appeal of synthesis is obvious: the synthesized implementation is guaranteed to satisfy the specification. No separate verification is needed.

From a practical point of view, the value proposition is not so clear. Instead of writing programs, the user of a synthesis procedure now writes specifications. But many people find it much easier to understand the precise meaning of a program than to understand the precise meaning of a temporal formula. Is it really justified to place higher trust into a program that was synthesized automatically, albeit from a possibly ill-understood specification, than in a manually written, but well-understood program? A straightforward solution would be for the programmer to inspect the synthesized program and confirm that the implementation is indeed as intended. However, current synthesis tools fail miserably at producing readable code.

Most research on the synthesis problem has focused on the problem of finding some implementation, not necessarily a high-quality implementation. Since specification languages like LTL restrict the behavior of a system, but not its structure, it is no surprise that the synthesized implementations are often much larger and much more complex than a manual implementation. There has been some progress on improving other quality measures, such as the runtime performance [4], but very little has been done to optimize the structural quality of the synthesized implementations (cf. [14]). Can we develop synthesis algorithms that produce implementations that are small, structurally simple, and therefore easy to understand?

Fig. 1.
figure 1

Three implementations of the TBURST4 component of the AMBA bus controller. Standard synthesis with Acacia+ produces the state graph on the left with 14 states and 61 cycles. Bounded synthesis produces the graph in the middle with 7 states and 19 cycles. The graph on the right, produced by our tool, has 7 states and 7 cycles, which is the minimum.

A first step into this direction is Bounded Synthesis [9]. Here, we bound the number of states of the implementation and can therefore, by incrementally increasing the bound, ensure that the synthesized solution has minimal size.

In this paper, we go one step further by synthesizing implementations where, additionally, the number of (simple) cycles in the state graph is limited by a given bound. Reducing the number of cycles makes an implementation much easier to understand. Compare the three implementations of the TBURST4 component of the AMBA bus controller shown in Fig. 1: standard synthesis with Acacia+ produces the state graph on the left with 14 states and 61 cycles. Bounded Synthesis produces the middle one with 7 states and 19 cycles. The graph on the right, produced by our tool, has 7 states and 7 cycles, which is the minimum.

An interesting aspect of the number of cycles as a parameter of the implementations is that the number of cycles that is potentially needed to satisfy an LTL specification explodes in the size of the specification: we show that there is a triple exponential lower and upper bound on the number of cycles that can be enforced by an LTL specification. The impact of the size of the specification on the number of cycles is thus even more dramatic than on the number of states, where the blow-up is double exponential.

Our synthesis algorithm is inspired by Tiernan’s cycle counting algorithm from 1970 [17]. Tiernan’s algorithm is based on exhaustive search. From some arbitrary vertex v, the graph is unfolded into a tree such that no vertices repeat on any branch. The number of vertices in the tree that are connected to v then corresponds to the number of cycles through v in the graph. Subsequently, v is removed from the graph, and the algorithm continues with one of the remaining vertices until the graph becomes empty. We integrate Tiernan’s algorithm into the Bounded Synthesis approach. Bounded Synthesis uses a SAT-solver to simultaneously construct an implementation and a witness for the correctness of the implementation [9]. For the standard synthesis from an LTL specification \(\varphi \), the witness is a finite graph which describes an accepting run of the universal tree automaton corresponding to \(\varphi \). To extend the idea to Bounded Cycle Synthesis, we define a second witness that proves the number of cycles, as computed by Tiernan’s algorithm, to be equal to or less than the given bound. An example state graph with three cycles is shown on the left in Fig. 2. The witness consists of the three graphs shown on the right in Fig. 2. The first graph proves that vertex 1 is on two cycles (via vertex 2 and vertices 2 and 3). The second graph proves that vertex 2 is on a further cycle, not containing vertex 1, namely via vertex 3. There are no further cycles through vertex 3.

Our experiments show that Bounded Cycle Synthesis is comparable in performance to standard Bounded Synthesis. The specifications that can be handled by Bounded Cycle Synthesis are smaller than what can be handled by tools like Acacia+, but the quality of the synthesized implementations is much better. Bounded Cycle Synthesis could be used in a development process where the programmer decomposes the system into modules that are small enough so that the implementation can still be inspected comfortably by the programmer (and synthesized reasonably fast by using the Bounded Cycle Synthesis approach). Instead of manually writing the code for such a module, the programmer has the option of writing a specification, which is then automatically replaced by the best possible implementation.

Fig. 2.
figure 2

Witness for an example state graph with three cycles. The state graph is shown on the left. The first graph on the right proves that vertex 1 is on two cycles (via vertex 2 and vertices 2 and 3). The second graph proves that vertex 2 is on a further cycle not, containing vertex 1, namely via vertex 3. There are no further cycles through vertex 3.

2 Preliminaries

The non-negative integers are denoted by \( \mathbb {N}\). An alphabet \( \varSigma \) is a non-empty finite set. \( \varSigma ^{\omega } \) denotes the set of infinite words over \( \varSigma \). If \( \alpha \in \varSigma ^{\omega }\), then \( \alpha _{n} \) accesses the n-th letter of \( \alpha \), starting at \( \alpha _{0}\). For the rest of the paper we assume \( \varSigma = 2^{\mathcal {I}\cup \mathcal {O}} \) to be partitioned into sets of input signals \( \mathcal {I}\) and output signals \( \mathcal {O}\).

A Mealy machine \( \mathcal {M}\) is a tuple \( (\mathcal {I},\mathcal {O}, T, t_{I}, \delta , \lambda ) \) over input signals \( \mathcal {I}\) and output signals \( \mathcal {O}\), where T is a finite set of states, \( t_{I} \in T \) is the initial state, \( \delta :T \times 2^{\mathcal {I}} \rightarrow T \) is the transition function, and \( \lambda :T \times 2^{\mathcal {I}} \rightarrow 2^{\mathcal {O}} \) is the output function. Thereby, the output only depends on the current state and the last input letter. The size of \( \mathcal {M}\), denoted by \( |\mathcal {M}|\), is defined as \( |T|\). A path p of a Mealy machine M is an infinite sequence \( p = (t_{0},\sigma _{0})(t_{1},\sigma _{1})(t_{2},\sigma _{2}) \ldots \in (T \times \varSigma )^{\omega } \) such that \( t_{0} = t_{I}\), \( \delta (t_{n},\mathcal {I}\cap \sigma _{n}) = t_{n+1} \) and \( \lambda (t_{n},\mathcal {I}\cap \sigma _{n}) = \mathcal {O}\cap \sigma _{n} \) for all \( n \in \mathbb {N}\). We use \( \pi _{1}(p) = \sigma _{0}\sigma _{1}\sigma _{2}\ldots \in \varSigma ^{\omega }\), to denote the projection of p to its second component. \( \mathcal {P}(\mathcal {M}) \) denotes the set of all paths of a Mealy machine \( \mathcal {M}\).

Specifications are given in Linear-time Temporal Logic (LTL). The atomic propositions of the logic consist of the signals \(\mathcal {I}\cup \mathcal {O}\), resulting in the alphabet \(\varSigma = 2^{\mathcal {I}\cup \mathcal {O}}\). The syntax of an LTL specification \( \varphi \) is defined as follows:

The size of a specification \( \varphi \) is denoted by \( |\varphi | \) and is defined to be the number of sub-formulas of \( \varphi \). The semantics of LTL are defined over infinite words \( \alpha \in \varSigma ^{\omega }\). We define the satisfaction of a word \( \alpha \) at a position \( n \in \mathbb {N}\) and a specification \( \varphi \), denoted by \( \alpha , n \vDash \varphi \), for the different choices of \( \varphi \), respectively, as follows:

  • \( \alpha , n \vDash \textit{true} \)

  • \( \alpha , n \vDash a \) iff \( a \in \alpha _{i} \)

  • \( \alpha , n \vDash \lnot \varphi \) iff \( \alpha , n \not \vDash \varphi \)

  • \( \alpha , n \vDash \varphi _{1} \vee \varphi _{2} \) iff \( \alpha , n \vDash \varphi _{1} \) or \( \alpha , i \vDash \varphi _{2} \)

  • iff \( \alpha , n + 1 \vDash \varphi \)

  • \( \alpha , n \vDash \varphi _{1} {{\mathrm{\mathcal {U}}}}\varphi _{2} \) iff \( \exists m \ge n.\ \alpha , m \vDash \varphi _{2} \) and \( \forall n \le i < m.\ \alpha , i \vDash \varphi _{1}. \)

An infinite word \( \alpha \) satisfies \( \varphi \), denoted by \( \alpha \vDash \varphi \), iff \( \alpha , 0 \vDash \varphi \). The language \( \mathcal {L}(\varphi ) \) is the set of all words that satisfy \( \varphi \), i.e., \( \mathcal {L}(\varphi ) = \{ \alpha \in \varSigma ^{\omega } \mid \alpha \vDash \varphi \}\). Beside the standard operators, we have the standard derivatives of the boolean operators, as well as and . A Mealy machine \( \mathcal {M}\) is an implementation of \( \varphi \) iff \( \pi _{1}(\mathcal {P}(\mathcal {M})) \subseteq \mathcal {L}(\varphi )\).

Let \( G = (V,E) \) be a directed graph. A (simple) cycle c of G is a tuple \( (C,\eta )\), consisting of a non-empty set \( C \subseteq V \) and a bijection \( \eta :C \mapsto C \) such that

  • \( \forall v \in C.\ (v,\eta (v)) \in E \) and

  • \( \forall v \in C.\ n \in \mathbb {N}.\ \eta ^{n}(v) = v \ \Leftrightarrow \ n \!\!\mod |C| = 0\),

where \( \eta ^{n} \) denotes n times the application of \( \eta \). In other words, a cycle of G is a path through G that starts and ends at the same vertex and visits every vertex of V at most once. We say that a cycle \( c = (C,\eta ) \) has length n iff \( |C| = n\).

We extend the notion of a cycle of a graph G to Mealy machines \( \mathcal {M}= (\mathcal {I}, \mathcal {O}, T, t_{I}, \delta , \lambda )\), such that c is a cycle of \( \mathcal {M}\) iff c is a cycle of the graph (TE) for \( E = \{ (t,t') \mid \exists \nu \in 2^{\mathcal {I}}.\ \delta (t,\nu ) = t\}\). Thus, we ignore the input labels of the edges of \( \mathcal {M}\). The set of all cycles of a Mealy machine \( \mathcal {M}\) is denoted by \( \mathcal {C}(\mathcal {M})\).

A universal co-Büchi automaton \( \mathcal {A}\) is a tuple \( (\varSigma ,Q,q_{I},\varDelta ,R)\), where \( \varSigma \) is the alphabet, Q is a finite set of states, \( q_{0} \in Q \) is the initial state, \( \varDelta \subseteq Q \times \varSigma \times Q \) is the transition relation and \( R \subseteq Q \) is the set of rejecting states. A run \( r = (q_{0},\sigma _{0})(q_{1},\sigma _{1})(q_{2},\sigma _{2})\ldots \in (Q \times \varSigma )^{\omega } \) of \( \mathcal {A}\) is an infinite sequence such that \( q_{0} = q_{I} \) and \( (q_{n},\sigma _{n},q_{n+1}) \in \varDelta \) for all \( n \in \mathbb {N}\). A run r is accepting if it has a suffix \( q_{n}q_{n+1}q_{n+2}\ldots \in (Q \,\backslash \,R)^{\omega } \) for some \( n \in \mathbb {N}\). An infinite word \( \alpha \in \varSigma ^{\omega } \) is accepted by \( \mathcal {A}\) if all corresponding runs, i.e., all runs \( r = (q_{0},\sigma _{0})(q_{1},\sigma _{1})(q_{2},\sigma _{2})\ldots \) with \( \alpha = \sigma _{0}\sigma _{1}\sigma _{2}\ldots \), are accepting. The language \( \mathcal {L}(\mathcal {A}) \) of \( \mathcal {A}\) is the set of all \( \alpha \in \varSigma ^{\omega }\), accepted by \( \mathcal {A}\).

The run graph G of a universal co-Büchi automaton \( \mathcal {A}= (2^{\mathcal {I}\cup \mathcal {O}},Q,q_{I},\varDelta ,R) \) and a Mealy machine \( \mathcal {M}= (\mathcal {I}, \mathcal {O}, T, t_{I}, \delta , \lambda ) \) is a directed graph \( G = (T \times Q,E)\), with \( E = \{ ((t,q),(t',q')) \mid \exists \sigma .\ \delta (t,\mathcal {I}\cap \sigma ) = t',\, \lambda (t,\mathcal {I}\cap \sigma ) = {\mathcal {O}\cap \sigma },\, (q,\sigma ,q') \in \varDelta \}\). A vertex (tq) of G is rejecting iff \( q \in R\). A run graph is accepting iff there is no cycle of G, which contains a rejecting vertex. If the run graph is accepting, we say, \( \mathcal {M}\) is accepted by \( \mathcal {A}\).

3 Bounds on the Number of Cycles

Our goal is to synthesize systems that have a simple structure. System quality most certainly has other dimensions as well, but structural simplicity is a property of interest for most applications.

The purpose of this section is to give theoretical arguments why the number of cycles is a good measure: we show that the number of cycles may explode even in cases where the number of states is small, and even if the specification enforces a large implementation, there may be a further explosion in the number of cycles. This indicates that bounding the number of cycles is important, if one wishes to have a structurally simple implementation. On the other hand, we observe that bounding the number of states alone is not sufficient in order to obtain a simple structure.

Similar observations apply to modern programming languages, which tend to be much better readable than transition systems, because their control constructs enforce a simple cycle structure. Standard synthesis techniques construct transition systems, not programs, and therefore loose this advantage. With our approach, we get closer to the control structure of a program, without being restricted to a specific programming language.

3.1 Upper Bounds

First, we show that the number of cycles of a Mealy machine \( \mathcal {M}\), implementing an LTL specification \( \varphi \), is bounded triply exponential in the size of \( \varphi \). To this end, we first bound the number of cycles of an arbitrary graph G with bounded outdegree.

On graphs with arbitrary outdegree, the maximal number of cycles is given by a fully connected graph, where each cycle describes a permutation of states, and vice versa. Hence, using standard math we obtain an upper bound of \( 2^{n \log n} \) cycles for a graph with n states. However, our proof uses a more involved argument to improve the bound even further down to \( 2^{n \log (m + 1)} \) for graphs with bounded outdegree m. Such an improvement is desirable, as for LTL the state graph explodes in the number of states, while the outdegree is constant in the number of input and output signals.

Lemma 1

Let \( G = (V,E) \) be a directed graph with \( |V| = n \) and with maximal outdegree m. Then G has at most \( 2^{n \log (m + 1)} \) cycles.

Proof

We show the result by induction over n. The base case is trivial, so let \( n > 1 \) and let \( v \in V \) be some arbitrary vertex of G. By induction hypothesis, the subgraph \( G'\), obtained from G by removing v, has at most \( 2^{(n - 1) \log (m+1)} \) cycles. Each of these cycles is also a cycle in G, thus it remains to consider the cycles of G containing v. In each of these remaining cycles, v has one of m possible successors in \( G' \) and from each such successor \( v' \) we have again \( 2^{(n-1) \log (m+1)} \) possible cycles in \( G' \) returning to \( v'\). Hence, if we redirect these cycles to v instead of \( v'\), i.e., we insert v before \( v' \) in the cycle, then we cover all possible cycles of G containing v Footnote 1. All together, we obtain an upper bound of \( 2^{(n - 1) \log (m+1)} + m \cdot 2^{(n - 1) \log (m+1)} = 2^{n \log (m+1)} \) cycles in G.    \(\square \)

We obtain an upper bound on the number of cycles of a Mealy machine \( \mathcal {M}\).

Lemma 2

Let \( \mathcal {M}\) be a Mealy machine. Then .

Proof

The Mealy machine \( \mathcal {M}\) has an outdegree of \( 2^{|\mathcal {I}|} \) and, thus, by Lemma 1, the number of cycles is bounded by .    \(\square \)

Finally, we are able to derive an upper bound on the implementations realizing a LTL specification \( \varphi \).

Theorem 1

Let \( \varphi \) be a realizable LTL specification. Then there is a Mealy machine \( \mathcal {M}\), realizing \( \varphi \), with at most triply exponential many cycles in \( |\varphi |\).

Proof

From [9, 15, 16] we obtain a doubly exponential upper bound in \( |\varphi | \) on the size of \( \mathcal {M}\). With that, applying Lemma 2 yields the desired result.    \(\square \)

3.2 Lower Bounds

It remains to prove that the bound of Theorem 1 is tight. To this end, we show that for each \( n \in \mathbb {N}\) there is a realizable LTL specification \( \varphi \) with \( |\varphi | \in \varTheta (n)\), such that every implementation of \( \varphi \) has at least triply exponential many cycles in n. The presented proof is inspired by [1], where a similar argument is used to prove a lower bound on the distance of the longest path through a synthesized implementation \( \mathcal {M}\). We start with a gadget, which we use to increase the number of cycles exponentially in the length of the longest cycle of \( \mathcal {M}\).

Lemma 3

Let \( \varphi \) be a realizable LTL specification, for which every implementation \( \mathcal {M}\) has a cycle of length n. Then there is a realizable specification \( \psi \), such that every Mealy machine \( \mathcal {M}' \) implementing \( \psi \) contains at least \( 2^{n} \) many cycles.

Proof

Let a and b be a fresh input and output signals, respectively, which do not appear in \( \varphi \), and let \( \mathcal {M}= (\mathcal {I}, \mathcal {O}, T, t_{I}, \delta , \lambda ) \) be an arbitrary implementation of \( \varphi \). We define and construct the implementation \( \mathcal {M}' \) as

$$\begin{aligned} \mathcal {M}' = (\mathcal {I}\cup \{ a \}, \mathcal {O}\cup \{ b \}, T \times 2^{\{ b \}}, (t_{I},\emptyset ), \delta ', \lambda '), \end{aligned}$$

where \( \lambda '((t,s),\nu ) = \lambda (t,\mathcal {I}\cap \nu ) \cup s \) and

$$\begin{aligned} \delta '((t,s), \nu ) = {\left\{ \begin{array}{ll} (\delta (t,\mathcal {I}\cap \nu ), \emptyset ) &{} \text {if } a \in \nu \\ (\delta (t,\mathcal {I}\cap \nu ), \{ b \}) &{} \text {if } a \notin \nu \end{array}\right. } \end{aligned}$$

We obtain that \( \mathcal {M}' \) is an implementation of \( \psi \). The implementation remembers each input a for one time step and then outputs the stored value. Thus, it satisfies . Furthermore, \( \mathcal {M}' \) still satisfies \( \varphi \). Hence, \( \psi \) must be realizable, too.

Next, we pick an arbitrary implementation \( \mathcal {M}'' \) of \( \psi \), which must exist according to our previous observations. Then, after projecting away the fresh signals a and b from \( \mathcal {M}''\), we obtain again an implementation for \( \varphi \), which contains a cycle \( (C,\eta ) \) of length n, i.e., \( C = \{ t_{1}, t_{2}, \ldots , t_{n}\}\). We obtain that \( \mathcal {M}'' \) contains at least the cycles

$$\begin{aligned} \mathbb {C} = \{ ( \{ (t_{i},f(t_{i})) \mid i \in \{ 1,2,\ldots n \}\}, (t,s) \mapsto (\eta (t),f(\eta (t)))) \mid f :C \rightarrow 2^{\{ b \}} \}, \end{aligned}$$

which concludes the proof, since \( |\mathbb {C}| = 2^{n}\).    \(\square \)

Now, with Lemma 3 at hand, we are ready to show that the aforementioned lower bounds are tight. The final specification only needs the temporal operators , i.e., the bound already holds for a restricted fragment of LTL.

Theorem 2

For every \( n > 1\), there is a realizable specification \( \varphi _{n} \) with \( |\varphi _{n}| \in \varTheta (n)\), for which every implementation \( \mathcal {M}_{n} \) has at least triply exponential many cycles in n.

Proof

According to Lemma 3, it suffices to find a realizable \( \varphi _{n}\), such that \( \varphi _{n} \) contains at least one cycle of length doubly exponential in n. We choose

figure a

with \( \mathcal {I}= \mathcal {I}_{a} \cup \mathcal {I}_{b} \cup \mathcal {I}_{c} \cup \mathcal {I}_{d} \) and \( \mathcal {O}= \{s\}\), where \( \mathcal {I}_{x} = \{ x_{1}, x_{2}, \ldots , x_{n}\}\). The specification describes a monitor, which checks whether the invariant over the input signals \( \mathcal {I}\) is satisfied or not. Thereby, satisfaction is signaled by the output s, which needs to be triggered infinitely often, as long as the invariant stays satisfied.

In the following, we denote a subset \( x \subseteq \mathcal {I}_{x} \) by the n -ary vector \( \vec {x} \) over \( \{0, 1\}\), where the i -th entry of \( \vec {x} \) is set to 1 if and only if \( x_{i} \in x\).

The specification \( \varphi _{n} \) is realizable. First, consider that to check the fulfillment of \( \varphi _{n}^{\textit{prem}} \) (\( \varphi _{n}^{\textit{con}}\)), an implementation \( \mathcal {M}\) needs to store the set of all requests \( \vec {a} \) (\( \vec {c}\)), whose 1 -positions have not yet been released by a corresponding response \( \vec {b} \)(\( \vec {\!d}\)). Furthermore, to monitor the complete invariant , \(\mathcal {M}\) has to guess at each point in time, whether \( \varphi _{n}^{\textit{prem}} \) will be satisfied in the future (under the current request \( \vec {a}\)), or not. To realize this guess, \( \mathcal {M}\) needs to store a mapping f, which maps each open request \( \vec {a} \) to the corresponding set of requests \( \vec {c}\) Footnote 2. This way, \( \mathcal {M}\) can look up the set of requests \( \vec {c}\), tracked since the last occurrence of \( \vec {a}\), whenever \( \vec {a} \) gets released by a corresponding vector \( \vec {b}\). If this is the case, it continues to monitor the satisfaction of \( \varphi _{n}^{\textit{con}} \) (if not already satisfied) and finally adjusts the output signal s, correspondingly. Note that \( \mathcal {M}\) still has to continuously update and store the mapping f, since the next satisfaction of \( \varphi _{n}^{\textit{prem}} \) may already start while the satisfaction of current \( \varphi _{n}^{\textit{con}} \) is still checked. There are double exponential many such mappings f, hence, \( \mathcal {M}\) needs to be at least doubly exponential in n.

It remains to show that every such implementation \( \mathcal {M}\) contains a cycle of at least doubly exponential length. By the aforementioned observations, we can assign each state of \( \mathcal {M}\) a mapping f, that maps vectors \( \vec {a} \) to sets of vectors\(~\vec {c}\). By interpreting the vectors as numbers, encoded in binary, we obtain that \( f :\{1,2,\ldots ,2^{n}\} \mapsto 2^{\{1,2,\ldots ,2^{n}\}}\). Next, we again map each such mapping f to a binary sequence \( b_{f} = b_{0}b_{1}\ldots b_{m} \in \{ 0, 1 \}^{m} \) with \( m = 2^{n}\). Thereby, a bit \( b_{i} \) of \( b_{f} \) is set to 1 if and only if \( i \in f(i)\). It is easy to observe, that if two binary sequences are different, then their related states have to be different as well.

To conclude the proof, we show that the environment has a strategy to manipulate the bits of associated sequences \( b_{f} \) via the inputs \( \mathcal {I}\).

To set bit \( b_{i}\), the environment chooses the requests \( \vec {a} \) and \( \vec {c} \) such that they represent i in binary. The remaining inputs are fixed to \( \vec {b} = \vec {d} = \vec {0}\). Hence, all other bits are not affected, as possible requests of previous \( \vec {a} \) and \( \vec {c} \) remain open.

To reset bit \( b_{i}\), the environment needs multiple steps. First, it picks \( \vec {a} = \vec {c} = \vec {d} = \vec {0} \) and \( \vec {b} = \vec {1}\). This does not affect any bit of the sequence \( b_{f}\), since all requests introduced through vectors \( \vec {c} \) are still open. Next, the environment executes the aforementioned procedure to set bit \( b_{j} \) for every bit currently set to 1, except for the bit \( b_{i}\), it wants to reset. This refreshes the requests introduced by previous vectors \( \vec {a} \) for every bit, except for \( b_{i}\). Furthermore, it does not affect the sequence \( b_{f}\). Finally, the environment picks \( \vec {a} = \vec {b} = \vec {c} = \vec {0} \) and picks \( \vec {d} \) such that it represents i in binary. This removes i from every entry in f, but only resets \( b_{i}\), since all other bits are still open due to the previous updates.

With these two operations, the environment can enforce any sequences of sequences \( b_{f}\), including a binary counter counting up to \( 2^{2^{n}}\). As different states are induced by the different sequences, we obtain a cycle of doubly exponential length in n by resetting the counter at every overflow.    \(\square \)

3.3 The Trade-Off Between States and Cycles

We conclude this section with some observations regarding tradeoffs between the problem of synthesizing implementations, which are minimal in the number of states, versus the problem of synthesizing implementations, which are minimal in the number of cycles. The main question we answer, is whether we can achieve both: minimality in the number of states and minimality in the number of cycles. Unfortunately, this is not possible, as shown by Theorem 3.

Theorem 3

For every \( n > 1\), there is a realizable LTL specification \( \varphi _{n} \) with \( |\varphi | \in \varTheta (n)\), such that

  • there is an implementation of \( \varphi \) consisting of n states and

  • there is an implementation of \( \varphi \) containing m cycles,

  • but there is no implementation of \( \varphi \) with n states and m cycles.

Proof

Fig. 3.
figure 3

The Mealy automata \( \mathcal {M}_{n} \) (red/dotted) and \( \mathcal {M}_{n}' \) (blue/dashed). Solid edges are shared between both automata.

Consider the specification

over \( \mathcal {I}= \{ a \} \) and \( \mathcal {O}= \{ b, c\}\), where denotes i times the application of . The specification \( \varphi _{n} \) is realizable with at least \( n = 2k + 1 \) states. The corresponding Mealy machine \( \mathcal {M}_{n} \) is depicted in Fig. 3. However, \( \mathcal {M}_{n} \) has \( m = 2^{k} \) many cycles. This blowup can be avoided by spending the implementation at least one more state, which reduces the number of cycles to \( m = 1\). The result \( \mathcal {M}_{n}' \) is also depicted in Fig. 3.    \(\square \)

Our results show that the number of cycles can explode (even more so than the number of states), and that sometimes this explosion is unavoidable. However, the results also show that there are cases, where the cycle count can be improved by choosing a better structured solution. Hence, it is desirable to have better control over the number of cycles that appear in an implementation. In the remainder of the paper, we show how to achieve this control.

4 Bounding the Cycles

In this section, we show how to synthesize an implementation \( \mathcal {M}\) from a given LTL specification \( \varphi \), while giving a guarantee on the size and the number of cycles of \( \mathcal {M}\). We first show how to guarantee a bound on the number of states of \( \mathcal {M}\), by reviewing the classical Bounded Synthesis approach. Our encoding uses Mealy machines as implementations, and Boolean Satisfiability (SAT) as the underlying constraint system.

We then review the classical algorithm to count the cycles of \( \mathcal {M}\) and show how this algorithm gets embedded into a constraint system, such that we obtain a guarantee on the number of cycles of \( \mathcal {M}\).

4.1 Bounded Synthesis

In the bounded synthesis approach [9], we first translate a given LTL specification \( \varphi \) into an equivalent universal co-Büchi automaton \( \mathcal {A}\), such that \( \mathcal {L}(\mathcal {A}) = \mathcal {L}(\varphi )\). Thus, we reduce the problem to finding an implementation \( \mathcal {M}\) that is accepted by \( \mathcal {A}\), i.e., we look for an implementation \( \mathcal {M}\) such that the run graph of \( \mathcal {M}\) and \( \mathcal {A}\) contains no cycle with a rejecting vertex. This property is witnessed by a ranking function, which annotates each vertex of G by a natural number that bounds the number of possible visits to rejecting states. The annotation itself is bounded by \( n \cdot k\), where n is the size bound on \( \mathcal {M}\) and k denotes the number or rejecting states of \( \mathcal {A}\).

Fix some set of states T with \( |T| = n \) and let \( \mathcal {A}= (2^{\mathcal {I}\cup \mathcal {O}},Q,q_{I},\varDelta ,R)\). Then, to guess a solution within SAT, we introduce the following variables:

  • \( \textsc {trans}(t,\nu ,t') \) for all \( t,t' \in T \) and \( \nu \in 2^{\mathcal {I}}\), for the transition relation of \( \mathcal {M}\).

  • \( \textsc {label}(t,\nu ,x) \) for all \( t \in T\), \( \nu \in 2^{\mathcal {I}} \) and \( x \in \mathcal {O}\), for the labels of each transition.

  • \( \textsc {rgstate}(t,q) \) for all \( t \in T \) and \( q \in Q\), to denote the reachable states of the run graph G of \( \mathcal {M}\) and \( \mathcal {A}\). Only reachable states have to be annotated.

  • \( \textsc {annotation}(t,q,i) \) for all \( t \in T\), \( q \in Q \) and \( 0 < i \le \log (n \cdot k)\), denoting the annotation of a state (tq) of G. Thereby, we use a logarithmic number of bits to encode the annotated value in binary. We use \( \textsc {annotation}(t,q) \circ m \) for \( \circ \in \{ <, \le , =, \ge , >\}\), to denote an appropriate encoding of the relation of the annotation to some value m or other annotations \( \textsc {annotation}(t',q')\).

Given a universal co-Büchi automaton \( \mathcal {A}\) and a bound n on the states of the resulting implementation, we encode the Bounded Synthesis problem via the SAT formula \( \mathcal {F}_{BS}(\mathcal {A},n)\), consisting of the following constraints:

  • The target of every transition is unambiguous:

    $$\begin{aligned} \bigwedge \limits _{t \in T,\, \nu \in 2^{\mathcal {I}}} \textit{exactlyOne}(\{ \textsc {trans}(t,v,t') \mid t' \in T\}) \end{aligned}$$

    where \( \textit{exactelyOne}\,:X \mapsto \mathbb {B}(X) \) returns a SAT query, which ensures that among all variables of the set X exactly one is true and all others are false.

  • The initial state \( (t_{I},q_{I}) \) of the run graph for some arbitrary, but fix, \( t_{I} \in T \) is reachable and annotated by one. Furthermore, all annotations are bounded by \( n \cdot k\):

    $$\begin{aligned} \textsc {rgstate}(1,1) \wedge \textsc {annotation}(1,1) = 1 \wedge \bigwedge \limits _{t \in T, \, q \in Q} \textsc {annotation}(t,q) \le n \cdot k \end{aligned}$$
  • Each annotation of a vertex of the run graph bounds the number of visited accepting states, not counting the current vertex itself:

    $$\begin{aligned} \bigwedge \limits _{t \in T,\, q \in Q} \textsc {rgstate}(t,q) \rightarrow \bigwedge \limits _{\sigma \in 2^{\varSigma }} \textit{label}(t,\sigma ) \rightarrow \bigwedge \limits _{t' \in T} \textsc {trans}(t,\mathcal {I}\cap \sigma ,t') \rightarrow \end{aligned}$$
    $$\begin{aligned} \qquad \bigwedge \limits _{q' \in \varDelta (q,\sigma )} \textsc {rgstate}(t',q') \wedge \textsc {annotation}(t,q) \prec _{q} \textsc {annotation}(t',q') \end{aligned}$$

    where \( \prec _{q} \) equals < if \( q \in R \) and equals \( \le \) otherwise. Furthermore, we use the function \( \textit{label}(t,\sigma ) \) to fix the labeling of each transition, i.e., \( \textit{label}(t,\sigma ) = \bigwedge _{x \in \mathcal {O}\cap \sigma }\, \textsc {label}(t,\mathcal {I}\cap \sigma ,x) \wedge \bigwedge _{x \in \mathcal {O}\backslash \sigma } \lnot \textsc {label}(t,\mathcal {I}\cap \sigma ,x)\).

Theorem 4

(Bounded Synthesis [9]). For each bound \( n \in \mathbb {N}\) and each universal co-Büchi automaton \( \mathcal {A}\), the SAT formula \( \mathcal {F}_{BS}(\mathcal {A},n) \) is satisfiable if and only if there is a Mealy machine \( \mathcal {M}\) with \( |\mathcal {M}| = n\), which is accepted by \( \mathcal {A}\).

4.2 Counting Cycles

Before we bound the number of cycles of a Mealy machine \( \mathcal {M}\), we review Tiernan’s classical algorithm [17] to count the number of cycles of a directed graph G. The algorithm not only gives insights into the complexity of the problem, but also contains many inspirations for our latter approach.

Algorithm 1. Given a directed graph \( G = (V,E)\), we count the cycles of G using the following algorithm:

  1. (1)

    Initialize the cycle counter c to \( c := 0 \) and some set P to \( P := \emptyset \).

  2. (2)

    Pick some arbitrary vertex \( v_{r} \) of G, set \( v := v_{r} \) and \( P := \{ v_{r}\}\).

  3. (3)

    For all edges \( (v,v') \in E\), with \( v' \notin P \,\backslash \{ v_{r} \}\):

    1. (3a)

      If \( v' = v_{r}\), increase c by one.

    2. (3b)

      Otherwise, add \( v' \) to P and recursively execute (3). Afterwards, reset P to its value before the recursive call.

  4. (4)

    Obtain the sub-graph \( G'\), by removing \( v_{r} \) from G:

    1. (4a)

      If \( G' \) is empty, return c.

    2. (4b)

      Otherwise, continue from (2) with \( G'\).

The algorithm starts by counting all cycles that contain the first picked vertex\(~v_{r}\). This is done by an unfolding of the graph into a tree, rooted in \( v_{r}\), such that there is no repetition of a vertex on any path from the root to a leaf. The number of vertices that are connected to the root by an edge of E then represents the corresponding number of cycles through \( v_{r}\). The remaining cycles of G do not contain \( v_{r} \) and, thus, are cycles of the sub-graph \( G' \) without \( v_{r}\), as well. Hence, we count the remaining cycles by recursively counting the cycles of \( G'\). The algorithm terminates as soon as \( G' \) gets empty.

The algorithm is correct [17], but has the drawback, that the unfolded trees, may become exponential in the size of the graph, even if none of their vertices is connected to the root, i.e., even if there is no cycle to be counted. For an example consider the induced graph of \( \mathcal {M}_{n}'\), as depicted in Fig. 3. However, this drawback can be avoided by first reducing the graph to all its strongly connected components (SCCs) and then by counting the cycles of each SCC separately [13, 18]. A cycle never leaves an SCC of the graph.

As a result, we obtain an improved algorithm, which is exponential in the size of G, but linear in the number of cycles m. Furthermore, the time between two detections of a cycle, during the execution, is bounded linear in the size of the graph G.

4.3 Bounded Cycle Synthesis

We combine the insights of the previous sections to obtain a synthesis algorithm, which not only bounds the number of states of the resulting implementation \( \mathcal {M}\) but also bounds the number of cycles of \( \mathcal {M}\). We use the unfolded trees from the previous section as our witnesses.

We call a tree that witnesses m cycles in G, all containing the root r of the tree, a witness-tree \( \mathcal {T}_{r,m} \) of G. Formally, a witness-tree \( \mathcal {T}_{r,m} \) of \( G = (V,E) \) is a labeled graph \( \mathcal {T}_{r,m} = ((W,B\cup R),\tau )\), consisting of a graph \( (W,B \cup R) \) with \( m = |R| \) and a labeling function \( \tau \,:W \rightarrow V\), such that:

  1. 1.

    The edges are partitioned into blue edges B and red edges R.

  2. 2.

    All red edges lead back to the root:

    \( R \subseteq W \times \{ r \} \)

  3. 3.

    No blue edges lead back to the root:

    \( B \cap W \times \{ r \} = \emptyset \)

  4. 4.

    Each non-root has at least one blue incoming edge:

    \( \forall w' \in W \,\backslash \{ r \}.\ \exists w \in W.\ (w,w') \in B \)

  5. 5.

    Each vertex has at most one blue incoming edge:

    \( \forall w_{1},w_{2},w \in W.\ (w_{1},w) \in B \wedge (w_{2},w) \in B \Rightarrow w_{1} = w_{2} \)

  6. 6.

    The graph is labeled by an unfolding of G:

    \( \forall w,w' \in B \cup R.\ (\tau (w),\tau (w')) \in E\),

  7. 7.

    The unfolding is complete:

    \( \forall w \in W.\ \forall v' \in V.\ (\tau (w),v') \in E \Rightarrow \exists w' \in W.\ (w,w') \in B \cup R \wedge \tau (w') = v' \)

  8. 8.

    Let \( w_{i}, w_{j} \in W \) be two different vertices that appear on a path from the root to a leaf in the r -rooted tree (WB)Footnote 3. Then the labeling of \( w_{i} \) and \( w_{j} \) differs, i.e., \( \tau (v_{i}) \ne \tau (v_{j})\).

  9. 9.

    The root of the tree is the same as the corresponding vertex of G, i.e., \( \tau (r) = r\).

Lemma 4

Let \( G = (V,E) \) be a graph consisting of a single SCC, \( r \in V \) be some vertex of G and m be the number of cycles of G containing r. Then there is a witness-tree \( \mathcal {T}_{r,m} = ((W,B \cup R),\tau ) \) of G with \( |W| \le m \cdot |V|\).

Proof

We construct \( \mathcal {T}_{r,m} \) according to the strategy induced by Algorithm 1, where an edge is colored red if and only if it leads back to the root. The constructed tree satisfies all conditions 1–9. By correctness of Algorithm 1, we have that \( |R| = m\).

Now, for the sake of contradiciton, assume \( |W| > m \cdot |V|\). First we observe, that the depth of the tree (WB) must be bounded by \( |V| \) to satisfy Condition 8. Hence, as there are at most m red edges in \( \mathcal {T}_{r,m}\), there must be a vertex \( w \in W \) without any outgoing edges. However, since G is a single SCC, this contradicts the completeness of \( \mathcal {T}_{r,m} \) (Condition 7).    \(\square \)

Lemma 5

Let \( G = (V,E) \) be a graph consisting of a single SCC and let \( \mathcal {T}_{r,m} \) be a witness-tree of G. Then there are at most m cycles in G that contain r.

Proof

Let \( \mathcal {T}_{r,m} = ((W,R \cup B),\tau )\). Assume for the sake of contradiction that G has more than m cycles and let \( c = (C,\eta ) \) be an arbitrary such cycle. By the completeness of \( \mathcal {T}_{r,m}\), there is path \( w_{0}w_{1}\ldots w_{|C|-1} \) with \( w_{0} = r \) and \( \tau (w_{i}) = \eta ^{i}(r) \) for all \( 0 \le i < |C|\). From \( w_{i} \ne r \) and Condition 2, it follows \( (w_{i-1},w_{i}) \in B \) for all \( 0< i < |C|\). Further, \( \eta ^{|C|}(r) = r \) and thus \( (w_{|C|-1},w_{0}) \in R\). Hence, by the tree shape of (WB), we get \( |R| > m\), yielding the desired contradiction.    \(\square \)

From Lemmas 4 and 5 we derive that \( \mathcal {T}_{r,m} \) is a suitable witness to bound the number of cycles of an implementation \( \mathcal {M}\). Furthermore, from Lemma 4 we also obtain an upper bound on the size of \( \mathcal {T}_{r,m}\).

We proceed with our final encoding. Therefore, we first construct a simple directed graph G out of the implementation \( \mathcal {M}\). Then, we guess all the sub-graphs, obtained from G via iteratively removing vertices, and split them into their corresponding SCCs. Finally, we guess the witness-tree for each such SCC.

To keep the final SAT encoding compact, we even introduce some further optimizations. First, we do not need to introduce a fresh copy for each SCC, since the SCC of a vertex is always unique. Thus, it suffices to guess an annotation for each vertex, being unique for each SCC. Second, we have to guess n trees\(~\mathcal {T}_{i,r_{i}}\), each one consisting of at most \( i \cdot n \) vertices, such that the sum of all i is equal to the overall number of cycles m. One possible solution would be to overestimate each i by m. Another possibility would be to guess the exact distribution of the cycles over the different witness-trees \( \mathcal {T}_{i,r_{i}}\). However, there is a smarter solution: we guess all trees together in a single graph bounded by \( m \cdot n\). Additionally, to avoid possible interleavings, we add an annotation of each vertex by its corresponding witness-tree \( \mathcal {T}_{i,r_{i}}\). Hence, instead of bounding the number of each \( \mathcal {T}_{i,r_{i}}\) separately by i, we just bound the number of all red edges in the whole forest by m. This way, we not only reduce the size of the encoding, but also skip the additional constrains, which would be necessary to sum the different witness-tree bounds i to m, otherwise.

Let T be some ordered set with \( |T| = n \) and \( S = T \times \{ 1,2,\ldots , m\}\). We use T to denote the vertices of G and S to denote the vertices of the forest of \( \mathcal {T}_{i,r_{i}} \) s. Further, we use \( M = T \times \{ 1 \} \) to denote the roots and \( N = S \,\backslash \, M \) to denote the non-roots of the corresponding trees. We introduce the following variables:

  • \( \textsc {edge}(t,t') \) for all \( t,t' \in T\), denoting the edges of the abstraction of \( \mathcal {M}\) to G.

  • \( \textsc {bedge}(s,s') \) for all \( s \in S \) and \( s' \in N\), denoting a blue edge.

  • \( \textsc {redge}(s,s') \) for all \( s \in S \) and \( s' \in M\), denoting a red edge.

  • \( \textsc {wtree}(s,i) \) for all \( s \in S\), \( 0 < i \le \log n\), denoting the witness-tree of each s. As before, we use \( \textsc {wtree}(s) \circ x \) to relate values with the underlying encoding.

  • \( \textsc {visited}(s,t) \) for all \( s \in S \) and \( t \in T\), denoting the set of all vertices t, already visited at s, since leaving the root of the corresponding witness-tree.

  • \( \textsc {rbound}(c,i) \) for all \( 0 < c \le m\), \( 0 < i \le \log (n \cdot m)\), denoting an ordered list of all red edges, bounding the red edges of the forest.

  • \( \textsc {scc}(k,t,i) \) for all \( 0 < k \le n\), \( t \in T, \) and \( 0 \le i < \log n\), denoting the SCC of t in the k -th sub-graph of G. The sub-graphs are obtained by iteratively removing vertices of T, according to the pre-defined order. This way, each sub-graph contains exactly all vertices that are larger than the root.

Note that by the definition of S we introduce m explicit copies for each vertex of G. This is sufficient, since each cycle contains each vertex at most once. Thus, the labeling \( \tau \) of a vertex s can be directly derived from the first component of s.

Given a universal co-Büchi automaton \( \mathcal {A}\), a bound n on the states of the resulting implementation \( \mathcal {M}\), and a bound m on the number of cycles of \( \mathcal {M}\), we encode the Bounded Cycle Synthesis problem via the SAT formula \( \mathcal {F}_{BS}(\mathcal {A},n) \wedge \mathcal {F}_{CS}(\mathcal {A},n,m) \wedge \mathcal {F}_{SCC}(n)\). The constraints of \( \mathcal {F}_{CS}(\mathcal {A},n,m)\), bounding the cycles of the system, are given by Table 1. The constraints of \( \mathcal {F}_{SCC}(n)\), enforcing that each vertex is labeled by a unique SCC, can be found in the technical report [8].

Theorem 5

For each pair of bounds \( n, m \in \mathbb {N}\) and each universal co-Büchi automaton \( \mathcal {A}\) with \( |\mathcal {A}| = k\), the formula \( \mathcal {F}= \mathcal {F}_{BS}(\mathcal {A},n) \wedge \mathcal {F}_{CS}(\mathcal {A},n,m) \wedge \mathcal {F}_{SCC} \) is satisfiable if and only if there is a Mealy machine \( \mathcal {M}\) with \( |\mathcal {M}| = n \) and \( |\mathcal {C}(\mathcal {M})| = m \), accepted by \( \mathcal {A}\). Furthermore, \( \mathcal {F}\) consists of x variables with and .

Table 1. Constraints of the SAT formula \( \mathcal {F}_{CS}(\mathcal {A}, n, m)\).

5 Experimental Results

We have implemented the Bounded Cycle Synthesis approach in our tool BoWSer, the Bounded Witness Synthesizer, and compared it against standard Bounded Synthesis and Acacia+ (v2.3) [6, 7]. To ensure a common encoding, we used BoWSer for both, the Bounded Synthesis and the Bounded Cycle Synthesis approach. Our tool uses LTL3BA (v1.0.2) [3] to convert specifications to universal co-Büchi automata. The created SAT queries are solved by MiniSat (v.2.2.0) [5] and clasp (v.3.1.4) [10], where the result of the faster solver is taken.

The benchmarks are given in TLSF [11] and represent a decomposition of Arm’s Advanced Microcontroller Bus Architecture (AMBA) [2]. They are created from the assumptions and guarantees presented in [12], which were split into modules, connected by new signals. A detailed description of the benchmarks is given in [11].

All experiments were executed on a Unix machine, operated by a 64-bit kernel (v4.1.12) running on an Intel Core i7 with 2.8 GHz and 8 GB RAM. Each experiment had a time limit of 1000 s and a memory limit of 8 GB. When counting cycles of a solution, the limit was set to 10000000 cycles.

Table 2. Results of the tools LTL3BA, Aca(cia)+ and BoWSer. The LTL3BA tool was used to generate the universal co-Büchi tree automata . The Bo(unded) Sy(nthesis) and Bo(unded) Cy(cle Synthesis) encodings were generated by BoWSer.

The results of the evaluation are shown in Table 2, which displays the sizes of the intermediate universal co-Büchi tree automata , the sizes of the synthesized implementations \( \mathcal {M}\), the number of cycles of each implementation \(\mathcal {M}\), and the overall synthesis time. Thereby, for each instance, we guessed the minimal number of states for the Bounded Synthesis approach and, additionally, the minimal number of cycles for the Bounded Cycle Synthesis approach, to obtain a single satisfiable instance. Further, to verify the result, we also created the unsatisfiable instance, where the state bound was decreased by one in the case of Bounded Synthesis and the cycle bound was decreased by one in the case of Bounded Cycle Synthesis. Note that these two instances already give an almost complete picture, since for increased and decreased bounds the synthesis times behave monotonically. Hence, increasing the bound beyond the first realizable instance increases the synthesis time. Decreasing it below the last unsatisfiable instance decreases the synthesis time. The results for the TBURST4 component are additionally depicted in Fig. 1.

On most benchmarks, Acacia+ solves the synthesis problem the fastest, followed by Bounded Synthesis and our approach. (On some benchmarks, Bounded Synthesis outperforms Acacia+.) Comparing the running times of Bounded Synthesis and Bounded Cycle Synthesis, the overhead for bounding the number of cycles is insignificant on most benchmarks. The two exceptions are ENCODE, which requires a fully connected implementation, and TBURST4, where the reduction in the number of cycles is substantial. In terms of states and cycles, our tool outperforms Bounded Synthesis on half of the benchmarks and it outperforms Acacia+ on all benchmarks.

The results of Acacia+ show that the number of cycles is indeed an explosive factor. However, they also show that this explosion can be avoided effectively.

6 Conclusions

We have introduced the Bounded Cycle Synthesis problem, where we limit the number of cycles in an implementation synthesized from an LTL specification. Our solution is based on the construction of a witness structure that limits the number of cycles. The existence of such a witness can be encoded as a SAT problem. Our experience in applying Bounded Cycle Synthesis to the synthesis of the AMBA bus arbiter shows that the approach leads to significantly better implementations. Furthermore, the performance of our prototype implementation is sufficient to synthesize the components (in a natural decomposition of the specification) in reasonable time.

Both Bounded Synthesis and Bounded Cycle Synthesis can be seen as the introduction of structure into the space of implementations. Bounded Synthesis structures the implementations according to the number of states, Bounded Cycle Synthesis additionally according to the number of cycles. The double exponential blow-up between the size of the specification and the number of states, and the triple exponential blow-up between the size and the number of cycles indicate that, while both parameters provide a fine-grained structure, the number of cycles may even be the superior parameter. Formalizing this intuition and finding other useful parameters is a challenge for future work.

Our method does not lead to a synthesis algorithm in the classical sense, where just a specification is given and an implementation or an unsatisfiability result is returned. In our setting, the bounds are part of the input, and have to be determined beforehand. In Bounded Synthesis, the bound is usually eliminated by increasing the bound incrementally. With multiple bounds, the choice which parameter to increase becomes non-obvious. Finding a good strategy for this problem is a challenge on its own and beyond the scope of this paper. We leave it open for future research.