diff --git a/Documentation/CHANGELOG.md b/Documentation/CHANGELOG.md index 1c93f154f..53e53eb8f 100644 --- a/Documentation/CHANGELOG.md +++ b/Documentation/CHANGELOG.md @@ -8,17 +8,22 @@ For more information on HARK, see [our Github organization](https://github.com/e ## Changes -### 0.15.0 (in development) +### 0.15.0 -Release Date: TBA +Release Date: June 4, 2024 Note: Due to major changes on this release, you may need to adjust how AgentTypes are instantiated in your projects using HARK. If you are manually constructing "complicated" objects like MrkvArray, they should be assigned to your instances *after* initialization, not passed as part of the parameter dictionary. See also the new constructor methodology for how to pass parameters for such constructed inputs. +This release drops support for Python 3.8 and 3.9, consistent with SPEC 0, and adds support for Python 3.11 and 3.12. We expect that all HARK features still work with the older versions, but they are no longer part of our testing regimen. + ### Major Changes +- Drop official support for Python 3.8 and 3.9, add support for 3.11 and 3.12. [#1415](https://github.com/econ-ark/HARK/pull/1415) - Replace object-oriented solvers with single function versions. [#1394](https://github.com/econ-ark/HARK/pull/1394) - Object-oriented solver code has been moved to /HARK/ConsumptionSaving/LegacyOOsolvers.py, for legacy support of downstream projects. - AgentTypeMonteCarloSimulator now requires model shock, parameter, and dynamics information to be organized into 'blocks'. The DBlock object is introduced. [#1411](https://github.com/econ-ark/HARK/pull/1411) +- RBlock object allows for recursive composition of DBlocks in models, as demonstrated by the AgentTypeMonteCarloSimulator [#1417](https://github.com/econ-ark/HARK/pull/1417/) +- Transtion, reward, state-rulle value function, decision value function, and arrival value function added to DBlock [#1417](https://github.com/econ-ark/HARK/pull/1417/) - All methods that construct inputs for solvers are now functions that are specified in the dictionary attribute `constructors`. [#1410](https://github.com/econ-ark/HARK/pull/1410) - Such constructed inputs can use alternate parameterizations / formats by changing the `constructor` function and providing its arguments in `parameters`. - Move `HARK.datasets` to `HARK.Calibration` for better organization of data and calibration tools. [#1430](https://github.com/econ-ark/HARK/pull/1430) diff --git a/Documentation/NARK/NARK.dep b/Documentation/NARK/NARK.dep new file mode 100644 index 000000000..156d6e3f5 --- /dev/null +++ b/Documentation/NARK/NARK.dep @@ -0,0 +1,133 @@ +\RequireVersions{ + *{application}{TeX} {1990/03/25 v3.x} + *{format} {LaTeX2e} {2023-11-01 v2.e} + *{file} {./econtexRoot.tex}{0000/00/00 v0.0} + *{file} {./Resources/econtexPaths.tex}{0000/00/00 v0.0} + *{class} {./Resources/texmf-local/tex/latex/econtex}{2017/08/01 v0.0} + *{package}{snapshot} {2002/03/05 v1.14} + *{package}{ifthen} {2022/04/13 v1.1d} + *{package}{changepage} {2009/10/20 v1.0c} + *{package}{setspace} {2022/12/04 v6.7b} + *{class} {scrartcl} {2023/07/07 v3.41} + *{package}{scrkbase} {2023/07/07 v3.41} + *{package}{scrbase} {2023/07/07 v3.41} + *{package}{scrlfile} {2023/07/07 v3.41} + *{package}{scrlfile-hook}{2023/07/07 v3.41} + *{package}{scrlogo} {2023/07/07 v3.41} + *{package}{keyval} {2022/05/29 v1.15} + *{package}{tocbasic} {2023/07/07 v3.41} + *{file} {scrsize12pt.clo}{2023/07/07 v3.41} + *{package}{typearea} {2023/07/07 v3.41} + *{package}{fontenc} {0000/00/00 v0.0} + *{package}{babel} {2024/02/07 v24.2} + *{file} {english.ldf} {2017/06/06 v3.3r} + *{file} {babel-english.tex}{0000/00/00 v0.0} + *{package}{calc} {2023/07/08 v4.3} + *{package}{cancel} {2013/04/12 v2.2} + *{package}{verbatim} {2023-11-06 v1.5v} + *{package}{amsmath} {2023/05/13 v2.17o} + *{package}{amstext} {2021/08/26 v2.01} + *{package}{amsgen} {1999/11/30 v2.0} + *{package}{amsbsy} {1999/11/29 v1.2d} + *{package}{amsopn} {2022/04/08 v2.04} + *{package}{amssymb} {2013/01/14 v3.01} + *{package}{amsfonts} {2013/01/14 v3.01} + *{package}{amsthm} {2020/05/29 v2.20.6} + *{package}{xpatch} {2020/03/25 v0.3a} + *{package}{expl3} {2024-02-20 v3} + *{file} {l3backend-pdftex.def}{2024-02-20 v3} + *{package}{xparse} {2024-02-18 v3} + *{package}{etoolbox} {2020/10/05 v2.5k} + *{package}{threeparttable}{2003/06/13 v3.0} + *{package}{dcolumn} {2023/07/08 v1.06} + *{package}{array} {2023/10/16 v2.5g} + *{package}{multicol} {2023/03/30 v1.9f} + *{package}{multirow} {2021/03/15 v2.8} + *{package}{booktabs} {2020/01/12 v1.61803398} + *{package}{latexsym} {1998/08/17 v2.2e} + *{package}{afterpage} {2023/07/04 v1.08} + *{package}{enotez} {2022/01/04 v0.10d} + *{package}{l3keys2e} {2024-02-18 v2e} + *{package}{xtemplate} {2023-10-10 v3} + *{package}{xtemplate-2023-10-10}{0000/00/00 v0.0} + *{package}{translations}{2022/02/05 v1.12} + *{package}{pdftexcmds} {2020-06-27 v0.33} + *{package}{infwarerr} {2019/12/03 v1.5} + *{package}{iftex} {2022/02/03 v1.0f} + *{package}{ltxcmds} {2023-12-04 v1.26} + *{package}{moreverb} {2008/06/03 v2.3a} + *{package}{hhline} {2020/01/04 v2.04} + *{package}{tipa} {2002/08/08 v1.1} + *{package}{fontenc} {0000/00/00 v0.0} + *{file} {t3enc.def} {2001/12/31 v3} + *{file} {t1cmss.fd} {2023/04/13 v2.5m} + *{package}{xcolor} {2023/11/15 v3.01} + *{file} {color.cfg} {2016/01/02 v1.6} + *{file} {pdftex.def} {2022/09/22 v1.2b} + *{file} {mathcolor.ltx}{0000/00/00 v0.0} + *{package}{accents} {2006/05/12 v1.4} + *{package}{appendix} {2020/02/08 v1.2c} + *{package}{eucal} {2009/06/22 v3.00} + *{package}{ulem} {2019/11/18 v0.0} + *{package}{bm} {2023/07/08 v1.2f} + *{package}{bbm} {1999/03/15 v1.2} + *{package}{url} {2013/09/16 v3.4} + *{package}{optional} {2005/01/26 v2.2b;} + *{package}{natbib} {2010/09/13 v8.31b} + *{package}{footmisc} {2023/07/05 v6.0f} + *{package}{manyfoot} {2019/08/03 v1.11} + *{package}{nccfoots} {2005/02/03 v1.2} + *{package}{perpage} {2014/10/25 v2.0} + *{package}{./Resources/texmf-local/tex/latex/econtexSetup}{0000/00/00 v0.0} + *{package}{wasysym} {2020/01/19 v2.4} + *{package}{psibycus} {2004/10/18 v4.5} + *{file} {ibycus4.map} {0000/00/00 v0.0} + *{file} {Uibycus.fd} {2004/10/18 v4.5} + *{file} {iby4extr.tex}{0000/00/00 v0.0} + *{package}{ushort} {2001/06/13 v2.2} + *{package}{graphicx} {2021/09/16 v1.2d} + *{package}{graphics} {2022/03/10 v1.4e} + *{package}{trig} {2021/08/11 v1.11} + *{file} {graphics.cfg}{2016/06/04 v1.11} + *{package}{hyperref} {2024-01-20 v7.01h} + *{package}{kvsetkeys} {2022-10-05 v1.19} + *{package}{kvdefinekeys}{2019-12-19 v1.6} + *{package}{pdfescape} {2019/12/09 v1.15} + *{package}{hycolor} {2020-01-27 v1.10} + *{package}{auxhook} {2019-12-17 v1.6} + *{package}{nameref} {2023-11-26 v2.56} + *{package}{refcount} {2019/12/15 v3.6} + *{package}{gettitlestring}{2019/12/15 v1.6} + *{package}{kvoptions} {2022-06-15 v3.15} + *{file} {pd1enc.def} {2024-01-20 v7.01h} + *{package}{intcalc} {2019/12/15 v1.3} + *{file} {puenc.def} {2024-01-20 v7.01h} + *{package}{bitset} {2019/12/09 v1.3} + *{package}{bigintcalc} {2019/12/15 v1.5} + *{package}{atbegshi-ltx}{2021/01/10 v1.0c} + *{file} {hpdftex.def} {2024-01-20 v7.01h} + *{package}{atveryend-ltx}{2020/08/19 v1.0a} + *{package}{rerunfilecheck}{2022-07-10 v1.10} + *{package}{uniquecounter}{2019/12/15 v1.4} + *{package}{/Volumes/Sync/GitHub/llorracc/SolvingMicroDSOPs/SolvingMicroDSOPs-Latest/.resources/texmf-local/tex/latex/local-econark}{0000/00/00 v0.0} + *{package}{subfiles} {2020/11/14 v2.2} + *{package}{import} {2020/04/01 v6.2} + *{package}{xmpincl} {2021/09/22 v2.4} + *{package}{ifpdf} {2019/10/25 v3.4} + *{file} {t3cmr.fd} {2001/12/31 v0.0} + *{file} {translations-basic-dictionary-english.trsl}{(english v0.0} + *{file} {supp-pdf.mkii}{0000/00/00 v0.0} + *{package}{epstopdf-base}{2020-01-24 v2.11} + *{file} {epstopdf-sys.cfg}{2010/07/13 v1.3} + *{file} {NARK.out} {0000/00/00 v0.0} + *{file} {NARK.out} {0000/00/00 v0.0} + *{package}{bookmark} {2023-12-10 v1.31} + *{file} {bkm-pdftex.def}{2023-12-10 v1.31} + *{file} {t1cmtt.fd} {2023/04/13 v2.5m} + *{file} {umsa.fd} {2013/01/14 v3.01} + *{file} {umsb.fd} {2013/01/14 v3.01} + *{file} {ulasy.fd} {1998/08/17 v2.2e} + *{file} {uwasy.fd} {2020/01/19 v2.4} + *{file} {ueuf.fd} {2013/01/14 v3.01} + *{file} {ueus.fd} {2013/01/14 v3.01} +} diff --git a/Documentation/NARK/NARK.pdf b/Documentation/NARK/NARK.pdf index 9e911eaeb..d2a75486e 100644 Binary files a/Documentation/NARK/NARK.pdf and b/Documentation/NARK/NARK.pdf differ diff --git a/Documentation/NARK/NARK.tex b/Documentation/NARK/NARK.tex index 120a57ace..d0095a1ee 100755 --- a/Documentation/NARK/NARK.tex +++ b/Documentation/NARK/NARK.tex @@ -1,7 +1,8 @@ \input{./econtexRoot} \documentclass[12pt]{\econtex} \usepackage{\econtexSetup} -\usepackage{\econtexShortcuts} +%\usepackage{\econtexShortcuts} +\usepackage{/Volumes/Sync/GitHub/llorracc/SolvingMicroDSOPs/SolvingMicroDSOPs-Latest/.resources/texmf-local/tex/latex/local-econark} \usepackage{cancel} @@ -10,6 +11,7 @@ \title{Suggested Variable Naming Conventions \\ in the Econ-ARK Toolkit} +% \forcedate{2024-06-03} % Update for SMDSOPs-BST harmonization % \forcedate{2021-02-25} % Updates for HARK 1.0 release % \forcedate{2020-02-26} % Add sav, modl; other tweaks % \forcedate{2020-06-29} % Update date; shorten ALevBF; add @@ -66,7 +68,7 @@ \subsection{Single-Letter} A few exceptions to these rules are explicitly noted below the table. -When an alternative is needed with a meaning similar to, but distinct from, the definitions below, please use a multi-letter name to represent it. For example, please do not use $W$ for wealth (if some measure of wealth that differs from $\ALev$, $\BLev$, $\HLev$, or $\NLev$ is needed); instead use, say, \texttt{Wlth} or \texttt{Wealth}. (Some examples follow in a subsequent section). +When an alternative is needed with a meaning similar to, but distinct from, the definitions below, please use a multi-letter name to represent it. For example, please do not use $W$ for wealth (if some measure of wealth that differs from $\ALvl$, $\BLvl$, $\HLvl$, or $\NLvl$ is needed); instead use, say, \texttt{Wlth} or \texttt{Wealth}. (Some examples follow in a subsequent section). Finally, a few of the definitions below are actually prohibitions; these are based on many years of experience which have shown that use of the prohibited variable name generates more confusion than clarity. @@ -76,33 +78,33 @@ \subsection{Single-Letter} \begin{tabular}{|lcl|} \hline Letter & & Meaning \\ \hline - \ALev & & \textit{A}ssets \textit{A}fter \textit{A}ll \textit{A}ctions \textit{A}re \textit{A}ccomplished (end of period) - \\ \BLev & & \textit{B}eginning \textit{B}ank \textit{B}alances \textit{B}efore any \textit{B}ehavior (\textit{b}eginning-of-period) - \\ \CLev & & \textit{C}onsumption \textit{C}hoice \textit{C}onnects $B$ to $A$ - \\ \DLev & & \textit{D}ebt - \\ \ELev & & PROHIBITED: Too many possible meanings (expectations, effort, expenses) - \\ \FLev & & Production \textit{F}unction - \\ \GLev & & \textit{G}rowth - \\ \HLev & & \textit{H}uman wealth - \\ \ILev & & \textit{I}nvestment - \\ \JLev & & Ad\textit{J}ustment costs (e.g., in a $Q$ model) - \\ \KLev & & Capital or beginning of period nonhuman assets - \\ \LLev & & PROHIBITED: Is it Labor or Leisure or Land or ...? - \\ \MLev & & \textit{M}arket resources (the sum of capital, capital income, and labor income) - \\ \NLev & & \textit{N}et wealth including human wealth ($=B + H$) - \\ \OLev & & PROHIBITED: Too similar to the number 0; too many possible meanings - \\ \PLev & & PROHIBITED: Is it prices, permanent income, present value, profits, ...? - \\ \QLev & & Hayashi/Abel $Q$ (or similar asset price) - \\ \RLev & & \textit{R}eturn (see the variants articulated below) - \\ \SLev & & PROHIBITED: ``saving'' (flow)? ``savings'' (stock)? or the ``saving rate'' (ratio)? - \\ \TLev & & This is a tough one. See the discussion below. - \\ \ULev & & \textit{U}tility - \\ \VLev & & \textit{V}alue - \\ \WLev & & \textit{W}age - \\ \XLev & & e\textit{X}penditures (as distinct from consumption; e.g., for durables) - \\ \YLev & & Noncapital income (usually, the sum of transfer and labor income) - \\ \ZLev & & Lei\textit{Z}ure in consumption/leisure tradeoff - \\ \hline + A & & \textit{A}ssets \textit{A}fter \textit{A}ll \textit{A}ctions \textit{A}re \textit{A}ccomplished (end of period)\\ + B & & \textit{B}ank \textit{B}alances \textit{B}efore any \textit{B}ehavior (\textit{b}eginning-of-period)\\ + C & & \textit{C}onsumption \textit{C}hoice \textit{C}onnects $B$ to $A$\\ + D & & \textit{D}ebt\\ + E & & PROHIBITED: Too many possible meanings (expectations, effort, expenses)\\ + F & & Production \textit{F}unction\\ + G & & \textit{G}rowth\\ + H & & \textit{H}uman wealth\\ + I & & \textit{I}nvestment\\ + J & & Ad\textit{J}ustment costs (e.g., in a $Q$ model)\\ + K & & Capital or beginning of period nonhuman assets\\ + L & & PROHIBITED: Is it Labor or Leisure or Land or ...?\\ + M & & \textit{M}arket resources (the sum of capital, capital income, and labor income)\\ + N & & \textit{N}et wealth including human wealth ($=B + H$)\\ + O & & PROHIBITED: Too similar to the number 0; too many possible meanings\\ + P & & PROHIBITED: Is it prices, permanent income, present value, profits, ...?\\ + Q & & Hayashi/Abel $Q$ (or similar asset price)\\ + R & & \textit{R}eturn (see the variants articulated below)\\ + S & & PROHIBITED: ``saving'' (flow)? ``savings'' (stock)? or the ``saving rate'' (ratio)?\\ + T & & This is a tough one. See the discussion below.\\ + U & & \textit{U}tility\\ + V & & \textit{V}alue\\ + W & & \textit{W}age\\ + X & & e\textit{X}penditures (as distinct from consumption; e.g., for durables)\\ + Y & & Noncapital income (usually, the sum of transfer and labor income)\\ + Z & & Lei\textit{Z}ure in consumption/leisure tradeoff\\ + \\ \hline \end{tabular} \caption{Preferred Usages of Roman Letters} \label{table:RomanLetters} @@ -110,7 +112,7 @@ \subsection{Single-Letter} \subsection{Exceptions to the Rules} -The letter $\TLev$ is an exception to the rule that lower- and upper-case versions of variables are individual and aggregate quantities. We reserve the capital letter to designate the end of the horizon (death, or the end of the economy, occurs at the end of period $\TLev$). The lower case version $t$ is so ubiquitiously used as the current time period that we follow that convention here. +The letter $\TLvl$ is an exception to the rule that lower- and upper-case versions of variables are individual and aggregate quantities. We reserve the capital letter to designate the end of the horizon (death, or the end of the economy, occurs at the end of period $\TLvl$). The lower case version $t$ is so ubiquitiously used as the current time period that we follow that convention here. Finally, the following are exempted from the prohibition on single-letter variable names because they are used so frequently that the prohibition would be more trouble than it is worth: $a$, $b$, $c$, $m$. @@ -124,7 +126,6 @@ \subsection{Standard Variable Names} \begin{table}[ht] \centering \begin{tabular}{|rcl|} - \hline Name & - & Description \\ \hline \texttt{CND} & - & Consumption of Nondurable Good @@ -193,8 +194,8 @@ \section{Factors and Rates} \hline Code & \LaTeX & Description & \\ \hline - \verb|\DiePrb| & $\DiePrb$ & Probabilty of death & - \\ \verb|\LivPrb| & $\LivPrb$ & Probability to not die $=(1-\DiePrb)$ & + \verb|\DiePrb| & $\DiePrb$ or $\cancel{\Alive}$ & Probabilty of death ($\DiePrb=\Alive-1$) & + \\ \verb|\LivPrb| & $\LivPrb$ or $\Alive$ & Probability to not die $\Alive=(1-\DiePrb)$ & \\ \hline \end{tabular} \caption{Special Cases: Factors and Rates} @@ -217,30 +218,31 @@ \section{Parameters} \centering \begin{tabular}{|>{\ttfamily}rcll|} \hline - Name & \LaTeX & Description & Illustration + Name & \LaTeX & Description & Illustration \\ \hline - \verb|\CARA| & $\CARA$ & Coefficient of Absolute Risk Aversion &$\uFunc(\bullet)=-\CARA^{-1} e^{-\CARA \bullet}$ + \verb|\CARA| & $\CARA$ & Coefficient of Absolute Risk Aversion &$\uFunc(\bullet)=-\CARA^{-1} e^{-\CARA \bullet}$ \\ \verb|\CRRA| & $\CRRA$ & Coefficient of Relative Risk Aversion & $\uFunc(\bullet)=(1-\CRRA)^{-1}\bullet^{1-\CRRA}$ - \\ \verb|\DiscFac| & $\DiscFac$ & Time Discount Factor & $\uFunc^{\prime}(\cLev_{t}) = \Rfree \DiscFac \uFunc^{\prime}(\cLev_{t+1})$ + \\ \verb|\DiscFac| & $\DiscFac$ & Time Discount Factor & $\uFunc^{\prime}(\cLvl_{t}) = \Rfree \DiscFac \uFunc^{\prime}(\cLvl_{t+1})$ \\ \verb|\discRte| & $\discRte$ & Time Discount rate & $\discRte=\DiscFac^{-1}-1$ - \\ \verb|\DeprFac| & $\DeprFac$ & Depreciation Factor (Hebrew \texttt{daleth}) & $\Kap_{t+1} = \DeprFac \Kap_{t}+\ILev_{t}$ + \\ \verb|\DeprFac| & $\DeprFac$ & Depreciation Factor (Hebrew \texttt{daleth}) & $\Kap_{t+1} = \DeprFac \Kap_{t}+\ILvl_{t}$ \\ \verb|\deprRte| & $\deprRte$ & Depreciation Rate & $\DeprFac = 1-\deprRte$ \\ \verb|\TranShkAgg| & $\TranShkAgg$ & Transitory shock (aggregate) & $\Ex_{t}[\TranShkAgg_{t+n}]=1$ if $\TranShkAgg$ iid \\ \verb|\tranShkInd| & $\tranShkInd$ & Transitory shock (individual) & $\Ex_{t}[\tranShkInd_{t+n}]=1$ if $\tranShkInd$ iid + \\ \verb|\tranShkEmp| & $\tranShkEmp$ & Transitory shock (individual, employed) & $\Ex_{t}[\tranShkInd_{t+n}]=1$ if $\tranShkInd$ iid \\ \verb|\PermShkAgg| & $\PermShkAgg$ & Permanent shock (aggregate) & $\Ex_{t}[\PermShkAgg_{t+n}]=1$ if $\PermShkAgg$ iid \\ \verb|\permShkInd| & $\permShkInd$ & Permanent shock (individual) & $\Ex_{t}[\permShkInd_{t+n}]=1$ if $\permShkInd$ iid - \\ \verb|\PopGro| & $\PopGro$ & Population Growth Factor & $\mathtt{Pop}_{t+1} = \PopGro \mathtt{Pop}_{t}$ - \\ \verb|\popGro| & $\popGro$ & Population Growth rate & $\PopGro = 1 + \popGro$ - \\ \verb|\PtyGro| & $\PtyGro$ & Productivity Growth Factor & $\GLev = \PtyGro \PopGro$ - \\ \verb|\ptyGro| & $\ptyGro$ & Productivity Growth rate & $\PtyGro = (1+\ptyGro)$ - \\ \verb|\leiShare| & $\leiShare$ & Leisure share, Cobb-Douglas utility & $\uFunc(c,z)=(1-\CRRA)^{-1}(c^{1-\leiShare}z^{\leiShare})^{1-\CRRA}$ - \\ \verb|\MPC| & $\MPC$ & Marginal Propensity to Consume & $\cFunc^{\prime}(\mRat)=\partial c/\partial m$ - \\ \verb|\Pat| & $\Pat$ & Absolute Patience Factor (\texttt{Thorn}) & $\Pat = (\Rfree \DiscFac)^{1/\CRRA} $ - \\ \verb|\PatPGro| & $\PatPGro$ & Growth Patience Factor (\texttt{Thorn}) & $\Pat = (\Rfree \DiscFac)^{1/\CRRA}/\PtyGro $ - \\ \verb|\PatR| & $\PatR$ & Return Patience Factor (\texttt{Thorn}) & $\Pat = (\Rfree \DiscFac)^{1/\CRRA}/\Rfree $ - \\ \verb|\pat| & $\pat$ & Absolute Patience rate (\texttt{thorn}) & $\pat = (\Rfree \DiscFac)^{1/\CRRA}-1 \approx \CRRA^{-1}(\rfree-\discRte) $ - \\ \verb|\patpGro| & $\patpGro$ & Growth Patience rate (\texttt{thorn}) & $\patpGro = \pat -\ptyGro $ - \\ \verb|\patr| & $\patr$ & Return Patience rate (\texttt{thorn}) & $\patr =\pat -\rfree $ + \\ \verb|\PopGroFac| & $\PopGroFac$ & Population Growth Factor & $\mathtt{Pop}_{t+1} = \PopGroFac \mathtt{Pop}_{t}$ + \\ \verb|\popGroRte| & $\popGroRte$ & Population Growth rate & $\PopGroFac = 1 + \popGroRte$ + \\ \verb|\PtyGroFac| & $\PtyGroFac$ & Productivity Growth Factor & $\GLvl = \PtyGroFac \PopGroFac$ + \\ \verb|\ptyGroRte| & $\ptyGroRte$ & Productivity Growth rate & $\PtyGroFac = (1+\ptyGroRte)$ + \\ \verb|\leiShare| & $\leiShare$ & Leisure share, Cobb-Douglas utility & $\uFunc(c,z)=(1-\CRRA)^{-1}(c^{1-\leiShare}z^{\leiShare})^{1-\CRRA}$ + \\ \verb|\MPC| & $\MPC$ & Marginal Propensity to Consume & $\cFunc^{\prime}(\mNrm)=\partial c/\partial m$ + \\ \verb|\APFac| & $\APFac$ & Absolute Patience Factor (\texttt{Thorn}) & $\APFac = (\Rfree \DiscFac)^{1/\CRRA} $ + \\ \verb|\GPFac| & $\APFac$ & Growth Patience Factor (\texttt{Thorn}) & $\APFac = (\Rfree \DiscFac)^{1/\CRRA}/\PtyGroFac$ + \\ \verb|\RPFac| & $\RPFac$ & Return Patience Factor (\texttt{Thorn}) & $\APFac = (\Rfree \DiscFac)^{1/\CRRA}/\Rfree $ + \\ \verb|\APRte| & $\APRte$ & Absolute Patience rate (\texttt{thorn}) & $\APRte = (\Rfree \DiscFac)^{1/\CRRA}-1 \approx \CRRA^{-1}(\rfree-\discRte) $ + \\ \verb|\GPRte| & $\GPRte$ & Growth Patience rate (\texttt{thorn}) & $\GPRte = \APRte -\ptyGroRte $ + \\ \verb|\RPRte| & $\RPRte$ & Return Patience rate (\texttt{thorn}) & $\RPRte =\APRte -\rfree $ \\ \verb|\riskyshare| & $\riskyshare$ & Portfolio share in risky assets & $\Rport_{t+1}=(1-\riskyshare)\Rfree+\riskyshare\Risky_{t+1}$ \\ \hline \end{tabular} @@ -251,9 +253,9 @@ \section{Parameters} Mnemonics: \begin{itemize} \item Hebrew \texttt{daleth} is the fourth letter of the Hebrew alphabet (as d and $\delta$ are of the Roman and Greek) and is an etymological and linguistic cousin of those letters -\item $\discRte$ is the lower case Greek letter \texttt{omega}, because people say ``OMG, I've got to think about the future.'' +\item $\discRte$ is the lower case Greek letter \texttt{nu}, because newness is about the future \item You are invited to scrutinize $\Xi$ yourself to imagine reasons it could represent something to do with population growth. -\item The glorious letter $\Pat$ (pronounced `\href{https://en.wikipedia.org/wiki/Thorn_(letter)}{thorn}') enriched Old English, Gothic, and some other defunct alphabets; sadly, it remains in use today only in Iceland. It is useful because having to type the many symbols in the object $(\Rfree \DiscFac)^{1/\CRRA}$ over and over again is a \textit{thorn} in the side of economists working with dynamic models! (It is the `absolute patience factor' because if it is less than one the consumer wants to bring resources from the future to the present and is therefore absolutely impatient; for a fuller discussion of this terminology, see \cite{carrollTractable}.) +\item The glorious letter $\APFac$ (pronounced `\href{https://en.wikipedia.org/wiki/Thorn_(letter)}{thorn}') enriched Old English, Gothic, and some other defunct alphabets; sadly, it remains in use today only in Iceland. It is useful because having to type the many symbols in the object $(\Rfree \DiscFac)^{1/\CRRA}$ over and over again is a \textit{thorn} in the side of economists working with dynamic models! (It is the `absolute patience factor' because if it is less than one the consumer wants to bring resources from the future to the present and is therefore absolutely impatient; for a fuller discussion of this terminology, see \cite{carrollTractable}.) \end{itemize} @@ -267,7 +269,7 @@ \section{Operators} \hline Name & \LaTeX & Code & Description & Illustration \\ \hline - \verb|\Ex| & $\Ex$ & \texttt{Ex\_} & The expectation as of date $t$ & $\Ex_{t}[\uFunc^{\prime}(\cRat_{t+1})]$ + \verb|\Ex| & $\Ex$ & \texttt{Ex\_} & The expectation as of date $t$ & $\Ex_{t}[\uFunc^{\prime}(\cNrm_{t+1})]$ \\ \verb|\PDV| & $\PDV$ & \texttt{PDV\_} & Present Discounted Value & $\PDV_{t}^{T}(y)$ is human wealth \\ \hline \end{tabular} @@ -283,8 +285,6 @@ \section{Modifiers} \centering \begin{tabular}{|>{\ttfamily}lcl|} \hline - \textit{[object]}\texttt{P} & - & ``Prime'' means derivative, e.g.\ \texttt{vPP} is the second derivative of value: $\vFunc^{\prime\prime}$ -\\ \hline \textit{[object]}\texttt{Agg} & - & Value of something at the aggregate level (as opposed to \texttt{Ind}) \\ \textit{[object]}\texttt{Ind} & - & Value of something at the level of an individual (as opposed to \texttt{Agg}) \\ \textit{[object]}\texttt{Lvl} & - & Level @@ -301,12 +301,11 @@ \section{Modifiers} \\ \textit{[object]}\texttt{Rte} & - & A `rate' variable like the discount rate $\discRte$ \\ \textit{[object]}\texttt{Fac} & - & A factor variable like the discount factor $\DiscFac$ \\ \textit{[object]}\texttt{Amt} & - & An amount, like \texttt{TaxAmt} which might be lump-sum - \\ \textit{[object]}\texttt{Nrm} & - & A normalized quantity; ex: \texttt{RNrm}=$\Rfree/\PGro$ - \\ \hline - \\ \textit{[object]}\texttt{Abve} & - & Range of points ABOvE some boundary + \\ \textit{[object]}\texttt{Nrm} & - & A normalized quantity; ex: \texttt{RNrm}=$\Rfree/\PtyGroFac$ + \\ \textit{[object]}\texttt{Abve} & - & Range of points ABoVE some boundary \\ \textit{[object]}\texttt{Belw} & - & Range of points BELoW some boundary \\ \textit{[object]}\texttt{Grid} & - & Points to be used as a grid for interpolations - \\ \textit{[object]}\texttt{Xtra} & - & An ``extra'' set of points to be added to some existing set + \\ \textit{[object]}\texttt{Xtra} & - & An ``extra'' set of points to be added to some existing set \\ \hline \end{tabular} \caption{General Purpose Modifiers} \label{table:General} diff --git a/HARK/__init__.py b/HARK/__init__.py index bc0da6990..fec3e06ee 100644 --- a/HARK/__init__.py +++ b/HARK/__init__.py @@ -1,6 +1,6 @@ from .core import * -__version__ = "0.14.1" +__version__ = "0.15.0" """ Logging tools for HARK. diff --git a/HARK/model.py b/HARK/model.py index d1b0ee46a..c97a2ad76 100644 --- a/HARK/model.py +++ b/HARK/model.py @@ -3,7 +3,15 @@ """ from dataclasses import dataclass, field -from HARK.distribution import Distribution +from HARK.distribution import ( + Distribution, + DiscreteDistributionLabeled, + combine_indep_dstns, + expected, +) +from inspect import signature +import numpy as np +from typing import Any, Callable, Mapping, List, Union class Aggregate: @@ -31,6 +39,101 @@ def __init__(self, args): pass +def discretized_shock_dstn(shocks, disc_params): + """ + Discretizes a collection of independent shocks and combines + them into one DiscreteDistributionLabeled. + + Shocks are discretized only if they have a corresponding + element of disc_params defined. + + Parameters + ----------- + shocks: dict of Distribution + A dictionary of Distributions, representing independent exogenous shocks. + + disc_params: dict of dict + A dictionary of dictionaries with arguments to Distribution.discretize. + Keys of this dictionary should be shared with the shocks argument. + """ + dshocks = {} + + for shockn in shocks: + if shockn == "live": # hacky hack + pass + elif shockn in disc_params: + dshocks[shockn] = DiscreteDistributionLabeled.from_unlabeled( + shocks[shockn].discretize(**disc_params[shockn]), var_names=[shockn] + ) + else: + # assume already discrete + dshocks[shockn] = DiscreteDistributionLabeled.from_unlabeled( + shocks[shockn], var_names=[shockn] + ) + + all_shock_dstn = combine_indep_dstns(*dshocks.values()) + + return all_shock_dstn + + +def simulate_dynamics( + dynamics: Mapping[str, Union[Callable, Control]], + pre: Mapping[str, Any], + dr: Mapping[str, Callable], +): + """ + From the beginning-of-period state (pre), follow the dynamics, + including any decision rules, to compute the end-of-period state. + + Parameters + ------------ + + dynamics: Mapping[str, Callable] + Maps variable names to functions from variables to values. + Can include Controls + ## TODO: Make collection of equations into a named type + + + pre : Mapping[str, Any] + Bound values for all variables that must be known before beginning the period's dynamics. + + + dr : Mapping[str, Callable] + Decision rules for all the Control variables in the dynamics. + """ + vals = pre.copy() + + for varn in dynamics: + # Using the fact that Python dictionaries are ordered + + feq = dynamics[varn] + + if isinstance(feq, Control): + # This tests if the decision rule is age varying. + # If it is, this will be a vector with the decision rule for each agent. + if isinstance(dr[varn], np.ndarray): + ## Now we have to loop through each agent, and apply the decision rule. + ## This is quite slow. + for i in range(dr[varn].size): + vals_i = { + var: vals[var][i] + if isinstance(vals[var], np.ndarray) + else vals[var] + for var in vals + } + vals[varn][i] = dr[varn][i]( + *[vals_i[var] for var in signature(dr[varn][i]).parameters] + ) + else: + vals[varn] = dr[varn]( + *[vals[var] for var in signature(dr[varn]).parameters] + ) # TODO: test for signature match with Control + else: + vals[varn] = feq(*[vals[var] for var in signature(feq).parameters]) + + return vals + + @dataclass class DBlock: """ @@ -48,3 +151,138 @@ class DBlock: shocks: dict = field(default_factory=dict) dynamics: dict = field(default_factory=dict) reward: dict = field(default_factory=dict) + + def get_shocks(self): + return self.shocks + + def get_dynamics(self): + return self.dynamics + + def get_vars(self): + return list(self.shocks.keys()) + list(self.dynamics.keys()) + + def transition(self, pre, dr): + """ + Returns variable values given previous values and decision rule for all controls. + """ + return simulate_dynamics(self.dynamics, pre, dr) + + def calc_reward(self, vals): + """ + Computes the reward for a given set of variable values + """ + rvals = {} + + for varn in self.reward: + feq = self.reward[varn] + rvals[varn] = feq(*[vals[var] for var in signature(feq).parameters]) + + return rvals + + def get_state_rule_value_function_from_continuation(self, continuation): + """ + Given a continuation value function, returns a state-rule value + function: the value for each state and decision rule. + This value includes both the reward for executing the rule + 'this period', and the continuation value of the resulting states. + """ + + def state_rule_value_function(pre, dr): + vals = self.transition(pre, dr) + r = list(self.calc_reward(vals).values())[0] # a hack; to be improved + cv = continuation( + *[vals[var] for var in signature(continuation).parameters] + ) + + return r + cv + + return state_rule_value_function + + def get_decision_value_function(self, dr, continuation): + """ + Given a decision rule and a continuation value function, + return a function for the value at the decision step/tac, + after the shock have been realized. + """ + srvf = self.get_state_rule_value_function_from_continuation(continuation) + + def decision_value_function(shpre): + return srvf(shpre, dr) + + return decision_value_function + + def get_arrival_value_function(self, disc_params, dr, continuation): + """ + Returns an arrival value function, which is the value of the states + upon arrival into the block. + + This involves taking an expectation over shocks (which must + first be discretized), a decision rule, and a continuation + value function.) + """ + + def arrival_value_function(arvs): + dvf = self.get_decision_value_function(dr, continuation) + + ds = discretized_shock_dstn(self.shocks, disc_params) + + arvs_args = [arvs[avn] for avn in arvs] + + def mod_dvf(shock_value_array): + shockvs = { + shn: shock_value_array[shn] + for i, shn in enumerate(list(ds.variables.keys())) + } + + dvf_args = {} + dvf_args.update(arvs) + dvf_args.update(shockvs) + + return dvf(dvf_args) + + return expected(func=mod_dvf, dist=ds) + + return arrival_value_function + + +@dataclass +class RBlock: + """ + A recursive block. + + Parameters + ---------- + ... + """ + + name: str = "" + description: str = "" + blocks: List[DBlock] = field(default_factory=list) + + def get_shocks(self): + ### TODO: Bug in here is causing AttributeError: 'set' object has no attribute 'draw' + + super_shocks = {} # uses set to avoid duplicates + + for b in self.blocks: + for k, v in b.get_shocks().items(): # use d.iteritems() in python 2 + super_shocks[k] = v + + return super_shocks + + def get_controls(self): + dyn = self.get_dynamics() + + return [varn for varn in dyn if isinstance(dyn[varn], Control)] + + def get_dynamics(self): + super_dyn = {} # uses set to avoid duplicates + + for b in self.blocks: + for k, v in b.get_dynamics().items(): # use d.iteritems() in python 2 + super_dyn[k] = v + + return super_dyn + + def get_vars(self): + return list(self.get_shocks().keys()) + list(self.get_dynamics().keys()) diff --git a/HARK/models/consumer.py b/HARK/models/consumer.py new file mode 100644 index 000000000..bee7b102a --- /dev/null +++ b/HARK/models/consumer.py @@ -0,0 +1,88 @@ +from HARK.distribution import Bernoulli, Lognormal, MeanOneLogNormal +from HARK.model import Control, DBlock, RBlock + +""" +Blocks for consumption saving problem (not normalized) +in the style of Carroll's "Solution Methods for Solving +Microeconomic Dynamic Stochastic Optimization Problems" +""" + +# TODO: Include these in calibration, then construct shocks +LivPrb = 0.98 +TranShkStd = 0.1 +RiskyStd = 0.1 + +calibration = { + "DiscFac": 0.96, + "CRRA": 2.0, + "R": 1.03, # note: this can be overriden by the portfolio dynamics + "Rfree": 1.03, + "EqP": 0.02, + "LivPrb": LivPrb, + "PermGroFac": 1.01, + "BoroCnstArt": None, +} + +consumption_block = DBlock( + **{ + "name": "consumption", + "shocks": { + "live": Bernoulli(p=LivPrb), # Move to tick or mortality block? + "theta": MeanOneLogNormal(sigma=TranShkStd), + }, + "dynamics": { + "b": lambda k, R: k * R, + "y": lambda p, theta: p * theta, + "m": lambda b, y: b + y, + "c": Control(["m"]), + "p": lambda PermGroFac, p: PermGroFac * p, + "a": lambda m, c: m - c, + }, + "reward": {"u": lambda c, CRRA: c ** (1 - CRRA) / (1 - CRRA)}, + } +) + +consumption_block_normalized = DBlock( + **{ + "name": "consumption normalized", + "shocks": { + "live": Bernoulli(p=LivPrb), # Move to tick or mortality block? + "theta": MeanOneLogNormal(sigma=TranShkStd), + }, + "dynamics": { + "b": lambda k, R, PermGroFac: k * R / PermGroFac, + "m": lambda b, theta: b + theta, + "c": Control(["m"]), + "a": lambda m, c: m - c, + }, + "reward": {"u": lambda c, CRRA: c ** (1 - CRRA) / (1 - CRRA)}, + } +) + +portfolio_block = DBlock( + **{ + "name": "portfolio", + "shocks": { + "risky_return": Lognormal.from_mean_std( + calibration["Rfree"] + calibration["EqP"], RiskyStd + ) + }, + "dynamics": { + "stigma": Control(["a"]), + "R": lambda stigma, Rfree, risky_return: Rfree + + (risky_return - Rfree) * stigma, + }, + } +) + +tick_block = DBlock( + **{ + "name": "tick", + "dynamics": { + "k": lambda a: a, + }, + } +) + +cons_problem = RBlock(blocks=[consumption_block, tick_block]) +cons_portfolio_problem = RBlock(blocks=[consumption_block, portfolio_block, tick_block]) diff --git a/HARK/models/test_models.py b/HARK/models/test_models.py index 9d0bbd9f2..9cb9152d1 100644 --- a/HARK/models/test_models.py +++ b/HARK/models/test_models.py @@ -1,4 +1,5 @@ from HARK.distribution import Lognormal +import HARK.models.consumer as cons import HARK.models.perfect_foresight as pfm import HARK.models.perfect_foresight_normalized as pfnm from HARK.simulation.monte_carlo import AgentTypeMonteCarloSimulator @@ -67,3 +68,80 @@ def test_simulate(self): ## smoke test self.mcs.initialize_sim() self.mcs.simulate() + + +class test_pfnm(unittest.TestCase): + def setUp(self): + self.mcs = AgentTypeMonteCarloSimulator( ### Use fm, blockified + pfnm.calibration, + pfnm.block, + {"c_nrm": lambda m_nrm: PFexample.solution[0].cFunc(m_nrm)}, + { # initial states + "a_nrm": Lognormal(-6, 0), + #'live' : 1, + "p": 1.0, + }, + agent_count=3, + T_sim=120, + ) + + def test_simulate(self): + ## smoke test + self.mcs.initialize_sim() + self.mcs.simulate() + + +class test_consumer_models(unittest.TestCase): + def setUp(self): + self.cs = AgentTypeMonteCarloSimulator( ### Use fm, blockified + cons.calibration, + cons.cons_problem, ### multiple cons blocks! + { + "c": lambda m: PFexample.solution[0].cFunc(m), + # danger: normalized decision rule for unnormalized problem + }, + { # initial states + "k": Lognormal(-6, 0), + #'live' : 1, + "p": 1.0, + }, + agent_count=2, + T_sim=5, + ) + + self.pcs = AgentTypeMonteCarloSimulator( ### Use fm, blockified + cons.calibration, + cons.cons_portfolio_problem, ### multiple cons blocks! + { + "c": lambda m: m / 2, + # danger: normalized decision rule for unnormalized problem + "stigma": lambda a: a / (2 + a), + # just a dummy share func + }, + { # initial states + "k": Lognormal(-6, 0), + #'live' : 1, + "p": 1.0, + "R": 1.03, + }, + agent_count=2, + T_sim=5, + ) + + def test_simulate(self): + self.cs.initialize_sim() + self.cs.simulate() + + self.assertEqual(self.cs.calibration["R"], 1.03) + self.assertFalse("R" in self.cs.history) + + self.pcs.initialize_sim() + self.pcs.simulate() + + self.assertFalse("R" in self.cs.history) + + # test to see if the R value is + # as calibrated for cons + # and dynamic for the portfolio model + + self.assertTrue(self.pcs.history["R"][0][0] != 1.03) diff --git a/HARK/simulation/monte_carlo.py b/HARK/simulation/monte_carlo.py index bcd406a0e..fcae5f31a 100644 --- a/HARK/simulation/monte_carlo.py +++ b/HARK/simulation/monte_carlo.py @@ -3,8 +3,7 @@ """ from copy import copy -from inspect import signature -from typing import Any, Callable, Mapping, Sequence, Union +from typing import Mapping, Sequence import numpy as np @@ -13,8 +12,9 @@ IndexDistribution, TimeVaryingDiscreteDistribution, ) -from HARK.model import Aggregate, Control +from HARK.model import Aggregate from HARK.model import DBlock +from HARK.model import simulate_dynamics def draw_shocks(shocks: Mapping[str, Distribution], conditions: Sequence[int]): @@ -55,64 +55,6 @@ def draw_shocks(shocks: Mapping[str, Distribution], conditions: Sequence[int]): return draws -def simulate_dynamics( - dynamics: Mapping[str, Union[Callable, Control]], - pre: Mapping[str, Any], - dr: Mapping[str, Callable], -): - """ - From the beginning-of-period state (pre), follow the dynamics, - including any decision rules, to compute the end-of-period state. - - Parameters - ------------ - - dynamics: Mapping[str, Callable] - Maps variable names to functions from variables to values. - Can include Controls - ## TODO: Make collection of equations into a named type - - - pre : Mapping[str, Any] - Bound values for all variables that must be known before beginning the period's dynamics. - - - dr : Mapping[str, Callable] - Decision rules for all the Control variables in the dynamics. - """ - vals = pre.copy() - - for varn in dynamics: - # Using the fact that Python dictionaries are ordered - - feq = dynamics[varn] - - if isinstance(feq, Control): - # This tests if the decision rule is age varying. - # If it is, this will be a vector with the decision rule for each agent. - if isinstance(dr[varn], np.ndarray): - ## Now we have to loop through each agent, and apply the decision rule. - ## This is quite slow. - for i in range(dr[varn].size): - vals_i = { - var: vals[var][i] - if isinstance(vals[var], np.ndarray) - else vals[var] - for var in vals - } - vals[varn][i] = dr[varn][i]( - *[vals_i[var] for var in signature(dr[varn][i]).parameters] - ) - else: - vals[varn] = dr[varn]( - *[vals[var] for var in signature(dr[varn]).parameters] - ) # TODO: test for signature match with Control - else: - vals[varn] = feq(*[vals[var] for var in signature(feq).parameters]) - - return vals - - def calibration_by_age(ages, calibration): """ Returns calibration for this model, but with vectorized @@ -196,8 +138,9 @@ def __init__( super().__init__() self.calibration = calibration - self.shocks = block.shocks - self.dynamics = block.dynamics + self.block = block + self.shocks = block.get_shocks() + self.dynamics = block.get_dynamics() self.dr = dr self.initial = initial @@ -206,7 +149,7 @@ def __init__( self.T_sim = T_sim # changes here from HARK.core.AgentType - self.vars = list(self.shocks.keys()) + list(self.dynamics.keys()) + self.vars = block.get_vars() self.vars_now = {v: None for v in self.vars} self.vars_prev = self.vars_now.copy() diff --git a/HARK/tests/test_model.py b/HARK/tests/test_model.py index 26b1a7c5e..f5b2db434 100644 --- a/HARK/tests/test_model.py +++ b/HARK/tests/test_model.py @@ -3,6 +3,7 @@ from HARK.distribution import Bernoulli import HARK.model as model from HARK.model import Control +import HARK.models.consumer as cons # TODO: let the shock constructor reference this parameter. LivPrb = 0.98 @@ -22,10 +23,69 @@ "reward": {"u": lambda c, CRRA: c ** (1 - CRRA) / (1 - CRRA)}, } +test_block_B_data = {"name": "test block B", "shocks": {"SB": Bernoulli(p=0.1)}} + +test_block_C_data = {"name": "test block B", "shocks": {"SC": Bernoulli(p=0.2)}} + +test_block_D_data = {"name": "test block D", "shocks": {"SD": Bernoulli(p=0.3)}} + class test_DBlock(unittest.TestCase): def setUp(self): self.test_block_A = model.DBlock(**test_block_A_data) + self.cblock = cons.consumption_block_normalized + + # prior states relative to the decision, so with realized shocks. + self.dpre = {"k": 2, "R": 1.05, "PermGroFac": 1.1, "theta": 1, "CRRA": 2} + + # simple decision rule + self.dr = {"c": lambda m: m} def test_init(self): self.assertEqual(self.test_block_A.name, "test block A") + + def test_transition(self): + post = self.cblock.transition(self.dpre, self.dr) + + self.assertEqual(post["a"], 0) + + def test_calc_reward(self): + self.assertEqual(self.cblock.calc_reward({"c": 1, "CRRA": 2})["u"], -1.0) + + def test_state_rule_value_function(self): + savf = self.cblock.get_state_rule_value_function_from_continuation(lambda a: 0) + + dv0 = savf(self.dpre, self.dr) + + self.assertEqual(dv0, -0.34375) + + cv = 1 + # note change in continuation value here. + dv1 = self.cblock.get_decision_value_function(self.dr, lambda a: cv)(self.dpre) + + self.assertEqual(dv1, dv0 + cv) + + def test_arrival_value_function(self): + av = self.cblock.get_arrival_value_function( + {"theta": {"N": 5}}, {"c": lambda m: m}, lambda a: 0 + ) + + av({"k": 1, "R": 1.05, "PermGroFac": 1.1, "theta": 1, "CRRA": 2}) + + +class test_RBlock(unittest.TestCase): + def setUp(self): + self.test_block_B = model.DBlock(**test_block_B_data) + self.test_block_C = model.DBlock(**test_block_C_data) + self.test_block_D = model.DBlock(**test_block_D_data) + + def test_init(self): + r_block_tree = model.RBlock( + blocks=[ + self.test_block_B, + model.RBlock(blocks=[self.test_block_C, self.test_block_D]), + ] + ) + + r_block_tree.get_shocks() + self.assertEqual(len(r_block_tree.get_shocks()), 3) diff --git a/examples/Blocks/Model Setup Demo.ipynb b/examples/Blocks/Model Setup Demo.ipynb new file mode 100644 index 000000000..ef723aa0b --- /dev/null +++ b/examples/Blocks/Model Setup Demo.ipynb @@ -0,0 +1,270 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "78e88e29", + "metadata": {}, + "outputs": [], + "source": [ + "from HARK.model import RBlock" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "530a91d0", + "metadata": {}, + "outputs": [], + "source": [ + "def rblock_arrival_value(states):\n", + " return \"tbd\"\n", + "\n", + "\n", + "def solution_objects(stg):\n", + " if callable(stg):\n", + " return stg\n", + " elif isinstance(stg, RBlock):\n", + " return [rblock_arrival_value] + stg.get_controls()\n", + "\n", + "\n", + "def solution(interval):\n", + " return [solution_objects(stg) for stg in interval]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "035c6056", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "DBlock(name='tick', description='', shocks={}, dynamics={'k': at 0x715bbbf2dbd0>}, reward={})" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "## This contains model data, which will later be contained in a YAML file\n", + "import HARK.models.consumer as cons\n", + "\n", + "# Specifically there are these objects, which would be produced from the parsed YAML\n", + "cons.consumption_block_normalized\n", + "cons.portfolio_block\n", + "cons.tick_block" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "b6eadbc6", + "metadata": {}, + "outputs": [], + "source": [ + "## create empty two-period-model object\n", + "##>>> mdl2prd = HARK2.modelMake(modelKind=finiteHorizon,\n", + "## [other configs])\n", + "\n", + "model = [] # could be an object later" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "e53584e1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "## >>> mdl2prd.solution\n", + "##\n", + "##[\n", + "## interval\n", + "##]\n", + "\n", + "solution(model) # coudl be a method on the object" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "6a95729a", + "metadata": {}, + "outputs": [], + "source": [ + "def terminal_value_function(k):\n", + " return 0" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "50f1d15e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.append(terminal_value_function)\n", + "\n", + "model" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "7cf6da6b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "solution(model)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "cbe7a0c1", + "metadata": {}, + "outputs": [], + "source": [ + "# probably we need to put the stages in a sublist ...\n", + "# >>> mdl2prd.solution[prdT].interval.make_empty_stage_list()\n", + "\n", + "model.insert(0, RBlock()) # prepend a recursive block" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "0cb8c7c7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[, 'c'],\n", + " ]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model[0].blocks.insert(0, cons.consumption_block_normalized)\n", + "\n", + "solution(model)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "614e2e3b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[, 'c', 'stigma'],\n", + " ]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Now add a portfolio stage\n", + "## append_stage will test whether there are already any other stages in existence\n", + "## If so it will\n", + "### - prepend to the list of stages an empty earlier stage\n", + "### - set stg[new_stg].vEndStg = stg[successor_stg].vBegStg\n", + "\n", + "# >>> mdl2prd.solution[prdT].interval.append_stage(\n", + "# stage_name='Shr',\n", + "# parse_file_model='portfolio_shr_solve.yml',\n", + "# parse_file_model='portfolio_shr_stage.yml' # again not sure if needed\n", + "# )\n", + "\n", + "model[0].blocks.append(cons.portfolio_block)\n", + "model[0].blocks.append(cons.tick_block)\n", + "\n", + "solution(model)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "a0e05c58", + "metadata": {}, + "outputs": [], + "source": [ + "# This doesn't need to be explicit because the existence of arrival value functions are implied already.\n", + "\n", + "###\n", + "# We are finished adding stages; finish by adding vBeg\n", + "# >>> mdl2prd.solution[prdT].interval.add_vBeg() #\n", + "# >>> mdl2prd.solution[prdT].interval.solution\n", + "# [vBeg, [ Shr, c ], vEnd]\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hark-env", + "language": "python", + "name": "hark-env" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/MonteCarlo/Generic Monte Carlo Perfect Foresight.ipynb b/examples/MonteCarlo/Generic Monte Carlo Perfect Foresight.ipynb index ad7730d29..348c7df77 100644 --- a/examples/MonteCarlo/Generic Monte Carlo Perfect Foresight.ipynb +++ b/examples/MonteCarlo/Generic Monte Carlo Perfect Foresight.ipynb @@ -743,7 +743,7 @@ { "data": { "text/plain": [ - "DBlock(name='', description='', shocks={'live': }, dynamics={'p': at 0x7f62f2c9ce50>, 'r_eff': at 0x7f62f2c9cee0>, 'b_nrm': at 0x7f62f2c9cf70>, 'm_nrm': at 0x7f62f2c9d000>, 'c_nrm': , 'a_nrm': at 0x7f62f2c9d120>}, reward={'u': at 0x7f62f2c9d5a0>})" + "DBlock(name='', description='', shocks={'live': }, dynamics={'p': at 0x77ecbd89c4c0>, 'r_eff': at 0x77ecbd89c550>, 'b_nrm': at 0x77ecbd89c5e0>, 'm_nrm': at 0x77ecbd89c670>, 'c_nrm': , 'a_nrm': at 0x77ecbd89c790>}, reward={'u': at 0x77ecbd89cc10>})" ] }, "execution_count": 12, diff --git a/pyproject.toml b/pyproject.toml index 1e1ef5c47..9127c5ab9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "econ-ark" -version = "0.14.1" +version = "0.15.0" authors = [{name = "Econ-ARK team", email = "econ-ark@jhuecon.org"}] classifiers = [ "Development Status :: 3 - Alpha",