common parsing: jsonmodel not necessary as tag info is in AST

time-shift
Houtan Bastani 2019-01-22 00:57:24 +01:00
parent 407ac26f5b
commit e1b01d9225
No known key found for this signature in database
GPG Key ID: 000094FB955BE169
9 changed files with 94 additions and 138 deletions

View File

@ -1,12 +1,11 @@
function [Y, lhssub, X, startdates, enddates, residnames] = common_parsing(ds, ast, jsonmodel, overlapping_dates)
%function [Y, lhssub, X, startdates, enddates, residnames] = common_parsing(ds, ast, jsonmodel, overlapping_dates)
function [Y, lhssub, X, startdates, enddates, residnames] = common_parsing(ds, ast, overlapping_dates)
%function [Y, lhssub, X, startdates, enddates, residnames] = common_parsing(ds, ast, overlapping_dates)
%
% Code common to sur.m and pooled_ols.m
%
% INPUTS
% ds [dseries] dataset
% ast [cell array] JSON representation of abstract syntax tree
% jsonmodel [cell array] JSON representation of model block
% overlapping_dates [boolean] if true, dates are same across equations
%
% OUTPUTS
@ -54,7 +53,7 @@ residnames = cell(neqs, 1);
%% Loop over equations
for i = 1:neqs
[Y{i}, lhssub{i}, X{i}, residnames{i}, startdates{i}, enddates{i}] = ...
parse_ols_style_equation(ds, ast{i}, jsonmodel{i});
parse_ols_style_equation(ds, ast{i});
end
if overlapping_dates

View File

@ -64,21 +64,21 @@ if nargin < 3
end
%% Get Equation(s)
[ast, jsonmodel] = get_ast_jsonmodel(eqtags);
ast = get_ast(eqtags);
%% Parse equations
[Y, lhssub, X, fp, lp] = common_parsing(ds, ast, jsonmodel, true);
[Y, lhssub, X, fp, lp] = common_parsing(ds, ast, true);
%% Loop over equations
for i = 1:length(Y)
pnames = X{i}.name;
[nobs, nvars] = size(X{i}.data);
if isfield(jsonmodel{i}, 'tags') && ...
isfield(jsonmodel{i}.tags, 'name')
tag = jsonmodel{i}.tags.('name');
if isfield(ast{i}, 'tags') && ...
isfield(ast{i}.tags, 'name')
tag = ast{i}.tags.('name');
else
tag = ['eq_line_no_' num2str(jsonmodel{i}.line)];
tag = ['eq_line_no_' num2str(ast{i}.line)];
end
%% Estimation
@ -155,7 +155,7 @@ for i = 1:length(Y)
title = ['OLS Estimation of equation ''' tag ''''];
end
preamble = {sprintf('Dependent Variable: %s', jsonmodel{i}.lhs), ...
preamble = {['Dependent Variable: ' Y{i}.name{:}], ...
sprintf('No. Independent Variables: %d', nvars), ...
sprintf('Observations: %d from %s to %s\n', nobs, fp{i}.char, lp{i}.char)};

View File

@ -1,23 +1,23 @@
function [jsonmodel] = getEquationsByTags(jsonmodel, tagname, tagvalue)
%function [jsonmodel] = getEquationsByTags(jsonmodel, tagname, tagvalue)
% Return the jsonmodel structure with the matching tags
function [ast] = getEquationsByTags(ast, tagname, tagvalue)
%function [ast] = getEquationsByTags(ast, tagname, tagvalue)
% Return the ast structure with the matching tags
%
% INPUTS
% jsonmodel [cell array] JSON representation of model block
% tagname [string] The name of the tag whos values are to
% be selected
% tagvalue [string] The values to be selected for the
% provided tagname
% ast [cell array] JSON representation of model block
% tagname [string] The name of the tag whos values are to
% be selected
% tagvalue [string] The values to be selected for the
% provided tagname
%
% OUTPUTS
% jsonmodel [cell array] JSON representation of model block,
% with equations removed that don't match
% eqtags
% ast [cell array] JSON representation of model block,
% with equations removed that don't match
% eqtags
%
% SPECIAL REQUIREMENTS
% none
% Copyright (C) 2017-2018 Dynare Team
% Copyright (C) 2017-2019 Dynare Team
%
% This file is part of Dynare.
%
@ -34,24 +34,34 @@ function [jsonmodel] = getEquationsByTags(jsonmodel, tagname, tagvalue)
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
assert(nargin == 3, 'Incorrect number of arguments passed to getEquationsByTags');
assert(iscell(jsonmodel) && ~isempty(jsonmodel), ...
'the first argument must be a cell array of structs');
assert(ischar(tagname), 'Tag name must be a string');
assert(ischar(tagvalue) || iscell(tagvalue), 'Tag value must be a string or a cell string array');
if nargin ~= 3
error('Incorrect number of arguments passed to function')
end
if isempty(ast) || ~iscell(ast)
error('the first argument must be a cell array of structs');
end
if ~ischar(tagname)
error('Tag name must be a string');
end
if ~ischar(tagvalue) && ~iscell(tagvalue)
error('Tag value must be a string or a cell string array');
end
if ischar(tagvalue)
tagvalue = {tagvalue};
end
idx2keep = [];
for i=1:length(tagvalue)
for i = 1:length(tagvalue)
found = false;
for j=1:length(jsonmodel)
assert(isstruct(jsonmodel{j}), 'Every entry in jsonmodel must be a struct');
if isfield(jsonmodel{j}, 'tags') && ...
isfield(jsonmodel{j}.tags, tagname) && ...
strcmp(jsonmodel{j}.tags.(tagname), tagvalue{i})
for j=1:length(ast)
assert(isstruct(ast{j}), 'Every entry in the ast must be a struct');
if isfield(ast{j}, 'tags') && ...
isfield(ast{j}.tags, tagname) && ...
strcmp(ast{j}.tags.(tagname), tagvalue{i})
idx2keep = [idx2keep; j];
found = true;
break
@ -62,5 +72,5 @@ for i=1:length(tagvalue)
end
end
assert(~isempty(idx2keep), 'getEquationsByTags: no equations selected');
jsonmodel = jsonmodel(unique(idx2keep, 'stable'));
ast = ast(unique(idx2keep, 'stable'));
end

View File

@ -1,15 +1,14 @@
function [ast, jsonmodel] = get_ast_jsonmodel(eqtags)
% function [ast, jsonmodel] = get_ast_jsonmodel(eqtags)
% return AST and jsonmodel from json output of preprocessor for the given
% equation tags.
function ast = get_ast(eqtags)
%function ast = get_ast(eqtags)
% return the Abstract Syntax Tree the JSON output of preprocessor for the
% given equation tags. Equations are ordered in eqtag order
%
% INPUTS
% eqtags [cellstr] names of equation tags for which to get info.
% If empty, get all
% If empty, get all equations
%
% OUTPUTS
% ast [cell array] JSON representation of the abstract syntax tree
% jsonmodel [cell array] JSON representation of the model block
%
% SPECIAL REQUIREMENTS
% none
@ -39,14 +38,14 @@ end
jsonfile = [M_.fname filesep() 'model' filesep() 'json' filesep() 'modfile-original.json'];
if exist(jsonfile, 'file') ~= 2
error('Could not find %s! Please use the json=compute option (See the Dynare invocation section in the reference manual).', jsonfile);
error(['Could not find ' jsonfile '! ' ...
'Please use the json=compute option ' ...
'(See the Dynare invocation section in the reference manual).']);
end
jsonmodel = loadjson(jsonfile);
ast = jsonmodel.abstract_syntax_tree;
jsonmodel = jsonmodel.model;
ast = loadjson(jsonfile);
ast = ast.abstract_syntax_tree;
if ~isempty(eqtags)
ast = getEquationsByTags(ast, 'name', eqtags);
jsonmodel = getEquationsByTags(jsonmodel, 'name', eqtags);
end
end
end

View File

@ -1,18 +1,16 @@
function [ast, jsonmodel, ds] = handle_constant_eqs(ast, jsonmodel, ds)
%function [ast, jsonmodel, ds] = handle_constant_eqs(ast, jsonmodel, ds)
function [ast, ds] = handle_constant_eqs(ast, ds)
%function [ast, ds] = handle_constant_eqs(ast, ds)
%
% Code to handle equations of type `X = 0;` in AST. Returns equation(s)
% removed from AST and ds.X == 0.
%
% INPUTS
% ast [cell array] JSON representation of abstract syntax tree
% jsonmodel [cell array] JSON representation of model block
% ds [dseries] data to be updated
% ast [cell array] JSON representation of abstract syntax tree
% ds [dseries] data to be updated
%
% OUTPUTS
% ast [cell array] updated JSON representation of abstract syntax tree
% jsonmodel [cell array] JSON representation of model block
% ds [dseries] data to be updated
% ast [cell array] updated JSON representation of abstract syntax tree
% ds [dseries] data to be updated
%
% SPECIAL REQUIREMENTS
% none
@ -34,6 +32,18 @@ function [ast, jsonmodel, ds] = handle_constant_eqs(ast, jsonmodel, ds)
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
if nargin ~= 2
error('Incorrect number of arguments to function')
end
if isempty(ast) || ~iscell(ast)
error('ast must be a cell')
end
if isempty(ds) || ~isdseries(ds)
error('ds must be a nonempty dseries')
end
for i = length(ast):-1:1
assert(strcmp(ast{i}.AST.node_type, 'BinaryOpNode') && strcmp(ast{i}.AST.op, '='), 'Expecting equation');
if strcmp(ast{i}.AST.arg2.node_type, 'NumConstNode')
@ -43,61 +53,6 @@ for i = length(ast):-1:1
ds.(ast{i}.AST.arg1.name) = ...
dseries(ast{i}.AST.arg2.value*ones(ds.nobs, 1), ds.firstdate, ast{i}.AST.arg1.name);
ast = ast([1:i-1, i+1:end]);
jsonmodel = jsonmodel([1:i-1, i+1:end]);
end
end
% for i = 1:length(ast)
% ast{i}.AST.arg2 = replace_in_equtaion_recursive(ast{i}.AST.arg2, vars_and_vals);
% end
end
% function node = replace_in_equtaion_recursive(node, vars_and_vals)
% if strcmp(node.node_type, 'NumConstNode')
% elseif strcmp(node.node_type, 'VariableNode')
% if strcmp(node.type, 'endogenous')
% if any(strcmp(vars_and_vals(:,1), node.name))
% node = struct('node_type', 'NumConstNode', ...
% 'value', vars_and_vals{strcmp(vars_and_vals(:,1), node.name), 2});
% end
% end
% elseif strcmp(node.node_type, 'UnaryOpNode')
% node.arg = replace_in_equtaion_recursive(node.arg, vars_and_vals);
% if strcmp(node.arg.node_type, 'NumConstNode')
% switch node.op
% case 'log'
% node = struct('node_type', 'NumConstNode', ...
% 'value', log(node.arg.value));
% case 'exp'
% node = struct('node_type', 'NumConstNode', ...
% 'value', exp(node.arg.value));
% case 'uminus'
% node = struct('node_type', 'NumConstNode', ...
% 'value', -node.arg.value);
% end
% end
% elseif strcmp(node.node_type, 'BinaryOpNode')
% node.arg1 = replace_in_equtaion_recursive(node.arg1, vars_and_vals);
% node.arg2 = replace_in_equtaion_recursive(node.arg2, vars_and_vals);
% if strcmp(node.arg1.node_type, 'NumConstNode')
% if strcmp(node.arg2.node_type, 'NumConstNode')
% node = struct('node_type', 'NumConstNode', ...
% 'value', eval(['node.arg1.value' node.op 'node.arg1.value']));
% elseif node.arg1.value == 0
% if strcmp(node.op, 'minus')
% node = struct('node_type', 'UnaryOpNode', ...
% 'op', 'uminus', ...
% 'arg', node.arg2);
% elseif strcmp(node.op, 'plus')
% node = node.arg2;
% else
% error(['Node type not supported ' node.op]);
% end
% end
% end
% if strcmp(node.arg2.node_type, 'NumConstNode') && node.arg2.value == 0
% node = node.arg1;
% end
% else
% error(['Node type not supported: ' node.node_type])
% end
% end

View File

@ -1,12 +1,11 @@
function [Y, lhssub, X, residual, fp, lp] = parse_ols_style_equation(ds, ast, jsonmodel)
%function X = parse_ols_style_equation()
function [Y, lhssub, X, residual, fp, lp] = parse_ols_style_equation(ds, ast)
%function [Y, lhssub, X, residual, fp, lp] = parse_ols_style_equation(ds, ast)
% Run OLS on chosen model equations; unlike olseqs, allow for time t
% endogenous variables on LHS
%
% INPUTS
% ds [dseries] data
% ast [struct] AST representing the equation to be parsed
% jsonmodel [cell array] JSON representation of model block
%
% OUTPUTS
% Y [dseries] LHS of the equation (with lhssub subtracted)
@ -37,8 +36,8 @@ function [Y, lhssub, X, residual, fp, lp] = parse_ols_style_equation(ds, ast, js
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
%% Check inputs
if nargin ~= 3
error('parse_ols_style_equation takes 3 arguments')
if nargin ~= 2
error('parse_ols_style_equation takes 2 arguments')
end
if isempty(ds) || ~isdseries(ds)
@ -46,7 +45,7 @@ if isempty(ds) || ~isdseries(ds)
end
if isempty(ast) || ~isstruct(ast)
error('ast must be a struct');
error('parse_ols_style_equation: arg 2 must be a struct');
end
line = ast.line;
@ -65,10 +64,6 @@ else
end
end
if isempty(jsonmodel) || ~isstruct(jsonmodel)
error('jsonmodel must be a struct');
end
%% Set LHS (Y)
lhssub = dseries();
Y = evalNode(ds, ast.AST.arg1, line, dseries());
@ -161,12 +156,12 @@ if ~isempty(lhssub)
end
% If it exists, account for tag set in mod file
if isfield(jsonmodel, 'tags') ...
&& isfield(jsonmodel.tags, 'sample') ...
&& ~isempty(jsonmodel.tags.sample)
colon_idx = strfind(jsonmodel.tags.sample, ':');
fsd = dates(jsonmodel.tags.sample(1:colon_idx-1));
lsd = dates(jsonmodel.tags.sample(colon_idx+1:end));
if isfield(ast, 'tags') ...
&& isfield(ast.tags, 'sample') ...
&& ~isempty(ast.tags.sample)
colon_idx = strfind(ast.tags.sample, ':');
fsd = dates(ast.tags.sample(1:colon_idx-1));
lsd = dates(ast.tags.sample(colon_idx+1:end));
if fp > fsd
warning(['The sample over which you want to estimate contains NaNs. '...
'Adjusting estimation range to begin on: ' fp.char])

View File

@ -67,8 +67,8 @@ else
end
%% Get Equation(s)
[ast, jsonmodel] = get_ast_jsonmodel(eqtags);
neqs = length(jsonmodel);
ast = get_ast(eqtags);
neqs = length(ast);
%% Replace parameter names in equations
country_name = param_common{1};
@ -76,8 +76,8 @@ regexcountries = ['(' strjoin(param_common(2:end),'|') ')'];
ast = replace_parameters(ast, country_name, regexcountries, param_regex);
%% Find parameters and variable names in every equation & Setup estimation matrices
[Y, ~, X, ~, ~, residnames] = common_parsing(ds, ast, jsonmodel, overlapping_dates);
clear ast jsonmodel;
[Y, ~, X, ~, ~, residnames] = common_parsing(ds, ast, overlapping_dates);
clear ast
nobs = zeros(length(Y), 1);
nobs(1) = Y{1}.nobs;
fp = Y{1}.firstobservedperiod;

View File

@ -47,13 +47,13 @@ else
end
%% Get Equation(s)
[ast, jsonmodel] = get_ast_jsonmodel(eqtags);
[ast, jsonmodel, ds] = handle_constant_eqs(ast, jsonmodel, ds);
neqs = length(jsonmodel);
ast = get_ast(eqtags);
[ast, ds] = handle_constant_eqs(ast, ds);
neqs = length(ast);
%% Find parameters and variable names in equations and setup estimation matrices
[Y, ~, X] = common_parsing(ds, ast, jsonmodel, true);
clear ast jsonmodel;
[Y, ~, X] = common_parsing(ds, ast, true);
clear ast
nobs = Y{1}.nobs;
[Y, X, constrained] = put_in_sur_form(Y, X);

View File

@ -123,9 +123,7 @@ else
end
%% Parse equation
[ast, jsonmodel] = get_ast_jsonmodel({eqtag});
[Y, ~, X, fp, lp] = common_parsing(ds, ast, jsonmodel, true);
clear ast jsonmodel
[Y, ~, X, fp, lp] = common_parsing(ds, get_ast({eqtag}), true);
lhsname = Y{1}.name;
Y = Y{1}.data;
X = X{1};