Automata | Comp. Sc. Engg.

A Pumping Lemma For Cfls

5 min read
A Pumping Lemma for CFLs: Consider any CFG G = (N, Σ,P,S). A Pumping Lemma for the language of this grammar, L(G), can be derived by noting that a “very long string” w ∈ L(G) requires a very long derivation sequence to derive it from S. Since we only have a finite number of non-terminals, some non-terminal must repeat in this derivation sequence, and furthermore, the second occurrence of the non-terminal must be a result of expanding the first occurrence (it must lie within the parse tree generated by the first occurrence). For example, consider the CFG S -> (S) |T| e T -> [T] |T T| e. Here is an example derivation: S => ( S ) => ((T)) => (( [T] )) => (( [ ] )) Occurrence-1 Occurrence-2 Occurrence-1 involves Derivation-1: T => [ T ] => [ ] Occurrence-2 involves Derivation-2: T => e Here, the second T arises because we took T and expanded it into [ T ] and then to [ ]. Now, the basic idea is that we can use Derivation-1 used in the first occurrence in place of Derivation-2, to obtain a longer string: S => (S) => ((T)) => (( [ T ] )) => (( [[ T ]] )) => (( [[ ]] )) ^ ^ Occurrence-1 Use Derivation-1 here In the same fashion, we can use Derivation-2 in place of Derivation-1 to obtain a shorter string, as well: S => ( S ) => ( ( T ) ) => ( ( ) ) ^ Use Derivation-2 here When all this happens, we can find a repeating non-terminal that can be pumped up or down. In our present example, it is clear that we can manifest (([i ]i)) for i ≥ 0 by either applying Derivation-2 directly, or by applying some number of Derivation-1s followed by Derivation-2. In order to conveniently capture the conditions mentioned so far, it is good to resort to parse trees. Consider a CFG with |V | non-terminals, and with the right-hand side of each rule containing at most b syntactic elements (terminals or non-terminals). Consider a b-ary tree built up to height |V | 1, as shown in Figure 13.7. The string yielded on the frontier of the tree w = uvxyz. If there are two such parse trees for w, pick the one that has the fewest number of nodes. Now, if we avoid having the same non-terminal used in any path from the root to a leaf, basically each path will “enjoy” a growth up to height at most |V | (recall that the leaves are terminals). The string w = uvxyz is, in this case, of length at most b|V |. This implies that if we force the string to be of length b|V | 1 (called p hereafter), a parse tree for this string will have some path that repeats a non-terminal. Call the higher occurrence V1 and the lower occurrence (contained within V1) V2. Pick the lowest two such repeating pair of non-terminals. Now, we have these facts:

Equivalence (Preorder Plus Symmetry)

4 min read
Equivalence (Preorder plus Symmetry): An equivalence relation is reflexive, symmetric, and transitive. Consider the BB relation for three basketball players A, B, and C. Now, consider a “specialization” of this relation obtained by leaving out certain edges: ≡BB = {A,A, A,B, B,A, B,B, C,C}. This relation is an equivalence relation, as can be easily verified. Note that ≡BB =≤BB ≤∩ −1 BB. In other words, this equivalence relation is obtained by taking the preorder ≤ BB and intersecting it with its inverse. The fact that BB ∩ −1 BB is an equivalence relation is not an accident. The following section demonstrates a general result in this regard. Intersecting a preorder and its inverse: Theorem 4.1. The relation obtained by intersecting a preorder r with its inverse r−1 is an equivalence relation. Proof: First we show that R∩R−1 is reflexive. Let R be a preorder over set S. Therefore, R is reflexive, i.e., it contains x, x pairs for every x ∈ S. From the definition of R−1, it also contains these pairs. Hence, the intersection contains these pairs. Therefore, R ∩ R−1 is reflexive. Next we show that R ∩ R−1 is symmetric. That is, to show that for every x, y ∈ S, x, y ∈ R ∩ R−1 implies y, x ∈ R ∩ R−1. If the antecedent, i.e., x, y ∈ R ∩ R−1 is false, the assertion is vacuously true. Consider when the antecedent is true for a certain x, y. These x and y must be such that x, y ∈ R and x, y ∈ R−1. The former implies that y, x ∈ R−1. The latter implies that y, x ∈ R. Hence, y, x ∈ R ∩ R−1. Hence, R ∩ R−1 is symmetric. Next we prove that R∩R−1 is transitive. Since R is a preorder, it is transitive. We now argue that the inverse of any transitive relation is transitive. From the definition of transitivity, for every x, y, z ∈ S, from the antecedents x, y ∈ R and y, z ∈ R, the consequent x, z ∈ R follows. From these antecedents, we have that y, x ∈ R−1 and z, y ∈ R−1 respectively. From the above conclusion x, z ∈ R, we can infer that z, x ∈ R−1. Hence, R−1 is transitive and so is the conjunction of R and R−1. Identity relation: Given a set S, the identity relation R over S is {x, x | x ∈ S}. An identity relation is one extreme (special case) of an equivalence relation. This relation is commonly denoted by the equality symbol, =, and relates equals with equals. Please note the contrast with Theorem 4.1. Universal relation: The universal relation R over S is S × S, and represents the other extreme of relating everything to everything else. This is often an uninteresting binary relation.2 Equivalence class: An equivalence relation R over S partitions elements(R) = domain(R)∪ codomain(R) into equivalence classes. Intuitively, the equivalence classes Ei are those subsets of elements(R) such that every pair of elements in Ei is related by R, and Eis are the maximal such subsets. More formally, given an equivalence relation R, there are two cases:

A Pumping Lemma For Cfls

5 min read
A Pumping Lemma for CFLs: Consider any CFG G = (N, Σ,P,S). A Pumping Lemma for the language of this grammar, L(G), can be derived by noting that a “very long string” w ∈ L(G) requires a very long derivation sequence to derive it from S. Since we only have a finite number of non-terminals, some non-terminal must repeat in this derivation sequence, and furthermore, the second occurrence of the non-terminal must be a result of expanding the first occurrence (it must lie within the parse tree generated by the first occurrence). For example, consider the CFG S -> (S) |T| e T -> [T] |T T| e. Here is an example derivation: S => ( S ) => ((T)) => (( [T] )) => (( [ ] )) Occurrence-1 Occurrence-2 Occurrence-1 involves Derivation-1: T => [ T ] => [ ] Occurrence-2 involves Derivation-2: T => e Here, the second T arises because we took T and expanded it into [ T ] and then to [ ]. Now, the basic idea is that we can use Derivation-1 used in the first occurrence in place of Derivation-2, to obtain a longer string: S => (S) => ((T)) => (( [ T ] )) => (( [[ T ]] )) => (( [[ ]] )) ^ ^ Occurrence-1 Use Derivation-1 here In the same fashion, we can use Derivation-2 in place of Derivation-1 to obtain a shorter string, as well: S => ( S ) => ( ( T ) ) => ( ( ) ) ^ Use Derivation-2 here When all this happens, we can find a repeating non-terminal that can be pumped up or down. In our present example, it is clear that we can manifest (([i ]i)) for i ≥ 0 by either applying Derivation-2 directly, or by applying some number of Derivation-1s followed by Derivation-2. In order to conveniently capture the conditions mentioned so far, it is good to resort to parse trees. Consider a CFG with |V | non-terminals, and with the right-hand side of each rule containing at most b syntactic elements (terminals or non-terminals). Consider a b-ary tree built up to height |V | 1, as shown in Figure 13.7. The string yielded on the frontier of the tree w = uvxyz. If there are two such parse trees for w, pick the one that has the fewest number of nodes. Now, if we avoid having the same non-terminal used in any path from the root to a leaf, basically each path will “enjoy” a growth up to height at most |V | (recall that the leaves are terminals). The string w = uvxyz is, in this case, of length at most b|V |. This implies that if we force the string to be of length b|V | 1 (called p hereafter), a parse tree for this string will have some path that repeats a non-terminal. Call the higher occurrence V1 and the lower occurrence (contained within V1) V2. Pick the lowest two such repeating pair of non-terminals. Now, we have these facts:

Right- And Left-linear Cfgs

3 min read
Right- and Left-Linear CFGs: A right-linear CFG is one where every production rule has exactly one non-terminal and that it also appears rightmost. For example, the following grammar is right-linear: S -> 0 A | 1 B | e A -> 1 C | 0 B -> 0 C | 1 C -> 1 | 0 C. Recall that S -> 0 A | 1 B | e is actually three different production rules S -> 0 A, S -> 1 B, and S -> e, where each rule is right-linear. This grammar can easily be represented by the following NFA obtained almost directly from the grammar: IS - 0 -> A IS - 1 -> B IS - e -> F1 A - 1 -> C A - 0 -> F2 B - 0 -> C B - 1 -> F3 C - 0 -> C C - 1 -> F4. A left-linear grammar is defined similar to a right-linear one. An example is as follows: S -> A 0 | B 1 | e A -> C 1 | 0 B -> C 1 | 1 C -> 1 | C 0. A purely left-linear or a purely right-linear CFG denotes a regular language. However, the converse is not true; that is, if a language is regular, it does not mean that it has to be generated by a purely leftlinear or purely right-linear CFG. Even non-linear CFGs are perfectly capable of sometimes generating regular sets, as in S -> T T | e T -> 0 T | 0. It also must be borne in mind that we cannot “mix up” left- and rightlinear productions and expect to obtain a regular language. Consider the productions S -> 0 T | e T -> S 1. In this grammar, the productions are linear - left or right. However, since we use left- and right-linear rules, the net effect is as if we defined the grammar S -> 0 S 1 | e which generates the non-regular context-free language {0n1n | n ≥ 0}. Conversion of purely left-linear grammars to NFA: Converting a left-linear grammar to an NFA is less straightforward. We first reverse the language it represents by reversing the grammar. Grammar reversal is approached as follows: given a production rule S → R1R2 . . .Rn, we obtain a production rule for the reverse of the language represented by S by reversing the production rule to: Sr → RrnRrn−1 . . .Rr1 . Applying this to the grammar at hand, we obtain Sr -> 0 Ar | 1 Br | e Ar -> 1 Cr | 0 Br -> 1 Cr | 1 Cr -> 1 | 0 Cr. Once an NFA for this right-linear grammar is built, it can be reversed to obtain the desired NFA.

Ultimate Periodicity And Dfas

3 min read
Ultimate Periodicity and DFAs: Ultimate periodicity is a property that captures a central property of regular sets (recall the definition of ultimate periodicity given in Definition 5.1, page 76). Theorem . If L is a regular language over an alphabet Σ, then the set Len = {length(w) | w ∈ L} is ultimately periodic. Note: The converse is not true. For example, the language {0n1n | n ≥ 0} has strings whose lengths are ultimately periodic, and yet this language is not regular. A good way to see that Theorem 10.3 is true is as follows. Given any DFA D over some alphabet Σ, consider the NFA N obtained from D by first replacing every transition labeled by a symbol in Σ \ {a} by a. In other words, we are applying a homomorphism that replaces every symbol of the DFA by a. Hence, the resulting machine is bound to be an NFA, and the lengths of strings in its language will be the same as those of the strings in the language of the original DFA (in other words, what we have described is a length-preserving homomorphism). Now, if we convert this NFA to a DFA, we will get a machine that starts out in a start state and proceeds for some number (≥ 0) of steps before it “coils” into itself. In other words, it attains a lasso shape. It cannot have any other shape than the ‘coil’ (why?). This coiled DFA shows that the length of strings in the language of any DFA is ultimately periodic with the period defined by the size of the coil. We now take an extended example to illustrate these ideas. Consider the DFA built over Σ = {a, b, c, d, f} using the following command pipeline: echo ’(ad)* ((abc)((acf)* (da)*)d)’ | retofm | fmdeterm | fmmin | grail2ps.perl - | gv -

Binary Relation Basics

5 min read
Binary Relation Basics: A binary relation R on S is a subset of S × S. It is a relation that can be expressed by a 2-place predicate. Examples: (i) x loves y, (ii) x > y. Set S is the domain of the relation. Theoretically, it is possible that the domain S is empty (in which case R will be empty). In all instances that we consider, the domain S will be non-empty. However, it is quite possible that S is non-empty and R is empty. We now proceed to examine various types of binary relations. In all these definitions, we assume that the binary relation R in question is on S, i.e., a subset of S×S. For a relation R, two standard prefixes are employed: irr- and non-. Their usages will be clarified in the sequel. Relations can be depicted as graphs. Here are conventions attributed to Andrew Hodges in [63]. The domain is represented by a closed curve (e.g., circle, square, etc) and the individuals in the domain by dots labeled, perhaps, a, b, c, and so on. The fact that a, b ∈ R will be depicted by drawing a single arrow (or equivalently one-way arrow) from dot a to dot b. We represent the fact that both a, b ∈ R and b, a ∈ R by drawing a double arrow between a and b. We represent the fact that a, a ∈ R by drawing a double arrow from a back to itself (this is called a loop). We shall present examples of these drawings in the sequel. We shall use the following examples. Let S = {1, 2, 3}, R1 = {x, x | x ∈ S}, R2 = S × S, and R3 = {1, 1, 2, 2, 3, 3, 1, 2, 2, 1, 2, 3, 3, 2}. All these (and three more) relations are depicted in Figure 4.1. Reflexive, and Related Notions: R is reflexive, if for all x ∈ S, x, x ∈ R. Equivalently, In R’s graph, there is no dot without a loop. Informally, “every element is related to itself.” A relation R is irreflexive if there are no reflexive elements; i.e., for no x ∈ S is it the case that x, x ∈ R. Equivalently, In R’s graph, no dot has a loop.

Introduction To Push-down Automata

5 min read
Push-down Automata: A push-down automaton (PDA) is a structure (Q,Σ, Γ, δ, q0, z0, F) where Q is a finite set of states, Σ is the input alphabet, Γ is the stack alphabet (that usually includes the input alphabet Σ), q0 is the initial state, F ⊆ Q is the set of accepting states, z0 the initial stack symbol, and δ : Q × (Σ ∪ {ε}) × Γ → 2Q×Γ∗. In each move, a PDA can optionally read an input symbol. However, in each move, it must read the top of the stack (later, we will see that this assumption comes in handy when we have to convert a PDA to a CFG). Since we will always talk about an NPDA by default, the δ function returns a set of nondeterministic options. Each option is a next-state to go to, and a stack string to push on the stack, with the first symbol of the string appearing on top of the stack after the push is over. For example, if q1, ba ∈ δ(q0, x, a), the move can occur when x can be read from the input and the stack top is a. In this case, the PDA moves over x (it cannot read x again). Also, an a is removed from the stack. However, as a result of the move, an a is promptly pushed back on the stack, and is followed by a push of b, with the machine going to state q1. The transition function δ of a PDA may be either deterministic or nondeterministic. DPDA versus NPDA: A push-down automaton can be deterministic or nondeterministic. DPDA and NPDA are not equivalent in power; the latter are strictly more powerful than the former. Also, notice that unlike with a DFA, a deterministic PDA can move on ε. Therefore, the exact specification of what deterministic means becomes complicated. We summarize the definition from [60]. A PDA is deterministic if and only if the following conditions are met: In this book, I will refrain from giving a technically precise definition of DPDAs. It really becomes far more involved than we wish to emphasize in this chapter, at least. For instance, with a DPDA, it becomes necessary to know when the string ends, thus requiring a right end-marker .

Stabilization At A Fixed-point

5 min read
Stabilization at a Fixed-Point: In every finite-state system modeled using a finite-state Boolean transition system, the least fixed-point is always reached in a finite number of steps. Let us try to argue this fact first using only a simple observation. The observation is that all the Boolean expressions generated during the course of fixed-point computation are over the same set of variables. Since there are exactly 22N Boolean functions over N Boolean variables (see Illustration 4.5.2), eventually two of the approximants in the fixed-point computation process will have to be the same Boolean function. However, this argument does not address whether it is possible to have “evasive” or “oscillatory” approximants Pi, Pi 1, . . . , Pj such that i = j and Pj = Pi. If this were possible, it would be possible to cycle through Pi, . . . , Pj without ever stabilizing on a fixed-point. Fortunately, this is not possible! Each approximant Pi 1 is more defined than the previous approximant Pi, in the sense defined by the implication lattice defined in Illustration 4.5.3. With this requirement, the number of these ascending approximants is finite, and one of these would be the least fixed-point. See Andersson’s paper [7] for additional examples of forward reachability. The book by Clarke et.al. [20] gives further theoretical insights. An example with multiple fixed-points: Consider the state transition system in Figure 11.6 with initial state s0 (called MultiFP). The set of its reachable states is simply {s0} (and is characterized by the formula a ∧ b), as there is no reachable node from s0. Now, a fixed-point iteration beginning with the initial approximant for the reachable states set to P0 = false will converge to the fixedpoint a ∧ b. What are the other fixed-points one can attain in this system? Here they are: Hence, in this example, there are three distinct fixed-points for the recursive formula defining reachable states. Of these, the least fixedpoint is a∧b, and truly characterizes the set of reachable states; a∨b is the intermediate fixed-point, and 1 is the greatest fixed-point. It is clear that (a ∧ b) ⇒ (a ∨ b) and (a ∨ b) ⇒ 1, which justifies these fixed-point orderings. Figure 11.6 also describes the BED commands to produce this intermediate fixed-point.

Dealing With Recursion

6 min read
Introduction: Recursion is a topic central to computer science. Lambda calculus offers us a very elegant (and fundamental) way to model and study recursion. In a book on computability and automata, such a study also serves another purpose; to concretely demonstrate that Lambda calculus provides a universal mechanism to model computations, similar to the role played by Turing machines. While this chapter can be skimmed, or even skipped, we have taken sufficient pains to make this chapter as “friendly” and intuitive as possible, permitting it to be covered without spending too much time. Covering this chapter will permit fixed-point theory to be used as a conceptual “glue” in covering much important material, including studying context-free grammars, state-space reachability methods, etc. Recursive Definitions: Let’s get back to the discussion of function ‘Fred’ introduced in Chapter 2, Section 2.6. Now consider a recursively defined function, also called ‘Fred.’ We fear that this will make it impossible to ‘de-Fred:’ function Fred x = if (x=0) then 0 else x Fred(x-1) It is quite tempting to arrive at the following de-Freded form: function(x) = if (x=0) then 0 else x self(x-1) However, it would really be nice if we can avoid using such ad hoc conventions, and stay within the confines of the Lambda notation as introduced earlier. We shall soon demonstrate how to achieve this; it is, however, instructive to examine one more recursive definition, now involving a function called Bob: function Bob(x) = Bob(x 1). One would take very little time to conclude that this recursive definition is “plain nonsense,” from the point of view of recursive programming. For example, a function call Bob(3) would never terminate. However, unless we can pin down exactly why the above definition is “nonsense,” we will have a very ad hoc and non-automatable method for detecting nonsensical recursive definitions - relying on human visual inspection alone. Certainly we do not expect humans to be poring over millions of lines of code manually detecting nonsensical recursion. Here, then, is how we will proceed to “de-Fred” recursive definitions (i.e., create irredundant names for them):

The Y Operator

3 min read
= (λx.if (x = 0) then 0 else if (x = 1) then x 0 else x ⊥) = (λx.if (x = 0) then 0 else if (x = 1) then 1 else ⊥) which (calling it f2) is yet another function that defined for one more input value. In summary, substituting f0 for f, one gets f1, and substituting f1, one gets f2. Continuing this way, each fi turns into a function fi 1 that is defined for one more input value. While none of these functions satisfies the equation, in the limit of these functions is a total function that satisfies the equation, and hence is a fixed-point (compared with earlier examples, such as the cos function, which seemed to “stabilize” to a fixed-point in a few steps on a finite-precision calculator; in case of the fi series, we achieve the fixed-point only in the limit). This limit element happens to be the least fixed-point (in a sense precisely defined in the next section), and is written μx.(if (x = 0) then 0 else x f(x − 1)). Let this least fixed-point function be called h. It is easy to see that h is the following function: h(n) = Σn i=0 i. It is reassuring to see that the least fixed-point is indeed the function that computes the same “answers” as function Fred would compute if compiled and run on a machine. It turns out that in recursive programming, the “desired solution” is always the least fixed-point, while in other contexts (e.g., in reachability analysis of finite-state machines demonstrated in Chapter 9), that need not be true. The ‘solution’ point of view for recursion also explains recursive definitions of the form function Bob(x) = Bob(x 1). The only solution for function Bob is the everywhere undefined function λx. ⊥. To see this more vividly, one can try to de-Bob the recursion to get Bob = Y (lambda y . lambda x . y(x 1)). Suppose H = (lambda y . lambda x . y(x 1)). Now, supplying a value such as 5 to Bob, and continuing as with function Fred, one obtains the following reduction sequence: Bob 5 = (Y H) 5 = H (Y H) 5 = (lambda y . lambda x . y(x 1)) (Y H) 5 = (lambda x . (Y H)(x 1)) 5 = (Y H)(5 1) = (Y H) 6 = ... = (Y H) 7 = ... = (non-convergent). In other words, Bob turns out to be the totally undefined function, or “bottom function.”

The Least Fixed-point

4 min read
The least fixed-point: In the above example, we obtained a fixed-point h which we asserted to be the “least” in a sense that will now be made clear. In general, given a recursive program, if there are multiple fixed-points, The desired meaning of recursive programs corresponds to the least fixed-point, and The fixed-point finding combinator Y is guaranteed to compute the least fixed-point [114]. To better understand these assertions, consider the following four definitions of functions of type Z × Z → Z, where Z is the integers (this example comes from [78]): f1 = λ(x, y) . if x = y then y 1 else x 1 f2 = λ(x, y) . if x ≥ y then x 1 else y − 1 f3 = λ(x, y) . if x ≥ y and x− y is even then x 1 else ⊥ Now consider the recursive definition: F(x, y) = if x = y then y 1 else F(x, F(x − 1, y 1)). We can substitute f1, f2, or f3 in place of F and get a true equation! Exercise 6.8 asks you to demonstrate this. However, of these functions, f3 is the least defined function in the sense that whenever f3(x) is defined, fi(x) is defined for i = 1, 2, but not vice versa, and there is no other function (say f4) that is less defined than f3 and also serves as a solution to F. To visualize concepts such as “less defined,” imagine as if we were plotting the graphs of these functions. Now, when a function is undefined for an x value, we introduce a “gap” in the graph. In this sense, the graph of the least fixed-point function is the “gappiest” of all; it is a solution, and is the most undefined of all solutions – it has the most number of “gaps.” These notions can be captured precisely in terms of least upper-bounds of pointed complete partial orders [107]. In our example, it can be shown that f3 is the least fixed-point for the recursion. Fixed-points in Automata Theory: We will have many occasions to appeal to the least fixed-point idea in this book. Here are some examples: It is also worth noting that while least fixed-points are most often of interest, in many domains such as temporal logic, the greatest fixedpoints are also of interest. The functional (higher order function) H from Section 6.1.1, namely H = (λy.λx.if (x = 0) then 0 else x y(x − 1)) has an interesting property: it works as a “bottom refiner!” In other words, when fed the “everywhere undefined function” f0 (called the “bottom function”), it returns the next better approximation of the least fixed-point h in the form of f1. When fed f1, it returns the next better approximation f2, and so on. It may sound strange that the meaning of recursive programs is determined starting from the most uninteresting of functions, namely the ‘bottom’ or ⊥ function. However, this is the most natural approach to be taking, because

The Automaton/logic Connection

4 min read
Introduction: : Throughout the entire 150 years (or so) history of computer science, one can see an attempt on part of researchers to understand reasoning as well as computation in a unified setting. This direction of thinking is best captured by Hilbert in one of his famous speeches made in the early 1900s in which he challenged the mathematical community with 23 open problems. Many of these problems are still open, and some were solved only decades after Hilbert’s speech. One of the conjectures of Hilbert was that the entire body of mathematics could perhaps be “formalized.” What this meant is basically that mathematicians had no more creative work to carry out; if they wanted to discover a new result in mathematics, all they had to do was to program a computer to systematically crank out all possible proofs, and check to see whether the theorem whose proof they are interested in appears in one of these proofs! In 1931, Kurt G¨odel dropped his ‘bomb-shell.3 He formally stated and proved the result, “Such a device as Hilbert proposed is impossible!” By this time, Turing, Church, and others demonstrated the true limits of computing through concrete computational devices such as Turing machines and the Lambda calculus. The rest “is history!” The Automaton/Logic Connection: Scientists now have a firm understanding of how computation and logic are inexorably linked together. The work in the mid 1960s, notably that of J.R. B¨uchi, furthered these connections by relating branches of mathematics known as Presburger arithmetic and branches of logic known as WS1S4 with deterministic finite automata. Work in the late 1970s, notably by Pnueli, resulted in the adoption of temporal logic as a formal logic to reason about concurrency. Temporal logic was popularized by Manna and Pnueli through several textbooks and papers. Work in the 1980s, notably by Emerson, Clarke, Kurshan, Sistla, Sifakis, Vardi, and Wolper established deep connections between temporal logic and automata on infinite words (in particular B¨uchi automata). Work in the late 1980s, notably by Bryant, brought back yet another thread of connection between logic and automata by the proposal of using binary decision diagrams, essentially minimized deterministic finite automata for the finite language of satisfying instances of a Boolean formula, as a data structure for Boolean functions. The symbolic model checking algorithm proposed by McMillan in the late 1980s hastened the adoption of BDDs in verification, thus providing means to tackle the correctness problem in computer science. Also, spanning several decades, several scientists, including McCarthy, Wos, Constable, Boyer, Moore, Gordon, and Rushby, led efforts on the development of mechanical theorem-proving tools that provide another means to tackle the correctness problem in computer science.

Reactive Computing Systems

5 min read
Introduction: Reactive computing systems are hardware/software ensembles that maintain an ongoing interaction with their environment, coordinating as well as facilitating these interactions. They are widely used in all walks of life—often in areas that directly affect life. Examples of reactive systems include device drivers that control the operation of computer peripherals such as disks and network cards, embedded control systems used in spacecraft or automobiles, cache coherency controllers that maintain memory consistency in multiprocessor machines, and even certain cardiac pacemakers that measure body functions (such as body electric fields and exercise/sleep patterns) to keep a defective heart beating properly. Model checking has already been employed in most of these areas, with its use imminent in critical areas such as medical systems. Clearly, knowing a little bit about the inner workings of a model checker can go a long way towards their proper usage. Why model checking? The design of most reactive systems is an involved as well as exacting task. Hundreds of engineers are involved in planning, analyzing, as well as building and testing the various hardware and software components that go into these systems. Despite all this exacting work, at least two vexing problems remain: Formal methods based on model checking are geared towards eliminating the above difficulties associated with late cycle debugging. While model checking is not a panacea, it has established a track record of finding many deep bugs missed by weeks or months of testing. Specifically,

First-order Logic (Fol) And Validity

3 min read
First-order Logic (FOL) and Validity: Below, we will introduce many notions of first-order logic intuitively, through examples. We refer the reader to one of many excellent books in first-order logic for details. One step called skolemization merits some explanation. Basically, skolemization finds a witness to model the existential variable. In general, from a formula of the form ∃X.P(X), we can infer P(c) where c is a constant in the domain. Likewise, from P(c), we can infer ∃X.P(X); in other words, for an unspecified constant c in the domain, ∃X.P(X) ⇔ P(c). We will use this equivalence in the following proofs. There is another use of skolemization illustrated by the following theorem (which we won’t have occasion to use): ∀X.∃Y.P(X, Y ) ⇔ P(X, f(X)). Here, f is an unspecified (but fixed) function. This equivalence is valid because of two reasons: A warm-up exercise: Suppose we are given the following proof challenge: Some patients like every doctor. No patient likes a quack. Therefore, prove that no doctor is a quack. It is best to approach problems such as this using predicates to model the various classes of individuals2 instead of employing ‘arbitrary constants’ such as p and d to denote patients, doctors, etc. Introduce predicate p to carve out a subset of people (P) to be patients, and similarly d for doctors. Let l (for “likes”) be a binary relation over P. Our proof will consist of instantiation of formulas, followed by Modus ponens, and finally proof by contradiction. A1: The statement, “Some patients like every doctor:” ∃x ∈ P : (p(x) ∧ ∀y : (d(y) ⇒ l(x, y))). A2: The statement, “No patient likes a quack:” ∀x, y ∈ P : (p(x) ∧ q(y)⇒ ¬l(x, y)). Proof goal: “No doctor is a quack.” ∀x ∈ P : (d(x) ⇒¬q(x)). Negate the proof goal: ∃x ∈ P : (d(x) ∧ q(x)). Skolemize negated proof goal: (x0 ∈ P ∧ d(x0) ∧ q(x0). Skolemize A1: c ∈ P ∧ (p(c) ∧ ∀y : (d(y) ⇒ l(c, y))) (we will suppress domain membership assertions such as c ∈ P from now on). Specialize: From A1, we specialize y to x0 to get: p(c) ∧ (d(x0) ⇒ l(c, x0)). But since d(x0) is true in the negated proof goal, we get: p(c) ∧ l(c, x0) (more irrelevant facts suppressed). Since q(x0) is true in the negated proof goal, we also get: p(c) ∧ l(c, x0) ∧ q(x0). Use A2 and specialize x to c and y to x0 to get ¬l(c, x0). Contradiction: Since we have l(c, x0) and ¬l(c, x0), we get a contradiction.

Greibach’s Theorem

4 min read
Greibach’s Theorem: There is a theorem analogous to Rice’s Theorem for PDAs. Known as Greibach’s Theorem, the high-level statement of the theorem (in terms of its practical usage) is as follows: It is impossible to algorithmically classify (using, of course, a Turing machine) context-free grammars on the basis of whether their languages are regular or not. The Computation History Method: As we mentioned , it is possible to “teach” LBAs (and NPDAs) to answer certain difficult questions about Turing machines. This idea is detailed in Section 17.3.2 through 17.3.4. We first recap basic facts about linear bounded automata (LBA) and present a decidability result about them (Section 17.3.1). Thereafter, we present three undecidability results based on the computation history method: (i) emptiness of LBA languages (Section 17.3.2), (ii) universality of the language of a CFG (Section 17.3.3), and (iii) Post’s correspondence problem (Section 17.3.4). In Chapter 18, Section 18.2.3, we emphasize the importance of the undecidability of Post’s correspondence problem (PCP) by presenting a classic proof due to Robert Floyd: we reduce PCP to the validity problem for first-order logic. This proof then establishes that the validity problem for first-order logic is undecidable. Decidability of LBA acceptance: LBAs are Turing machines that are allowed to access (read or write) only that region of the input tape where the input was originally presented. To enforce such a restriction, one may place two distinguished symbols, say and , around the original input string.1 With these conventions, it can easily be seen that instantaneous descriptions of an LBA that begin as q0w will change to the general form lqr, where |lr| = |w|. Therefore, there are a finite number, say N, of these IDs (see Exercise 17.1). A decider can simulate an LBA starting from ID q0w, and see if it accepts within this many IDs; if not, the LBA will not accept its input. Hence, LBA acceptance is decidable.

Temporal Logics

3 min read
Temporal Logics Kripke structures: Kripke structures are finite-state machines used to model concurrent systems. A Kripke structure is a four-tuple S, s0,R, L where S is a finite set of states, s0 is an initial state, R ⊆ S × S is a total relation known as the reachability relation, and L : S → 2P is a labeling function, with P being a set of atomic propositions. It is standard practice to require that R be total, as Kripke structure are used to model infinite computations (in modeling finite computations, terminal states are equipped with transitions to themselves, thus in effect making R total). The fact that we choose one initial state is a matter of convenience. Figure 22.1 (bottom) presents two Kripke structures. In the Kripke structure on the left, S = {s0, s1, s2}, s0 = s0, R is shown by the directed edges, and L by the subsets of {a, b} that label the states. In its behavior over time, this Kripke structure asserts a and b true in the first time step, b true in the second time step, and a in the third time step. In the fourth time step, it may assert either a or b. One of these sequences is shown in the middle – namely, choosing to assert a in the fourth time step, and b in the fifth. When a label is omitted (e.g., there is no b in state s2), we are effectively asserting ¬b. Therefore, the assertion in state s3 is ¬a∧¬b. The corresponding “waveforms2” (as if viewed on an oscilloscope) are shown at the top of this figure. From these discussions it is clear that we model the behavior of systems in terms of the truth values of a set of Boolean variables. This is the most common approach taken when modeling systems as finitestate machines.We therefore let P be the set of these Boolean variables. There are of course other ways to model systems. For instance, if one were to employ a set of Boolean variables B and a set of integer variables I to model a system, P would consist of B as well as propositions over integers, such as i > 2 or i = j 1. In any case, knowing the truth of the atomic propositions P, it is possible to calculate the truth of any Boolean proposition built over P. Each state s ∈ S is an equivalence class of time points, while R models how time advances. Whenever the system is at a state s ∈ S, a fixed set of Boolean propositions determined by L are true. Since S is finite, we can immediately see that the temporal behavior of systems modeled using Kripke structures recur over time, thus basically generating a regular language of truth values of the propositions in P. For example, Figure 22.1 shows how the truth of the Boolean proposition a ∨ b varies with time. Since either a or b is always true, a ∨ b is always true for the Kripke structure on the left; that is not the case for the Kripke structure on the right, as we can enter state s3 where both a and b are false.

Dfa For Presburger Arithmetic

4 min read
In Automaton/Logic Connection, Symbolic Techniques, we took our first step towards presenting another perspective of computation, namely one based on mathematical logic. Specifically, in Automaton/Logic Connection, Symbolic Techniques, we demonstrated that We connected these ideas to the real world by demonstrating how to encode the familiar game of tic-tac-toe using BDDs, as well as computing all possible draw configurations in one fell swoop. In Basic Notions in Logic including SAT, we examined the power of machines to decide the validity of first-order logic sentences, and proved that Turing machines cannot be programmed to algorithmically carry out this decision. In Complexity Theory and NP-Completeness, we showed that Turing machines can decide Boolean logic, but the apparent complexity is exponential (the NPC class). DFA for Presburger Arithmetic through Model Checking: Algorithms will again pursue the automaton/logic connection, but in the context of verifying reactive systems. This section illustrates another instance of automaton-logic connection. In contrast to the undecidability of full first-order logic, there is a fragment of first-order logic called Presburger arithmetic that is decidable. A widely used decision procedure for Presburger arithmetic consists of building a DFA for the satisfying instances of Presburger formulas. In this connection, an interesting contrast with Automaton/Logic Connection is the following. BDDs are essentially DFA whose languages are a finite set of finite strings,1 with each string specifying assignments to the Boolean variables of the BDD. In contrast, the languages of the Presburger DFA built in this chapter are finite or infinite sets of finite but unbounded strings. Each string encodes the assignments to the quantified individual variables of a Presburger formula. In this chapter we present the following results: − The DFA for the conjunction of two Presburger formulas f1 and f2 may be obtained by first obtaining the DFA d1 and d2 for the individual formulas and then performing a DFA product construction for intersection. Similar results are obtained for disjunction and negation. − Existential quantification can be modeled by hiding the quantified symbol from the interface of the corresponding automaton. The result may be an NFA that can then be determinized.

Model (Proctype) And Property (Never) Automata

3 min read
Model (proctype) and property (never) automata: A typical Promela model consists of multiple proctypes and one never automaton. The proctypes are concurrent processes whose atomic statements interleave in all possible ways. The collection of proctypes represents the “system” or “model.” Formally, one can say that the asynchronous or interleaving product of the model automata represents the set of all behaviors of interest. A never or property automaton observes the infinite runs of this interleaving product (all model runs). Conceptually, after every move of the model (a move of one of the constituent proctypes), one move of the property automaton is performed to check whether the model automaton move left the system in a good state. Formally, one can say that the synchronous product of the model and property automata are performed. In Figure 21.2, the property automaton represents the complement5 of the desired property—hence, the keyword never. One of the desired properties in our example is that progress is infinitely often set true. This means that infinitely often, every philosopher gets to eat. If there is even one philosopher who, after a finite amount of eatings, is never allowed to eat again, we certainly would like to know that. The never automaton accepts a run (or a computation) if the run visits one of the final states infinitely. The never automaton defined in Figure 21.2 can nondeterministically loop in its initial do/od loop. In fact, it can even stay in its initial state if progress is false. However, it may also choose to go to the final state labeled accept when progress is false. Here, it can continue to visit accept so long as progress is false. Hence, this never automaton accepts only an infinite sequence of progress being false—precisely when our desired liveness property is violated. When we ran the description in Figure 21.2 through the SPIN model checker (which is a model checker for descriptions written in Promela), it quickly found a liveness violation which indicates that, indeed, there exists at least one philosopher who will starve forever. SPIN produces a message sequence chart (MSC) corresponding to this error; this is shown in Figure 21.3. An MSC displays the “lifelines” (time lines of behaviors) of all the processes participating in the protocol. Ignoring the never and init lifelines that are at the left extremity, the main lifelines shown are vertical lines tracing the behaviors of various process instances, specifically phi1:1, fork:2, phi1:3, fork:4, phi1:5, and fork:6. Reading this MSC, we find out how the bug occurs:

Properties Of Boolean Formulas

3 min read
Properties of Boolean Formulas Boolean satisfiability: an overview: Research on Boolean satisfiability methods (SAT) is one of the “hottest” areas in formal methods, owing to the fact that BDDs are often known to become exponentially sized. The idea of model checking without BDDs was introduced. This work also coincided with the arrival on the scene, of efficient Boolean satisfiability methods. These modern SAT solvers utilization in carrying out these algorithms. Easily modifiable versions of these tools are now freely available. Boolean SAT methods are now able to often handle extremely large system models, establish correctness properties, and provide explanations when the properties fail. Andersson presents many of the basic complexity results, including the inevitability of exponential blow up, even in the domain of SAT. We discuss a summary of these issues, and offer a glimpse at the underlying ideas behind modern SAT tools. Unfortunately, space does not permit our detailed presentation of the use of SAT techniques or some of their unusual applications in system verification. The reader may find many tutorials on the Internet or web sites. Normal forms We now discuss several properties of Boolean (or propositional) formulas to set the stage for discussions about the theory of NP-completeness. There are two commonly used normal forms for Boolean formulas: the conjunctive normal form (CNF) and the disjunctive normal form (DNF). Given a Boolean expression (function) over n variables x1 . . .xn, a sum-of-products (SOP) or disjunctive normal form (DNF) expression for it is one where products of literals are disjoined (OR-ed) – a literal being a variable or its negation. For example, nand(x, y) is expressed in SOP (DNF) as

Acceptance, Halting, Rejection

3 min read
Acceptance, Halting, Rejection: Given a Turing machine M = (Q,Σ, Γ, δ, q0,B, F), the transition function δ is partial - it need not be defined for all inputs and states. When not defined, the machine becomes “stuck” - and is said to halt. Therefore, note that a TM can halt in any state. Also, by convention, no moves are defined out of the control states within F. Therefore, a TM always halts when it reaches a state f ∈ F. Here are further definitions: A TM accepts when halting at f ∈ F. A TM rejects when halting in any other state outside F. A TM loops when not halting. “Acceptance” of a TM closely examined Compared to DFAs and PDAs, the notion of acceptance for a TM is unusual in the following sense: a TM can accept an input without fully reading the input—or, in an extreme situation, not even reading one cell of the input (e.g., if q0 ∈ F)! Hence, curiously, any TM with q0 ∈ F has language Σ∗. On the other hand, if a TM never accepts, its language is ∅. This can be the result of the TM looping on every input, or the TM getting stuck in a reject state for every input. As a final illustration, given an arbitrary language L1, a TM that accepts any string within the set L1 and does not accept (loops or rejects) strings outside L1, has L1 as its language. Instantaneous descriptions: While capturing the ‘snapshot’ of a TM in operation, we need to record the control state of the machine, the contents of the tape, and what the head is scanning. All these are elegantly captured using an instantaneous description containing the tape contents, w, with a single state letter q placed somewhere within it. Specifically, suppose that the string lqr represents that the tape contents is lr, the finite-state control is in state q, and the head is scanning r[0]. The initial ID is q0w, for initial input string w. We define, the ‘step’ function that takes IDs to IDS, as follows: l1par1 l1bqr1 if and only if δ(p, a) = (q, b,R). The TM changes the tape cell contents a to b and moves right one step, facing r1[0], the first character of r1. Similarly, l1cpar1 l1qcbr1 if and only if δ(p, a) = (q, b,L). The TM changes an a to a b and moves left one step to now face c, the character that was to the left of the tape cell prior to the move.

Simulations Of Turing Machine

5 min read
Simulations: We show that having multiple tapes or having nondeterminism does not change the inherent power of a Turing machine. Multi-tape vs. single-tape Turing machines: A k-tape Turing machine simply maintains k instantaneous descriptions. In each step, its δ function specifies how each ID evolves. One can simulate this behavior on a single tape Turing machine by placing the k logical tapes as segments, end-to-end, on a single actual tape, and also remembering where the k tape heads are through “dots” kept on each segment. One step of a k-tape Turing machine now becomes a series of k activities conducted one after the other on the k tape segments. Nondeterministic Turing machines: A nondeterministic Turing machine can be conveniently simulated on a single tape deterministic Turing machine. However, it is much more convenient to explain how a nondeterministic Turing machine can be simulated on a multi-tape deterministic Turing machine. For the ease of exposition, we will carry this explanation out with respect to the example given in Figure 15.3. We will employ a 3-tape deterministic Turing machine to simulate the NDTM in Figure 15.3 (hereafter called ww ndtm). The first tape maintains a read-only copy of the initial input string given to ww ndtm. We call it the input tape. The second tape maintains a tree path in the nondeterministic computation tree of ww ndtm. We call it the tree path tape. The third tape is the “working tape.”

Ndtms

5 min read
NDTMs: An NDTM is a Turing machine with nondeterminism in its finite-state control, much like we have seen for earlier machine types such as PDAs. To motivate the incorporation of nondeterminism into Turing machines, consider a problem such as determining whether an undirected graph G has a clique (a completely connected subgraph) of k nodes.4 No efficient algorithm for this problem is known: all known algorithms have a worst-case exponential time complexity. Computer scientists have found that there exist thousands of problems such as this that arise in many practical contexts. They have not yet found a method to construct a polynomial algorithm for these problems. However, they have discovered another promising approach: Guess and check: While all this may sound bizarre, the fundamental ideas are quite simple. The crux of the matter is that many problems can be solved by the “guess and check” approach. For instance, finding the prime factors of very large numbers is hard. As [98] summarizes, it was conjectured by Mersenne that 267 − 1 is prime. This conjecture remained open for two centuries until Frank Cole showed, in 1903, that it wasn’t; in fact, 267−1 = 193707721×761838257287. Therefore, if we could somehow have guessed that 193707721 and 761838257287 are the factors of 267 − 1, then checking the result would have been extremely easy! The surprising thing is that there are two gradations of “difficulty” among problems for which only exponential algorithms seem to exist: those for which short guesses exist, and checking the guesses is easy, and those for which the existence of short guesses is, as yet, unknown. To sum up:

Validity Of First-order Logic Is Undecidable

4 min read
Validity of first-order logic is undecidable: Valid formulas are those that are true under all interpretations. For example, ∀x.f (x) = g(x) ⇒ ∃a.f (a) = g(a). Validity stems from the innate structure of the formula, as it must remain true under every conceivable interpretation. We will now summarize Floyd’s proof that the validity problem for firstorder logic is undecidable. First, an abbreviation: for σi ∈ {0, 1}, use the abbreviation fσ1,σ2,...,σn(a) = fσn(fσn−1 (. . . fσ1(a)) . . .). The proof proceeds by building a FOL formula for a given “Post system” (an instance of Post’s correspondence problem). Given a Post system S = {(α1, β1), (α2, β2), . . . , (αn, βn), n ≥ 1 over Σ = {0, 1}, construct the wff WS (we will refer to the two antecedents of WS as A1 and A2, and its consequent as C1): We now prove that S has a solution iff WS is valid. Part 1. (WS valid) ⇒ (S has a solution). If valid, it is true for all interpretations. Pick the following interpretation: a = ε f0(x) = x0 (string ‘x’ and string ‘0’ concatenated) f1(x) = x1 (similar to the above) p(x, y) = There exists a non-empty sequence i1i2 . . . im such that x = αi1αi2 . . .αim and y = βi1βi2 . . .βim Under this interpretation, parts A1 and A2 of WS are true. Here is why: Part 2. (WS valid) ⇐ (S has a solution). If S has a solution, let it be the sequence i1i2 . . . im. In other words, αi1αi2 . . .αim = βi1βi2 . . . βim = Soln. Now, in order to show that WS is valid, we must show that for every interpretation it is true. We approach this goal by showing that under every interpretation where the antecedents ofWS, namely A1 and A2, are true, the consequent, namely C1, is also true (if any antecedent is false, WS is true, so this case is not considered). From A1, we conclude that p(fαi1 (a), fβi1 (a)) is true. Now using A2 as a rule of inference, we can conclude through Modus ponens, that p(fαi2 (fαi1 (a)), fβi2 (fβi1 (a)) is true. In other words, p(fαi1αi2 (a), fβi1βi2 (a)) is true. We continue this way, applying the functions in the order dictated by the assumed solution for S; in other words, we arrive at the assertion that the following is true (notice that the subscripts of f describe the order in which the solution to S considers the α’s and β’s): p(fαi1αi2 ...αim(a), fβi1βi2...βim(a)).

An Introduction To Model Checking

7 min read
An Introduction to Model Checking: The development of model checking methods is one of the towering achievements of the late 20th century in terms of debugging concurrent systems. This development came about in the face of the pressing need faced by the computing community in the late 1970’s for effective program debugging methods. The correctness of programs is the central problem in computing, because there are often very designs that are correct, and vastly more that are incorrect. In some sense, defining what ‘correct’ means is half the problem - proving correctness being the other half of the problem. The quest for high performance and flexibility in terms of usage (e.g., in mobile computing applications) require systems (software or hardware) to be designed using multiple computers, processes, threads, and/or function units, thus quickly making system behavior highly concurrent and non-intuitive. With the rapid progress in computing, especially with the availability of inexpensive microprocessors, the computer user community found itself – in the late 1970’s – in a position where it had plenty of inexpensive hardware but close to no practical debugging methods for concurrent systems! We will now examine the chain of events that led to the introduction of model checking in this setting. Model checking in the design of modern microprocessors: All modern microprocessors are designed to be able to communicate with other microprocessors through shared memory. Unfortunately since only one processor can be writing at any memory location at a given time, and since “shared memory” exists in the form of multiple levels of caches, with further levels of caches being far slower to access than nearly levels of caches, extremely complex protocols are employed to allow processors to share memory. Even one bug in one of these protocols can render a microprocessor useless, requiring a redesign that can cost several 100s of millions of dollars. No modern microprocessor is sold today without its cache coherence protocol being debugged through model checking. Model checking in the design of device drivers: Drivers for computer input/output devices such as Floppy Disk Controllers, USB Drivers, and Blue-tooth Drivers are extremely complex. Traditional debugging is unable to weed out hidden bugs unless massive amounts of debugging time are expended. Latent bugs can crash computers and/or become security holes. Projects such as the Microsoft Research SLAM project have technology transitioned model checking into the real world by making the Static Driver Verifier part of the Windows Driver Foundation. With this, and other similar developments, device-driver writers now have the opportunity to model-check their protocols and find deep-seated bugs that have often escaped, and/or have taken huge amounts of time to locate using traditional debugging cycles. Has the enterprise of model checking succeeded? What about social processes? We offer two quotes:

Dining Philosophers

5 min read
and left hands (respectively), while P1 would eat with F1 and F2, and P2 with F2 and F0. Clearly, when one philosopher ‘chows,’ the other two have to lick their lips, patiently waiting their turn. It is assumed that despite their advanced state of learning, they are disallowed from trying to eat with one fork or reach across the table for the disallowed fork. In order to pick up a fork, a philosopher sends a message to the fork through the appropriate channel. For example, to acquire F0 or F1, respectively, P0 would send an are_you_free request message through channel C5 or C0, respectively. Such a request obtains a “yes” or a “no” reply. If the reply is “yes,” the philosopher acquires the fork; otherwise he retries (if for the left fork) or gives up the already acquired left fork and starts all over (if for the right fork). Consequently, the deadlock due to all the philosophers picking up their left forks and waiting for their right forks does not arise in our implementation. After finishing eating, a philosopher puts down the two forks he holds by sequentially issuing two release messages, each directed at the respective forks through the appropriate channels. Figure 21.2 describes how the above protocol is described in the Promela modeling language. Consider the init section where we create channels c0 through c5. Each channel is of zero size and carries mtype messages. Communication through a channel of size 0 occurs through rendezvous wherein the sender and the receiver both have to be ready in order for the communication to take place. As one example, consider when proctype phil executes its statement lf!are_you_free. We trace channel lf and find that it connects to a philosopher’s left-hand side fork. This channel happens to be the same as the rp channel as far as fork processes are concerned (rp stands for the ‘right-hand philosopher’ for a fork). These connections are specified in the init section. Hence, proctype fork must reach rp?are_you_free statement at which time both lf!are_you_free and rp?are_you_free execute jointly. As a result of this rendezvous, proctypes phil as well as fork advance past these statements in their respective codes. Continuing with the init section, after “wiring up” the phil and fork processes, we run three copies of phil and three copies of fork in parallel (the atomic construct ensures that all the proctype instances start their execution at the same time). The never section specifies the property of interest, and will be described in Sections 21.4.1 and 22.1. Now we turn our attention to the proctypes phil and fork.

Ltl Syntax

3 min read
LTL syntax: LTL formulas ϕ are inductively defined as follows, through a contextfree grammar: ϕ → x, a propositional variable | ¬ϕ negation of an LTL formula | (ϕ) parenthesization | ϕ1 ∨ ϕ2 disjunction | Gϕ henceforth ϕ | Fϕ eventually ϕ (“future”) | Xϕ next ϕ | (ϕ1U ϕ2) ϕ1 until ϕ2 | (ϕ1W ϕ2) ϕ1 weak-until ϕ2 Note that G is sometimes denoted by  while F is denoted by ♦. We also introduce the X operator into the syntax above to capture the notion of next in a time sense. It is clear that in many real systems— for example, in globally clocked digital sequential circuits—the notion of next time makes perfect sense. However, in reasoning about the executions of one sequential process Pi among a collection of parallel processes P1, . . . , Pn, the notion of next time does not have a unique meaning. As far as Pi is concerned, it has a list of candidate “next” statements to be considered; however, these candidate statements may be selected only after an arbitrary amount of interleavings from other processes. Hence, what is “next” in a local sense (from the point of view of Pi alone) becomes “eventually” in a global sense. While conducting verification, we will most likely not be proving properties involving X. However, X as a temporal operator can help expand other operators such as G through recursion. With this overview, we now proceed to examine the semantics of LTL. LTL semantics: Recall that the semantics of LTL are defined over (infinite) computational sequences. LTL semantics can be defined over computation trees by conjoining the truth of an LTL formula over every computational sequence in the computational tree. Let σ = σ0 = s0, s1, . . ., where the superscript 0 in σ0 emphasizes that the computational sequence begins at state s0. By the same token, let σi = si, si 1, . . ., namely the infinite sequence beginning at si. By σ |= ϕ we mean ϕ is true with respect to computation σ; σ |= ϕ means ϕ is false with respect to computation σ. Here is the inductive definition for the semantics of LTL: σ |= x iff x is true at s0 (written s0(x)) σ |= ¬ϕ iff σ |= ϕ σ |= (ϕ) iff σ |= ϕ σ |= ϕ1 ∨ ϕ2 iff σ |= ϕ1 ∨ σ |= ϕ2 σ |= Gϕ iff σi |= ϕ for every i ≥ 0 σ |= Fϕ iff σi |= ϕ for some i ≥ 0 σ |= Xϕ iff σ1 |= ϕ σ |= (ϕ1U ϕ2) iffσk |= ϕ2 for some k ≥ 0 and σj |= ϕ1 for all j < k σ |= (ϕ1W ϕ2) iffσ |= Gϕ1 ∨ σ |= (ϕ1U ϕ2) LTL example: Consider formula GF x (a common abbreviation for G(F x)). Its semantics are calculated as follows: σ |= GFx iff σi |= Fx, for all i ≥ 0 σi |= Fx iff σj |= x, for some j ≥ i Putting it all together, we obtain the meaning as: x is true infinitely often—meaning, beginning at no point in time is it permanently false.