Historical IntroductionEver since the first program verification systems of King [35] and Good [27], theorem provers have played an important part in the mechanically-assisted analysis of computer programs and software systems. Theorem provers have evolved over the years to better support this application, principally through improved automation for reasoning about arithmetic, data structures, and recursively or inductively defined functions and relations. During this time, the focus of formal verification has expanded from verifying small concrete programs to analyzing rather intricate (often concurrent) algorithms and the specifications (rather than the code) for fairly complex systems. These algorithms and specifications often are formalized directly in the notation of the theorem prover concerned, and these notations also have evolved, principally through use of higher-order logic and rich type systems, so that they provide attractive environments for formal specification. Until recently, the large majority of substantial formal verifications were performed using theorem provers of this kind, such as ACL2 [34] [38] (which uses a symbolic representation based on BDDs) became widely available. The limitation to finite state meant that most specifications had to be severely "downscaled" by Draconian restrictions on the size of data structures. Such downscaling usually does not preserve correctness (sometimes it does not preserve incorrectness either) and this compromises model checking as an approach to verification-hence, its early uses were mostly for refutation (i.e., bug finding), but it was highly effective for that purpose.The invention of predicate abstraction [47] allowed model checking to expand from refutation to verification: rather than arbitrarily downscale an algorithm or system specification to finite state, predicate abstraction provides a mechanizable approach to the construction of propertypreserving abstractions-so that model checking the finite state abstraction does verify the original specification. Initially, manual guidance was needed to select the predicates on which to abstract, but it was soon recognized that the predicates appearing explicitly in the specification provide a good starting point, and that the selection can iteratively be refined through examination of the counterexamples produced by model checking inadequate abstractions [45].This approach evolved into the automated methodology of counterexample-guided abstraction refinement (CE-GAR) [11], which employs a loop comprising abstraction, model checking, counterexample generation and analysis, and abstraction refinement. Decision procedures are used to construct the abstractions, and for software specifications (where the concrete transition relation may be too large or too complex to manipulate directly) these are often constructed and explored "on the fly" with an explicit state model checker; any counterexample produced by model checking an abstraction is checked in its concrete interpretation by a satisfiabilit...