An abstract data type specifies values and operations independently of their storage. A FIFO queue has ordered sequences as its abstract values; an array and a linked list can represent those same values. A representation invariant identifies valid storage states, and an abstraction function says what each valid state means.[ref]
Implementation of an abstract state and operations using a more concrete representation, justified by a coupling invariant. For example, an insertion-history list may be implemented by a sorted array when clients observe only occurrence counts and order statistics. The observable behavior, rather than insertion order internally, must agree.
A relation between abstract and concrete states used to prove data refinement. Establish it initially; show that each concrete operation simulates the specified abstract operation and restores the relation; show that returned observations agree. For a rank collection, and justify constant-time indexed queries on a sorted array.
A condition describing legal abstract states, independently of their concrete storage. A bounded-key multiset has nonnegative counts and zero counts outside its allowed range. A representation invariant instead constrains implementation states; an abstraction function connects a valid representation to its abstract state. The two kinds of invariant should not be conflated.
A representation invariant specifies which concrete storage states are valid at the API boundary. Construction must establish it, and each completed operation must preserve it. Internal steps may temporarily violate it only while that state is inaccessible to observers; callbacks or concurrent access would require further reasoning.[ref]
The short proof pattern is mathematical induction on the number of completed calls: the initial state satisfies ; every permitted transition from an -state ends in an -state; hence every state observable through the API satisfies . An unrestricted external write falls outside this argument.
An abstraction function maps a valid concrete representation to its abstract value. Write and . Different storage states can denote the same abstract value. Correct implementation requires both preservation of the representation invariant and agreement with the specified operation after applying the abstraction function; preserving a length bound alone would not prove first-in, first-out behavior.
The representation invariant answers "is this storage state allowed?" The abstraction function answers "which value does it represent?" Thus is a truth value, whereas is a value of the abstract data type. Treating as a partial function on all storage states, or as a function defined on only, expresses the same restriction. The abstraction function may forget storage details, and need not be executable code: its purpose is to connect an implementation to its formal specification.[ref]
This distinction makes functional correctness manageable one operation at a time. The unreduced rational representation below separates valid storage from mathematical meaning; correct operations through an abstraction function then checks whether an implementation performs the promised addition. For an example with hidden mutable storage and failure cases, the bounded queue with encapsulation supplies a different abstraction function, reading an occupied prefix of an array as a sequence.
Consider an original abstract data type whose values are rational numbers. Store an ordered pair of integers, interpreted as a numerator and a denominator. Use exact, unbounded integer arithmetic in this model. The storage space, representation invariant and abstraction function are
The representation invariant does not require a positive denominator or a reduced fraction. Consequently , and are three different concrete states with the same abstract rational number . Similarly, and both represent zero. The abstraction function is a surjection: every rational number has an integer numerator and a nonzero integer denominator, so every abstract value has a representation.
Figure 1.
Several valid integer pairs represent one rational value; zero denominators have no abstract value
. Details.
Both and violate the representation invariant; neither has a value under this abstraction function. By contrast, is completely valid. Simplifying it to the reduced fraction may be a useful implementation choice, but is not a requirement of this representation. Strengthening the representation invariant to require a positive denominator and a greatest common divisor of one would choose a unique stored representative for each rational number; every constructor and operation would then need to establish that stronger condition.
Equality of abstract values is therefore different from equality of stored ordered pairs. For valid and ,
This defines an equivalence relation on : each equivalence class contains all representations of one rational number. An API equality operation can compare these cross-products using exact integer arithmetic. Comparing the two fields individually would incorrectly declare and unequal as rational numbers. The general reason is that an abstraction function may map several concrete values to one abstract value.[ref]
For a deterministic binary operation on an abstract data type, let be its specified operation on abstract values and the implementation on concrete states. For every permitted valid input pair , require both
The first condition preserves the representation invariant. The second makes a commutative diagram: either execute and then apply the abstraction function, or apply the abstraction function to both inputs and then execute the abstract operation ; both paths reach the same value. These conditions state functional correctness of a completed operation; termination is an additional obligation for algorithm correctness.[ref]
For addition in the unreduced rational representation, choose
For example, represents , precisely the sum of and . The short correctness argument uses nonzero denominators: and imply , preserving the representation invariant, and
Figure 1.
Correct rational addition makes both paths agree; an invariant-preserving incorrect operation gives a different value
. Details.
Now consider an incorrect implementation that uses addition on the numerators and multiplication on the denominators:
It preserves the representation invariant for every valid input pair because its denominator is still . Yet represents , not the specified sum . Even perfect checks of the representation invariant before and after this call would miss the error: the result is a legal representation of the wrong rational number.
The incorrect operation also exposes an accidental dependence on representation. Replace by the equivalent state while keeping . The correct operation gives , still representing ; the incorrect operation gives , representing instead of its previous . A correct addition must yield the same abstract result for equivalent inputs, although its concrete outputs may differ. This is why checks against the formal specification should compare abstract values, including unreduced representations and representations with a negative denominator, rather than demand identical stored pairs.
The calculation assumes exact integers. An implementation with bounded storage must additionally specify how it handles products and sums outside its supported range; the mathematical argument alone does not establish its functional correctness. The bounded queue with encapsulation illustrates the corresponding need to account for returned status values and failed operations, alongside the abstract state transition.

Ancestors (3)

  1. Encapsulation (computer programming)
  2. Computer science
  3. Home

Discussion (0) New discussion

There are no discussions about this article yet.

Articles by others on the same topic (0)

There are currently no matching articles.