!pip install quantecon import matplotlib.pyplot as plt plt.rcParams["figure.figsize"] = (11, 5) #set default figure size import quantecon as qe import numpy as np from mpl_toolkits.mplot3d import Axes3D ψ = (0.3, 0.7) # probabilities over {0, 1} cdf = np.cumsum(ψ) # convert into cummulative distribution qe.random.draw(cdf, 5) # generate 5 independent draws from ψ def mc_sample_path(P, ψ_0=None, sample_size=1_000): # set up P = np.asarray(P) X = np.empty(sample_size, dtype=int) # Convert each row of P into a cdf n = len(P) P_dist = [np.cumsum(P[i, :]) for i in range(n)] # draw initial state, defaulting to 0 if ψ_0 is not None: X_0 = qe.random.draw(np.cumsum(ψ_0)) else: X_0 = 0 # simulate X[0] = X_0 for t in range(sample_size - 1): X[t+1] = qe.random.draw(P_dist[X[t]]) return X P = [[0.4, 0.6], [0.2, 0.8]] X = mc_sample_path(P, ψ_0=[0.1, 0.9], sample_size=100_000) np.mean(X == 0) from quantecon import MarkovChain mc = qe.MarkovChain(P) X = mc.simulate(ts_length=1_000_000) np.mean(X == 0) %time mc_sample_path(P, sample_size=1_000_000) # Our homemade code version %time mc.simulate(ts_length=1_000_000) # qe code version mc = qe.MarkovChain(P, state_values=('unemployed', 'employed')) mc.simulate(ts_length=4, init='employed') mc.simulate(ts_length=4, init='unemployed') mc.simulate(ts_length=4) # Start at randomly chosen initial state mc.simulate_indices(ts_length=4) P = [[0.9, 0.1, 0.0], [0.4, 0.4, 0.2], [0.1, 0.1, 0.8]] mc = qe.MarkovChain(P, ('poor', 'middle', 'rich')) mc.is_irreducible P = [[1.0, 0.0, 0.0], [0.1, 0.8, 0.1], [0.0, 0.2, 0.8]] mc = qe.MarkovChain(P, ('poor', 'middle', 'rich')) mc.is_irreducible mc.communication_classes P = [[0, 1, 0], [0, 0, 1], [1, 0, 0]] mc = qe.MarkovChain(P) mc.period P = [[0.0, 1.0, 0.0, 0.0], [0.5, 0.0, 0.5, 0.0], [0.0, 0.5, 0.0, 0.5], [0.0, 0.0, 1.0, 0.0]] mc = qe.MarkovChain(P) mc.period mc.is_aperiodic P = np.array([[0.4, 0.6], [0.2, 0.8]]) ψ = (0.25, 0.75) ψ @ P P = [[0.4, 0.6], [0.2, 0.8]] mc = qe.MarkovChain(P) mc.stationary_distributions # Show all stationary distributions P = ((0.971, 0.029, 0.000), (0.145, 0.778, 0.077), (0.000, 0.508, 0.492)) P = np.array(P) ψ = (0.0, 0.2, 0.8) # Initial condition fig = plt.figure(figsize=(8, 6)) ax = fig.add_subplot(111, projection='3d') ax.set(xlim=(0, 1), ylim=(0, 1), zlim=(0, 1), xticks=(0.25, 0.5, 0.75), yticks=(0.25, 0.5, 0.75), zticks=(0.25, 0.5, 0.75)) x_vals, y_vals, z_vals = [], [], [] for t in range(20): x_vals.append(ψ[0]) y_vals.append(ψ[1]) z_vals.append(ψ[2]) ψ = ψ @ P ax.scatter(x_vals, y_vals, z_vals, c='r', s=60) ax.view_init(30, 210) mc = qe.MarkovChain(P) ψ_star = mc.stationary_distributions[0] ax.scatter(ψ_star[0], ψ_star[1], ψ_star[2], c='k', s=60) plt.show() α = β = 0.1 N = 10000 p = β / (α + β) P = ((1 - α, α), # Careful: P and p are distinct ( β, 1 - β)) mc = MarkovChain(P) fig, ax = plt.subplots(figsize=(9, 6)) ax.set_ylim(-0.25, 0.25) ax.grid() ax.hlines(0, 0, N, lw=2, alpha=0.6) # Horizonal line at zero for x0, col in ((0, 'blue'), (1, 'green')): # Generate time series for worker that starts at x0 X = mc.simulate(N, init=x0) # Compute fraction of time spent unemployed, for each n X_bar = (X == 0).cumsum() / (1 + np.arange(N, dtype=float)) # Plot ax.fill_between(range(N), np.zeros(N), X_bar - p, color=col, alpha=0.1) ax.plot(X_bar - p, color=col, label=f'$X_0 = \, {x0} $') # Overlay in black--make lines clearer ax.plot(X_bar - p, 'k-', alpha=0.6) ax.legend(loc='upper right') plt.show() %%file web_graph_data.txt a -> d; a -> f; b -> j; b -> k; b -> m; c -> c; c -> g; c -> j; c -> m; d -> f; d -> h; d -> k; e -> d; e -> h; e -> l; f -> a; f -> b; f -> j; f -> l; g -> b; g -> j; h -> d; h -> g; h -> l; h -> m; i -> g; i -> h; i -> n; j -> e; j -> i; j -> k; k -> n; l -> m; m -> g; n -> c; n -> j; n -> m; import re re.findall('\w', 'x +++ y ****** z') # \w matches alphanumerics re.findall('\w', 'a ^^ b &&& $$ c') """ Return list of pages, ordered by rank """ import re from operator import itemgetter infile = 'web_graph_data.txt' alphabet = 'abcdefghijklmnopqrstuvwxyz' n = 14 # Total number of web pages (nodes) # Create a matrix Q indicating existence of links # * Q[i, j] = 1 if there is a link from i to j # * Q[i, j] = 0 otherwise Q = np.zeros((n, n), dtype=int) with open(infile) as f: edges = f.readlines() for edge in edges: from_node, to_node = re.findall('\w', edge) i, j = alphabet.index(from_node), alphabet.index(to_node) Q[i, j] = 1 # Create the corresponding Markov matrix P P = np.empty((n, n)) for i in range(n): P[i, :] = Q[i, :] / Q[i, :].sum() mc = MarkovChain(P) # Compute the stationary distribution r r = mc.stationary_distributions[0] ranked_pages = {alphabet[i] : r[i] for i in range(n)} # Print solution, sorted from highest to lowest rank print('Rankings\n ***') for name, rank in sorted(ranked_pages.items(), key=itemgetter(1), reverse=1): print(f'{name}: {rank:.4}')