Of course it's proof by induction. You prove that it's true for iteration N+1 if it was true for iteration N. You prove that it was true for iteration 0. Then you're done.
Here's how we did it in the Pascal-F verifier [1] around 1980. This is the
simplest example - proving that all entries in an array are zero after the
array is initialized.
type tabix = 1..100;
type tab = array [tabix] of integer;
rule function allzero(a: tab; i,j: tabix): boolean; begin end;
var table1: tab;
i,j: tabix;
...
for i := 1 to 100 do begin
table1[i] := 0;
assert(allzero(table1,1,i-1));
state(allzero(table1,1,i));
end;
assert(allzero(a,1,100));
...
assert(table1[j] = 0); { table1[j] must be 0 }
The loop invariant is
state(allzero(table1,1,i));
which says that the predicate "allzero" is true for table1 from 1 to i.
"allzero" is defined in the Boyer-Moore theorem prover as a recursive function.
(defn allzero (a i j)
(if (lessp j i)
t
(and (allzero a (add1 i) j) (equal (selecta! a i) 0))))
That's a recursive function. The prover is able to prove that it terminates.
"(selecta! a i)" is LISP for "a[i]" here.
We need three theorems about "allzero". First, that it's vacuously true for j < i:
(implies (and (arrayp! a)
(numberp i)
(numberp j)
(lessp j i))
(allzero a i j)))
Notation: "arrayp!" is true if the item is an array. "numberp" is true if it's an integer. "lessp"
is "<".
Then that it's true for a single element if that element is zero:
(implies (and (arrayp! a)
(numberp i)
(numberp j)
(equal i j)
(equal (selecta! a i) 0))
(allzero a i j))))
And finally, the hard one, that if it's true up to N, and a[N+1] is zero, it's
true up to N+1.
(implies (and (arrayp! a)
(numberp i)
(numberp j)
(allzero a i j)
(equal (selecta! a (add1 j)) 0))
(allzero a i (add1 j))))
These are all proved, once, with the Boyer-Moore theorem prover. Once proven, they can be
used as rules by the much simpler and faster Oppen-Nelson prover built into the Pascal-F verifier. Over time, you build up a library of such rules, which are applied automatically
by the fast prover.
This is 1980 technology; there's been a lot of progress in the last 35 years. This ran on a 1 MIPS VAX 11/780 and later on Sun II workstations. Back then, it was very slow to do this. That's a solved problem. It's still rather painful. But it works.
[1] http://www.animats.com/papers/verifier/verifiermanual.pdf