Zacznijmy od niezmiennika dla pętli zewnętrznej: .
// 1
s := 1;
i := 1;
while i < n do
(
k := 1;
l := 0;
p := 1;
while p < i do
(
k := k + 1;
if l < p then
(
l := l + 1;
p := 1
)
else
(
p := p + 1;
)
)
s := s + 6 * k + p - l;
i := i + 1;
)
// 2
Dwie zaznaczone implikacja są łatwe do udowodnienia.
Trudniej jest znależć niezmiennik dla pętli wewnętrznej.
Przede wszystkim zauważmy, że jeśli ma się "odnawiać" po każdym obrocie zewnętrznej pętli, to wartość dodawana do zmiennej powinna wynosić:
Zatem pętla wewnętrzna powinna prawdopodobnie obliczać na zmiennej wartość .
Jeśli uważnie przyjrzymy się pętli wewnętrznej, to zaobserwujemy, że zmienna przechowuje wartość
plus "zaczęte" , czyli plus .
Spróbujmy niezmiennik postaci:
Pozostaje jeszcze ustalić ograniczenia górne lub dolne zmiennych p, l.
Po pierwsze, zawsze zachodzi .
Po drugie, oczekujemy, że spełniony będzie warunek .
Zauważmy, że zmienna nigdy nie osiągnie wartości , gdyż wcześniej zmienna osiągnie tę wartość, a wtedy nastąpi od razu wyjście z pętli.
Połączmy te ograniczenia w jeden zwięły warunek:
Oto odpowiednie anotacje całego programu:
// 1
s := 1;
i := 1;
while i < n do
(
k := 1;
l := 0;
p := 1;
// 3
while p < i do
(
k := k + 1;
if l < p then
(
l := l + 1;
p := 1
)
else
(
p := p + 1;
)
)
// 4
s := s + 6 * k + p - l;
i := i + 1;
)
// 2
Musimy teraz udowodnić dwie kolejne zaznaczone powyżej implikacje:
- .
Pierwsza z nich jest oczywista, natomiast nie jesteśmy w stanie dowieść drugiej!
Jest tak dlatego, że w nie mamy informacji o tym, że przed wejściem do pętli wewnętrznej
zachodziło , a jest to niezbędne w dowodzie.
Zmodyfikujmy następująco:
i wróćmy do ostatniej z implikacji powyżej. Wciąż brakuje nam pewnych informacji!
Tym razem nie potrafimy pokazać, że zachodzi , co stanowi część formuły .
Powinniśmy dodać do warunek , który zachodzi zawsze po wejściu do pętli zewnętrznej.
Otrzymujemy ostatecznie:
Teraz dowód ostatniej implikacji jest możliwy.
Zauważmy w szczególności, że warunek w połączeniu z warunkiem obecnym w daje nam .
Ponieważ mamy:
a ponieważ , otrzymujemy:
Na koniec pozostał nam dowód poprawności instrukcji wewnętrznej w wewnętrznej pętli:
...
k := k + 1;
if l < p then
(
l := l + 1;
p := 1
)
else
(
p := p + 1;
)
...
Musimy wpisać jakąś asercję w miejsce znaku zapytania.
Nietrudno jest odgadnąć właściwą formułę: wystarczy dodać jeden do wyrażenia, które stoi po prawej stronie w równaniu w ,
czyli zastąpić je przez .
Oznaczmmy przez asercję, którą otrzymujemy w ten sposób z :
Oto szczegółowa anotacja rozważanego fragmentu programu:
...
// 5
k := k + 1;
if l < p then
(
// 6
l := l + 1;
p := 1
)
else
(
// 7
p := p + 1;
)
...
oraz implikacje niezbędne dla dokończenia dowodu:
- .