PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/pymaclab/dsge/solvers/steadystate.py

https://github.com/TomAugspurger/pymaclab
Python | 172 lines | 145 code | 7 blank | 20 comment | 9 complexity | 851b52ba8ae79cb4cddda47366b73929 MD5 | raw file
Possible License(s): Apache-2.0
  1. '''
  2. .. module:: steadystate
  3. :platform: Linux
  4. :synopsis: The steadystate module currently contains a shell class for sub-branching as well as two classes for calculating the
  5. steady state of DSGE models. One of them computes steady states using closed form information, while the other one makes
  6. use of a nonlinear root-finding algorithm supplied by the scipy optimize package.
  7. .. moduleauthor:: Eric M. Scheffel <eric.scheffel@nottingham.edu.cn>
  8. '''
  9. import re
  10. import numpy as np
  11. import copy
  12. from scipy import optimize
  13. # Switch off runtime warnings here
  14. import warnings
  15. warnings.filterwarnings("ignore")
  16. class SSsolvers(object):
  17. def __init__(self):
  18. pass
  19. class ManualSteadyState(SSsolvers):
  20. """
  21. Solve for the steady state manually
  22. """
  23. def __init__(self,intup,other=None):
  24. self.manss_sys = intup[0]
  25. self.paramdic = intup[1]
  26. self.other = other
  27. def solve(self):
  28. list_tmp1 = copy.deepcopy(self.manss_sys)
  29. # Create manual (closed-form) steady state dictionary
  30. _rlog = 'LOG\('
  31. _rexp = 'EXP\('
  32. rlog = re.compile(_rlog)
  33. rexp = re.compile(_rexp)
  34. manss={}
  35. locals().update(self.paramdic)
  36. globals().update(self.paramdic)
  37. for x in list_tmp1:
  38. str_tmp3 = x[:]
  39. while rlog.search(str_tmp3):
  40. str_tmp3 = re.sub(rlog,'np.log(',str_tmp3)
  41. while rexp.search(str_tmp3):
  42. str_tmp3 = re.sub(rexp,'np.exp(',str_tmp3)
  43. str_tmp = str_tmp3.split(';')[0]
  44. list_tmp = str_tmp.split('=')
  45. str_tmp1 = list_tmp[0].strip()
  46. str_tmp2 = list_tmp[1].strip()
  47. manss[str_tmp1] = eval(str_tmp2)
  48. locals()[str_tmp1] = eval(str_tmp2)
  49. globals().update(manss)
  50. self.sstate = manss
  51. class Fsolve(SSsolvers):
  52. def __init__(self,intup,other=None):
  53. self.ssm = intup[0]
  54. self.ssi = intup[1]
  55. self.paramdic = intup[2]
  56. self.other = other
  57. # create a dic holding non _bar values in ssi
  58. tmp_dic = {}
  59. for keyo in self.ssi.keys():
  60. if '_bar' not in keyo: tmp_dic[keyo] = self.ssi[keyo]
  61. self.nonbardic = tmp_dic
  62. def solve(self,bounds_dic=None):
  63. # Turn the non-linear system into a representation
  64. # that is suitable for fsolve(invar) !
  65. patup = ('{-10,10}|None','iid','{-10,10}')
  66. ssi = self.ssi
  67. subdic = {}
  68. for y,z in zip(ssi.items(),range(len(ssi.items()))):
  69. subdic[y[0]] = (y[0],y[1],z)
  70. list_tmp1 = copy.deepcopy(self.ssm)
  71. for var in ssi.keys():
  72. _mreg = '(\+|\*|-|/|^|\()'+var
  73. mreg = re.compile(_mreg)
  74. _rlog = 'LOG\('
  75. _rexp = 'EXP\('
  76. rlog = re.compile(_rlog)
  77. rexp = re.compile(_rexp)
  78. for i1,line in enumerate(list_tmp1):
  79. # First strip away any whitespace
  80. while ' ' in list_tmp1[i1]:
  81. list_tmp1[i1] = list_tmp1[i1].replace(' ','')
  82. while rlog.search(list_tmp1[i1]):
  83. list_tmp1[i1] = re.sub(rlog,'np.log(',list_tmp1[i1])
  84. while rexp.search(list_tmp1[i1]):
  85. list_tmp1[i1] = re.sub(rexp,'np.exp(',list_tmp1[i1])
  86. # Eliminate IID variables by setting equal to zero
  87. while self.other.vreg(patup,list_tmp1[i1],True,'max'):
  88. varli = self.other.vreg(patup,list_tmp1[i1],True,'max')
  89. varli.reverse()
  90. for varo in varli:
  91. pos = varo[3][0]
  92. poe = varo[3][1]
  93. vari = varo[0]
  94. list_tmp1[i1] = list_tmp1[i1][:pos]+'0.0'+list_tmp1[i1][poe:]
  95. while mreg.search(list_tmp1[i1]):
  96. ma = mreg.search(list_tmp1[i1])
  97. matot = ma.group()
  98. if len(ma.group(1))>0:
  99. var = ma.group()[1:]
  100. pos = ma.span()[0]+1
  101. else:
  102. var = ma.group()
  103. pos = ma.span()[0]
  104. poe = ma.span()[1]
  105. list_tmp1[i1] = list_tmp1[i1][:pos]+'invar['+str(subdic[var][2])+']'+list_tmp1[i1][poe:]
  106. func_repr = list_tmp1
  107. self.subdic = copy.deepcopy(subdic)
  108. self.ssm_alt = copy.deepcopy(func_repr)
  109. # Define the function to be handed over
  110. # to fsolve
  111. if bounds_dic == None:
  112. def func(invar):
  113. locals().update(self.paramdic)
  114. locals().update(self.nonbardic)
  115. fdot = np.zeros((len(func_repr)),float)
  116. for i1,x in enumerate(func_repr):
  117. fdot[i1] = eval(x)
  118. return fdot
  119. else:
  120. def func(invar):
  121. locals().update(self.paramdic)
  122. locals().update(self.nonbardic)
  123. fdot = np.zeros((len(func_repr)),float)
  124. for i1,x in enumerate(func_repr):
  125. fdot[i1] = eval(x)
  126. return np.sum(np.abs(fdot))
  127. # Define the initial values and
  128. # start the non-linear solver
  129. inlist = []
  130. for x in subdic.values():
  131. inlist.append([x[2],x[1],x[0]])
  132. inlist.sort()
  133. init_val = [float(x[1]) for x in inlist]
  134. # Prepare the case of constrained optimisation if needed
  135. blist = []
  136. if bounds_dic != None:
  137. for elem in inlist:
  138. if elem[2] in bounds_dic.keys(): blist.append(bounds_dic[elem[2]])
  139. else: blist.append((None,None))
  140. # Accomodate unconstrained and constrained optimisation
  141. if bounds_dic == None:
  142. outobj = optimize.root(func,init_val,method='hybr')
  143. output = outobj.x
  144. mesg = outobj.message
  145. ier = outobj.status
  146. else:
  147. outobj = optimize.minimize(func,init_val,method='L-BFGS-B',bounds=blist)
  148. output = outobj.x
  149. mesg = outobj.message
  150. ier = outobj.status
  151. # Attach the outputs of the solver as attributes
  152. self.fsout={}
  153. for x,y in zip(output,inlist):
  154. self.fsout[y[2]] = x
  155. self.ier = ier
  156. self.mesg = mesg
  157. self.output = output