"""
Behavior classes for the Godley-Lavoie 2006 SIM model.
This module will define the forward and simulate behavior of the Godley-Lavoie 2006 SIM model.
"""
__author__ = ["Karl Naumann-Woleske"]
__credits__ = ["Karl Naumann-Woleske"]
__license__ = "MIT"
__maintainer__ = ["Karl Naumann-Woleske"]
import logging
import torch
from macrostat.core.behavior import Behavior
from macrostat.models.GL06SIM.parameters import ParametersGL06SIM
from macrostat.models.GL06SIM.scenarios import ScenariosGL06SIM
from macrostat.models.GL06SIM.variables import VariablesGL06SIM
logger = logging.getLogger(__name__)
[docs]
class BehaviorGL06SIM(Behavior):
"""Behavior class for the Godley-Lavoie 2006 SIM model."""
version = "GL06SIM"
def __init__(
self,
parameters: ParametersGL06SIM | None = None,
scenarios: ScenariosGL06SIM | None = None,
variables: VariablesGL06SIM | None = None,
scenario: int = 0,
debug: bool = False,
):
"""Initialize the behavior of the Godley-Lavoie 2006 SIM model.
Parameters
----------
parameters: ParametersGL06SIM | None
The parameters of the model.
scenarios: ScenariosGL06SIM | None
The scenarios of the model.
variables: VariablesGL06SIM | None
The variables of the model.
record: bool
Whether to record the model output.
scenario: int
The scenario to use for the model.
"""
if parameters is None:
parameters = ParametersGL06SIM()
if scenarios is None:
scenarios = ScenariosGL06SIM()
if variables is None:
variables = VariablesGL06SIM()
super().__init__(
parameters=parameters,
scenarios=scenarios,
variables=variables,
scenario=scenario,
debug=debug,
)
[docs]
def initialize(self):
r"""Initialize the behavior of the Godley-Lavoie 2006 SIM model.
Within the book the initialization is generally to set all non-scenario
variables to zero.
Parameters
----------
Equations
---------
.. math::
:nowrap:
\begin{align}
C_d(0) &= C_s(0) = 0 \\
G_d(0) &= G_s(0) = 0 \\
T_s(0) &= T_d(0) = 0 \\
N_s(0) &= N_d(0) = 0 \\
YD(0) &= 0 \\
W(0) &= 0 \\
H_s(0) &= 0 \\
H_h(0) &= 0
\end{align}
Dependency
----------
Sets
-----
- ConsumptionDemand
- ConsumptionSupply
- GovernmentDemand
- GovernmentSupply
- TaxSupply
- TaxDemand
- LabourSupply
- LabourDemand
- DisposableIncome
- WageRate
- MoneySupply
- HouseholdMoneyStock
"""
self.state["ConsumptionDemand"] = torch.zeros(1)
self.state["ConsumptionSupply"] = torch.zeros(1)
self.state["GovernmentDemand"] = torch.zeros(1)
self.state["GovernmentSupply"] = torch.zeros(1)
self.state["TaxSupply"] = torch.zeros(1)
self.state["TaxDemand"] = torch.zeros(1)
self.state["LabourSupply"] = torch.zeros(1)
self.state["LabourDemand"] = torch.zeros(1)
self.state["DisposableIncome"] = torch.zeros(1)
self.state["MoneySupply"] = torch.zeros(1)
self.state["HouseholdMoneyStock"] = torch.zeros(1)
[docs]
def step(self, **kwargs):
"""Step function of the Godley-Lavoie 2006 SIM model."""
self.government_supply(**kwargs)
self.labour_demand(**kwargs)
self.labour_supply(**kwargs)
self.tax_demand(**kwargs)
self.tax_supply(**kwargs)
self.labour_income(**kwargs)
self.disposable_income(**kwargs)
self.consumption_demand(**kwargs)
self.consumption_supply(**kwargs)
self.government_money_stock(**kwargs)
self.household_money_stock(**kwargs)
self.national_income(**kwargs)
[docs]
def government_supply(
self, t: int, scenario: dict, params: dict | None = None, **kwargs
):
r"""In the model it is assumed that the supply will adjust to the demand,
that is, whatever is demanded can and will be produced. Equation (3.2)
in the book.
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
G_s(t) = G_d(t)
Dependency
----------
- scenario: GovernmentDemand
Sets
-----
- GovernmentSupply
"""
self.state["GovernmentSupply"] = scenario["GovernmentDemand"]
[docs]
def labour_demand(
self, t: int, scenario: dict, params: dict | None = None, **kwargs
):
r"""We can resolve the labour demand from the national income equation,
together with the consumption demand (+ disposable income) and the government demand
knowing that labour demand is equal to labour supply.
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
N_d(t) =\frac{\alpha_2 H_h(t-1) + G_d}{W(t)(1-\alpha_1(1-\theta))}
Dependency
----------
- prior: HouseholdMoneyStock
- scenario: GovernmentDemand
- scenario: WageRate
Sets
-----
- LabourDemand
"""
numerator = (
scenario["GovernmentDemand"]
+ params["PropensityToConsumeSavings"] * self.prior["HouseholdMoneyStock"]
)
denominator = scenario["WageRate"] * (
1 - params["PropensityToConsumeIncome"] * (1 - params["TaxRate"])
)
self.state["LabourDemand"] = numerator / denominator
[docs]
def labour_supply(
self, t: int, scenario: dict, params: dict | None = None, **kwargs
):
r"""In the model it is assumed that the supply will be equal to
the amount of labour demanded. Equation (3.4) in the book
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
N_s(t) = N_d(t)
Dependency
----------
- state: LabourDemand
Sets
-----
- LabourSupply
"""
self.state["LabourSupply"] = self.state["LabourDemand"]
[docs]
def tax_demand(self, t: int, scenario: dict, params: dict | None = None, **kwargs):
r"""The tax demand is a function of the tax rate, the labour supply,
and the wage rate. Equation (3.6) in the book.
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
T_d(t) = \theta N_s(t) W(t)
Dependency
----------
- parameters: TaxRate
- state: LabourSupply
- scenario: WageRate
Sets
-----
- TaxDemand
"""
self.state["TaxDemand"] = (
params["TaxRate"] * self.state["LabourSupply"] * scenario["WageRate"]
)
[docs]
def tax_supply(self, t: int, scenario: dict, params: dict | None = None, **kwargs):
r"""In the model it is assumed that the supply will be equal to
the amount of taxes demanded. Equation (3.3) in the book
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
T_s(t) = T_d(t)
Dependency
----------
- state: TaxDemand
Sets
-----
- TaxSupply
"""
self.state["TaxSupply"] = self.state["TaxDemand"]
[docs]
def labour_income(
self, t: int, scenario: dict, params: dict | None = None, **kwargs
):
r"""The labour income is the wage rate times the labour supply. This is
an intermediate variable used to calculate the disposable income, but is
computed explicitly here to compute the transaction flows.
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
W(t) N_s(t)
Dependency
----------
- scenario: WageRate
- state: LabourSupply
Sets
-----
- LabourIncome
"""
self.state["LabourIncome"] = scenario["WageRate"] * self.state["LabourSupply"]
[docs]
def disposable_income(
self, t: int, scenario: dict, params: dict | None = None, **kwargs
):
r"""The disposable income is the wage bill minus the taxes.
Equation (3.5) in the book.
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
YD(t) = W(t) N_s(t) - T_s(t)
Dependency
----------
- state: LabourIncome
- state: TaxSupply
Sets
-----
- DisposableIncome
"""
self.state["DisposableIncome"] = (
self.state["LabourIncome"] - self.state["TaxSupply"]
)
[docs]
def consumption_demand(
self, t: int, scenario: dict, params: dict | None = None, **kwargs
):
r"""The consumption demand is a function of the disposable income,
the propensity to consume income, and the propensity to consume savings.
Equation (3.7) in the book.
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
C_d(t) = \alpha_1 YD(t) + \alpha_2 H_h(t-1)
Dependency
----------
- state: DisposableIncome
- prior: HouseholdMoneyStock
Sets
-----
- ConsumptionDemand
"""
self.state["ConsumptionDemand"] = (
params["PropensityToConsumeIncome"] * self.state["DisposableIncome"]
+ params["PropensityToConsumeSavings"] * self.prior["HouseholdMoneyStock"]
)
[docs]
def consumption_supply(
self, t: int, scenario: dict, params: dict | None = None, **kwargs
):
r"""In the model it is assumed that the supply will adjust to the demand,
that is, whatever is demanded can and will be produced. Equation (3.1)
in the book.
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
C_s(t) = C_d(t)
Dependency
----------
- state: ConsumptionDemand
Sets
-----
- ConsumptionSupply
"""
self.state["ConsumptionSupply"] = self.state["ConsumptionDemand"]
[docs]
def government_money_stock(
self, t: int, scenario: dict, params: dict | None = None, **kwargs
):
r"""The government money stock is a function of the government demand,
and the tax supply. Equation (3.8) in the book.
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
H_s(t) = H_s(t-1) + G_d(t) - T_d(t)
Dependency
----------
- scenario: GovernmentDemand
- state: TaxDemand
- prior: GovernmentMoneyStock
Sets
-----
- GovernmentMoneyStock
"""
self.state["GovernmentMoneyStock"] = (
self.prior["GovernmentMoneyStock"]
+ scenario["GovernmentDemand"]
- self.state["TaxDemand"]
)
[docs]
def household_money_stock(
self, t: int, scenario: dict, params: dict | None = None, **kwargs
):
r"""The household money stock is a function of the disposable income,
the propensity to consume income, and the propensity to consume savings.
Equation (3.9) in the book.
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
H_h(t) = H_h(t-1) + YD(t) - C_d(t)
Dependency
----------
- state: DisposableIncome
- state: ConsumptionDemand
- prior: HouseholdMoneyStock
Sets
-----
- HouseholdMoneyStock
"""
self.state["HouseholdMoneyStock"] = (
self.prior["HouseholdMoneyStock"]
+ self.state["DisposableIncome"]
- self.state["ConsumptionDemand"]
)
[docs]
def national_income(
self, t: int, scenario: dict, params: dict | None = None, **kwargs
):
r"""The national income is the sum of the consumption demand,
the government demand, and the tax supply. Equation (3.10) in the book.
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
params : dict
Parameter dictionary
Equations
---------
.. math::
Y(t) = C_s(t) + G_s(t)
Dependency
----------
- state: ConsumptionSupply
- state: GovernmentSupply
Sets
-----
- NationalIncome
"""
self.state["NationalIncome"] = (
self.state["ConsumptionSupply"] + self.state["GovernmentSupply"]
)
############################################################################
# Steady State
############################################################################
[docs]
def compute_theoretical_steady_state_per_step(
self, t: int, params: dict, scenario: dict
):
r"""Compute the theoretical steady state of the model for each given
period. This is done per-period as there are parameters and scenarios
that may be time-varying, so the interpretation is a timeseries of the
theoretical steady state at a given period based on the parameters and
scenarios at that period.
Parameters
----------
params: dict
The parameters at the given period
scenario: dict
The scenarios at the given period
Equations
---------
.. math::
:nowrap:
\begin{align}
G^\star(t) &= G_s(t) = G_d(t)\\
r^\star(t) &= r(t)\\
\alpha_3 &= \frac{1-\alpha_1}{\alpha_2}\\
Y^\star(t) &= \frac{G^\star}{\theta}\\
YD^\star(t) = YD^{e\star}(t) = C^\star(t) &= \frac{G^\star(t)(1-\theta)}{\theta}\\
H_h^\star(t) &= \alpha_3 YD^\star(t)\\
T^\star(t) & \theta\cdot Y^\star(t)\\
B_s^\star(t) &= \frac{r^\star(t) B_{CB}^\star(t) + T^\star(t) - G^\star(t)}{r^\star(t)}\\
B_{CB}^\star(t) &= B_s^\star(t) - B_h^\star(t)\\
H_s^\star(t) &= H_{s}(t-1) + (B_{CB}(t) - B_{CB}(t-1))
\end{align}
"""
kwargs = dict(t=t, params=params, scenario=scenario)
# Scenario specific items, as in normal step()
self.government_supply(**kwargs)
self.state["NationalIncome"] = (
self.state["GovernmentSupply"] / params["TaxRate"]
)
self.state["DisposableIncome"] = self.state["NationalIncome"] * (
1 - params["TaxRate"]
)
a3 = (1 - params["PropensityToConsumeIncome"]) / params[
"PropensityToConsumeSavings"
]
self.state["HouseholdMoneyStock"] = a3 * self.state["DisposableIncome"]
self.state["ConsumptionDemand"] = self.state["DisposableIncome"]
self.consumption_supply(**kwargs)
numerator = (
scenario["GovernmentDemand"]
+ params["PropensityToConsumeSavings"] * self.state["HouseholdMoneyStock"]
)
denominator = scenario["WageRate"] * (
1 - params["PropensityToConsumeIncome"] * (1 - params["TaxRate"])
)
self.state["LabourDemand"] = numerator / denominator
self.labour_supply(**kwargs)
self.tax_demand(**kwargs)
self.tax_supply(**kwargs)
self.labour_income(**kwargs)
self.state["GovernmentMoneyStock"] = self.state["HouseholdMoneyStock"]