|
3 | 3 |
|
4 | 4 | Functions
|
5 | 5 | ---------
|
6 |
| - mc_compute_stationary [Status: 1 x Simple Test Written] |
7 |
| - mc_sample_path [Status: TBD] |
| 6 | + mc_compute_stationary [Status: 1 x Simple Test Written] |
| 7 | + mc_sample_path [Status: TBD] |
8 | 8 |
|
9 |
| -Notes |
10 |
| ------ |
11 |
| -[1] There is currently a section in this test file which contains the examples used for the Wiki Page: "Testing: Writing Tests" |
12 |
| - (Marked Below). This is technically running 3 x of the Same Tests |
13 | 9 | """
|
14 | 10 |
|
15 | 11 | from __future__ import division
|
|
18 | 14 | import unittest
|
19 | 15 | from numpy.testing import assert_allclose
|
20 | 16 |
|
21 |
| -from ..mc_tools import mc_compute_stationary |
22 |
| - |
23 |
| -### Tests: mc_compute_stationary ### |
24 |
| - |
25 |
| -def test_mc_compute_stationary_pmatrices(): |
26 |
| - """ |
27 |
| - Test mc_compute_stationary with P Matrix and Known Solutions |
28 |
| - """ |
29 |
| - |
30 |
| - #-P Matrix-# , #-Known Solution-# |
31 |
| - testset = [ |
32 |
| - ( np.array([[0.4,0.6], [0.2,0.8]]) , np.array([0.25, 0.75]) ), |
33 |
| - ] |
34 |
| - |
35 |
| - #-Loop Through TestSet-# |
36 |
| - for (P, known) in testset: |
37 |
| - computed = mc_compute_stationary(P) |
38 |
| - assert_allclose(computed, known) |
39 |
| - |
40 |
| - |
41 |
| - |
42 |
| -### Tests: mc_sample_path ### |
43 |
| - |
44 |
| - |
45 |
| - # - Work Needed Here - # |
46 |
| - |
47 |
| - |
48 |
| - |
49 |
| -#################################### |
50 |
| -# Wiki Example # |
51 |
| -# ------------ # |
52 |
| -# Tests For: mc_compute_stationary # |
53 |
| -# Note: This can be removed but is # |
54 |
| -# a record of examples written for # |
55 |
| -# "Wiki: Writing Tests" # |
56 |
| -#################################### |
57 |
| - |
58 |
| -#--------------------------------# |
59 |
| -#-Examples: Simple Test Examples-# |
60 |
| -#--------------------------------# |
61 |
| - |
62 |
| -# Check required infrastructure is imported |
63 |
| -import numpy as np |
64 |
| - |
65 |
| -# Check that the test_mc_tools.py file has imported the relevant function we wish to test: mc_compute_stationary |
66 |
| -# Note: This will import the function from the `installed` location (may want to use relative references) |
67 |
| - |
68 |
| -from ..mc_tools import mc_compute_stationary |
69 |
| -#from quantecon import mc_compute_stationary |
70 |
| - |
71 |
| -#-Example of Assertion Failures-# |
72 |
| - |
73 |
| - # from numpy.testing import assert_array_equal |
74 |
| - |
75 |
| - # def test_mc_compute_stationary_pmatrix(): |
76 |
| - # """ |
77 |
| - # Test for a Known Solution |
78 |
| - # Module: mc_tools.py |
79 |
| - # Function: mc_compute_stationary |
80 |
| - # """ |
81 |
| - # P = np.array([[0.4,0.6], [0.2,0.8]]) |
82 |
| - # P_known = np.array([0.25, 0.75]) |
83 |
| - # computed = mc_compute_stationary(P) |
84 |
| - # assert_array_equal(computed, P_known) |
85 |
| - |
86 |
| -# Example Output from Above Test |
87 |
| -# --------------------------------------------------------------------------- |
88 |
| -# AssertionError Traceback (most recent call last) |
89 |
| -# #Traceback details are presented here |
90 |
| - |
91 |
| -# AssertionError: |
92 |
| -# Arrays are not equal |
93 |
| - |
94 |
| -# (mismatch 50.0%) |
95 |
| -# x: array([ 0.25, 0.75]) |
96 |
| -# y: array([ 0.25, 0.75]) |
97 |
| - |
98 |
| -from numpy.testing import assert_allclose |
99 |
| - |
100 |
| -def test_mc_compute_stationary_pmatrix(): |
101 |
| - """ |
102 |
| - Test mc_compute_stationary for a Known Solution of Matrix P |
103 |
| - Module: mc_tools.py |
104 |
| - Function: mc_compute_stationary |
105 |
| - """ |
106 |
| - P = np.array([[0.4,0.6], [0.2,0.8]]) |
107 |
| - P_known = np.array([0.25, 0.75]) |
108 |
| - computed = mc_compute_stationary(P) |
109 |
| - assert_allclose(computed, P_known) |
110 |
| - |
111 |
| -#-Slightly More General Version with testset-# |
112 |
| - |
113 |
| -def test_mc_compute_stationary_pmatrix(): |
114 |
| - testset1 = (np.array([[0.4,0.6], [0.2,0.8]]), np.array([0.25, 0.75])) |
115 |
| - check_mc_compute_stationary_pmatrix(testset1) |
116 |
| - |
117 |
| -def check_mc_compute_stationary_pmatrix(testset): |
118 |
| - """ |
119 |
| - Test mc_compute_stationary for a Known Solution of Matrix P |
120 |
| - Module: mc_tools.py |
121 |
| - Function: mc_compute_stationary |
122 |
| - |
123 |
| - Arguments |
124 |
| - --------- |
125 |
| - [1] test_set : tuple(np.array(P), np.array(known_solution)) |
126 |
| - """ |
127 |
| - (P, known) = testset |
128 |
| - computed = mc_compute_stationary(P) |
129 |
| - assert_allclose(computed, known) |
130 |
| - |
131 |
| -#-----------------------------------------------------------------# |
132 |
| -#-Examples: Unittest vs Nose Functions (with setup) vs Nose Class-# |
133 |
| -#-----------------------------------------------------------------# |
134 |
| - |
135 |
| -from ..mc_tools import mc_compute_stationary # Good to use relative imports so as not to use the system installation quantecon when running tests |
136 |
| - |
137 |
| -# Supporting Test Function # |
138 |
| -# Some Tests will require Setup Functions to Generate a Type of Matrix etc |
139 |
| -# These can be Imported or Defined In the Test File as a function |
140 |
| -# Example From: https://github.com/oyamad/test_mc_compute_stationary |
| 17 | +from quantecon.mc_tools import DMarkov, mc_compute_stationary, mc_sample_path |
141 | 18 |
|
| 19 | +# KMR Function |
| 20 | +# Useful because it seems to have 1 unit eigvalue, but a second one that |
| 21 | +# approaches unity. Good test of accuracy. |
142 | 22 | def KMR_Markov_matrix_sequential(N, p, epsilon):
|
143 |
| - """ |
144 |
| - Generate the Markov matrix for the KMR model with *sequential* move |
145 |
| -
|
146 |
| - N: number of players |
147 |
| - p: level of p-dominance for action 1 |
148 |
| - = the value of p such that action 1 is the BR for (1-q, q) for any q > p, |
149 |
| - where q (1-q, resp.) is the prob that the opponent plays action 1 (0, resp.) |
150 |
| - epsilon: mutation probability |
151 |
| -
|
152 |
| - References: |
153 |
| - KMRMarkovMatrixSequential is contributed from https://github.com/oyamad |
154 |
| - """ |
155 |
| - P = np.zeros((N+1, N+1), dtype=float) |
156 |
| - P[0, 0], P[0, 1] = 1 - epsilon * (1/2), epsilon * (1/2) |
157 |
| - for n in range(1, N): |
158 |
| - P[n, n-1] = \ |
159 |
| - (n/N) * (epsilon * (1/2) + |
160 |
| - (1 - epsilon) * (((n-1)/(N-1) < p) + ((n-1)/(N-1) == p) * (1/2)) |
161 |
| - ) |
162 |
| - P[n, n+1] = \ |
163 |
| - ((N-n)/N) * (epsilon * (1/2) + |
164 |
| - (1 - epsilon) * ((n/(N-1) > p) + (n/(N-1) == p) * (1/2)) |
165 |
| - ) |
166 |
| - P[n, n] = 1 - P[n, n-1] - P[n, n+1] |
167 |
| - P[N, N-1], P[N, N] = epsilon * (1/2), 1 - epsilon * (1/2) |
168 |
| - return P |
169 |
| - |
170 |
| -############## |
171 |
| -## unittest ## |
172 |
| -############## |
173 |
| - |
174 |
| -# Pro: Consistent Naming Convention, Benefits of inheritance from unittest.TestCase in terms of assertion logic, Nose can parse unittest |
175 |
| -# Con: Can be a bit less flexible, Larger Initial Barier to Entry for Beginners |
176 |
| - |
177 |
| -class Test_mc_compute_stationary_KMRMarkovMatrix1(unittest.TestCase): |
178 |
| - """ |
179 |
| - Test Suite for mc_compute_stationary using KMR Markov Matrix [using unittest.TestCase] |
180 |
| - """ |
181 |
| - |
182 |
| - # Starting Values # |
183 |
| - |
184 |
| - N = 27 |
185 |
| - epsilon = 1e-2 |
186 |
| - p = 1/3 |
187 |
| - TOL = 1e-2 |
188 |
| - |
189 |
| - def setUp(self): |
190 |
| - """ Calculate KMR Matrix and Compute the Stationary Distribution """ |
191 |
| - self.P = KMR_Markov_matrix_sequential(self.N, self.p, self.epsilon) |
192 |
| - self.v = mc_compute_stationary(self.P) |
193 |
| - |
194 |
| - def test_markov_matrix(self): |
195 |
| - for i in range(len(self.P)): |
196 |
| - self.assertEqual(sum(self.P[i, :]), 1) |
197 |
| - |
198 |
| - def test_sum_one(self): |
199 |
| - self.assertTrue(np.allclose(sum(self.v), 1, atol=self.TOL)) |
200 |
| - |
201 |
| - def test_nonnegative(self): |
202 |
| - self.assertEqual(np.prod(self.v >= 0-self.TOL), 1) |
| 23 | + """ |
| 24 | + Generate the Markov matrix for the KMR model with *sequential* move |
| 25 | +
|
| 26 | + N: number of players |
| 27 | + p: level of p-dominance for action 1 |
| 28 | + = the value of p such that action 1 is the BR for (1-q, q) for any q > p, |
| 29 | + where q (1-q, resp.) is the prob that the opponent plays action 1 (0, resp.) |
| 30 | + epsilon: mutation probability |
| 31 | +
|
| 32 | + References: |
| 33 | + KMRMarkovMatrixSequential is contributed from https://github.com/oyamad |
| 34 | + """ |
| 35 | + P = np.zeros((N+1, N+1), dtype=float) |
| 36 | + P[0, 0], P[0, 1] = 1 - epsilon * (1/2), epsilon * (1/2) |
| 37 | + for n in range(1, N): |
| 38 | + P[n, n-1] = \ |
| 39 | + (n/N) * (epsilon * (1/2) + |
| 40 | + (1 - epsilon) * (((n-1)/(N-1) < p) + ((n-1)/(N-1) == p) * (1/2)) |
| 41 | + ) |
| 42 | + P[n, n+1] = \ |
| 43 | + ((N-n)/N) * (epsilon * (1/2) + |
| 44 | + (1 - epsilon) * ((n/(N-1) > p) + (n/(N-1) == p) * (1/2)) |
| 45 | + ) |
| 46 | + P[n, n] = 1 - P[n, n-1] - P[n, n+1] |
| 47 | + P[N, N-1], P[N, N] = epsilon * (1/2), 1 - epsilon * (1/2) |
| 48 | + return P |
203 | 49 |
|
204 |
| - def test_left_eigen_vec(self): |
205 |
| - self.assertTrue(np.allclose(np.dot(self.v, self.P), self.v, atol=self.TOL)) |
206 |
| - |
207 |
| - def tearDown(self): |
208 |
| - pass |
209 |
| - |
210 |
| - |
211 |
| -#################### |
212 |
| -## Nose Functions ## |
213 |
| -#################### |
214 |
| - |
215 |
| -# Nose offers a variety of ways to construct tests: Functions, Classes, etc. |
216 |
| - |
217 |
| -# Individual Test Functions with setup decorator # |
218 |
| -# ---------------------------------------------- # |
219 |
| - |
220 |
| -from nose.tools import with_setup |
| 50 | +### Tests: mc_compute_stationary ### |
221 | 51 |
|
222 |
| -#-Starting Values-# |
| 52 | +def test_mc_compute_stationary_pmatrices(): |
| 53 | + """ |
| 54 | + Test mc_compute_stationary with P Matrix and Known Solutions |
| 55 | + """ |
223 | 56 |
|
224 |
| -N = 27 |
225 |
| -epsilon = 1e-2 |
226 |
| -p = 1/3 |
227 |
| -TOL = 1e-2 |
| 57 | + #-P Matrix-# , #-Known Solution-# |
| 58 | + testset = [ |
| 59 | + ( np.array([[0.4,0.6], [0.2,0.8]]), np.array([0.25, 0.75]) ), |
| 60 | + ( np.eye(2), np.eye(2) ) |
| 61 | + ] |
228 | 62 |
|
229 |
| -def setup_func(): |
230 |
| - """ Setup a KMRMarkovMatrix and Compute Stationary Values """ |
231 |
| - global P # Not Usually Recommended! |
232 |
| - P = KMR_Markov_matrix_sequential(N, p, epsilon) |
233 |
| - global v # Not Usually Recommended! |
234 |
| - v = mc_compute_stationary(P) |
| 63 | + #-Loop Through TestSet-# |
| 64 | + for (P, known) in testset: |
| 65 | + computed = mc_compute_stationary(P) |
| 66 | + assert_allclose(computed, known) |
235 | 67 |
|
236 |
| -@with_setup(setup_func) |
237 |
| -def test_markov_matrix(): |
238 |
| - for i in range(len(P)): |
239 |
| - assert sum(P[i, :]) == 1, "sum(P[i,:]) %s != 1" % sum(P[i, :]) |
240 | 68 |
|
241 |
| -@with_setup(setup_func) |
242 |
| -def test_sum_one(): |
243 |
| - assert np.allclose(sum(v), 1, atol=TOL) == True, "np.allclose(sum(v), 1, atol=%s) != True" % TOL |
244 | 69 |
|
245 |
| -@with_setup(setup_func) |
246 |
| -def test_nonnegative(): |
247 |
| - assert np.prod(v >= 0-TOL) == 1, "np.prod(v >= 0-TOL) %s != 1" % np.prod(v >= 0-TOL) |
248 | 70 |
|
249 |
| -@with_setup(setup_func) |
250 |
| -def test_left_eigen_vec(): |
251 |
| - assert np.allclose(np.dot(v, P), v, atol=TOL) == True, "np.allclose(np.dot(v, P), v, atol=%s) != True" % TOL |
252 | 71 |
|
253 | 72 | # Basic Class Structure with Setup #
|
254 | 73 | ####################################
|
255 | 74 |
|
256 | 75 | class Test_mc_compute_stationary_KMRMarkovMatrix2():
|
257 |
| - """ |
258 |
| - Test Suite for mc_compute_stationary using KMR Markov Matrix [suitable for nose] |
259 |
| - """ |
260 |
| - |
261 |
| - #-Starting Values-# |
262 |
| - |
263 |
| - N = 27 |
264 |
| - epsilon = 1e-2 |
265 |
| - p = 1/3 |
266 |
| - TOL = 1e-2 |
267 |
| - |
268 |
| - def setUp(self): |
269 |
| - """ Setup a KMRMarkovMatrix and Compute Stationary Values """ |
270 |
| - self.P = KMR_Markov_matrix_sequential(self.N, self.p, self.epsilon) |
271 |
| - self.v = mc_compute_stationary(self.P) |
272 |
| - |
273 |
| - def test_markov_matrix(self): |
274 |
| - for i in range(len(self.P)): |
275 |
| - assert sum(self.P[i, :]) == 1, "sum(P[i,:]) %s != 1" % sum(self.P[i, :]) |
276 |
| - |
277 |
| - def test_sum_one(self): |
278 |
| - assert np.allclose(sum(self.v), 1, atol=self.TOL) == True, "np.allclose(sum(v), 1, atol=%s) != True" % self.TOL |
279 |
| - |
280 |
| - def test_nonnegative(self): |
281 |
| - assert np.prod(self.v >= 0-self.TOL) == 1, "np.prod(v >= 0-TOL) %s != 1" % np.prod(self.v >= 0-self.TOL) |
282 |
| - |
283 |
| - def test_left_eigen_vec(self): |
284 |
| - assert np.allclose(np.dot(self.v, self.P), self.v, atol=self.TOL) == True, "np.allclose(np.dot(v, P), v, atol=%s) != True" % self.TOL |
| 76 | + """ |
| 77 | + Test Suite for mc_compute_stationary using KMR Markov Matrix [suitable for nose] |
| 78 | + """ |
| 79 | + |
| 80 | + #-Starting Values-# |
| 81 | + |
| 82 | + N = 27 |
| 83 | + epsilon = 1e-2 |
| 84 | + p = 1/3 |
| 85 | + TOL = 1e-2 |
| 86 | + |
| 87 | + def setUp(self): |
| 88 | + """ Setup a KMRMarkovMatrix and Compute Stationary Values """ |
| 89 | + self.P = KMR_Markov_matrix_sequential(self.N, self.p, self.epsilon) |
| 90 | + self.mc = DMarkov(self.P) |
| 91 | + self.stationary = self.mc.mc_compute_stationary() |
| 92 | + stat_shape = self.stationary.shape |
| 93 | + |
| 94 | + if len(stat_shape) is 1: |
| 95 | + self.n_stat_dists = 1 |
| 96 | + else: |
| 97 | + self.n_stat_dists = stat_shape[1] |
| 98 | + |
| 99 | + |
| 100 | + def test_markov_matrix(self): |
| 101 | + "Check that each row of matrix sums to 1" |
| 102 | + mc = self.mc |
| 103 | + assert_allclose(np.sum(mc.P, axis=1), np.ones(mc.n)) |
| 104 | + |
| 105 | + def test_sum_one(self): |
| 106 | + "Check each stationary distribution sums to 1" |
| 107 | + stationary_distributions = self.stationary |
| 108 | + assert_allclose(np.sum(stationary_distributions, axis=0), |
| 109 | + np.ones(self.n_stat_dists)) |
| 110 | + |
| 111 | + def test_nonnegative(self): |
| 112 | + "Check that the stationary distributions are non-negative" |
| 113 | + stationary_distributions = self.stationary |
| 114 | + assert(np.all(stationary_distributions > -1e-16)) |
| 115 | + |
| 116 | + def test_left_eigen_vec(self): |
| 117 | + "Check that vP = v for all stationary distributions" |
| 118 | + mc = self.mc |
| 119 | + stationary = self.stationary |
| 120 | + |
| 121 | + if self.n_stat_dists is 1: |
| 122 | + assert_allclose(np.dot(stationary, mc.P), stationary, atol=self.TOL) |
| 123 | + else: |
| 124 | + for i in range(self.n_stat_dists): |
| 125 | + curr_v = stationary_distributions[:, i] |
| 126 | + assert_allclose(np.dot(curr_v, mc.P), curr_v, atol=self.TOL) |
285 | 127 |
|
286 | 128 |
|
0 commit comments