How to turn i.i.d. U(0,1) random numbers into observations from the distributions a model actually needs — the inverse transform and composition methods, and what makes a variate-generation algorithm good.
Goal. Study algorithms that produce observations (realizations) from some desired input distribution, given a stream of i.i.d. U(0,1) random numbers.
Chapter 3 produced the raw material: uniform random numbers. This chapter turns them into random variates from whatever distribution the model calls for — e.g. the exponential interarrival and service times of an M/M/1 queue.
4.1. Structure
It is essential to have a statistically reliable underlying RNG. Every algorithm below assumes its input really is i.i.d. U(0,1); a defective generator corrupts every variate built from it.
Factors in choosing an algorithm.
1. Exactness. An algorithm is exact if the variates it produces have exactly the desired distribution, not merely approximately.
Example of an inexact method. To generate Z∼N(0,1):
Generate u1,…,u12 i.i.d. U(0,1).
Return Z=u1+u2+⋯+u12−6.
The moments come out right:
E[Z]=12⋅21−6=0,Var(Z)=12⋅121=1,
and by the CLT the sum is approximately normal. But it is not exact. Since each ui∈[0,1], the output always satisfies
Z∈[−6,6],
whereas a true N(0,1) variable has range (−∞,∞). The algorithm can never produce a value beyond ±6, so it truncates both tails — exactly the region that matters most in reliability, risk, and rare-event studies. It is also wasteful: 12 random numbers per variate. Avoid it; use an exact method (§4.2.5) instead.
2. Efficiency.
memory usage;
execution time, including setup time (some algorithms precompute tables; that cost is paid once but must be counted).
3. Simplicity: easy to understand, implement, and debug. There is a trade-off between efficiency and simplicity — the fastest algorithm is rarely the clearest.
4. If possible, use exactly one random number per random variate. Reasons:
Simplicity.
Synchronization. When comparing two systems with common random numbers (§3.3, practical issue 3), we want the i-th variate in system A to be built from the same ui as in system B. If one system consumes a variable number of uniforms per variate, the two streams drift out of step and the comparison loses its sharpness.
Monotonicity. With one uniform per variate and X=F−1(u), the variate is a monotone function of u. This is what makes variance-reduction techniques such as antithetic variates work.
4.2. RVG Algorithms
Direct methods — build the variate straight from the definition of the distribution:
Inverse transform — universally applicable in principle, but may be hard to implement.
Composition ⎫
Convolution ⎭ — apply only to input distributions of a specific form (mixtures and sums, respectively).
When these fail — that is, when F−1 has no usable closed form and the distribution is neither a convenient mixture nor a convenient sum (the normal, gamma, and beta distributions are the standard examples) — fall back on:
Acceptance–rejection method.
Special techniques, e.g. for normal random variables.
4.2.1. Inverse Transform Method
Continuous case. Let X be a continuous r.v. with c.d.f. F.
Algorithm.
Generate u∼U(0,1).
Return X=F−1(u).
The catch is step 2: F−1 must be computed, and for many distributions (normal, gamma, beta) it has no closed form.
Proof that the output has c.d.f. F.
P(X≤x)=P(F−1(u)≤x)=P(F(F−1(u))≤F(x))=P(u≤F(x))=F(x)applying F to both sides; valid since F is non-decreasingsince u∼U(0,1).
The last step is the definition of the uniform distribution: P(u≤a)=a for any a∈[0,1], and here a=F(x) is indeed in [0,1] because it is a probability. So the c.d.f. of the generated X is F, exactly — the method is exact.
Example: X∼Exp(λ). Here F(x)=1−e−λx for x>0. Set u=F(x) and solve:
u=1−e−λx⟹e−λx=1−u⟹x=−λ1ln(1−u).
Algorithm.
Generate u∼U(0,1).
Return X=−λ1ln(1−u).
Variant. Replace step 2 by “2′. Return X=−λ1lnu.”
This is valid because 1−u∼U(0,1) whenever u∼U(0,1), so the two versions produce the same distribution. It saves one subtraction per variate — a genuine but small gain in a tight loop.
Two cautions, though:
Monotonicity is lost. Version 2 is increasing in u; version 2′ is decreasing. Under 2, a large u gives a long interarrival time in both of two systems being compared; under 2′ the correspondence is reversed. Where synchronization or antithetic variates matter, prefer 2.
The value u=0. An LCG can output u=0 (when zi=0), and ln0 is undefined. Version 2 never has this problem, since 1−u∈(0,1]. If 2′ is used, u=0 must be screened out.
Efficiency problem. The number of comparisons the chain performs equals I, the index it returns. Since the algorithm returns xi exactly when I=i, and P(I=i)=P(X=xi)=p(xi), the number of comparisons N is a random variable with the same distribution as the index, so by the definition of expectation,
E[N]=i=1∑ni⋅P(N=i)=i=1∑nip(xi).
If the probable values sit late in the list, this is close to n: tiny jumps at x1,x2,… and the big jumps only at the end.
Two fixes.
Binary search. Since F(x1)≤F(x2)≤⋯≤F(xn) is a sorted array, locate u by bisection instead of scanning: O(log2n) comparisons instead of O(n), whatever the probabilities.
Reorder the comparisons. Test the values in decreasing order of probability. Relabel so that p(1)≥p(2)≥⋯≥p(n) and build the cumulative sums for that new order; then E[N]=∑iip(i) is as small as possible. The reordering is done once in setup, so it costs nothing at run time.
Example.n=6 with p=(0.05,0.05,0.10,0.10,0.20,0.50):
order of testing
E[comparisons]
as given: x1,x2,…,x6
∑iipi=4.85
decreasing probability: x6,x5,x3,x4,x1,x2
∑iip(i)=2.15
More than twice as fast, for no cost beyond sorting once.
Does reordering change the simulation? No. The output distribution is exactly the same — each xi is still returned with probability p(xi), because the intervals of (0,1] assigned to the values have the same widths p(xi); only their positions along (0,1] are permuted. The only thing that changes is the expected number of comparisons, i.e. the run time.
The one side effect: reordering destroys the monotone relationship between u and X, so the output is no longer F−1(u) as a function of u. If synchronization or antithetic variates matter (see “Advantages” below), keep the natural order or use binary search, which preserves it.
Example: discrete uniform.X∼DU(1,100), i.e. X∈{1,2,…,100} with p(i)=1001 for every i, so F(i)=100i.
The general algorithm becomes:
Generate u∼U(0,1).
if u ≤ 0.01 return X = 1; else if u ≤ 0.02 return X = 2; … ; else return X = 100
But here the chain can be replaced by a formula. The first i with u≤i/100 is characterized by
100i−1<u≤100i⟺i−1<100u≤i⟺i=⌈100u⌉,
so step 2 collapses to
X=⌈100u⌉
— one multiplication and one ceiling, instead of up to 100 comparisons. (Equal probabilities are what make this possible; unequal ones need the search.)
Generalized inverse transform. To cover continuous, discrete, and mixed distributions in one statement:
Generate u∼U(0,1).
Return X=min{x:F(x)≥u}.
This is the same rule as before, written so it always makes sense. An ordinary inverse F−1 requires F to be strictly increasing and continuous; a discrete F is flat in places (so no unique inverse) and jumps in places (so some values of u have no x with F(x)=u at all). Taking the smallest x whose F(x) has reachedu handles both defects, and reduces to the usual F−1(u) when F is continuous and strictly increasing.
Advantages and disadvantages of the inverse transform method.
Disadvantages.
Must invert the c.d.f., which may have no closed form (normal, gamma, beta).
May not be the most efficient approach even when the inverse exists.
Advantages.
Easy to generate from truncated distributions. Truncating means restricting X to an interval [a,b] and renormalizing:
F∗(x)=F(b)−F(a)F(x)−F(a),a≤x≤b,
which is the original density chopped off outside [a,b] and scaled up so the area is again 1.
Inverting F∗ costs nothing extra: generate u∼U(0,1) and return
X=F−1(F(a)+u[F(b)−F(a)]).
In words: instead of drawing u uniformly over all of (0,1), draw it uniformly over the slice (F(a),F(b)) of the vertical axis. Every draw is usable — no rejection, one uniform per variate.
Facilitates variance reduction when comparing alternative systems. Let X1∼F1 be the output of system 1 and X2∼F2 that of system 2, and suppose we want the difference in mean cost,
E[X1]−E[X2]=E[X1−X2],
so that X1−X2 is an unbiased estimator of the gap. Generate both by inverse transform, X1=F1−1(u1) and X2=F2−1(u2). Since
Var(X1−X2)=Var(X1)+Var(X2)−2cov(X1,X2),
the precision of the comparison is controlled entirely by how we couple u1 and u2:
coupling
cov(X1,X2)
Var(X1−X2)
1. u1⊥u2 (independent)
0
Var(X1)+Var(X2)
2. u1=u2 (common random numbers)
>0
smaller
3. u1=1−u2 (antithetic)
<0
larger
Case 2 is the useful one. Both F1−1 and F2−1 are non-decreasing, so a large u pushes bothX1 and X2 up and a small u pushes both down: the two outputs move together, cov(X1,X2)>0, and the variance of the difference drops. Note X1=X2 still, since F1=F2. Monotonicity is exactly what the inverse transform provides and what a rejection-based method does not — hence “facilitates”.
(Case 3 is not useless in general; antithetic variates reduce variance when estimating a single mean by averaging X1 and X2, where the negative correlation helps. It is only harmful here, where we take a difference.)
4.2.2. Composition
The name. The target distribution is composed of simpler ones — the way a mixture’s chemical composition lists its ingredients. The method is also called the mixture method: decompose F into pieces you know how to sample from, pick a piece at random, then sample from it.
Setup. Use this when F can be written as a convex combination of other c.d.f.s F1,F2,… (finitely or infinitely many):
F(x)=j≥1∑pjFj(x),j≥1∑pj=1,pj≥0.
Equivalently, in terms of densities or mass functions,
f(x)=j≥1∑pjfj(x)orp(x)=j≥1∑pjp(j)(x).
Algorithm.
Generate a positive random integer J with P(J=j)=pj (a discrete variate — use the inverse transform of §4.2.1).
Split the formula into its two terms and read off the weights:
f(x)=p1a⋅f1(x)1+p2(1−a)⋅f2(x)2x,
where f1 is the U(0,1) density and f2(x)=2x on [0,1] is a triangular density with F2(x)=x2, so F2−1(u)=u.
Algorithm.
Generate u1,u2 independent U(0,1).
If u1≤a, return X=u2; else return X=u2.
Here u1 chooses the component (J=1 with probability a) and u2 generates from it.
Example: symmetric triangular distribution on [−1,1].
f(x)=⎩⎨⎧1+x,1−x,0,−1≤x≤0,0≤x≤1,otherwise.
Each half of the triangle has area 21, so take p1=p2=21 with
f1(x)=2(1+x) on [−1,0],f2(x)=2(1−x) on [0,1]
(each doubled so that it integrates to 1 on its own half). For the right piece, F2(x)=2x−x2, and solving u=2x−x2 gives x=1−1−u, i.e. 1−u after replacing 1−u by u. The left piece is its mirror image.
Algorithm (composition).
Generate u1,u2 independent U(0,1).
If u1≤21, return X=u2−1; else return X=1−1−u2.
The same distribution by inverse transform. The c.d.f. is
F(x)=⎩⎨⎧2(1+x)2,1−2(1−x)2,−1≤x≤0,0≤x≤1,
and F(0)=21, so u<21 corresponds to the left half. Solving u=2(1+x)2 gives x=−1+2u; solving u=1−2(1−x)2 gives x=1−2(1−u).
Generate u∼U(0,1).
If u<21, return X=−1+2u; else return X=1−2(1−u).
Efficiency comparison (expected operations per variate):
u’s
comparisons
additions
multiplications
square roots
inverse
1
1
1.5
1
1
composition
2
1
1.5
0
1
How the counts are obtained. Each row averages the two branches, which are taken with probability 21 each; a subtraction counts as an addition. For the inverse method, the left branch −1+2u uses one multiplication (2u), one square root and one addition, while the right branch 1−2(1−u) uses one multiplication (2×), one square root and two additions (1−u and 1−⋅) — so the average is 21(1)+21(2)=1.5 additions, with 1 multiplication and 1 square root either way, plus the single comparison u<21 and the single uniform. For composition, u2−1 has one addition and 1−1−u2 has two, giving the same 1.5 average and the same one square root and one comparison, but no multiplication — the factor 2 never appears, because doubling the density was absorbed into choosing a half. The cost is that u1 is spent on the coin toss and u2 on the value, so two uniforms are consumed instead of one.
Conclusion. The two methods differ in exactly two places: composition saves one multiplication but spends one extra random number. Generating a random number is far more expensive than a multiplication, so the inverse transform is more efficient here. (It also keeps X monotone in u, which composition does not — see §4.2.1, advantage 4.)
4.2.3. Convolution
Setup. Let Y1,Y2,…,Ym be i.i.d. with common c.d.f. G, and define
X=Y1+Y2+⋯+Ym.
The c.d.f. F of X is called the m-fold convolution of G with itself. Use this method whenever the target distribution is known to arise as such a sum.
Algorithm (to generate from F):
Generate Y1,…,Ym independently from G.
Return X=Y1+Y2+⋯+Ym.
Why the proof is trivial. Unlike the inverse transform or composition, there is nothing to verify: F was defined as the distribution of the sum, and the algorithm literally forms that sum from independent draws. Correctness is by construction. The work in this method lies elsewhere — in recognizing that the desired F is a convolution of something samplable.
Example: sum of two exponentials. Let X1⊥X2∼Exp(λ) and Z=X1+X2. Then
Condition on X2 (law of total probability, continuous version). To find P(A), split according to the value x that X2 takes, weight each case by the density fX2(x), and integrate over all x — the continuous analogue of P(A)=∑jP(A∣Bj)P(Bj). The range is [0,∞) because X2≥0. The purpose is to turn a two-variable event into a one-variable one.
Use the condition, then drop it. Given X2=x, the event X1+X2≤z is X1+x≤z, i.e. X1≤z−x. Then, because X1⊥X2, knowing X2=x says nothing about X1, so P(X1≤z−x∣X2=x)=P(X1≤z−x) — the condition disappears. Also substitute fX2(x)=λe−λx.
Substitute the c.d.f. of X1.P(X1≤z−x)=FX1(z−x)=1−e−λ(z−x), valid when z−x≥0. When x>z the argument is negative and FX1=0 (X1 is never negative), so the integrand vanishes there; hence the upper limit drops from ∞ to z.
Expand and simplify. Multiply out (1−e−λ(z−x))λe−λx and split into two integrals. In the second, e−λ(z−x)⋅e−λx=e−λz+λx−λx=e−λz: the x cancels, leaving a constant.
Evaluate. First integral: ∫0zλe−λxdx=[−e−λx]0z=1−e−λz. Second: the integrand is the constant λe−λz, so the integral is that constant times the interval length z.
Rewrite as a sum. Factor out e−λz: 1−e−λz(1+λz). The two terms in the bracket are 0!(λz)0=1 and 1!(λz)1=λz, i.e. i=0,1 of ∑ii!(λz)i. Writing it this way exposes the pattern: for a sum of n exponentials the same calculation, repeated, gives the terms i=0,…,n−1.
Generalization: the Erlang distribution. Let X1,…,Xn be i.i.d. Exp(λ) and Z=X1+⋯+Xn. Repeating the argument gives
FZ(z)=1−i=0∑n−1e−λzi!(λz)i,z≥0,
and Z is called an Erlang(n,λ) variable — the special case of the Gamma(n,λ) distribution with integer shape parameter.
Reading the formula. The sum is exactly P(N(z)≤n−1) for a Poisson variable N(z) with mean λz. This is the Poisson-process statement of §2.5: the n-th arrival occurs by time z if and only if at least n arrivals have occurred by then. So “waiting for the n-th event” and “counting events” are two views of the same process.
Algorithm for Erlang(n,λ).
Generate Y1,…,Yn i.i.d. Exp(λ) (each by inverse transform, §4.2.1).
Return X=Y1+Y2+⋯+Yn.
This is exact and trivially correct, but it costs n uniforms and n logarithms per variate. One improvement is free:
X=i=1∑n(−λ1lnui)=−λ1ln(i=1∏nui),
so multiply the uniforms first and take a single logarithm. The n uniforms are still needed, which is why convolution becomes unattractive for large n — and why the Gamma distribution with non-integer shape needs a different method (acceptance–rejection, §4.2.4).
Composition vs. convolution. Both write the target in terms of simpler distributions, but in opposite ways:
composition
convolution
decomposition
F=∑jpjFj (weighted mixture)
X=Y1+⋯+Ym (sum)
what you do
pick one component at random, sample it
sample all components, add them
uniforms used
1 for the choice + those for one component
those for all m components
Example: symmetric triangular distribution, third method. Recall (§4.2.2)
f(x)=⎩⎨⎧x+1,−x+1,0,−1≤x<0,0≤x≤1,otherwise.
Let u1⊥u2∼U(0,1) and Z=u1+u2. The pair (u1,u2) is uniform on the unit square (joint density =1), so a probability is an area:
FZ(z)=P(Z≤z)=P(u1+u2≤z)=0≤u1≤1,0≤u2≤1u1+u2≤z∬1du1du2=area of the part of the square below the line u2=z−u1.
Case 0≤z≤1. The line cuts off a right triangle at the origin with legs z and z:
FZ(z)=21z2.
Case 1≤z≤2. Now the line cuts off the top-right corner, a right triangle with legs 2−z. Shaded area = whole square minus that corner:
FZ(z)=1−21(2−z)2=−21z2+2z−1.
Differentiating gives the density of Z:
fZ(z)=FZ′(z)={z,−z+2,0≤z≤1,1≤z≤2,
a triangle on [0,2] with peak at z=1. Subtracting 1 slides it to [−1,1]: X=Z−1 has fX(x)=fZ(x+1), which is x+1 on [−1,0] and −(x+1)+2=1−x on [0,1] — exactly the target.
Algorithm (convolution).
Generate u1⊥u2∼U(0,1).
Return X=u1+u2−1.
Why this beats both earlier methods. Add the new row to the table from §4.2.2:
u’s
comparisons
additions
multiplications
square roots
inverse
1
1
1.5
1
1
composition
2
1
1.5
0
1
convolution
2
0
2
0
0
Convolution uses the same two uniforms as composition but eliminates the comparison, the multiplication, and above all the square root, at the price of half an extra addition. A square root is by far the most expensive operation in the table — many times the cost of an addition, and more than the cost of drawing a uniform — so removing it outweighs the second uniform, and convolution is the most efficient of the three for this distribution. (Against inverse transform, the trade is one extra uniform plus half an addition in exchange for dropping a comparison, a multiplication and a square root; the square root alone settles it.)
4.2.4. Acceptance–Rejection (AR)
Where it sits. Methods 1–3 (§4.2.1–4.2.3) are direct: they compute X from the uniforms by a formula. Acceptance–rejection is the indirect method from the list in §4.2: it does not compute X; it generates candidates from an easier distribution and keeps only some of them. The arrow in the lecture outline (“rejection → indirect”) just records that classification.
When to use it. When the desired p.d.f. f has a form too complex to invert or decompose.
Idea. Use a simple, easy-to-sample p.d.f. — a surrogate — that approximates f from above, then correct for the difference by discarding a fraction of the draws.
Setup. Choose a majorizing functiont with
t(x)≥f(x)for all x.
Then
c=∫−∞∞t(x)dx≥∫−∞∞f(x)dx=1,
so t is not a density (its area exceeds 1), but its normalization
r(x)=ct(x)
is a valid p.d.f. (r≥0 and ∫r=c/c=1). r is the surrogate we actually sample from.
AR algorithm.
Generate Y∼r.
Generate u∼U(0,1), independent of Y.
If u≤t(Y)f(Y), return X=Y (accept).
Otherwise discard Y and go back to step 1.
On step 1:Y is generated from the surrogate r, not from f — that is the whole point. Since r was chosen to be simple, this is done by one of the direct methods (typically inverse transform). Y is only a candidate for X; steps 3–4 decide whether it becomes one.
On step 3: the ratio f(Y)/t(Y) lies in [0,1] because t≥f. Comparing it with a uniform means: accept Y with probability f(Y)/t(Y). Where t hugs f this is near 1 (almost always accept); where t is far above f it is small (usually reject). The rejections thin out exactly the regions where r over-samples relative to f.
Proof that the output has c.d.f. F. The returned X is a candidate Ygiven that it was accepted, so
We compute the denominator first (it is also the efficiency, comment 2 below):
P(Y accepted)=P(u≤t(Y)f(Y))=∫−∞∞P(u≤t(Y)f(Y)Y=y)r(y)dy=∫−∞∞P(u≤t(y)f(y))r(y)dy=∫−∞∞t(y)f(y)⋅ct(y)dy=c1∫−∞∞f(y)dy=c1.(condition on Y)(u⊥Y, so the condition drops)(P(u≤a)=a;r=t/c)
The numerator is the same calculation with the extra event Y≤x, which after conditioning on Y=y just restricts the integral to y≤x:
Note the mechanism: t(y) cancels between the acceptance probability f/t and the surrogate density t/c, and c cancels between numerator and denominator. Whatever shape t has, the output is exactly f — the choice of t affects only speed, never correctness.
Comments.
Generating from r must be much easier than generating from f; otherwise there is no point in using a surrogate. In practice, choose simple majorizing functions — piecewise constant or piecewise linear.
The algorithm loops until a pair (u,Y) with u≤f(Y)/t(Y) turns up. From the proof,
P(Y accepted)=c1=area under t1,P(reject)=1−c1.
Why the average number of trials is c: each pass through steps 1–3 is an independent trial with success probability p=1/c (fresh Y and u each time). The number of trials until the first success is therefore Geometric(p), whose mean is 1/p=c. So c uniforms-pairs are consumed per variate on average — a large c means a slow generator.
P(Y accepted)=1/c is called the efficiency of the AR method. We want it as close to 1 as possible, i.e. t as tight around f as possible — but a tighter t is usually a more complicated one, harder to sample from. This is the same simplicity vs. efficiency trade-off as in §4.1.
Example.f(x)=23x2 on (−1,1) (and 0 elsewhere). Check: ∫−1123x2dx=1. The maximum of f is 23, at x=±1.
First attempt: a flat majorizing function. Take t(x)=23 on (−1,1) — the smallest constant that stays above f. Then c=23⋅2=3 and r(x)=t(x)/3=21 on (−1,1), i.e. r is the U(−1,1) density.
Generate Y∼U(−1,1) (e.g. Y=2u′−1 with u′∼U(0,1)).
Generate u∼U(0,1), independent of Y.
If u≤Y2, return X=Y. (t(Y)f(Y)=2323Y2=Y2)
Otherwise go back to step 1.
Efficiency =1/c=1/3: on average three candidates (six uniforms) per accepted variate. The waste is visible in the figure — the rectangle under t has area 3 while the bowl under f has area 1, and everything in between is rejected.
Improvement: a tighter majorizing function. We need t≥f but with less area. On [−1,1] we have ∣x∣≥x2, so
t(x)=23∣x∣≥23x2=f(x),
with equality at x=0,±1. Its area is c=∫−1123∣x∣dx=23, so the efficiency rises to 1/c=2/3: on average 1.5 candidates per variate instead of 3. The surrogate is r(x)=t(x)/c=∣x∣ on (−1,1), a symmetric “V” density, easy to sample by inverse transform: its right half has c.d.f. x2, so ∣Y∣=u′, and a fair coin picks the sign.
Generate u1,u2∼U(0,1); set Y=u2 if u1≤21, else Y=−u2. Then Y∼r.
Generate u∼U(0,1), independent of Y.
If u≤∣Y∣, return X=Y. (t(Y)f(Y)=23∣Y∣23Y2=∣Y∣)
Otherwise go back to step 1.
Each trial now costs three uniforms and a square root instead of two uniforms, but only 1.5 trials are needed on average instead of 3 — the trade-off of comment 3 in miniature.
4.2.5. Special Techniques
There is no general recipe here. A special technique exploits some property that the target distribution happens to have — a relation to another distribution we already know how to sample. Two small examples now; the big one (the normal distribution) gets its own treatment in §4.3.
Example: chi-square with one degree of freedom. Recall from §2.6.3 that if Y∼N(0,1) then Y2∼χ12. So:
Generate Y∼N(0,1) (§4.3).
Return X=Y2.
Combining with convolution: χk2 is the sum of k independent χ12 variables, so X=Y12+⋯+Yk2 with Yi i.i.d. N(0,1).
Example: geometric by Bernoulli trials. Let X∼Geo(p) be the number of trials needed until the first success, each trial succeeding with probability p. Simulate the trials literally:
Set X=1.
Generate Y∼Bernoulli(p) (i.e. u∼U(0,1) and Y=1 if u≤p).
If Y=1, return X.
Otherwise set X=X+1 and go back to step 2.
This is exact and transparent, but it consumes one uniform per trial, and the expected number of trials is E[X]=1/p. For p=0.01 that is 100 uniforms per variate. §4.4 gives a one-uniform formula instead.
4.3. Generating Continuous Random Variates
§4.2 presented the methods abstractly. This section collects the concrete algorithms actually used for the common continuous distributions.
Uniform U(a,b). Inverse transform: F(x)=b−ax−a on [a,b], so u=b−ax−a⟺x=a+(b−a)u.
Generate u∼U(0,1).
Return X=a+(b−a)u.
Exponential Exp(λ). From §4.2.1:
Generate u∼U(0,1).
Return X=−λ1lnu.
Erlang(m,λ). From §4.2.3, X=Y1+⋯+Ym with Yi i.i.d. Exp(λ):
Generate u1,…,um∼U(0,1).
Return X=−λ1ln(∏i=1mui).
(Gamma with non-integer shape, Weibull, beta, etc. need special-purpose methods, mostly acceptance–rejection; not covered here.)
4.3.1. Normal distribution: the Box–Muller method
The normal c.d.f. has no closed-form inverse, so inverse transform is out. Composition and convolution do not apply. The trick is a special technique: look at two independent standard normals at once and switch to polar coordinates.
The key fact. Let X1⊥X2∼N(0,1) and write the point (X1,X2) in polar form:
R2=X12+X22,Θ=tan−1(X1X2).
Then R2 and Θ are independent, with
R2∼Exp(21)(rate 21, mean 2),Θ∼U(0,2π).
Why. The joint density of (X1,X2) is the product of two N(0,1) densities:
It depends on (x1,x2) only through x12+x22=r2 — the density is rotationally symmetric, which is why the angle will come out uniform. To change variables to (S,Θ)=(R2,Θ) we need the Jacobian of the map g1(x1,x2)=x12+x22, g2(x1,x2)=tan−1(x2/x1). Using dxdtan−1x=1+x21,
The change-of-variables formula gives fS,Θ(s,θ)=fX1,X2(x1,x2)∣J∣−1, so
fS,Θ(s,θ)=2π1e−s/2⋅21=Exp(1/2) density in s21e−s/2⋅U(0,2π) density in θ2π1,s≥0,0≤θ<2π.
The joint density factors into a function of s alone times a function of θ alone, which is exactly the statement that S=R2 and Θ are independent with those marginals.
Run it backwards. We know how to generate both pieces: R2∼Exp(21) is −2lnu1 by inverse transform (rate λ=21 gives −λ1lnu=−2lnu), and Θ=2πu2. Converting back from polar to Cartesian coordinates then yields two independent standard normals.
Algorithm (Box–Muller).
Generate u1⊥u2∼U(0,1).
Return
X1=−2lnu1cos(2πu2),X2=−2lnu1sin(2πu2).
Two uniforms in, two independent N(0,1) variates out — exact, no rejection.
Two cautions.
The uniforms must really be independent. If u1,u2 are consecutive outputs of a poor LCG (recall RANDU, §3.2.3), the pairs (u1,u2) lie on a few lines in the unit square, and after the transformation the points (X1,X2) fall on a visible spiral in the plane. In practice one uses separate streams for u1 and u2 (§3.3, practical issue 3).
Cost. One logarithm, one square root, one sine and one cosine per pair. The trigonometric functions are expensive, which motivates the next algorithm.
4.3.2. Normal distribution: the polar method (acceptance–rejection)
The polar method avoids sin and cos by generating the angle geometrically instead of computing it.
Algorithm (polar method).
Generate V1⊥V2∼U(−1,1) (i.e. Vi=2ui−1).
Let S=V12+V22. If S>1 (or S=0), go back to step 1.
Otherwise let
W=S−2lnS
and return X1=V1W, X2=V2W.
Why it works. The pair (V1,V2) is uniform on the square [−1,1]2; conditioning on S≤1 makes it uniform on the unit disk. For a uniform point in the disk, the angle Θ is U(0,2π) and the squared radius S is U(0,1) (because P(S≤s)=area of disk of radius s=πs/π=s), independently of each other. Now compare with Box–Muller: we need cosΘ, sinΘ, and −2lnu for a uniform u. But
cosΘ=SV1,sinΘ=SV2,and S itself is the uniform we need, so R=−2lnS.
Multiplying out,
X1=RcosΘ=−2lnS⋅SV1=V1S−2lnS=V1W,
and likewise X2=V2W. The cosine and sine have been replaced by a division.
Efficiency.P(accept)=P(S≤1)=area of squarearea of unit disk=4π≈0.785, so on average 4/π≈1.27 attempts, i.e. about 2.55 uniforms per pair of normals. The price of avoiding trigonometry is that roughly one attempt in five is thrown away, and the method no longer uses a fixed number of uniforms per variate (bad for synchronization, §4.1).
Non-standard normal. If Y∼N(0,1) then X=μ+σY∼N(μ,σ2). Generate Y by either method above and shift and scale.
4.3.3. Lognormal distribution
X is lognormal, X∼LN(μ,σ2), if lnX∼N(μ,σ2) — equivalently X=eY with Y∼N(μ,σ2). (Note μ,σ2 are the mean and variance of lnX, not of X.)
Generate Y∼N(μ,σ2).
Return X=eY.
4.3.4. Truncated distributions
Suppose we want X restricted to an interval [a,b]. There are two different things “truncate” can mean:
Redistribute the mass that falls outside [a,b] proportionally over [a,b] — the conditional distribution of X given a≤X≤b.
Pile up the outside mass at the endpoints: values below a become a, values above b become b. This is clipping, X∗=min(max(X,a),b), and it creates atoms at a and b.
The first is the usual meaning. Its c.d.f. is
F~(x)=F(b)−F(a)F(x)−F(a),a≤x≤b,
with density f~(x)=F(b)−F(a)f(x) on [a,b] — the original density scaled up by the constant 1/(F(b)−F(a)) so that it integrates to 1 again. (Check: F~(x)=∫axF(b)−F(a)f(y)dy=F(b)−F(a)F(x)−F(a).)
This is the “advantage 3” of §4.2.1 in detail. The alternative — generate from F and reject anything outside [a,b] — is acceptance–rejection with efficiency F(b)−F(a), which can be tiny if the interval is in a tail; the inverse-transform version uses every uniform.
4.3.5. More continuous distributions
A short tour of the other continuous distributions the textbook covers.
Inverse transform, closed form.
Weibull(α,β): F(x)=1−e−(x/β)α, so F−1(u)=β[−ln(1−u)]1/α. Algorithm: generate u, return X=β(−lnu)1/α. (Equivalently: an Exp variable with mean βα, raised to the power 1/α.)
Log-logistic(α,β): F−1(u)=β[u/(1−u)]1/α.
Triangular(0,1,m) (mode m∈(0,1)):
F−1(u)={mu,1−(1−m)(1−u),0≤u≤m,m<u≤1.
Generate u; if u≤m return mu, otherwise return 1−(1−m)(1−u). For triang(a,b,m) rescale: X′=a+(b−a)X with mode (m−a)/(b−a).
The textbook’s “Why?”: in the second branch one may not replace 1−u by u. The usual excuse — “u and 1−u have the same distribution” — applies to a uniform used on its own. Here the same u also decides the branch: the second formula is only ever evaluated for u∈(m,1], and on that set 1−u ranges over [0,1−m) while u ranges over (m,1] — different sets, different distributions. Making the swap gives the wrong answer (in a check with m=0.3, P(X≤m) came out 0.60 instead of 0.30). To swap, you would have to swap in both places: test u≥1−m and use 1−u in the first branch as well.
Special properties.
Student’s tk: if Y∼N(0,1) and Z∼χk2 are independent, X=Y/Z/k∼tk. Generate Y (§4.3.1) and Z (§4.2.5) and combine.
Fk1,k2: with independent Z1∼χk12, Z2∼χk22, X=(Z1/k1)/(Z2/k2).
Beta(α1,α2) on [0,1]: with independent Y1∼Gamma(α1,1), Y2∼Gamma(α2,1), X=Y1/(Y1+Y2). Special cases need no gamma: Beta(α1,1) has F(x)=xα1, so X=u1/α1; Beta(1,1)=U(0,1); and 1−X∼Beta(α2,α1).
Gamma(α,β) with non-integer α: no closed-form inverse; the textbook gives two acceptance–rejection algorithms (Ahrens–Dieter for 0<α<1, Cheng for α>1). Scale is free: Gamma(α,β)=β⋅Gamma(α,1). The m-Erlang algorithm of §4.3 is the integer case; for m≳10 the general gamma generator is faster, and for large m the product ∏ui can underflow toward 0 before its logarithm is taken.
Lognormal: matching a target mean and variance. The parameters μ,σ2 of LN(μ,σ2) are the mean and variance of lnX, not of X. If the model is specified by m′=E[X] and s′2=Var(X), convert first:
μ=lnm′2+s′2m′2,σ2=ln(1+m′2s′2),
then generate Y∼N(μ,σ2) and return X=eY. (Check with m′=2, s′2=1: simulated mean 2.00, variance 1.00.)
Empirical distributions. With raw observations X(1)≤⋯≤X(n) and the piecewise-linear empirical c.d.f. of §2, the inverse transform needs no search because the corners sit at levels 0,n−11,n−12,…,1:
Generate u; let P=(n−1)u and I=⌊P⌋+1.
Return X=X(I)+(P−I+1)(X(I+1)−X(I)).
The output always lies in [X(1),X(n)] — no values beyond the observed range can ever appear, which is the known limitation of empirical input modelling.
4.4. Generating Discrete Random Variates
Inverse transform works for every discrete distribution (§4.2.1), but is not always the fastest. Besides the specific formulas below, the section ends with two table-based methods — table lookup and the alias method — that trade setup and storage for speed.
Bernoulli(p).X=1 with probability p, 0 with probability 1−p. Inverse transform with two values:
Generate u∼U(0,1).
If u≤p, return X=1; otherwise return X=0.
Binomial(n,p). The number of successes in n independent Bernoulli(p) trials is a sum, so use convolution:
Generate Y1,…,Yn i.i.d. Bernoulli(p).
Return X=Y1+⋯+Yn.
Costs n uniforms per variate; fine for small n.
Discrete uniform DU(i,j).P(X=k)=j−i+11 for k=i,i+1,…,j. Generalizing the ⌈100u⌉ trick of §4.2.1:
Generate u∼U(0,1).
Return X=i+⌊(j−i+1)u⌋.
Here ⌊x⌋ is the largest integer ≤x. The product (j−i+1)u is uniform on [0,j−i+1); its floor is uniform on {0,1,…,j−i}; adding i shifts to {i,…,j}. (The floor form is slightly safer than the ceiling form when u can be exactly 0.)
Geometric(p).p(k)=(1−p)k−1p, k=1,2,… — the number of trials up to and including the first success. Instead of simulating the trials (§4.2.5), invert the c.d.f. in closed form. The inverse-transform intervals are
0<u≤p⇒X=1,p<u≤p+(1−p)p⇒X=2,…
and in general X=k when
i=1∑k−1(1−p)i−1p<u≤i=1∑k(1−p)i−1p.
Each side is a geometric series: ∑i=1k(1−p)i−1p=p1−(1−p)1−(1−p)k=1−(1−p)k. So the condition is
1−(1−p)k−1<u≤1−(1−p)k⟺(1−p)k≤1−u<(1−p)k−1.
Take logarithms. Since 0<1−p<1, ln(1−p)<0, so the inequalities flip:
kln(1−p)≤ln(1−u)<(k−1)ln(1−p),
and dividing by the negative number ln(1−p) flips them back:
k≥ln(1−p)ln(1−u)>k−1.
The integer k sitting just above ln(1−p)ln(1−u) is its ceiling. Finally replace 1−u by u (same distribution):
Generate u∼U(0,1).
Return X=⌈ln(1−p)lnu⌉.
One uniform and one logarithm, regardless of p — compare 1/p uniforms for the trial-by-trial method. The formula is the discrete twin of the exponential’s −λ1lnu: the geometric is the exponential’s discrete analogue (it has the same memoryless property), and the generators have the same shape.
Arbitrary discrete distribution.X∈{0,1,…,n} with P(X=i)=p(i). Inverse transform:
Generate u∼U(0,1).
Return X=i for the i with j=0∑i−1p(j)≤u<j=0∑ip(j).
This is the search of §4.2.1; for large n it is slow, and the first improvement is to test the values in decreasing order of p(i). The two methods below go further.
4.4.1. Table lookup
Idea. If all probabilities are given to q decimal places, then each p(i) is a whole number of units of size 10−q. Build a vector m of length 10q in which value i appears 10qp(i) times. Picking a uniformly random entry of m then returns i with exactly the right probability — no search at all.
Example.P(0)=0.15, P(1)=0.20, P(2)=0.37, P(3)=0.28, so q=2. Construct m of length 100:
m=[150,…,0,201,…,1,372,…,2,283,…,3].
Generate J∼DU(1,100), i.e. J=1+⌊100u⌋.
Return X=mJ.
Check: P(X=2)=P(J lands on one of the 37 entries equal to 2)=37/100. ✓
Simple and very fast (one uniform, one index), but it needs setup and 10q storage locations — q=6 already means a million entries.
4.4.2. Improved table lookup
Idea. Split each probability by decimal digit and keep one table per digit. Same example:
i
p(i)
tenths digit
hundredths digit
0
0.15
1
5
1
0.20
2
0
2
0.37
3
7
3
0.28
2
8
sum
8
20
Build one table from the tenths digits (value i appears “tenths digit” times) and one from the hundredths digits:
Total storage 8+20=28 instead of 100. (Value 1 is absent from m(2) because its hundredths digit is 0.)
The tenths table carries total mass 8/10=0.8 and the hundredths table carries 20/100=0.2. So:
Generate u∼U(0,1).
If u≤0.8, generate J1∼DU(1,8) and return X=mJ1(1).
Otherwise generate J2∼DU(1,20) and return X=mJ2(2).
Check: P(X=2)=P(X=2∣table 1)P(table 1)+P(X=2∣table 2)P(table 2)=83⋅108+207⋅102=0.30+0.07=0.37. ✓ The two terms are exactly the tenths and hundredths parts of 0.37.
This is composition (§4.2.2) in disguise: p=0.8p(1)+0.2p(2), where p(j) is the uniform-pick distribution on table j. It costs two uniforms per variate instead of one, in exchange for far less storage when q is large.
4.4.3. The alias method
The alias method keeps table lookup’s speed — one uniform-pick plus one comparison — with only 2(n+1) storage locations, whatever the precision of the probabilities.
Setup. Two vectors of length n+1:
cutoff valuesF0,F1,…,Fn∈[0,1],
aliasesL0,L1,…,Ln∈{0,1,…,n}.
Algorithm.
Generate I∼DU(0,n) and u∼U(0,1) independently.
If u≤FI, return X=I; otherwise return X=LI.
How to read it. Each value I is drawn with probability n+11 — an equal-size “column”. Inside column I, a fraction FI of the column belongs to I itself and the remaining 1−FI belongs to one other value, its alias LI. So
P(X=k)=n+11[Fk+i:Li=k∑(1−Fi)]:
k’s own share of its column, plus whatever the other columns hand to it as an alias. The setup consists of choosing F and L so that this equals p(k) for every k.
It resembles acceptance–rejection (draw a candidate, compare u to a threshold), with one crucial difference: on “rejection” we do not start over — we return the alias. There is no loop, so exactly one I and one u are consumed per variate.
Setup for the examplep=(0.15,0.20,0.37,0.28), n+1=4. Scale by n+1: q=4p=(0.60,0.80,1.48,1.12). Each column has capacity 1; values with qi<1 have spare room, values with qi>1 have excess. Repeatedly fill a “small” column from a “large” one:
step
small column i
gets Fi=qi
alias Li
donor’s remaining q
1
0 (0.60)
0.60
2
q2=1.48−0.40=1.08
2
1 (0.80)
0.80
2
q2=1.08−0.20=0.88
3
2 (0.88)
0.88
3
q3=1.12−0.12=1.00
4
3 (1.00)
1.00
— (never used)
Result: F=(0.60,0.80,0.88,1.00), L=(2,2,3,3).
Check: P(X=2)=41[0.88+(1−0.60)+(1−0.80)]=41(1.48)=0.37 ✓, and P(X=3)=41[1.00+(1−0.88)]=41(1.12)=0.28 ✓. (The table is not unique — a different pairing order gives different valid F,L.)
Assessment. Very fast once set up; drawbacks are the setup computation and the 2(n+1) storage locations. For a fixed discrete distribution sampled millions of times, it is the method of choice.
Summary of the discrete methods.
method
uniforms / variate
time per variate
storage
setup
inverse transform
1
up to n comparisons
n+1
sort (optional)
table lookup
1
O(1)
10q
build table
improved table lookup
2
O(1)
sum of digits
build tables
alias
2 (or 1 split in two)
O(1)
2(n+1)
build F,L
4.5. Generating Random Vectors
Why a separate section. Everything so far produces one random variable at a time, and successive variates are independent. Many inputs come in correlated groups: a job’s processing times at two consecutive stations, a customer’s order size and service time, daily demands for related products. Generating each coordinate on its own throws the correlation away. We need a way to produce a whole vector X=(X1,…,Xd)T with a prescribed mean and a prescribed dependence structure.
so Σ is d×d with entries Σij=cov(Xi,Xj) — variances on the diagonal, covariances off it (§2.3). Two facts about Σ that the construction below relies on:
Σ is symmetric, since cov(Xi,Xj)=cov(Xj,Xi).
Σ is positive semidefinite: for any constant vector a, aTΣa=Var(aTX)≥0. A variance cannot be negative.
Linear transformations. If Y=b+AX for a constant vector b and constant matrix A, then
E[Y]=b+Aμ,cov(Y)=AΣAT.
(The second follows from Y−E[Y]=A(X−μ), so cov(Y)=E[A(X−μ)(X−μ)TAT]=AΣAT.) This is the whole trick: we can manufacture any covariance we like by applying a matrix to something simple.
4.5.2. The multivariate normal distribution
X∼Nd(μ,Σ) is the d-dimensional normal with mean vector μ and covariance matrix Σ. Its one property we need: a linear transformation of a multivariate normal is again multivariate normal. Combined with the formulas above, if X∼Nd(μ,Σ) then b+AX∼N(b+Aμ,AΣAT).
The simplest member of the family is the standard one. Let Z1,…,Zd be i.i.d. N(0,1) (§4.3.1) and Z=(Z1,…,Zd)T. Then E[Z]=0 and cov(Z)=Id (variances 1, covariances 0 by independence), so Z∼Nd(0,Id).
The plan. Take X=μ+AZ. Then X is multivariate normal with
E[X]=μ,cov(X)=AIAT=AAT.
So all we need is a matrix A with
AAT=Σ,
a “square root” of Σ. There are two standard ways to get one; the lecture uses the second.
Cholesky factorization. Any symmetric positive-definite Σ can be written Σ=LLT with L lower-triangular. Take A=L. Cheap to compute (O(d3/3)) and what most software does.
Eigenvalue (spectral) decomposition — next.
4.5.3. Eigenvalue decomposition
Definitions. For a d×d matrix Σ, if a constant λ and a non-zero vector v satisfy
Σv=λv,
then λ is an eigenvalue of Σ and v a corresponding eigenvector. (Geometrically: Σ merely stretches v by the factor λ without turning it.)
Facts for a real symmetric matrix (spectral theorem):
It has d linearly independent eigenvectors, which can be chosen orthogonal and of unit length: v1,…,vd with viTvj=0 for i=j and ∥vi∥=1.
Put them side by side in P=[v1v2⋯vd]. Orthonormal columns mean PTP=I, i.e. P−1=PT — the inverse is free.
With Λ=diag(λ1,…,λd),
Σ=PΛPT.
Because Σ is positive semidefinite, every λi≥0 (λi=viTΣvi≥0), so Λ1/2=diag(λ1,…,λd) is a real matrix with Λ1/2Λ1/2=Λ.
The square root. Take A=PΛ1/2. Then
AAT=PΛ1/2(PΛ1/2)T=PΛ1/2Λ1/2PT=PΛPT=Σ.✓
(We used (Λ1/2)T=Λ1/2 since it is diagonal.)
Verification, step by step. Let Z=(Z1,…,Zd)T with Zi i.i.d. N(0,1) and define
X=μ+PΛ1/2Z.
Mean: E[X]=μ+PΛ1/2E[Z]=μ+0=μ.
Covariance:
cov(X)=E[(X−μ)(X−μ)T]=E[PΛ1/2ZZTΛ1/2PT]=PΛ1/2E[ZZT]Λ1/2PT=PΛ1/2IΛ1/2PT=PΛPT=Σ.(X−μ=PΛ1/2Z;(ABC)T=CTBTAT)(constants come out of the expectation)(E[ZiZj]=1 if i=j,0 otherwise)
And X is normal because each coordinate is a linear combination of the independent normals Z1,…,Zd plus a constant.
Algorithm (multivariate normal via eigen decomposition).
Setup (once): compute the eigenvalues λi and orthonormal eigenvectors vi of Σ; form P and Λ1/2; store A=PΛ1/2.
Generate Z1,…,Zd i.i.d. N(0,1) (Box–Muller or polar method, §4.3).
Return X=μ+PΛ1/2Z.
One matrix–vector multiplication per vector; the expensive part (the decomposition) is paid once.
Example (d=2). Two correlated standard normals with correlation ρ:
μ=(μ1μ2),Σ=(1ρρ1).
Eigenvalues and eigenvectors (check by multiplying out):
Σ(11)=(1+ρ)(11),Σ(1−1)=(1−ρ)(1−1),
so λ1=1+ρ, λ2=1−ρ (both ≥0 since ∣ρ∣≤1), and after normalizing to unit length,
Check: Var(X1)=2(1+ρ)+(1−ρ)=1, and cov(X1,X2)=2(1+ρ)−(1−ρ)=ρ. ✓
The same Σ by Cholesky.L=(1ρ01−ρ2) satisfies LLT=Σ, giving
X1=μ1+Z1,X2=μ2+ρZ1+1−ρ2Z2.
Different formulas, same distribution — both are valid square roots of Σ. (For general variances σ12,σ22: X1=μ1+σ1Z1, X2=μ2+σ2(ρZ1+1−ρ2Z2).) The Cholesky form shows the mechanism plainly: X2 borrows a share ρ of X1’s noise and tops up with fresh noise so that its variance is still 1.
Remarks.
The Zimust be independent — this is where the quality of the normal generator (§4.3.1’s spiral warning) matters doubly.
The construction only controls the first two moments. For a non-normal vector with prescribed marginals and correlation, transforming Z by a matrix destroys the marginals; one then uses Z only to carry the dependence and maps each coordinate through Fi−1(Φ(⋅)) (the “NORTA” idea). Beyond the scope of this course.
4.6. Generating Stochastic Processes
A stochastic process (§2.5) is a whole family of random variables indexed by time. Generating one means generating a sample path. The workhorse is the Poisson process — the arrival process of almost every queueing model — and its time-varying generalization.
4.6.1. The Poisson process
Counting process. Let Sn be the time of the n-th event (the n-th arrival time), with S0=0, and let
Xn=Sn−Sn−1
be the n-th interarrival time, so Sn=∑i=1nXi. Define
N(t)=max{n:Sn≤t}=number of events that have occurred up to time t.
{N(t):t≥0} is a counting process: it starts at 0, is integer-valued, non-decreasing, and jumps by 1 at each Sn.
Definition. If the interarrival times X1,X2,… are i.i.d. Exp(λ), then {N(t)} is called a Poisson process with rate λ, written PP(λ).
Properties of PP(λ).
Poisson counts. For every t,
P(N(t)=k)=e−λtk!(λt)k,k=0,1,2,…,
i.e. N(t)∼Poisson(λt), so E[N(t)]=λt. Hence λ=E[N(t)]/t: the rate (or arrival rate) is the expected number of events per unit time. More generally the number of events in any interval of length s is Poisson(λs), and counts in disjoint intervals are independent. (This is the Erlang formula of §4.2.3 read the other way: P(N(t)≥n)=P(Sn≤t).)
Arrival-time theorem. Given that N(t)=k, the k arrival times (S1,…,Sk) are distributed as the order statistics of k i.i.d. U(0,t) random variables. That is: take U1,…,Uk i.i.d. U(0,t), sort them into ascending order Uˉ(1)<Uˉ(2)<⋯<Uˉ(k); then (S1,…,Sk) has the same joint distribution as (Uˉ(1),…,Uˉ(k)). In words: given how many events occurred, they are scattered uniformly and independently over the interval — the Poisson process has no preferred times.
Bernoulli splitting. Let {N(t)} be PP(λ) and fix probabilities p1,…,pr>0 with ∑j=1rpj=1. Assign each arrival, independently of everything else, to category i with probability pi, and let Ni(t) count the category-i arrivals, so N(t)=N1(t)+⋯+Nr(t).
Theorem. Under Bernoulli splitting the r processes {N1(t)},…,{Nr(t)} are independent Poisson processes, with {Ni(t)}∼PP(λpi).
The case r=2, with probabilities p and 1−p, is the one we will use: the arrivals that pass a coin toss form PP(λp), those that fail form PP(λ(1−p)), and the two streams are independent of each other. (The independence is the surprising part: knowing many arrivals went to stream 1 tells you nothing about stream 2.)
4.6.2. The nonhomogeneous Poisson process
Motivation: traffic on a highway. A PP(λ) has one constant rate for all time. Real arrival rates vary:
A single λ would average the rush hours and the quiet hours together and get both wrong. We need a process whose rate is a function of time.
Definition. A counting process {N(t)} is a nonhomogeneous Poisson process (NPP) with rate functionλ(t)≥0 if
N(0)=0;
{N(t)} has independent increments: counts in disjoint time intervals are independent;
in a short window (t,t+h],
P(N(t+h)=k∣N(t)=k)P(N(t+h)=k+1∣N(t)=k)P(N(t+h)=k+j∣N(t)=k)=1−λ(t)h+o(h)=λ(t)h+o(h)=o(h),j≥2(no event)(exactly one event)(two or more events)
Here o(h) means a quantity that vanishes faster than h as h→0. In words: over a very short interval almost surely either 0 or 1 event happens, and the chance of 1 event is proportional to the length of the interval with proportionality constant λ(t) — the current value of the rate.
Counts. Define the mean-value functionm(t)=∫0tλ(s)ds. Then
P(N(t)=k)=e−m(t)k!m(t)k,k=0,1,2,…,
so N(t)∼Poisson(m(t)) and E[N(t)]=∫0tλ(s)ds — the area under the rate curve. More generally N(t+s)−N(t)∼Poisson(∫tt+sλ(u)du). With a constant rate λ(t)≡λ we get m(t)=λt and recover PP(λ): the NPP is the generalization.
Nonhomogeneous Bernoulli splitting. Now let the coin be biased by time: fix a function p(t):[0,∞)→[0,1] and assign an arrival occurring at time t to stream 1 with probability p(t), to stream 2 with probability 1−p(t).
Theorem. If {N(t)}∼PP(λ) is split with time-dependent probability p(t), then {N1(t)} and {N2(t)} are independent nonhomogeneous Poisson processes with rate functions λp(t) and λ(1−p(t)):
(The same holds if the parent process is itself an NPP with rate λ(t): the pieces are NPPs with rates λ(t)p(t) and λ(t)(1−p(t)).) Thinning out a Poisson stream with a time-varying coin produces exactly an NPP — this is the key to generating one.
4.6.3. Generating a Poisson process on [0,T]
Approach 1: lay down the interarrival times. Since the gaps are i.i.d. Exp(λ), generate them one at a time by inverse transform and accumulate. Set s0=0, i=0.
Generate u∼U(0,1).
Set si+1=si−λ1lnu(previous arrival plus an Exp(λ) gap).
Set i=i+1.
If si≤T, go back to step 1; otherwise stop. The arrival times are s1,…,si−1 and N(T)=i−1.
The last generated time, the one that overshoots T, is discarded; it only serves to tell us we are done. This is the natural method inside a discrete-event simulation, where the next arrival is scheduled as soon as the current one occurs.
Approach 2: use the arrival-time theorem. Decide the count first, then place the points.
Generate N(T)∼Poisson(λT) (a discrete variate — inverse transform with the p.m.f. computed recursively, p(k+1)=p(k)⋅λT/(k+1)).
Generate u1,…,uN(T) i.i.d. U(0,T).
Sort them; return uˉ(1)<uˉ(2)<⋯<uˉ(N(T)) as the arrival times s1,…,sN(T).
By property 2 the output has exactly the distribution of a PP(λ) path on [0,T]. This approach generates the whole path at once (convenient for vectorized code) at the cost of a sort.
4.6.4. Generating a nonhomogeneous Poisson process
A tempting but wrong method. Mimic Approach 1 with the current rate: having generated ti−1, draw the next gap from Exp(λ(ti−1)),
ti=ti−1−λ(ti−1)1lnu.
This uses the rate at the previous arrival for the entire gap, as if the rate stayed frozen until the next event. It does not: the rate may rise steeply right after ti−1.
If λ(ti−1) happens to be small, the gap has mean 1/λ(ti−1), which is large, and the process can jump clean over a high-rate period in which many arrivals should have occurred. In a test with a rate function that dips to 0.25 and then peaks at 3.25, this method produced on average 3.9 arrivals on [0,10] where the true mean is 7.3, and only 1.5 arrivals in the rush-hour window where there should be 4.9. So this is not a correct way.
The correct way: the thinning method. Generate too many candidate arrivals from a homogeneous Poisson process whose rate is at least as large as λ(t) everywhere, then keep each candidate at time t with probability λ(t)/λ∗. Let
λ∗=0≤t≤Tmaxλ(t).
Algorithm (thinning), to generate ti given ti−1:
Set t=ti−1.
Generate u1⊥u2∼U(0,1).
Set t=t−λ∗1lnu1(advance by an Exp(λ∗) gap: the next candidate).
If u2≤λ∗λ(t), accept: set ti=t. Otherwise go back to step 2 and try again (keeping the advanced t).
Repeat until t>T.
How to understand the algorithm. It is nonhomogeneous Bernoulli splitting run deliberately. The candidate times produced by steps 2–3 form a homogeneous PP(λ∗) — that is just Approach 1 with rate λ∗. Step 4 then assigns each candidate at time t to one of two streams with a time-dependent coin:
N1(t)=number of candidates accepted by time t,N2(t)=number rejected,p(t)=λ∗λ(t).
By the splitting theorem, {N1(t)} is a nonhomogeneous Poisson process with rate function
λ∗⋅p(t)=λ∗⋅λ∗λ(t)=λ(t),
exactly the target. (The rejected stream is an NPP with rate λ∗−λ(t), independent of the accepted one — we simply throw it away.) Note that p(t)≤1 precisely because λ∗ was chosen as the maximum of λ; that is the only role λ∗ plays. The analogy with acceptance–rejection (§4.2.4) is exact: λ∗ is a flat majorizing function for λ(t), and λ(t)/λ∗ is the acceptance probability.
Checks. In the same test as above, thinning gave 7.29 arrivals on average against the true 7.32, and 4.89 in the rush-hour window against 4.88.
Efficiency. The expected fraction of candidates accepted is
λ∗T∫0Tλ(t)dt=area of the rectanglearea under λ,
the same picture as the AR efficiency 1/c. If λ(t) has a sharp peak, λ∗ is large and most candidates are rejected during the quiet periods. The standard fix is the AR fix: use a piecewise constantλ∗ — split [0,T] into subintervals, each with its own local maximum — so the majorizing rectangle hugs the curve.
4.7. Example - generating the inputs of the inventory system
The inventory model of §1.3 needs three kinds of random input. Each one is generated from U(0,1) random numbers with a method of this chapter.
input
distribution
method
formula
time between demands
Exp with mean 0.1 month
inverse transform (§4.2.1)
X=−0.1lnu
demand size
D∈{1,2,3,4} w.p. 61,31,31,61
discrete inverse transform (§4.2.1)
compare u with 61,21,65
order lead time
U(0.5,1)
inverse transform (§4.3)
L=0.5+0.5u
4.7.1. Time between demands
The mean is 1/λ=0.1 month, so λ=10 per month and F(x)=1−e−10x, x≥0. Set u=F(x) and solve:
u=1−e−10x⟹e−10x=1−u⟹x=−0.1ln(1−u).
Since 1−u∼U(0,1) as well:
Generate u∼U(0,1).
Return X=−0.1lnu.
(If the RNG can return u=0, use −0.1ln(1−u) instead; see §4.2.1.)
4.7.2. Demand size
The c.d.f. is a staircase:
d
1
2
3
4
p(d)
1/6
1/3
1/3
1/6
F(d)
1/6
1/2
5/6
1
Discrete inverse transform: return the smallest d with u≤F(d).
Generate u∼U(0,1).
If u≤1/6, return D=1; else if u≤1/2, return D=2; else if u≤5/6, return D=3; else return D=4.
The cut points 1/6,1/2,5/6 split (0,1] into four intervals whose widths are the probabilities, and u falls into exactly one of them:
Alternative: table lookup (§4.4.1). All the probabilities are multiples of 1/6, so store
m=[1,2,2,3,3,4]
(value d appears 6p(d) times), generate J=1+⌊6u⌋, and return D=mJ. Check: P(D=2)=P(J∈{2,3})=2/6=1/3. Because m is sorted, this returns the same D as the search for every u (up to the boundary points), just without any comparisons.
4.7.3. Order lead time
For U(0.5,1), F(x)=0.5x−0.5 on [0.5,1]. Set u=F(x):
u=0.5x−0.5⟹x=0.5+0.5u,
which is the formula a+(b−a)u of §4.3.
Generate u∼U(0,1).
Return L=0.5+0.5u.
4.7.4. Worked example
Suppose the generator gives the following random numbers:
input
u
variate
time to demand 1
0.81
−0.1ln0.81=0.021 month
size of demand 1
0.55
21<0.55≤65⇒D=3
time to demand 2
0.17
−0.1ln0.17=0.177 month
size of demand 2
0.12
0.12≤61⇒D=1
lead time
0.30
0.5+0.5⋅0.30=0.65 month
Starting from I(0)=60: the first demand comes at t=0.021 and takes 3 items (I=57); the second comes at t=0.021+0.177=0.198 and takes 1 item (I=56). If an order is placed at the review at t=1, with this lead time it arrives at t=1.65.
4.7.5. When each input is generated during the simulation
Demand at time t: generate the size D and set I←I−D; generate the next interdemand time X and schedule the next demand at t+X.
Inventory evaluation (beginning of each month): if I<s, order Z=S−I, generate the lead time L, and schedule the order arrival at t+L. If I≥s, nothing is generated.
Order arrival and end of simulation: no random input.
At t=0, generate the first interdemand time to schedule the first demand.
4.7.6. Use a separate stream for each input
Following §3.3 (practical issue 3), take interdemand times, demand sizes and lead times from three different streams. The reason is concrete here: how many lead times are consumed depends on the policy (s,S), since a policy that orders more often uses more of them. With one shared stream, those extra draws would shift every later demand, and two policies would face different demand sequences. With separate streams, every (s,S) pair sees exactly the same demands (common random numbers, §4.2.1 advantage 4), so the difference in average cost reflects the policies rather than luck.