SlideShare a Scribd company logo
1
How invariants help writing loops
Author: Sander Kooijmans
Document version: 1.0
Why this document?
Did you ever feel frustrated because of a nasty bug in your code? Did
you spend hours looking at the code and stepping through complex
loops with a debugger?
Software engineers must have skills to write correct code. One of these
skills is Test-Driven Development (TDD). TDD has received a lot of attention lately, other techniques
are overlooked: techniques to prove correctness of algorithms and techniques to derive correct
algorithms. In this document I present a technique based on Prof. Dijkstra’s style of proving and
deriving algorithms.
Predicates
Before explaining invariants I will explain what predicates are. A predicate is a
function that has a number of variables as input and returns true or false.
Take the following two statements:
After execution of these two statements the following predicates hold:
≡
≡
≡
For brevity we omit the arguments of a predicate. For example: ≡
Hoare triple
Tony Hoare invented a technique to prove the correctness of algorithms: Hoare triples. A Hoare
triple looks like this: , where and are predicates and is a
statement. The Hoare triple means: when holds and is executed,
then if terminates then holds. It is important that terminates. If does not terminate
does not have to hold.
Hoare used these triples to specify how to prove assignments, if-loops, while-loops and
composition.
In this document I will only focus on while-loops.
Hoare triple for a while-loop
What is an invariant? An invariant is a predicate which holds before and after each iteration of a
loop. An invariant gives meaning to the variables. And an invariant defines the intent of the
variables.
2
To prove the while-loop the following four parts must be
proven:
1. holds before the while-loop is executed
2. holds after each iteration
3. ⇒
4. The while-loop terminates
is called an invariant.
Note that because of part 1 the invariant holds at the beginning of the first iteration. Because of
part 2 the invariant holds at the end of the first iteration and therefore at the beginning of the
second iteration. And because of part 2 the invariant also holds at the end of the second iteration
and therefore at the beginning of the third iteration, and so on. We conclude from parts 1 and 2 that
the invariant holds at the beginning and the end of each iteration.
The third part states that the invariant can be used to prove the postcondition. And since the loop
has terminated you can use the negation of the guard as well to prove the postcondition.
The fourth part is obvious. If the loop does never terminate, then there is no guarantee that the
postcondition will ever hold.
How can you prove that a while-loop terminates? You have to come up with a
bound function. A bound function is a function that has all variables of your
program as input and returns a number. The bound function must decrease by
at least one each iteration and must be bounded from below. You can
compare it with a stairs: if you step down a stairs one or more steps each
iteration then sooner or later you will reach the end of the stairs and step on the ground.
Proving an algorithm to calculate 2n
Let me give an example of a while-loop and to illustrate an invariant and bound function. Here is an
algorithm that calculates for the input variable . In code I use the notation
instead of .
The table to the right shows the values of , and before each iteration. Notice that and
change each iteration. Also notice that the and are equal in each row in the table.
First check the precondition: it states that is at least zero. The postcondition states that the
variable is equal to . The invariant states that is equal to . There are four things we have to
prove:
3
1. The invariant holds before the while-loop is executed. Fill in and in the
invariant: , which is true.
2. The invariant holds after each iteration. Here we can use the fact that the invariant holds at
the beginning of the iteration. So at the beginning holds . The assignment
doubles the value of . The assignment doubles the value of . The
result of the two assignments is that the invariant holds again. Notice that after the first
assignment the invariant does not hold. That is not a problem because the invariant holds at
the end of the loop.
3. When the loop terminates we know that . Together with the invariant
this yields the postcondition: .
4. The bound function decreases with exactly one each iteration. The loop ends with
, thus the bound function cannot get below zero. This proves that the loop
terminates.
This was the most formal part of this document. Do not despair if you didn’t understand the
complete proof. From now on this document will be less formal.
Professor Edsger Wybe Dijkstra
You may know Professor Dijkstra from:
 Eindhoven University of Technology where he has worked in the past (and I
graduated from that university)
 Goto statement considered harmful (also called anti-goto letter)
 Semaphores
 Dijkstra’s shortest path algorithm
 Winning the Turing Award in 1972
There is one more thing that Professor Dijkstra was famous for: he invented a way to develop proof
and program hand in hand.
What I am going to explain you, is inspired by Dijkstra’s formal way of developing a proof and
program.
Deriving the algorithm to calculate 2n
Let’s write the algorithm to calculate again, but this time we start with the precondition and
postcondition:
Next we introduce the invariant. The invariant consists of the postcondition where the constant
has been replaced by the new variable .
4
The invariant must hold before the loop. So how should we initialize the variables and ? Often the
simplest way to initialize is by using ‘simple’ values like 0 or 1. Can we initialize with zero? Then we
must choose such that is zero. That is impossible. Thus we must try something else.
The precondition states that the smallest valid value for is zero. So let’s try to initialize with zero.
When we choose to initialize with zero then the invariant tells us that p must be initialized with the
value 1.
Next focus on the guard of the while-loop. When should we stop iterating? If then the
invariant is equal to the postcondition. We must continue iterating until . So the guard is
.
Finally we focus on the statements inside the while-loop. We plan on increasing . Increasing by
one is the simplest thing we can do. If is increased by 1 then what should we do with ? The right
side of the invariant’s equation is doubled when is increased by 1. So we need to double the left
side as well. This can be done by multiplying by 2. So the result is:
We already proved that the loop terminates using the bound function .
Subarray notation
The second example is about arrays. I use a particular notation for subarrays
that works very will with Dijkstra’s way of deriving programs. Let us review
this notation.
Let be an array of length 10. Then the following predicates about hold:
 represents the complete array
 contains , , and .
 contains and .
5
 Concatenating and results in
 contains
 is empty
 contains elements
Sorting red and blue elements using swaps
Assume we have an enumeration of colors. It consists of the colors and . Let the variable
be an array containing and elements in an arbitrary order. Let us derive an
algorithm that sorts the array so that it starts with all s and ends with all s. And as
extra limitation we only want to use swaps of two elements at a time to modify the array.
We start with writing down the precondition and postcondition:
The idea I have to sort the array is as follows: we let the
red part ‘grow’ from left to right and let the blue part ‘grow’ from
right to left. Look at the image at the right. We use two variables
to keep track of the bounds of the red and blue parts.
contains only red elements,
contains only blue elements.
The elements in between, thus , still have to be sorted.
Now it is time to formulate the invariant:
How do we initialize the while-loop? ? Then we must be sure that is red. And
what if ? The easiest choice for is zero: contains zero
elements. And all of these zero elements are red. And for the same reason we initialize with
.
Sounds strange? This is a little bit of mathematics you should know: if you say that ‘something’ is true
for all elements of some set then by definition that ‘something’ is true for the empty set. Why? Put
simply, the empty set does not contain an element that contradicts that ‘something’. Compare that
to summing all numbers in a set. If the set is empty then the sum is zero. Compare that to multiplying
all numbers in a set. If the set is empty then the product is one.
6
When should the while-loop terminate? The still have to be sorted. The while-loop
should terminate if that segment is empty. That is the case if . Thus the guard of the while-
loop is .
Now we focus on the body of the while-loop. We want to increase and decrease . When can we
increase by one? If is red. So let’s write that down:
What if is not red? The precondition tells us that it then must be blue. So we know that
is blue. We don’t know anything yet about . What if we swap elements
and of the array? Then has become blue and we can then decrease b by one.
And if we decrease by one before executing the swap, then we can swap elements and . That
gets rid of the minus one:
Does this loop terminate? To answer this question we have to come up with a bound function. Look
at the while-loop: each iteration either is increased by one or is decreased by one. This inspires
me to come up with the bound function . Initially it has the value and it
decreases each iteration. The while-loop terminates when . Thus cannot get below
zero. This proves that the while-loop terminates for any input.
7
When to apply this technique?
Most of the time we write trivial loops. For these loops you don’t need to apply this technique. Or
maybe you apply this technique in your mind. Within a couple of seconds you convince yourself
about the correctness of the loop you just wrote down.
Every now and again a complex loop needs to be written. At those times invariants are a valuable
tool to derive and verify your loop.
Exercises
For each exercise derive:
1. Initialization before the loop
2. The guard
3. The assignments in the body
4. Bound function
5. Write tests to check your solution
The exercises start easy and become more and more difficult. Some exercises are marked with the
word ‘challenge’. Those exercises require more mathematical insight than the other exercises.
Exercise 1: Straightforward loops and empty arrays
Given is an array of integers.
Can you write a loop that calculates the sum of all elements of the array? What is the sum for an
empty array?
Can you write a loop that determines the maximum value of the array? What is the maximum value
of an empty array?
Can you write a loop that checks whether all numbers in the loop are positive numbers? All numbers
of the array are positive if . Are
all elements of the empty array positive?
Can you write a loop that checks whether there exists a number in the array that is negative? A
negative number exists in the array if
. Does a negative number exist in an empty array?
8
Exercise 2: Another invariant to calculate 2n
Above a while-loop was derived that calculates 2n
using the invariant . Can you derive a
while-loop with the slightly different invariant ?
How often iterates the while-loop if is 30? What is the order1
of your solution?
Exercise 3: A more efficient implementation to calculate powers
(challenge)
The goal of this challenge is to write an algorithm that calculates and has order
O(log(exponent)). One way of doing that is by using the following property that holds for
:
𝑏𝑎𝑠𝑒 𝑒𝑥𝑝𝑜𝑛𝑒𝑛𝑡
= {
𝑏𝑎𝑠𝑒(𝑏𝑎𝑠𝑒2)
𝑒𝑥𝑝𝑜𝑛𝑒𝑛𝑡−1
2 if exponent is odd
(𝑏𝑎𝑠𝑒2
)
𝑒𝑥𝑝𝑜𝑛𝑒𝑛𝑡
2 if exponent is even
Hint: Try as invariant
Exercise 4: Celebrity problem
In a group of persons a celebrity is someone who is known by everyone but does not
know anyone. Can you write an algorithm that finds the celebrity? The number of persons
in the group is denoted by . The persons are represented by numbers
in the range .
Hint 1: what does and tell you about or being the celebrity?
Hint 2: try as invariant “ ”. (If you like try too and look at the
difference in your solutions.)
Exercise 5: Maximum subarray problem
Given an array of integer numbers. Can you can you find the contiguous subarray which has the
largest sum? For example, for the sequence of values -2, 1, -3, 4, -1, 2, 1, -5, 4 the contiguous
subarray with the largest sum is 4, -1, 2, 1, with sum 6. Find a solution that uses a single while-loop.
1
The order of an algorithm is denoted by the big O notation. If the algorithm iterates n times, then we say it
has order O(n). If an algorithm iterates n2
we say it has order O(n2
). If the algorithm iterates 3*n2
we still say it
has order O(n2
). Thus we omit the constant factor 3 from the order. The idea behind this notation is that for
large values of n the run time is dominated by the factors of n. For example, in the long run 100*n will perform
much better than 1*n2
. Thus an algorithm of order O(n) runs faster than an algorithm of order O(n2
) (for large
values of n).
9
Hint 1: scan through the array values, computing at each position the maximum sum of any subarray
ending at that position. This subarray is either empty (in which case its sum is zero) or consists of one
more element than the maximum subarray ending at the previous position.
Hint 2: Let’s call the array . Let be an integer variable. Use the invariant:
“maximum sum of , , …, ” and
“maximum sum of any subarray of ”.
Exercise 6: Dutch national flag problem (sorting three colors)
We continue sorting colors. This time we introduce a third color: white. Why white?
Because red, white and blue constitute the Dutch national flag and the author of this
document happens to be Dutch...
Let be an array of red, white and blue elements. Here are the precondition
and postcondition:
Hint: in the example above we moved the red elements to the start of the array and the blue
elements to the end of the array. Can you move the white elements directly after the red elements?
Exercise 7: Quicksort (challenge)
Transform the algorithm from exercise 6 as follows: instead of colors the array should contain
numbers. Choose any element in the array. The value of that element is ‘white’. All elements with
the same value are ‘white’. All smaller values are ‘red’ and all higher values are ‘blue’.
See what the transformed algorithm does? It divides the array in three parts. The element that you
choose to define the white numbers is called the pivot. The red elements contains all numbers that
are smaller than the pivot and all blue elements contain all numbers larger than the pivot.
This looks like a sorting algorithm for numbers. We still have to sort the red and blue segments. For
this you need two recursive calls. After adding these two calls you have implemented Quicksort. This
algorithm was developed by Tony Hoare (yes, him from the triples) in 1960.
Hint: if the red or blue part contains less than two elements it is already sorted.
If the red and blue part have (about) equal lengths, Quicksort operates in O(n*log(n)). However, if
the red or blue part is empty, then it degrades to O(n2
), which is as bad as Bubble Sort and Insertion
Sort.
10
Exercise 8: Binary search
Let be an array containing numbers. This time the array is sorted ascendingly. Can we use
the fact that the array is sorted to quickly determine whether some number is present in the array?
Hint 1: which element in the sorted array gives you most information about whether the number is
present? The first element, the middle element or the last element?
Hint 2: can you halve the remaining subarray that should contain (if is present) each iteration?
Hint 3: Use as invariant “if contains then it is in ”.
Exercise 9: Primes kata (challenge)
If you are familiar with prime numbers and are in for a challenge you can give this exercise a try.
Write a function that calculates the prime factors of a given number. For example: given the number
60 the function should return a list containing 2, 3, 5 and 5 because 2*3*5*5=60. Don’t use the sieve
of Eratosthenes2
. Instead use two nested while-loops.
Hint: use the following three invariants:
invariant 1: contains only primes
invariant 2: * "product of factors" ==
invariant 3: has no prime factors less than candidate
2
The sieve of Eratosthenes finds all prime numbers in the range . The algorithm starts with the value 2
(which is a prime number) and then marks all multiples of 2 less than as NOT being a prime number. The
multiples of 2 are 4, 6, 8, …. The next number, 3 has not been marked as NOT being prime, thus it is a prime
number. The algorithm marks all multiples of 3 less than as NOT being a prime number. The number 4 is a
multiple of 2 and was marked as NOT being a prime number before. The number 5 is not a multiple of 2 and 3
and was not marked as NOT being a prime number. Thus 5 is a prime number. The algorithm continues marking
all multiples of 5 as NOT being prime. And so on.
11
Further reading
Derrick G. Kourie, Bruce W. Watson.
The Correctness-by-Construction Approach to Programming.
Springer, 2012.
Anne Kaldewaij.
Programming: The Derivation of Algorithms
Prentice Hall International (UK) Ltd, 1990.
Tom Verhoeff
http://www.win.tue.nl/~wstomv/edu/nma/
See the section “Summer Session 2006” for material for lectures.
Contact
e-mail: sander.kooijmans@hightechict.nl
website HighTech ICT: www.hightechict.nl
website Sander: www.gogognome.nl

More Related Content

PDF
Dotnet programming concepts difference faqs- 3
PDF
Chapter 3 introduction to algorithms handouts (with notes)
PPT
C language UPTU Unit3 Slides
PPTX
The selection sort algorithm
DOCX
C# language basics (Visual studio)
PDF
10. switch case
PPTX
chap4 : Converting and Casting (scjp/ocjp)
PPTX
Selection sort
Dotnet programming concepts difference faqs- 3
Chapter 3 introduction to algorithms handouts (with notes)
C language UPTU Unit3 Slides
The selection sort algorithm
C# language basics (Visual studio)
10. switch case
chap4 : Converting and Casting (scjp/ocjp)
Selection sort

What's hot (6)

PPTX
CPP04 - Selection
PDF
Wade not in unknown waters. Part three.
PDF
Point free or die - tacit programming in Haskell and beyond
PPTX
Unit 5 integrals
PPTX
Switch case in C++
PPTX
25 the ratio, root, and ratio comparison test x
CPP04 - Selection
Wade not in unknown waters. Part three.
Point free or die - tacit programming in Haskell and beyond
Unit 5 integrals
Switch case in C++
25 the ratio, root, and ratio comparison test x
Ad

Similar to How invariants help writing loops (20)

PPTX
#6 formal methods – loop proof using induction method
PDF
Programming methodology lecture07
DOCX
CMIS 102 Hands-On Lab Week 4OverviewThis hands-on lab all.docx
PPTX
Lecture 03 Programming C for Beginners 001
PDF
3.Loops_conditionals.pdf
PPTX
Iterations FOR LOOP AND WHILE LOOP .pptx
PDF
while- loop understanding with -ease.pdf
PDF
Loops and Files
PDF
Loop invarient
PDF
Lecture01a correctness
PDF
Chapter 13.1.5
PDF
Chapter_05HGUYUYGUYGUTFTIVVGUTFGIHGHYIYUIGY
DOCX
Adsa u1 ver 1.0
PPTX
Mastering Python lesson3b_for_loops
DOCX
An Introduction to Computer Science with Java, Python an.docx
PDF
Loops in C Programming | for Loop | do-while Loop | while Loop | Nested Loop
PDF
Real World Haskell: Lecture 2
PPT
C++ CH3-P2 using c++ in all other parts.ppt
PDF
Chp-1 Quick Review of basic concepts.pdf
#6 formal methods – loop proof using induction method
Programming methodology lecture07
CMIS 102 Hands-On Lab Week 4OverviewThis hands-on lab all.docx
Lecture 03 Programming C for Beginners 001
3.Loops_conditionals.pdf
Iterations FOR LOOP AND WHILE LOOP .pptx
while- loop understanding with -ease.pdf
Loops and Files
Loop invarient
Lecture01a correctness
Chapter 13.1.5
Chapter_05HGUYUYGUYGUTFTIVVGUTFGIHGHYIYUIGY
Adsa u1 ver 1.0
Mastering Python lesson3b_for_loops
An Introduction to Computer Science with Java, Python an.docx
Loops in C Programming | for Loop | do-while Loop | while Loop | Nested Loop
Real World Haskell: Lecture 2
C++ CH3-P2 using c++ in all other parts.ppt
Chp-1 Quick Review of basic concepts.pdf
Ad

More from nextbuild (13)

PDF
Aws microservice keynote
PDF
A first taste of integration with Apache Camel
PDF
Effective code reviews
PDF
Microservices in the real world
PDF
Asp.net in a new world
PDF
Meteor - building an email client
PDF
Swimming upstream in the container revolution
PPTX
Event sourcing your AngularJS applications
PDF
Make color schemes a no brainer with sass
PDF
Cqrs from the trenches
PPTX
Architecting for the cloud
PDF
Finally… reliable software!
PDF
Cucumber spec - a tool takes your bdd to the next level
Aws microservice keynote
A first taste of integration with Apache Camel
Effective code reviews
Microservices in the real world
Asp.net in a new world
Meteor - building an email client
Swimming upstream in the container revolution
Event sourcing your AngularJS applications
Make color schemes a no brainer with sass
Cqrs from the trenches
Architecting for the cloud
Finally… reliable software!
Cucumber spec - a tool takes your bdd to the next level

Recently uploaded (20)

PPTX
Spectroscopy.pptx food analysis technology
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
PPTX
TLE Review Electricity (Electricity).pptx
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PPTX
Group 1 Presentation -Planning and Decision Making .pptx
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
Machine Learning_overview_presentation.pptx
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Machine learning based COVID-19 study performance prediction
PDF
Assigned Numbers - 2025 - Bluetooth® Document
PDF
Accuracy of neural networks in brain wave diagnosis of schizophrenia
PDF
Getting Started with Data Integration: FME Form 101
PPTX
cloud_computing_Infrastucture_as_cloud_p
PDF
A comparative study of natural language inference in Swahili using monolingua...
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
NewMind AI Weekly Chronicles - August'25-Week II
Spectroscopy.pptx food analysis technology
Digital-Transformation-Roadmap-for-Companies.pptx
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
TLE Review Electricity (Electricity).pptx
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
MIND Revenue Release Quarter 2 2025 Press Release
Group 1 Presentation -Planning and Decision Making .pptx
Diabetes mellitus diagnosis method based random forest with bat algorithm
Machine Learning_overview_presentation.pptx
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Machine learning based COVID-19 study performance prediction
Assigned Numbers - 2025 - Bluetooth® Document
Accuracy of neural networks in brain wave diagnosis of schizophrenia
Getting Started with Data Integration: FME Form 101
cloud_computing_Infrastucture_as_cloud_p
A comparative study of natural language inference in Swahili using monolingua...
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Per capita expenditure prediction using model stacking based on satellite ima...
NewMind AI Weekly Chronicles - August'25-Week II

How invariants help writing loops

  • 1. 1 How invariants help writing loops Author: Sander Kooijmans Document version: 1.0 Why this document? Did you ever feel frustrated because of a nasty bug in your code? Did you spend hours looking at the code and stepping through complex loops with a debugger? Software engineers must have skills to write correct code. One of these skills is Test-Driven Development (TDD). TDD has received a lot of attention lately, other techniques are overlooked: techniques to prove correctness of algorithms and techniques to derive correct algorithms. In this document I present a technique based on Prof. Dijkstra’s style of proving and deriving algorithms. Predicates Before explaining invariants I will explain what predicates are. A predicate is a function that has a number of variables as input and returns true or false. Take the following two statements: After execution of these two statements the following predicates hold: ≡ ≡ ≡ For brevity we omit the arguments of a predicate. For example: ≡ Hoare triple Tony Hoare invented a technique to prove the correctness of algorithms: Hoare triples. A Hoare triple looks like this: , where and are predicates and is a statement. The Hoare triple means: when holds and is executed, then if terminates then holds. It is important that terminates. If does not terminate does not have to hold. Hoare used these triples to specify how to prove assignments, if-loops, while-loops and composition. In this document I will only focus on while-loops. Hoare triple for a while-loop What is an invariant? An invariant is a predicate which holds before and after each iteration of a loop. An invariant gives meaning to the variables. And an invariant defines the intent of the variables.
  • 2. 2 To prove the while-loop the following four parts must be proven: 1. holds before the while-loop is executed 2. holds after each iteration 3. ⇒ 4. The while-loop terminates is called an invariant. Note that because of part 1 the invariant holds at the beginning of the first iteration. Because of part 2 the invariant holds at the end of the first iteration and therefore at the beginning of the second iteration. And because of part 2 the invariant also holds at the end of the second iteration and therefore at the beginning of the third iteration, and so on. We conclude from parts 1 and 2 that the invariant holds at the beginning and the end of each iteration. The third part states that the invariant can be used to prove the postcondition. And since the loop has terminated you can use the negation of the guard as well to prove the postcondition. The fourth part is obvious. If the loop does never terminate, then there is no guarantee that the postcondition will ever hold. How can you prove that a while-loop terminates? You have to come up with a bound function. A bound function is a function that has all variables of your program as input and returns a number. The bound function must decrease by at least one each iteration and must be bounded from below. You can compare it with a stairs: if you step down a stairs one or more steps each iteration then sooner or later you will reach the end of the stairs and step on the ground. Proving an algorithm to calculate 2n Let me give an example of a while-loop and to illustrate an invariant and bound function. Here is an algorithm that calculates for the input variable . In code I use the notation instead of . The table to the right shows the values of , and before each iteration. Notice that and change each iteration. Also notice that the and are equal in each row in the table. First check the precondition: it states that is at least zero. The postcondition states that the variable is equal to . The invariant states that is equal to . There are four things we have to prove:
  • 3. 3 1. The invariant holds before the while-loop is executed. Fill in and in the invariant: , which is true. 2. The invariant holds after each iteration. Here we can use the fact that the invariant holds at the beginning of the iteration. So at the beginning holds . The assignment doubles the value of . The assignment doubles the value of . The result of the two assignments is that the invariant holds again. Notice that after the first assignment the invariant does not hold. That is not a problem because the invariant holds at the end of the loop. 3. When the loop terminates we know that . Together with the invariant this yields the postcondition: . 4. The bound function decreases with exactly one each iteration. The loop ends with , thus the bound function cannot get below zero. This proves that the loop terminates. This was the most formal part of this document. Do not despair if you didn’t understand the complete proof. From now on this document will be less formal. Professor Edsger Wybe Dijkstra You may know Professor Dijkstra from:  Eindhoven University of Technology where he has worked in the past (and I graduated from that university)  Goto statement considered harmful (also called anti-goto letter)  Semaphores  Dijkstra’s shortest path algorithm  Winning the Turing Award in 1972 There is one more thing that Professor Dijkstra was famous for: he invented a way to develop proof and program hand in hand. What I am going to explain you, is inspired by Dijkstra’s formal way of developing a proof and program. Deriving the algorithm to calculate 2n Let’s write the algorithm to calculate again, but this time we start with the precondition and postcondition: Next we introduce the invariant. The invariant consists of the postcondition where the constant has been replaced by the new variable .
  • 4. 4 The invariant must hold before the loop. So how should we initialize the variables and ? Often the simplest way to initialize is by using ‘simple’ values like 0 or 1. Can we initialize with zero? Then we must choose such that is zero. That is impossible. Thus we must try something else. The precondition states that the smallest valid value for is zero. So let’s try to initialize with zero. When we choose to initialize with zero then the invariant tells us that p must be initialized with the value 1. Next focus on the guard of the while-loop. When should we stop iterating? If then the invariant is equal to the postcondition. We must continue iterating until . So the guard is . Finally we focus on the statements inside the while-loop. We plan on increasing . Increasing by one is the simplest thing we can do. If is increased by 1 then what should we do with ? The right side of the invariant’s equation is doubled when is increased by 1. So we need to double the left side as well. This can be done by multiplying by 2. So the result is: We already proved that the loop terminates using the bound function . Subarray notation The second example is about arrays. I use a particular notation for subarrays that works very will with Dijkstra’s way of deriving programs. Let us review this notation. Let be an array of length 10. Then the following predicates about hold:  represents the complete array  contains , , and .  contains and .
  • 5. 5  Concatenating and results in  contains  is empty  contains elements Sorting red and blue elements using swaps Assume we have an enumeration of colors. It consists of the colors and . Let the variable be an array containing and elements in an arbitrary order. Let us derive an algorithm that sorts the array so that it starts with all s and ends with all s. And as extra limitation we only want to use swaps of two elements at a time to modify the array. We start with writing down the precondition and postcondition: The idea I have to sort the array is as follows: we let the red part ‘grow’ from left to right and let the blue part ‘grow’ from right to left. Look at the image at the right. We use two variables to keep track of the bounds of the red and blue parts. contains only red elements, contains only blue elements. The elements in between, thus , still have to be sorted. Now it is time to formulate the invariant: How do we initialize the while-loop? ? Then we must be sure that is red. And what if ? The easiest choice for is zero: contains zero elements. And all of these zero elements are red. And for the same reason we initialize with . Sounds strange? This is a little bit of mathematics you should know: if you say that ‘something’ is true for all elements of some set then by definition that ‘something’ is true for the empty set. Why? Put simply, the empty set does not contain an element that contradicts that ‘something’. Compare that to summing all numbers in a set. If the set is empty then the sum is zero. Compare that to multiplying all numbers in a set. If the set is empty then the product is one.
  • 6. 6 When should the while-loop terminate? The still have to be sorted. The while-loop should terminate if that segment is empty. That is the case if . Thus the guard of the while- loop is . Now we focus on the body of the while-loop. We want to increase and decrease . When can we increase by one? If is red. So let’s write that down: What if is not red? The precondition tells us that it then must be blue. So we know that is blue. We don’t know anything yet about . What if we swap elements and of the array? Then has become blue and we can then decrease b by one. And if we decrease by one before executing the swap, then we can swap elements and . That gets rid of the minus one: Does this loop terminate? To answer this question we have to come up with a bound function. Look at the while-loop: each iteration either is increased by one or is decreased by one. This inspires me to come up with the bound function . Initially it has the value and it decreases each iteration. The while-loop terminates when . Thus cannot get below zero. This proves that the while-loop terminates for any input.
  • 7. 7 When to apply this technique? Most of the time we write trivial loops. For these loops you don’t need to apply this technique. Or maybe you apply this technique in your mind. Within a couple of seconds you convince yourself about the correctness of the loop you just wrote down. Every now and again a complex loop needs to be written. At those times invariants are a valuable tool to derive and verify your loop. Exercises For each exercise derive: 1. Initialization before the loop 2. The guard 3. The assignments in the body 4. Bound function 5. Write tests to check your solution The exercises start easy and become more and more difficult. Some exercises are marked with the word ‘challenge’. Those exercises require more mathematical insight than the other exercises. Exercise 1: Straightforward loops and empty arrays Given is an array of integers. Can you write a loop that calculates the sum of all elements of the array? What is the sum for an empty array? Can you write a loop that determines the maximum value of the array? What is the maximum value of an empty array? Can you write a loop that checks whether all numbers in the loop are positive numbers? All numbers of the array are positive if . Are all elements of the empty array positive? Can you write a loop that checks whether there exists a number in the array that is negative? A negative number exists in the array if . Does a negative number exist in an empty array?
  • 8. 8 Exercise 2: Another invariant to calculate 2n Above a while-loop was derived that calculates 2n using the invariant . Can you derive a while-loop with the slightly different invariant ? How often iterates the while-loop if is 30? What is the order1 of your solution? Exercise 3: A more efficient implementation to calculate powers (challenge) The goal of this challenge is to write an algorithm that calculates and has order O(log(exponent)). One way of doing that is by using the following property that holds for : 𝑏𝑎𝑠𝑒 𝑒𝑥𝑝𝑜𝑛𝑒𝑛𝑡 = { 𝑏𝑎𝑠𝑒(𝑏𝑎𝑠𝑒2) 𝑒𝑥𝑝𝑜𝑛𝑒𝑛𝑡−1 2 if exponent is odd (𝑏𝑎𝑠𝑒2 ) 𝑒𝑥𝑝𝑜𝑛𝑒𝑛𝑡 2 if exponent is even Hint: Try as invariant Exercise 4: Celebrity problem In a group of persons a celebrity is someone who is known by everyone but does not know anyone. Can you write an algorithm that finds the celebrity? The number of persons in the group is denoted by . The persons are represented by numbers in the range . Hint 1: what does and tell you about or being the celebrity? Hint 2: try as invariant “ ”. (If you like try too and look at the difference in your solutions.) Exercise 5: Maximum subarray problem Given an array of integer numbers. Can you can you find the contiguous subarray which has the largest sum? For example, for the sequence of values -2, 1, -3, 4, -1, 2, 1, -5, 4 the contiguous subarray with the largest sum is 4, -1, 2, 1, with sum 6. Find a solution that uses a single while-loop. 1 The order of an algorithm is denoted by the big O notation. If the algorithm iterates n times, then we say it has order O(n). If an algorithm iterates n2 we say it has order O(n2 ). If the algorithm iterates 3*n2 we still say it has order O(n2 ). Thus we omit the constant factor 3 from the order. The idea behind this notation is that for large values of n the run time is dominated by the factors of n. For example, in the long run 100*n will perform much better than 1*n2 . Thus an algorithm of order O(n) runs faster than an algorithm of order O(n2 ) (for large values of n).
  • 9. 9 Hint 1: scan through the array values, computing at each position the maximum sum of any subarray ending at that position. This subarray is either empty (in which case its sum is zero) or consists of one more element than the maximum subarray ending at the previous position. Hint 2: Let’s call the array . Let be an integer variable. Use the invariant: “maximum sum of , , …, ” and “maximum sum of any subarray of ”. Exercise 6: Dutch national flag problem (sorting three colors) We continue sorting colors. This time we introduce a third color: white. Why white? Because red, white and blue constitute the Dutch national flag and the author of this document happens to be Dutch... Let be an array of red, white and blue elements. Here are the precondition and postcondition: Hint: in the example above we moved the red elements to the start of the array and the blue elements to the end of the array. Can you move the white elements directly after the red elements? Exercise 7: Quicksort (challenge) Transform the algorithm from exercise 6 as follows: instead of colors the array should contain numbers. Choose any element in the array. The value of that element is ‘white’. All elements with the same value are ‘white’. All smaller values are ‘red’ and all higher values are ‘blue’. See what the transformed algorithm does? It divides the array in three parts. The element that you choose to define the white numbers is called the pivot. The red elements contains all numbers that are smaller than the pivot and all blue elements contain all numbers larger than the pivot. This looks like a sorting algorithm for numbers. We still have to sort the red and blue segments. For this you need two recursive calls. After adding these two calls you have implemented Quicksort. This algorithm was developed by Tony Hoare (yes, him from the triples) in 1960. Hint: if the red or blue part contains less than two elements it is already sorted. If the red and blue part have (about) equal lengths, Quicksort operates in O(n*log(n)). However, if the red or blue part is empty, then it degrades to O(n2 ), which is as bad as Bubble Sort and Insertion Sort.
  • 10. 10 Exercise 8: Binary search Let be an array containing numbers. This time the array is sorted ascendingly. Can we use the fact that the array is sorted to quickly determine whether some number is present in the array? Hint 1: which element in the sorted array gives you most information about whether the number is present? The first element, the middle element or the last element? Hint 2: can you halve the remaining subarray that should contain (if is present) each iteration? Hint 3: Use as invariant “if contains then it is in ”. Exercise 9: Primes kata (challenge) If you are familiar with prime numbers and are in for a challenge you can give this exercise a try. Write a function that calculates the prime factors of a given number. For example: given the number 60 the function should return a list containing 2, 3, 5 and 5 because 2*3*5*5=60. Don’t use the sieve of Eratosthenes2 . Instead use two nested while-loops. Hint: use the following three invariants: invariant 1: contains only primes invariant 2: * "product of factors" == invariant 3: has no prime factors less than candidate 2 The sieve of Eratosthenes finds all prime numbers in the range . The algorithm starts with the value 2 (which is a prime number) and then marks all multiples of 2 less than as NOT being a prime number. The multiples of 2 are 4, 6, 8, …. The next number, 3 has not been marked as NOT being prime, thus it is a prime number. The algorithm marks all multiples of 3 less than as NOT being a prime number. The number 4 is a multiple of 2 and was marked as NOT being a prime number before. The number 5 is not a multiple of 2 and 3 and was not marked as NOT being a prime number. Thus 5 is a prime number. The algorithm continues marking all multiples of 5 as NOT being prime. And so on.
  • 11. 11 Further reading Derrick G. Kourie, Bruce W. Watson. The Correctness-by-Construction Approach to Programming. Springer, 2012. Anne Kaldewaij. Programming: The Derivation of Algorithms Prentice Hall International (UK) Ltd, 1990. Tom Verhoeff http://www.win.tue.nl/~wstomv/edu/nma/ See the section “Summer Session 2006” for material for lectures. Contact e-mail: sander.kooijmans@hightechict.nl website HighTech ICT: www.hightechict.nl website Sander: www.gogognome.nl