In this section, we describe our technique for synthesizing safe digital feedback controllers using CEGIS. For this purpose, we first provide the synthesizer’s general architecture, followed by describing our two approaches to synthesizing safe controllers: the first one is a baseline approach that relies on a naïve unfolding of the transition relation, whereas the second uses abstraction to evaluate all possible executions of the system.
4.1 General Architecture of the Program Synthesizer
The input specification provided to the program synthesizer is of the form \(\exists P .\, \forall a.\, \sigma (a, P)\), where P ranges over functions (where a function is represented by the program computing it), a ranges over ground terms, and \(\sigma \) is a quantifier-free formula. We interpret the ground terms over some finite domain \(\mathcal {D}\). The design of our synthesizer consists of two phases, an inductive synthesis phase and a validation phase, which interact via a finite set of test vectors inputs that is updated incrementally. Given the aforementioned specification \(\sigma \), the inductive synthesis procedure tries to find an existential witness P satisfying the specification \(\sigma (a, P)\) for all a in inputs (as opposed to all \(a \in \mathcal {D}\)). If the synthesis phase succeeds in finding a witness P, this witness is a candidate solution to the full synthesis formula. We pass this candidate solution to the validation phase, which checks whether it is a full solution (i.e., P satisfies the specification \(\sigma (a, P)\) for all \(a\in \mathcal {D}\)). If this is the case, then the algorithm terminates. Otherwise, additional information is provided to the inductive synthesis phase in the form of a new counterexample that is added to the inputs set and the loop iterates again. More details about the general architecture of the synthesizer can be found in [8].
4.2 Synthesis Problem: Statement (Recap) and Connection to Program Synthesis
At this point, we recall the synthesis problem that we solve in this work: we seek a digital feedback controller K (see Eq. 3) that makes the closed-loop plant model safe for initial state \(x_0\), reference signal \(r_k\) and input \(u_k\) as defined in Sect. 3.4. We consider non-deterministic initial states within a specified range, the reference signal to be set to zero, saturation on the inputs, and account for digitization and quantization errors introduced by the controller.
When mapping back to the notation used for describing the general architecture of the program synthesizer, the controller K denotes P, \((x_0, u_k)\) represents a and \(\phi _{ stability } \wedge \phi _{ input } \wedge \phi _{ init } \wedge \phi _{ safety }\) denotes the specification \(\sigma \).
4.3 Naïve Approach: CEGIS with Multi-staged Verification
An overview of the algorithm for controller synthesis is given in Fig. 2. One important observation is that we verify and synthesize a controller over k time steps. We then compute a completeness threshold \(\overline{k}\) [17] for this controller, and verify correctness for \(\overline{k}\) time steps. Essentially, \(\overline{k}\) is the number of iterations required to sufficiently unwind the closed-loop state-space system, which ensures that the boundaries are not violated for any other \(k{>}\overline{k}\).
Theorem 1
There exists a finite \(\overline{k}\) such that it is sufficient to unwind the closed-loop state-space system up to \(\overline{k}\) in order to ensure that \(\phi _{ safety }\) holds.
Proof
A stable control system is known to have converging dynamics. Assume the closed-loop matrix eigenvalues are not repeated (which is sensible to do, since we select them). The distance of the trajectory from the reference point (origin) decreases over time within subspaces related to real-valued eigenvalues; however, this is not the case in general when dealing with complex eigenvalues. Consider the closed-loop matrix that updates the states in every discrete time step, and select the eigenvalue \(\vartheta \) with the smallest (non-trivial) imaginary value. Between every pair of consecutive time steps \(k\,T_s\) and \((k+1)\,T_s\), the dynamics projected on the corresponding eigenspace rotate \(\vartheta T_s\) radians. Thus, taking \(\overline{k}\) as the ceiling of \(\frac{2\pi }{\vartheta T_s}\), after \(k{\ge }\overline{k}\) steps we have completed a full rotation, which results in a point closer to the origin. The synthesized \(\overline{k}\) is the completeness threshold. \(\square \)
Next, we describe the different phases in Fig. 2 (blocks 1 to 4) in detail.
-
1.
The inductive synthesis phase (synthesize) uses BMC to compute a candidate solution K that satisfies both the stability criteria (Sect. 3.3) and the safety specification (Sect. 3.4). To synthesize a controller that satisfies the stability criteria, we require that a computed polynomial satisfies Jury’s criterion [11]. The details of this calculation can be found in the Appendix. Regarding the second requirement, we synthesize a safe controller by unfolding the transition system k steps and by picking a controller K and a single initial state, such that the states at each step do not violate the safety criteria. That is, we ask the bounded model checker if there exists a K that is safe for at least one \(x_0\) in our set of all possible initial states. This is sound if the current k is greater than the completeness threshold. We also assume some precision \(\langle I_p,F_p\rangle \) for the plant and a sampling rate. The checks that these assumptions hold are performed by subsequent verify stages.
-
2.
The first verify stage, safety, checks that the candidate solution K, which we synthesized to be safe for at least one initial state, is safe for all possible initial states, i.e., does not reach an unsafe state within k steps where we assume k to be under the completeness threshold. After unfolding the transition system corresponding to the previously synthesized controller k steps, we check that the safety specification holds for any initial state. This is shown in Algorithm 1.
-
3.
The second verify stage, precision, restores soundness with respect to the plant’s precision by using interval arithmetic [22] to validate the operations performed by the previous stage.
-
4.
The third verify stage, complete, checks that the current k is large enough to ensure safety for any \(k'\,{>}\,k\). Here, we compute the completeness threshold \(\overline{k}\) for the current candidate controller K and check that \(k\,{\ge }\,\overline{k}\). This is done according to the argument given above and illustrated in Fig. 3.
Checking that the safety specification holds for any initial state can be computationally expensive if the bounds on the allowed initial states are large.
Theorem 2
If a controller is safe for each of the corner cases of our hypercube of allowed initial states, it is safe for any initial state in the hypercube.
Thus we only need to check \(2^n\) initial states, where n is the dimension of the state space (number of continuous variables).
Proof
Consider the set of initial states, \(X_0\), which we assume to be convex since it is a hypercube. Name \(v_i\) its vertexes, where \(i=1,\ldots , 2^n\). Thus any point \(x \in X_0\) can be expressed by convexity as \(x = \sum _{i=1}^{2^n} \alpha _i v_i\), where \(\sum _{i=1}^{2^n} \alpha _i =1\). Then if \(x_0=x\), we obtain
$$\begin{aligned} x_k&= (A_d - B_d K)^k x = (A_d - B_d K)^k \sum _{i=1}^{2^n} \alpha _i v_i = \sum _{i=1}^{2^n} \alpha _i (A_d - B_d K)^k v_i = \sum _{i=1}^{2^n} \alpha _i x_k^i, \end{aligned}$$
where \(x_k^i\) denotes the trajectories obtained from the single vertex \(v_i\). We conclude that any k-step trajectory is encompassed, within a convex set, by those generated from the vertices. \(\square \)
Illustrative Example. We illustrate our approach with an example, extracted from [13]. Since we have not learned any information about the system yet, we pick an arbitrary candidate solution (we always choose \(K=[0 \ 0 \ 0]^T\) in our experiments to simplify reproduction), and a precision of \(I_p=13\), \(F_p=3\). In the first verify stage, the safety check finds the counterexample \( x_0 = [-0.5 \ 0.5 \ 0.5] \). After adding the new counterexample to its sets of inputs, synthesize finds the candidate solution \(K=[0\,0 \,0.00048828125]^T\), which prompts the safety verifier to return \(x_0=[-0.5\,-0.5\,-0.5]\) as the new counterexample.
In the subsequent iteration, the synthesizer is unable to find further suitable candidates and it returns UNSAT, meaning that the current precision is insufficient. Consequently, we increase the precision the plant is modelled with to \(I_p=17\), \(F_p=7\). We increase the precision by 8 bits each step in order to be compliant with the CBMC type API. Since the previous counterexamples were obtained at lower precision, we remove them from the set of counterexamples. Back in the synthesize phase, we re-start the process with a candidate solution with all coefficients 0. Next, the safety verification stage provides the first counterexample at higher precision, \(x_0=[-0.5 \ 0.5 \ 0.5]\) and synthesize finds \(K=[0 \ 0.01171875 \ 0.015625]^T\) as a candidate that eliminates this counterexample. However, this candidate triggers the counterexample \(x_0=[0.5\ -0.5\ -0.5]\) found again by the safety verification stage. In the next iteration, we get the candidate \(K=[0 \ 0 \ -0.015625]\), followed by the counterexample \(x_0 = [0.5 \ 0.5 \ 0.5]\). Finally, synthesize finds the candidate \(K=[0.01171875 \ -0.013671875 \ -0.013671875]^T\), which is validated as a final solution by all verification stages.
4.4 Abstraction-Based CEGIS
The naïve approach described in Sect. 4.3 synthesizes a controller for an individual initial state and input with a bounded time horizon and, subsequently, it generalizes it to all reachable states, inputs, and time horizons during the verification phase. Essentially, this approach relies on the symbolic simulation over a bounded time horizon of individual initial states and inputs that form part of an uncountable space and tries to generalize it for an infinite space over an infinite time horizon.
Conversely, in this section, we find a controller for a continuous initial set of states and set of inputs, over an abstraction of the continuous dynamics [7] that conforms to witness proofs at specific times. Moreover, this approach uses abstraction refinement enabling us to always start with a very simple description regardless of the complexity of the overall dynamics, and only expand to more complex models when a solution cannot be found.
The CEGIS loop for this approach is illustrated in Fig. 4.
-
1.
We start by doing some preprocessing:
-
(a)
Compute the characteristic polynomial of the matrix \((A_d-B_dK)\) as \(P_a(z) = z^n+\sum _{i=1}^n{(a_i-k_i)z^{n-i}}\).
-
(b)
Calculate the noise set N from the quantizer resolutions and estimated round-off errors:
$$N=\left\{ \nu _1+\nu _2+ \nu _3 : \nu _1 \in \left[ -\frac{q_1}{2}\ \ \frac{q_1}{2}\right] \wedge \nu _2 \in \left[ -\frac{q_2}{2}\ \ \frac{q_2}{2}\right] \wedge \nu _3 \in \left[ -q_3\ \ q_3\right] \right\} \nonumber $$
where \(q_1\) is the error introduced by the truncation in the ADC, \(q_2\) is the error introduced by the DAC and \(q_3\) is the maximum truncation and rounding error in \(u_k=-K \cdot \mathcal {F}_{\langle I_c,F_c \rangle }(x_k)\) as discussed in Sect. 3.5. More details on how to model quantization as noise are given in Appendix B.2.
-
(c)
Calculate a set of initial bounds on K, \(\phi _{ init }^{K}\), based on the input constraints
$$(\phi _{ init } \wedge \phi _{ input } \wedge u_k=-K x_k) \Rightarrow \phi _{ init }^{K}$$
Note that these bounds will be used by the synthesize phase to reduce the size of the solution space.
-
2.
In the synthesize phase, we synthesize a candidate controller \(K \in \mathbb {R}\langle I_c,F_c\rangle ^n\) that satisfies \(\phi _{ stability } \wedge \phi _{ safety } \wedge \phi _{ init }^{K}\) by invoking a SAT solver. If there is no candidate solution we return UNSAT and exit the loop.
-
3.
Once we have a candidate solution, we perform a safety verification of the progression of the system from \(\phi _{ init }\) over time, \(x_{k} \models \phi _{ safety }\). In order to compute the progression of point \(x_0\) at iteration k, we accelerate the dynamics of the closed-loop system and obtain:
$$\begin{aligned} x=&(A_d-B_dK)^kx_0 +\sum _{i=0}^{k-1} (A_d-B_dK)^i B_{n}(\nu _1+\nu _2+\nu _3) : B_n= [1 \cdots 1]^T \end{aligned}$$
(6)
As this still requires us to verify the system for every k up to infinity, we use abstract acceleration again to obtain the reach-tube, i.e., the set of all reachable states at all times given an initial set \(\phi _{ init }\):
$$\begin{aligned} \hat{X}^\# =\mathcal {A} X_0 + \mathcal {B}_{n} N, \quad X_0 =\left\{ x : x \,\models \, \phi _{ init } \right\} , \end{aligned}$$
(7)
where \(\mathcal {A}=\bigcup _{k=1}^\infty (A_d-B_dK)^k, \mathcal {B}_{n}=\bigcup _{k=1}^\infty \sum _{i=0}^k(A_d-B_dK)^iB_{n}\) are abstract matrices for the closed-loop system [7], whereas the set N is non-deterministically chosen.
We next evaluate
. If the verification holds we have a solution, and exit the loop. Otherwise, we find a counterexample iteration k and corresponding initial point \(x_0\) for which the property does not hold, which we use to locally refine the abstraction. When the abstraction cannot be further refined, we provide them to the abstract phase.
-
4.
If we reach the abstract phase, it means that the candidate solution is not valid, in which case we must refine the abstraction used by the synthesizer.
-
(a)
Find the constraints that invalidate the property as a set of counterexamples for the eigenvalues, which we define as \(\phi _\Lambda \). This is a constraint in the spectrum i.e., transfer function) of the closed loop dynamics.
-
(b)
We use \(\phi _\Lambda \) to further constrain the characteristic polynomial \(z^n+\sum _{i=1}^n(a_i-k_i)z^{n-i}=\prod _{i=1}^n (z-\lambda _i) : |\lambda _i|<1 \wedge \lambda _i \models \phi _{\Lambda }\). These constraints correspond to specific iterations for which the system may be unsafe.
-
(c)
Pass the refined abstraction \(\phi (K)\) with the new constraints and the list of iterations k to the synthesize phase.
Illustrative Example. Let us consider the following example with discretized dynamics
$$A_d = \left[ \begin{array}{ccc}2.6207&{}-1.1793&{}0.65705\\ 2&{}0&{}0\\ 0&{}0.5&{}0\end{array}\right] , \quad B_d = \left[ \begin{array}{c}8\\ 0\\ 0\end{array}\right] $$
Using the initial state bounds \(\underline{x_{0}}=-0.9\) and \(\overline{x_{0}}=0.9\), the input bounds \(\underline{u}=-10\) and \(\overline{u}=10\), and safety specifications \(\underline{x_{i}}=-0.92\) and \(\overline{x_{i}}=0.92\), the synthesize phase in Fig. 4 generates an initial candidate controller \(K=[\begin{array}{ccc}0.24609375&-0.125&0.1484375\end{array}]\). This candidate is chosen for its closed-loop stable dynamics, but the verify phase finds it to be unsafe and returns a list of iterations with an initial state that fails the safety specification \((k,x_0) {\in } \{ (2, [\begin{array}{ccc}0.9&-0.9&0.9\end{array}]),(3, [\begin{array}{ccc}0.9&-0.9&-0.9\end{array}])\}\). This allows the abstract phase to create a new safety specification that considers these iterations for these initial states to constrain the solution space. This refinement allows synthesize to find a new controller \(K=[\begin{array}{ccc}0.23828125&-0.17578125&0.109375\end{array}]\), which this time passes the verification phase, resulting in a safe system.