Establishing specified properties of a system using formal proofs about a precise model. Formal verification connects an implementation to a formal specification; correctness of the model and its assumptions still matters when applying the result to a physical system.
For a small example, the summation loop verification below starts with executable steps and asks two separate questions: does any returned value satisfy the postcondition, and does execution reach that return? A loop invariant answers the first; a loop variant answers the second. This turns an unbounded family of permitted inputs into a few reusable proof obligations.
The model must specify programming language semantics, including the meaning of variable assignments, comparisons and integer arithmetic. A proof about exact mathematical integers need not describe a machine that wraps on integer overflow. Similarly, a correct formal proof of a weak or mistaken formal specification does not establish the intended behavior. Choosing the right formal specification and relating the model to the implemented system remain substantive tasks.
Software testing examines chosen executions and can expose a counterexample. A formal proof instead justifies a statement throughout its stated model; it does not require executing every permitted input. This makes formal verification valuable when rare boundary cases matter, while software testing can still reveal an incorrect model or misunderstood requirement.
In 1969, Tony Hoare presented rules for variable assignment, composition and iteration in a small programming language. His paper explicitly says those rules do not prove successful termination, and discusses the dependence of arithmetic reasoning on the chosen overflow behavior. These reservations already make the model's scope part of the argument.[ref]
A condition selecting admissible infinite paths in a transition system, often to exclude executions that postpone an enabled activity forever. The notation quantifies only over initial paths in a transition system satisfying the chosen condition. For example, requires infinitely often, while requires permanently from some point onwards. Neither condition implies the other.
A model consisting of a set of states, a transition relation , initial states , a set of atomic propositions, and a label function identifying which atomic propositions hold at each state. A path in a transition system follows permitted transitions. Some definitions omit labels or initial conditions; specify the convention used in each application.
A transition system whose edges carry action labels. A CSP operational semantics uses visible CSP events and the internal label .
A state with no successor in the transition relation. Assuming no terminal states makes every finite path in a transition system extendible and avoids choosing a separate convention for interpreting infinite-path temporal logic at a dead end.
A finite or infinite sequence of states in which for each consecutive pair. In infinite-path linear temporal logic semantics, paths are infinite; an initial path must also start in the specified initial set. Repeated states are allowed, unlike conventions for a simple path in a graph.
An infinite path in a transition system represented by a finite prefix followed by infinite repetition of a nonempty finite loop. If stored positions are and , the represented sequence is . The linear temporal logic condition holds exactly when occurs on the repeated part, and holds exactly when holds everywhere on that part.
A binary relation on the states of a system, with meaning that one permitted step changes to . A Boolean formula can encode a transition relation after choosing bits for the current and next states.
For a state formula in a fixed labelled transition system, its satisfaction set is . This is a set of states; it is distinct from the assertion that every initial state satisfies the formula.
A formal verification method that encodes a bounded execution and a violated specification as a Boolean satisfiability problem. A satisfying assignment yields a counterexample. For infinite-path properties, a lasso path can finitely represent a repeated execution. Failure to find a counterexample at one finite bound alone does not prove an unbounded property.[ref]
Compute , the triangular number , for a nonnegative integer . The empty sum gives zero when . Use exact mathematical integers and keep the input unchanged; every comparison and variable assignment is a terminating operation. The original sequential procedure is
require n is an integer and n >= 0
i = 0
s = 0
while i < n:
    i = i + 1
    s = s + i
return s
The order of the two variable assignments matters: the addition uses the newly incremented . For , the pairs at successive condition checks are . At the last check, is false, and the returned sum is .
The precondition is with , under the exact-arithmetic model just stated. The postcondition for returned value is , with still equal to its starting value. At each condition check use the loop invariant
and the loop variant . The equation says that the accumulator is the triangular number for precisely the processed prefix ; the inequalities connect that prefix to the loop's condition.
Figure 1.
The summation loop restores its invariant before each condition check
. Original sequential control flow for the summation loop verification. The blue loop head carries the loop invariant; the orange body increments before adding it to . A false condition leads to the postcondition. The loop variant decreases on the return arrow. All values are mathematical integers and remains unchanged. Details.
Initialization gives , so holds, including when . For preservation, let the old values satisfy and . Write and for the values after both variable assignments. Since are integers, gives , and
Thus the completed body restores . Between the two variable assignments, the equation can be false; the loop invariant is required at the loop head. This preservation step is mathematical induction on the number of completed iterations.
At exit, the false condition gives , while gives . Hence , so : this proves partial correctness. For algorithm termination, gives the nonnegative integer . When the condition is true, ; the terminating body gives . Therefore the loop cannot repeat forever. Together these arguments prove total correctness for every permitted input, including .
Figure 2.
Four additions finish the sum; an unchanged index cannot make progress
. Original exact trace for : five condition checks and four body executions give , while the loop variant decreases from four to zero. The right panel shows the stalled loop from partial correctness: the same program state repeats and never decreases. Its equation remains true, but it never reaches an exit. Details.
Two changes expose what the proof checks. Swapping the two body instructions computes , returning rather than for . Leaving unchanged can preserve an initial equation forever without producing any answer. The first change breaks the intended postcondition; the second breaks algorithm termination. A trace can reveal these failures, while the two proof obligations explain them.
The exact-arithmetic assumption has a concrete boundary. In a stipulated unsigned eight-bit model where each addition wraps modulo , fits in the input representation, but its intended triangular number is . The stored accumulator instead finishes at , so the mathematical postcondition fails. This is integer overflow, and the proof above does not apply to that altered model. Restricting the same implementation to prevents overflow in its stored loop values, since ; alternatively use a representation supporting the required exact integer arithmetic. The equations in the proof are mathematical statements, not instructions to evaluate products in eight bits.
A mathematically precise description of permitted behaviour. A formal specification for the microkernel file-read example's service could relate an authorized request to the exact returned bytes; a formal specification of its microkernel's IPC need only describe the protected transport operation. They state different obligations.
For the summation loop verification, require a nonnegative integer input and a returned value satisfying . The formal specification describes what answer is acceptable without requiring this particular loop: another implementation may satisfy the same contract. State separately whether partial correctness or total correctness is required. A Hoare triple packages the precondition, the program and the postcondition; Hoare logic supplies rules for establishing such claims.
Precision alone does not ensure a useful requirement. The postcondition permits returning zero for every nonnegative integer input; it does not specify the intended triangular number. Conversely, an impossible precondition permits no starts, making a universal correctness claim vacuous. Check both that intended inputs are admitted and that admitted outputs express the intended task.
Specify behavior by constructing a mathematical model and defining the operations on that model. Finite sequences model a FIFO queue: insertion appends, the head is the first element, and successful deletion removes it. An axiomatic specification can then be checked against the model without requiring the implementation to use that representation.
Describe operations through laws relating their observable results, without selecting an internal representation. For an abstract data type, the laws must state the operation domains and error results as well as ordinary cases. A disjoint union can distinguish a successful value from an error with the same textual spelling.
A clause stating which parts of a program state an operation preserves. A query's returned value alone does not prohibit it from also mutating the receiver; a binary update's result equation alone does not preserve its distinct operand. Explicit frame conditions rule out these behaviors and make substitution and composition arguments possible.
An auxiliary planning fluent certifying that a safety condition has been checked for the current state in automated planning. A checking action requires facts establishing the condition and adds the certificate; the hazardous action requires that certificate.
Every action capable of invalidating the check must delete the certificate. Otherwise checking a safe configuration and then changing it could authorize an unsafe action using stale evidence. For river crossing, certify that the departure bank contains no incompatible pair, invalidate the certificate on every load, unload or crossing, and require it before sailing. This compiles a safety test into positive STRIPS preconditions when a suitable finite static compatibility relation is supplied.
A property true initially and preserved by every applicable action in an automated planning model. Mathematical induction on the plan length then proves it for every reachable state. Typical examples are unique object locations, a capacity bound, and exactly one occupancy marker being true. An invariant is a consequence to prove from the action rules; merely declaring the intended capacity in prose does not enforce it.
The condition required of a starting program state for a stated correctness guarantee. In the summation loop verification, and admit and , but exclude . The accompanying model assumes exact integer arithmetic and terminating elementary operations. The initial values of need no restriction because initialization overwrites them before use.
A precondition is a logical assumption, not automatically an executable check. Writing require in a procedure states its contract; an implementation that checks or rejects invalid inputs needs that behavior specified too. Weakening a precondition admits more starts and therefore demands more proof: dropping here makes a terminating counterexample to , since initialization returns zero while .
The condition required of a final program state when a program finishes under its precondition. The summation loop verification requires returned value to satisfy and preserves the input . Relating the answer to the original input matters: allowing the program to replace by zero would change the intended contract.
A postcondition alone gives no promise of algorithm termination. It also need not specify a unique output: allows many answers, while the exact triangular number equation determines one integer answer for each permitted . Stronger postconditions express more obligations; proving only a weaker consequence cannot justify the stronger requirement.
Conformance of compiled machine code to the behaviour of the code model used to justify it. Binary correctness can extend formal verification across the compilation step; the result applies to the particular compiled artifact and its assumptions.

Articles by others on the same topic (2)

Formal verification is a rigorous mathematical approach used to prove or disprove the correctness of computer systems, algorithms, and hardware designs with respect to a certain formal specification or properties. Unlike traditional testing methods, which can only provide a degree of confidence based on the tests performed, formal verification aims to provide definitive guarantees about a system's behavior.