4.3: Loop Invariant
- Page ID
- 112225
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\dsum}{\displaystyle\sum\limits} \)
\( \newcommand{\dint}{\displaystyle\int\limits} \)
\( \newcommand{\dlim}{\displaystyle\lim\limits} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\(\newcommand{\longvect}{\overrightarrow}\)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)Mathematical induction is a foundation for the logic we use when we are using a looping statement in a program. In our programming class, we are frequently asked to use a looping statement in a program, most of times, we code the program with a looping statement, and then test it with a few sample data. If the looping statement produces correct results with those testing data, we simply accept the correctness of the looping statement we use and assume it will work for all cases.
Example
Write a function that receives a positive integer (a natural number), and then produces the sum of squares of all the numbers from 0 to the number the function receives. For example, if the function receives 5, then the function should produce 02+12+22+32+42+52 which is 55
This is a simple programming assignment; the code is shown as following:
We normally check the correctness of this function by entering a few of testing data, such as 5, 6, and 7 in the main(). If the results are all correct, then we assume this function will work for any positive integers we may enter. For some simple calculation, like this one, it will be fine. However, for some complicated calculation, the correctness may not be obvious. Especially, if the result of a function is related to a life and death situation, then we can't just accept the correctness of the function by the results that come from a few of sample data. We will need a solid proof.
In this example, even we don't have to, we would like to introduce the way of proving the correctness of the looping statement we used in the function sumSquares().
First, we explain what is a "Loop Invariant"
Definition
A loop invariant is a predicate that is true before the loop begins and it is also true after each iteration of the loop.
For the looping statement we use in the function sumSquares(), consider the predicate "s = 02+12+22+32, ..., + i2, where i is the value of the looping variable after each iteration", if we can prove it is a loop invariant, then it will be true before the looping statement begins and it also true after each iteration. In particular, it will be true after the last iteration. That means s = 02+12+22+32, ..., + n2 is true and this proves the looping statement produces the result we expect.
However, the process of proving is not always simple, but we want to get it a try.
Proof
To prove the predicate "s = 02+12+22+32, ..., + i2" is a loop invariant, we need to prove it is true before the loop begins and it is also true after each iteration.
Before the loop begins, s = 0 and i = 0, so the predicate "s = 02" is true.
Now, we need to prove the predicate is also true after each iteration of the loop. We will use mathematical induction for the proof.
It is not too difficult to see that, after the first iteration, the value of the looping variable i is 1, and, since s=s+i*i, s=1. Thus s = 02+12, so the predicate is true
Assume that the predicate is true after the i iterations, that means, after i iterations, s = 02+12+22+32, ..., + i2. Now we need to prove that, after i+1 iterations, we have s = 02+12+22+32, ..., + (i+1)2
In the ith iteration, the value of the looping variable is i and in the (i+1)th iteration, the value of the looping variable will be i+1, thus, after i+1 iterations, s = s + (i+1)(i+1). On the right side of equal sign, the value of s is 02+12+22+32, ..., + i2, thus, after the i+1 iterations, s = 02+12+22+32, ..., + i2+ (i+1)(i+1) = 02+12+22+32, ..., + (i+1)2. The proof is completed.
With such strict proof, we can make sure the loop we use produces correct result for any given positive integer.
It may seem difficult for you to grasp the logic we use in this proof. No worries, we can't become an expert after one logic class. As you become mathematically mature, you will have much more strength to handle such task.
What we do need to know here is we can't prove the correctness of a looping statement just by testing it with sample data. Sometimes, even with a large set of sample data, we still can't make sure a looping statement will produce the correct result.
Example
Following program contains a user-defined function getLargest() which receives an integer array along with its length, and then returns the largest number in the array it receives
In the main(), we test this function with an array, it works fine. The function produces correct result for this sample data. We can test the function with over hundreds of sample data. Even the results are all correct, we still can't say the function will work for all integer arrays. We can easily find an integer array, such as y[5] = {-5, -2, -10, -4, -7}, which the function will produce an incorrect result.
Prove the correctness of programs is a big topic and mathematical induction is only one of the tools we can use in this area.

