You are on page 1of 6

Documentation for the example selection sort

Proof elaborated by Steffen Schlager and Richard Bubel


Documentation written by Benjamin Niedermann

1 Introduction
The example contains a simple implementation of the selection sort algorithm. It
will be shown that on certain preconditions the implementation works correct, i.e
the result is a sorted array that is a permutation of the given array. Consequently
the problem of verifying the implementation can be divided into the following
two subproblems:

A) How to verify that the resulting array is sorted?


B) How to verify that the resulting array is a permutation of the given array?
Following sections which are necessary to answer the first questions are labeled
with A) and to answer the second question are labeled with B). At the end
of this documentation the reader can find a short description how to prove the
problem concretely with KeY.
The proof requires a special version of KeY that is not officially available yet.

2 Verifying selection sort


2.1 The file Sort.java
The class Sort consists only of the method demo() and the array a. Calling
demo() causes the array a to be sorted by the algorithm selection sort in de-
scending order. The actual algorithm will not be covered below, but only the
used pre- and postconditions and invariants will be discussed briefly. One main
idea of the invariants is to partition the array a into an already sorted part and
a still unsorted part by the variable pos. The JML-blocks contain the following
annotations:

1. Precondition
The given array should be not empty:
requires(a6=null & a.length>0)

2. Postcondition
The array is sorted:
ensures(∀ int i: 0≤i & i<a.length-1 ⇒ a[i]≥a[i+1])

3. Loop invariant for the outer loop divided into three main conjunctions:

1
A) The separation must be within the array:
0≤pos & pos≤a.length
A) Definition of the sorted part
∀ int x: x≥0 & x<pos-1 ⇒ a[x]≥a[x+1]
A) For the unsorted part it is necessary that every element is less than or equal
to all elements of the sorted part:
∀ int x: x≥0 & x≤pos-1 ⇒ (∀ int y: y≥pos & y<a.length ⇒
a[x]≥a[y])

4. Loop invariant for the inner loop divided into three main conjunctions:

A) Search for the maximum only within the unsorted partition:


pos≤counter & counter≤a.length
A) The helping variable idx is within the unsorted partition:
pos≤idx & idx<a.length & pos<a.length
A) The element indexed by idx is the maximum of the already examined ele-
ments in the unsorted partition:
∀ int x: x≥pos & x<counter ⇒ a[idx]≥a[x]

2.2 The file sortAlg.key


The file “sortAlg.key” contains the correctness proof obligation for the selec-
tion sort algorithm. Correctness includes that the array is both sorted and a
permutation of the original array after calling demo(). First the function

int mult[\f or (jint[] o; int i) o[i]](jint[], int, int, int)

and the predicate

perm[\f or (jint[] o; int i) o[i]; \f or (jint[] o) o.length](jint[], jint[])

are introduced (Remark: To increase the readability the expressions, so called


dependencies, standing directly after mult and perm are omitted from this
point. They are used to indicate memory dependencies of predicates or func-
tions. For more information see 2.4 and [BHS08]). Both mult and perm are
indirectly defined by the rules multDef and permDef . Furthermore the rule
permT ransition is defined within this file.

1. B) int mult(jint [] a, int el, int start, int end)

a[start] = el & start ≥ 0 &



 mult(a, el, start + 1, end) + 1,
start < end







:= mult(a, el, start + 1, end) + 0, a[start] 6= el & start ≥ 0 &


 start < end





0, else
The function mult returns how often an element el appears in the array
a considerring the lower bound start and the upper bound end.

2
2. B) boolean perm(int [] a, int [] b)
.
:↔ ∀n : mult(a, n, 0, a.length) = mult(b, n, 0, b.length)

The predicate perm returns true if and only if a is a permutation of b.


3. B) permT ransition

∀ int x ∀ int y : x ≥ 0 & x < a.length & y ≥ 0 & y < a.length & perm(a, b)
→ {a[x] := a[y] || a[y] := a[x]}perm(a, b))

The rule permTransition says if two elements are swapped in an array a,


then the array a is a permutation of the original one.

Remark: The rule permT ransistion is proved by means of the proof obligations
that can be found in “permTrans.key”, “multPart.key” and “unwindEnd.key”.
All of these proofs involve inductions on natural numbers but do not incorporate
programs. Therefore they are not considered in this documentation.

2.3 A) The resulting array is sorted


To show that the array a is sorted after executing demo() it suffices to show the
validity of following formula in JavaDL [BHS07, chapter 3]:

inReachableState

∀ S o r t s e l f l v { s e l f := s e l f l v }
(
s e l f . a 6= null
& s e l f 6= null
& s e l f .< c r e a t e d > = TRUE
& s e l f . a 6= null
& s e l f . a . length > 0

< s e l f . demo ( ) ;>
(
∀ jint i
(
0≤ i & i < s e l f . a . l e n g t h −1
→ s e l f . a [ i ] ≥ s e l f . a [ i +1]
)
)
)

For proving this formula in KeY no interaction with the user is necessary. The
invariants given in JML (see 2.1) are used to instantiate the invariant rules of
the two while-loops. The resulting obligation is automatically closed after 3273
steps on 26 branches.

3
inReachableState is a special predicate which summarizes a conjunction of sev-
eral predicates in KeY to shorten the length of the proof obligation. These
predicates answer the purpose to model states which are reachable by Java
Card programs [BHS07, page 105].
A modified version of the selection sort example can be found in the folder
“ArrayIsSorted” which shows only that the resulting array is sorted: All decla-
rations of rules, predicates and functions have been removed in “sortAlg.key”,
because the JML-blocks in “Sort.java” are effectual for this part of the proof.

2.4 B: The resulting array is a permutation of the given


array
For proving B) more interaction is necessary than for proving A), because of
two reasons:
1. As JML does not support the permutation predicate directly the loop
invariant must be added manually using Java DL.

2. The fact that a transposition is a permutation needs to be added by the


rule permT ransition manually. This rule does not replace any expression
but adds some. Because this can easily cause infinite loops, it is necessary
to understand the proof not only in a syntactic but also in a symantic
way.

To prove B) you have to show the correctness of the following statement:

inReachableState

∀ S o r t s e l f l v { s e l f := s e l f l v }{\ f o r int i ;
deepCopyArrayA [ i ] := s e l f . a [ i ] }
(
s e l f . a 6= deepCopyArrayA
& s e l f . a 6= null
& deepCopyArrayA 6= null
& perm ( s e l f . a , deepCopyArrayA )
& s e l f 6= null
& s e l f .< c r e a t e d > = TRUE
& s e l f . a 6= null
& s e l f . a . length> 0

< s e l f . demo ( ) ;>
(
perm ( s e l f . a , deepCopyArrayA )
)
)
}

After expanding demo() and simplifying the statement, the loop invariant

4
perm [ \ f o r ( j i n t [ ] o ; int i ) o [ i ] ; \ f o r ( j i n t [ ] o ) o .
l e n g t h ] ( s e l f . a , deepCopyArrayA )
must be proved for the outer loop. In KeY this is equally done to the proof of
A), with the exception that the invariant must be introduced manually (see 3).
As you can see at the definition of perm (see 2.2) the valuation of perm only
depends on the values of a[i], b[i], a.length, b.length (∀ int i). This explicit
dependencies allows the calculus to ignore heap changes which are outside of this
dependency set without expanding the definition. As recently as the calculus
reaches the swapping
int temp=a [ i d x ] ;
a [ i d x ]=a [ pos ] ;
a [ pos ]=tmp ;
the definition of perm must be expanded, because perm is by definition de-
pended on these variables used in the swapping. At this point the rule permT ransition
must be applied to prove that the swapping is correct (For more information
about dependencies see [BHS08]).
A modified version of the selection sort example can be found in the folder
“ArrayIsPermutation”: As far as possible the JML-blocks have been reduced in
“Sort.java” to show only the permutation property.

3 Concrete approach for KeY


As the loop invariant for the outer loop is not specified completely in ”Sort.java“,
the proof cannot be done automatically, but only nearly automatically. In order
to prove the sorting algorithm in KeY follow this steps:
1. Deactivate ’Minimize Interaction’ in the options menu and set the strategy
option for ’Loop Treatment’ to none.
2. Start the prover.
3. The prover stops after several steps. Select the outer loop and apply the
’loop invariant’-rule.
4. The following formula has to be added as conjunct to the loop invariant
for the outer loop:

perm[\f or (jint[] o; int i) o[i]; \f or (jint[] o) o.length]


(self.a, deepCopyArrayA)
5. After adding the conjunct and applying the rule, reactivate ’Loop Treat-
ment’ to invariant.
6. Restart the prover. All goals except one will be closed automatically.
(Otherwise restart the prover again)
7. Apply the ’permTransition’-rule exactly once to each remaining possibil-
ity.
Remark: Applying the rule will not cause the marked expression to disap-
pear, but some will be added. Therefore be careful that you do not apply
the rule several times on the same expression.

5
8. Restart the prover. The proof should be closed after up to 20000 steps.
Explanation: By setting ’Loop Treatment’ to none in Step 1 it is guar-
anteed that the prover will not use automatically the weak form of the loop
invariant for the outer loop. In Step 2 the prover begins to apply the typical
rules, like expanding the program and dissolving the modality, to the problem
until the rule ’Loop invariant’ would be the next best choice. At this point the
prover stops and hands the control over to the user. When the user applies
the rule ‘Loop invariant‘ to the outer loop in step 3, the instantiation window
opens (Remark: without choosing ’Minimize Interaction’ in Step 1 the window
would not have been opened, but the instantiation would have been done auto-
matically). In field ’inv (formula)’ the user can find an invariant which nearly
equates to the invariant that can be found in ”Sort.java“. Because the invari-
ant for the inner loop does not need to extend, the option ’Loop Treatment’ is
reseted to invariant in Step 5. For step 6-8 see 2.4.

References
[BHS07] Bernhard Beckert, Reiner Hähnle, and Peter H. Schmitt, editors. Veri-
fication of Object-Oriented Software: The KeY Approach. LNCS 4334.
Springer-Verlag, 2007.
[BHS08] Richard Bubel, Reiner Hähnle, and Peter H. Schmitt. Specification
predicates with explicit dependency information. In Bernhard Beckert,
editor, Proceedings, 5th International Verification Workshop (VER-
IFY’08), volume 372 of CEUR Workshop Proceedings, pages 28–43.
CEUR-WS.org, 2008.

You might also like