Triple nested while loop – Big Oh Notation – Count of Primitive Operations

Question:

I’m having some trouble figuring out the primitive count of operations for the following lines of code

def question1(n):
    n = n           # 1 ops
    i = 0           # 1 ops
    a = 0           # 1 ops
    while i < n:            # n ops
        j = 0               # n ops
        while j < n:        # n * n ops
            k = 0           # n * n ops
            while k < 60:                   # n * n * 60 ops
                a = i * j - i * 2 + k       # n * n * 60 * 5 ops
                k += 1                      # n * n * 60 * 2 ops
            j += 1          # n * n ops
        i += 1              # n ops

# total sum of prim operations = (n * n * 483) + (3 * n) + 3

I’m not sure if

            while k < 60:                   # n * n * 60 ops
                a = i * j - i * 2 + k       # n * n * 60 * 5 ops
                k += 1                      # n * n * 60 * 2 ops

Is it really

n * n * 60?

or should it be

 n * n * n * 60
Asked By: Jeff924D

||

Answers:

I would say it is definitely not n * n * n * 60. You might be confused about asymptotic notation, which may be influencing this question in the first place. The third while loop is executed 60 times, meaning that each operation within it is executed 60 times. This while loop runs 60 times for each of the n iterations of the second while loop, which runs n times for each of the n iterations of the first while loop, yielding n * n * 60.

Although the 60 is involved here, it is still a constant and is therefore of little significance for large values of n. The use of a triple nested loop is more of a trick question in this case, designed to show an example of why the polynomial properties of the algorithm are more important than any constants, just because as n gets large, n * n becomes much larger than 60 does.

Your calculation looks correct, though. The only thing missed is that the following blocks are actually 2 operations each :

j += 1          # n * n * 2 ops, equal to j = j + 1, an assignment AND addition
i += 1          # n * 2 ops ( i = i + 1 )   
Answered By: brett-mullen

"primitive operations" is an ambiguous concept. For instance, a while statement will at some point evaluate the condition as false (which you didn’t count) and then make the execution jump to the statement after the loop. One could say those are two operations (evaluation + jump).

Someone could say that k += 1 should count as 3 operations:

  • load the value of k into a CPU register,
  • add one to it
  • store that register’s value back in k.

But if Python were compiled into a machine language that has the INC instruction (like NASM), and we deal with fixed-size integers (like 32 bit), it is only one operation.

So this concept is fuzzy, and it is quite useless to sum them up. You should not identify "primitive operations", but identify chunks of code that have a constant time complexity.

Analysis in terms of constant time complexity

First we need to decide whether to think of integer arithmetic operations to be constant in time, or whether we should take into consideration that integers (certainly in Python) can have arbitrary size, and therefore these operations do not have a constant time complexity. See also "bit complexity". I will assume here that you want to regard arithmetic operations as having a constant time complexity.

Then we can identify this chunk of code has having a constant time complexity:

            k = 0
            while k < 60:
                a = i * j - i * 2 + k
                k += 1
            j += 1

Note here that executing the inner block (that has a constant complexity) 60 times, still means the total has a constant time complexity, since 60 is a constant (independent from the input).

Also the initialisation of integer variables or their incrementing all represent constant time complexity.

There are two nested loops that each iterate times when they get executed. So that means the (above) inner part gets executed ² times.

Hence, the overal time complexity is O( ²)

Answered By: trincot