SE 504 Solution of 2-Color version of the Dutch National Flag Problem Here we supply a solution to the 2-color version of the Dutch National Flag problem. The purpose is to illustrate how to prove the correctness of a program in which an array is modified. Recall that, in the 2-color version of the Dutch National Flag Problem, we are given an array in which every element's value can be characterized as being either RED or BLUE. (For the sake of simplicity, we assume that each element is equal to one of the two values RED or BLUE.) The goal is to swap elements of the array so as to achieve a state in which no BLUE element precedes any RED element. Further, the location of the boundary between RED and BLUE elements is to be indicated by the variable k. As modifications to the array are restricted to swapping pairs of its elements, let us postulate the existence of a command (or subprogram, if you prefer to look at it that way) called swap. The swap command, which involves three parameters, has the following semantics: wp.(swap.b.i.j).Q = Q(b := b(i,j : b.j, b.i)) where (provided that i=j implies E=F) { E if i=k b(i,j : E,F).k = { F if j=k (+) { b.k otherwise Note that this is simply an extension of the notation b(i:E) denoting an array exactly like b except at location i. Using the "if" function, (+) can be written as follows: b(i,j : E,F).k = if(i=k, E, if(j=k, F, b.k)) (*) In terms of Hoare Triples (rather than wp), we could say that {Q(b := b(i,j : b.j, b.i)} swap.b.i.j {Q} is true and that replacing the precondition with a predicate that is strictly weaker would result in a Hoare Triple that is false. Lemma 1: Let b' be an abbreviation for b(i,j : b.j, b.i). Then ------- (a) b'.i = b.j, (b) b'.j = b.i, (c) (&k | 0<=k<#b & k!=i & k!=j : b'.k = b.k) Proof: ----- (a) b'.i | (b) b'.j | = < defn of b' > | = < defn of b' > | b(i,j : b.j, b.i).i | b(i,j : b.j, b.i).j | = < (*) > | = < (*) > | if(i=i, b.j, if(j=i, b.i, b.i)) | if(i=j, b.j, if(j=j, b.i, b.i)) | = < reflexivity of = > | = < reflexivity of = > | if(true, b.j, if(j=i, b.i, b.i)) | if(i=j, b.j, if(true, b.i, b.i)) | = < if(true, y, z) = y > | = < if(true, y, z) = y > | b.j | if(i=j, b.j, b.i) To complete the proof of (b), we observe that, if i != j, the proof continues as follows: if(i=j, b.j, b.i) = < assumption i != j > if(false, b.j, b.i) = < if(false, y, z) = z > b.i which is what we wanted. On the other hand, if i = j the proof continues like this: if(i=j, b.j, b.i) = < assumption i = j > if(true, b.j, b.i) = < if(true, y, z) = y > b.j = < assumption i = j, (Gries 3.84a) > b.i In effect, we've proved both (i=j) ==> (b'.j = b.i) and (i != j) ==> (b'.j = b.i), which is to say that we've proved their conjunction. As this conjunction is equivalent to b'.j = b.i (as shown immediately below), this suffices as a proof of b'.j = b.i. (i=j) ==> (b'.j = b.i) & (i != j) ==> (b'j = b.i) = < (Gries 3.78) > (i=j v i != j) ==> (b'.j = b.i) = < (i != j) = !(i=j); Excluded Middle (Gries 3.28) > true ==> (b'.j = b.i) = < true is left identity of ==> (Gries 3.73) > b'.j = b.i As for (c), by Gries's and Schneider's Metatheorem 9.16 (and remarks just before the end of Section 9.1), it suffices to let k be an arbitrary integer satisfying the range of the universal quantifier (i.e., 0<=k<#b & k!=i & k!=j) and to show that, for this value of k, the body holds. In other words, we show (0<=k<#b & k!=i & k!=j) ==> (b'.k = b.k) Assume 0<=k<#b, k!=i, and k!=j. b'.k = < defn of b' > b(i,j : b.j, b.i).k = < (*) > if(i=k, b.j, if(j=k, b.i, b.k)) = < assumptions k!=i and k!=j > if(false, b.j, if(false, b.i, b.k)) = < if(false, y, z) = z (applied to nested if) > if(false, b.j, b.k) = < if(false, y, z) = z > b.k END OF PROOF OF LEMMA. Corollary: perm.b.b' (i.e., b' is a permutation of b) Before giving the program (and relevant parts of its correctness proof), we give another result that will be useful in carrying out that proof: Lemma 2: The following is a valid step in an "equational logic style" proof: A & B = < A ==> (B = C) > A & C Proof: It follows from Gries (3.62): (A ==> (B = C)) = ((A & B) = (A & C)) ---------------------------------------------------------------------------- Finally, here is a program solving the 2-color version of the Dutch National Flag problem: |[var b : array of { RED, BLUE }; { b = B } var k : int; var m : int; k, m := 0, #b; { loop invariant P: P1 & P2 & P3 & P4, where P1 : perm.b.B P2 : 0<=k<=m<=#b P3 : (&i | 0<=i k := k+1; # k!=m & b.k = BLUE ---> swap.b.k.(m-1); m := m-1; od { Q: perm.b.B & (&i | 0<=i Q] (iv) [P & (B0 v B1) ==> t>0] (v)(a) {P & B0 & t=C} k := k+1 {t wp.(swap.b.k.(m-1)).(wp.(m:=m-1).P) = < wp assignment law > wp.(swap.b.k.(m-1)).P(m:=m-1) = < wp swap law > P(m:=m-1)(b := b(k,m-1 : b.(m-1),b.k)) = < abbreviate b(k,m-1 : b.(m-1),b.k)) as b' > P(m:=m-1)(b:=b') = < defn of P; textual sub distributes over & (and other operators) > (P1(m:=m-1) & P2(m:=m-1) & P3(m:=m-1) & P4(m:=m-1))(b := b') = < m does not occur in P1, P3 > (P1 & P2(m:=m-1) & P3 & P4(m:=m-1))(b := b') = < textual sub distributes over & > P1(b:=b') & P2(m:=m-1)(b:=b') & P3(b:=b') & P4(m:=m-1)(b:=b') = < defn of P1, ..., P4 and text. sub. > perm.b'.B & 0<=k<=m-1<=#b' & (&i | 0<=i 0<=k<=m-1<=#b' & (&i | 0<=i k<=m-1 & (&i | 0<=i k<=m-1 & (&i | 0<=i k<=m-1 & (&i | m-1<=i<#b' : b'.i = BLUE) = < Split off term (8.23); non-emptiness of range follows from assumption m<=#b and #b=#b') > k<=m-1 & b'.(m-1) = BLUE & (&i | m<=i<#b' : b'.i = BLUE) = < b'.(m-1) = b.k (by part (b) of Lemma 1) and b.k = BLUE (by assumption); it follows that b'.(m-1) = BLUE > k<=m-1 & (&i | m<=i<#b' : b'.i = BLUE) = < by the Corollary to Lemma 4 (see below), k<=m-1 (the 1st conjunct) implies R = R(b':=b), where R is the 2nd conjunct above; hence, by Lemma 2 (see above) we may replace R by R(b':=b) > k<=m-1 & (&i | m<=i<#b : b.i = BLUE) = < assumption P4; (Gries 3.39) > k<=m-1 = < assumptions k<=m, k!=m > true ------------------------------------------------------------------- Lemma 3: k<=m-1 ==> (&i | 0<=i (&i | 0<=i<#b & i!=k & i!=m-1 : b'.i = b.i) = < Range split (Gries 8.16) > (&i | 0<=i < Gries 3.76b > (&i | 0<=i B) = (A & B = A) (Gries 3.60) > (&i | 0<=i (&i | 0<=i ((&i | 0<=i (&i | 0<=i (&i | 0<=i (&i | 0<=i (&i | 0<=i (&i | 0<=i (&i | m<=i<#b : b'.i = b.i) ------- Proof: Similar to that of Lemma 3. Corollary: k<=m-1 ==> --------- ((&i | m<=i<#b' : b'.i = BLUE) = (&i | m<=i<#b: b.i = BLUE)) Proof: Similar to that of Corollary to Lemma 3. ------------------------------------------------------------------- (v)(b) {P & B1 & t=C} swap.b.k.(m-1); m := m-1 {t wp.(swap.b.k.(m-1).(wp.(m := m-1).(t wp.(swap.b.k.(m-1)).(m-1-k < C) = < wp swap law > (m-1-k < C)(b := b(k, m-1 : b.(m-1), b.k)) = < text. sub. > m-1-k < C = < assumption m-k = C > m-1-k < m-k = < algebra > -1 < 0 = < arithmetic > true