證明程式正確——迴圈不變量、歸納法與停機性

不變量的初始化(initialization)

在你相信某件事貫穿整個迴圈都為真之前,你得先檢查它在最一開始就為真——也就是在迴圈本體連一次都還沒執行之前。這第一步檢查就是初始化。它是梯子的底端:如果你還沒踏出第一步時托盤就不平,那後面踩得再小心也救不回來。所以初始化要問的是:依照迴圈正上方對變數的設定,不變量是否已經成立?

具體做法是:用迴圈變數的初始值,在迴圈入口處檢驗不變量。通常這個情形幾乎是顯然成立的,因為迴圈還什麼都沒做,於是不變量談的是一個空範圍。以插入排序為例,不變量「A[1..i-1] 已排序」在 i=1 時檢查,此時 A[1..0] 是空前綴——空清單(或單一元素清單)自然已排序,所以成立。對於不變量「s = A[1..i-1] 之和」的累加,初始化把 s 設為 0、i 設為 1,而空範圍 A[1..0] 之和的確是 0。重點是要去驗證,而不是揮揮手帶過。

初始化正是每個迴圈證明背後那個歸納法的基底情形;維持則是歸納步驟。人們常因為它「顯然」成立而略過,但略過之處正是差一錯誤與未初始化變數的藏身地。如果你的不變量在入口處無法被弄成真,那就是一個訊號:不變量本身有問題,或迴圈前的設定漏了一步。

對鍵值 x 做線性搜尋:不變量為「x 不在 A[1..i-1] 中」。入口處 i=1,故 A[1..0] 為空,「x 不在空範圍中」是空真(vacuously true)。初始化成立——而此時尚未看過任何元素。

初始化通常牽涉空範圍,因而是空真或顯然為真。

空範圍讓「對所有元素……」型的不變量空真,也讓「求和/計數」型的不變量等於單位元(求和為 0,乘積為 1)。這是正確的,不是鑽漏洞。

又稱
base case of the invariant不變量的基底情形