Dynare Python
The general goal of the project is to create a Python package that can
- trigger the Dynare Preprocessor
- apply Python algorithms to Python representation of a Dynare model
- call Julia to leverage DynareJulia algorithms and recover results as Python objects
- call MATLAB/Octave to leverage Dynare MATLAB/Octave algorithms and recover results as Python objects
Development tasks
Add Python output to the Dynare Preprocessor
Either:
- as
*.py
files - by interpreting the bytecode output
Proposed changes to the preprocessor should follow our CodingGuidelines, both the general rules and the C++-specific rules (see the dedicated C++ section on that page).
*.py
files
-
The Dynare preprocessor has a generic infrastructure for handling different output languages. Currently, it supports MATLAB/Octave, C and Julia. The idea is thus to add Python as a 4th output language, leveraging the existing infrastructure.
-
In terms of calling interface, the preprocessor accepts a command-line option
language
whose value can be eithermatlab
orjulia
(C output is subsumed in thematlab
option value when used in combination with theuse_dll
option); this is handled inDynareMain.cc
. A newpython
option value should be added (and theLanguageOutputType
class enum inExtendedPreprocessorTypes.hh
should be expanded accordingly). Throughout the preprocessor code, the distinction between MATLAB/Octave and Julia is currently passed through abool julia
function argument in calling trees; this should probably be replaced by passing aLanguageOutputType
value that covers the three languages. -
The engine for manipulating and outputting symbolic algebraic expressions is located in
ExprNode.hh
andExprNode.cc
. In particular, there is a generic framework for outputting expressions in various contexts, depending on the programming language (MATLAB/Octave, C, Julia) and on the type of expression (dynamic expression with leads and lags, static expression, time series…), as reflected in theExprNodeOutputType
class enum. For Python, the following values should be added:-
pythonDynamicModel
(for outputting the dynamic model) -
pythonStaticModel
(for outputting the static model) -
pythonDynamicSteadyStateOperator
(used inside aSTEADY_STATE
operator within a dynamic model) -
pythonSteadyStateFile
(for writing the contents of thesteady_state_model
block) - and maybe some type for writing time series in some native Python object (similar to
matlabDseries
andjuliaTimeDataFrame
)
Once these new enums are in place, they should be handled throughout the expression writing engine, in particular:
- within the helpers
isSteadyStateOperatorOutput()
,isSparseModelOutput()
(should always returntrue
for Python),ARRAY_SUBSCRIPT_OFFSET()
(array indexing is 0-based in Python); a newisPythonOutput()
helper should also be created; NB:LEFT_ARRAY_SUBSCRIPT()
andRIGHT_ARRAY_SUBSCRIPT()
need no adjustment since Python uses brackets for array-indexing; - in the
writeOutput()
methods of the various classes, so as to write use the correct objects and mathematical function names for the Python context - maybe also adapt the
cost()
methods (note that they currently don’t treat Julia separately, which is thus treated as MATLAB/Octave)
-
-
Finally, top-level methods for writing Python files should be implemented
- Methods for generating the different files should be implemented in the
ModelTree
,StaticModel
,DynamicModel
andSteadyStateModel
classes (the latter class is in theModelEquationBlock.{cc,hh}
source files) - A possibility is to take inspiration from the Julia methods. Ideally, things should be factorized as much as possible with other existing methods, possibly using template functions. Note that the main differences between Python code and Julia code relevant here are:
-
def
instead offunction
- array indexing starts with 0 instead of 1 (already handled by the
ARRAY_SUBSCRIPT_OFFSET()
helper) - Python functions don't terminate with
end
-
- In particular, note that
ModelTree.hh
createsdynamic_set_auxiliary_series()
that manipulates time series withlag
andlead
functions. We need to choose a time series representation in Python (in relation with theExprNodeOutputType
enum discussion above) - Finally, a new top-level method
ModFile::writePythonOutput()
should be created. It should generate all the*.py
files, and be called from themain()
function inDynareMain.cc
(similarly to what is done for MATLAB/Octave and Julia).
- Methods for generating the different files should be implemented in the
calling the bytecode representation generated by the preprocessor
- the code for
bytecode
MEX file needs to separated between a MEX wrapper and a standardC
library
<modfilename>/model/json/modfile.json
Parse the JSON file - This file contains
statementName
keys that describe computing tasks requested by the user - See function
parse_statements!()
inDynareJulia/src/DynareParser.jl
Decide about the distribution of Dynare Preprocessor for Python (should be transparent to the Python user who installs the Dynare Python package)
- Ideally, installing the Dynare Python package should automatically download the binary Preprocessor adapted to the user's platform (as in Julia)
- There already exists a Dynare preprocessor package for Conda, created and maintained by Pablo Winant
Check that a Python package can call Python code that it generated itself
- In Julia, this raise a
world age issue
Use JuliaCall to call DynareJulia
- See JuliaCall