I haven't tried recently, and I'm afraid it's unlikely I'll have time to anytime soon, for partly covid related reasons. You're welcome to close the issue and I'll reopen it if I encounter it again.

This is great. Maybe just one line on the downloads page pointing people to the artifacts on the pipelines page would help.

It would be good if as well as providing unstable builds of the master branch, unstable builds of the current major version branch were also provided (e.g. the 4.6 branch at present).

While people can of course compile this themselves, in practice this is quite onerous.

Thanks Sébastien! This sounds great. I'll test it over the weekend.

Having this in the path blocks access to the standard MATLAB `graph`

class (for working with network graphs).

It would be helpful if this naming clash could be avoided.

@sebastien Sounds great! Thanks. Glad we found a compromise.

@sebastien I'm not asking for any commitments on formatting of the comments. If they're there, it's very easy to tweak things to support changes in this formatting. Given these big changes in Dynare 4.6, DynareOBC is already going to be littered with `if DynareVersion >= 4.6`

. A few more cases is not the end of the world! If the information is there somewhere, I can extract it. The problem at the moment is that the information isn't there at all.

@MichelJuillard Providing the mapping of MLV names to elements of T in M_ would be great!

@sebastien If the ordering of the MLVs in the _tt.m files agreed with the ordering in the MOD file then that'd be sufficient for my purposes as I suppose I can process the MOD file to get the MLV names.

But frankly reordering the MLVs in the _tt.m file sounds like an approach that is both more fragile, and less generally useful, than just adding comments labelling the elements of T. E.g. `T(4) = exp(y); % #Y`

@sebastien I'm not sure I understand your point.

If a human is debugging the steady state of the model, they will end up looking at the inside of the _tt.m files. Comments there saying that e.g. T(4) was the MLV "Y" would be of great help to them. They would also be sufficient for what I need. I end up looking in _static.m files with shocking regularity, independent of DynareOBC. The ones generated by Dynare 4.6 are much less user friendly. A few auto-generated comments seem like a pretty small concession to user friendliness.

(As an aside, I think it's a real shame that MLVs are no longer given named variables in the static and dynamic files, as these really were incredibly useful. But this seems like a WONTFIX.)

To be absolutely clear: I need to know which element of the T vector corresponds to which MLV name. That's all! I don't care if this information is provided in the _tt.m file in some form, in a separate text file, or in the JSON (modulo a few concerns about extra processing time if the JSON has to be generated and then parsed by DynareOBC).

Once I have that information, then I can use the generated _tt.m files to get what I need. I cannot at present both due to the ordering, and due to not knowing which MLVs are defined in the file (though the later could be solved by processing the MOD file relatively easily).

But the generated JSON is in Dynare syntax, not MATLAB. Parsing the JSON does not seem significantly easier than just parsing the original MOD file. The only way the JSON would significantly help is if the JSON contained a mapping of MLV names to elements of the T vector.

The old _static.m and _dynamic.m files really gave me exactly what I needed, without me even having to think about mapping variable and parameter names to values.

I accept that my code may have to change with future Dynare versions (this is inevitable with anything based on regexping generated functions!), but this really seems like a case where the perfect is the enemy of the good. Adding comments to the _tt.m files noting which elements of T correspond to which MLV would have minimal performance impact, would enhance transparency generally, and would solve all of my problems.

If you want to go further and autogenerate functions for returning MLVs or somesuch, that'd be great too, but why not start with the simple thing of just adding comments.

One additional argument for greater transparency about temporary variables in the static and dynamic files is debugging.

When I encounter a problem with a model's steady state (i.e. non-zero residuals), the first thing I do is to place a breakpoint in the _static.m file and try to understand where the problem is coming from. With Dynare 4.5, this was easy as all of the MLVs were defined in the _static.m file, so I could very easily examine the values of relevant variables. (The way I write MOD files, most things of interest end up being MLVs.)

One solution that would greatly enhance transparency would be a preprocessor option to include source lines as comments. This is a relatively common feature in other "language transformation" engines. (For example, MATLAB Coder will do it when generating C from MATLAB.)

For your information, here are the DynareOBC functions which process the old _static.m and _dynamic.m files. They're not pretty, but should give you an idea what is needed.

This bug came up in conversation with @MichelJuillard .

For example, this model block:

```
model;
#Pi=exp(pi);
#Pi_LEAD=exp(pi(1));
#Pi_STEADY=exp(pi_STEADY);
#kappa=(gamma/2)*(Pi-1)^2;
#kappa_STEADY=(gamma/2)*(Pi_STEADY-1)^2;
#c=log(1-kappa-eta)+y;
#c_LEAD=log(1-(gamma/2)*(Pi_LEAD-1)^2-eta)+y(1);
#h=y-z;
#w=sigma*c+nu*h-log(1-tauw);
#re=-log(beta)-d(1)+pi_STEADY;
#y_STEADY=(1/(sigma+nu))*(log((1-tauw)*((1-beta)*(Pi_STEADY-1)*Pi_STEADY/theta*gamma+1))-sigma*log(1-kappa_STEADY-eta));
#gdp=log(1-kappa)+y;
#gdp_STEADY=log(1-kappa_STEADY)+y_STEADY;
#dynareOBCMaxArgA1=(0);
#dynareOBCMaxArgB1=(re+phi_pi*(pi-pi_STEADY)+phi_y*(gdp-gdp_STEADY));
#dynareOBCMaxFunc1=max(dynareOBCMaxArgA1,dynareOBCMaxArgB1);
r=(dynareOBCMaxFunc1);
1=beta*exp(d(1)+r-pi(1)+sigma*(c-c_LEAD));
(Pi-1)*Pi=theta/gamma*(exp(w-z)-1)+beta*exp(d(1)+sigma*(c-c_LEAD)+y(1)-y)*(Pi_LEAD-1)*Pi_LEAD;
d=rhod*d(-1)+sigmad*epsilond;
z=rhoz*z(-1)+sigmaz*epsilonz;
end;
```

becomes this in the JSON file (with `json=parse`

):

```
...
"model":[
{"lhs": "r", "rhs": "dynareOBCMaxFunc1", "line": 37}
, {"lhs": "1", "rhs": "beta*exp(d(1)+r-pi(1)+sigma*(c-c_LEAD))", "line": 38}
, {"lhs": "Pi*(Pi-1)", "rhs": "theta/gamma*(exp(w-z)-1)+Pi_LEAD*(Pi_LEAD-1)*beta*exp(y(1)+d(1)+sigma*(c-c_LEAD)-y)", "line": 39}
, {"lhs": "d", "rhs": "rhod*d(-1)+sigmad*epsilond", "line": 40}
, {"lhs": "z", "rhs": "rhoz*z(-1)+sigmaz*epsilonz", "line": 41}
]
, "xrefs": {"parameters": [], "endogenous": [], "exogenous": [], "exogenous_deterministic": []}
, "abstract_syntax_tree":[
{ "number":0, "line":37, "AST": {"node_type" : "BinaryOpNode", "op" : "=", "arg1" : {"node_type" : "VariableNode", "name" : "r", "type" : "endogenous", "lag" : 0}, "arg2" : {"node_type" : "VariableNode", "name" : "dynareOBCMaxFunc1", "type" : "modelLocalVariable", "lag" : 0}}}, { "number":1, "line":38, "AST": {"node_type" : "BinaryOpNode", "op" : "=", "arg1" : {"node_type" : "NumConstNode", "value" : 1}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "VariableNode", "name" : "beta", "type" : "parameter", "lag" : 0}, "arg2" : {"node_type" : "UnaryOpNode", "op" : "exp", "arg" : {"node_type" : "BinaryOpNode", "op" : "+", "arg1" : {"node_type" : "BinaryOpNode", "op" : "-", "arg1" : {"node_type" : "BinaryOpNode", "op" : "+", "arg1" : {"node_type" : "VariableNode", "name" : "d", "type" : "endogenous", "lag" : 1}, "arg2" : {"node_type" : "VariableNode", "name" : "r", "type" : "endogenous", "lag" : 0}}, "arg2" : {"node_type" : "VariableNode", "name" : "pi", "type" : "endogenous", "lag" : 1}}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "VariableNode", "name" : "sigma", "type" : "parameter", "lag" : 0}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "-", "arg1" : {"node_type" : "VariableNode", "name" : "c", "type" : "modelLocalVariable", "lag" : 0}, "arg2" : {"node_type" : "VariableNode", "name" : "c_LEAD", "type" : "modelLocalVariable", "lag" : 0}}}}}}}}, { "number":2, "line":39, "AST": {"node_type" : "BinaryOpNode", "op" : "=", "arg1" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "VariableNode", "name" : "Pi", "type" : "modelLocalVariable", "lag" : 0}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "-", "arg1" : {"node_type" : "VariableNode", "name" : "Pi", "type" : "modelLocalVariable", "lag" : 0}, "arg2" : {"node_type" : "NumConstNode", "value" : 1}}}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "+", "arg1" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "BinaryOpNode", "op" : "/", "arg1" : {"node_type" : "VariableNode", "name" : "theta", "type" : "parameter", "lag" : 0}, "arg2" : {"node_type" : "VariableNode", "name" : "gamma", "type" : "parameter", "lag" : 0}}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "-", "arg1" : {"node_type" : "UnaryOpNode", "op" : "exp", "arg" : {"node_type" : "BinaryOpNode", "op" : "-", "arg1" : {"node_type" : "VariableNode", "name" : "w", "type" : "modelLocalVariable", "lag" : 0}, "arg2" : {"node_type" : "VariableNode", "name" : "z", "type" : "endogenous", "lag" : 0}}}, "arg2" : {"node_type" : "NumConstNode", "value" : 1}}}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "VariableNode", "name" : "Pi_LEAD", "type" : "modelLocalVariable", "lag" : 0}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "BinaryOpNode", "op" : "-", "arg1" : {"node_type" : "VariableNode", "name" : "Pi_LEAD", "type" : "modelLocalVariable", "lag" : 0}, "arg2" : {"node_type" : "NumConstNode", "value" : 1}}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "VariableNode", "name" : "beta", "type" : "parameter", "lag" : 0}, "arg2" : {"node_type" : "UnaryOpNode", "op" : "exp", "arg" : {"node_type" : "BinaryOpNode", "op" : "-", "arg1" : {"node_type" : "BinaryOpNode", "op" : "+", "arg1" : {"node_type" : "VariableNode", "name" : "y", "type" : "endogenous", "lag" : 1}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "+", "arg1" : {"node_type" : "VariableNode", "name" : "d", "type" : "endogenous", "lag" : 1}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "VariableNode", "name" : "sigma", "type" : "parameter", "lag" : 0}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "-", "arg1" : {"node_type" : "VariableNode", "name" : "c", "type" : "modelLocalVariable", "lag" : 0}, "arg2" : {"node_type" : "VariableNode", "name" : "c_LEAD", "type" : "modelLocalVariable", "lag" : 0}}}}}, "arg2" : {"node_type" : "VariableNode", "name" : "y", "type" : "endogenous", "lag" : 0}}}}}}}}}, { "number":3, "line":40, "AST": {"node_type" : "BinaryOpNode", "op" : "=", "arg1" : {"node_type" : "VariableNode", "name" : "d", "type" : "endogenous", "lag" : 0}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "+", "arg1" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "VariableNode", "name" : "rhod", "type" : "parameter", "lag" : 0}, "arg2" : {"node_type" : "VariableNode", "name" : "d", "type" : "endogenous", "lag" : -1}}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "VariableNode", "name" : "sigmad", "type" : "parameter", "lag" : 0}, "arg2" : {"node_type" : "VariableNode", "name" : "epsilond", "type" : "exogenous", "lag" : 0}}}}}, { "number":4, "line":41, "AST": {"node_type" : "BinaryOpNode", "op" : "=", "arg1" : {"node_type" : "VariableNode", "name" : "z", "type" : "endogenous", "lag" : 0}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "+", "arg1" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "VariableNode", "name" : "rhoz", "type" : "parameter", "lag" : 0}, "arg2" : {"node_type" : "VariableNode", "name" : "z", "type" : "endogenous", "lag" : -1}}, "arg2" : {"node_type" : "BinaryOpNode", "op" : "*", "arg1" : {"node_type" : "VariableNode", "name" : "sigmaz", "type" : "parameter", "lag" : 0}, "arg2" : {"node_type" : "VariableNode", "name" : "epsilonz", "type" : "exogenous", "lag" : 0}}}}}], "variable_mapping":[
], "statements": [{"statementName": "param_init", "name": "beta", "value": "0.997"},
...
```

@sebastien Thanks Sebastien, this is super helpful!

@MichelJuillard It's not feasible for DynareOBC to maintain its own preprocessor. Previously it could piggy back on the Dynare one.

As I said, what I need is the ability to evaluate the value of nonlinear expressions given as MLVs in both static and dynamic contexts. Under previous Dynare versions, a few simple regexps were sufficient to transform the _static.m and _dynamic.m files into ones outputting what is required.

There is really no need for a whole new interface. DynareOBC will inevitably end up exploiting Dynare internals due to the complexity of what it has to do.

For Dynare 4.6 to be usable, all that is needed is a comment at the end of lines defining MLVs in the _tt files stating which MLV this is.

@MichelJuillard The point is that in previous versions I didn't have to use the T variables. The _static.m and _dynamic.m files contained lines of the form:

`MLVName__ = something;`

These directly gave me the required MLVs.

Per a request from a DynareOBC user, today I started working on making DynareOBC compatible with Dynare 4.6.

This is proving harder than expected due to the changes to preprocessor output.

Previously, DynareOBC relied on the *_static.m and *_dynamic.m files containing lines giving the value of model local variables (MLVs). This is used in multiple places, e.g. for obtaining the steady state of the augmented model, or for generating code for MLV simulation.

Of course, it is not your duty to support DynareOBC, but having this information in the static and dynamic files was generally useful. For example, in code prepared for the Dynare summer school I used to teach, I used this feature to facilitate writing code for a "perturbation plus" type simulation algorithm (i.e. perturbation used for next period values conditional on today's state and future shock, but given this approximation, the full nonlinear equations + cubature were used to derive today's value).

To make things easy again, it would be sufficient if the generated *_tt.m added comments at the end of each line defining a temporary variable (i.e. T(*)) definition with the name of the MLV to which the given element T(*) corresponds. E.g.:

`#dynareOBCMaxFunc1=max(dynareOBCMaxArgA1,dynareOBCMaxArgB1);`

would become:

`T(14) = max(T(12),T(13)); % dynareOBCMaxFunc1`

Alternatively, the optionally generated JSON could contain this information.

However, I guess that for either of these approaches to be viable as a strategy for DynareOBC to support Dynare 4.6, this would need to be added to Dynare fairly quickly (e.g. for 4.6.2), which may not be viable.

If this is not possible, (and in any case), it would be good to have some documentation of what users can safely assume about the elements of the T vector. A few relevant questions follow:

- Are all MLVs defined in the model block and used somewhere in the model guaranteed to be in the T vector?
- If MLV A is defined before MLV B in the model block, then will A definitely be before B in the T vector?
- Are the MLVs guaranteed to be the first elements of the T vector, or could MLVs and generated temporaries be interspersed?