0% found this document useful (0 votes)
5 views83 pages

Program Correctness: Jorge A. Pérez

The document discusses binary search and monotonic functions. It defines ascending, increasing, descending, and decreasing functions. Binary search works on an ascending array a of length n. It improves on linear search by repeatedly dividing the search space in half. An invariant J is chosen such that the search subarray is non-empty and contains the target value if it exists. A variant function vf is the length of the search subarray to prove termination. The body of the loop narrows the search subarray and updates J and vf accordingly.

Uploaded by

Mhm
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views83 pages

Program Correctness: Jorge A. Pérez

The document discusses binary search and monotonic functions. It defines ascending, increasing, descending, and decreasing functions. Binary search works on an ascending array a of length n. It improves on linear search by repeatedly dividing the search space in half. An invariant J is chosen such that the search subarray is non-empty and contains the target value if it exists. A variant function vf is the length of the search subarray to prove termination. The body of the loop narrows the search subarray and updates J and vf accordingly.

Uploaded by

Mhm
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 83

Program Correctness

Block 5

Jorge A. Pérez
(based on slides by Arnold Meijster)

Bernoulli Institute for Mathematics, Computer Science, and AI


University of Groningen, Groningen, the Netherlands

March 10, 2023


Outline

Linear Search

Binary Search in Ordered Sequences


Massaging the Postcondition
Roadmap

The Dutch National Flag problem

2 / 30
Linear Search

We consider the following specification for computing the least


natural number that satisfies some unspecified property prop:

var k : N;
fP : M = Min fi 2 N j prop (i )g 1g
<

L
fQ : k = M g

I A bi-regular spec: the precondition is constant (it is independent


from variable k ) and the postcondition is of the form x = X .
I From now on, we use pre-regular preconditions anywhere in the
annotation, without carrying it through every step.

3 / 30
Linear Search: Invariant
Notice:
P  M = Min fi 2 N j prop (i )g 1 <

fM 1 (i.e. such an M exists)g


<

 M 2 N ^ prop (M ) ^ 8i 2 N(prop (i ) ) M  i )
0 We will iterate on k to inspect prop (k ), so we need a while.
1 Choose an invariant J and a guard B such that J ^ :B ) Q.

J :0k M
B : :prop (k )

4 / 30
Linear Search: Invariant
Notice:
P  M = Min fi 2 N j prop (i )g 1 <

fM 1 (i.e. such an M exists)g


<

 M 2 N ^ prop (M ) ^ 8i 2 N(prop (i ) ) M  i )
0 We will iterate on k to inspect prop (k ), so we need a while.
1 Choose an invariant J and a guard B such that J ^ :B ) Q.

J :0k M
B : :prop (k )
J ^ :B  0  k  M ^ prop (k )
fprop (k ) ^ P g
) 0k M ^M k
) Q : k =M
4 / 30
Linear Search: Initialization & Variant

P :M = Min fi 2 N j prop (i )g 1g
<

J :0k M
B : :prop (k )
Q :k = M

2 Initialization: Find a command T0 such that ftrueg T0 fJ g


Note that we use the precondition true, since P is pre-regular.
ftrueg
(* use conjunct M 2 N of P *)
f0  0  M g
k := 0;
fJ : 0  k  M g
3 Variant function: Choose a vf 2 Z and prove J ^ B ) vf 0
We choose vf = M k . Clearly, J ^ B ) M k  0
5 / 30
Linear Search: Body of the Loop

fJ ^ B ^ vf = Vg

fJ ^ vf < Vg

6 / 30
Linear Search: Body of the Loop

fJ ^ B ^ vf = Vg
(* definitions J , B and vf *)
f0  k  M ^ :prop (k ) ^ M k = Vg

fJ ^ vf < Vg

6 / 30
Linear Search: Body of the Loop

fJ ^ B ^ vf = Vg
(* definitions J , B and vf *)
f0  k  M ^ :prop (k ) ^ M k = V g
(* P ) prop (M ); 0  k  M ^ prop (M ) ^ :prop (k ) ) k 6= M *)
f0  k < M ^ M k = V g

fJ ^ vf < Vg

6 / 30
Linear Search: Body of the Loop

fJ ^ B ^ vf = Vg
(* definitions J , B and vf *)
f0  k  M ^ :prop (k ) ^ M k = V g
(* P ) prop (M ); 0  k  M ^ prop (M ) ^ :prop (k ) ) k 6= M *)
f0  k < M ^ M k = V g
(* prepare k := k + 1 *)
f0  k + 1  M ^ M (k + 1) < V g

fJ ^ vf < Vg

6 / 30
Linear Search: Body of the Loop

fJ ^ B ^ vf = Vg
(* definitions J , B and vf *)
f0  k  M ^ :prop (k ) ^ M k = V g
(* P ) prop (M ); 0  k  M ^ prop (M ) ^ :prop (k ) ) k 6= M *)
f0  k < M ^ M k = V g
(* prepare k := k + 1 *)
f0  k + 1  M ^ M (k + 1) < V g
k := k + 1;

fJ ^ vf < Vg

6 / 30
Linear Search: Body of the Loop

fJ ^ B ^ vf = Vg
(* definitions J , B and vf *)
f0  k  M ^ :prop (k ) ^ M k = V g
(* P ) prop (M ); 0  k  M ^ prop (M ) ^ :prop (k ) ) k 6= M *)
f0  k < M ^ M k = V g
(* prepare k := k + 1 *)
f0  k + 1  M ^ M (k + 1) < V g
k := k + 1;
f0  k  M ^ M k < V g
fJ ^ vf < Vg

6 / 30
Linear Search: Body of the Loop

fJ ^ B ^ vf = Vg
(* definitions J , B and vf *)
f0  k  M ^ :prop (k ) ^ M k = V g
(* P ) prop (M ); 0  k  M ^ prop (M ) ^ :prop (k ) ) k 6= M *)
f0  k < M ^ M k = V g
(* prepare k := k + 1 *)
f0  k + 1  M ^ M (k + 1) < V g
k := k + 1;
f0  k  M ^ M k < V g
(* definitions J , and vf *)
fJ ^ vf < V g

6 / 30
Linear Search: Conclusion

We derived the program fragment (linear search algorithm):

var k : Z;
fP : M = Min fi 2 N j prop (i )g < 1g
k := 0;
fJ : 0  k  M g
(* vf = M k *)
while :prop (k ) do
k := k + 1;
end;
fQ : k = M g

7 / 30
Application: Linear Search in an Array

Given an array a of length n and a value w , compute the smallest i


such that a [i ] = w .
If such an index does not exist, the result should be n.

8 / 30
Application: Linear Search in an Array

Given an array a of length n and a value w , compute the smallest i


such that a [i ] = w .
If such an index does not exist, the result should be n.

const n : N; w : Z; a : array [0::n ) of R;


var k : N;
fP : M = Min fi 2 N j a [i ] = w _ n  i gg
S
fQ : k = M g
Note that M  n, so M 1.<

(This is Specification (8.2) in the reader.)

8 / 30
Application: Linear Search in an Array

We instantiate prop (i )  (n  i _ a [i ] = w ) in the linear search


algorithm we derived. Note that :prop (i )  (i < n ^ a [i ] 6= w ):

var k : Z;
fP : M = Min fi 2 N j n  i _ a [i ] = w gg
k := 0;
fJ : 0  k  M g
(* vf = M k *)
while k < n ^ a [k ] 6= w do (* short circuit evaluation *)
k := k + 1;
end;
fQ : k = M g

9 / 30
Outline

Linear Search

Binary Search in Ordered Sequences


Massaging the Postcondition
Roadmap

The Dutch National Flag problem

10 / 30
Up to Here...

We have seen:
I The roadmap for designing repetitions
I Linear search (Ch 8.1)

Coming next:
I Binary search (Ch 8.2)
I The Dutch National Flag problem (Ch 8.4)
I Chapters 10 and 9

11 / 30
Up to Here...

We have seen:
I The roadmap for designing repetitions
I Linear search (Ch 8.1)

Coming next:
I Binary search (Ch 8.2)
I The Dutch National Flag problem (Ch 8.4)
I Chapters 10 and 9

We shall use additional keywords to express conditions within


annotated linear proofs:
I suppose, define, assume, introduce, ...
Useful when deriving side conditions for recurrence relations.

11 / 30
Monotonic functions

It is convenient to distinguish ordered arrays.


Let V be an interval of Z, and let f : V ! R be a function (a
sequence of numbers).
We say f is
I ascending ( / ): if 8i ; j 2 V : (i  j ) f (i )  f (j ))

12 / 30
Monotonic functions

It is convenient to distinguish ordered arrays.


Let V be an interval of Z, and let f : V ! R be a function (a
sequence of numbers).
We say f is
I ascending ( / ): if 8i ; j 2 V : (i  j ) f (i )  f (j ))
I increasing (< / <): if 8i ; j 2 V : (i j ) f (i ) f (j ))
< <

12 / 30
Monotonic functions

It is convenient to distinguish ordered arrays.


Let V be an interval of Z, and let f : V ! R be a function (a
sequence of numbers).
We say f is
I ascending ( / ): if 8i ; j 2 V : (i  j ) f (i )  f (j ))
I increasing (< / <): if 8i ; j2 V : (i j ) f (i ) f (j ))
< <

I descending ( / ): if 8i j 2 V : (i  j ) f (i )  f (j ))
;

I decreasing ( / ): if 8i j 2 V : (i j ) f (i ) f (j ))
< > ; < >

12 / 30
Monotonic functions

It is convenient to distinguish ordered arrays.


Let V be an interval of Z, and let f : V ! R be a function (a
sequence of numbers).
We say f is
I ascending ( / ): if 8i ; j 2 V : (i  j ) f (i )  f (j ))
I increasing (< / <): if 8i ; j2 V : (i j ) f (i ) f (j ))
< <

I descending ( / ): if 8i j 2 V : (i  j ) f (i )  f (j ))
;

I decreasing ( / ): if 8i j 2 V : (i j ) f (i ) f (j ))
< > ; < >

f is called monotonic if it has one of the above properties.

12 / 30
Binary Search
Consider now an ascending array a, with lenght n.
Given a value w , compute the smallest index k such that a [k ] = w .
If such an index does not exist, the result should be k = n.

Q: Why is it relevant that a is ascending?

13 / 30
Binary Search
Consider now an ascending array a, with lenght n.
Given a value w , compute the smallest index k such that a [k ] = w .
If such an index does not exist, the result should be k = n.

Q: Why is it relevant that a is ascending?


A: If a is ascending and w occurs in a then
the smallest k s.t. a [k ] = w is also the smallest k s.t. w  a [k ].
(Relevant if w doesn’t occur in a.)

13 / 30
Binary Search
Consider now an ascending array a, with lenght n.
Given a value w , compute the smallest index k such that a [k ] = w .
If such an index does not exist, the result should be k = n.

Q: Why is it relevant that a is ascending?


A: If a is ascending and w occurs in a then
the smallest k s.t. a [k ] = w is also the smallest k s.t. w  a [k ].
(Relevant if w doesn’t occur in a.)

We use the following specification:


const n : N; w : Z; a : array [0::n ) of R;
var k : N;
fP : a is ascendingg
S
fQ : k = Min fi 2 N j n  i _ w  a [i ]gg

13 / 30
Binary Search
Consider now an ascending array a, with lenght n.
Given a value w , compute the smallest index k such that a [k ] = w .
If such an index does not exist, the result should be k = n.

Q: Why is it relevant that a is ascending?


A: If a is ascending and w occurs in a then
the smallest k s.t. a [k ] = w is also the smallest k s.t. w  a [k ].
(Relevant if w doesn’t occur in a.)

We use the following specification:


const n : N; w : Z; a : array [0::n ) of R;
var k : N;
fP : a is ascendingg
S
fQ : k = Min fi 2 N j n  i _ w  a [i ]gg
To enforce the informal specification, we need an active finalization:
if k < n ^ a [k ] 6= w then k := n end; 13 / 30
Massaging the Postcondition
Q :k = Min fi 2 N j n  i _ w  a [i ]g

14 / 30
Massaging the Postcondition
Q : k = Min fi 2 N j n  i _ w  a [i ]g
 fproperties of Min g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N((n  i _ w  a [i ]) ) k  i )

14 / 30
Massaging the Postcondition
Q : k = Min fi 2 N j n  i _ w  a [i ]g
 fproperties of Min g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N((n  i _ w  a [i ]) ) k  i )
 fcontraposition: p ) q  :q ) :p g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) (i n ^ a [i ] w ))
< < <

14 / 30
Massaging the Postcondition
Q : k = Min fi 2 N j n  i _ w  a [i ]g
 fproperties of Min g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N((n  i _ w  a [i ]) ) k  i )
 fcontraposition: p ) q  :q ) :p g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) (i n ^ a [i ] w ))
< < <

 f8i 2 N(i k ) i n )  k  n arithmeticg


< < ;

0  k  n ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

14 / 30
Massaging the Postcondition
Q : k = Min fi 2 N j n  i _ w  a [i ]g
 fproperties of Min g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N((n  i _ w  a [i ]) ) k  i )
 fcontraposition: p ) q  :q ) :p g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) (i n ^ a [i ] w ))
< < <

 f8i 2 N(i k ) i n )  k  n arithmeticg


< < ;

0  k  n ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

 fcalculus; logicg
0  k  n ^ (k = n _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

14 / 30
Massaging the Postcondition
Q : k = Min fi 2 N j n  i _ w  a [i ]g
 fproperties of Min g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N((n  i _ w  a [i ]) ) k  i )
 fcontraposition: p ) q  :q ) :p g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) (i n ^ a [i ] w ))
< < <

 f8i 2 N(i k ) i n )  k  n arithmeticg


< < ;

0  k  n ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

 fcalculus; logicg
0  k  n ^ (k = n _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

 flogic; array a is ascendingg


0  k  n ^ (k = n _ w  a [k ]) ^ (k = 0 _ a [k 1] w )<

14 / 30
Massaging the Postcondition
Q : k = Min fi 2 N j n  i _ w  a [i ]g
 fproperties of Min g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N((n  i _ w  a [i ]) ) k  i )
 fcontraposition: p ) q  :q ) :p g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) (i n ^ a [i ] w ))
< < <

 f8i 2 N(i k ) i n )  k  n arithmeticg


< < ;

0  k  n ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

 fcalculus; logicg
0  k  n ^ (k = n _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

 flogic; array a is ascendingg


0  k  n ^ (k = n _ w  a [k ]) ^ (k = 0 _ a [k 1] w )<

 fdefine: a [ 1] = 1 and a [n ] = 1g

14 / 30
Massaging the Postcondition
Q : k = Min fi 2 N j n  i _ w  a [i ]g
 fproperties of Min g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N((n  i _ w  a [i ]) ) k  i )
 fcontraposition: p ) q  :q ) :p g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) (i n ^ a [i ] w ))
< < <

 f8i 2 N(i k ) i n )  k  n arithmeticg


< < ;

0  k  n ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

 fcalculus; logicg
0  k  n ^ (k = n _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

 flogic; array a is ascendingg


0  k  n ^ (k = n _ w  a [k ]) ^ (k = 0 _ a [k 1] w )<

 fdefine: a [ 1] = 1 and a [n ] = 1g
0  k  n ^ w  a [k ] ^ a [k 1] w <

14 / 30
Massaging the Postcondition
Q : k = Min fi 2 N j n  i _ w  a [i ]g
 fproperties of Min g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N((n  i _ w  a [i ]) ) k  i )
 fcontraposition: p ) q  :q ) :p g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) (i n ^ a [i ] w ))
< < <

 f8i 2 N(i k ) i n )  k  n arithmeticg


< < ;

0  k  n ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

 fcalculus; logicg
0  k  n ^ (k = n _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

 flogic; array a is ascendingg


0  k  n ^ (k = n _ w  a [k ]) ^ (k = 0 _ a [k 1] w )<

 fdefine: a [ 1] = 1 and a [n ] = 1g
0  k  n ^ w  a [k ] ^ a [k 1] w <

 frewritingg
Q : 0  k  n ^ a [k 1] w  a [k ]
<

14 / 30
Massaging the Postcondition
Q : k = Min fi 2 N j n  i _ w  a [i ]g
 fproperties of Min g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N((n  i _ w  a [i ]) ) k  i )
 fcontraposition: p ) q  :q ) :p g
0  k ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) (i n ^ a [i ] w ))
< < <

 f8i 2 N(i k ) i n )  k  n arithmeticg


< < ;

0  k  n ^ (n  k _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

 fcalculus; logicg
0  k  n ^ (k = n _ w  a [k ]) ^ 8i 2 N(i k ) a [i ] w )
< <

 flogic; array a is ascendingg


0  k  n ^ (k = n _ w  a [k ]) ^ (k = 0 _ a [k 1] w ) <

 fdefine: a [ 1] = 1 and a [n ] = 1g
0  k  n ^ w  a [k ] ^ a [k 1] w <

 frewritingg
Q : 0  k  n ^ a [k 1] w  a [k ]
<

Note: The program will not inspect a [ 1] and a [n ]. Indeed, k = 0


and k = n are only needed to reason about boundary cases. 14 / 30
Binary Search: Invariant and Guard
Revising the postcondition, we obtain the following specification:

const n : N; w : Z; a : array [0::n ) of R;


var k : N;
fP : a is ascending; a [ 1] = 1 ^ a [n ] = 1g
B
fQ : 0  k  n ^ a [k 1] < w  a [k ]g

15 / 30
Binary Search: Invariant and Guard
Revising the postcondition, we obtain the following specification:

const n : N; w : Z; a : array [0::n ) of R;


var k : N;
fP : a is ascending; a [ 1] = 1 ^ a [n ] = 1g
B
fQ : 0  k  n ^ a [k 1] < w  a [k ]g
0 We decide that we need a while-program:
We will inspect the array a iteratively for several indices.
1 Choose an invariant J and a guard B such that J ^ :B ) Q.
We use the heuristic split variable, with the new variable j :

J :0j k n ^ a [j 1] < w  a [k ]
B :j 6= k
Clearly, J ^ :B ) Q.
15 / 30
Binary Search: Initialization & Variant

P : a is ascending; a [ 1] = 1 ^ a [n ] = 1
J :0j k n ^ a [j 1] w  a [k ]
<

B :j 6= k
2 Initialization: Because P is pre-regular, we can use true as
precondition. We find a command T0 such that ftrueg T0 fJ g.
ftrueg
(* n 2 N; calculus; use P *)
f0  0  n  n ^ a [0 1] w  a [n ]g
<

j :=0; k := n ;
fJ : 0  j  k n ^ a [j 1] w  a [k ]g
<

3 Variant function: Choose a vf 2 Z and prove J ^ B ) vf  0.


We choose vf = k j 2 Z. Clearly, J ^ B ) vf  0.

16 / 30
Binary Search: Body of the Loop
We will be working towards a body of the following form:

fJ ^ B ^ vf = Vg
S0 ;
fJ ^ vf = V ^ j m < kg
if a [m ] < w then
j := m + 1;
else
k := m ;
end
fJ ^ vf < V g
I Clearly, S0 should involve an assignment to m, which is a point
in the interval formed by j and k .
I Both ‘m := j ’ or ‘m := k 1’ are alternatives, but we would like
to reduce by half the search area.
I Hence, we shall consider ‘m := (j + k ) div 2’.
17 / 30
Binary Search: Body of the Loop
fJ ^ B ^ vf = Vg

fJ ^ vf < Vg
18 / 30
Binary Search: Body of the Loop
fJ ^ B ^ vf = V g
f0  j  k  n ^ a [j 1] < w  a [k ] ^ j =6 k ^ k j = Vg

if a [m ] < w then

j := m + 1;

else

k := m;

end
fJ ^ vf < Vg
18 / 30
Binary Search: Body of the Loop
fJ ^ B ^ vf = V g
f0  j  k  n ^ a [j 1] w  a [k ] ^ j 6= k ^ k j = V g
<

(* (j  k ^ j k )  (j + j  j + k ^ j + k k + k )  2  j  j + k
< < < 2  k *)
f0  j  (j + k ) div 2 k  n ^ a [j 1] w  a [k ] ^ k j = V g
< <

if a [m ] < w then

j := m + 1;

else

k := m;

end
fJ ^ vf < Vg
18 / 30
Binary Search: Body of the Loop
fJ ^ B ^ vf = V g
f0  j  k  n ^ a [j 1] w  a [k ] ^ j 6= k ^ k j = V g
<

(* (j  k ^ j k )  (j + j  j + k ^ j + k k + k )  2  j  j + k
< < < 2  k *)
f0  j  (j + k ) div 2 k  n ^ a [j 1] w  a [k ] ^ k j = V g
< <

m := (j + k )div 2;
f0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = Vg
if a [m ] < w then

j := m + 1;

else

k := m;

end
fJ ^ vf < Vg
18 / 30
Binary Search: Body of the Loop
fJ ^ B ^ vf = V g
f0  j  k  n ^ a [j 1] w  a [k ] ^ j 6= k ^ k j = V g
<

(* (j  k ^ j k )  (j + j  j + k ^ j + k k + k )  2  j  j + k
< < < 2  k *)
f0  j  (j + k ) div 2 k  n ^ a [j 1] w  a [k ] ^ k j = V g
< <

m := (j + k ) div 2;
f0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = Vg
if a [m ] < w then
fa [m ] < w ^ 0  j  m < k n ^ a [j 1] < w  a [k ] ^ k j = Vg

j := m + 1;

else
fw  a [m ] ^ 0  j  m < k n ^ a [j 1] < w  a [k ] ^ k j = Vg

k := m;

end
fJ ^ vf < Vg
18 / 30
Binary Search: Body of the Loop
fJ ^ B ^ vf = V g
f0  j  k  n ^ a [j 1] w  a [k ] ^ j 6= k ^ k j = V g
<

(* (j  k ^ j k )  (j + j  j + k ^ j + k k + k )  2  j  j + k
< < < 2  k *)
f0  j  (j + k ) div 2 k  n ^ a [j 1] w  a [k ] ^ k j = V g
< <

m := (j + k ) div 2;
f0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
if a [m ] < w then
fa [m ] < w ^ 0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
(* logic; calculus; prepare j := m + 1 *)
f0  m + 1  k  n ^ a [m + 1 1] < w  a [k ] ^ k (m + 1) < V g
j := m + 1;

else
fw  a [m ] ^ 0  j  m < k n ^ a [j 1] < w  a [k ] ^ k j = Vg

k := m;

end
fJ ^ vf < Vg
18 / 30
Binary Search: Body of the Loop
fJ ^ B ^ vf = V g
f0  j  k  n ^ a [j 1] w  a [k ] ^ j 6= k ^ k j = V g
<

(* (j  k ^ j k )  (j + j  j + k ^ j + k k + k )  2  j  j + k
< < < 2  k *)
f0  j  (j + k ) div 2 k  n ^ a [j 1] w  a [k ] ^ k j = V g
< <

m := (j + k ) div 2;
f0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
if a [m ] < w then
fa [m ] < w ^ 0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
(* logic; calculus; prepare j := m + 1 *)
f0  m + 1  k  n ^ a [m + 1 1] < w  a [k ] ^ k (m + 1) < V g
j := m + 1;
f0  j  k  n ^ a [j 1] < w  a [k ] ^ k j < V g
else
fw  a [m ] ^ 0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g

k := m;

end
fJ ^ vf < Vg
18 / 30
Binary Search: Body of the Loop
fJ ^ B ^ vf = V g
f0  j  k  n ^ a [j 1] w  a [k ] ^ j 6= k ^ k j = V g
<

(* (j  k ^ j k )  (j + j  j + k ^ j + k k + k )  2  j  j + k
< < < 2  k *)
f0  j  (j + k ) div 2 k  n ^ a [j 1] w  a [k ] ^ k j = V g
< <

m := (j + k ) div 2;
f0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
if a [m ] < w then
fa [m ] < w ^ 0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
(* logic; calculus; prepare j := m + 1 *)
f0  m + 1  k  n ^ a [m + 1 1] < w  a [k ] ^ k (m + 1) < V g
j := m + 1;
f0  j  k  n ^ a [j 1] < w  a [k ] ^ k j < V g
else
fw  a [m ] ^ 0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
(* logic; calculus; prepare k := m *)
f0  j  m  n ^ a [j 1] < w  a [m ] ^ m j < V g
k := m ;

end
fJ ^ vf < Vg
18 / 30
Binary Search: Body of the Loop
fJ ^ B ^ vf = V g
f0  j  k  n ^ a [j 1] w  a [k ] ^ j 6= k ^ k j = V g
<

(* (j  k ^ j< k )  (j + j  j + k ^ j + k k + k )  2  j  j + k
< < 2  k *)
f0  j  (j + k ) div 2 k  n ^ a [j 1] w  a [k ] ^ k j = V g
< <

m := (j + k ) div 2;
f0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
if a [m ] < w then
fa [m ] < w ^ 0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
(* logic; calculus; prepare j := m + 1 *)
f0  m + 1  k  n ^ a [m + 1 1] < w  a [k ] ^ k (m + 1) < V g
j := m + 1;
f0  j  k  n ^ a [j 1] < w  a [k ] ^ k j < V g
else
fw  a [m ] ^ 0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
(* logic; calculus; prepare k := m *)
f0  j  m  n ^ a [j 1] < w  a [m ] ^ m j < V g
k := m ;
f0  j  k  n ^ a [j 1] < w  a [k ] ^ k j < V g
end
fJ ^ vf < V g
18 / 30
Binary Search: Body of the Loop
fJ ^ B ^ vf = V g
f0  j  k  n ^ a [j 1] w  a [k ] ^ j 6= k ^ k j = V g
<

(* (j  k ^ j< k )  (j + j  j + k ^ j + k k + k )  2  j  j + k
< < 2  k *)
f0  j  (j + k ) div 2 k  n ^ a [j 1] w  a [k ] ^ k j = V g
< <

m := (j + k ) div 2;
f0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
if a [m ] < w then
fa [m ] < w ^ 0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
(* logic; calculus; prepare j := m + 1 *)
f0  m + 1  k  n ^ a [m + 1 1] < w  a [k ] ^ k (m + 1) < V g
j := m + 1;
f0  j  k  n ^ a [j 1] < w  a [k ] ^ k j < V g
else
fw  a [m ] ^ 0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
(* logic; calculus; prepare k := m *)
f0  j  m  n ^ a [j 1] < w  a [m ] ^ m j < V g
k := m ;
f0  j  k  n ^ a [j 1] < w  a [k ] ^ k j < V g
end
fJ ^ vf < V g
18 / 30
Binary Search: Body of the Loop
fJ ^ B ^ vf = V g
f0  j  k  n ^ a [j 1] w  a [k ] ^ j 6= k ^ k j = V g
<

(* (j  k ^ j< k )  (j + j  j + k ^ j + k k + k )  2  j  j + k
< < 2  k *)
f0  j  (j + k ) div 2 k  n ^ a [j 1] w  a [k ] ^ k j = V g
< <

m := (j + k ) div 2;
f0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
if a [m ] < w then
fa [m ] < w ^ 0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
(* logic; calculus; prepare j := m + 1 *)
f0  m + 1  k  n ^ a [m + 1 1] < w  a [k ] ^ k (m + 1) < V g
j := m + 1;
f0  j  k  n ^ a [j 1] < w  a [k ] ^ k j < V g
else
fw  a [m ] ^ 0  j  m < k  n ^ a [j 1] < w  a [k ] ^ k j = V g
(* logic; calculus; prepare k := m *)
f0  j  m  n ^ a [j 1] < w  a [m ] ^ m j < V g
k := m ;
f0  j  k  n ^ a [j 1] < w  a [k ] ^ k j < V g
end (* collect branches; definitions J and vf *)
fJ ^ vf < V g
18 / 30
Binary Search: Conclusion
const n : N; w : Z; a : array [0::n ) of R;
var k ; j ; m : N;
fP : a is ascendingg
j := 0; k := n ;
fJ : 0  j  k  n ^ a [j 1] < w  a [k ]g
(* vf = k j *)
while j 6= k do
m := (j + k ) div 2;
if a [m ] < w then
j := m + 1;
else
k := m ;
end;
end;
fk = Min fi 2 N j i < n ) w  a [i ]gg
if k < n ^ a [k ] 6= w then
k := n ;
end;
fQ : k = Min fi 2 N j i < n ) w = a [i ]gg
19 / 30
Outline

Linear Search

Binary Search in Ordered Sequences


Massaging the Postcondition
Roadmap

The Dutch National Flag problem

20 / 30
The Dutch National Flag problem (DNFP)

I A sorting problem introduced by Dijkstra.


I Input: An array of red, white, and blue balls.
Output: The array re-arranged in a such way that balls of the
same color are gathered together.

21 / 30
The Dutch National Flag problem (DNFP)

I A sorting problem introduced by Dijkstra.


I Input: An array of red, white, and blue balls.
Output: The array re-arranged in a such way that balls of the
same color are gathered together.
I Example: Given an array such as
                
the task is to transform it into
                

21 / 30
The Dutch National Flag problem (DNFP)

I A sorting problem introduced by Dijkstra.


I Input: An array of red, white, and blue balls.
Output: The array re-arranged in a such way that balls of the
same color are gathered together.
I Example: Given an array such as
                
the task is to transform it into
                
I Notice: the array can only be modified by swapping two
elements.
I We seek an efficient iterative procedure.
As we will see, the choice of the invariant will be crucial.

21 / 30
DNFP: Statement
I An array a of length n, which stores three sorts of elements
(denoted 0, 1, and 2, representing the balls of different colors).

22 / 30
DNFP: Statement
I An array a of length n, which stores three sorts of elements
(denoted 0, 1, and 2, representing the balls of different colors).
I For each index i 2 [0::n ), we have a [i ] = 0 _ a [i ] = 1 _ a [i ] = 2.

22 / 30
DNFP: Statement
I An array a of length n, which stores three sorts of elements
(denoted 0, 1, and 2, representing the balls of different colors).
I For each index i 2 [0::n ), we have a [i ] = 0 _ a [i ] = 1 _ a [i ] = 2.
I We can swap elements, assuming the following specification:
f0  i = I < n ^ 0j =J < n ^ a [i ] = X ^ a [j ] = Y g
swap(i ; j )
fi = I ^ j = J ^ a [i ] = Y ^ a [j ] = X g

22 / 30
DNFP: Statement
I An array a of length n, which stores three sorts of elements
(denoted 0, 1, and 2, representing the balls of different colors).
I For each index i 2 [0::n ), we have a [i ] = 0 _ a [i ] = 1 _ a [i ] = 2.
I We can swap elements, assuming the following specification:
f0  i = I < n ^ 0j =J < n ^ a [i ] = X ^ a [j ] = Y g
swap(i ; j )
fi = I ^ j = J ^ a [i ] = Y ^ a [j ] = X g
I We look for a command that, after termination, ensures that
there are indices r and w such that:

0r w n
^ (8i : 0  i r a [i ] = 0)
< ;

^ (8i : r  i w a [i ] = 1)
< ;

^ (8i : w  i n a [i ] = 2)
< ;

Note: This postcondition allows for zero balls of each color.


22 / 30
DNFP: Invariant (1/3)

What is a good invariant for the required an iterative process?


I At the beginning all balls are mixed; at the end, they are sorted.
These should be two special cases of our invariant.

23 / 30
DNFP: Invariant (1/3)

What is a good invariant for the required an iterative process?


I At the beginning all balls are mixed; at the end, they are sorted.
These should be two special cases of our invariant.
I It is natural to design an invariant that partitions the array into
four segments: red, white, blue, and ‘mixed’ (unsorted).
I At the beginning, the first three segments are empty and the
mixed segment covers the entire array.
I At the end, the mixed segment is empty.

23 / 30
DNFP: Invariant (2/3)
What is a good invariant for the required an iterative process?
I It is natural to design an invariant that partitions the array into
four segments: red, white, blue, and ‘mixed’ (unsorted).
I There are four alternatives:

24 / 30
DNFP: Invariant (2/3)
What is a good invariant for the required an iterative process?
I It is natural to design an invariant that partitions the array into
four segments: red, white, blue, and ‘mixed’ (unsorted).
I There are four alternatives:

0 n
red white blue unsorted

24 / 30
DNFP: Invariant (2/3)
What is a good invariant for the required an iterative process?
I It is natural to design an invariant that partitions the array into
four segments: red, white, blue, and ‘mixed’ (unsorted).
I There are four alternatives:

0 n
red white blue unsorted
0 n
red white unsorted blue

24 / 30
DNFP: Invariant (2/3)
What is a good invariant for the required an iterative process?
I It is natural to design an invariant that partitions the array into
four segments: red, white, blue, and ‘mixed’ (unsorted).
I There are four alternatives:

0 n
red white blue unsorted
0 n
red white unsorted blue
0 n
red unsorted white blue

24 / 30
DNFP: Invariant (2/3)
What is a good invariant for the required an iterative process?
I It is natural to design an invariant that partitions the array into
four segments: red, white, blue, and ‘mixed’ (unsorted).
I There are four alternatives:

0 n
red white blue unsorted
0 n
red white unsorted blue
0 n
red unsorted white blue
0 n
unsorted red white blue

I What (dis)advantages do you find in each of these options?


24 / 30
DNFP: Invariant (3/3)
I The preferable option is to maintain the ‘mixed’ segment in the
interior of the array (why?)

25 / 30
DNFP: Invariant (3/3)
I The preferable option is to maintain the ‘mixed’ segment in the
interior of the array (why?)
I The invariant modifies the postcondition by introducing a new
index/variable b:
0r w bn
^ (8i : 0  i < r ; a [ i ] = 0)
^ (8i : r  i < w ; a [i ] = 1)
^ (8i : b  i < n ; a [i ] = 2)

The indices i such that w  i < b define the ‘mixed’ segment.

Graphically:
0 r w b n
red white unsorted blue
I With this invariant, the variant function is
The guard of the loop is
25 / 30
DNFP: Invariant (3/3)
I The preferable option is to maintain the ‘mixed’ segment in the
interior of the array (why?)
I The invariant modifies the postcondition by introducing a new
index/variable b:
0r w bn
^ (8i : 0  i < r ; a [ i ] = 0)
^ (8i : r  i < w ; a [i ] = 1)
^ (8i : b  i < n ; a [i ] = 2)

The indices i such that w  i < b define the ‘mixed’ segment.

Graphically:
0 r w b n
red white unsorted blue
I With this invariant, the variant function is vf = b w .
The guard of the loop is
25 / 30
DNFP: Invariant (3/3)
I The preferable option is to maintain the ‘mixed’ segment in the
interior of the array (why?)
I The invariant modifies the postcondition by introducing a new
index/variable b:
0r w bn
^ (8i : 0  i < r ; a [ i ] = 0)
^ (8i : r  i < w ; a [i ] = 1)
^ (8i : b  i < n ; a [i ] = 2)

The indices i such that w  i < b define the ‘mixed’ segment.

Graphically:
0 r w b n
red white unsorted blue
I With this invariant, the variant function is vf = b w .
The guard of the loop is B : w < b.
25 / 30
DNFP: Idea of the Body (1/3)

In the general case, we have:

r w b n
0 0 0 0 0 0 1 1 1 ? ? ? ? 2 2 2 2

We act depending on the color of the element at index w .


First case:
I If a [w ] = 1 then
0 0 0 0 0 0 1 1 1 1 ? ? ? 2 2 2 2
and so it suffices to execute

26 / 30
DNFP: Idea of the Body (1/3)

In the general case, we have:

r w b n
0 0 0 0 0 0 1 1 1 ? ? ? ? 2 2 2 2

We act depending on the color of the element at index w .


First case:
I If a [w ] = 1 then
0 0 0 0 0 0 1 1 1 1 ? ? ? 2 2 2 2
and so it suffices to execute

w := w +1

26 / 30
DNFP: Idea of the Body (1/3)

In the general case, we have:

r w b n
0 0 0 0 0 0 1 1 1 ? ? ? ? 2 2 2 2

We act depending on the color of the element at index w .


First case:
I If a [w ] = 1 then
0 0 0 0 0 0 1 1 1 1 ? ? ? 2 2 2 2
and so it suffices to execute

w := w +1

This yields:
0 0 0 0 0 0 1 1 1 1 ? ? ? 2 2 2 2

26 / 30
DNFP: Idea of the Body (2/3)
In the general case, we have:

r w b n
0 0 0 0 0 0 1 1 1 ? ? ? ? 2 2 2 2

We act depending on the color of the element at index w .


Second case:
I If a [w ] = 2 then
0 0 0 0 0 0 1 1 1 2 ? ? ? 2 2 2 2
and so we execute

27 / 30
DNFP: Idea of the Body (2/3)
In the general case, we have:

r w b n
0 0 0 0 0 0 1 1 1 ? ? ? ? 2 2 2 2

We act depending on the color of the element at index w .


Second case:
I If a [w ] = 2 then
0 0 0 0 0 0 1 1 1 2 ? ? ? 2 2 2 2
and so we execute

swap(b 1; w );
b := b 1

27 / 30
DNFP: Idea of the Body (2/3)
In the general case, we have:

r w b n
0 0 0 0 0 0 1 1 1 ? ? ? ? 2 2 2 2

We act depending on the color of the element at index w .


Second case:
I If a [w ] = 2 then
0 0 0 0 0 0 1 1 1 2 ? ? ? 2 2 2 2
and so we execute

swap(b 1; w );
b := b 1

This yields:
0 0 0 0 0 0 1 1 1 ? ? ? 2 2 2 2 2
27 / 30
DNFP: Idea of the Body (3/3)
In the general case, we have:

r w b n
0 0 0 0 0 0 1 1 1 ? ? ? ? 2 2 2 2

We act depending on the color of the element at index w .


Final case:
I If a [w ] = 0 then
0 0 0 0 0 0 1 1 1 0 ? ? ? 2 2 2 2
and so we execute

28 / 30
DNFP: Idea of the Body (3/3)
In the general case, we have:

r w b n
0 0 0 0 0 0 1 1 1 ? ? ? ? 2 2 2 2

We act depending on the color of the element at index w .


Final case:
I If a [w ] = 0 then
0 0 0 0 0 0 1 1 1 0 ? ? ? 2 2 2 2
and so we execute

swap(r ; w );
r := r + 1; w := w +1

This yields:
0 0 0 0 0 0 0 1 1 1 ? ? ? 2 2 2 2
28 / 30
DNFP: Conclusion
const n : N; a : array [0::n ) of Z;
var r ; w ; b : Z;
fP : (as discussed above)g
r := 0; w := 0; b := n ;
fJ : (as discussed above)g
(* vf = b w *)
while w < b do
if a [w ] = 1 then
w := w + 1;
else
if a [w ] = 2 then
swap(b 1; w );
b := b 1;
else
if a [w ] = 0 then
swap(r ; w );
r := r + 1; w := w + 1;
end;
end;
end
fQ : (as discussed above)g
29 / 30
The End

30 / 30

You might also like