forked from shade-econ/sequence-jacobian
-
Notifications
You must be signed in to change notification settings - Fork 0
/
solved_block.py
68 lines (54 loc) · 3.27 KB
/
solved_block.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import numpy as np
import nonlinear
import jacobian as jac
from simple_block import simple
def solved(unknowns, targets, block_list=[]):
"""Creates SolvedBlocks. Can be applied in two ways, both of which return a SolvedBlock:
- as @solved(unknowns=..., targets=...) decorator on a single SimpleBlock
- as function solved(blocklist=..., unknowns=..., targets=...) where blocklist
can be any list of blocks
"""
if block_list:
# ordinary call, not as decorator
return SolvedBlock(block_list, unknowns, targets)
else:
# call as decorator, return function of function
def solver(f):
return SolvedBlock([simple(f)], unknowns, targets)
return solver
class SolvedBlock:
"""SolvedBlocks are mini SHADE models embedded as blocks inside larger SHADE models.
When creating them, we need to provide the basic ingredients of a SHADE model: the list of
blocks comprising the model, the list on unknowns, and the list of targets.
When we use .jac to ask for the Jacobian of a SolvedBlock, we are really solving for the 'G'
matrices of the mini SHADE models, which then become the 'curlyJ' Jacobians of the block.
Similarly, when we use .td to evaluate a SolvedBlock on a path, we are really solving for the
nonlinear transition path such that all internal targets of the mini SHADE model are zero.
"""
def __init__(self, block_list, unknowns, targets):
self.block_list = block_list
self.unknowns = unknowns
self.targets = targets
# need to have inputs and outputs!!!
self.outputs = (set.union(*(b.outputs for b in block_list)) | set(self.unknowns)) - set(self.targets)
self.inputs = set.union(*(b.inputs for b in block_list)) - self.outputs
def ss(self, *args, **kwargs):
# implementing steady-state for general solved block would be tantamount to providing
# a general method to solve for the steady state of any SHADE model
# this is not our focus for now, since our methodological contributions are on dynamic side
raise NotImplementedError('Cannot evaluate steady state for a SolvedBlock!')
def td(self, ss, monotonic=False, returnindividual=False, noisy=False, **kwargs):
# TODO: add H_U_factored caching of some kind
# also, inefficient since we are repeatedly starting from the steady state, need option
# to provide a guess (not a big deal with just SimpleBlocks, of course)
return nonlinear.td_solve(ss, self.block_list, self.unknowns, self.targets, monotonic=monotonic,
returnindividual=returnindividual, noisy=noisy, **kwargs)
def jac(self, ss, T, shock_list, output_list=None, save=False, use_saved=False):
# H_U_factored caching could be helpful here too
return jac.get_G(self.block_list, shock_list, self.unknowns, self.targets,
T, ss, output_list, save=save, use_saved=use_saved)
def ajac(self, ss, T, shock_list, output_list=None, save=False, use_saved=False, Tpost=None):
if Tpost is None:
Tpost = 2*T
return jac.get_G_asymptotic(self.block_list, shock_list, self.unknowns,
self.targets, T, ss, output_list, save=save, use_saved=use_saved, Tpost=Tpost)