"""
Behavior classes for the Godley-Lavoie 2006 SIMEX model.
This module will define the forward and simulate behavior of the Godley-Lavoie 2006 SIMEX 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.GL06SIMEX.parameters import ParametersGL06SIMEX
from macrostat.models.GL06SIMEX.scenarios import ScenariosGL06SIMEX
from macrostat.models.GL06SIMEX.variables import VariablesGL06SIMEX
logger = logging.getLogger(__name__)
[docs]
class BehaviorGL06SIMEX(Behavior):
"""Behavior class for the Godley-Lavoie 2006 SIMEX model."""
version = "GL06SIMEX"
def __init__(
self,
parameters: ParametersGL06SIMEX | None = None,
scenarios: ScenariosGL06SIMEX | None = None,
variables: VariablesGL06SIMEX | None = None,
scenario: int = 0,
debug: bool = False,
):
"""Initialize the behavior of the Godley-Lavoie 2006 SIMEX model.
Parameters
----------
parameters: ParametersGL06SIMEX | None
The parameters of the model.
scenarios: ScenariosGL06SIMEX | None
The scenarios of the model.
variables: VariablesGL06SIMEX | 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 = ParametersGL06SIMEX()
if scenarios is None:
scenarios = ScenariosGL06SIMEX()
if variables is None:
variables = VariablesGL06SIMEX()
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 SIMEX model.
Within the book the initialization is generally to set all non-scenario
variables to zero. Accordingly
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
- 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["ExpectedDisposableIncome"] = torch.zeros(1)
self.state["DisposableIncome"] = torch.zeros(1)
self.state["HouseholdMoneyStock"] = torch.zeros(1)
[docs]
def step(self, t: int, scenario: dict, params: dict | None = None):
"""Step function of the Godley-Lavoie 2006 SIMEX model."""
kwargs = dict(t=t, scenario=scenario, params=params)
self.government_supply(**kwargs)
self.expected_disposable_income(**kwargs)
self.consumption_demand(**kwargs)
self.consumption_supply(**kwargs)
self.national_income(**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.government_money_stock(**kwargs)
self.household_money_demand(**kwargs)
self.household_money_stock(**kwargs)
[docs]
def government_supply(
self, t: torch.tensor, scenario: dict, params: dict | None = None
):
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
Equations
---------
.. math::
G_s(t) = G_d(t)
Dependency
----------
- scenario: GovernmentDemand
Sets
-----
- GovernmentSupply
"""
self.state["GovernmentSupply"] = scenario["GovernmentDemand"]
[docs]
def labour_demand(
self, t: torch.tensor, scenario: dict, params: dict | None = None
):
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
Equations
---------
.. math::
N_d(t) =\frac{Y(t)}{W(t)}
Dependency
----------
- state: NationalIncome
- scenario: WageRate
Sets
-----
- LabourDemand
"""
self.state["LabourDemand"] = self.state["NationalIncome"] / scenario["WageRate"]
[docs]
def labour_supply(
self, t: torch.tensor, scenario: dict, params: dict | None = None
):
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
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: torch.tensor, scenario: dict, params: dict | None = None):
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
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: torch.tensor, scenario: dict, params: dict | None = None):
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
Equations
---------
.. math::
T_s(t) = T_d(t)
Dependency
----------
- state: TaxDemand
Sets
-----
- TaxSupply
"""
self.state["TaxSupply"] = self.state["TaxDemand"]
[docs]
def expected_disposable_income(
self, t: torch.tensor, scenario: dict, params: dict | None = None
):
r"""The expected disposable income is simply the prior period's
disposable income. Equation (3.20) in the book.
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Equations
---------
.. math::
YD^e(t) = YD(t-1)
Dependency
----------
- prior: DisposableIncome
Sets
-----
- ExpectedDisposableIncome
"""
self.state["ExpectedDisposableIncome"] = self.prior["DisposableIncome"]
[docs]
def labour_income(
self, t: torch.tensor, scenario: dict, params: dict | None = None
):
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
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: torch.tensor, scenario: dict, params: dict | None = None
):
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
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: torch.tensor, scenario: dict, params: dict | None = None
):
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
Equations
---------
.. math::
C_d(t) = \alpha_1 YD(t) + \alpha_2 H_h(t-1)
Dependency
----------
- state: ExpectedDisposableIncome
- prior: HouseholdMoneyStock
Sets
-----
- ConsumptionDemand
"""
self.state["ConsumptionDemand"] = (
params["PropensityToConsumeIncome"] * self.state["ExpectedDisposableIncome"]
+ params["PropensityToConsumeSavings"] * self.prior["HouseholdMoneyStock"]
)
[docs]
def consumption_supply(
self, t: torch.tensor, scenario: dict, params: dict | None = None
):
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
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: torch.tensor, scenario: dict, params: dict | None = None
):
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
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_demand(
self, t: torch.tensor, scenario: dict, params: dict | None = None
):
r"""The household demand for money is equivalent to their expected
income in excess of consumption demand
Parameters
----------
t : torch.tensor
Current time step
scenario : dict
Scenario dictionary
Equations
---------
.. math::
H_d(t) = H_h(t-1) + YD^e(t) - C_d(t)
Dependency
----------
- state: ExpectedDisposableIncome
- state: ConsumptionDemand
- prior: HouseholdMoneyStock
Sets
-----
- HouseholdMoneyDemand
"""
self.state["HouseholdMoneyDemand"] = (
self.prior["HouseholdMoneyStock"]
+ self.state["ExpectedDisposableIncome"]
- self.state["ConsumptionDemand"]
)
[docs]
def household_money_stock(
self, t: torch.tensor, scenario: dict, params: dict | None = None
):
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
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: torch.tensor, scenario: dict, params: dict | None = None
):
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
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"]
)