Formal Specification Exercise¶
Formal Specification¶
Specifications describe what a program is supposed to do. They may come from customers, end users, or an analyst team, expressed informally in text, in structured documents, or using formal mathematical notation. This lesson focuses on precise specification using mathematical notations.
Two notations are used:
First-Order Logic (FOL) / Predicate Calculus — enables precise expression of propositions, combination via logical connectives (and, or, not), and quantification (∀, ∃)
OCL (Object Constraint Language) — part of UML; provides FOL-equivalent syntax for annotating UML diagrams
The Specification Process¶
Mathematical specification proceeds in three stages:
Signature — name of the program, names and types of input arguments, name and type of the result
Precondition — assertion about the function’s input arguments (what must be true for meaningful execution)
Postcondition — assertion about the output (how the result relates to the input)
SQRT Example¶
Signature: Real y = SQRT(Real x)
Precondition: x ≥ 0 (defined over non-negative reals only)
Postcondition: y × y = x
Notes on postconditions: For pure functions, output is completely determined by input. For impure functions, postconditions must also describe side effects (changes to global variables, I/O, changes to instance variables in OO contexts).
SORT Example¶
Signature: Vector<int> y = SORT(Vector<int> x)
Precondition: True (any vector of integers is valid input)
Postcondition has two parts:
The output is ordered
The output contains the same elements as the input (is a permutation)
Specifying ORDERED¶
Signature: Bool z = ORDERED(Vector<int> y)
Precondition: True (even an empty vector is trivially ordered)
Postcondition: ∀i (1 ≤ i < |y|) . y[i] ≤ y[i+1]
For every index i from 1 up to (but not including) the length of y, the element at position i must be less than or equal to the element at position i+1. Using < |y| avoids indexing past the end.
RORDERED (reverse/descending order) is identical except: y[i] ≥ y[i+1]
Specifying Permutation¶
To express “same elements as,” we use the well-defined mathematical concept of permutation.
Signature: Bool z = PERMUTATION(Vector<int> x, Vector<int> y)
Precondition: |x| = |y| (vectors must have equal length)
Postcondition — three cases (recursive definition):
Case 1 — Empty vectors: If |x| = 0, then x is a permutation of y (base case).
Case 2 — First elements match: If |x| > 0 and x[1] = y[1], then x is a permutation of y if tail(x) is a permutation of tail(y) (where tail = everything except the first element).
Case 3 — First elements differ: If x[1] ≠ y[1], then:
There exists some position j (where
1 < j ≤ |y|) such thaty[j] = x[1]x is a permutation of y if
tail(x)is a permutation ofy[1..j-1] ^ y[j+1..|y|](concatenation of the segments of y excluding position j)
This recursive definition is well-founded because each recursive call operates on shorter vectors, and the base case (empty vectors) is handled.
The ^ symbol denotes concatenation of two vectors.
OCL Version of ORDERED¶
The same ORDERED specification in OCL syntax:
Uses
|for separating the quantifier variable from the proposition (instead of the dot in FOL)Limitations on the variable’s value are separated from the main proposition by the
implieskeywordUses OCL’s built-in
Sequenceclass instead of vectors
Takeaway¶
Formal specification languages (FOL, OCL) with accompanying tools enable precise expression of system functionality. Although writing specifications requires careful thought about exactly what you want to say, the effort saves significant rework from misunderstood requirements. Industrial-strength tools exist for many formal specification languages.