• Keine Ergebnisse gefunden

Implementation issues

Im Dokument Explicit state space verification (Seite 55-59)

Search strategies

3.2 Implementation issues

Functionally, data structures can be divided into the following units (physi-cally, units can overlap in actual implementations):

• The actual system description in a form that enables an efficient re-trieval of actions enabled in a given state, as well as an efficient compu-tation of successor states; for reduced state space generation, additional requirements may arise;

• A stack for implementing the recursion in line 17; stacked information includes the current state and an iteration index for the loop starting in line 10.

38

3

5 1

2 4

Figure 3.2: The states of the depicted graph are labeled by their respective dfs numbers thus defining the evolution of a particular run of depth first search.

When search explores the back edge [4,1] from current state 4, the stack starting from 1 consists of 1,2,3,4—one of the two elementary cycles. For the second cycle—1,2,4,5— 4 has already left the stack before 5 is explored, so this cycle does never manifest itself through a stack portion. Nevertheless, one member of this cycle (state 1) can be recognized through the back edge [4,1].

• A search structure that implements the set S in a way that contain-ment queries can be handled efficiently and attached information (dfs, lowlink, connected edges, values of atomic propositions, ...) can be retrieved and updated;

• A component stack implementingT;

• The actual transition system graph, with traversal capabilities depend-ing on the verification problem.

In the design of a data structure for thesystem description, we are faced with a space/time tradeoff. For time efficiency, information required for en-abling checks or successor computations should be preprocessed such that it can be directly accessed. For space efficiency, we would re-compute that information every time we need it, out of a more compact system representa-tion. While, on one hand, explicit information may consume just the space that would have lead to successful completion of a search (as exhibited, for instance, in [M¨01] for arguing in favor of a highly implicit high level Petri net representation as opposed to explicit low level nets), too implicit informa-tion may lead to a prohibitively slow algorithm. Though space is the critical resource in general, data structures for system descriptions are generally no major contributors to space complexity. So, there issome room left here to trade space for time.

An efficient implementation of enabling checks and successor computa-tions should at least take advantage of the fact that accomputa-tions tend to be local.

Between a state and one of its successors, only few components are different, and for only few actions enabledness depends on those components. Which components are changed, and which actions depend on them, is usually obvi-ous from the system description: a guarded command changes the variables mentioned in its assignments, and its enabledness depends on the variables mentioned in the guard. A Petri net transitiontchanges places int∪t and its enabledness depends ont. Local actions in composed systems depend on and change only local states. Thus, the set of enabled actions can be com-puted incrementally by checking, after a successor computation, only those actions for enabledness that depend on changed variables. For monotonous enabling conditions, like in the case of Petri nets, the number of checks can be reduced even further: a previously enabled transition needs to be checked only if tokens have been removed from pre-places, and a previously disabled transition needs to be checked for enabledness only if tokens have been pro-duced on the pre-places. Information about actions to be re-checked after an occurrence of an(other) action can be explicitly recorded as part of the sys-tem description and is a case where the time gains are worth the (moderate) additional space requirement.

A brute force implementation of the searchstack, would in turn consume large amounts of space and time. The stack corresponds to a cycle free path in the transition system. Such a path can become extremely long during depth first search. Thus, at least the space consuming stack of current states should be stored only implicitly. In several implementations, the current state information on the recursion stack is realized as a reference (pointer) into the search structure from which the state can be restored.

If all actions are invertible, and the reverse of actions can be computed efficiently (for Petri nets, these assumptions are true), information about the current state can be completely reconstructed out of the involved action. The action that leads to the successor state is determined by the loop index (line 10), now the only information that needs to be kept on the stack. When backtracking from a subsequent call of Tarjan’s algorithm, the current state can be reconstructed by executing the reverse action at the current state used by the subroutine. Thus, only one single, global variable containing the current state is sufficient for depth first search. As an additional advantage, successor state computation and backtracking can be implemented as an

40 actual modification of the global current state variable, with no need to copy components that are left unchanged by the action. This means that the time complexity of enabledness checks, action occurrences, and backtracking from subsequent states does not depend on the number of components of the state vector, but only on the average number of components an action is directly related to. Due to locality, this yields a tremendous efficiency gain.

In general, it is convenient to assume that, for space efficiency reasons, the search structure forS overlaps with the actual implementation of the set S. That is, in addition to procedures to search and insert elements, we need a way to retrieve an actual element of S via a reference. A reference is a small piece of data (usually a pointer) from which a state (the assignment to all state variables, or marking on all places) can be reconstructed efficiently.

We want to use references on the stack (unless we have invertible actions), and in the explicit representation of edges in the transition system in order to avoid space consuming multiple representations of elements of S.

Older verification tools (e.g. EMC [CES86b]) store S as a linked list of assignment vectors, yielding an efficient insertion procedure, simple pointers as reference to elements, but a rather expensive search procedure. Search can be speeded up by putting a hash structure or a search tree on top of the list. Alternatively, the list can be replaced by a tree where each path in the tree corresponds to a state, searching corresponds to traversing the tree from top to down, inserting to adding a new branch, and references to leaf nodes from which the referenced state can be retrieved by traversing the tree from bottom to top. Fig. 3.3 depicts a search tree as used in our implementation.

If we need to access the search structure via references, our freedom to im-plement the search structure is limited (compared to a data structure where search and insert are the only operations to be implemented). In forthcom-ing chapters, we shall argue that all verification techniques we are goforthcom-ing to present, and most reduction techniques can be implemented without relying on references to stored states (they only need to investigate the respective current state). If, furthermore, the stack can be implemented without refer-ences, for instance due to having invertible actions, we get a lot of freedom to implement the search structure. For instance, we can transform a state into smaller representation yet identifying it uniquely, and store only the representation—even if it is hard or impossible to reproduce the actual state out of that representation. In Ch. 8, we are going to propose such a ”finger-print”transformation of states. In order to establish compatibility between

y

z z

x

y

z

0 1

0 0

17 2

Im Dokument Explicit state space verification (Seite 55-59)