Correctness on iterative and recursive processes

Iterative processes are proven using loop invariants, and recursive processes are proven using induction. In some cases it might be trickier to find a good loop invariant, where proving recursive processes is just to follow the very own definitions of the process.


Consider the following recursive definition:

maxList [x] = x
maxList (x:xs) = max(x, maxList xs)

We can prove its correctness using induction:

– Base case: Max element of a list of size 1 is the element itself.

– Inductive step: Assume that maxList of xs is maximum element.

Then for maxList (x:xs) we have 2 cases:
1. maxList of xs is >= x, in which case we select maxList xs
2. x is >= maxList xs, in which case we select x
In either case, we pick the larger element which will be the maximum.


Now consider the following iterative definition:

var max = x[0], i;

for (i = 0; i < x.length; i++) {
     if (x[i] >= max) max = x[i];
}

In this case we need to find a loop invariant to use that will hold pre-, during, and post- processing of that code block.

We can use the following loop invariant: max is the biggest element in the subarray x(0, i).

– Before loop: for array of size 1 we have the same element to be maximum. So the loop invariant holds.

– Within the loop, we have two cases:
1. x[i] >= max, in which we set max to be x[i]
2. x[i] < max, in which we don't change max
In either case, the loop invariant holds.

– After loop: max is the biggest element in the subarray x(0, x.length – 1) which is just x.

Usefulness of algebraic structures

Let’s consider the partial order relation. 

Namely, it’s a relation that has the following properties: reflexive, transitive, antisymmetric.

One example of such a relation is ≤ on naturals.

Another example is ⊆ on sets.

But if we look at these 2 examples from a higher perspective, the first one is about comparing numbers and the second one is about subsets of a set. E.g. 1 ≤ 2 and {1, 2} ⊆ {1, 2, 3}

It might not be immediately obvious that these 2 examples have anything in common, but with partial orders (and algebraic structures in general) we can capture such abstractions.

Property of squares

Consider the following task:
Print the first 100 squares using at most one loop. The constraints are that you are not allowed to use multiplication or functions.

To tackle this one, we will have to use one interesting property of the squares that I noticed while taking my kid to school. At the school, there was a table with all natural numbers listed from 1 to 100. While looking at it, I noticed the distances between the squares kept increasing by 2k + 1 for every kth square.

So for example, from 1 to 4 (the first square), the distance is 3. Since this is the first square, k = 1 so 2*1 + 1 = 3. The distance from 4 to 9 (the second square) is 5. Since this is the second square, k = 2 so 2*2 + 1 = 5. And so on.

Naturally I tried to generalize this and came to the following recurrent relation:

n_0 = 1
n_k = n_{k - 1} + 2k + 1

Before we use this relation in our program, we will first prove its correctness.

We will prove that n_k = (k + 1)^2 by induction.

The base case is k = 0: n_0 = 1 = 1^2 which is true. Now, we assume that n_k = (k + 1)^2. If we add 2k + 3 to both sides, we get n_{k + 1} = n_k + 2k + 3 = (k + 1)^2 + 2k + 3 = k^2 + 4k + 4 = (k + 2)^2. Thus the identity is proven.

Now, here is our simple program:

var s = 1;
for (var i = 1; i <= 100; i++) {
    console.log(s);
    s += i + i + 1;
}

Reimbursement formula

Let’s assume that you work at an awesome company as a contractor.
They allow you to purchase equipment, and will reimburse the money you spent.

However, as a freelancer, you have to pay taxes. Let’s assume taxes are at 10% for any payment you receive on your account.

To further increase the greatness of the company, they say they will pay the taxes for you as long as you do the proper calculation.

So, as an example, let’s say you spend like $100 on computer equipment and ask for $100 reimbursement.
You will receive $100 on your bank account and have to pay 10% of that in taxes, so that’s $10, so you end up with $90.

You might also try to ask for $110 from the company, but 10% of that is $11 so you are left with $99. If you ask them to send you $11 for the taxes you paid, you will again have to pay 10% of $11 ($1.1) in taxes, and so on.

So the question is, how much money should the company reimburse you once, so that you get an amount close to the one you spent which includes taxes?

The answer is, if N is the money spent, you need to ask for reimbursement of N + \lceil \frac{N}{9} \rceil money.

As an example:

I spend: $100
They send: N + \lceil \frac{N}{9} \rceil, or $112
I pay tax: 10% * $112 = $11.2

Now, it holds that \$112 = Send \geq Spend + Tax = \$111.2

To derive that formula, we need to think in terms of recursion. Consider that multiple transactions are made, and for each transaction, you need to pay 10% in taxes of the transaction value.

Start with a number N:
1. Ask for pay of N money (company reimburses N)
2. Ask for pay of 10% of N (company reimburses 10% of N)
3. Ask for pay of 10% of 10% of N (company reimburses 10% of 10% of N)

And then, sum all the terms.

That makes something like: S = N + N/10 + N/100 + ... = N(1 + 1/10 + 1/100 + ...).

To calculate the 1 + 1/10 + 1/100 + ... part, we can let n = 1.1111.... So, 10n = 11.1111... and 10n - n = 9n = 10 and we get that n = 10/9. We rewrite that as 1 + 1/9 so that we can use ceil on the fractional part to get an integer.

P.S. I work at Automattic 🙂