Reference¶
model_solver package¶
model_solver.model_solver module¶
- class ModelSolver(eqns, endo_vars)¶
Bases:
object
ModelSolver is designed to handle and solve mathematical models represented by a system of equations.
It supports various mathematical functions such as min, max, log, and exp. This class allows you to initialize a model with a list of equations and endogenous variables. It subsequently solves the model using input data stored in a Pandas DataFrame.
Usage Example:
Let equations and endogenous be lists containing equations and endogenous variables, respectively, stored as strings, e.g.,
equations = [ 'x + y = A', 'x / y = B' ] endogenous = [ 'x', 'y' ]
where ‘A’ and ‘B’ are exogenous variables.
To initialize a ModelSolver instance, use:
model = ModelSolver(equations, endogenous)
This reads in the equations and endogenous variables, performs block analysis and ordering, and generates simulation code.
To solve the model using input data in a Pandas DataFrame, let’s assume you have a DataFrame named “input_df” containing data on ‘A’ and ‘B’ as well as initial values for ‘x’ and ‘y’. You can solve the model by invoking:
solution_df = model.solve_model(input_df)
Now, solution_df is a Pandas DataFrame with the same dimensions as input_df, but with the endogenous variables replaced by the solutions to the model. The last solution is also stored in model.last_solution.
- Parameters:
eqns (list[str])
endo_vars (list[str])
- __init__(eqns, endo_vars)¶
Reads in equations and endogenous variables and does a number of operations, e.g. analyzing block structure using graph theory.
- Parameters:
eqns (
list
[str
]) – A list of equations in string formatendo_vars (
list
[str
]) – A list of endogenous variables
- Return type:
None
Example
>>> equations = ["x1 = a1", "x2 = a2", "0.2*x1+0.7*x2 = 0.1*ca+0.8*cb+0.3*i1", "0.8*x1+0.3*x2 = 0.9*ca+0.2*cb+0.1*i2", "k1 = k1(-1)+i1", "k2 = k2(-1)+i2"] >>> endogenous = ["x1", "x2", "ca", "cb", "k1", "k2"] >>> model = ModelSolver(equations, endogenous) ---------------------------------------------------------------------------------------------------- Initializing model * Importing equations * Importing endogenous variables * Analyzing model * Analyzing equation strings * Generating bipartite graph (BiGraph) connecting equations and endogenous variables * Finding maximum bipartite match (MBM) (i.e. associating every equation with exactly one endogenus variable) * Generating directed graph (DiGraph) connecting endogenous variables using bipartite graph and MBM * Finding condensation of DiGraph (i.e. determining minimal blocks of systems of simulataneous equations) * Generating simulation code (i.e. block-wise symbolic objective function, symbolic Jacobian matrix and lists of endogenous and exogenous variables) Finished ----------------------------------------------------------------------------------------------------
- describe()¶
Display a summary of the model’s characteristics.
Prints information about the model, including the number of equations, blocks, simple definition blocks, and the distribution of equation counts in the blocks.
- Return type:
None
- draw_blockwise_graph(variable, max_ancs_gens=5, max_desc_gens=5, max_nodes=50, figsize=(7.5, 7.5))¶
Draws a directed graph of a block containing the given variable with a limited number of ancestors and descendants.
- Parameters:
variable (
str
) – The variable for which the blockwise graph will be drawn.max_ancs_gens (
int
) – Maximum number of generations of ancestors to include in the graph.max_desc_gens (
int
) – Maximum number of generations of descendants to include in the graph.max_nodes (
int
) – Maximum number of nodes to include in the graph. If the graph has more nodes, it won’t be plotted.figsize (
tuple
[float
,float
]) – A tuple specifying the width and height of the figure for the graph.
- Return type:
None
Example
Draws a directed graph of the block containing ‘var1’ with up to 3 generations of ancestors and 2 generations of descendants.
model = ModelSolver(equations, endogenous) model.draw_blockwise_graph('var1', max_ancs_gens=3, max_desc_gens=2, max_nodes=30, figsize=(10, 10))
- property endo_vars: tuple[str, ...]¶
Return the endogenous variables in the model.
- property eqns: tuple[str, ...]¶
Return the equations in the model.
- property exog_vars: tuple[str, ...]¶
Return the exogenous variables in the model.
- find_endo_var(endo_var, noisy=False)¶
Find the block that solves the specified endogenous variable.
Note
This function searches for the specified endogenous variable in the model’s blocks and returns the block number of the block that solves it. If the endogenous variable is not found in any block, it returns None.
- Parameters:
endo_var (
str
) – The endogenous variable to be found.noisy (
bool
) – Whether output should be printed or returned.
- Return type:
int
|None
- Returns:
The block number of the block that solves the specified endogenous variable. Returns None if the endogenous variable is not found in any block.
- Raises:
IndexError – If endo_var is not endogenous in model.
- gen_get_var_info(var_col_index)¶
Function that returns function that returns names, columns and lags for variables.
- Return type:
Callable
[[Iterable
[str
]],tuple
[list
[str
],ndarray
[Any
,dtype
[int64
]],ndarray
[Any
,dtype
[int64
]]]]- Parameters:
var_col_index (dict[str, int])
- property last_solution: DataFrame¶
Returns the last found solution in the model.
- Returns:
The last found solution as a dataframe.
- Raises:
AttributeError – If no solution is found.
- property max_iter: int¶
Return maximum number of iterations.
- property max_lag: int¶
Return max_lag in the model.
- property root_tolerance: float¶
Return root tolerance.
- sensitivity(i, period_index, method='std', exog_subset=None)¶
Analyses sensitivity of endogenous variables to exogenous variables for a specific period.
- Parameters:
i (
int
) – The index of the block for which variable values will be displayed.period_index (
int
) – The index of the period for which variable values will be shown.exog_subset (
list
[str
] |None
) – List of exogenous variables to be analysed. If None, all relevant exogenous variables will be analysed.method (
str
) –Method for sensitivity analysis. Default is ‘std’.
’std’: Adjusts variables by adding their standard deviation.
’pct’: Adjusts variables by adding 1% of their value.
’one’: Adjusts variables by adding 1 to their value.
- Return type:
DataFrame
- Returns:
DataFrame showing the sensitivity of endogenous variables to exogenous variables.
- Raises:
RuntimeError – If no solution is found.
ValueError – If method is not std, pct or one.
Example
model = ModelSolver(equations, endogenous) sensitivity_df = model.sensitivity(1, 3, method='pct', exog_subset=['exog_var1', 'exog_var2']) print(sensitivity_df)
With output:
| endog_var1 | endog_var2 | -------------------------------------- exog_var1 | 0.23 | 0.12 | exog_var2 | 0.45 | 0.56 |
- show_block(i)¶
Prints endogenous and exogenous variables and equations for a given block.
- Parameters:
i (
int
) – The index of the block to display.- Raises:
IndexError – If block i is not in model.
- Return type:
None
Example
model = ModelSolver(equations, endogenous) model.show_block(1)
A block consists of an equation or a system of equations:
5 endogenous variables: - var1 - var2 - var3 - var4 - var5 3 predetermined variables: - pred_var1 - pred_var2 - pred_var3 4 equations: - eqn1: var1 = pred_var1 + pred_var2 - eqn2: var2 = var1 + pred_var2 - eqn3: var3 = pred_var2 + pred_var3 - eqn4: var4 = var3 + pred_var1
- show_block_vals(i, period_index, noisy=True)¶
Prints the values of endogenous and predetermined variables in a given block for a specific period.
- Parameters:
i (
int
) – The index of the block for which variable values will be displayed.period_index (
int
) – The index of the period for which variable values will be shown.noisy (
bool
) – Whether output should be printed or returned.
- Return type:
tuple
[Series
,Series
] |tuple
[None
,None
]- Returns:
Two pd.Series of endogenous and predetermined values, or None, None.
- Raises:
RuntimeError – If no solution is found.
Example
model = ModelSolver(equations, endogenous) model.show_block_vals(1, 3)
With output:
Block 1 has endogenous variables in 2023-01-04 that evaluate to: var1=10.5 var2=15.2 ... Block 1 has predetermined variables in 2023-01-04 that evaluate to: pred_var1=8.1 pred_var2=9.7
- show_blocks()¶
Prints endogenous and exogenous variables and equations for every block in the model.
Iterates through all blocks in the model and calls the show_block function to display their details.
- Return type:
None
Example
model = ModelSolver(equations, endogenous) model.show_blocks()
The output is like this:
-------------------------------------------------- Block 1 -------------------------------------------------- Endogenous Variables: - var1 - var2 Exogenous Variables: - exog_var1 - exog_var2 Equations: - eqn1: var1 = exog_var1 + exog_var2 - eqn2: var2 = var1 + exog_var2 -------------------------------------------------- Block 2 -------------------------------------------------- Endogenous Variables: - var3 - var4 Exogenous Variables: - exog_var3 - exog_var4 Equations: - eqn3: var3 = exog_var3 + exog_var4 - eqn4: var4 = var3 + exog_var4 ... -------------------------------------------------- Block n -------------------------------------------------- Endogenous Variables: - var_n1 - var_n2 Exogenous Variables: - exog_var_n1 - exog_var_n2 Equations: - eqn_n1: var_n1 = exog_var_n1 + exog_var_n2 - eqn_n2: var_n2 = var_n1 + exog_var_n2
- solve_model(input_df, jit=True)¶
Solves the model subject to a given DataFrame.
- Parameters:
input_df (
DataFrame
) – A DataFrame containing input data for the model.jit (
bool
) – Flag indicating whether to use just-in-time (JIT) compilation for solving equations.
- Return type:
DataFrame
- Returns:
A DataFrame containing the model’s output data.
- Raises:
TypeError – If any column in input_df is not of numeric data type.
Example
>>> equations = ["x1 = a1", "x2 = a2", "0.2*x1+0.7*x2 = 0.1*ca+0.8*cb+0.3*i1", "0.8*x1+0.3*x2 = 0.9*ca+0.2*cb+0.1*i2", "k1 = k1(-1)+i1", "k2 = k2(-1)+i2"] >>> endogenous = ["x1", "x2", "ca", "cb", "k1", "k2"] >>> model = ModelSolver(equations, endogenous) ---------------------------------------------------------------------------------------------------- Initializing model * Importing equations * Importing endogenous variables * Analyzing model * Analyzing equation strings * Generating bipartite graph (BiGraph) connecting equations and endogenous variables * Finding maximum bipartite match (MBM) (i.e. associating every equation with exactly one endogenus variable) * Generating directed graph (DiGraph) connecting endogenous variables using bipartite graph and MBM * Finding condensation of DiGraph (i.e. determining minimal blocks of systems of simulataneous equations) * Generating simulation code (i.e. block-wise symbolic objective function, symbolic Jacobian matrix and lists of endogenous and exogenous variables) Finished ---------------------------------------------------------------------------------------------------- >>> input_data = pd.DataFrame({"x1": [2, 4, 1, 2], "x2": [2, 1, 2, 3], "ca": [1, 3, 4, 1], "cb": [1, 2, 1, 4], "k1": [1, 3, 4, 1], "k2": [1, 2, 1, 4], "a1": [1, 2, 4, 4], "a2": [3, 2, 3, 4], "i1": [1, 2, 4, 4], "i2": [3, 2, 3, 4]}) >>> output_data = model.solve_model(input_data) ---------------------------------------------------------------------------------------------------- Solving model First period: 1, last period: 3 Solving | | ... Finished ----------------------------------------------------------------------------------------------------
- switch_endo_vars(old_endo_vars, new_endo_vars)¶
Sets old_endo_vars as exogenous and new_endo_vars as endogenous and performs block analysis.
Note
This function switches the endogenous and exogenous status of variables and performs block analysis on the model.
Example
model = ModelSolver(equations, endogenous) model.switch_endo_vars(['var1', 'var2'], ['var3', 'var4'])
- Parameters:
old_endo_vars (
list
[str
]) – List of old endogenous variables to be switched to exogenous.new_endo_vars (
list
[str
]) – List of new endogenous variables to be switched from exogenous.
- Raises:
ValueError – If any variable in old_endo_vars is not in the current list of endogenous variables or if any variable in new_endo_vars is already in the list of endogenous variables.
- Return type:
None
- trace_to_exog_vals(i, period_index, noisy=True)¶
Traces the given block back to exogenous values and prints those values.
- Parameters:
i (
int
) – The index of the block for which variable values will be displayed.period_index (
int
) – The index of the period for which exogenous values will be traced.noisy (
bool
) – Whether output should be printed or returned.
- Return type:
Series
|None
- Returns:
A pd.Series of exogenous values, or None.
- Raises:
RuntimeError – If no solution is found.
Example
model = ModelSolver(equations, endogenous) model.trace_to_exog_vals(1, 3)
With output:
Block 1 traces back to the following exogenous variable values in 2023-01-04: exog_var1=12.5 exog_var2=8.2 exog_var3=10.0
- trace_to_exog_vars(i, noisy=True)¶
Prints all exogenous variables that are ancestors to the given block.
- Parameters:
i (
int
) – The index of the block for which variable values will be displayed.noisy (
bool
) – Whether output should be printed or returned.
- Return type:
list
[str
] |None
- Returns:
A list of exogenous variables that are ancestors to the given block, or None.
Example
model = ModelSolver(equations, endogenous) model.trace_to_exog_vars(1)