Analysis of Algorithms (Complexity)

COMP2521 20T2 - Complexity ♢ [0/46]
❖ Performance Analysis

Program run-time is critical for many applications

Program efficiency can be investigated in two ways: Sometimes, the goal is to compare alternative implementations

Mostly, the goal is to determine whether ...

COMP2521 20T2 - Complexity ♢ [1/46]
❖ ... Performance Analysis

Typically:  larger input ⇒ longer run time

[Diagram:Pics/runTimeGrowth.png]

COMP2521 20T2 - Complexity ♢ [2/46]
❖ ... Performance Analysis

What to analyse?

[Diagram:Pics/runTime.png]

COMP2521 20T2 - Complexity ♢ [3/46]
❖ Empirical Analysis

Empirical study of program performance (measurement)

  1. Write program (implement algorithm)

  2. Run program with range of data
    (inputs varying in size and composition)

  3. Measure the actual running time

  4. Plot the results
 

Measuring run-time on Linux:  time  command  (real, user, sys)

COMP2521 20T2 - Complexity ♢ [4/46]
❖ ... Empirical Analysis


Limitations:

COMP2521 20T2 - Complexity ♢ [5/46]
❖ Theoretical Analysis


Formal analysis of algorithm performance (complexity)

Gives a basis for choosing which algorithm to use in a program.
COMP2521 20T2 - Complexity ♢ [6/46]
❖ Pseudocode


Pseudocode is a useful way to describe algorithms

COMP2521 20T2 - Complexity ♢ [7/46]
❖ ... Pseudocode

Example: Find maximal element in an array

arrayMax(A):
|  Input  array A of n integers
|  Output maximum element of A
|
|  currentMax=A[0]
|  for all i=1..n-1 do
|  |  if A[i]>currentMax then
|  |     currentMax=A[i]
|  |  end if
|  end for
|  return currentMax

COMP2521 20T2 - Complexity ♢ [8/46]
❖ ... Pseudocode

Control flow Function declaration Expressions
COMP2521 20T2 - Complexity ♢ [9/46]
❖ The Abstract RAM Model


RAM = Random Access Machine


Gives a simple model of computation to use in analyses
COMP2521 20T2 - Complexity ♢ [10/46]
❖ Primitive Operations

Every algorithm uses a core set of basic operations

Examples:
COMP2521 20T2 - Complexity ♢ [11/46]
❖ Counting Primitive Operations

By inspecting pseudocode … Example:
arrayMax(A):
|  Input  array A of n integers
|  Output maximum element of A
|
|  currentMax=A[0]                   1
|  for all i=1..n-1 do               n+(n-1)
|  |  if A[i]>currentMax then        2(n-1)
|  |     currentMax=A[i]             n-1
|  |  end if
|  end for
|  return currentMax                 1
                                     -------
                             Total   5n-2
COMP2521 20T2 - Complexity ♢ [12/46]
❖ Estimating Running Times

Algorithm arrayMax requires ...

Define: Let T(n) be worst-case time of arrayMax. Then

   a(5n - 2)  ≤  T(n)  ≤  b(5n - 2)

Hence, the running time T(n) is bounded by two linear functions

COMP2521 20T2 - Complexity ♢ [13/46]
❖ ... Estimating Running Times

Seven commonly encountered functions for algorithm analysis

COMP2521 20T2 - Complexity ♢ [14/46]
❖ ... Estimating Running Times

This chart shows various algorithmic growth rates

[Diagram:Pics/big-o-chart.png]


The lesson: logarithmic complexity is tolerable; exponential is not.

Chart borrowed from: http://bigocheatsheet.com/

COMP2521 20T2 - Complexity ♢ [15/46]
❖ ... Estimating Running Times

Growth rate is not affected by constant factors or lower-order terms

Examples:    102n + 105  is linear,    105n2 + 108n  is quadratic


For arrayMax, changing the hardware/software environment

Linear growth rate of T(n)

COMP2521 20T2 - Complexity ♢ [16/46]
❖ Example of estimating running times

Determine the number of primitive operations

matrixProduct(A,B):
|  Input  n×n matrices A, B
|  Output n×n matrix A·B
|
|  for all i=1..n do
|  |  for all j=1..n do
|  |  |  C[i,j]=0
|  |  |  for all k=1..n do
|  |  |     C[i,j]=C[i,j]+A[i,k]·B[k,j]
|  |  |  end for
|  |  end for
|  end for
|  return C

COMP2521 20T2 - Complexity ♢ [17/46]
❖ ... Example of estimating running times

matrixProduct(A,B):
|  Input  n×n matrices A, B
|  Output n×n matrix A·B
|
|  for all i=1..n do               2n+1
|  |  for all j=1..n do            n(2n+1)
|  |  |  C[i,j]=0                  n2
|  |  |  for all k=1..n do         n2(2n+1)
|  |  |     C[i,j]=C[i,j]
|  |  |            +A[i,k]·B[k,j]  n3·5
|  |  |  end for
|  |  end for
|  end for
|  return C                        1
                                   ------------
                           Total   7n3+4n2+3n+2

COMP2521 20T2 - Complexity ♢ [18/46]
❖ Big-Oh Notation


Given functions f(n) and g(n), we say that

if there are positive constants c and n0 such that


We tend not to use f(n) in discussing algorithm complexity.

We quote algorithm complexity as O(1)  or O(n)  or O(n2),  etc.

E.g.  matrixProduct has O(n3) complexity.

COMP2521 20T2 - Complexity ♢ [19/46]
❖ ... Big-Oh Notation


Example:

2n + 10  is  O(n)

  • 2n+10 ≤ c·n

    ⇒   (c-2)n ≥ 10

    ⇒   n ≥ 10/(c-2)

  • pick c=3 and n0=10
  

[Diagram:Pics/bigOh.png]

COMP2521 20T2 - Complexity ♢ [20/46]
❖ ... Big-Oh Notation


Example:

n2  is not  O(n)

  • n2c·n
    ⇒   nc
  • inequality cannot be satisfied since c must be a constant

[Diagram:Pics/bigOh-2.png]

COMP2521 20T2 - Complexity ♢ [21/46]
❖ Big-Oh and Rate of Growth


Big-Oh gives upper bound on growth rate of a function

Use big-Oh to rank functions according to their rate of growth

f(n) is O(g(n))g(n) is O(f(n))
g(n) grows fasteryesno
f(n) grows fasternoyes
same order of growthyesyes
COMP2521 20T2 - Complexity ♢ [22/46]
❖ Big-Oh Rules


How to determine O(n) from f(n) ...

COMP2521 20T2 - Complexity ♢ [23/46]
❖ Asymptotic Analysis of Algorithms

Asymptotic analysis of algorithms

Example: Constant factors and lower-order terms are eventually dropped
⇒ can disregard them when counting primitive operations
COMP2521 20T2 - Complexity ♢ [24/46]
❖ Example: Computing Prefix Averages

i-th prefix average of array X is average of first i elements:

A[i] = (X[0] + X[1] + … + X[i]) / (i+1)

Note: computing the array A of prefix averages of another array X has applications in e.g. financial analysis

COMP2521 20T2 - Complexity ♢ [25/46]
❖ ... Example: Computing Prefix Averages

A quadratic algorithm to compute prefix averages:

prefixAverages1(X):
|  Input  array X of n integers
|  Output array A of prefix averages of X
|
|  for all i=0..n-1 do          O(n)
|  |  s=X[0]                    O(n)
|  |  for all j=1..i do         O(n2)
|  |     s=s+X[j]               O(n2)
|  |  end for
|  |  A[i]=s/(i+1)              O(n)
|  end for
|  return A                     O(1)

Running time cost =   2·O(n2) + 3·O(n) + O(1) = O(n2)

time complexity of algorithm prefixAverages1 is O(n2)

COMP2521 20T2 - Complexity ♢ [26/46]
❖ ... Example: Computing Prefix Averages

The following algorithm computes prefix averages by keeping a running sum:

prefixAverages2(X):
|  Input  array X of n integers
|  Output array A of prefix averages of X
|
|  s=0
|  for all i=0..n-1 do          O(n)
|     s=s+X[i]                  O(n)
|     A[i]=s/(i+1)              O(n)
|  end for
|  return A                     O(1)

Thus, prefixAverages2 is O(n)

COMP2521 20T2 - Complexity ♢ [27/46]
❖ Example: Binary Search

The following recursive algorithm searches for a value in a sorted array:

search(v,a,lo,hi):
|  Input  value v
|         array a[lo..hi] of values
|  Output true if v in a[lo..hi]
|         false otherwise
|
|  mid=(lo+hi)/2
|  if lo>hi then return false
|  if a[mid]=v then
|     return true
|  else if a[mid]<v then
|     return search(v,a,mid+1,hi)
|  else
|     return search(v,a,lo,mid-1)
|  end if
COMP2521 20T2 - Complexity ♢ [28/46]
❖ ... Example: Binary Search

Successful search for a value of 8:

[Diagram:Pics/binary-search-found.png]

COMP2521 20T2 - Complexity ♢ [29/46]
❖ ... Example: Binary Search

Unsuccessful search for a value of 7:

COMP2521 20T2 - Complexity ♢ [30/46]
❖ ... Example: Binary Search

Cost analysis:

Thus, binary search is O(log2 n) or simply O(log n)
COMP2521 20T2 - Complexity ♢ [31/46]
❖ Math Needed for Complexity Analysis

  • Summations
  • Logarithms
    • logb (xy) = logb x + logb y
    • logb (x/y) = logb x - logb y
    • logb xa = a logb x
    • logb a = logx a / logx b
  • Exponentials
    • a(b+c) = abac
    • abc = (ab)c
    • ab / ac = a(b-c)
    • b = alogab
    • bc = ac·logab
  • Proof techniques
  • Summation   (addition of sequences of numbers)
  • Basic probability   (for average case analysis, randomised algorithms)

COMP2521 20T2 - Complexity ♢ [32/46]
❖ Relatives of Big-Oh

big-Omega

big-Theta

f(n) is O(g(n)) if f(n) is asymptotically less than or equal to g(n)

f(n) is Ω(g(n)) if f(n) is asymptotically greater than or equal to g(n)

f(n) is Θ(g(n)) if f(n) is asymptotically equal to g(n)

COMP2521 20T2 - Complexity ♢ [33/46]
❖ Complexity Classes

Problems in Computer Science …

Classes of problems:
NP stands for "nondeterministic, polynomial time"
COMP2521 20T2 - Complexity ♢ [34/46]
❖ ... Complexity Classes


Computer Science jargon for difficulty:

Programs for intractable problems are only usable for small n

Computational complexity theory deals with degrees of intractability

COMP2521 20T2 - Complexity ♢ [35/46]
❖ Generate and Test Algorithms

In scenarios where

then a generate and test strategy can be used.

It is necessary that states are generated systematically, so that


Some randomised algorithms do not require this   (more on this later in this course)
COMP2521 20T2 - Complexity ♢ [36/46]
❖ ... Generate and Test Algorithms

Simple example: checking whether an integer n is prime

Generation is straightforward: Testing is also straightfoward:
COMP2521 20T2 - Complexity ♢ [37/46]
❖ ... Generate and Test Algorithms

Function for primality checking:

isPrime(n):
|  Input  natural number n
|  Output true if n prime, false otherwise
|
|  for all i=2..n-1 do      // generate
|  |  if n mod i = 0 then   // test
|  |     return false       // i is a divisor => n is not prime
|  |  end if
|  end for
|  return true              // no divisor => n is prime

Complexity of isPrime is O(n)

Can be optimised: check only numbers between 2 and `|__sqrt n__|`     ⇒   O(`sqrt n`)

COMP2521 20T2 - Complexity ♢ [38/46]
❖ Example: Subset Sum


Problem to solve ...

Is there a subset S of these numbers with sum(S)=1000 ?

 34,  38,  39,  43,  55,  66,  67,  84,  85,
 91, 101, 117, 128, 138, 165, 168, 169, 182,
184, 186, 234, 238, 241, 276, 279, 288, 386,
387, 388, 389

General problem:

COMP2521 20T2 - Complexity ♢ [39/46]
❖ ... Example: Subset Sum

Generate and test approach:

subsetsum(A,n,k):
|  Input  set A of n integers, target sum k
|  Output true if Σb∈Bb=k for some B⊆A, false otherwise
|
|  for each subset S⊆A do
|  |  if sum(S)=k then
|  |     return true
|  |  end if
|  end for
|  return false

How many subsets are there of n elements?

How could we generate them?

COMP2521 20T2 - Complexity ♢ [40/46]
❖ ... Example: Subset Sum

Given: a set of n distinct integers in an array A

A method to generate subsets:
COMP2521 20T2 - Complexity ♢ [41/46]
❖ ... Example: Subset Sum

Algorithm:

subsetsum1(A,n,k):
|  Input  set A of n integers, target sum k
|  Output true if Σb∈Bb=k for some B⊆A, false otherwise
|
|  for s=0..2n-1 do
|  |  if k = Σ(ith bit of s is 1) A[i] then
|  |     return true
|  |  end if
|  end for
|  return false

Obviously, subsetsum1 is O(2n)

COMP2521 20T2 - Complexity ♢ [42/46]
❖ ... Example: Subset Sum

Alternative approach …

subsetsum2(A,n,k)

COMP2521 20T2 - Complexity ♢ [43/46]
❖ ... Example: Subset Sum

Algorithm:

subsetsum2(A,n,k):
|  Input  array A, index n, target sum k
|  Output true if Σb∈Bb=k, B=A[0..n-1], false otherwise
|
|  if k=0 then
|     return true   // empty set solves this
|  else if n=0 then
|     return false  // no elements => no sums
|  else
|     return subsetsum2(A,n-1,k-A[n-1])
|              ∨ subsetsum2(A,n-1,k)
|  end if

COMP2521 20T2 - Complexity ♢ [44/46]
❖ ... Example: Subset Sum

Cost analysis:

Thus, subsetsum2 also is O(2n)

Subset Sum is a member of the class of NP-complete problems

COMP2521 20T2 - Complexity ♢ [45/46]
❖ Summary



Here we considered only running time; memory space usage is also important
COMP2521 20T2 - Complexity ♢ [46/46]


Produced: 4 Jun 2020