Algorithms and Data Structures
Algorithms and Data Structures
Algorithms and Data Structures
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
N.Wirth. <strong>Algorithms</strong> <strong>and</strong> <strong>Data</strong> <strong>Structures</strong>. Oberon version 210<br />
Appendix C. The Dijkstra loop<br />
E.W. Dijkstra [C.1] (see also [C.2]) introduced <strong>and</strong> justified a multibranch generalization of the<br />
conventional WHILE loop in his theory of systematic derivation of imperative programs. This loop proves<br />
convenient for expression <strong>and</strong> — most importantly — for verification of the algorithms which are usually<br />
expressed in terms of embedded loops, thus significantly reducing the effort of debugging.<br />
In the language Oberon-07 presented in [C.3], the syntax of this loop is defined as follows:<br />
WhileStatement<br />
= WHILE logical expression DO<br />
operator sequence<br />
{ELSIF logical expression DO<br />
operator sequence}<br />
END.<br />
If any of the logical expressions (guards) is evaluated to TRUE then the corresponding operator sequence is<br />
executed. The evaluation of the guards <strong>and</strong> the execution of the corresponding operator sequences is<br />
repeated until all guards evaluate to FALSE. So, the postcondition for this loop is the conjunction of<br />
negations of all guards.<br />
Example:<br />
WHILE m > n DO m := m - n<br />
ELSIF n > m DO n := n - m<br />
END<br />
Postcondition: ~(m > n) & ~(n > m), which is equivalent to n = m.<br />
The loop invariant must hold at the beginning <strong>and</strong> at the end of each branch.<br />
Roughly speaking, an n-branch Dijkstra loop corresponds to constructions with n usual loops that are<br />
somehow embedded one into another.<br />
The advantage of the Dijkstra loop is due to the fact that all the logic of an arbitrarily complex loop is<br />
expressed at the same level <strong>and</strong> is radically clarified, so that algorithms with various cases of embedded<br />
interacting ("braided") loops receive a completely uniform treatement.<br />
An efficient way to construct such a loop consists in enumerating all possible situations that can emerge,<br />
describing them by the corresponding guards, <strong>and</strong> for each guard — independently of the others —<br />
constructing operations that advance the algorithm towards its goal, togethers with the operations that<br />
restore the invariant. The enumeration of the guards is stopped when the disjunction (OR) of all guards<br />
covers the assumed precondition of the loop. It is useful to remember that the task of construction of a<br />
correct loop is simplified if one postpones worrying about the order of evaluation of the guards <strong>and</strong><br />
execution of the branches, optimizations of evaluation of the guards etc., until the loop is correctly<br />
constructed. Such lower-level optimizations are rarely significant, <strong>and</strong> their implementation is greatly<br />
simplified when the correctness of a complicated loop has already been ensured.<br />
Although in Dijkstra's theory the order of guard evaluations is undefined, in this book the guards are<br />
assumed to be evaluated (<strong>and</strong> branches selected for execution) in their textual order.<br />
In most programming languages the Dijkstra loop has to be modelled. In the older versions of Oberon<br />
(including Component Pascal) it is sufficient to use the LOOP construct, with the body consisting of a<br />
multibranch IF operator that contains the single loop EXIT operator in the ELSE branch: