Source code for macrostat.models.IOPC.behavior

"""
This module will define the forward and simulate behavior of
Marco Veronese Passarella's 3IO-PC 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.IOPC.parameters import ParametersIOPC
from macrostat.models.IOPC.scenarios import ScenariosIOPC
from macrostat.models.IOPC.variables import VariablesIOPC

logger = logging.getLogger(__name__)


[docs] class BehaviorIOPC(Behavior): """Behavior class for Marco Veronese Passarella's 3IO-PC model""" version = "IOPC"
[docs] def __init__( self, parameters: ParametersIOPC | None = None, scenarios: ScenariosIOPC | None = None, variables: VariablesIOPC | None = None, scenario: int = 0, debug: bool = False, ): """Initialize the behavior of Marco Veronese Passarella's 3IO-PC model Parameters ---------- parameters: ParametersIOPC | None The parameters of the model. scenarios: ScenariosIOPC | None The scenarios of the model. variables: VariablesIOPC | 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 = ParametersIOPC() if scenarios is None: scenarios = ScenariosIOPC() if variables is None: variables = VariablesIOPC() super().__init__( parameters=parameters, scenarios=scenarios, variables=variables, scenario=scenario, debug=debug, )
############################################################################ # Initialization ############################################################################
[docs] def initialize(self): r"""Initialize the behavior of Passarella's 3IO-PC model in the spirit of Godley & Lavoie, by keeping all variables as zero. Accordingly, we can just "pass" the function as by default the state variables are all zero. The only exceptions are the price-indices which we initialize to one """ self.state["Prices"] = torch.ones_like(self.state["Prices"]) self.state["ConsumerPriceIndex"] = torch.ones(1) self.state["ConsumerPriceInflation"] = torch.ones(1) self.state["GovernmentPriceIndex"] = torch.ones(1)
############################################################################ # Step ############################################################################
[docs] def step(self, **kwargs): """Step function of the Godley-Lavoie 2006 PC model.""" # Scenario items self.consumption_government(**kwargs) self.set_interest_rate(**kwargs) # Items based on prior self.interest_earned_on_bills_household(**kwargs) self.expected_disposable_income(**kwargs) # Solution of the step # Input-output mechanisms self.prices(**kwargs) self.price_indices(**kwargs) self.inflation(**kwargs) self.propensity_to_consume_income(**kwargs) self.consumption(**kwargs) self.final_demand(**kwargs) self.real_gross_output(**kwargs) self.national_income(**kwargs) self.taxes(**kwargs) self.disposable_income(**kwargs) self.wealth(**kwargs) self.expected_wealth(**kwargs) self.household_bill_demand(**kwargs) self.household_bill_holdings(**kwargs) self.household_money_stock(**kwargs) self.central_bank_profits(**kwargs) self.government_bill_issuance(**kwargs) self.central_bank_bill_holdings(**kwargs) self.central_bank_money_stock(**kwargs)
[docs] def consumption_government( self, t: int, scenario: dict, params: dict | None = None, **kwargs, ): r"""Calculate the consumption of the government. This is given exogenously by the scenario. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Dependency ---------- - scenario: ConsumptionGovernment Sets ----- - RealConsumptionGovernment """ self.state["RealConsumptionGovernment"] = scenario["GovernmentDemand"]
[docs] def set_interest_rate( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Set the interest rate. This is given exogenously by the scenario. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} r(t) = \bar{r} \end{align) Dependency ---------- - scenario: InterestRate Sets ----- - InterestRate """ self.state["InterestRate"] = scenario["InterestRate"]
[docs] def interest_earned_on_bills_household( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Calculate the interest earned on bills by the household. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} r(t-1)B_h(t-1) \end{align} Dependency ---------- - prior: InterestRate - prior: HouseholdBillStock Sets ----- - InterestEarnedOnBillsHousehold """ self.state["InterestEarnedOnBillsHousehold"] = ( self.prior["InterestRate"] * self.prior["HouseholdBillStock"] )
[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 prices(self, t: int, scenario: dict, params: dict | None = None, **kwargs): r"""Compute the sectoral prices as the sum of unit labour cost and a markup on intermediate prices Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} P_i(t) = \frac{w}{pr_i} + (1 + \mu)\sum_j a_{ij}P_j(t) \end{align} Dependency ---------- - scenario: WageRate - params: LabourProductivity - params: Requirement - params: Markup Sets ----- - Prices """ self.state["Prices"] = torch.linalg.solve( A=( torch.eye(params["Requirement"].shape[0]) - (1 + params["Markup"]) * params["Requirement"].T ), B=scenario["WageRate"] / params["LabourProductivity"], )
[docs] def price_indices( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Compute the consumer and government price indices based on their consumption shares Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} p_c(t) &= \beta_{HH}^\top P(t)\\ p_g(t) &= \beta_{G}^\top P(t) \end{align} Dependency ---------- - state: Prices - params: HouseholdBudgetShare - params: GovernmentBudgetShare Sets ----- - ConsumerPriceIndex - GovernmentPriceIndex """ self.state["ConsumerPriceIndex"] = ( self.state["Prices"] @ params["HouseholdBudgetShare"] ) self.state["GovernmentPriceIndex"] = ( self.state["Prices"] @ params["GovernmentBudgetShare"] )
[docs] def inflation(self, t: int, scenario: dict, params: dict | None = None, **kwargs): r"""Compute the inflation (i.e. term for absence of money illusion) Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} \pi(t) &= \left(\frac{p_c(t) - p_c(t-1)}{p_c(t-1)}\right)\left(\frac{V(t-1)}{p_c(t-1)}\right) \end{align} Dependency ---------- - prior: Wealth - prior: ConsumerPriceIndex - state: ConsumerPriceIndex Sets ----- - ConsumerPriceInflation """ self.state["ConsumerPriceInflation"] = ( (self.state["ConsumerPriceIndex"] - self.prior["ConsumerPriceIndex"]) / self.prior["ConsumerPriceIndex"] ) * (self.prior["Wealth"] / self.state["ConsumerPriceIndex"])
[docs] def propensity_to_consume_income( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Endogenous propensity to consume out of income, dependent on the rate of interest Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} \alpha_1(t) = \alpha_{10} - \alpha_{11} r(t-1) \end{align} Dependency ---------- - prior: InterestRate - params: PropensityToConsumeIncomeBase - params: PropensityToConsumeIncomeInterest Sets ----- - PropensityToConsumeIncome """ self.state["PropensityToConsumeIncome"] = params[ "PropensityToConsumeIncomeBase" ] - (params["PropensityToConsumeIncomeInterest"] * self.prior["InterestRate"])
[docs] def consumption(self, t: int, scenario: dict, params: dict | None = None, **kwargs): r"""Calculate the consumption. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} c(t) = \alpha_1 \left(\frac{YD^e(t)}{p_c(t)} - \pi(t)\right) + \alpha_2 \frac{V(t-1)}{p_c(t)} \end{align} Dependency ---------- - state: PropensityToConsumeIncome - state: ExpectedDisposableIncome - state: ConsumerPriceIndex - state: ConsumerPriceInflation - prior: Wealth - params: PropensityToConsumeSavings Sets ----- - RealConsumptionHousehold """ self.state["RealConsumptionHousehold"] = self.state[ "PropensityToConsumeIncome" ] * ( (self.state["ExpectedDisposableIncome"] / self.state["ConsumerPriceIndex"]) - self.state["ConsumerPriceInflation"] ) + params[ "PropensityToConsumeSavings" ] * ( self.prior["Wealth"] / self.state["ConsumerPriceIndex"] )
[docs] def final_demand( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Calculate the final demand as the sum of household and government demands spread over the sectors Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} d_i(t) = \beta_{HH,i}C_{HH}(t) + \beta_{GOV,i}G(t) \end{align} Dependency ---------- - state: RealConsumptionHousehold - state: RealConsumptionGovernment - params: HouseholdBudgetShare - params: GovernmentBudgetShare Sets ----- - RealFinalDemand """ self.state["RealFinalDemand"] = +( params["HouseholdBudgetShare"] * self.state["RealConsumptionHousehold"] ) + (params["GovernmentBudgetShare"] * self.state["RealConsumptionGovernment"])
[docs] def real_gross_output( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Compute real gross output as the solution to the linear set of equations Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} x(t) = (I - A)^{-1}d(t) \end{align} Dependency ---------- - state: RealFinalDemand - params: Requirement Sets ----- - RealGrossOutput """ self.state["RealGrossOutput"] = torch.linalg.solve( A=(torch.eye(params["Requirement"].shape[0]) - params["Requirement"]), B=self.state["RealFinalDemand"], )
[docs] def national_income( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""National income is the sum of nominal final demand Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} Y(t) = P^\top(t)d(t) \end{align} Dependency ---------- - state: Prices - state: RealFinalDemand Sets ----- - NationalIncome """ self.state["NationalIncome"] = ( self.state["Prices"] @ self.state["RealFinalDemand"] )
[docs] def taxes(self, t: int, scenario: dict, params: dict | None = None, **kwargs): r"""Calculate the taxes. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} T(t) = \theta (Y(t) + r(t-1)B_h(t-1)) \end{align} Dependency ---------- - params: TaxRate - state: NationalIncome - state: InterestEarnedOnBillsHousehold Sets ----- - Taxes """ self.state["Taxes"] = params["TaxRate"] * ( self.state["NationalIncome"] + self.state["InterestEarnedOnBillsHousehold"] )
[docs] def disposable_income( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Calculate the disposable income. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} YD(t) = Y(t) - T(t) + r(t-1)B_h(t-1) \end{align} Dependency ---------- - state: NationalIncome - state: Taxes - state: InterestEarnedOnBillsHousehold Sets ----- - DisposableIncome """ self.state["DisposableIncome"] = ( self.state["NationalIncome"] - self.state["Taxes"] + self.state["InterestEarnedOnBillsHousehold"] )
[docs] def wealth(self, t: int, scenario: dict, params: dict | None = None, **kwargs): r"""Calculate the wealth. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} V(t) = V(t-1) + YD(t) - C(t) \end{align} Dependency ---------- - state: DisposableIncome - state: ConsumerPriceIndex - state: RealConsumptionHousehold - prior: Wealth Sets ----- - Wealth """ self.state["Wealth"] = ( self.prior["Wealth"] + self.state["DisposableIncome"] - ( self.state["ConsumerPriceIndex"] * self.state["RealConsumptionHousehold"] ) )
[docs] def expected_wealth( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Calculate the expected wealth. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} V^e(t) = V(t-1) + YD^e(t) - C(t) \end{align} Dependency ---------- - state: ExpectedDisposableIncome - state: RealConsumptionHousehold - state: ConsumerPriceIndex - prior: Wealth Sets ----- - ExpectedWealth """ self.state["ExpectedWealth"] = ( self.prior["Wealth"] + self.state["ExpectedDisposableIncome"] - ( self.state["ConsumerPriceIndex"] * self.state["RealConsumptionHousehold"] ) )
[docs] def household_bill_demand( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Calculate the household bill demand. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} \frac{B_h(t)}{V^e(t)} = \lambda_0 + \lambda_1 r(t) - \lambda_2 \frac{YD^e(t)}{V^e(t)} \end{align} Dependency ---------- - state: ExpectedWealth - state: ExpectedDisposableIncome - state: InterestRate - params: WealthShareBills_Constant - params: WealthShareBills_InterestRate - params: WealthShareBills_Income Sets ----- - HouseholdBillDemand """ self.state["HouseholdBillDemand"] = self.state["ExpectedWealth"] * ( # Baseline share params["WealthShareBills_Constant"] # Interest rate effect + params["WealthShareBills_InterestRate"] * self.state["InterestRate"] # Income-to-wealth ratio effect - params["WealthShareBills_Income"] * torch.where( self.state["ExpectedWealth"] > 0, self.state["ExpectedDisposableIncome"] / self.state["ExpectedWealth"], torch.zeros_like(self.state["ExpectedDisposableIncome"]), ) )
[docs] def household_bill_holdings( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Calculate the household bill holdings. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} B_h(t) = B_h(t-1) + (B_h^d(t) - B_h(t-1)) \end{align} Dependency ---------- - state: HouseholdBillDemand Sets ----- - HouseholdBillStock """ self.state["HouseholdBillStock"] = self.state["HouseholdBillDemand"]
[docs] def household_money_stock( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Calculate the household deposits as a residual. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} H_h(t) = V(t) - B_h(t) \end{align} Dependency ---------- - state: Wealth - state: HouseholdBillStock Sets ----- - HouseholdMoneyStock """ self.state["HouseholdMoneyStock"] = ( self.state["Wealth"] - self.state["HouseholdBillStock"] )
[docs] def central_bank_profits( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Calculate the central bank profits (income on bills held). Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} r(t-1)B_{CB}(t-1) \end{align} Dependency ---------- - prior: InterestRate - prior: CentralBankBillStock Sets ----- - CentralBankProfits """ self.state["CentralBankProfits"] = ( self.prior["InterestRate"] * self.prior["CentralBankBillStock"] )
[docs] def government_bill_issuance( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Calculate the government bill issuance. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} B_s(t) = B_s(t-1) + (G(t) - r(t-1)B_s(t-1)) - (T(t) + r(t-1)B_{CB}(t-1)) \end{align} Dependency ---------- - prior: InterestRate - prior: GovernmentBillStock - state: GovernmentPriceIndex - state: RealConsumptionGovernment - state: Taxes - state: CentralBankProfits Sets ----- - GovernmentBillStock """ self.state["GovernmentBillStock"] = ( self.prior["GovernmentBillStock"] + ( # Government demand self.state["GovernmentPriceIndex"] * self.state["RealConsumptionGovernment"] # Interest expense on bills issued + self.prior["InterestRate"] * self.prior["GovernmentBillStock"] ) - ( # Tax revenue self.state["Taxes"] # Central bank profits + self.state["CentralBankProfits"] ) )
[docs] def central_bank_bill_holdings( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Calculate the central bank bill holdings. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} B_{CB}(t) = B_{s}(t) - B_{h}(t) \end{align} Dependency ---------- - state: GovernmentBillStock - state: HouseholdBillStock Sets ----- - CentralBankBillStock """ self.state["CentralBankBillStock"] = ( self.state["GovernmentBillStock"] - self.state["HouseholdBillStock"] )
[docs] def central_bank_money_stock( self, t: int, scenario: dict, params: dict | None = None, **kwargs ): r"""Calculate the central bank money stock. Parameters ---------- t: int The time step. scenario: dict The scenario. params: dict | None The parameters. Equations --------- .. math:: :nowrap: \begin{align} H_{s}(t) = H_{s}(t-1) + (B_{CB}(t) - B_{CB}(t-1)) \end{align} Dependency ---------- - state: CentralBankBillStock - prior: CentralBankMoneyStock - prior: CentralBankBillStock Sets ----- - CentralBankMoneyStock """ self.state["CentralBankMoneyStock"] = ( self.prior["CentralBankMoneyStock"] + self.state["CentralBankBillStock"] - self.prior["CentralBankBillStock"] )