Skip to content

Commit 176633d

Browse files
committed
TESTS: Rearranged the mc_tools tests and made it work for new function.
1 parent 5fdf72f commit 176633d

File tree

1 file changed

+97
-255
lines changed

1 file changed

+97
-255
lines changed

quantecon/tests/test_mc_tools.py

Lines changed: 97 additions & 255 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,9 @@
33
44
Functions
55
---------
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]
88
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
139
"""
1410

1511
from __future__ import division
@@ -18,269 +14,115 @@
1814
import unittest
1915
from numpy.testing import assert_allclose
2016

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
14118

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.
14222
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
20349

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 ###
22151

222-
#-Starting Values-#
52+
def test_mc_compute_stationary_pmatrices():
53+
"""
54+
Test mc_compute_stationary with P Matrix and Known Solutions
55+
"""
22356

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+
]
22862

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)
23567

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, :])
24068

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
24469

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)
24870

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
25271

25372
# Basic Class Structure with Setup #
25473
####################################
25574

25675
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)
285127

286128

0 commit comments

Comments
 (0)