10.4. The Fast Fourier Transform 489
The fast Fourier transform (FFT) algorithm allows us to perform this multi-
plication in O(n log n) time. The improvement of the FFT is based on an interesting
observation. Namely, that another way of representing a degree-(n − 1) polynomial
is by its value on n distinct inputs. Such a representation is unique because of the
following theorem.
Theorem 10.24 [The Interpolation Theorem for Polynomials]: Given a set
of n points in the plane, S = {(x0, y0), (x1, y1), (x2, y2), . . . , (xn−1, yn−1)}, such that
the xi’s are all distinct, there is a unique degree-(n − 1) polynomial p(x) with
p(xi) = yi, for i = 0, 1, . . . , n − 1.
Suppose, then, that we can represent a polynomial not by its coefficients, but
instead by its value on a collection of different inputs. This theorem suggests an
alternative method for multiplying two polynomials p and q. In particular, evaluate
p and q for 2n different inputs x0, x1, . . . , x2n−1 and compute the representation of
the product of p and q as the set
{(x0, p(x0)q(x0)), (x1, p(x1)q(x1)), . . . , (x2n−1, p(x2n−1)q(x2n−1))}.
Such a computation would clearly take just O(n) time given the 2n input-output
pairs for each of p and q.
The challenge, then, to effectively using this approach to multiply p and q is to
come up quickly with 2n input-output pairs for p and q. Applying Horner’s rule to
2n different inputs would take us Θ(n2) time, which is not asymptotically any faster
than using the convolution directly. So Horner’s rule is of no help here. Of course,
we have full freedom in how we choose the set of 2n inputs for our polynomials.
That is, we have full discretion to choose inputs that are easy to evaluate. For
example, p(0) = a0 is a simple case. But we have to choose a set of 2n easy inputs
to evaluate p on, not just one. Fortunately, the mathematical concept we discuss
next provides a convenient set of inputs that are collectively easier to use to evaluate
a polynomial than applying Horner’s rule 2n times.
10.4.1 Primitive Roots of Unity
A number ω is a primitive nth root of unity, for n ≥ 2, if it satisfies the following
properties:
1. ωn = 1, that is, ω is an nth root of 1.
2. The numbers 1, ω, ω2, . . . , ωn−1 are distinct.
Note that this definition implies that a primitive nth root of unity has a multiplicative
inverse, ω−1 = ωn−1, for
ω−1ω = ωn−1ω = ωn = 1.
Thus, we can speak in a well-defined fashion of negative exponents of ω, as well
as positive ones.
490 Chapter 10. Number Theory and Cryptography
The notion of a primitive nth root of unity may, at first, seem like a strange
definition with few examples. But it actually has several important instances. One
important one is the complex number
e2πi/n = cos(2π/n) + i sin(2π/n),
which is a primitive n√th root of unity, when we take our arithmetic over the complex
numbers, where i = −1.
Primitive nth roots of unity have a number of important properties, including
the following three ones.
Lemma 10.25 (Cancellation Property): If ω is an nth root of unity, then, for
any integer k = 0, with −n < k < n,
n−1
∑ ωk j = 0.
j=0
Proof: Since ωk = 1,
∑n−1 = (ωk)n − 1 = (ωn)k − 1 = 1k − 1 = 1−1 = 0
ωk − 1 ωk − 1 ωk − 1 ωk − 1
ωk j
j=0
Lemma 10.26 (Reduction Property): If ω is a primitive (2n)th root of unity,
then ω2 is a primitive nth root of unity.
Proof: If 1, ω, ω2, . . . , ω2n−1 are distinct, then 1, ω2, (ω2)2, . . . , (ω2)n−1 are also
distinct.
Lemma 10.27 (Reflective Property): If ω is a primitive nth root of unity and
n is even, then
ωn/2 = −1.
Proof: By the cancellation property, for k = n/2,
n−1 ω(n/2) j
∑0 =
j=0
= ω0 + ωn/2 + ωn + ω3n/2 + · · · + ω(n/2)(n−2) + ω(n/2)(n−1)
= ω0 + ωn/2 + ω0 + ωn/2 + · · · + ω0 + ωn/2
= (n/2)(1 + ωn/2).
Thus, 0 = 1 + ωn/2.
An interesting corollary to the reflective property, which motivates its name, is
the fact that if ω is a primitive nth root of unity and n ≥ 2 is even, then
ωk+n/2 = −ωk.
10.4. The Fast Fourier Transform 491
10.4.2 The Discrete Fourier Transform
Let us now return to the problem of evaluating a polynomial defined by a coefficient
vector a as
n−1
p(x) = ∑ aixi,
i=0
for a carefully chosen set of input values. The technique we discuss in this section,
called the Discrete Fourier Transform (DFT), is to evaluate p(x) at the nth roots
of unity, ω0, ω1, ω2, . . . , ωn−1. Admittedly, this gives us just n input-output pairs,
but we can “pad” our coefficient representation for p with 0’s by setting ai = 0, for
n ≤ i ≤ 2n − 1. This padding would let us view p as a degree-(2n − 1) polynomial,
which would in turn let us use the primitive (2n)th roots of unity as inputs for a
DFT for p. Thus, if we need more input-output values for p, let us assume that the
coefficient vector for p has already been padded with as many 0’s as necessary.
Formally, the Discrete Fourier Transform for the polynomial p represented by
the coefficient vector a is defined as the vector y of values
y j = p(ω j),
where ω is a primitive nth root of unity. That is,
n−1
∑y j = aiωi j.
i=0
In the language of matrices, we can alternatively think of the vector y of y j values
and the vector a as column vectors, and say that
y = Fa,
where F is an n × n matrix such that F[i, j] = ωi j.
The Inverse Discrete Fourier Transform
Interestingly, the matrix F has an inverse, F−1, so that F−1(F(a)) = a for all a.
The matrix F−1 allows us to define an inverse Discrete Fourier Transform. If
we are given a vector y of the values of a degree-(n − 1) polynomial p at the nth
roots of unity, ω0, ω1, . . . , ωn−1, then we can recover a coefficient vector for p by
computing
a = F−1y.
Moreover, the matrix F−1 has a simple form, in that F−1[i, j] = ω−i j/n. Thus, we
can recover the coefficient ai as
n−1
∑ai = y jω−i j/n.
j=0
The following lemma justifies this claim, and is the basis of why we refer to F and
F−1 as “transforms.”
492 Chapter 10. Number Theory and Cryptography
Lemma 10.28: For any vector a, F−1 · Fa = a.
Proof: Let A = F−1 ·F. It is enough to show that A[i, j] = 1 if i = j, and A[i, j] = 0
if i = j. That is, A = I, where I is the identity matrix. By the definitions of F−1, F,
and matrix multiplication,
1 n−1
ω−ikωk j.
∑A[i,j]=
n k=0
If i = j, then this equation reduces to
1 n−1 1
ω0
∑A[i, i]= = n · n = 1.
n k=0
So, consider the case when i = j, and let m = j − i. Then the i jth entry of A can be
written as
1 n−1
ωmk,
∑A[i,j] =
n k=0
where −n < m < n and m = 0. By the cancellation property for a primitive nth root
of unity, the right-hand side of the above equation reduces to 0; hence,
A[i, j] = 0,
for i = j.
Given the DFT and the inverse DFT, we can now define our approach to multi-
plying two polynomials p and q.
The Convolution Theorem
To use the discrete Fourier transform and its inverse to compute the convolution of
two coefficient vectors, a and b, we apply the following steps, which we illustrate
in a schematic diagram, as shown in Figure 10.15.
1. Pad a and b each with n 0’s and view them as column vectors to define
a = [a0, a1, . . . , an−1, 0, 0, . . . , 0]T
b = [b0, b1, . . . , bn−1, 0, 0, . . . , 0]T .
2. Compute the Discrete Fourier Transforms y = Fa and z = Fb .
3. Multiply the vectors y and z component-wise, defining the simple product
y · z = Fa · Fb , where
(y · z)[i] = (Fa · Fb )[i] = Fa [i] · Fb [i] = yi · zi,
for i = 1, 2, . . . , 2n − 1.
4. Compute the inverse Discrete Fourier Transform of this simple product. That
is, compute c = F−1(Fa · Fb ).
10.4. The Fast Fourier Transform 493
[a0,a1,a2,...,an-1] [b0,b1,b2,...,bn-1]
Pad with n 0's Pad with n 0's
[a0,a1,a2,...,an-1,0,0,...,0] [b0,b1,b2,...,bn-1,0,0,...,0]
DFT DFT
[y0,y1,y2,...,y2n-1] [z0,z1,z2,...,z2n-1]
Component
Multiply
[y0z0,y1z1,...,y2n-1z2n-1]
inverse DFT
[c0,c1,c2,...,c2n-1]
(Convolution)
Figure 10.15: An illustration of the Convolution Theorem, to compute c = a ∗ b.
494 Chapter 10. Number Theory and Cryptography
The reason the above approach works is because of the following.
Theorem 10.29 [The Convolution Theorem]: Suppose we are given two n-
length vectors a and b padded with 0’s to 2n-length vectors a and b , respectively.
Then a ∗ b = F−1(Fa · Fb ).
Proof: We will show that F(a ∗ b) = Fa · Fb . So, consider A = Fa · Fb . Since
the second halves of a and b are padded with 0’s,
n−1 n−1 bk ωik
∑ ∑a jωi j ·
A[i] =
j=0 k=0
n−1 n−1
∑ ∑= a jbkωi( j+k),
j=0 k=0
for i = 0, 1, . . . , 2n − 1. Consider, next, B = F(a ∗ b). By the definition of convolu-
tion and the DFT,
2n−1 2n−1 a jbl− jωil.
∑ ∑B[i] =
l=0 j=0
Substituting k for l − j, and changing the order of the summations, we get
2n−1 2n−1− j a jbkωi( j+k).
∑ ∑B[i] =
j=0 k=− j
Since bk is undefined for k < 0, we can start the second summation above at k = 0.
In addition, since a j = 0 for j > n − 1, we can lower the upper limit in the first
summation above to n − 1. But once we have made this substitution, note that the
upper limit on the second summation above is always at least n. Thus, since bk = 0
for k > n − 1, we may lower the upper limit on the second summation to n − 1.
Therefore,
n−1 n−1 a jbkωi( j+k),
∑ ∑B[i] =
j=0 k=0
which proves the theorem.
We now have a method for computing the multiplication of two polynomials
that involves computing two DFTs, doing a simple linear-time component-wise
multiplication, and computing an inverse DFT. Thus, if we can find a fast algo-
rithm for computing the DFT and its inverse, then we will have a fast algorithm for
multiplying two polynomials. We describe such a fast algorithm, which is known
as the “fast Fourier transform,” next.
10.4. The Fast Fourier Transform 495
10.4.3 The Fast Fourier Transform Algorithm
The Fast Fourier Transform (FFT) Algorithm computes a Discrete Fourier Trans-
form (DFT) of an n-length vector in O(n log n) time. In the FFT algorithm, we
apply the divide-and-conquer approach to polynomial evaluation by observing that
if n is even, we can divide a degree-(n − 1) polynomial
p(x) = a0 + a1x + a2x2 + · · · + an−1xn−1
into two degree-(n/2 − 1) polynomials
peven(x) = a0 + a2x + a4x2 + · · · + an−2xn/2−1
podd(x) = a1 + a3x + a5x2 + · · · + an−1xn/2−1
and noting that we can combine these two polynomials into p using the equation
p(x) = peven(x2) + xpodd(x2).
The DFT evaluates p(x) at each of the nth roots of unity, ω0, ω1, ω2, . . . , ωn−1. Note
that, by the reduction property, the values (ω2)0, ω2, (ω2)2, (ω2)3, . . . , (ω2)n−1 are
(n/2)th roots of unity. Thus, we can evaluate each of peven(x) and podd(x) at
these values, and we can reuse those same computations in evaluating p(x). This
observation is used in Algorithm 10.16 (FFT) to define the, which takes as input
an n-length coefficient vector a and a primitive nth root of unity ω. For the sake of
simplicity, we assume that n is a power of two.
Algorithm FFT(a, ω):
Input: An n-length coefficient vector a = [a0, a1, . . . , an−1] and a primitive nth
root of unity ω, where n is a power of 2
Output: A vector y of values of the polynomial for a at the nth roots of unity
if n = 1 then
return y = a.
x ← ω0 {x will store powers of ω, so initially x = 1.}
{Divide Step, which separates even and odd indices}
aeven ← [a0, a2, a4, . . . , an−2]
aodd ← [a1, a3, a5, . . . , an−1]
{Recursive Calls, with ω2 as (n/2)th root of unity, by the reduction property}
yeven ← FFT(aeven, ω2)
yodd ← FFT(aodd, ω2)
{Combine Step, using x = ωi}
for i ← 0 to n/2 − 1 do
yi ← yei ven + x · yoi dd {Uses reflective property}
yi+n/2 ← yei ven − x · yoi dd
x ← x·ω
return y
Algorithm 10.16: Recursive FFT algorithm.
496 Chapter 10. Number Theory and Cryptography
The Correctness of the FFT Algorithm
The pseudo-code description in Algorithm 10.16 for the FFT algorithm is decep-
tively simple, so let us say a few words about why it works correctly. First, note
that the base case of the recursion, when n = 1, correctly returns a vector y with
the one entry, y0 = a0, which is the leading and only term in the polynomial p(x)
in this case.
In the general case, when n ≥ 2, we separate a into its even and odd instances,
aeven and aodd, and recursively call the FFT using ω2 as the (n/2)th root of unity.
As we have already mentioned, the reduction property of a primitive nth root of
unity, allows us to use ω2 in this way. Thus, we may inductively assume that
yei ven = peven(ω2i)
yiodd = podd(ω2i).
Let us therefore consider the for-loop that combines the values from the recursive
calls. Note that in the i iteration of the loop, x = ωi. Thus, when we perform the
assignment statement
yi ← yei ven + xyoi dd,
we have just set
yi = peven((ω2)i) + ωi · podd((ω2)i)
= peven((ωi)2) + ωi · podd((ωi)2)
= p(ωi),
and we do this for each index i = 0, 1, . . . , n/2 − 1. Similarly, when we perform the
assignment statement
yi+n/2 ← yei ven − xyoi dd,
we have just set
yi+n/2 = peven((ω2)i) − ωi · podd((ω2)i).
Since ω2 is a primitive (n/2)th root of unity, (ω2)n/2 = 1. Moreover, since ω is
itself a primitive nth root of unity,
ωi+n/2 = −ωi,
by the reflection property. Thus, we can rewrite the above identity for yi+n/2 as
yi+n/2 = peven((ω2)i+(n/2)) − ωi · podd((ω2)i+(n/2))
= peven((ωi+(n/2))2) + ωi+n/2 · podd((ωi+(n/2))2)
= p(ωi+n/2),
and this will hold for each i = 0, 1, . . . , n/2 − 1. Thus, the vector y returned by the
FFT algorithm will store the values of p(x) at each of the nth roots of unity.
10.4. The Fast Fourier Transform 497
Analyzing the FFT Algorithm
The FFT algorithm follows the divide-and-conquer paradigm, dividing the original
problem of size n into two subproblems of size n/2, which are solved recursively.
We assume that each arithmetic operation performed by by algorithms takes O(1)
time. The divide step as well as the combine step for merging the recursive solu-
tions, each take O(n) time. Thus, we can characterize the running time T (n) of the
FFT algorithm using the recurrence equation
T (n) = 2T (n/2) + bn,
for some constant b > 0. By the Master Theorem (5.6), T (n) is O(n log n). There-
fore, we can summarize our discussion as follows.
Theorem 10.30: Given an n-length coefficient vector a defining a polynomial
p(x), and a primitive nth root of unity, ω, the FFT algorithm evaluates p(x) at each
of the nth roots of unity, ωi, for i = 0, 1, . . . , n − 1, in O(n log n) time.
There is also an inverse FFT algorithm, which computes the inverse DFT in
O(n log n) time. The details of this algorithm are similar to those for the FFT
algorithm and are left as an exercise (R-10.14). Combining these two algorithms
in our approach to multiplying two polynomials p(x) and q(x), given their n-length
coefficient vectors, we have an algorithm for computing this product in O(n log n)
time.
By the way, this approach for using the FFT algorithm and its inverse to com-
pute the product of two polynomials can be extended to the problem of computing
the product of two large integers. We discuss this method next.
10.4.4 Multiplying Big Integers
Let us revisit the problem studied in Section 5.2.2. Namely, suppose we are given
two big integers I and J that use at most N bits each, and we are interested in
computing I ·J. The main idea of the method we describe in this section is to use the
FFT algorithm to compute this product. Of course, a major challenge in utilizing
the FFT algorithmic design pattern in this way is to define integer arithmetic so that
it gives rise to primitive roots of unity (see, for example, Exercise C-10.8).
The algorithm we describe here assumes that we can break I and J up into
words of O(log N) bits each, such that arithmetic on each word can be done using
built-in operations in our computer model in constant time. This is a reasonable
assumption, since it takes log N bits just to represent the number N itself. The
number system we use for the FFT in this case is to perform all arithmetic modulo
p, for a suitably chosen prime number p, which itself can be represented in a single
word of at most O(log N) bits. The specific prime modulus p we choose is to find
small integers c ≥ 1 and n ≥ 1, such that p = cn + 1 is prime and N/ log p ≤ n/2.
For the sake of the simplicity of our description, let us additionally assume that n
is a power of two.
498 Chapter 10. Number Theory and Cryptography
In general, we would expect c in the above definition of p to be O(log n), since
a fundamental theorem from number theory states that a random odd number in
the range [1, n] is prime with probability Ω(1/ log n). That is, we expect p to be
represented with O(log N) bits. Given this prime number p, our intent is to perform
all arithmetic in the FFT modulo p. Since we are performing this arithmetic on the
words of a large vector of integers, we also want the size of each word to be less
than half of that used to represent p, so we can represent the product of any two
words without having the modulo-p arithmetic “wipe out” any pairwise products
of words. For example, the following values of p work well for modern computers:
• If n ≤ 210 = 1024, then we choose p = 25 · 210 + 1 = 25 601 as our prime
modulus, which can be represented using a 15-bit word. Moreover, since
p > 214 in this case, such a choice allows us to multiply numbers whose
representations are as large as 210 words of 7 bits each.
• If n ≤ 227 = 134 217 728, then we choose p = 15 · 227 + 1 = 2 013 265 921 as
our prime modulus, which uses a 31-bit word. Moreover, since p > 230 in
this case, we can multiply numbers whose representations are as large as 227
words of 15 bits each, or 240MB.
Given a prime p = cn + 1, for reasonably small c ≥ 1, and n defined so that
N/ log p is O(n), we define m = (log p)/2 . We view I and J respectively as
being vectors a and b of words that use m bits each, extended with as many 0’s
as needed to make a and b both have length n, with at least the last half of their
higher-order terms being 0. We can write I and J as
n−1 ai 2mi
∑I =
i=0
n−1 bi 2mi .
∑J =
i=0
Moreover, we choose n so that the first n/2 of the ai’s and bi’s are nonzero at most.
Thus, we can represent the product K = I · J, as
n−1 ci 2mi .
∑K =
i=0
Once we have a prime number p = cn + 1, for a reasonably small integer c ≥ 1,
we find an integer x that is a generator of the group Z ∗ (see Section 10.1). That is,
p
we find x such that xi mod p is different for i = 0, 1, . . . , p − 1. Given such a gen-
erator, x, then we can use ω = xc mod p as a primitive nth root of unity (assuming
all multiplication and addition is done modulo p). That is, each of (xc)i mod p are
distinct for i = 0, 1, 2, . . . , n − 1, but, by Fermat’s Little Theorem (Theorem 10.8),
(xc)n mod p = xcn mod p
= xp−1 mod p
= 1.
10.4. The Fast Fourier Transform 499
In order to compute the product of the big N-bit integers I and J, recall that
view I and J, respectively, as extended n-length vectors a and b of words having m
bits each (with at least the n/2 higher-order words being all 0’s). Note that, since
m = log p/2 , we have that 2m < p. Thus, each of the terms in a and b is already
reduced modulo p without us having to do any additional work, and any product of
two of these terms is also reduced modulo p.
To compute K = I · J, we then apply the Convolution Theorem, using the FFT
and inverse FFT algorithms, to compute the convolution c of a and b. In this
computation we use ω, as defined above, as the primitive nth root of unity, and
we perform all the internal arithmetic (including the component-wise products of
the transformed versions of a and b) modulo p.
The terms in the convolution c are all less than p, but in order to build a repre-
sentative of K = I · J, we actually need each term to be represented using exactly m
bits. Thus, after we have the convolution c, we must compute the product K as
n−1 ci 2mi .
∑K =
i=0
This final computation is not as difficult as it looks, however, since multiplying by
a power of two in binary is just a shifting operation. Moreover, p is O(2m+1), so
the above summation just involves propagating some groups of carry bits from one
term to the next. Thus, this final construction of a binary representation of K as
a vector of words of m bits each can be done in O(n) time. Since applying the
Convolution Theorem as described above takes O(n log n) time, this gives us the
following.
Theorem 10.31: Given two N-bit integers I and J, we can compute the product
K = I · J in O(N) time, assuming that arithmetic involving words of size O(log N)
can be done in constant time.
Proof: The number n is chosen so that it is O(N/ log N). Thus a running time
of O(n log n) is O(N), assuming that arithmetic operations involving words of size
O(log N) can be done in constant time.
In some cases, we cannot assume that arithmetic involving O(log n)-size words
can be done in constant time, but instead, we must pay constant time for every
bit operation. In this model it is still possible to use the FFT to multiply two N-
bit integers, but the details are somewhat more complicated and the running time
increases to O(N log N log log N).
In Section 10.5, we study some important implementation issues related to the
FFT algorithm, including an experimental analysis of how well it performs in prac-
tice.
500 Chapter 10. Number Theory and Cryptography
10.5 Java Example: FFT
There are a number of interesting implementation issues related to the FFT algo-
rithm, which we discuss in this section. We begin with the description of a big inte-
ger class that performs multiplication using the recursive version of the FFT, as de-
scribed above in pseudo-code in Algorithm 10.16. We show the declaration of this
class and its important instance variables and constants in Code Fragment 10.17. A
significant detail in these declarations includes our defining the primitive nth root
of unity, OMEGA. Our choice of 3115 derives from the fact that 31 is a generator
for Z ∗ for the prime number 15 · 227 + 1. We know 31 is a generator for this Z∗p,
p
because of a theorem from number theory. This theorem states that an integer x is
a generator of Z ∗ if and only if xφ( p)/q mod p is not equal to 1 for any prime divisor
p
q of φ(p), where φ(p) is the Euler totient function defined in Section 10.1. For our
particular p, φ(p) = 15 · 227; hence, the only prime divisors q we need to consider
are 2, 3, and 5.
import java.lang.*;
import java.math.*;
import java.util.*;
public class BigInt {
protected int signum=0; // neg = -1, 0 = 0, pos = 1
protected int[ ] mag; // magnitude in little-endian format
public final static int MAXN=134217728; // Maximum value for n
public final static int ENTRYSIZE=15; // Bits per entry in mag
protected final static long P=2013265921; // The prime 15*2^{27}+1
protected final static int OMEGA=440564289; // Root of unity 31^{15} mod P
protected final static int TWOINV=1006632961; // 2^{-1} mod P
Code Fragment 10.17: Declarations and instance variables for a big integer class
that supports multiplication using the FFT algorithm.
A Recursive FFT Implementation
We show the multiplication method of our big integer class, BigInt, in Code Frag-
ment 10.18, and, in Code Fragment 10.19, we show our implementation of the re-
cursive FFT algorithm. Note that we use a variable, prod, to store the product that
is used in the subsequent two expressions. By factoring out this common subex-
pression we can avoid performing this repeated computation twice. In addition,
note that all modular arithmetic is performed as long operations. This requirement
is due to the fact that P uses 31 bits, so that we may need to perform additions and
subtractions that would overflow a standard-size integer. Instead, we perform all
arithmetic as long operations and then store the result back to an int.
10.5. Java Example: FFT 501
public BigInt multiply(BigInt val) {
int n = makePowerOfTwo(Math.max(mag.length,val.mag.length))*2;
int signResult = signum * val.signum;
int[ ] A = padWithZeros(mag,n); // copies mag into A padded w/ 0’s
int[ ] B = padWithZeros(val.mag,n); // copies val.mag into B padded w/ 0’s
int[ ] root = rootsOfUnity(n); // creates all n roots of unity
int[ ] C = new int[n]; // result array for A*B
int[ ] AF = new int[n]; // result array for FFT of A
int[ ] BF = new int[n]; // result array for FFT of B
FFT(A,root,n,0,AF);
FFT(B,root,n,0,BF);
for (int i=0; i<n; i++)
AF[i] = (int)(((long)AF[i]*(long)BF[i]) % P); // Component multiply
reverseRoots(root); // Reverse roots to create inverse roots
inverseFFT(AF,root,n,0,C); // Leaves inverse FFT result in C
propagateCarries(C); // Convert C to right no. bits per entry
return new BigInt(signResult,C);
}
Code Fragment 10.18: The multiplication method for a big integer class that sup-
ports multiplication using a recursive FFT algorithm.
public static void FFT(int[ ] A, int[ ] root, int n, int base, int[ ] Y) {
int prod;
if (n==1) {
Y[base] = A[base];
return;
}
inverseShuffle(A,n,base); // inverse shuffle to separate evens and odds
FFT(A,root,n/2,base,Y); // results in Y[base] to Y[base+n/2-1]
FFT(A,root,n/2,base+n/2,Y); // results in Y[base+n/2] to Y[base+n-1]
int j = A.length/n;
for (int i=0; i<n/2; i++) {
prod = (int)(((long)root[i*j]*Y[base+n/2+i]) % P);
Y[base+n/2+i] = (int)(((long)Y[base+i] + P − prod) % P);
Y[base+i] = (int)(((long)Y[base+i] + prod) % P);
}
}
public static void inverseFFT(int[ ] A, int[ ] root, int n, int base, int[ ] Y) {
int inverseN = modInverse(n); // n^{-1}
FFT(A,root,n,base,Y);
for (int i=0; i<n; i++)
Y[i] = (int)(((long)Y[i]*inverseN) % P);
}
Code Fragment 10.19: A recursive implementation of the FFT algorithm.
502 Chapter 10. Number Theory and Cryptography
Avoiding Repeated Array Allocation
The pseudo-code for the recursive FFT algorithm calls for the allocation of several
new arrays, including aeven, aodd, yeven, yodd, and y. Allocating all of these
arrays with each recursive call could prove to be a costly amount of extra work.
If it can be avoided, saving this additional allocation of arrays could significantly
improve the constant factors in the O(n log n) time (or O(N) time) performance of
the FFT algorithm.
Fortunately, the structure of FFT allows us to avoid this repeated array alloca-
tion. Instead of allocating many arrays, we can use a single array, A, for the input
coefficients and use a single array, Y , for the answers. The main idea that allows for
this usage is that we can think of the arrays A and Y as partitioned into subarrays,
each one associated with a different recursive call. We can identify these subarrays
using just two variables, base, which identifies the base address of the subarray,
and n, which identifies the size of the subarray. Thus, we can avoid the overhead
associated with allocating lots of small arrays with each recursive call.
The Inverse Shuffle
Having decided that we will not allocate new arrays during the FFT recursive calls,
we must deal with the fact that the FFT algorithm involves performing separate
computations on even and odd indices of the input array. In the pseudo-code of Al-
gorithm 10.16, we use new arrays aeven and aodd, but now we must use subarrays
in A for these vectors. Our solution for this memory management problem is to take
the current n-cell subarray in A, and divide it into two subarrays of size n/2. One of
the subarrays will have the same base as A, while the other has base base+ n/2. We
move the elements at even indices in A to the lower half and we move elements at
odd indices in A to the upper half. In doing so, we define an interesting permutation
known as the inverse shuffle. This permutation gets its name from its resemblance
to the inverse of the permutation we would get by cutting the array A in half and
shuffling it perfectly as if it were a deck of cards. (See Figure 10.20.)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
old A:
new A:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Figure 10.20: An illustration of the inverse shuffle permutation.
10.5. Java Example: FFT 503
Precomputing Roots of Unity and Other Optimizations
There are a number of additional optimizations that we utilized in our FFT im-
plementation. In Code Fragment 10.21, we show some of the important support
methods for our implementation, including the computation of the inverse n−1, the
inverse shuffle permutation, the precomputation of all the nth roots of unity, prop-
agation of the carries after the convolution has been computed modulo p.
protected static int modInverse(int n) { // assumes n is power of two
int result = 1;
for (long twoPower = 1; twoPower < n; twoPower *= 2)
result = (int)(((long)result*TWOINV) % P);
return result;
}
protected static void inverseShuffle(int[ ] A, int n, int base) {
int shift;
int[ ] sp = new int[n];
for (int i=0; i<n/2; i++) { // Unshuffle A into the scratch space
shift = base + 2*i;
sp[i] = A[shift]; // an even index
sp[i+n/2] = A[shift+1]; // an odd index
}
for (int i=0; i<n; i++)
A[base+i] = sp[i]; // copy back to A
}
protected static int[ ] rootsOfUnity(int n) { //assumes n is power of 2
int t = MAXN;
int nthroot = OMEGA;
for (int t = MAXN; t>n; t /= 2) // Find prim. nth root of unity
nthroot = (int)(((long)nthroot*nthroot) % P);
int[ ] roots = new int[n];
int r = 1; // r will run through all nth roots of unity
for (int i=0; i<n; i++) {
roots[i] = r;
r = (int)(((long)r*nthroot) % P);
}
return roots;
}
protected static void propagateCarries(int[ ] A) {
int i, carry;
carry = 0;
for (i=0; i<A.length; i++) {
A[i] = A[i] + carry;
carry = A[i] >>> ENTRYSIZE;
A[i] = A[i] − (carry << ENTRYSIZE);
}
}
Code Fragment 10.21: Support methods for a recursive FFT.
504 Chapter 10. Number Theory and Cryptography
An Iterative FFT Implementation
There are additional time improvements that can be made in the FFT algorithm,
which involve replacing the recursive version of the algorithm with an iterative
version. Our iterative FFT is a part of an alternate big integer class, called FastInt.
The multiplication method for this class is shown in Code Fragment 10.22.
public FastInt multiply(FastInt val) {
int n = makePowerOfTwo(Math.max(mag.length,val.mag.length))*2;
logN = logBaseTwo(n); // Log of n base 2
reverse = reverseArray(n,logN); // initialize reversal lookup table
int signResult = signum * val.signum;
int[ ] A = padWithZeros(mag,n); // copies mag into A padded w/ 0’s
int[ ] B = padWithZeros(val.mag,n); // copies val.mag into B padded w/ 0’s
int[ ] root = rootsOfUnity(n); // creates all n roots of unity
FFT(A,root,n); // Leaves FFT result in A
FFT(B,root,n); // Leaves FFT result in B
for (int i=0; i<n; i++)
A[i] = (int) (((long)A[i]*B[i]) % P); // Component-wise multiply
reverseRoots(root); // Reverse roots to create inverse roots
inverseFFT(A,root,n); // Leaves inverse FFT result in A
propagateCarries(A); // Convert A to right no. of bits/entry
return new FastInt(signResult,A);
}
Code Fragment 10.22: The multiplication method for an iterative FFT.
Computing the FFT in Place
From Code Fragment 10.22, we already can see a difference between this and the
multiply method for the recursive version of the FFT. Namely, we are now per-
forming the FFT in-place. That is, the array A is being used for both the input and
output values. This saves us the extra work of copying between output and input ar-
rays. In addition, we compute the logarithm of n, base two, and store this in a static
variable, as this logarithm is used repeatedly in calls to the iterative FFT algorithm.
Avoiding Recursion
The main challenge in avoiding recursion in an in-place version of the FFT algo-
rithm is that we have to figure out a way of performing all the inverse shuffles in
the input array A. Rather than performing each inverse shuffle with each iteration,
we instead perform all the inverse shuffles in advance, assuming that n, the size of
the input array, is a power of two.
In order to figure out the net effect of the permutation we would get by repeated
and recursive inverse shuffle operations, let us consider how the inverse shuffles
move data around with each recursive call. In the first recursive call, of course,
we perform an inverse shuffle on the entire array A. Note how this permutation
10.5. Java Example: FFT 505
operates at the bit level of the indices in A. It brings all elements at addresses that
have a 0 as their least significant bit to the bottom half of A. Likewise, it brings
all elements at addresses that have a 1 as their least significant bit to the top half of
A. That is, if an element starts out at an address with b as its least significant bit,
then it ends up at an address with b as its most significant bit. The least significant
bit in an address is the determiner of which half of A an element winds up in. In
the next level of recursion, we repeat the inverse shuffle on each half of A. Viewed
again at the bit level, for b = 0, 1, these recursive inverse shuffles take elements
originally at addresses with b as their second least significant bit, and move them
to addresses that have b as their second most significant bit. Likewise, for b = 0, 1,
the ith levels of recursion move elements originally at address with b as their ith
least significant bit, to addresses with b as their ith most significant bit. Thus, if an
element starts out at an address with binary representation [bl−1 . . . b2b1b0], then it
ends up at an address with binary representation [b0b1b2 . . . bl−1], where l = log2 n.
That is, we can perform all the inverse shuffles in advance just by moving elements
in A to the address that is the bit reversal of their starting address in A. To perform
this permutation, we build a permutation array, reverse, in the multiply method, and
then use this in the bitReversal method called inside the FFT method to permute the
elements in the input array A according to this permutation. The resulting iterative
version of the FFT algorithm is shown in Code Fragment 10.23.
public static void FFT(int[ ] A, int[ ] root, int n) {
int prod,term,index; // Values for common subexpressions
int subSize = 1; // Subproblem size
bitReverse(A,logN); // Permute A by bit reversal table
for (int lev=1; lev<=logN; lev++) {
subSize *= 2; // Double the subproblem size.
for (int base=0; base<n−1; base += subSize) { // Iterate subproblems
int j = subSize/2;
int rootIndex = A.length/subSize;
for (int i=0; i<j; i++) {
index = base + i;
prod = (int) (((long)root[i*rootIndex]*A[index+j]) % P);
term = A[index];
A[index+j] = (int) (((long)term + P − prod) % P);
A[index] = (int) (((long)term + prod) % P);
}
}
}
}
public static void inverseFFT(int[ ] A, int[ ] root, int n) {
int inverseN = modInverse(n); // n^{-1}
FFT(A,root,n);
for (int i=0; i<n; i++)
A[i] = (int) (((long)A[i]*inverseN) % P);
} Code Fragment 10.23: An iterative implementation of the FFT algorithm.
506 Chapter 10. Number Theory and Cryptography
protected static void bitReverse(int[ ] A, int logN) {
int[ ] temp = new int[A.length];
for (int i=0; i<A.length; i++)
temp[reverse[i]] = A[i];
for (int i=0; i<A.length; i++)
A[i] = temp[i];
}
protected static int[ ] reverseArray(int n, int logN) {
int[ ] result = new int[n];
for (int i=0; i<n; i++)
result[i] = reverse(i,logN);
return result;
}
protected static int reverse(int N, int logN) {
int bit=0;
int result=0;
for (int i=0; i<logN; i++) {
bit = N & 1;
result = (result << 1) + bit;
N = N >>> 1;
}
return result;
}
Code Fragment 10.24: Support methods for an iterative implementation of the FFT
algorithm. Other support methods are like those in the recursive implementation.
We show the additional support methods used by the iterative FFT algorithm
in Code Fragment 10.24. All of these support methods deal with the operation
of computing the reverse permutation table and then using it to perform the bit-
reversal permutation on A.
Experimental Results
Of course, the goal of using the FFT algorithm for big integer multiplication is to
perform this operation in O(n log n) time, on integers represented as n-word vectors,
as opposed to the standard O(n2) multiplication algorithm taught in grade schools.
In addition, we designed an iterative version of the FFT algorithm with the goal of
improving the constant factors in the running time of this multiplication method.
To test these goals in practice, we designed a simple experiment.
In this experiment, we randomly generated ten big integers that consisted of 2s
words of 15 bits each, for s = 7, 8, . . . , 16, and we multiplied them in consecutive
pairs, producing nine products for each value of s. We timed the execution time
for performing these products, and compared these times to those for multiplying
integers represented with the same number of bits in a standard implementation of
the Java BigInteger class. The results of this experiment are shown in Figure 10.25.
The running times are shown in milliseconds. The experiment was performed in
10.5. Java Example: FFT 507
the Sun Java virtual machine for JDK 1.2 on a Sun Ultra5 with a 360MHz processor
and 128MB of memory.
1000000
100000
Time in milliseconds 10000 BigInteger
1000 Recursive FFT
100 Iterative FFT
10
1
128 256 512 1024 2048 4096 8192 16384 32768 65536
Size in words
Figure 10.25: Running times for integer multiplication. The chart shows running
times for multiplying integers made up of various numbers of words of 15 bits each
(for the FFT), or the equivalent size for a standard BigInteger implementation. Note
that the scales are logarithmic for both the x- and y-axes.
Note that we display the results of the experiment on a log-log scale. This
choice corresponds to the power test (Section 1.6.2) and allows us to see the rel-
ative costs of the different implementations much clearer than we would see on a
standard linear scale. Since log nc = c log n, the slope of a line on a log-log scale
correlates exactly with the exponent of a polynomial in a standard linear scale.
Likewise the height of a line on a log-log scale corresponds to a constant of pro-
portionality. The chart in Figure 10.25 displays time using base-ten on the y-axis
and base-two on the x-axis. Using the fact that log2 10 is approximately 3.322, we
indeed see that the running time of the standard multiplication algorithm is Θ(n2),
whereas the running time of the FFT algorithms is close to linear. Likewise, we
note that the constant factor in the iterative FFT algorithm implementation is about
70% of the constant for the recursive FFT algorithm implementation. Also note the
significant trade-off that exists between the FFT-based methods and the standard
multiplication algorithm. At the small end of the scale, the FFT-based methods are
ten times slower than the standard algorithm, but at the high end of the scale they
are more than ten times faster!
508 Chapter 10. Number Theory and Cryptography
10.6 Exercises
Reinforcement
R-10.1 Prove Theorem 10.1.
R-10.2 Show the execution of method EuclidGCD(14300, 5915) by constructing a table
similar to Table 10.2.
R-10.3 Write a nonrecursive version of Algorithm EuclidGCD.
R-10.4 Show the execution of method EuclidBinaryGCD(14300, 5915) by constructing
a table similar to Table 10.2.
R-10.5 Show the existence of additive inverses in Zp, that is, prove that for each x ∈ Zp,
there is a y ∈ Zp, such that x + y mod p = 0.
R-10.6 Construct the multiplication table of the elements of Z11, where the element in
row i and column j (0 ≤ i, j ≤ 10) is given by i · j mod 11.
R-10.7 Prove Corollary 10.7.
R-10.8 Give an alternative proof of Theorem 10.6 and Corollary 10.7 that does not use
Theorem 10.3.
R-10.9 Show the execution of method FastExponentiation(5, 12, 13) by constructing a
table similar to Table 10.8.
R-10.10 Write a nonrecursive version of Algorithm ExtendedEuclidGCD.
R-10.11 Extend Table 10.10 with two rows giving the values of ia and jb at each step of
the algorithm and verify that ia + jb = 1.
R-10.12 Show the execution of method ExtendedEuclidGCD(412, 113) by constructing a
table similar to Table 10.10.
R-10.13 Compute the multiplicative inverses of the numbers 113, 114, and 127 in Z299.
R-10.14 Describe the inverse FFT algorithm, which computes the inverse DFT in O(n log n)
time. That is, show how to reverse the roles of a and y and change the assign-
ments so that, for each output index, we have
∑ai=1 n−1
n
y jω−i j.
j=1
R-10.15 Prove a more general form of the reduction property of primitive roots of unity.
Namely, show that, for any integer c > 0, if ω is a primitive (cn)th root of unity,
then ωc is a primitive nth root of unity.
R-10.16 Write in the form a + bi the complex nth roots of unity for n = 4 and n = 8.
R-10.17 What is the bit-reversal permutation, reverse, for n = 16?
R-10.18 Use the FFT and inverse FFT to compute the convolution of a = [1, 2, 3, 4] and
b = [4, 3, 2, 1]. Show the output of each component as in Figure 10.15.
R-10.19 Use the convolution theorem to compute the product of the polynomials p(x) =
3x2 + 4x + 2 and q(x) = 2x3 + 3x2 + 5x + 3.
10.6. Exercises 509
R-10.20 Compute the discrete Fourier transform of the vector [5, 4, 3, 2] using arithmetic
modulo 17 = 24 + 1. Use the fact that 5 is a generator of Z1∗7.
R-10.21 Construct a table showing an example of the RSA cryptosystem with parameters
p = 17, q = 19, and e = 5. The table should have two rows, one for the plaintext
M and the other for the ciphertext C. The columns should correspond to integer
values in the range [10, 20] for M.
Creativity
C-10.1 Justify the correctness of the binary Euclid’s algorithm (Algorithm 10.3) and
analyze its running time.
C-10.2 Let p be an odd prime.
a. Show that Zp has exactly (p − 1)/2 quadratic residues.
b. Show that
a p−1
b
≡ a 2 (mod p).
c. Give a randomized algorithm for finding a quadratic residue of Zp in ex-
pected O(1) time.
d. Discuss the relationship between quadratic residues and the quadratic prob-
ing technique for collision resolution in hash tables (see Section 2.5.5 and
Exercise C-2.35).
C-10.3 Let p be a prime. Give an efficient alternative algorithm for computing the mul-
tiplicative inverse of an element of Zp that is not based on the extended Euclid’s
algorithm. What is the running time of your algorithm?
C-10.4 Show how to modify Algorithm ExtendedEuclidGCD to compute the multiplica-
tive inverse of an element in Zn using arithmetic operations on operands with at
most 2 log2 n bits.
C-10.5 Prove the correctness of method Jacobi(a, b) (Algorithm 10.12) for computing
the Jacobi symbol. Also, show that this method executes O(log max(a, b) arith-
metic operations.
C-10.6 Give a pseudo-code description of the compositeness witness function of the
Rabin-Miller algorithm.
C-10.7 Describe a divide-and-conquer algorithm, not based on the FFT, for multiplying
two degree-n polynomials with integer coefficients in O(nlog2 3) time, assuming
that elementary arithmetic operations on any two integers run in constant time.
C-10.8 Prove that ω = 24b/m is a primitive mth root of unity when multiplication is taken
modulo (22b + 1), for any integer b > 0.
C-10.9 Given degree-n polynomials p(x) and q(x), describe an O(n log n)-time method
for multiplying the derivative of p(x) by the derivative of q(x).
C-10.10 Describe a version of the FFT that works when n is a power of 3 by dividing the
input vector into three subvectors, recursing on each one, and then merging the
subproblem solutions. Derive a recurrence equation for the running time of this
algorithm and solve this recurrence using the Master Theorem.
510 Chapter 10. Number Theory and Cryptography
C-10.11 Suppose you are given a set of real numbers X = {x0, x1, . . . , xn−1}. Note that,
by the Interpolation Theorem for Polynomials, there is a unique degree-(n − 1)
polynomial p(x), such that p(xi) = 0 for i = 0, 1, . . . , n − 1. Design a divide-and-
conquer algorithm that can construct a coefficient representation of this p(x) in
O(n log2 n) time.
Projects
P-10.1 Write a class that contains methods for modular exponentiation and computing
modular inverses.
P-10.2 Implement the randomized primality testing algorithms by Rabin-Miller and by
Solovay-Strassen. Test the results of these algorithms on randomly generated
32-bit integers using the confidence parameters 7, 10, and 20, respectively.
P-10.3 Implement a simplified RSA cryptosystem for integer messages with a Java class
that provides methods for encrypting, decrypting, signing, and verifying a signa-
ture.
P-10.4 Implement a simplified El Gamal cryptosystem for integer messages with a Java
class that provides methods for encrypting, decrypting, signing, and verifying a
signature.
Chapter Notes
An introduction to number theory is provided in books by Koblitz [123] and Kranakis [125].
The classic textbook on numerical algorithms is the second volume of Knuth’s series on
The Art of Computer Programming [121]. Algorithms for number theoretic problems are
also presented in the books by Bressoud and Wagon [40] and by Bach and Shallit [20].
The Solovay-Strassen randomized primality testing algorithm appears in [190, 191]. The
Rabin-Miller algorithm is presented in [171].
The book by Schneier [180] describes cryptographic protocols and algorithms in detail.
Applications of cryptography to network security are covered in the book by Stallings [192].
The RSA cryptosystem is named after the initials of its inventors, Rivest, Shamir, and
Adleman [173]. The El Gamal cryptosystem is named after its inventor [75]. The hash
tree structure was introduced by Merkle [153, 154]. The one-way accumulator function is
introduced in [27, 179].
The Fast Fourier Transform (FFT) appears in a paper by Cooley and Tukey [54]. It is
also discussed in books by Aho, Hopcroft, and Ullman [7], Baase [19], Cormen, Leiser-
son, and Rivest [55], Sedgewick [182, 183], and Yap [213], all of which were influential
in the discussion given above. In particular, the fast integer multiplication algorithm im-
plementation given above is fashioned after the QuickMul algorithm of Yap and Li. For
information on additional applications of the FFT, the interested reader is referred to books
by Brigham [41] and Elliott and Rao [66], and the chapter by Emiris and Pan [67]. Sections
10.1 and 10.2 are based in part on a section of an unpublished manuscript of Achter and
Tamassia [1].
liChapter Network Algorithms
I¿ -,-.____ 't
I
Contents
. .....11.1 Complexity Measures and Models
11.1.1 The Networking Protqcol Stack
Mo1d1.1e.2lTh.e..M.e.s.s.a.g.e.-.P.ä.s.s.in.g.......................... 514
11.1.3 Complexity Measures for Network Algorithms . . . . 516
11.2 Fundamental Distributed Algorithms .......... 517
11.2.1 Leader Election in a Ring 517
11 2 2 Leader Election in a Tree 521
11.2.3 Breadth-First Search 523
11.2.4 Minimum Spanning Trees 528
11.3 Broadcast and Unicast Routing 530
11.3.1 The Elooding Algorithm for Broadcast Routing . . 530
11.3.2 The Distance Vector Algorithm for U.nicast Routing . 532
11.3.3 The Link-State Algorithm for Unicast Routing . .. . 534
11.4 Multicast Routing 535
11.4.1 Reverse Path Forwarding . 535
537
11.4.2 Center-Based Trees .
. 538
11.4.3 Steiner Trees- 541
11 5 Exercises
512 Chapter 11. NetworkAIgø
Network algorithms are written to execute on a computS network, and the
algorithms include those that specify how specialized computers, called
send data packets through the network. The computer network is modeled
,
graph, with the vertices representing processors, or routers, and the edges rep
senting communications channels (See Figure 11.1.) Algorithms that mn on flc
n&works are unconventional, because the inputs to such algorithms are typicaij,
spread throughoùt the network and the execution of such algorithms is distribue
across the processors, in the network.
We begin our study of network algorithms, then, by considering several funth..
mental disthbuted algorithms. These algorithms address some baic issues that aieV
'encountered in network algorithms, including leader election and building spaimc
trees. We examine each algorithm in both a synchronous setting, 'where process0
can operate in "lock step" in a senes of "rounds," and an asyníchronous setting,
where processors can run at relatively different speeds. In some cases, deaJfig
with asynchrony introduces new compliations, but in diverse networks, such asC
the Internet, asynchrony is a reahty that must be dealt with effectively £
A major class of network algorithms are routing algorithms, which specify how
to move information packets between various computers in a network Good rout-
ing algorithms should route packets so as to amve at their destinations quickly and
reliably, while also being "fair" to other packets in the network One challenge to
designing good routing algorithms is that these goals are somewhat contradictory, -:
since fairness sometimes conflicts with speedy packet delivery.: Another challenge
is that the p ocessing needed to implement a routing scheme should 'also be fast and
efficient. We therefore focus the second part of.this chapter on routing algonthms,
including methods for the following communication patterns:
Broadcast routing, which sends a packet to every computer
Unicast routing, which sends a packet to a specific computer
Malticast routing, which sends a packet tO a group of computers.
We will study these routing algorithms by analyzing the costs invOlved in setting up
'the algorithm añd also in routing messages using that algorithm., Before we discuss
how these and other network algorithms work, however, wè hduld explain a bit
more about the computatiönal model in which they are' designed to operate.
Figure 11.1: A computational network, whose vertices are processors añd edges are
communication links Bold edges define a simple cyclé kiow n as a ring nétwork.
11.1. Complexity Measures and Models 513
11.1 Complexity Measures and Models
Before we can fully study network algorithms, we need to better understand how
networks, such as the Internet, work. Specifically, we need to explore how inter-
processor communication is performed, modeled, and analyzed.
11.11. The Networking Protocol Stack
One Way to get a handle on the way a network, such as the Internet, functions is in
terms of a layered networking model, having the, following conceptual layers:
Physical layer: This is the layer where raw bits are transmitted across some
medium, such as electrical wires or fiber-optic' cables. The design decisions
for this layer have mostly to do with engineering techniques for representing
l's and 0's, maximizing transmission bandwidth, and minimizing transmis-
sion noise. ''
Data-link layen This is the layer that handles the methods for breaking
'data into subunits called frames and trânsmitting data froth oné computer,
through the physical layer, to another. A typical example includes the point-
to-pòint protocol, which describes how to send data between two physically
connected computers. '
Network layer: This layer is concerned with methods for breaking data into
packets (different than' frames) and routing those packets from computer to
'computer through the entire network. Algorithmic issues concerned with
this layer deal with methods for routing packets through the network and for
breaking and reassembling packets. The primary Internet protocol used in
this layer is the Internet Protocol, or IP. This protocol uses a "best effort"
approach, which means that no performance guarantees are made and some
packets mayeven be lost.
Transport layen This 'layer accepts, data' from various applications, splits
it up into smaller units if. need be, and passes these to the network layer
in a fashion that fulfills specific guarantees on rehabihty and congestion
coñtrol. The 'two primary Internet protocols that ,exist 'in this layer are the
Transmission Con fr01 Protocol (TCP), which provides error-free, end-to-
end, connection-oriented transmission between two machines on the Internet,
and the User Datagram Protocol (UDP), which is a connectionless, best-
effort protocol.
's Application layer. This is the layer at which applications operate, using the
lower-level protocôls Examples of Internet applications include electronic
máil (SMTP), file transfer (FTP and SCP), virtual teÈniinals (TELNET and
SSH), the World Wide Web (HflP), and the Domain Name Service (DNS),
which maps host names '(such as www.cs.brown.edu) to IP addresses (such
as 128.148.32.110). '
514 Chapter ii. Netwo&
11.1.2 The Message-Passing Model
. We say very little about the details of the networking protoco1 stack i«
ter Tnstead, the network algonthms we discuss operate in a compu0
that abstracts the functionality provided by the various layers in the abo4
prototol stack: Still, understanding the different layers of the twt
stack allows us to tie concepts in our distributed computational model t
functions and protocols in a real network, such as the Internet.
There are several possible ways of abstracting the functionality of a
a way that would allow us to describe network algorithths. 1n this chapteì
use a message-passing model that is commonly used to describe such diii
algorithms, where loosely coupled processors communicate in order to sol
putatiQnal problems. The alternative model of parallel algorithms is intro
Section 14.2. In a parallel algorithm, tightly coupled multiple processors cto
and coordinate, often through a shared memory space. i;
In the distributed message passing model, which will be our exclusive
this chapter, the network is modeled. as a graph, where the vertices corre4,
processors and the edges correspond to fixed connections between proces
do not: change throughput the computation. Each edge e supports message j,
between the two processors associated with the endpoints of e. Messagesc
sent only in one direction if e is directed, and in both directions if e is undfr
For example, at the network layer of the Internet, vertices cótrespond to spe&
computers called IP )outers, each identified by a unique numeric code call
address, and the messages exchanged by them are basic data transmissiot
called IP packets. Alternatively, vertices could correspond to server computé
the Internet and edges could correspond to pérmanent TCP/IP connections t1
maintained between various pairs of servers.
As the name implies, in the message passing model, information is co
cated in the network by exchanging messages. Each processor in the netwo
assigned a unique numeric identifier (for example, it could be the IP address
router or host on the Internet). Moreover, we assume that each processor know
neighbors in the network, and that it communicates directly only with its neigh
In some cases, we may even allow each proöessor to know the total number of
cessors in the ñetwork, but in many instances this global knowledge is unavail
'or unnecessary.
Another important consideration in network algorithms is whether or not
rithms have to cope with potential changes to the network while they are ru
During the execution of an algorithm, processors may fail (or "crash"), ne
connections may go down, and we could have some processors remain active;'
perform faulty or even malicious computations. Ideally, we would like distribu
algonthms to be dynaimc, that is, be able to respond to changes in the netW
and be fault-tolerant, that is, be able to recover correctly and gracefully from
ures. Nevertheless, the techniques for making distributed algorithms fully roi
omp1eXity Measures and Models
1.
áre.fairly intricate; hence, they are beyond the scope of this book. Therefore, in
this chapter, we assume that the topology of the network does not change and that
processors remain active and nonfaulty while the network is executing a distributed
algorithm. That is, we assume the network remains static during algorithm execw.
tioiì.
t1 One of the most important considerations in the message-passing model for
distributed computing is the assumption we make about the synchronization of pro-
cessors in the network. There are several possible choices we can make regarding
synchronization, but the following are the two most utilized models in distributed
algorithm design:
Synchronous model: In this model, each processor has an internal clock
that times program execution and the clocks of all the processors are syn-
chronized Also, we assume that the! execution speeds of the processors are
uniform and each processor takes the same amount of time to perform the
same operation (such as an addition or comparison). Finally, we assumeï that
it takes the same amount of time to send a message through any connection
in the network.
Asyñchronous model: In this model, we make nô assumptions about any
internal clocks that the processors might havei. Moreover, we do not assume
that the speeds of the processors are necessarily similar. Thus, the steps in an
asyñchronous algorithm are determined by conditions or events, not by clock
"ticks?' Still, there are some reasonable timing assumptions that we make to
allow algorithms to perform their tasks effectively. First, we assume that
each communication channel, represented by an edge, is a first-in, first-out
çI (FIFO) queue that can buffer an arbitrary number of messages. That is, the
messages that are sent on an edge are stored in a buffer for that edge so that
the messages arrive in the same order they are sent. Second, we assume that
while processor speeds can vary, they are riot arbitrarily different from one
another. That is, there is a basic fairness assumption that guarantees that if a
processor p has an event enabling p to perform a task, then p will eventually
perform that tàsk
In addition to these two extreme versions of the distributéd computing mode!, we
can also consider intermediate versions, where processors have clocks, but these
clocks are not perfectly synchronized. Thus, in such an intermediate model we
cannot assume that procèssors compute in "lock step," but we can nevertheless
make choices based on "time out" events where processors do not respónd after
à lengthy period of time. Although such intermediate models more closely match
the actual timing properties of real networks, such as the Internet, we nevertheless
find it useful to restrict our attention to the synchronous and asynchronous models
described above. Algorithms designed for the synchronous model äre usually quite
simple and can often be translated into algorithms that work in the asynchronous
model. In addition, algorithms designed for the asynchronous model will certainly
still function correctly in an intermediate model that has limited synchronization.
516 çhapter IL Network AJg
11. 1.3 Complexity Measures for Network Algorithms
In traditional algorithm design, as studied in other chapters of this booÈ &
mary complexity measures used to determine the efficiency of an algorft
running tithe and mémory space used. Thèse complexity measUres do not
ately translate into the domain of network algorithms, however, since they
itly assume that a computation is performed on a single computer, not a ie
of computers. In network algorithms, inputs are spread across the compute0
network and computations must be carried out across many computers on tij
work. Thus, we must take some care to characterize the performance param
network algorithms..
The complexity measures fär comparing traditional algorithms have
counterparts in distnbuted algonthms, but there are also complexity measures
in the network setting In this chapter, we focus on the following complexiQ
sures:
Computational rounds: Several network algorithms proceed througI
ries of global rounds so as to eventually converge on a solution. The n
of rounds needed for convergence can therefore be used as a crude apI
imation of time In synchronous algorithms, these rounds are dete
by clock ticks, whereas in asynchronous algorithms these rOunds arer
determined by propagating "waves" of events across the network. +
Space: The amouni of space needed by a computation can be used ev
network algorithms, but it must be qualified as to. whether it is a global bp
on the total space used by all computers in the algorithm or.a local bouh
how much space is. needed per computer involved.
Local running time: While it is difficult to ahalyze the global runmng
needed for a computation, particularly for asynchronous algorithms, wc t
nevertheless analyze thé amount of local computing time needed for
ticular tomputer to participate in a network algorithm. If all computers
algorithm are essentially performiig the same type of function, then a s
local running time bound can suffice for all.. But if there äre several diffó
classes of computers participating in an algorithm, we should characte
the local running time needed for each class Ql computer. t
Message complexity This parameter measures the total number of mes
(of size at most logarithmic in the number of processors) that are sçnt
tween all pairs of computers dùring the computation. For example, if a i
sage M is routed through p edges to get from one computer t another,
would say that the message complexity of this communication is plMj, wh
1Ml denotes the, length of M (iii words).
Finally, if there is some other obvious complexity' measure that we are trying
optimize in a network algorithm (such as profit in an online auction protoco
retrieval cost in an Online caching scheme), then we should include bounds
thesé complexities as, well.
; yundan entai Distributed Algorithms 517
Fundamental Distributed Algorithms
Complexity measures for network algorithms are often best thought of as being j'[J
functiolS of some intuitive notions of the "size" of the problem wç are trying tó
solve. For example, the size of a problem could be expressed in terms otf the fol- h
lowing parameters: F
The number of words used to express the input; 'Ii
The number of processor deployed; and
The number of communication connections between processors. Fil I
Thus, to properly analyze the complexity measures for a network algorithm we F
must formalize what we mean by the size of the problem for that algorithm.
jF
To make these notions more concr6te, we study several fundamental distributed
algorithms in this sectiOn, analyzing their performance using some of the above
complexity measures. The specific problems we study are chosen both to illustrate
fuñdamental distributed algorithm techniques as well as methods for analyzing net-
work algorithms.
11,21. Leader Election in a Ring
The first problem we address is leader election in a ring network. In this problem,
we are given a network of n processors, that are connected in a ring, that is, the
graph of the network'is a simple cycle of n vertices. The goal is to identify one
of the n processors as the "leader," and have all the other processors agree on this
selection. We describe an algorithm for the case where the ring is a directed cycle.
Exercise C- 11.1 çonsiders the case of an undirected ring.
We begin b describing a synchronous solution. The main idea of the syn-
chronous solution is to sleët the leader as the processor with the smallest identi-
fier. The challenge is-that iú a ring there is no obvious place to start. So we start
the computation everywhere. At the beginning of the algorithm each processor
sends its identifier to the next pùocessor in the ring. In the subsequent rounds, each
processor performs the following computations:
1. It receives an identifier i frOm its predebessor in the ring
. It compares i to its own identifier,
3. 'It sends the minimum of these two values toits successor in the ring.
If a processor ever receives its own identifier from its predecessor, then this pro-
cessèr knows that it must have' the smallest identifier and hence, it is the leadet
This processor can then send a message around the ring infonning all the other
processors that it is the leader.
We give à descRfion of the above method in Algorithm 11.2. A sample exe-
cution of the algorithm is illustrated in Figure 11.3.
518 Chapter iL Network
Algorithm RingLeader(id):
Input: The unique identifier, id, for the processor mnning this algori
Output: The smallest identifier of a processor iñ the ring
M - [Candidate is id]
Send message M to the successor processor in the ring.
done *- false
repeat
Get message M froth the prededéssor processor in the ring.
jIM = [Candidate i]itshen
if i=id then
M - [Leader ¡s id]
done - true
else
m - min{i,id}
M i- [Candidate is m]
else
{M is a "Leader is" message}
done - true
Send message M to the next processor in the ring.
until done {M i a "Leader is" message}
return M
Algorithm 11.2: A synchronous algorithm run by each processor in a direc
to determine a "leader" for that ring of processors.
Before we añalyze algorithm RingLeader, let us first convince ourselves
works correctly. Let n be the number of processors. Each processor begins by s
ing its identifier in the first round: Then, in the next n - 1 rounds, each proc
accepts a "candidate is" message, computes the minimum m of the identifier i üf
message and its own identifier id, and transmits identifier in to the next proces
with a "candidate is" message Let £ be the smallest identifier of a processor j
ring. The first message sent by processor £ will traverse the entire ring and
come back unchanged to processor L. At that point, processor L will realize
it is the leader and will inform all the other processors with a "leader is" mets
that will traverse the entire ring over the next n rounds. It should be noted tha
number n of processors used in the above analysis does hot have to be knowpT
the processors. AlsO, observe that there are no deadlocks in the algonthm, thatt
no two processors are both waiting on messages that need to come from the otlig
Letus now analyze the performance of algorithm RingLeader. First, in te
of the number of rounds, the first "candidate is" message from the leader taW
rounds to traverse the ring. Also, the "leader is" message initiated by the lea4
takes n mOre rounds to. reach all the other processOrs. Thus, there are 2n rounds
çund2mtJhl Distributed Algorithms 519
DI5 4
Round i
29
8
4T 8 8-
18
12 4 12
Round 5
15 29
Round 4
4.
4Q15 4 w-4
8 Round6 29
nEswhniegoguwlarTbetehh1lee1ef.iai3mnc:ahtAliaenrldocgiuloelnunwdsfsitigrtwahutrhitaòhetnerioe"onpcfarisotnhcdleaeidbsasaelotgleerodi4ñsat"ihsnmmf"oRersfmoosuarsngstdeyhnesOeco"nhttrhFoeaonrlroopenuragsoccltheheassedsueoecdrrcsgeeestlsheWiacvtteeiiotrdnoiosuinnnthdoae,t
leàdèr with a "leader is" message
We analyze now the message complexity of the algonthm We distinguish two
phases in the algòrithm.
1. The first phase consists of the first n rounds where the processors are sending.
"candidate is" méssages md are propagating them on. In this phase, each
processor sènds and receives one message in each round. Thus, 0(n2) mes-
sàgesarë seht in the first phase.
2 Tm"pmthnhcoeuaeeaimksnsnlesetedba,scaiegidodirtetanesofstrdo,efwwripmiwtassihyel"aalssramsussdreàceosegcncuseetdosnhssnadsoesgsoniet"etshenlstwesetmauiiorñdleniflnestttssrihghelaeeingItshdnsn"eeee,tmtcxhth"ohtreilneesensdeasspradupomhgechuaerecanssesiedssase,sa"snigaowdsmerphsseroet,oosfrascepntaeshtdgsihe,seseowloTer"rhalhoeceidaunocaech.sndrh,teTiiewisrnnhsuiiQusltie(l"shtsn,is\mstes)hAene.pensdthsdttataoihwsngtieageos,l
520 chapter ii. NetworkAlgo
We coûclude as follows.
hTheorem 11.1: Suppose we are given an n-node distributed directed
work, N with distinct node identifiers but no distinguished leader. The RingL
algorithm finds a leader in N using a total of 0(n2) messages. Moreover, tii
message compléxity of the algorithm is 0(n2).
Proof: We have already seen that 0(n2) messages are sent Since each me
uses O(I) words, the total message complexity is 0(n2).
T
It i possible to improve thè message complexity for leader election in
by modifying algorithm RingLeader so that it requires fewer messages. We ex
twò possible modifications in Exercises C-1 1.2 and C-11 .3.
Asynchronous Leader Election
Algorithm 11.2 (RingLeader) was described and analyzed under the synchso
model. Moreover, we structured each round so that it would consist of a a mes
receiving step, a processing step, and a message sending step. Indeed this is
typical structure of synchronous distributed algorithms
In an asynchronous algorithm, we cannot assume that the procéssors move
'flock step" any longer. Instead, processing is determined by events, not ei
ticks. Still, the above algorithm for leader election in a ring also works ihk
asynchroñous model. The correctness of the algorithm did not actually depend
the processors acting synchronously It only depended on each processor rece
ing messages from its predecessor in the same sequence as they were sent
condition still holds in the asynchronous model
We summarize our study of leader election in a ring in the following theore
Theorem 11.2: Given a directçd ring with n ptocessors, algorithm RingLia
perfozms leader election with 0(n2) message complexity. Por each proceh
the local computing time is 0(n) and the local space used is 0(1). Algori
RingLeader works under both the synchronous and asynchronous models. Iii
synchronous model, its overall running time is 0(n).
Leader election might seem like a contrived problem at first, but it actuall'li
many applications. Any time we need to cOmpute a global function of a subset
nodes in a network, we essentially havç to perform a leader election. For exanijil
computing the sum of the values stored at computers connected in a ring, or,h
minimum or maximum of such values, can be solved by an algorithm similar to?
leader-election algorithm given above
Qf course, processors are not always connected in a ring. So, in the next sectio
we explore the. sçenario when processors are connected in a (free) tree.
nd.»eS Distributed Algorithms 521
11.2.2 Leader Election in a Tree
If the network is a (free) tree, electing a leader is much simpler than in a ring, since
a tree has a natural starting place for the computation: the external nodes.
Asynchronous Leader Election in a Tree
An asynchronous leader election algorithm for a tree is shown in Algorithm 11.5.
Again, we choose the processor with the smallest identifier as the leadet. The
algorithm assumes that a processor can perform a constant-time message check on
an incident edge to see if a message has arrived from that edge.
The main idèa of Algorithm TreeLeader is to use two phases. In the accumu-
lation phase, identifiers flow in from the external nodes of the tree. Each node
keeps track of the minimum identifier £ received from its neighbors, and after it
receives identifiers from all but one neighbor, it sends identifier £ to that neighbor.
At some point, a node receives identifiers from.all its neighbors. This node, called
accumulation node, determines the leadeL We illustrate this accumulation phase
in Figure 11 4 Once we have the leader identified at one node, we start the broad-
cast phase. In the broadcast phase, the accumulation node broadcasts the identifier
of the leader toward the external nodes. Note that a tie condition may occur where
two ádjacent nodes become accumulation nodes. In this, case, they broadcast to
their respective "halves" of the tree. Any node in the tree, even an external node,
can be an accumulation node, depending on the relative speed of the processors.
- Round O Round I
Round 2
Figüre 11.4: An illustration of the algorithm for finding a leader in a tree. We only
show the accumulation phase. Edges that have carried no message yet are shown
with thin lines Edges with messages flowing in that round are drawn as thick
arrows. Grey lines denote edges that have transported. .a message in a previous
round. . ..
522 Chaptèrll. Network A1gorj
Algorithm TreeLeader(id):
Input The umque identifier, id, for the processor runmng this algonthm
Output The smallest identifier of a processor in the tree
{Accumulation Phase} {d l}
let d be the number of neighbors of prodessor id
-in e- O {counter. for messages received}
{tentative ieader}
£ id
repeat
{begin a new round}
jfor each neighbor do
jcheck if à message from processor has arrived
jifa message M = [Candidate is M from has arrived then
£*min{i,t}
untilrnd-1
if in =4 then
¡k! - [Leader is L]
jfor each neighbor k do
jsend méssage M to processor
return M {M is a:" leader is" message}
else
M *- [Candidate is L]
send M to the neighbor kthat has not sent a. message yet
{Broadcast Phase}
repeat
{begin a new round}
check if a message froth processor k has arrived
if a message M from k has arrived then
m*m+1 ..
if M= [Candidate.is i] then
L4min{i,L}
MtjLeader ist]
jfor each neighbor do
jsend message M to processOr
else
.fM is a " leader is" message}
jfor each neighbor j $ k do
send message M to processor
untilm=d
return M {M is a " leader is" message}
Algorithm 11.5: An algorithm for computing a leader in a tree of processors. In
synchroñous version of the algorithm, all the processors begin a round at the sai
time until they stop.
Fundamental Distributed Algorithms 523
Synchronous Leader Election in a Tree
In the synchronous version of the algorithm, all the processors begin a round at the
same time Thus, the messages in the accumulation phase flow into the accumula-
lion node like the reverse of npples in a pond after a stone is dropped in Likewise,
in the broadcast phase, the messages propagate out from the accumulation node
like ripples in a pond in the forward direction. That is, in the accumulation phase
messages march into the "center" of the tree, and in the broadcast phase messages
march out.
The diameter of a graph is the length of a longest path between any twp nodes
in the graph. For a tree, the diameter is achieved by a path between two external
nodes. Interestingly, note that the number of rounds in the synchronous version of
the algorithm is exacfly equal to the diameter of the tree.
Performance of Tree Leader Election Algorithms
Analyzing the message complexity of the asynchronous tree leader election algo-
rithm is fairly straightforwàrd. During the accumulation phase, each processor
sends one "candidate is" message. During the broadcast phase, each processor
sends at most one. "leader is" message. Each message has 0(1) size. Thus, the
message complexity is 0(n).
We now study the local running time of the synchronous algorithm under the
assumption that we ignore the time spent waiting to begin a round. The algorithm
fòr processor i takes time O (diD), where d is the number of neighbors of processor
i, Sd D is the diametér of the tree. Also, processor i uses space d to keep track of
the neighbors that have sent messages.
We sunimañze ouustudy of leader election in a tree in the following theorem.
Theorem 11.3: Given a (free) tree with n nodes and with diameter D, algorithm
TreeLeader performs leader election with 0(n) message complexity. Algorithm
TreeLeader wotks under both the synchronous and asynchronous models. In the
synchronous model, for each processor t, the local computing time is 0(d1D) and
the local space used is o(d), where d is the number of neighbors of processor i.
11.2.3 Breadth-First Search
Scaeusnpptperocasilfiezicwedve,ehartalegvxoersaitihgnemtnheoirsrancl eoctnowsntonrruekccttaeisndganaseotbwurreocarekdntohof-dfpierr.ostcInesesSsaoerccrshtiaofnondr6aw.3ge.3rha,apwvheeGiddiesstncatuirftsiiesndga/
at a source node s. In this section, we describe distributed algorithms for solving
this problem.
524 Chapter 11. Netivor1csig
Synchronous BFS.
We first describe a simple synchronous breadth-first search (BPS) algori.
main ideaof this algorithm is to proceedin "waves" that propagate oUtWd
the source vertex sto construct a BFS tree layer-by-layer from the top down.
synchronization of the processors will benefit us greatly, in this Qase, to malç
propagation process completely coordinated,
j
We begin the algorithm by identifying s as an "external node" in the cufr
BPS tree, which is just s at this point. Then, in each round, each external no
sends a message to all of its neighbors that have not contacted y earlier, info L
them that y would like to make them. its children in the BPS tree. These n
respond by picking. y as their parent, if they have not already chosen some 0th
node as theft parent.
We illustrate this algorithm, in Figure 1 Ï .6 and we give the pseudo-code foi:
in Algorithm 11.7.
Round O Round i
Round 2
Round 4
Figuré 11.6: An illustration of the synchronized BFS algorithm. The thick edgej
are those of the BPS tree,: with the black thick edges being the. ones chosen in th
current round. .
j jjundameiital Distributed Algorithms 52E
Algorithm SynchronousBFS(v,$):
Input: The identifier y of the node (processor) executing this algorithm and the
identifier s of the start node of the BFS traversal
Output: For each node y, its parent in a BFS tree rooted at s
repeat
{begin a new round}
if y = s or y has received a message from one of its neighbors then
set parent(v) to be a node requesting y to become its child (or null, if
vr=s)
for each node w adjacent to y that has not contacted y yet do
send a message to w asking w to become a child of y
until y = s or y has received a message
Algorithm 11.7: A synchronous algorithm for computing a breadth-first search tree
in a connected network of processors.
Analyzing algorithm SynchronousBFS is simple. In each round, we propagate
out another level of the BFS. tree. Thus, the runniñg time of this algorithm is pro-
portional to the depth of the BFS trée. In addition, we send at most one message on
each edge in each direction over the entire computation. Thus, the number of mes-
sages sent in a network of n nodes and in edges is O(n+ m). Thus, this algorithm
is quite efficient. But it admittedly makes consiçierable use of the synchronization
of processors.
Asynchronous BFS
We cân make the above BFS algorithm asynchronous at the expense of additional
messages to keep things coordinated. Also, we require each processor to know the
total number of processors in the network.
Rather than relying on synchronized clocks to determine each round in the
computation, we will now have the source node s send out a "pulse" message that
triggers the other processors to perform the next round in the computation. By
using this pulse technique, we can still have the computation propagate out level
by level. The pulsing process itself is like breathingthere is a pulse-down phase,
where a signal is passed down the BFS tree from the root s, and a pulse-up phase
where a signal is combined from the external nodes back up the tree to the root s.
The processors at the external nodes ¿an only go from one round to the next /
if they have received a new pulse-down signal from their respective parents. Liker
wise, the root s will not issue a new pulse-down signal until it has received all the
pulse-up signals from its children. In this way, we can be sure that the prpces-
sors are operating in rough synchronization (at the granularity ofthe rounds). We
describe the asynchronous BFS algorithm in detail in Algorithm 11.8.
526 Chapter 11. Network A.Igorj
Algorithm AsynchronousBFS(v, s, n):
Input The identifier y of the processor running this algonthm, the idenot
s of the start node of the BFS traversal, and the number n of nodes in
network
Output: For each node y, its parent in tÎe BFS tree rooted at s
C i- 0 {verified BFS children for v}
set A to be the set of neighbors of y {candidate BFS children for v}.
repeat
{begin a new round}
if parent(v) is defined or y = s then
if parent(v) is defined then
wait for a pulse-down message from parent(v)
if C is not empty then
{v is an internal node in thè BFS tree}
send a pulse-down message to all nodes in C
wait for a pulse-up message from all nodes mC
else
{v is an external node in the BFS tree}
for each node u in A do
send a make-child message to u
for each node u in A do
get a message M from u and remove u from A
if Mis an accept-child message then
add utoC
send a pulse-up message to parent(v)
else
{v s has no parent yet.}
for each ñòde w lilA do
if w has sènt va make-child message then
remove w from A {wis ño longer a candidate child for y
if parent(v) is undefined then
parent(v) .+- w
send an accept-child message to w
else
send a reject-child message to w
until (y has received message done) or (y = s and has pulsed-down n-1 times
sénd a done mssage to all the nodes in C
H
Algorithm 11.8: An asynchronous algorithm for computing a breadth-first search
tree in a connected network of processors. This algorithm is tò be run simulta
ñeously by each node y in the network. The possible messages are pulse-dowif
pulse-up, make-child, accept-child, reject-child, and done.
undamen tal Distributed Algorithms 527
Performance
This asynchronous .BFS algorithm is admittedly more complicated than its syn-
chronous counterpart. The computation sfili operates in a sèrie of rounds, however.
In each round, the root npde s sends "pulse-down" messages down the partially
constructed BFS tree. When these messages reach the external levçl of the tree,
the current external nodes attempt to extend the BFS tree one more level, by issu-
ing "make-Child" messagés to candidate children. When these candidates respond,
either by accepting the invitation to become a child or rejecting it, the processors
send a "pulsé-up" messäge that propagates back up to s. The root s then starts the
wholè process all over again.
Since the BES tree can have height at most n - i nodes, node s repeats the
pulsing action for n - i times, just to make sure that each node in the network has
been included in the BFS tree. Thus, the synchronization from round to round is
done completçly via message passing. A current external node will not operate
until it gets a "pulse-down" message, and it will not issue a "pulse-up" message
until it has heard back from all of its candidate children (who either accept or reject
an invitation to become children). The BFS tree grows level-by-level just as in the
synchronous algorithm.
The number of messages needed to perform all of this coordination is more
than that needed in the syñchronous algorithm, however. Each edge in the network
still has at most one "make-child" message and a response. in each direction. Thus,
the total .messagé complexity for accepting and rejecting make-child requests is
0(m), where. rn is the number of edges in the network. But with each round of
the algorithm we need to prOpagate all the "pulse-down" and "pulse-up" messages.
Since they only travel along edges of the BFS tree, there are at most. 0(n) pulse-up
and pulse-down messages sent each round. Given that the source operates for n - i
roúnds, there are at most 0(n2) messages that are issued for the pulse coordinate.
Theréfore, the total message complexity of the algorithm is 0(n2 ± rn),where rn is
the number of edges in the network. This bound can be further simplified to just
0(n2), since mis 0(n2).
Thus, we summarize the above discussion with the following theorem.
Theorem 11.4: Given a network G with n vertices and m edges, we can compute
a breadth-first spanning tree in G in the asynchronous model using only 0(n2)
messages. .
In Exercise C-ii .4, we explore hQw to improve the. running time of the asyn-
chronous breadth-first search algorithm to be 0(nh + m), where h is the height of
the BFS tree.
528 Chapter 11. Network Á,g
11.2.4 Minimum Spanning Trees,
We recall that a minimum spanning free (MST) of a weighted graph is a
subgraph that is a treè and that has minimum weight (Section 7.3). Iii this
we describe an efficient distributed algorithm for this problem. Before we pro
the details, we first review an efficient sequential algorithm for finding an MS
to Barftvka (Section 7.3.3). The algorithm starts with each node of G in it
connected component of (zero) tree edges. It then proceeds, in a series of rt'
to add tree edges to join connected components .and thereby build up an MST
with all MST algorithms, it is based on the fact that, for any partition {V1 ,v
the vertices into two nonempty subsets, if e is a minimum-weight edge joinuj
and V2, then e belongs to a minimum spanning treé. (See Theorem 7.10.)
For the sake of simplicIty, let us assume that all the edge weights are uniq
Recall that, initially, each node of the graph. is in its own (trivial) connectetj cb
ponent and, the initial set, T, of tree edges is empty. At a high level, BarÛ.
algorithm then performs the following computations:
while there is more than one connected component defined by T do
for each coñnected component C in parallel do
choose the smallest edge e joining c to another component
add e to the set T çf tree edges
Barûvka's algorithm performs the above computations for each connected co
ponent in parallel, and therefore finds tree edges quickly. Note, in fact, that in
round, we are guaranteed tojoin each connectôd component with at least oneo
Thus, the number of connected components decreases by a factor of 2 with ¿a
round (defined by an iteration of the while loop), which impliesthat the total n
ber of rounds is logarithmic in the number of vertices.
Barûvka's Algorithm in a Distributed Setting '4
Let us implement a distributed Barûvka's algorithm for the synchronous m
(the asynchronous version of this algorithm is left as Exercise C-11 .7). Theré
two critical computations that need to be performed in each roundwe have
determine all the connected components and we need to determine the minim
outgoing edge from each one (recall that we are assuming that edge weights,
unique, so the, minimum outgoing edge from a component will also be uniqúe
(See Figure 11.9.)
We assume that, for each node y, y stores a list of the edges 'of T that
incident on y. Thus, each node y belongs to a tree, but y only stores informC
about its neighbors in T. In each round, the leader election algorithm in a tree fro
Section 11.2.2 is used twice as an auxiliary method: I
.
I. To identify each connected component 1
2: To find, for each connected component, the minimum-weight edge joiniñ I
component to another component.
pundamentdi Distribu ted Algorithms 529
/7 16 2»"lO 13 DI
IDk3-1 6 17 4"'i9 9
15 e13D. 8 14
Round O
l3L8iiL16 218fr- 12
_i5_p_
Round i
7
1
Round 2
Figure 11.9: An illustration of a synchronous distributed version of Barüvka's al-
gorithm. The thiòk edges identify MST edges, with the black thick edges being the
ones chosen in the given round.
A round operätes as follows. To identify the connected components, the leader-
election computation is performed using the identifier of each node Thus, each
component gets identified by the smallest identifier of its nodes. Next, each node
y computés the minimum-weight edge e incident on y, such that the endpoints of e
are in different connected. compoúents. If there is no such edge, we use. a fictitious
edge with infinite weight. Leader election is then performed again using the edges
associated with each vertex and their weights, which yields, for each connected
[component C the minimum-weight edge connecting C to another component1 Note
that we cän detect the end of the algorithm as the round in which we compute the
weight of the minimum-weight edge to be infinity.
Let n and. m denote the number of nodes and edges, respectively. To analyze
of Barûvka's algorithm, note
the message complexity of the distributed version round. Thus, since there are
thät 0(m) constant-size messages are sent at each
w0Q(e(lmoegx+na)mnroilnougendans')w,, taahynedtooivniemEraxplelrromcviseeestshCaeg-1em1ce.os7ms,awpgleeexcchiotaymlliepsnleOgxe(i,mttyhlofeogrrnes)a.ydInencrhEtroxoenfironcuidsseaMh0-aS1sT1y.n6to-,
chronous MST algorithm that still has message complexity O(mlogn).
530 Chapter 11. Network Algojjj
11.3 Broadcast and Unicast Routing
Having studied some fundamental distnbqted algonthms, let us now turn to
problems common in communication networksbroadcast routing and unj4]
routing. Broadcast routing is a message that is sent from one processor to ali o
processors in a network. This form of communication is ued when informaj0
a single processor must be shared wjth all, other processors in the network. Uni
routing, on the other hand, involves setting up data structures in a network so
support point-to-point communication, where a single processor has a message
it wishes to have relayed to another processor.
When discussing routing algorithms in the remaining subsections, we referâ
processor as a router. We récall our assumption that the network is fixed and di
not change over time. Thus, we restrict ourselves to the study of static routing al
nthms We also make the assumption that the messages exchanged by the ron
have constant size, which implies that the message complexity is proportional
the total number of messages exáhanged. Throughout the section, we denote w,.
n and in the number of nodes and edges of the network, respectively.
We begin our discussion with broadcast routing and then cover unicast roji
ing and multicast routing. The algorithms presented in this section are simplifi
versions of those used for packet routing in the Internet.
11.3.1 The Flooding Algorithm for Broadcast Routing
-- t
*
The flooding algonthm for broadcast routing is quite simple and requires virtuall
no setup. However, its routing cost is high.
A router s wishingto send a message M to all other routers in the network
gins by simply sending M to its neighbors. When a router y receives a floo
messäge M from an adjacent router u, y simply rebroadcafls M to all its neighbci
except for u itself Of course, left unmodified, this algorithm will cause an "hill
loop" of messages on any network that contains a cycle; a network without cyçi
has a simple routing algorithm, however, as we explore in an exercise (C-11 :5)2
't
Flooding with a Hop Counter
To avoid the infinite loop problem, we must associate some memory, orstate,
the main actors in the flooding algorithm. One possibility is that we add a,
cou nter to each message M and decrement the hop counter for M each time
router processes M. If a hop counter ever reaches o, we then discard the message
belongs to. If we initialize the hop counter for a message M to the diameter of4
network, then we can reach all the routers while avoiding the creation of an mû
number of messages.
Broadcast and (Jnicast Routing 531
flooding with Sequence Numbers
Another possibility is to store a hash table (or another efficient dictionary data
structure) at each router that keeps track of which messages the router has already
processed. When a router x originates a broadcast message, it assigns a unique
sequence number k to it. Thus, a flooding message is tagged by the pair (x, k).
When a router receives a message with .tag (x, k), it checks whether (x, k) is in its
table. If so, it simply discards the message. Otherwise, it adds (x, k) to the table
and rebroadcasts the message to its neighbors.
This approach will certainly eliminate the infinite loop problem, but it is not
space efficient. So a common heuristic tò use is to have each router keep only the
latest sequence number for each other router in the network, with the assumption
being that if a router receives a message onginated by x with sequence number k, it
has probably already processed all the messages sent by x with sequence numbers
.lessthank.
Analysis of Flooding Algorithms
To analyze flooding algorithms, we begin by noting that there is no setup cost
other than having each router know the number n of routers .in the network, and
possibly the diameter. D of the network. If we use the hop-counter heuristic, then
there .is no additional space needed at the ròuters. If we us.e the sequence-number
heuristic, on thé other hand, then the space needed by each router is 0(n) in the
worst case. In both cases, the expected time required by a router to process a
message is proportional to the number of neighbors pf the router, since search and
insertion in a hash table have 0(1) expected running time (see Section 2.5.3).
We now analyze the message complexity of flooding algorithms. When using
the hop-counter heuristic, the message complexity is .0 ( (dm - i)D) in the worst
case, where dM is the maximum degree of the routers in our network. When us-
iñg the sequence-number heuristic, the message complexity is 0(m), since we end
up sending a message along every edge in the network.. Since m is usually much
smaller than (dma i)D sequence numbers are generally preferable to hop coun-
ters. In either case, however, the flooding algorithm is only efficient for messages
we are willing to broadcast to all other routers in our network.
Still, the flooding algorithm is guaranteed to send a message M from its source
to each destination in the fewest number of hops in th synchronized network
model. That is, it always finds a shortest routing path. Given the overheads in-
volved in the flooding algorithm, however, it would be nice td have ah algorithm
that can route messages along shortest paths more efficiently. The algorithm we
discuss next does just this by performing some setup computations for determining
good routes in a network.
532 Chapter 11. Network Mgorj
11.3.2 The Distance Vector Algorithm for Unicast Routing r
The first unicast routing algorithm we discuss is a distributed yersion of a cl
algorithm for finding shortest paths in a graph attributed to Bellman and Ford(
lion 7.1.2). We assume that we have a positive weight w(e) assigned to each'
e of the network, which represents the cost of sending a message through e:
example, the weight could represent the average "latency" of the commupjc
link
The unicast routing problem is to set up data structures at the nodes t
network that support the efficient routing of a message from an origin node' to
destination node
The distance vector algorithm always routes along shortest paths. Them
idea of this algorithm is for each router x to store a bucket array called the disût
vector of router x, which stores the length of the best known path from x to e'
other routery in the network, denoted DX[y], and the first edge (connection) ofu
a path, denoted C[y]. Initially, for each edge (x,y), we assign
D[yJ=D[x]=w(x,y)
CX[y] =C[x} =(x,y).
All other D entries are set equal to ±oo. We then perform a series of roun
that iteratively1 refine each distance vector to find possibly better paths until eve
distance vector stores the actual distance to all other routers.
Distributed Relaxation
The setup of the distance vector algorithm consists of a series of rounds. In
each round consists of a collection of relaxation steps. At the beginning of a roui
each router sends its distance vector to all of its immediate neighbors m the n
work. After a router x has received the current distance vectors from each of i
nêighbors, it performs the following local computation for n - i rounds:
for each router w connected tò x do
for each router y in the network do
{ relaxation }
if D[y]±w(x,w)<D[y}then
{ a better route from x toy through w has been found}
D[y] *D[y]±w(x,w).
sroadcast and Unicast Routing sat
Perform a rice
Since each vertex x sends a vector of size n to each of its neighbors in each round,
the time and message complexity foi x to complete a round is O(dn), where d is
the degree of x and n is the number of routers in the network. Recall that we iterate
this algorithm for n - i rounds. In fact, we can improve this to D rounds, where
D is the diameter of the network, as the distance vectors will notchange after that
many rounds. I
After the setup, the distance vector of a router x stOres the actual distances of x
to the other routers in the network and th first edge of such paths Therefore, once
we have performed this setup, the routing algorithm is quite simple: if a router x
receives a message intended foi router y, x sends y along the edge C'4y].
Correctness of the Distance Vector Algorithm
The correctness of the, distance vector, algorithm follows by a simple inductive ar-
gument:
Lemma 11.5: At the end of round i, each distance vector stores the shortest path
to every other router restricted to visit at znost.i other routers along the way.
This fact is true at the beginning of the algonthm, and the relaxations done in each
round ensure that it will be true after each round as well.
Analysis of the Distance Vector. Algorithm
Let us analyze the complexity of the distance vector algorithm. Unlike the flooding
algorithm, discussed in Section 11.3.1, the distanèe vector algorithm has a signifi-
cant setup cost. The total number of messages' passed in each round is proportional
to n times the sum of all the degrees in the network.. This is because the number
of messages sent and received at a router x is O(dn), where d denotes the degree
of x. Thus, there are O(nm.) messages per round. Hence, the total message com-
plexity for the setup of the distance vector algorithm is O(Dnm), which is O(n2m)
in the worst case.
After the setup is èompleted, each router stotés a bucket array with n i ele-
ments, which takes 0(n) space, and processes a message in O(i) expected time
Note that the local spaòç requirement matches that of the flooding algorithm under
the sequence-number heuristic Since the distance vector algorithm finØs shortest
paths, like the flooding algorithm, but does so during the setup computhtion, it can
be viewed as träding off setup costs for 'subsequent effiöient message delivery.
534 Chapter Ii Network Mgòrj(
¡
11.3.3 The Link-State Algorithm för Unicast Routing
The last .static routing algorithm we discuss is ,a distributed version of a clasj'c
shortest path algorithm due to Dijkstra As in the distance vector algorithm
scnption, we assume that the edges have positive weights Whereas the distan
vector algorithm performed its setup in a series of röunds that each required o
local communication between adjacent routers, the hnk-state algorithm compus
single communication round that requires lots of global communication throughof
the entire network. T.
The link-state algonthm proceeds as follows The setup begins with eji
router x broadcasting the weights of its incident edges (that is, the "status" of x)
all other routers in the network, using a floodmg routing algorithm with sequen
numbers (which requires no prior setup; see Section 11.3.1); After this broadjt
phase, each router knows the entire network and can mn Dijkstra's shortest pá
algorithm on it to determine the shortest path from it to every other router y and &e
first edge C [y] of such a path. This. intemnal computation takes O(rnlo n) time j
ing standard implementations of Dijkstra's algorithm, or 0(n log n ± m) using moré
sophisticated data structures (recall Section 7 11)
As in the distance-vector algorithm, the data structure constructed by the sethp
at each router has 0(n) space and supports the processing of a message in 0(1)
expectedtime.
Let us now analyze 'the total message complexity of the setup m the link-state
algorithm. A total of m constant-size messages are broadcast, each of which cauè
m mésÑagès to be sent by the flooding algorithm in turn. Thus, the overall messag
complexity of the setup is 0(m2).
Comparison of Broadcast and Unicast Routing Algorithms
We compare the performance of the three static routiñg algorithms discussed in thii r
section inTabJe 11.10. Note that we aré not including the internal computation üme
that is required of a router that is participating in a preprocessing setup computatiot
in this table.
Algorithm messages loeal space local time routing time
Floodirigwíhopcount
Flooding w! seq. no. 0(1) 0(J) 0(4)' o((d_1)D)
0(1) 0(d)
Distancé vector 0(Dnm) 0(n) 0(1) - 0(m)
Link state 0(n) 0(1)
0(m2) 0(n) 0(p)
. .
0(p)
Table 11 10 Asymptotic performance bounds for static routing algorithms We us
the following notation for the network and routing parameters n, number of nods
m, number of edges, d, maximum node degree, D, diameter, and p, number ö
edges in a shortest routing path Note that p, d, and D are all Jess than n
4. Multicast Routing. 535
.
1.1.4 Multicast Routing
So far, we have studied routing algorithms for two types of communication-
broadcast and unicast routingwhich can be viewed as being at. the two extremes
of a, spectrum. Somewhere in the middlé pf this spectrum is multicast routing,
which involves commumcation with a subset of hosts on a network, called a multi-
cast group. . .. .
11 4 1 Reverse Path Forwarding
. The reverse path forwarding (RPF) algorithm adapts the flóoding algorithms for
broadcast routing to multicast routing It is designed to work in conjunction with
the existing shortest-path routing tables available at every routér, in order to broad-
cast a multicast message along the shortest path tree from a source
The method begins with a host that wishes to send a message to a group g The
host sends that message to its local router s in order for s to then send the message
to all of its neighbonng routers When a router x receives, from one if its neighbors
y, a multicast meEsage that originated at the router s, x cheéks its, local routing table
to see if y is on x's shortest path 'to s. If y is not on x's shoitest path to s, then
(assuming all the routing tables are correct and consistent) the link from y to x is.
not in thé shortest path treefrom s. Thus, in this case, x simply discards the packet
sent from y and sends bàck to ya special prune message, which includes the nàme
of the source s and the group g This prune message tells yto stop sending multicast
messages from.s intended for group g (and, if possible, not to señd any multicast
messages from s along this link no matter what, the groùp is). If, on the other hand,
y is on x's shortest path to s, then x replicates the message and sends it out, to 'all
of its neighboring routers; except for y itself. For, in this case, the link fromyto
x is on the shortest .path tree fröm s (again, assuming that all the routing tablesTare
correct and consistent).
This mode of broadcast communication extends outward from s along the short-
est path free T from s until it floods the entire network The fact that the algonthm
broadcasts a multicast message to every router in the network is wasteful if only a
small fraction of the routers on the network have clients wishing to receive multi-
cast messages that are sent to the group g
To. deal with this waste, the RPF algorithm provides an additional type of mès
sage prumng In particular, if a router x, at an external node of T, determines that it
has no clients on its local network that are interested in receiving messages for the
group g, then x issues a prune message to its parent y in T telling y to stop sending
it messages from s to the group g This message in effect tells y to remove the
external node x from' the free T. ..
536 Chapter ii; Network Algorj
Pruning z
These prune messages can, of course, be issued by many external nodes of
parallel; hence, we can have many external nodes of T remóved at.the same
Moreover, the removal of sème external nodes of T may create new externa ¿%
So, the RPF algorithm has each router x continually test if it has become ari
nal node in T and, if x has, then it should test 'if it has añy client hosts on iSi
networkthat are interested in receiving multicast messages for the group g. Ag
if there are no such clients, then x sends its parent in T a prune message for m
cast messages from s to the group g. This external-nodepruning continues untiL
remaining external nodes in T have clients wishing to receive multicast mesi'
to the group g. At this point the RPF algorithm has reached a steady state.
This steady state cannot be locked in forever, however, for we may have s
client hosts in our network that wish to start receiving messages for the grodp
That is, we may have at least one client h wishing to join the group g. Smc
RPF provides no explicit way for clients to join a group, the only way h can
to:receive multiçasts to group g is if h's router x is receiving those packets B'ijt:
has been pruned from T, then this will not happen. Thus, one additional compq
of the RPF algorithm is that the prunes that are stored at a node in the Interneji
timed out after a certain amount of time
When such a time-out occurs, say for a prune coming nom. a router z to
router x holding z's previous prune message, then x resumes sending multi1
packets for the group g to z. Therefore, if a router really intends not to r
or process certain types of multicast messages, then it must continually inform
upstream neighbors.. of this desire by using prune messages. For thjs reason,r'
RPF algorithm is not an efficient method for performing multicast routing.
Performance
In terms of message efficiency, the RPF initially sends out 0(m) messages, whç
is the number of connections (edges) in the network. After the first wave of
propagate through thé network, however, the complexity of multicasting redu
0(n) messages per multicast message, where n is the number of routers. And
further reduced as additional prune messages are processed. In terms of additiò
storage at the routers,, the RPF algorithm is not too efficient, for it requires that
router store every prune mèssage it receives until that prune message times ou
the worstcase, then, a router xmay have to storé äs many as 0(181 .IÇId) P
messages, where S is the set of sources, Ç is the set of groups, and d is the d
of x in the network. Thus, as we have already observed, the RPF algohthfll
efficient.
Multicast Routing
11.4.2 Center-Based Trees
A multicast algorithm with message efficiency better than» that of the reverse path
forwarding algorithm is the center-based trees method. In this algorithm, we
choose, for each group g, a single router z on the network that will act as the "cen-
ter" or "rendezvous" node for the group g. The router z forms the root node of the
multicast tree T for g, which is used for sending messages to routers that are a part
of this group. Any source wishing to send a multicast message to the group g first
sends that message toward the center z. In the simplest form of the center-based
trees algorithm, this message proceeds all the way to z, and once it is received by
z, then z broadcasts this message to all the nodes in T. Thus, each router x that is
represented by a node in T knows that if x receives a multicast message for g from
its parent in T, then x replicates this message and sends it to all of its neighbors that
correspond to its children in T. Likewise, in the simplest form of the center-based
trees method, if x receives a multicast message from any other neighbor different
than its parent in T, then it sends this message up the treeto z. Such a message i
coming from some source and should be sent up to z before being multicast to T.
As mentioned above, we must explicitly maintâin the multicast tree T for each
group g. Thus, we must provide a way for routers to join the group g. A join
operation for a router x begins by having x send a join message toward the center
node z. Any other router y receiving a join message frôm a neighbor t looks up
to see which of y's neighbors u is on the shortest path to z, and then y creates and
stores an internal record indicating that y now has a child t and a parent u in the
tree T. If y was already in the tree T (that is, there was already a record saying
that u was y's parent in T), then this completes the join operationthe router x is
now a connected external node in the tree T If y was not already in the tree T,
however, then y propagates the join message up to its (new) parent u in T. (See
Fi 11.11.)
(a) (b)
Figure 11.11: ,An illustration of thefl center-based trees protocol. (a) A multicast
tree centered at z, with thick edges being tree edges, dark gray nodes being group
members, and light.gray nodes being routers that simply propagate messages; (b)
the multicast tree after x joins. Notice that x could have joined using just one edge
and no additional intermediate nodes, but the route to z would not be a shórtest
path.
538 Chàpter 1L Network A1g6rj
Performance
For routers wishing to leave group g, either through explicit leave messages
because a join record times out, we essentially reverse the action weperformed f
à join. In terms of efficiency, the center-based trees methôd only sends messg
along T, the multicast tree for group g, so its message complexity is O(ITIYfo
each multicast. Iii addition, since èach router only stores the local structure of'
the maximüm number of records that neèd to be stored at any router x is o(IgI>i
where Ç is the set of groups and d is the degree of x in the network. Theref&
the center-based tree algorithm has the benefit of efficiency that cornes from alwài'g
sending multicast messages for a group g along a single tree T. This free may
be the most efficient tree for sending such a message, however.
11.4.3 Steiner Trees
r
The main goal of the Steiner tree algorithm is to optimize the total cost of ali
edges we are using to build the multicast tree for a group g. Formally, we j
G = (V, E) denote our network, with V be.ing the set of routers, and we define
metric, c(e), for the edges of G. Additionally, we assume we are given a subset S'
V that indicates the routers in our network that belong to the group.g. The Steine
tree T for S is the tree of immmum total cost that connects all the nodes in S Note
that if SI = 1, then T is a single node, that if 151 = 2, then T is the shortest pá
between the two nodes in S, and if j1 = IVI, then T is the minimum spanning tréc
for T. Thus, for these special cases, we can easily construct the optimal tree,
joining the nodes of S and we can use this tree for all multicasts to the group g
in the center-based trees algorithm. Unfortunately, solving the general case of tb
Steiner tree problem is NP-hard (Section 13.2.1); hence, we should try to emplq
some heuristic algorithm that can approximate the Steiner tree.
The Steiner tree approximation algorithm we describe is based on the minim
spanning tree algorithm describèd above (in Section 11.2.4). It uses informatio
already available at each router in the network and is known as the distance networ
algorithm, for it operates on a graph G1,.: derived from G, known as the distan
network for S. The graph G' is formed by taking the vertices of S as its nod
and connecting each pair of such nodes with an edge. The cost c' (e) of an
e = (y, w) in G' is exactly the distance between y and w in G, that is, the lengtl
the shortest path from y to w in G (we are assumiñg that G is undirected here).
specific algorithm is as follows:
1.. Construct a representation of the distance network, G' for S.
9 Find n minimum snannin free (MST TM in G'.
3 T;anS;teT oatreeAmCy taking the shortest path from y to wf
eachedge(v,w)inTM.
Find the MST TD in the subgraph of G induced by the nodes of TA.
Remóve from 7"D any paths leading to exterhal nodes not in S;