SE 504 (Formal Methods and Models)
Reasoning about programs with assignments to array elements

Let b be an array whose elements are of type T, let i satisfy 0≤i<#b, and let E be an expression of type T. Then the expression

b(i:E)

denotes the array that is "the same as b except at location i, where its value is E". (An alternative notation, used by David Gries in his 1981 book "Science of Programming", is "(b; i:E)".)

Array Element Evaluation Law:

We have, in all states

b(i:E).j = { if i=j
b.j otherwise

It is usually more convenient, at least in the context of performing calculations, to express this law using an if function, as follows:

b(i:E).j = if(i=j, E, b.j)

In order to reason about programs in which assignments are made to elements of an array, it is helpful to regard the assignment b.i := E as being an abbreviation for the more accurate b := b(i:E).

By doing so, our old friend, the wp assignment law, can be applied to array assignment, as follows:

wp.(b := b(i:E)).Q = Q(b := b(i:E))
which is in accord with said law.

wp Array Element Assignment Law

If you would prefer to think of an assignment to an array element in the more usual way, we must introduce this law:

wp.(b.i := E).Q = Q(b := b(i:E))


Calculation Examples

Here are some examples of calculating weakest preconditions of the form wp.(b.i := E).Q. Due to the proliferation of parentheses in the expressions, textual substitution will be denoted using square brackets rather than parentheses, as in [x := x+1].

Array Element Evaluation Law:
   b(i:E).j = if(i=j, E, b.j)
(if.0a) if(true,a,b) = a
(if.0b) if(false,a,b) = b
(if.1) if(p,a,a) = a
(if.2) if(E=F,a[x:=E],b) = if(E=F,a[x:=F],b)
(if.3a) Provided that has signature T × R → S:
    ifT(p,a,b) ⊕ c = ifS(p,a⊕c,b⊕c)
(if.3b) Provided that has signature R × T → S:
    c ⊕ ifT(p,a,b) = ifS(p,c⊕a,c⊕b)
(if.4a) ifbool(p,a,b) ≡ (p ⇒ a) ∧ (¬p ⇒ b)
(if.4b) ifbool(p,a,b) ≡ (p ∧ a) ∨ (¬p ∧ b)
(if.4c) ifbool(p,q,true) ≡ p ⇒ q
(if.5a) ifbool(p,a,b) ∧ ifbool(p,c,d) ≡ ifbool(p,a∧c,b∧d)
(if.5b) ifbool(p,a,b) ∨ ifbool(p,c,d) ≡ ifbool(p,a∨c,b∨d)
Example 1:

    wp.(b.(b.k):=k).(b.k = k)

 =     < wp array element assignment law >

    (b.k = k)[b:=b(b.k : k)]

 =     < textual sub >

    b(b.k : k).k = k

 =     < array element evaluation rule,
          with i:=b.k, j:=k, E:=k       >

    if(b.k = k,k,b.k) = k

 =     < (if.2), with a:=x, E:=b.k, F:=k, b:=b.k >

    if(b.k = k,b.k,b.k) = k

 =     < (if.1), with p:= b.k=k, a:b.k >

    b.k = k

An alternative way to finish the above (beginning with the third-to-last formula) is as follows:

    if(b.k = k,k,b.k) = k

 =     < if.3a, with p: b.k=k, a:k, b:b.k, c:k >

    if(b.k = k, k = k, b.k = k)

 =     < if.4a, with p: b.k=k, a: k=k, b: b.k=k >

    (b.k = k  ==>  k = k)  ∧  (¬(b.k = k)  ==>  b.k = k)

 =     < = is reflexive; Theorem: (¬p ==> p) ≡ p (easy to prove) >

    (b.k = k  ==>  true)  ∧  b.k = k

 =     < (3.72) >

    true ∧ b.k = k

 =     < (3.39) >

    b.k = k

Array Element Evaluation Law:
   b(i:E).j = if(i=j, E, b.j)
(if.0a) if(true,a,b) = a
(if.0b) if(false,a,b) = b
(if.1) if(p,a,a) = a
(if.2) if(E=F,a[x:=E],b) = if(E=F,a[x:=F],b)
(if.3a) Provided that has signature T × R → S:
    ifT(p,a,b) ⊕ c = ifS(p,a⊕c,b⊕c)
(if.3b) Provided that has signature R × T → S:
    c ⊕ ifT(p,a,b) = ifS(p,c⊕a,c⊕b)
(if.4a) ifbool(p,a,b) ≡ (p ⇒ a) ∧ (¬p ⇒ b)
(if.4b) ifbool(p,a,b) ≡ (p ∧ a) ∨ (¬p ∧ b)
(if.4c) ifbool(p,q,true) ≡ p ⇒ q
(if.5a) ifbool(p,a,b) ∧ ifbool(p,c,d) ≡ ifbool(p,a∧c,b∧d)
(if.5b) ifbool(p,a,b) ∨ ifbool(p,c,d) ≡ ifbool(p,a∨c,b∨d)
Example 2:

    wp.(b.(b.k):=k).(b.k ≠ k)

 =     < wp array assignment rule >

    (b.k ≠ k)[b:=b(b.k : k)]

 =     < textual sub >

    b(b.k : k).k ≠ k

 =     < array element evaluation rule  >

    if(b.k = k,k,b.k) ≠ k

 =     < (if.3a), with p:="b.k=k", a:=k, 
                  b:=b.k, c:=k, and ⊕:= "≠" >

    if(b.k = k, k≠k, b.k≠k)

 =     < (if.4b), with p:="b.k=k", a:="k≠k", b:="b.k≠k" >

    (b.k = k  ∧  k ≠ k)  ∨  (¬(b.k = k)  ∧  b.k ≠ k)

 =     < (3.10): ¬(x=y) ≡ x≠y >

    (b.k = k  ∧  k ≠ k)  ∨  (b.k ≠ k  ∧  b.k ≠ k)

 =     < (3.14) and (3.15); idempotence of ∧ (3.38) >

    (b.k = k  ∧  false)  ∨  b.k ≠ k
  
 =     < (3.40) zero of ∧ >

    false  ∨  b.k ≠ k

 =     < identity of ∨ (3.30) >

    b.k ≠ k

Array Element Evaluation Law:
   b(i:E).j = if(i=j, E, b.j)
(if.0a) if(true,a,b) = a
(if.0b) if(false,a,b) = b
(if.1) if(p,a,a) = a
(if.2) if(E=F,a[x:=E],b) = if(E=F,a[x:=F],b)
(if.3a) Provided that has signature T × R → S:
    ifT(p,a,b) ⊕ c = ifS(p,a⊕c,b⊕c)
(if.3b) Provided that has signature R × T → S:
    c ⊕ ifT(p,a,b) = ifS(p,c⊕a,c⊕b)
(if.4a) ifbool(p,a,b) ≡ (p ⇒ a) ∧ (¬p ⇒ b)
(if.4b) ifbool(p,a,b) ≡ (p ∧ a) ∨ (¬p ∧ b)
(if.4c) ifbool(p,q,true) ≡ p ⇒ q
(if.5a) ifbool(p,a,b) ∧ ifbool(p,c,d) ≡ ifbool(p,a∧c,b∧d)
(if.5b) ifbool(p,a,b) ∨ ifbool(p,c,d) ≡ ifbool(p,a∨c,b∨d)
Example 3:

    wp.(b.k := i).(b.j = b.(b.k))

 =     < wp array element assignment rule >

    (b.j = b.(b.k))[b := b(k:i)]

 =     < textual sub >

    b(k:i).j = b(k:i).(b(k:i).k)

 =     < array element evaluation rule, twice >

    if(k=j,i,b.j) = b(k:i).(if(k=k,i,b.k))

 =     < reflexivity of =, (if.0a) >

    if(k=j,i,b.j) = b(k:i).i

 =     < array element evaluation rule >

    if(k=j,i,b.j) = if(k=i,i,b.i)

 =     < (if.3a, with p:="k=j", a:=i, b:=b.j, c:=if(k=i,i.b.i), op:="=" >

    if(k=j, i=if(k=i,i,b.i), b.j=if(k=i,i,b.i))

 =     < (if.4b), with p:="k=j", a:="i=if(k=i,i.b.i)", b:="b.j=if(k=i,i,b.i)" >

    (k=j  ∧  i = if(k=i,i,b.i))  ∨  (¬(k=j)  ∧  b.j = if(k=i,i,b.i))

 =     < (if.3b), twice >

    (k=j  ∧  if(k=i,i=i,i=b.i))  ∨  (¬(k=j)  ∧  if(k=i,b.j=i,b.j=b.i))

 =     < (if.4b), twice >

    (k=j ∧  ((k=i ∧ i=i) ∨ (¬(k=i) ∧ i=b.i)))  ∨ (¬(k=j) ∧ ((k=i ∧ b.j=i) ∨ (¬(k=i) ∧ b.j=b.i)))

 =     < (3.10) ¬(x=y) ≡ x≠y; reflexivity of =, (3.39) (identity of &) >

    (k=j ∧  (k=i ∨ (k≠i ∧ i=b.i)))  ∨ (k≠j  ∧  ((k=i ∧ b.j=i) ∨ (k≠i ∧ b.j=b.i)))

 =     < distributivity of ∨ over ∧ >

    (k=j ∧  (k=i ∨ k≠i) ∧ (k=i ∨ i=b.i))  ∨ (k≠j  ∧  ((k=i ∧ b.j=i) ∨ (k≠i ∧ b.j=b.i)))

 =     < (k=i ∨ k≠i)≡true, (3.39) (identity of &) >

    (k=j  ∧ (k=i ∨ i=b.i))  ∨ (k≠j ∧ ((k=i ∧ b.j=i) ∨ (k≠i ∧ b.j=b.i)))

There may be a way to transform this into something simpler, but, if so, it would appear that any such transformation would rely entirely upon material from SE 500, as opposed to anything introduced here.