Core Module#

Core components of the MacroStat model.

The macrostat.core module consists of the following classes

BoundaryError(message)

Exception raised for invalid bounds.

Behavior(parameters, scenarios, variables[, ...])

Base class for the behavior of the MacroStat model.

Model(parameters, hyperparameters, ...)

A general class to represent a macroeconomic model.

Parameters([parameters, hyperparameters])

A class for handling parameters for the MacroStat model.

Scenarios(parameters[, scenarios, ...])

Scenarios class for the MacroStat model.

Variables([variable_info, timeseries, ...])

Variables class for the MacroStat model.

class macrostat.core.Behavior(parameters: Parameters, scenarios: Scenarios, variables: Variables, scenario: int = 0, differentiable: bool = False, debug: bool = False)[source]#

Bases: Module

Base class for the behavior of the MacroStat model.

apply_parameter_shocks(t: int, scenario: dict)[source]#

Apply parameter shocks to the model.

Any parameter in the model can be shocked/changed during the simulation using the scenario information. Specifically, for a parameter alpha, the user can pass two types of potential shocks: 1. An multiplicative shock, generically named alpha_multiply 2. An additive shock, generically named alpha_add

This function will apply the shocks to the parameters, and return a dictionary with the updated parameters. The application of the shocks is independent, that is, the multiplicative shock does not affect the additive shock and vice versa. This is done by first applying the multiplicative shock, and then the additive shock.

Parameters:
  • t (int) – The current timestep.

  • scenario (dict) – The scenario information for the current timestep.

Returns:

A dictionary with the updated parameters.

Return type:

dict

compute_theoretical_steady_state(**kwargs)[source]#

Compute the theoretical steady state of the model.

This process generally follows the structure of the forward() function, but instead of simulating the model, the steady state is computed at each timestep. Therefore, (1) the model is initialized, and (2) for each timestep the parameter and scenario information is passed to the compute_theoretical_steady_state_per_step() function that computes the steady state at that timestep.

Parameters:

**kwargs (dict) – Additional keyword arguments.

compute_theoretical_steady_state_per_step(**kwargs)[source]#

Compute the theoretical steady state of the model per step.

diffmax(x1, x2)[source]#

Smooth approximation to the minimum B: https://mathoverflow.net/questions/35191/a-differentiable-approximation-to-the-minimum-function

Requires:

self.hyper[‘max_constant’] as a large number

Parameters:
  • x1 (torch.Tensor) – The first variable to be compared.

  • x2 (torch.Tensor) – The second variable to be compared.

diffmax_v(x)[source]#

Smooth approximation to the maximum for a tensor. See diffmax

Requires:

self.hyper[‘max_constant’] as a large number

Parameters:

x (torch.Tensor) – The variable to be converted.

diffmin(x1, x2)[source]#

Smooth approximation to the minimum B: https://mathoverflow.net/questions/35191/a-differentiable-approximation-to-the-minimum-function

Requires:

self.hyper[‘min_constant’] as a large number

Parameters:
  • x1 (torch.Tensor) – The first variable to be compared.

  • x2 (torch.Tensor) – The second variable to be compared.

diffmin_v(x)[source]#

Smooth approximation to the minimum. See diffmin

Parameters:
  • x (torch.Tensor) – The variable to be converted.

  • Requires – self.hyper[‘min_constant’] as a large number

diffwhere(condition, x1, x2)[source]#

Where condition that is differentiable with respect to the condition.

Requires:

self.hyper[‘diffwhere’] = True self.hyper[‘sigmoid_constant’] as a large number

Note: For non-NaN/inf, where(x > eps, z, y) is (x - eps > 0) * (z - y) + y, so we can use the sigmoid function to approximate the where function.

Parameters:
  • condition (torch.Tensor) – Condition to be evaluated expressed as x - eps

  • x1 (torch.Tensor) – Value to be returned if condition is True

  • x2 (torch.Tensor) – Value to be returned if condition is False

forward()[source]#

Forward pass of the behavior.

This should include the model’s main loop, and is implemented as a placeholder. The idea is for users to implement an initialize() and step() function, which will be called by the forward() function.

If there are additional steps necessary, users may wish to overwrite this function.

initialize()[source]#

Initialize the behavior.

This should include the model’s initialization steps, and set all of the necessary state variables. They only need to be set for one period, and will then be copied to the history and prior to be used in the step function.

step(t: int, scenario: dict, params: dict | None = None)[source]#

Step function of the behavior.

This should include the model’s main loop.

Parameters:
  • t (int) – The current timestep.

  • scenario (dict) – The scenario information for the current timestep.

tanhmask(x)[source]#

Convert a variable into 0 (x<0) and 1 (x>0)

Requires:

self.hyper[‘tanh_constant’] as a large number

Parameters:

x (torch.Tensor) – The variable to be converted.

training: bool#
exception macrostat.core.BoundaryError(message: str)[source]#

Bases: Exception

Exception raised for invalid bounds.

class macrostat.core.Model(parameters: ~macrostat.core.parameters.Parameters | dict | None = None, hyperparameters: dict | None = None, scenarios: ~macrostat.core.scenarios.Scenarios | dict = None, variables: ~macrostat.core.variables.Variables | dict = None, behavior: ~macrostat.core.behavior.Behavior = <class 'macrostat.core.behavior.Behavior'>, name: str = 'model', log_level: int = 20, log_file: str = 'macrostat_model.log')[source]#

Bases: object

A general class to represent a macroeconomic model.

This class provides a wrapper for users to write their underlying model behavior while maintaining a uniformly accessible interface.

parameters#

The parameters of the model.

Type:

macrostat.core.parameters.Parameters

scenarios#

The scenarios of the model.

Type:

macrostat.core.scenarios.Scenarios

variables#

The variables of the model.

Type:

macrostat.core.variables.Variables

behavior#

The behavior class of the model.

Type:

macrostat.core.behavior.Behavior

name#

The name of the model.

Type:

str

Example

A general workflow for a model might look like:

>>> model = Model()
>>> output = model.simulate()
>>> model.save()
compute_theoretical_steady_state(scenario: int | str = 0, *args, **kwargs)[source]#

Compute the theoretical steady state of the model.

This process generally follows the structure of the forward() function, but instead of simulating the model, the steady state is computed at each timestep. Therefore, (1) the model is initialized, and (2) for each timestep the parameter and scenario information is passed to the compute_theoretical_steady_state_per_step() function that computes the steady state at that timestep.

Parameters:

scenario (int (optional)) – The scenario to use for the model run, defaults to 0, which represents the default scenario (no shocks).

classmethod from_json(parameter_file: str, scenario_file: str, variable_file: str, *args, **kwargs)[source]#

Initialize the model from a JSON file.

classmethod load(path: PathLike)[source]#

Class method to load a model instance from a pickled file.

Parameters:

path (os.PathLike) – path to the targeted file containing the model.

Notes

Note

This implementation is dependent on your pickling version

save(path: PathLike)[source]#

Save the model object as a pickled file

Parameters:

path (os.PathLike) – path where the model will be stored. If it is None then the model’s name will be used and the file stored in the working directory.

Notes

Note

This implementation is dependent on your pickling version

simulate(scenario: int | str = 0, *args, **kwargs)[source]#

Simulate the model.

Parameters:

scenario (int (optional)) – The scenario to use for the model run, defaults to 0, which represents the default scenario (no shocks).

to_json(file_path: PathLike, *args, **kwargs)[source]#

Convert the model to a JSON file split into parameters, scenarios, and variables.

Parameters:

file_path (os.PathLike) – The path to the file to save the model to.

class macrostat.core.Parameters(parameters: dict | None = None, hyperparameters: dict | None = None, *args, **kwargs)[source]#

Bases: object

A class for handling parameters for the MacroStat model.

classmethod from_csv(file_path: PathLike, *args, **kwargs)[source]#

Initialize the parameters from a CSV file.

Parameters:

file_path (os.PathLike) – The path to the CSV file to load the parameters from.

classmethod from_excel(file_path: PathLike, *args, **kwargs)[source]#

Initialize the parameters from an Excel file.

Parameters:

file_path (os.PathLike) – The path to the Excel file to load the parameters from.

classmethod from_json(file_path: PathLike, *args, **kwargs)[source]#

Initialize the parameters from a JSON file.

Parameters:

file_path (os.PathLike) – The path to the JSON file.

get_bounds()[source]#

Return the bounds for the parameters.

get_default_hyperparameters()[source]#

Return the default hyperparameters.

The hyperparameters are the parameters that are not directly used in the model, but rather for the simulation and calibration. They must include: 1. The number of timesteps to simulate 2. The scenario trigger, i.e. the timestep at which the scenario starts 3. The seed for the random number generator 4. The device to use for the simulation 5. May include other parameters, such as flags for the model

get_default_parameters()[source]#

Return the default parameters.

Should return a dictionary with the keys being the parameter names, and a subdictionary with the keys including: - “Value”: The value of the parameter. - “Lower”: The lower bound of the parameter. - “Upper”: The upper bound of the parameter. - “Unit”: The unit of the parameter. - “Notation”: The notation of the parameter.

get_values()[source]#

Return the values for the parameters.

is_equal(other: Parameters)[source]#

Compare the parameters to another Parameters object.

set_bound(key: str, value: tuple)[source]#

Set the bounds for a single parameter

Parameters:
  • key (str) – The key of the parameter to set the bounds for.

  • value (tuple) – The bounds to set for the parameter.

set_notation(key: str, value: str)[source]#

Set the notation for a single parameter.

set_unit(key: str, value: str)[source]#

Set the unit for a single parameter.

to_csv(file_path: PathLike, sphinx_math: bool = False)[source]#

Convert the parameters to a CSV file.

Parameters:
  • file_path (os.PathLike) – The path to the CSV file to save the parameters to.

  • sphinx_math (bool) – Whether to use Sphinx math notation in the CSV file.

to_excel(file_path: PathLike, *args, **kwargs)[source]#

Convert the parameters to an Excel file.

Parameters:

file_path (os.PathLike) – The path to the Excel file to save the parameters to.

to_json(file_path: PathLike, *args, **kwargs)[source]#

Convert the parameters to a JSON file.

Parameters:

file_path (os.PathLike) – The path to the JSON file to save the parameters to.

to_nn_parameters()[source]#

Convert the parameters to a nn.ParameterDict.

vectorize_parameters()[source]#

Vectorize the parameters.

verify_bounds()[source]#

Verify that the bounds are valid. By testing first that all parameters have bounds, and then that the bounds are valid.

verify_parameters()[source]#

Verify that the parameters are within the bounds.

class macrostat.core.Scenarios(parameters: Parameters, scenarios: dict | None = None, scenario_info: dict | None = None, calibration_variables: list[str] | None = None)[source]#

Bases: object

Scenarios class for the MacroStat model.

The aim of this class is to provide a uniform interface for handling scenarios, in particular for exogeneous shocks (e.g. also for the case where the shocks are calibrated to fit the data, such as using productivity shocks to fit the trajectory of GDP). It also contains user-specified scenarios such as exogenous supply shocks or the like.

add_scenario(timeseries: dict, name: str = None, colour: str = None)[source]#

Add a scenario to the model.

Parameters:
  • timeseries (dict) – The timeseries of the scenario.

  • name (str | None) – The name of the scenario. If None, the scenario will be named “Scenario.N” where N is the number of scenarios.

  • colour (str | None) – The colour of the scenario. If None, a random colour will be generated.

classmethod from_excel(excel_path: str, parameters: Parameters)[source]#

Initialize the scenarios from an Excel file.

Parameters:
  • excel_path (str) – The path to the Excel file containing the scenarios.

  • parameters (Parameters) – The parameters of the model. These are necessary to create the default scenarios.

classmethod from_json(json_path: str, parameters: Parameters)[source]#

Initialize the scenarios from a JSON file.

Parameters:
  • json_path (str) – The path to the JSON file containing the scenarios.

  • parameters (Parameters) – The parameters of the model. These are necessary to create the default scenarios.

get_default_scenario() dict[source]#

Return the default scenario variable in vectorized form.

get_default_scenario_values() dict[source]#

Return the default scenario values.

This function returns a dictionary of the scenario values with their default values.

get_scenario_index(scenario: str) int[source]#

Get the index of a scenario by name.

Parameters:

scenario (str) – The name of the scenario.

Returns:

The index of the scenario.

Return type:

int

to_excel(excel_path: str)[source]#

Save the scenarios to an Excel file.

Parameters:

excel_path (str) – The path to the Excel file to save the scenarios to.

to_json(json_path: str)[source]#

Save the scenarios to a JSON file.

Parameters:

json_path (str) – The path to the JSON file to save the scenarios to.

to_nn_parameters(scenario: int = 0)[source]#

Convert the scenarios to a PyTorch ParameterDict.

Parameters:

scenario (int) – The scenario to convert to PyTorch parameters.

vectorize_scenarios(timeseries: dict)[source]#

User-defined vectorization operations on the scenario timeseries.

By default, scenarios are defined as single-column vectors where the rows (dim 0) matches the number of timesteps and the column is the scenario variable or paramter. However, for users with vectorized implementations, one can modify this function to create vectors of shape TxK as needed

Parameters:

timeseries (dict[str:torch.tensor]) – dictionary of the scenario timeseries

Returns:

vectors – modified scenario timeseries

Return type:

dict[str:torch.tensor]

verify_scenario_info()[source]#

Verify that the scenario info is consistent: 1. There should be a one-to-one mapping between scenario info and timeseries 2. The scenario info should be a subset of the timeseries keys 3. The scenario info should have the [“Name”, “Colour”, “Index”] keys

class macrostat.core.Variables(variable_info: dict | None = None, timeseries: dict | None = None, parameters: Parameters | dict | None = None, *args, **kwargs)[source]#

Bases: object

Variables class for the MacroStat model.

This class contains the variables of a MacroStat model, specifically the output tensors from the simulation. Furthermore, it contains the methods to export the variables to different formats, and holds important information on the characteristics of each of the variables, such as their dimension, long-form name, unit, description and notation.

balance_sheet_actual()[source]#

Calculate the actual balance sheet of the model.

balance_sheet_theoretical(mathfmt: str = 'sphinx', non_camel_case: bool = False)[source]#

Calculate the theoretical balance sheet of the model based on the information in the info dictionary.

Parameters:
  • mathfmt (str) – The format to use for the math. Can be “sphinx”, “myst”, or “latex”.

  • non_camel_case (bool) – Whether to convert variable names to non-camel case.

Returns:

A DataFrame containing the theoretical balance sheet of the model.

Return type:

pd.DataFrame

check_health()[source]#

Check the health of the variables. This is where the user may want to implement checks for consistency of the variables, e.g. whether the balance sheet is in balance, or whether the redundant equations hold.

By default, this function returns True, indicating that the variables are healthy. This is to facilitate usage of the variables object in other functions.

compare(other: Self | DataFrame)[source]#

Compare the variables to another Variables object or DataFrame.

Parameters:

other (pd.DataFrame) – The DataFrame to compare the variables to.

classmethod from_excel(file_path: PathLike, *args, **kwargs)[source]#

Initialize the variables from an Excel file.

Parameters:

file_path (os.PathLike) – The path to the Excel file to read the variables from.

classmethod from_json(file_path: PathLike, *args, **kwargs)[source]#

Read the timeseries from a JSON file.

Parameters:

file_path (os.PathLike) – The path to the JSON file to read the timeseries from.

get_default_variables()[source]#

Return the default variables information dictionary.

This function returns a dictionary of the variable information with their default values. Users should implement this function in their model class, and it should return a dictionary with the variable names as keys and the variable information as values. The variable information should contain at least the following keys:

  • “history”: int - The number of periods that the variable requires information from.

  • “sectors”: list - The sectors that the variable is associated with.

  • “unit”: str - The unit of the variable.

  • “notation”: str - The notation of the variable.

get_flow_variables()[source]#

Get all the flow variables from the info dictionary. Flow variables are those that are flows between sectors i.e. their “sfc” tuple starts with “inflow” or “outflow”.

get_index_variables()[source]#

Get all the index variables from the info dictionary. Index variables are those that are indices, i.e. their “sfc” tuple starts with “index”.

get_stock_variables()[source]#

Get all the stock variables from the info dictionary. Stock variables are those that are assets or liabilities, i.e. their “sfc” tuple starts with “asset” or “liability”.

info_to_csv(file_path: str, sphinx_math: bool = False)[source]#

Convert the variables information to a CSV file.

Parameters:
  • file_path (str) – The path to the CSV file to save the variables information to.

  • sphinx_math (bool) – Whether to add a “:math:” marker to the notation column, e.g. for usage in the documentation

initialize_tensors(t: int, **kwargs)[source]#

Initialize the output tensors, creating two different dictionaries. First, a dictionary for the state variables (i.e. those that require only t-1 information, but no history) and second a dictionary for the history variables (i.e. those that require information from further previous periods). This distinction is important for PyTorch based simulations to reduce memory usage.

Parameters:

t (int) – The number of periods to initialize the tensors for.

new_state(**kwargs)[source]#

Initialize the state variables for the given period.

record_state(t: int, state_vars: dict)[source]#

Record the state variables for the given period.

Parameters:
  • t (int) – The period to record the state variables for.

  • state_vars (dict) – The state variables to record.

to_excel(file_path: PathLike)[source]#

Convert the variables to an Excel file.

Parameters:

file_path (os.PathLike) – The path to the Excel file to save the variables to.

to_json(file_path: PathLike)[source]#

Convert the parameters to a JSON file.

Parameters:

file_path (os.PathLike) – The path to the JSON file to save the timeseries to.

to_pandas()[source]#

Convert the variables to a pandas DataFrame.

transaction_matrix_actual()[source]#

Calculate the actual transaction matrix of the model.

transaction_matrix_theoretical(mathfmt: str = 'sphinx', non_camel_case: bool = False)[source]#

Calculate the theoretical transaction matrix of the model based on the information in the info dictionary.

Parameters:
  • mathfmt (str) – The format to use for the math. Can be “sphinx”, “myst”, or “latex”.

  • non_camel_case (bool) – Whether to convert variable names to non-camel case.

Returns:

A DataFrame containing the theoretical balance sheet of the model.

Return type:

pd.DataFrame

update_history(state: dict)[source]#

Update the history variables for the given period.

Parameters:
  • state (dict) – The state variables for the given period.

  • history (dict) – The history variables for the given period.

verify_sfc_info()[source]#

Verify that the sfc information in the info dictionary is complete.

This function checks first whether there is an sfc entry in the info dictionary for each variable. If there is, it then checks whether the sfc information makes sense, i.e. if they are flows they should have and “inflow” and “outflow” tuple in the list, otherwise they should contain at least one tuple with the first element being either “index”, “asset” or “liability”.