test_chebyshev_collocation()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 1
c 4
b 0
f 0
dl 0
loc 5
rs 9.4285
1
from nose import tools
2
3
import numpy as np
4
from scipy import stats
5
6
from . import models
7
from .. import basis_functions
8
from .. import solvers
9
10
11
def analytic_solution(t, k0, alpha, delta, g, n, s, **params):
12
    """Analytic solution for model with Cobb-Douglas production."""
13
    lmbda = (g + n + delta) * (1 - alpha)
14
    ks = (((s / (g + n + delta)) * (1 - np.exp(-lmbda * t)) +
15
           k0**(1 - alpha) * np.exp(-lmbda * t))**(1 / (1 - alpha)))
16
    return ks
17
18
19
def cobb_douglas_output(k, alpha, **params):
20
    """Intensive output has Cobb-Douglas functional form."""
21
    return k**alpha
22
23
24
def equilibrium_capital(alpha, delta, g, n, s, **params):
25
    """Equilibrium value of capital (per unit effective labor supply)."""
26
    return (s / (g + n + delta))**(1 / (1 - alpha))
27
28
29
def generate_random_params(scale, seed):
30
    np.random.seed(seed)
31
32
    # random g, n, delta such that sum of these params is positive
33
    g, n = stats.norm.rvs(0.05, scale, size=2)
34
    delta, = stats.lognorm.rvs(scale, loc=g + n, size=1)
35
    assert g + n + delta > 0
36
37
    # s and alpha must be on (0, 1) (but lower values are more reasonable)
38
    s, alpha = stats.beta.rvs(a=1, b=3, size=2)
39
40
    # choose k0 so that it is not too far from equilibrium
41
    kstar = equilibrium_capital(alpha, delta, g, n, s)
42
    k0, = stats.uniform.rvs(0.5 * kstar, 1.5 * kstar, size=1)
43
    assert k0 > 0
44
45
    params = {'g': g, 'n': n, 'delta': delta, 's': s, 'alpha': alpha,
46
              'k0': k0}
47
48
    return params
49
50
51
def initial_mesh(t, T, num, problem):
52
    ts = np.linspace(t, T, num)
53
    kstar = equilibrium_capital(**problem.params)
54
    ks = kstar - (kstar - problem.params['k0']) * np.exp(-ts)
55
    return ts, ks
56
57
58
random_seed = np.random.randint(2147483647)
59
random_params = generate_random_params(0.1, random_seed)
60
test_problem = models.SolowModel(cobb_douglas_output, equilibrium_capital,
61
                                 random_params)
62
63
polynomial_basis = basis_functions.PolynomialBasis()
64
solver = solvers.Solver(polynomial_basis)
65
66
67
def _test_polynomial_collocation(basis_kwargs, boundary_points, num=1000):
68
    """Helper function for testing various kinds of polynomial collocation."""
69
    ts, ks = initial_mesh(*boundary_points, num=num, problem=test_problem)
70
    k_poly = polynomial_basis.fit(ts, ks, **basis_kwargs)
71
    initial_coefs = k_poly.coef
72
    nodes = polynomial_basis.roots(**basis_kwargs)
73
74
    solution = solver.solve(basis_kwargs, boundary_points, initial_coefs,
75
                            nodes, test_problem)
76
77
    # check that solver terminated successfully
78
    msg = "Solver failed!\nSeed: {}\nModel params: {}\n"
79
    tools.assert_true(solution.result.success,
80
                      msg=msg.format(random_seed, test_problem.params))
81
82
    # compute the residuals
83
    normed_residuals = solution.normalize_residuals(ts)
84
85
    # check that residuals are close to zero on average
86
    tools.assert_true(np.mean(normed_residuals) < 1e-6,
87
                      msg=msg.format(random_seed, test_problem.params))
88
89
    # check that the numerical and analytic solutions are close
90
    numeric_soln = solution.evaluate_solution(ts)
91
    analytic_soln = analytic_solution(ts, **test_problem.params)
92
    tools.assert_true(np.mean(numeric_soln - analytic_soln) < 1e-6)
93
94
95
def test_chebyshev_collocation():
96
    """Test collocation solver using Chebyshev polynomials for basis."""
97
    boundary_points = (0, 100)
98
    basis_kwargs = {'kind': 'Chebyshev', 'degree': 50, 'domain': boundary_points}
99
    _test_polynomial_collocation(basis_kwargs, boundary_points)
100
101
102
def test_legendre_collocation():
103
    """Test collocation solver using Legendre polynomials for basis."""
104
    boundary_points = (0, 100)
105
    basis_kwargs = {'kind': 'Legendre', 'degree': 50, 'domain': boundary_points}
106
    _test_polynomial_collocation(basis_kwargs, boundary_points)
107