1function disp_identification(pdraws, ide_reducedform, ide_moments, ide_spectrum, ide_minimal, name, options_ident)
2% disp_identification(pdraws, ide_reducedform, ide_moments, ide_spectrum, ide_minimal, name, options_ident)
3% -------------------------------------------------------------------------
4% This function displays all identification analysis to the command line
5% =========================================================================
6% INPUTS
7%   pdraws:             [SampleSize by totparam_nbr] parameter draws
8%   ide_reducedform:    [structure] Containing results from identification
9%                       analysis based on the reduced-form solution (Ratto
10%                       and Iskrev, 2011).
11%   ide_moments:        [structure] Containing results from identification
12%                       analysis based on moments (Iskrev, 2010).
13%   ide_spectrum:       [structure] Containing results from identification
14%                       analysis based on the spectrum (Qu and Tkachenko, 2012).
15%   ide_minimal:        [structure] Containing results from identification
16%                       analysis based on the minimal state space system
17%                       (Komunjer and Ng, 2011).
18%   name:               [totparam_nbr by 1] string cell of parameter names
19%   options_ident:      [structure] identification options
20% -------------------------------------------------------------------------
21% OUTPUTS
22%   * all output is printed on the command line
23% -------------------------------------------------------------------------
24% This function is called by
25%   * dynare_identification.m
26% =========================================================================
27% Copyright (C) 2010-2019 Dynare Team
28%
29% This file is part of Dynare.
30%
31% Dynare is free software: you can redistribute it and/or modify
32% it under the terms of the GNU General Public License as published by
33% the Free Software Foundation, either version 3 of the License, or
34% (at your option) any later version.
35%
36% Dynare is distributed in the hope that it will be useful,
37% but WITHOUT ANY WARRANTY; without even the implied warranty of
38% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
39% GNU General Public License for more details.
40%
41% You should have received a copy of the GNU General Public License
42% along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
43% =========================================================================
44[SampleSize, totparam_nbr] = size(pdraws);
45no_identification_reducedform      = options_ident.no_identification_reducedform;
46no_identification_moments          = options_ident.no_identification_moments;
47no_identification_spectrum         = options_ident.no_identification_spectrum;
48no_identification_minimal          = options_ident.no_identification_minimal;
49tol_rank           = options_ident.tol_rank;
50checks_via_subsets = options_ident.checks_via_subsets;
51
52%% Display settings
53disp(['  ']),
54fprintf('Note that differences in the criteria could be due to numerical settings,\n')
55fprintf('numerical errors or the method used to find problematic parameter sets.\n')
56fprintf('Settings:\n')
57if options_ident.analytic_derivation_mode == 0
58    fprintf('    Derivation mode for Jacobians:                         Analytic using sylvester equations\n');
59elseif options_ident.analytic_derivation_mode == 1
60    fprintf('    Derivation mode for Jacobians:                         Analytic using kronecker products\n');
61elseif options_ident.analytic_derivation_mode < 0
62    fprintf('    Derivation mode for Jacobians:                         Numerical\n');
63end
64if checks_via_subsets
65    fprintf('    Method to find problematic parameters:                 Rank condition on all possible subsets\n');
66else
67    fprintf('    Method to find problematic parameters:                 Nullspace and multicorrelation coefficients\n');
68end
69if options_ident.normalize_jacobians == 1
70    fprintf('    Normalize Jacobians:                                   Yes\n');
71else
72    fprintf('    Normalize Jacobians:                                   No\n');
73end
74fprintf('    Tolerance level for rank computations:                 %s\n',num2str(options_ident.tol_rank));
75fprintf('    Tolerance level for selecting nonzero columns:         %.0d\n',options_ident.tol_deriv);
76fprintf('    Tolerance level for selecting nonzero singular values: %.0d\n',options_ident.tol_sv);
77
78
79%% Display problematic parameter sets for different criteria in a loop
80for jide = 1:4
81    no_warning_message_display = 1;
82    %% Set output strings depending on test
83    if jide == 1
84        strTest = 'REDUCED-FORM'; strJacobian = 'Tau'; strMeaning = 'Jacobian of steady state and reduced-form solution matrices';
85        if ~no_identification_reducedform
86            noidentification = 0; ide = ide_reducedform;
87            if SampleSize == 1
88                Jacob = ide.dREDUCEDFORM;
89            end
90        else %skip test
91            noidentification = 1; no_warning_message_display = 0;
92        end
93    elseif jide == 2
94        strTest = 'MINIMAL SYSTEM (Komunjer and Ng, 2011)'; strJacobian = 'Deltabar'; strMeaning = 'Jacobian of steady state and minimal system';
95        if options_ident.order == 2
96            strMeaning = 'Jacobian of first-order minimal system and second-order accurate mean';
97        elseif options_ident.order == 3
98            strMeaning = 'Jacobian of first-order minimal system and third-order accurate mean';
99        end
100        if ~no_identification_minimal
101            noidentification = 0; ide = ide_minimal;
102            if SampleSize == 1
103                Jacob = ide.dMINIMAL;
104            end
105        else %skip test
106            noidentification = 1; no_warning_message_display = 0;
107        end
108    elseif jide == 3
109        strTest = 'SPECTRUM (Qu and Tkachenko, 2012)'; strJacobian = 'Gbar'; strMeaning = 'Jacobian of mean and spectrum';
110        if options_ident.order > 1
111            strTest = 'SPECTRUM (Mutschler, 2015)';
112        end
113        if ~no_identification_spectrum
114            noidentification = 0; ide = ide_spectrum;
115            if SampleSize == 1
116                Jacob = ide.dSPECTRUM;
117            end
118        else %skip test
119            noidentification = 1; no_warning_message_display = 0;
120        end
121    elseif jide == 4
122        strTest = 'MOMENTS (Iskrev, 2010)'; strJacobian = 'J'; strMeaning = 'Jacobian of first two moments';
123        if options_ident.order > 1
124            strTest = 'MOMENTS (Mutschler, 2015)'; strJacobian = 'Mbar';
125        end
126        if ~no_identification_moments
127            noidentification = 0; ide = ide_moments;
128            if SampleSize == 1
129                Jacob = ide.si_dMOMENTS;
130            end
131        else %skip test
132            noidentification = 1; no_warning_message_display = 0;
133        end
134    end
135
136    if ~noidentification
137        %% display problematic parameters computed by identifcation_checks.m
138        if ~checks_via_subsets
139            if any(ide.ino) || any(any(ide.ind0==0)) || any(any(ide.jweak_pair))
140                no_warning_message_display=0;
141                skipline()
142                disp([upper(strTest), ':'])
143                disp('    !!!WARNING!!!');
144                if SampleSize>1
145                    disp(['    The rank of ', strJacobian, ' (', strMeaning, ') is deficient for ', num2str(length(find(ide.ino))),' out of ',int2str(SampleSize),' MC runs!'  ]),
146                else
147                    disp(['    The rank of ', strJacobian, ' (', strMeaning, ') is deficient!']),
148                end
149                skipline()
150                for j=1:totparam_nbr
151                    if any(ide.ind0(:,j)==0)
152                        pno = 100*length(find(ide.ind0(:,j)==0))/SampleSize;
153                        if SampleSize>1
154                            disp(['    ',name{j},' is not identified for ',num2str(pno),'% of MC runs!' ])
155                        else
156                            disp(['    ',name{j},' is not identified!' ])
157                        end
158                    end
159                end
160                npairs=size(ide.jweak_pair,2);
161                jmap_pair=dyn_unvech(1:npairs);
162                jstore=[];
163                for j=1:npairs
164                    iweak = length(find(ide.jweak_pair(:,j)));
165                    if iweak
166                        [jx,jy]=find(jmap_pair==j);
167                        jstore=[jstore jx(1) jy(1)];
168                        if SampleSize > 1
169                            disp(['    [',name{jx(1)},',',name{jy(1)},'] are PAIRWISE collinear for ',num2str((iweak)/SampleSize*100),'% of MC runs!' ])
170                        else
171                            disp(['    [',name{jx(1)},',',name{jy(1)},'] are PAIRWISE collinear!' ])
172                        end
173                    end
174                end
175                for j=1:totparam_nbr
176                    iweak = length(find(ide.jweak(:,j)));
177                    if iweak && ~ismember(j,jstore)
178                        if SampleSize>1
179                            disp(['    ',name{j},' is collinear w.r.t. all other parameters for ',num2str(iweak/SampleSize*100),'% of MC runs!' ])
180                        else
181                            disp(['    ',name{j},' is collinear w.r.t. all other parameters!' ])
182                        end
183                    end
184                end
185            end
186
187            %% display problematic parameters computed by identification_checks_via_subsets
188        elseif checks_via_subsets
189            if ide.rank < size(Jacob,2)
190                no_warning_message_display = 0;
191                skipline()
192                disp([upper(strTest), ':'])
193                disp('    !!!WARNING!!!');
194                if SampleSize>1
195                    disp(['    The rank of ', strJacobian, ' (', strMeaning, ') is deficient for ', num2str(length(find(ide.ino))),' out of ',int2str(SampleSize),' MC runs!'  ]),
196                else
197                    disp(['    The rank of ', strJacobian, ' (', strMeaning, ') is deficient!']),
198                end
199                if all(cellfun(@isempty,ide.problpars))
200                    disp(['    No problematic parameter combinations with maximum dimension ', num2str(size(ide.problpars,2)), ' were found. Increase max_dim_subsets_groups.']);
201                    skipline()
202                else
203                    disp(['    Displaying problematic parameter combinations (with maximum dimension ', num2str(size(ide.problpars,2)), '):']);
204                    skipline()
205                    probparamset_nbr = 0;
206                    for jset = 1:size(ide.problpars,2)
207                        if isempty(ide.problpars{jset}) == 0
208                            for jrow = 1:size(ide.problpars{jset},1)
209                                for j = transpose(ide.problpars{jset}(jrow,:))
210                                    probparamset_nbr = probparamset_nbr + 1;
211                                    %pno = 100*length(find(ide.ind0(:,j)==0))/SampleSize;
212                                    problparnamestring = strjoin(eval(['[', sprintf('name(%d), ', j), ']']),',');
213                                    if SampleSize > 1
214                                        if length(j) == 1
215                                            disp(['    ',problparnamestring,' is not identified for ',num2str(pno),'% of MC runs!' ])
216                                        else
217                                            disp(['    [',problparnamestring,'] are collinear (with tol = ', num2str(tol_rank), ') for ',num2str((iweak)/SampleSize*100),'% of MC runs!' ])
218                                        end
219                                    else
220                                        if length(j) == 1
221                                            disp(['    ',problparnamestring, ' is not identified!' ])
222                                        else
223                                            disp(['    [',problparnamestring, '] are collinear!' ])
224                                        end
225                                    end
226                                end
227                            end
228                        end
229                    end
230                end
231            end
232        end
233    end
234    %% All parameters are identified
235    if no_warning_message_display
236        skipline()
237        disp([upper(strTest), ':']);
238        disp(['    All parameters are identified in the ', strMeaning, ' (rank(', strJacobian, ') is full with tol = ', num2str(tol_rank), ').' ]),
239    end
240end
241
242
243
244%% Advanced identificaton patterns
245if SampleSize==1 && options_ident.advanced
246    skipline()
247    for j=1:size(ide_moments.cosndMOMENTS,2)
248        pax=NaN(totparam_nbr,totparam_nbr);
249        fprintf('\n')
250        disp(['Collinearity patterns with ', int2str(j) ,' parameter(s)'])
251        fprintf('%-15s [%-*s] %10s\n','Parameter',(15+1)*j,' Expl. params ','cosn')
252        for i=1:totparam_nbr
253            namx='';
254            for in=1:j
255                dumpindx = ide_moments.pars{i,j}(in);
256                if isnan(dumpindx)
257                    namx=[namx ' ' sprintf('%-15s','--')];
258                else
259                    namx=[namx ' ' sprintf('%-15s',name{dumpindx})];
260                    pax(i,dumpindx)=ide_moments.cosndMOMENTS(i,j);
261                end
262            end
263            fprintf('%-15s [%s] %14.7f\n',name{i},namx,ide_moments.cosndMOMENTS(i,j))
264        end
265    end
266end
267