Featured image of post III. Amortized Analysis

III. Amortized Analysis

Tightening algorithmic time bounds based on execution sequences

Introduction

Motivation

Analyzing an algorithm’s worst-case time complexity can be too pessimistic. Perhaps an algorithm A\mathcal{A} is usually cheap, but every nn executions, it is expensive. Should A\mathcal{A} be categorized as an expensive algorithm?

Definition

The amortized time cost for A\mathcal{A} is the average time cost per execution across any sequence of executions of length nn for some determined nn.

n=1n=1 is worst-case analysis, but larger nn can offer more optimistic analysis

Examples

Binary Counter

Problem

We want to store a big binary counter in an array AA initialized to 00. The cost model is every bit flip.

A4β€ΎA3β€ΎA2β€ΎA1β€ΎA0β€Ύcostβ€Ύ00000100001200010100011300100100101200110100111401000101001 \begin {array}{ccccc|c} \underline{A_4}\quad & \underline{A_3}\quad & \underline{A_2}\quad & \underline{A_1}\quad & \underline{A_0}\quad & \quad\underline{\textbf{cost}} \newline 0\quad & 0\quad & 0\quad & 0\quad & 0\quad & \newline & & & & & \quad1\newline 0\quad & 0\quad & 0\quad & 0\quad & \boxed{1}\quad & \newline & & & & & \quad2\newline 0\quad & 0\quad & 0\quad & \boxed{1}\quad & \boxed{0}\quad & \newline & & & & & \quad1\newline 0\quad & 0\quad & 0\quad & 1\quad & \boxed{1}\quad & \newline & & & & & \quad3\newline 0\quad & 0\quad & \boxed{1}\quad & \boxed{0}\quad & \boxed{0}\quad & \newline & & & & & \quad1\newline 0\quad & 0\quad & 1\quad & 0\quad & \boxed{1}\quad & \newline & & & & & \quad2\newline 0\quad & 0\quad & 1\quad & \boxed{1}\quad & \boxed{0}\quad & \newline & & & & & \quad1\newline 0\quad & 0\quad & 1\quad & 1\quad & \boxed{1}\quad & \newline & & & & & \quad4\newline 0\quad & \boxed{1}\quad & \boxed{0}\quad & \boxed{0}\quad & \boxed{0}\quad & \newline & & & & & \quad1\newline 0\quad & 1\quad & 0\quad & 0\quad & \boxed{1}\quad & \end {array}

The worst-case time complexity is O(log⁑n)\mathcal{O}(\log n) since at worst nn becomes a power of 22, and we have to flip all of its significant bits.

Amortized Analysis

Theorem
The amortized time cost is at most 22.
Proof
Consider nn (for large nn) executions beginning at any state. A0A_0 flips every execution. A1A_1 flips every other execution. A2A_2 flips every 4 executions. AkA_k flips every 2k2^k executions.

The total cost is the sum of these flips.

n+n2+n4+…≀2nn + \frac{n}{2} + \frac{n}{4} + … \leq 2n
Thus, the average per execution is at most 2∈O(1)2\in\mathcal{O}(1).

The β€œbeginning at any state” is important. Otherwise, our analysis is not generalizable.

Expensive Binary Counter

Problem

We want to store a big binary counter in an array AA initialized to 00. It costs 2k2^k to flip bit AkA_k.

Same problem but with exponential costs

A4β€ΎA3β€ΎA2β€ΎA1β€ΎA0β€Ύcostβ€Ύ000001000013000101000117001001001013001101001111501000101001 \begin {array}{ccccc|c} \underline{A_4}\quad & \underline{A_3}\quad & \underline{A_2}\quad & \underline{A_1}\quad & \underline{A_0}\quad & \quad\underline{\textbf{cost}} \newline 0\quad & 0\quad & 0\quad & 0\quad & 0\quad & \newline & & & & & \quad1\newline 0\quad & 0\quad & 0\quad & 0\quad & \boxed{1}\quad & \newline & & & & & \quad3\newline 0\quad & 0\quad & 0\quad & \boxed{1}\quad & \boxed{0}\quad & \newline & & & & & \quad1\newline 0\quad & 0\quad & 0\quad & 1\quad & \boxed{1}\quad & \newline & & & & & \quad7\newline 0\quad & 0\quad & \boxed{1}\quad & \boxed{0}\quad & \boxed{0}\quad & \newline & & & & & \quad1\newline 0\quad & 0\quad & 1\quad & 0\quad & \boxed{1}\quad & \newline & & & & & \quad3\newline 0\quad & 0\quad & 1\quad & \boxed{1}\quad & \boxed{0}\quad & \newline & & & & & \quad1\newline 0\quad & 0\quad & 1\quad & 1\quad & \boxed{1}\quad & \newline & & & & & \quad15\newline 0\quad & \boxed{1}\quad & \boxed{0}\quad & \boxed{0}\quad & \boxed{0}\quad & \newline & & & & & \quad1\newline 0\quad & 1\quad & 0\quad & 0\quad & \boxed{1}\quad & \end {array}

The worst-case time complexity is O(n)\mathcal{O}(n) since at worst nn becomes a power of 22, and we have to flip all of its significant bits (1+2+4+…+n2+n≀2n1+2+4+…+\frac{n}{2}+n\leq2n).

Amortized Analysis

Theorem
The amortized time cost is at most log⁑2(n)+1\log_2 (n) + 1.
Proof
Consider nn (for large nn) executions beginning at any state. A0A_0 flips every execution for a cost of 11. A1A_1 flips every other execution for a cost of 22. A2A_2 flips every 4 executions for a cost of 44. AkA_k flips every 2k2^k executions for a cost of 2k2^k.

nn has ⌊log⁑2n+1βŒ‹\lfloor\log_2 n + 1\rfloor significant bits.

The total cost is the sum of these flips.

n+2β‹…n2+4β‹…n4+β€¦βŸβŒŠlog⁑2n+1βŒ‹=n⌊log⁑2n+1βŒ‹\underbrace{n + 2\cdot\frac{n}{2} + 4\cdot\frac{n}{4} + …}_{\lfloor\log_2 n + 1\rfloor} = n\lfloor\log_2 n + 1\rfloor
Thus, the average per execution is ⌊log⁑2n+1βŒ‹βˆˆO(log⁑n)\lfloor\log_2 n + 1\rfloor\in\mathcal{O}(\log n).

Unbounded Array

Problem

We want to store a linear stream of data. We start with an Array A\mathcal{A} of memory space of size 11. Every new append inserts into A\mathcal{A}. If an append is attempted when A\mathcal{A} is completely filled, we must reallocate memory at double the size and re-insert previous data before inserting the new data.

It costs 11 to insert one slot of data.

Aβ€Ύcostβ€Ύβ–‘1β– 2β– β– 3β–‘β– β– β– 1β– β– β– β– 5β–‘β–‘β–‘β– β– β– β– β– 1β–‘β–‘β– β– β– β– β– β– 1β–‘β– β– β– β– β– β– β– 1β– β– β– β– β– β– β– β– 9β–‘β–‘β–‘β–‘β–‘β–‘β–‘β– β– β– β– β– β– β– β– β–  \begin {array}{c|c} \underline{A} & \underline{\textbf{cost}} \newline \Box&\newline &1\newline \blacksquare&\newline &2\newline \blacksquare\blacksquare&\newline &3\newline \Box\blacksquare\blacksquare\blacksquare&\newline &1\newline \blacksquare\blacksquare\blacksquare\blacksquare&\newline &5\newline \Box\Box\Box\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare&\newline &1\newline \Box\Box\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare&\newline &1\newline \Box\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare&\newline &1\newline \blacksquare\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare&\newline &9\newline \Box\Box\Box\Box\Box\Box\Box\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare\blacksquare&\newline \end {array}

The worst-case time complexity is O(n)\mathcal{O}(n) with respect to the data size since at worst, we are in a reallocation step where we must re-insert all old data.

Amortized Analysis

Theorem
The amortized time cost is at most 33.
Proof
Consider nn (for large nn) executions beginning at any state. Without including the cost of inserting old data, every append costs exactly 11. In total, this has cost nn.

Inserting old data costs the size of the old array. In total, this costs at most n+n2+…≀2nn + \frac{n}{2} + … \leq 2n.

Thus, the total cost is at most n+2n=3nn+2n=3n and the average cost per execution is 33.

Potentials

Potentials offer a more rigorous approach to amortized analysis. What we’ve been doing is still entirely correct, but might be problematically difficult with more complex algorithms.

Intuition: Banker’s Method

The intuitive way to think about potentials is with a bank. Every time A\mathcal{A} is executed, we earn some amount of coins k(S)k(S) (function on data-structure state). If the current A\mathcal{A} operation is cheap, we can split our earnings between this operation and saving it in the bank. If the current A\mathcal{A} operation is expensive, we can use our funds from the bank to support it.

k(S)k(S) is an amoritized time bound on A\mathcal{A} if we will always have enough coins to pay for an operation at any given time.

Definition

The potential function Ξ¦\Phi is a function mapping data-structure states to R\reals. It represents the β€œpotential” of that state (the coin cost).

Let aciac_i represent the amortized cost over ii algorithm executions. Let cic_i be the cost of the iith execution, and let SiS_i being the resulting state.

aci=ci+Ξ¦(Si)βˆ’Ξ¦(Siβˆ’1)ac_i = c_i + \Phi(S_i)-\Phi(S_{i-1}) Analogically, amortized cost=actual cost+change in potential\text{amortized cost}=\text{actual cost}+\text{change in potential}.

βˆ‘iaci=βˆ‘i(ci+Ξ¦(Si)βˆ’Ξ¦(Siβˆ’1))=βˆ‘ici+Ξ¦(Sn)βˆ’Ξ¦(S0)\begin{align*}\sum_iac_i&=\sum_i(c_i+\Phi(S_i)-\Phi(S_{i-1}))\newline&=\sum_ic_i+\Phi(S_n)-\Phi(S_0)\end{align*}

Observe that if Ξ¦(Sn)β‰₯Ξ¦(S0)\Phi(S_n)\geq\Phi(S_0) (which is frequently the case): βˆ‘iciβ‰€βˆ‘iaci\sum_ic_i\leq\sum_iac_i

Note that Ξ¦(S)\Phi(S) can be defined in any way, but unless Ξ¦(S0)βˆ’Ξ¦(Sn)\Phi(S_0)-\Phi(S_n) is appropriately bounded (as in above), our determined acac has no meaning.

Revisiting Binary Counter

Theorem
The amortized time cost is at most 22.
Proof
Let Ξ¦(S)=1s in S\Phi(S)=1\text{s in }S.

Consider the iith execution iβˆ’1β†’ii-1\rightarrow i. Let kk be the number of carries that occur.

In 10100β†’1010110100\rightarrow 10101, β€…β€Šk=0\thickspace k=0

In 10111β†’1100010111\rightarrow 11000, β€…β€Šk=3\thickspace k=3

Ξ¦(Si)βˆ’Ξ¦(Siβˆ’1)=βˆ’k+1\Phi(S_i)-\Phi(S_{i-1})=-k+1 since kk 11s become 00 and one 00 becomes a 11.

For the same reason, ci=k+1c_i=k+1.

In 10100β†’1010110100\rightarrow 10101

  • costs 11
  • changes potential from 2β†’32\rightarrow 3

In 10111β†’1100010111\rightarrow 11000, β€…β€Šk=3\thickspace k=3

  • costs 44
  • changes potential from 4β†’24\rightarrow 2

Thus, aci=(k+1)+(βˆ’k+1)=2ac_i=(k+1)+(-k+1)=2.

Since Ξ¦(Sn)β‰₯Ξ¦(S0)β€…β€Šβˆ€n\Phi(S_n)\geq\Phi(S_0)\thickspace\forall n,

βˆ‘iciβ‰€βˆ‘iaci\sum_ic_i\leq\sum_iac_i
My heart is in the work ― Andrew Carnegie
Built with Hugo
Theme Stack designed by Jimmy