Algorithm 2.1 Invert Multi-outcome Discrete Density

N = 4 # number of outcomes
oc = [2,3,4,5] # list the outcomes, 2 through 5 eggs
op = [0.15,0.2,0.6,0.05] # list of outcome probabilities
bp = [0]*N # set up the breakpoints
bp[0]=op[0]
for i in range(1,N):
   bp[i] = bp[i-1] + op[i]
# end of set up, go here to get samples
U=random.random(); k=0;
while( U >= bp[k]):
   k=k+1;
selected = oc[k]
print(selected)


Algorithm 2.2 Roulette Wheel Selection

import random
N = 4
tabLen = 100
oc = [2,3,4,5]
op = [0.15,0.2,0.6,0.05] # event probabilities
op =[int(op[i]*tabLen) for i in range(len(op))] # 15,20,60,5
 # set up: assign fractions of 100 according to the probabilities
rv = []  # for return values
for i in range(len(op)):
    for j in range(op[i]):
      rv.append(oc[i])
 # end of setup, go here to get samples
k = random.randint(0,99) # rv[k] is selected
selected = rv[k]

Algorithm 2.3 Vector Algorithm for Discrete Selection

import random
op = [0.15,0.2,0.6,0.05]}
bp = []
bp.append(op[0])
for i in range(1,len(op)):
  bp.append(bp[i-1]+op[i])
N = 10000
u = np.random.rand(N) # N vector of samples from U(0,1)
w2 = (u < bp[0])*2  # 2's where true
a = np.array(u>=bp[0]) # working arrays needed
b = np.array(u< bp[1])  # for the and operation
w3 = (a & b)*3  # 3's where true
a = np.array(u>=bp[1])
b = np.array(u< bp[2])
w4 = (a & b)*4  # 4's where true
w5 = (u>=bp[2])*5 # 5's where true
w = w2+w3+w4+w5 # 10000 vector with the right frequencies


Algorithm 2.4 Walker Construction Algorithm

import numpy as np
import matplotlib.pyplot as plt

def firstUnder(arr): #but greater than 0
  k=0
  while( True ):
    if( arr[k] == 0 or arr[k] > S ):
      k += 1
    else:
      break;
  return k

def firstOver(arr):
  k = 0
  while( True ):
    if( arr[k] < S):
      k += 1
    else:
      break;
  return k

def reset(idx,ind):
  Q[idx] = tab[idx]
  tab[idx] = 0
  resid = S - Q[idx]
  A[idx] = ind
  tab[ind] -= resid

### mmm ###
#rw = [.3,.4,.1,.2]
rw = [.02,.04,0.08,.15,.2,.21,.16,.09,.05];
M = len(rw)
tab = [0]*M
for i in range(M):
  tab[i] = rw[i]

Q = [0]*M
A = [0]*M
S = 1.0/M

for i in range(M-1):
  t = firstUnder(tab) #take from this sector
  p = firstOver(tab)  #put the residual here
  reset(t,p)

#last
t = 0; max = 0;
for i in range(M):
  if( tab[i] > max):
    max = tab[i];
    t = i
Q[t] = tab[t]


#print("Q-pre",Q)
for i in range(len(Q)):
  Q[i] *= len(Q)
print("Q: ",end="")
for i in range(len(Q)):
  print(str(round(Q[i],3))+" ",end="")
print("")
print("A: ",A)


Algorithm 2.5 Poisson Sampling

import numpy as np
import random
import matplotlib.pyplot as plt

def poissonSample(targ):
  u = 1; x = 0
  while( u > targ):
    last = x
    u *= random.random()
    #print("u now "+str(u)+", last now "+str(last))
    x += 1
  return last

lam = 0.1 # event rate per minute, lambda is a reserved word
t = 30  # number of minutes
targ = np.exp(-lam*t)
 # get a sample
X = poissonSample(targ)
print(X)


Algorithm 2.6 Rational Approximation to the Normal CDF

import numpy as np
import random
import matplotlib.pyplot as plt

# Abramowitz and Stegun
def normalCDF(x):
  a1 = 0.31938153; a2 = -0.356563782;
  a3 = 1.781477937; a4 = -1.821255978;
  a5 = 1.330274429; b=0.2316410; c=1/np.sqrt(2*np.pi)
  L=abs(x); K=1/(1+b*L);
  w = 1-c*np.exp(-L*L/2)*K*(a1+K*(a2+K*(a3+K*(a4+a5*K))));
  msign = -(x<0); mfact = 2*msign+1;
  w = mfact*(w+msign)
  return w
x = 1
print(normalCDF(x))


Algorithm 2.7 Gilbrat's Approximation Example

import numpy as np
import random
import matplotlib.pyplot as plt

a = 0.2; b=2.0; n=10
c = b-a
alfa = (n/c)*(b*(np.log(b)-1)-a*(np.log(a)-1))
beta2 = (n/c)*(b*(np.log(b)*np.log(b)-2*np.log(b)+2)-\
a*(np.log(a)*np.log(a)-2*np.log(a)+2))-alfa**2
beta = np.sqrt(beta2)

nReps = 2000000
X = np.zeros(nReps)
for i in range(nReps):
  R = 1;
  for j in range(n):
    r = a + c*random.random()
    R *= r
  X[i] = R

## generate the normal samples using alfa and beta
logXexact = beta*np.random.randn(nReps)+alfa

# do the lognormal
Xexact = np.exp(logXexact)
xmin = 0; xmax = 200

fig = plt.figure()
ax = plt.subplot(111)
ax.hist(Xexact, bins=200, density=True, log = True, \
range = [0,xmax],label="exact lognormal")
plt.hist(X, bins=200, density=True, log = True, \
range = [0,xmax],label="product random variable")
ax.legend()
x = np.linspace(xmin,xmax)
y = (1/(x*beta*np.sqrt(2*np.pi)))*\
np.exp(-(np.log(x)-alfa)**2/(2*beta*beta))
ax.plot(x, y, 'k', linewidth=1) # plot in black
plt.xlabel("X")
plt.ylabel("probability density")

title = "Lognormal Histogram Comparison, alpha= {:.2f}, beta= {:.2f}".\
format(alfa, beta)
plt.title(title)
plt.show()
fig.savefig('lognormal_comparisonDisp.png')


Algorithm 2.8 Joint Sampling Over a Triangle

mport numpy as np
import matplotlib.pyplot as plt

x = [0,0,1,0]
y = [0,1,0,0]
plt.plot(x,y)

for i in range(200):
  u1 = np.sqrt(np.random.uniform())
  u2 = np.random.uniform()
  x = 1-u1
  y = u2*u1
  plt.scatter(x,y,color='black',s=8)

plt.text(0.40,0.67, "y=1-x", fontsize=12)
plt.title("200 points uniformly over a triangle")
plt.hlines(0.685,0.322,0.39)
#plt.savefig("uniformovertrianglefig.png")
plt.show()