Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

 Open In Colab

Measuring Performance

When writing numerical methods, we need to compare how fast different algorithms are. However, execution time depends on the computer’s hardware.

Instead, we use computational complexity to characterize the number of operations an algorithm requires based on the size of its inputs (e.g., vector length nn, or matrix size n×nn \times n).

Big-O Notation

Complexity is represented using Big-O notation (O\mathcal{O}).

Similar to how we tracked the leading order of truncation error, Big-O notation only keeps the dominant leading term and disregards scalar constants as nn becomes very large.

  • O(n)\mathcal{O}(n): Linear time (complexity). Doubling the input size doubles the operations.

  • O(n2)\mathcal{O}(n^2): Quadratic time. Doubling the input size quadruples the operations.

  • O(n3)\mathcal{O}(n^3): Cubic time. Doubling the input size multiplies operations by 8.

Example: Matrix Multiplication

Traditional matrix multiplication of two n×nn \times n matrices requires multiplying every row of A\mathbf{A} by every column of B\mathbf{B}.

  • There are n2n^2 elements in the resulting matrix.

  • Calculating each element requires a dot product of length nn.

  • Total operations: n2×n=n3n^2 \times n = n^3.

Therefore, standard matrix multiplication is O(n3)\mathcal{O}(n^3).

Note: This is algorithm-dependent! Advanced algorithms (like the Strassen algorithm) can achieve O(n2.81)\mathcal{O}(n^{2.81}) by cleverly reusing sub-calculations.

Profiling Execution Time

Let’s prove this by actually timing matrix multiplication in Python for different matrix sizes nn, and plotting the execution time!

NB: Techincally this profiles the time, not the # of operations. It is however a useful and quick surrogate.

Common Linear Algebra Operations

Here is the computational complexity for standard operations on n×nn \times n matrices:

OperationDescriptionComplexity
Matrix additionAdding two matricesO(n2)\mathcal{O}(n^2)
Matrix normSquare root of sum of squaresO(n2)\mathcal{O}(n^2)
TransposeSwapping rows and columnsO(n2)\mathcal{O}(n^2)
Matrix-vector multMultiplying a matrix by a vectorO(n2)\mathcal{O}(n^2)
Matrix multiplicationMultiplying two matricesO(n3)\mathcal{O}(n^3)
Matrix inversionFinding the exact inverseO(n3)\mathcal{O}(n^3)
DeterminantComputing the determinantO(n3)\mathcal{O}(n^3)

Scaling in Parallel Computing

High-performance computing introduces a new element to complexity: scaling.

Instead of asking how execution time grows with input size nn, scaling asks how execution time decreases as we add more parallel hardware (CPU cores or compute nodes).

This is measured in O(number of nodes)\mathcal{O}(\text{number of nodes}). The ultimate goal is perfectly linear scaling O(N)\mathcal{O}(N), meaning 100 computers will solve the problem 100 times faster—but due to communication overhead, this is notoriously difficult to achieve!