Lamport proposed in [LaSc84, Lamp80a] to reason about safety and liveness conditions instead of pre- and post-conditions of the Hoare calculus. Although we are also interested in the temporal behavior of the synchronous programs, we aim at using the interactive verification for the data intensive parts only that be dealt well with the pre-/post-condition approach. Hence, we still make use of pre- and post conditions as given in the original Hoare calculus.
2.8 Adapting Interactive Verification to Synchronous Languages
However, none of these approaches can be directly used for the verification of synchronous programs. For this reason, we have to define a specialized Hoare calculus or similar interactive verification techniques for the synchronous model of computation. However, this adaptation is not straightforward: The main problem of this is that the assignment rule of the classic Hoare calculus implicitly defines a sequential programming model which is not sufficient for synchronous languages. Instead, the synchronous model of computation divides the execution of a program into macro steps that in turn consist of a finite number of micro steps (like assignments). The micro steps of a macro step are executed within the same variable environment, while all updates to the variables’ values are synchronously performed at the level of macro steps. Due to complex control flow statements like pre-emption and parallel statements, these micro step actions of a macro step might be distributed over a large part of a program.
In [StCO06], a program transformation has been considered where parallel assignments are considered as an abstraction of sequential programs to save states for model checking. As we already start from a synchronous program, we have no need to determine which assignments should be clustered into one parallel assignment, since this is determined by the semantics of the synchronous programming language. However, a related problem is considered here: This work defines a program transformation to collect the actions of different threads into a tuple action so that the concurrency is only available in these synchronous tuple-assignments. Such tuple-assignments have already been considered by Martin and Tucker [MaTu89] who used these assignments to reason about the correctness of systolic algorithms. Indeed, they already introduced the tuple-assignment form that will be used in Chapter 3 to employ for synchronous programs for the approach. Since synchronous languages did not yet exist when [MaTu89] was published, they did not discuss program transformations into that normal form, and directly used such descriptions without discussing their origin.
2.9 Modular Verification
Since reactive systems are often used in safety-critical applications, their functional correctness is of essential importance. For this reason, simulation and formal verification are routine steps in their design flows, and in particular, model checking is often used for this purpose. However, due to the well-known state space explosion problem, a modular or compositional verification [Roev98, BoRo98] is desired where modules can be replaced by their already verified properties. Large reactive systems can only be verified by modular or compositional
32 2 Preliminary and Related Work
approaches despite the tremendous progress on model checking procedures we have seen in the past two decades. Another reason for modular verification is that modules are defined for being reused later on, and therefore the effort for formal verification amortizes when one can simply reuse also the already verified properties.
Recent work of Schneider and Brandt [Schn09, BrSc09] describes a method to compile single synchronous modules on their own to SGAs that can be later linked together. Modular compilation was not possible for (imperative) synchronous languages, and since modular compilation is now available, it is natural to also establish modular verification. Clearly, it has to follow the semantics of modules and module calls, and this is defined differently for synchronous languages: While functional languages like Lustre consider modules as functions without side effects and essentially assume that all modules are started in parallel to all other modules, languages like Esterel and Quartz allow module calls in arbitrary statements. In these languages, modules are declared with input and output parameters (variables) so that the body statement of the module is only allowed to read its input variables and to write to its output variables. If the module is later on called in a context module, the input parameters are replaced with expressions of the same type, output parameters are replaced with local or output variables of the calling module, and thus, the assignments of the called modules then become assignments of the calling module. The calling module may also make assignments to its local and output variables, so that the two behaviors are combined. Moreover, module calls can be delayed to an arbitrary point of time, and a running module may be aborted or suspended by the context of its calling module.
Also, the simulation of synchronous modules has to be finally aborted so that temporal logic specifications referring to infinite behaviors cannot be completely answered. The results presented in this work are not only useful for modular verification: in [ABKV03], the authors considered the problem to make specifications for the simulation of reactive systems, which is difficult since the simulation has to be aborted after some finite time, so that properties that refer to the infinite behavior of the system cannot be completely answered. The results can be also used for simulation in pre-emption contexts or to verify temporal logic specification with bounded model checking or runtime verification [MoGS12].
Another way to deal with this problem is the use of compositional or modular verification [ClLM89a, GrLo91, HaLR93, AAHM99, LaGr98, RBHH01], where one first verifies some properties for single modules without their later context, and then makes later on use of these properties when the entire system is verified. Clearly, compositional verification is not new; many different approaches have already been developed including the assume-guarantee, assumption-commitment or rely-guarantee styles of compositional reasoning (see [RBHH01]). Moreover, the distinction between open and closed systems leads to the notion of module checking [KuVa96, KuVW01, Gode03] where one considers properties that hold even if the environment later on restricts input traces to some subset.
Concerning related work on modular verification of Esterel programs, I found only one paper of Merceron [Merc96] as related work. In contrast to this work, her paper does not consider the translation of synchronous programs to transition systems, and only considers the application of existing preservation results to the modular verification, which do neither consider substitution of parameters, nor delayed starting points, nor abortion/suspension.
Other papers like [HaLR93] consider the decomposition of a global specification ϕ of a parallel composition M1k M2 to local specifications ϕ1 and ϕ2 such that M1|= ϕ1 and
2.9 Modular Verification 33
M2|= ϕ2 implies M1k M2|= ϕ. This is a very important problem that is however not related
to the here encountered problems: it is assumed that a specification ϕi of a module Mi has
already been verified, but now the module is called in a general context (not just parallel composition) where parameters are substituted by expressions, and where the module’s behavior is completed by assignments of the context. Thus, the problem is to determine preservation results for the verified specification ϕi of a module Mi and there is no need to
decompose ϕ to the ϕis.
In [CBKT13] a symbolic decomposition of a transition relation by a locality check using decision diagrams is presented. They work directly on the low level description of a transition relation, this work instead uses synchronous guarded actions as description.
Outline
In the following Chapter, the definition of a Hoare calculus for Quartz on the source-code level is discussed. It is shown that a definition of a Hoare-like rule for every statement is cumbersome and that a normal form that collects the behavior of a macro step at a single program part allows easily to define such a calculus. Unfortunately, the main result of this chapter will be the impossibility of translating every Quartz program to this normal form. Hence, an other approach is presented in Chapter 4 and extended by the following chapters.
Chapter 3
Interactive Verification of Synchronous Programs at
Source-Code Level
In this chapter, the definition of a Hoare calculus at source-code level of Quartz is discussed. Introducing a Hoare calculus seems to be an easy task at the first glance: the rules only need to be extended for the synchronous statements, and even concurrent execution was considered for Hoare rules in the past [OwGr76a, OwGr76b, ApOl97, RBHH01]. The SOS rules defining the semantics of Quartz are a good starting point for that. Firstly, the idea of defining such rules is sketched. However, it will be explained in Section 3.1 that this is not at all straightforward. The main problem presented in Section 3.1.1 is thereby the presence of statements for concurrency in a form that has not yet been considered for Hoare calculus.
Having identified these problems, an alternative approach consisting of a normal form for Quartz programs and Hoare rules for these programs is shown in Section 3.2. The usefulness of these method is discussed in Section 3.2.4 by verifying an parallel algorithm. The main result of this chapter is presented in Section 3.2.5 that proves that the translation to the normal form is not possible without adding additional variables to the programs in general. The reason therefore is that there are some combinations of statements that introduce problems similar to the goto statement in sequential programs [Dijk68, KoFu06]. Besides the general transformation, two transformations for restricted classes of synchronous programs are given in Section 3.2.6 where it is not necessary to introduce the additional variables. These transformations led to the approach presented in Chapter 4.