From the early days of computing the verification of programs has been an important subject. Nowadays the subject is even more vital as computers are ubiquitous in our current way of life. Computers thrive in all kind of environments, and some of their applications are life critical. Indeed, more and more lives depend on the reliability of airborne systems, rail signaling applications, and medical device software.
Given the importance of the matter, many efforts have been done to ensure the quality of the software. On the organizational side, project management techniques have been devised for the software development process, e.g., the RUP (Rational Unified Process) [Kru80], the Waterfall Model [Roy70], the Spiral Model [Boe86], B-method [LSDS95], etc. Most recently, the so called agile methodologies, like SCRUM [TN86], are taking over the industry [SA08]. However, these software de-velopment frameworks can improve software quality only up to a certain point. In fact, they cannot offer complete guarantees for critical systems by themselves as their effectiveness is based only on empirical evidence [SA08].
These approaches share in common the fact that all of them require to describe what the system does without saying how to do it. That description is called the specification. Depending on the development process used, the specification can be informal (SCRUM), semi-formal (RUP), or formal (B-method). Getting the specifica-tion right is paramount for the software quality. On the one hand, the specificaspecifica-tion is used to check if the development team understood the requirements (are we building the right thing?). This is calledvalidation. On the other hand, it is used to check if the finished software does what it was meant to do (are we building the thing right?).
This is calledverification.
A very simple way to do verification is testing. In software testing, we use the specification to derive behaviors that we expect from the software. For each expected behavior we write atest. A test is a procedure that exercises the software (or a part of it), and tells if the observed behavior is correct or not (according to the specification).
Hence, a test can prove that there are errors in the software. However, proving the absence of errors is much more complicated. It implies to write a test for each possible behavior of the software. The number of behaviors of even simple software being
2 Chapter 1. Introduction extremely large means that testing is unfeasible for proving the absence of errors.
Nevertheless, some kinds of software cannot afford to contain any error since human lives depend on it. This need gave birth to a set of verification techniques that can guarantee the absence of errors in a given system: formal verification techniques.
Formal verification techniques, a.k.a. formal methods, can guarantee the absence of errors in a system. Among formal methods there are several variants ranging from theorem proving to model checking. These techniques aim to build a formal math-ematical proof of the program’s correctness. This requires of course that the speci-fication is formally described. It also requires that the program itself has a formally specified semantics. In these thesis we focus on the model checking variant of formal methods.
Model checking was invented in 1986 by Clarke et al. [CES86]. It attempts to build a proof of correctness by systematically exploring the behaviors of the program.
As testing, it also suffers from the extremely large number of possible behaviors of software. In model checking, the exploration of the behaviors is done by exploring the states of the system. The set of states is called the state space and it tends to be very large. In model checking this is known as thestate space explosion problem (SSE) [Val98]. Several approaches have been proposed to tackle theSSEproblem like abstraction, partial order reduction, symbolic model checking, etc.
Symbolic model checking is the approach we concentrate here. Symbolic model checking uses ad hoc data structures to encode the state space in a compact way. It also uses special operations to perform calculation on the data structures efficiently.
The class of data structure most favored by symbolic model checking are Decision Diagrams (DDs).
DDs are a data structure aimed at the representation of large sets of data. The data represented by a DD in model checking is usually the state space of a system.
The idea behind DD is to benefit from the redundancy found in these state spaces.
This redundancy appears because computer systems are generally well structured. A system can for example be composed of several subsystems with almost identical behavior. Decision Diagrams are conceived to take advantage of this redundancy.
For example, the state space of identical subsystems is stored in memory only once.
One can also take advantage of redundancy by caching operations. Indeed, several complex operations are repeated all the time and one can store their result for later reuse. The efficiency of this is amplified byDDsproperties such as canonicity, which enables efficient caching.
The problem withDDsis that they are very low level data structures. This means that the translation of new higher level languages to them becomes more and more difficult. We consider three axes to evaluate the advances in DDstheory: data types, operations, and optimizations.
The first class ofDecision Diagrams,BDDs[Bry86], supported only Booleans as data type. Since the early applications ofDDswere the verification of logical circuits this was not a problem. However, over time DDsstarted to be used to verify higher level
1.1. Motivations 3 formalisms,i.e., Petri nets. The initial application ofBDDstoPetri netswas limited to a special class ofPetri net easily translatable to a Boolean representation, namely safe Petri nets. Later came Multi-valued Decision Diagrams (MDDs) [KVBSV98], defined over an arbitrary domain. Nevertheless, they were only implemented over in-tegers. Later iterations overDecision Diagramscontinued to be based on integers as main data type,e.g.,DDDs[CEPA+02],SDDs[CTM05], IDDs[ST99], etc. Finally, ΣDDs [Hos11] introduce a breakthrough by representing sets of terms and user de-fined operations in a Decision Diagramstructure. However, the application of ΣDD in model checking was restricted to the rewriting of sets of terms in Algebraic Petri nets[Vau87]. Such application imposed some constraints on the rewrite rules and the way they were applied. For example, rewrite rules were applied using an innermost strategy. This poses a problem to their application in general model checking. In fact, the innermost rewriting strategy is not the best strategy to handle the rewriting of a whole system. Thus, to applyΣDDsto general model checking it is necessary to provide them with more flexibility regarding the rewriting strategy.
Decision Diagram Operations
Operations inDDsare used to describe the transition relation of the described system and the model checking algorithm. Since DDsrepresent sets of states, they support standard set operations,i.e., union, intersection, and difference. These operations are used for model checking,e.g.,computing the state space. They also need to support operations to transform the states they represent. This is the same as describing the transitions of the system. Finally, there are the model checking algorithms. These are usually described in pseudo code that uses theDDs operations. An example of such operation is the fixpoint, which is needed to build the state space using the set operations and the transitions.
BDDsrepresent Boolean functions (or sets of sequences of Boolean variables) and Boolean operations describe operations among them.MDDsintroduced their own op-erations to manipulate them. These opop-erations however lacked flexibility. Indeed, they cannot represent someDecision Diagrams-based optimizations. DDDs, which are a specialized version ofMDDs, propose to describe operations onDDsusing homomor-phisms. An homomorphism is a function that preserves some operation. In the case ofDecision Diagramsit preserves the union,i.e.,φ(a∪b)= φ(a)∪φ(b). Indeed, one can write homomorphisms elegantly in mathematical notation. They can also describe complex operations onDDs. However, homomorphisms have some drawbacks. First, translating homomorphisms to code is not always straightforward. Second, creating operations that respect the homomorphic property is a delicate affair, prone to errors.
Thus, in spite of their flexibility they are not easy to use for the non-expert user.
In the beginning of Decision Diagrams, the main optimization technique was the choice of the right variable ordering. Indeed, DDs can be interpreted as a set of
4 Chapter 1. Introduction sequences of variable assignments1. The order of these variables has a capital im-portance in the performance of the structure. Nonetheless, finding the right variable ordering is an NP-complete problem. Another optimization techniques have been de-veloped, for example hierarchy and saturation. OnlySDDsandΣDDsuse hierarchy.
Hierarchy means that the variables in theDDscan contain anotherDDs. This enables the usage of divide and conquer strategies, which maximize sharing and caching in the DD. Also, hierarchical systems are more easily translatable to suchDDs. Other well known optimization technique is saturation [CLS01]. Saturation consists of exploiting locality. The idea is that one can apply the model checking algorithm,e.g.,state space construction algorithm, to a part of the theDD. Indeed, as theDD-encoded state space grows larger more and more parts of it can be shared, thus decreasing its memory footprint. However, before attaining the inflection point, there is a peak in memory consumption. Saturation improves performance by attaining this peak locally, where it is small, and then having smaller peaks at a global scale. One can describe satura-tion using homomorphisms. However, such descripsatura-tions present the same problems that were explained for homomorphism in the previous subsection.