time   | Calls   |  line  | 
|---|
 |  |    7   | function [result_map] = ff_az_ds_vecsv(varargin)
   | 
 |  |    8   | %% FF_AZ_DS_VECSV finds the stationary asset distributions analytically
   | 
 |  |    9   | % Here, we implement the iteration free semi-analytical method for finding
   | 
 |  |   10   | % asset distributions. The method analytically give the exact
   | 
 |  |   11   | % stationary distribution induced by the policy function from the dynamic
   | 
 |  |   12   | % programming problem, conditional on discretizations.
   | 
 |  |   13   | %
   | 
 |  |   14   | % See the appedix of
   | 
 |  |   15   | % <https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3316939 Wang (2019)>
   | 
 |  |   16   | % which develops details on how this works. Suppose endo state size is N and
   | 
 |  |   17   | % shock is size M, then our transition matrix is (NxM) by (NxM). We know
   | 
 |  |   18   | % the coh(a,z) value associated with each element of the (NxM) by 1 array.
   | 
 |  |   19   | % We also know f(a'(a,z),z'|z) transition probability. We contruct a markov
   | 
 |  |   20   | % chain that has (NxM) states. Specifically:
   | 
 |  |   21   | %
   | 
 |  |   22   | % * We need to transform: mt_pol_idx. This matrix is indexing 1 through N,
   | 
 |  |   23   | % we need for it to index 1 through (NxM).
   | 
 |  |   24   | % * Then we need to duplicate the transition matrix fro shocks.
   | 
 |  |   25   | % * Transition Matrix is *sparse*
   | 
 |  |   26   | %
   | 
 |  |   27   | % Once we have the all states meshed markov transition matrix, then we can
   | 
 |  |   28   | % use standard methods to find the stationary distribution. Three options
   | 
 |  |   29   | % are offered here that provide identical solutions:
   | 
 |  |   30   | %
   | 
 |  |   31   | % # The Eigenvector Approach: very fast
   | 
 |  |   32   | % # The Projection Approach: medium
   | 
 |  |   33   | % # The Power Approach: very slow (especially with sparse matrix)
   | 
 |  |   34   | %
   | 
 |  |   35   | % The program here builds on the Asset Dynamic Programming Problem
   | 
 |  |   36   | % <https://fanwangecon.github.io/CodeDynaAsset/m_az/solve/html/ff_az_vf_vecsv.html
   | 
 |  |   37   | % ff_az_vf_vecsv>, here we solve for the asset distribution using
   | 
 |  |   38   | % vectorized codes.
   | 
 |  |   39   | % <https://fanwangecon.github.io/CodeDynaAsset/m_az/solve/html/ff_az_ds.html
   | 
 |  |   40   | % ff_az_ds> shows looped codes for finding asset distribution. The solution
   | 
 |  |   41   | % is the same. Both *ff_az_ds* and *ff_az_ds_vec* using
   | 
 |  |   42   | % optimized-vectorized dynamic programming code from ff_az_vf_vecsv. The
   | 
 |  |   43   | % idea here is that in addition to vectornizing the dynamic programming
   | 
 |  |   44   | % funcion, we can also vectorize the distribution code here.
   | 
 |  |   45   | %
   | 
 |  |   46   | % Distributions of Interest:
   | 
 |  |   47   | %
   | 
 |  |   48   | % * $p(a,z)$
   | 
 |  |   49   | % * $p(Y=y, z) = \sum_{a} \left( 1\left\{Y(a,z)=y\right\} \cdot p(a,z) \right)$
  | 
 |  |   50   | % * $p(Y=y, a) = \sum_{z} \left( 1\left\{Y(a,z)=y\right\} \cdot p(a,z) \right)$
  | 
 |  |   51   | % * $p(Y=y) = \sum_{a,z} \left( 1\left\{Y(a,z)=y\right\} \cdot p(a,z) \right)$
  | 
 |  |   52   | %
   | 
 |  |   53   | % Statistics include:
   | 
 |  |   54   | %
   | 
 |  |   55   | % * $\mu_y = \sum_{y} p(Y=y) \cdot y$
  | 
 |  |   56   | % * $\sigma_y = \sqrt{ \sum_{y} p(Y=y) \cdot \left( y - \mu_y \right)^2}$
  | 
 |  |   57   | % * $p(y=0)$
   | 
 |  |   58   | % * $p(y=\max(y))$
   | 
 |  |   59   | % * percentiles: $min_{y} \left\{ P(Y \le y) - percentile \mid P(Y \le y) \ge percentile \right\}$
  | 
 |  |   60   | % * fraction of outcome held by up to percentiles: $E(Y<y)/E(Y)$
   | 
 |  |   61   | %
   | 
 |  |   62   | % @param param_map container parameter container
   | 
 |  |   63   | %
   | 
 |  |   64   | % @param support_map container support container
   | 
 |  |   65   | %
   | 
 |  |   66   | % @param armt_map container container with states, choices and shocks
   | 
 |  |   67   | % grids that are inputs for grid based solution algorithm
   | 
 |  |   68   | %
   | 
 |  |   69   | % @param func_map container container with function handles for
   | 
 |  |   70   | % consumption cash-on-hand etc.
   | 
 |  |   71   | %
   | 
 |  |   72   | % @return result_map container contains policy function matrix, value
   | 
 |  |   73   | % function matrix, iteration results, and policy function, value function
   | 
 |  |   74   | % and iteration results tables.
   | 
 |  |   75   | %
   | 
 |  |   76   | % new keys included in result_map in addition to the output from
   | 
 |  |   77   | % <https://fanwangecon.github.io/CodeDynaAsset/m_az/solve/html/ff_az_vf_vecsv.html
   | 
 |  |   78   | % ff_az_vf_vecsv> are various distribution statistics for each model
   | 
 |  |   79   | % outcome, keys include *cl_mt_pol_a*, *cl_mt_pol_c*, *cl_mt_pol_coh*, etc.
   | 
 |  |   80   | %
   | 
 |  |   81   | % @example
   | 
 |  |   82   | %
   | 
 |  |   83   | %    % Get Default Parameters
   | 
 |  |   84   | %    it_param_set = 6;
   | 
 |  |   85   | %    [param_map, support_map] = ffs_az_set_default_param(it_param_set);
   | 
 |  |   86   | %    % Change Keys in param_map
   | 
 |  |   87   | %    param_map('it_a_n') = 500;
  | 
 |  |   88   | %    param_map('it_z_n') = 11;
  | 
 |  |   89   | %    param_map('fl_a_max') = 100;
  | 
 |  |   90   | %    param_map('fl_w') = 1.3;
  | 
 |  |   91   | %    % Change Keys support_map
   | 
 |  |   92   | %    support_map('bl_display') = false;
  | 
 |  |   93   | %    support_map('bl_post') = true;
  | 
 |  |   94   | %    support_map('bl_display_final') = false;
  | 
 |  |   95   | %    % Call Program with external parameters that override defaults
   | 
 |  |   96   | %    ff_az_ds_vecsv(param_map, support_map);
   | 
 |  |   97   | %
   | 
 |  |   98   | %
   | 
 |  |   99   | % @include
   | 
 |  |  100   | %
   | 
 |  |  101   | % * <https://fanwangecon.github.io/CodeDynaAsset/m_az/solve/html/ff_az_vf_vecsv.html ff_az_vf_vecsv>
   | 
 |  |  102   | % * <https://fanwangecon.github.io/CodeDynaAsset/m_az/solvepost/html/ff_az_ds_post_stats.html ff_az_ds_post_stats>
   | 
 |  |  103   | % * <https://fanwangecon.github.io/CodeDynaAsset/tools/html/fft_disc_rand_var_stats.html fft_disc_rand_var_stats>
   | 
 |  |  104   | % * <https://fanwangecon.github.io/CodeDynaAsset/tools/html/fft_disc_rand_var_mass2outcomes.html fft_disc_rand_var_mass2outcomes>
   | 
 |  |  105   | %
   | 
 |  |  106   | % @seealso
   | 
 |  |  107   | %
   | 
 |  |  108   | % * derive distribution f(y'(y,z)) one asset *loop*: <https://fanwangecon.github.io/CodeDynaAsset/m_az/solve/html/ff_az_ds.html ff_az_ds>
   | 
 |  |  109   | % * derive distribution f(y'({x,y},z)) two assets *loop*: <https://fanwangecon.github.io/CodeDynaAsset/m_akz/solve/html/ff_akz_ds.html ff_akz_ds>
  | 
 |  |  110   | % * derive distribution f(y'({x,y},z, *z'*)) two assets *loop*: <https://fanwangecon.github.io/CodeDynaAsset/m_akz/solve/html/ff_iwkz_ds.html ff_iwkz_ds>
  | 
 |  |  111   | % * derive distribution f(y'({y},z)) or f(y'({x,y},z)) *vectorized*: <https://fanwangecon.github.io/CodeDynaAsset/m_az/solve/html/ff_az_ds_vec.html ff_az_ds_vec>
  | 
 |  |  112   | % * derive distribution f(y'({y},z, *z'*)) or f(y'({x,y},z, *z'*)) *vectorized*: <https://fanwangecon.github.io/CodeDynaAsset/m_akz/solve/html/ff_iwkz_ds_vec.html ff_iwkz_ds_vec>
  | 
 |  |  113   | % * derive distribution f(y'({y},z)) or f(y'({x,y},z)) *semi-analytical*: <https://fanwangecon.github.io/CodeDynaAsset/m_az/solve/html/ff_az_ds_vecsv.html ff_az_ds_vecsv>
  | 
 |  |  114   | % * derive distribution f(y'({y},z, *z'*)) or f(y'({x,y},z, *z'*)) *semi-analytical*: <https://fanwangecon.github.io/CodeDynaAsset/m_akz/solve/html/ff_iwkz_ds_vecsv.html ff_iwkz_ds_vecsv>
  | 
 |  |  115   | %
   | 
 |  |  116   | 
 
  | 
 |  |  117   | %% Default
   | 
 |  |  118   | % Program can be externally invoked with _az_, _abz_ or various other
   | 
 |  |  119   | % programs. By default, program invokes using _az_ model programs:
   | 
 |  |  120   | %
   | 
 |  |  121   | % # it_subset = 5 is basic invoke quick test
   | 
 |  |  122   | % # it_subset = 6 is invoke full test
   | 
 |  |  123   | % # it_subset = 7 is profiling invoke
   | 
 |  |  124   | % # it_subset = 8 is matlab publish
   | 
 |  |  125   | % # it_subset = 9 is invoke operational (only final stats) and coh graph
   | 
 |  |  126   | %
   | 
 |  |  127   | 
 
  | 
< 0.001   |       1   |  128  | params_len = length(varargin); 
   | 
< 0.001   |       1   |  129  | bl_input_override = 0; 
   | 
< 0.001   |       1   |  130  | if (params_len == 6) 
   | 
< 0.001   |       1   |  131  |     bl_input_override = varargin{6}; 
  | 
< 0.001   |       1   |  132  | end 
   | 
 |  |  133   | 
 
  | 
< 0.001   |       1   |  134  | if (bl_input_override) 
   | 
 |  |  135   |     % if invoked from outside override fully
   | 
< 0.001   |       1   |  136  |     [param_map, support_map, armt_map, func_map, result_map, ~] = varargin{:}; 
  | 
 |  |  137   | 
 
  | 
 |  |  138   | else
   | 
 |  |  139   |     % default invoke
   | 
 |  |  140   |     close all;
   | 
 |  |  141   | 
 
  | 
 |  |  142   |     it_param_set = 8;
   | 
 |  |  143   |     bl_input_override = true;
   | 
 |  |  144   | 
 
  | 
 |  |  145   |     % 1. Generate Parameters
   | 
 |  |  146   |     [param_map, support_map] = ffs_az_set_default_param(it_param_set);
   | 
 |  |  147   | 
 
  | 
 |  |  148   |     % Note: param_map and support_map can be adjusted here or outside to override defaults
   | 
 |  |  149   |     % param_map('it_a_n') = 750;
  | 
 |  |  150   |     % param_map('it_z_n') = 15;
  | 
 |  |  151   | 
 
  | 
 |  |  152   |     param_map('st_analytical_stationary_type') = 'eigenvector';
  | 
 |  |  153   | %     param_map('st_analytical_stationary_type') = 'projection';
  | 
 |  |  154   | %     param_map('st_analytical_stationary_type') = 'power';
  | 
 |  |  155   |     
   | 
 |  |  156   |     % 2. Generate function and grids
   | 
 |  |  157   |     [armt_map, func_map] = ffs_az_get_funcgrid(param_map, support_map, bl_input_override); % 1 for override
   | 
 |  |  158   | 
 
  | 
 |  |  159   |     % 3. Solve value and policy function using az_vf_vecsv, if want to solve
   | 
 |  |  160   |     % other models, solve outside then provide result_map as input
   | 
 |  |  161   |     [result_map] = ff_az_vf_vecsv(param_map, support_map, armt_map, func_map);
   | 
 |  |  162   | 
 
  | 
< 0.001   |       1   |  163  | end 
   | 
 |  |  164   | 
 
  | 
 |  |  165   | %% Parse Parameters
   | 
 |  |  166   | 
 
  | 
 |  |  167   | % append function name
   | 
< 0.001   |       1   |  168  | st_func_name = 'ff_az_ds_vecsv'; 
   | 
< 0.001   |       1   |  169  | support_map('st_profile_name_main') = [st_func_name support_map('st_profile_name_main')]; 
  | 
< 0.001   |       1   |  170  | support_map('st_mat_name_main') = [st_func_name support_map('st_mat_name_main')]; 
  | 
< 0.001   |       1   |  171  | support_map('st_img_name_main') = [st_func_name support_map('st_img_name_main')]; 
  | 
 |  |  172   | 
 
  | 
 |  |  173   | % result_map
   | 
 |  |  174   | % ar_st_pol_names is from section _Process Optimal Choices_ in the value
   | 
 |  |  175   | % function code.
   | 
< 0.001   |       1   |  176  | params_group = values(result_map, {'cl_mt_pol_a', 'mt_pol_idx', 'ar_st_pol_names'}); 
  | 
< 0.001   |       1   |  177  | [cl_mt_pol_a, mt_pol_idx, ar_st_pol_names] = params_group{:}; 
  | 
< 0.001   |       1   |  178  | mt_pol_a = deal(cl_mt_pol_a{1}); 
  | 
 |  |  179   | 
 
  | 
 |  |  180   | % armt_map
   | 
< 0.001   |       1   |  181  | params_group = values(armt_map, {'mt_z_trans'}); 
  | 
< 0.001   |       1   |  182  | [mt_z_trans] = params_group{:}; 
  | 
 |  |  183   | 
 
  | 
 |  |  184   | % param_map
   | 
< 0.001   |       1   |  185  | params_group = values(param_map, { 'it_trans_power_dist', 'st_analytical_stationary_type'}); 
  | 
< 0.001   |       1   |  186  | [it_trans_power_dist, st_analytical_stationary_type] = params_group{:}; 
  | 
 |  |  187   | 
 
  | 
 |  |  188   | 
 
  | 
 |  |  189   | % support_map
   | 
< 0.001   |       1   |  190  | params_group = values(support_map, {'bl_profile_dist', 'st_profile_path', ... 
  | 
 |  |  191   |     'st_profile_prefix', 'st_profile_name_main', 'st_profile_suffix',...
   | 
 |  |  192   |     'bl_time', 'bl_display_final_dist', 'bl_post'});
   | 
< 0.001   |       1   |  193  | [bl_profile_dist, st_profile_path, ... 
   | 
 |       1   |  194  |     st_profile_prefix, st_profile_name_main, st_profile_suffix, ... 
   | 
 |       1   |  195  |     bl_time, bl_display_final_dist, bl_post] = params_group{:}; 
  | 
 |  |  196   | 
 
  | 
 |  |  197   | %% Start Profiler and Timer
   | 
 |  |  198   | 
 
  | 
 |  |  199   | % Start Profile
   | 
< 0.001   |       1   |  200  | if (bl_profile_dist) 
   | 
 |  |  201   |     close all;
   | 
 |  |  202   |     profile off;
   | 
 |  |  203   |     profile on;
   | 
 |  |  204   | end
   | 
 |  |  205   | 
 
  | 
 |  |  206   | % Start Timer
   | 
< 0.001   |       1   |  207  | if (bl_time) 
   | 
< 0.001   |       1   |  208  |     tic; 
   | 
< 0.001   |       1   |  209  | end 
   | 
 |  |  210   | 
 
  | 
 |  |  211   | %% Get Size of Endogenous and Exogenous State
   | 
 |  |  212   | % The key idea is that all information for policy function is captured by
   | 
 |  |  213   | % _mt_pol_idx_ matrix, its rows are the number of endogenous states, and
   | 
 |  |  214   | % its columns are the exogenous shocks.
   | 
 |  |  215   | 
 
  | 
< 0.001   |       1   |  216  | [it_endostates_rows_n, it_exostates_cols_n] = size(mt_pol_idx); 
   | 
 |  |  217   | 
 
  | 
 |  |  218   | %% 1. Generate Max Index in (NxM) from (N) array.
   | 
 |  |  219   | % Suppose we have: 
   | 
 |  |  220   | %
   | 
 |  |  221   | %   mt_pol_idx =
   | 
 |  |  222   | % 
   | 
 |  |  223   | %      1     1     2
   | 
 |  |  224   | %      2     2     2
   | 
 |  |  225   | %      3     3     3
   | 
 |  |  226   | %      4     4     4
   | 
 |  |  227   | %      4     5     5
   | 
 |  |  228   | %
   | 
 |  |  229   | % These become:
   | 
 |  |  230   | %
   | 
 |  |  231   | %   mt_pol_idx_mesh_max = 
   | 
 |  |  232   | % 
   | 
 |  |  233   | %      1     6    11
   | 
 |  |  234   | %      2     7    12
   | 
 |  |  235   | %      3     8    13
   | 
 |  |  236   | %      4     9    14
   | 
 |  |  237   | %      5    10    15
   | 
 |  |  238   | %      1     6    11
   | 
 |  |  239   | %      2     7    12
   | 
 |  |  240   | %      3     8    13
   | 
 |  |  241   | %      4     9    14
   | 
 |  |  242   | %      5    10    15
   | 
 |  |  243   | %      1     6    11
   | 
 |  |  244   | %      2     7    12
   | 
 |  |  245   | %      3     8    13
   | 
 |  |  246   | %      4     9    14
   | 
 |  |  247   | %      5    10    15
   | 
 |  |  248   | %
   | 
 |  |  249   | 
 
  | 
 |  |  250   | % mt_pol_idx_mesh_max is (NxM) by M, mt_pol_idx is N by M
   | 
< 0.001   |       1   |  251  | mt_pol_idx_mesh_max = mt_pol_idx(:) + (0:1:(it_exostates_cols_n-1))*it_endostates_rows_n; 
   | 
 |  |  252   | 
 
  | 
 |  |  253   | %% 2. Transition Probabilities from (M by M) to (NxM) by M
   | 
 |  |  254   | %
   | 
 |  |  255   | %   mt_trans_prob =
   | 
 |  |  256   | % 
   | 
 |  |  257   | %     0.9332    0.0668    0.0000
   | 
 |  |  258   | %     0.9332    0.0668    0.0000
   | 
 |  |  259   | %     0.9332    0.0668    0.0000
   | 
 |  |  260   | %     0.9332    0.0668    0.0000
   | 
 |  |  261   | %     0.9332    0.0668    0.0000
   | 
 |  |  262   | %     0.0062    0.9876    0.0062
   | 
 |  |  263   | %     0.0062    0.9876    0.0062
   | 
 |  |  264   | %     0.0062    0.9876    0.0062
   | 
 |  |  265   | %     0.0062    0.9876    0.0062
   | 
 |  |  266   | %     0.0062    0.9876    0.0062
   | 
 |  |  267   | %     0.0000    0.0668    0.9332
   | 
 |  |  268   | %     0.0000    0.0668    0.9332
   | 
 |  |  269   | %     0.0000    0.0668    0.9332
   | 
 |  |  270   | %     0.0000    0.0668    0.9332
   | 
 |  |  271   | %     0.0000    0.0668    0.9332
   | 
 |  |  272   | %
   | 
 |  |  273   | 
 
  | 
< 0.001   |       1   |  274  | mt_trans_prob = reshape(repmat(mt_z_trans(:)', [it_endostates_rows_n, 1]), [it_endostates_rows_n*it_exostates_cols_n, it_exostates_cols_n]); 
   | 
 |  |  275   | 
 
  | 
 |  |  276   | %% 3. Fill mt_pol_idx_mesh_idx to mt_full_trans_mat
   | 
 |  |  277   | % Try to always use sparse matrix, unless grid sizes very small, keeping
   | 
 |  |  278   | % non-sparse code here for comparison. Sparse matrix is important for
   | 
 |  |  279   | % allowing the code to be fast and memory efficient. Otherwise this method
   | 
 |  |  280   | % is much slower than iterative method.
   | 
 |  |  281   | 
 
  | 
< 0.001   |       1   |  282  | it_sparse_threshold = 100*7; 
   | 
 |  |  283   | 
 
  | 
< 0.001   |       1   |  284  | if (it_endostates_rows_n*it_exostates_cols_n > it_sparse_threshold) 
   | 
 |  |  285   |     
   | 
 |  |  286   |     %% 3.1 Sparse Matrix Approach
   | 
< 0.001   |       1   |  287  |     i = mt_pol_idx_mesh_max(:); 
   | 
< 0.001   |       1   |  288  |     j = repmat((1:1:it_endostates_rows_n*it_exostates_cols_n),[1,it_exostates_cols_n])'; 
   | 
< 0.001   |       1   |  289  |     v = mt_trans_prob(:); 
   | 
< 0.001   |       1   |  290  |     m = it_endostates_rows_n*it_exostates_cols_n; 
   | 
< 0.001   |       1   |  291  |     n = it_endostates_rows_n*it_exostates_cols_n; 
   | 
  0.028   |       1   |  292  |     mt_full_trans_mat = sparse(i, j, v, m, n); 
   | 
 |  |  293   |     
   | 
 |  |  294   | else
   | 
 |  |  295   |     
   | 
 |  |  296   |     %% 3.2 Full Matrix Approach
   | 
 |  |  297   |     %
   | 
 |  |  298   |     %   ar_lin_idx_start_point =
   | 
 |  |  299   |     % 
   | 
 |  |  300   |     %      0    15    30    45    60    75    90   105   120   135   150   165   180   195   210
   | 
 |  |  301   |     %
   | 
 |  |  302   |     %   mt_pol_idx_mesh_idx_meshfull =
   | 
 |  |  303   |     % 
   | 
 |  |  304   |     %      1     6    11
   | 
 |  |  305   |     %     17    22    27
   | 
 |  |  306   |     %     33    38    43
   | 
 |  |  307   |     %     49    54    59
   | 
 |  |  308   |     %     65    70    75
   | 
 |  |  309   |     %     76    81    86
   | 
 |  |  310   |     %     92    97   102
   | 
 |  |  311   |     %    108   113   118
   | 
 |  |  312   |     %    124   129   134
   | 
 |  |  313   |     %    140   145   150
   | 
 |  |  314   |     %    151   156   161
   | 
 |  |  315   |     %    167   172   177
   | 
 |  |  316   |     %    183   188   193
   | 
 |  |  317   |     %    199   204   209
   | 
 |  |  318   |     %    215   220   225
   | 
 |  |  319   |     %
   | 
 |  |  320   | 
 
  | 
 |  |  321   |     % Each row's linear index starting point
   | 
 |  |  322   |     ar_lin_idx_start_point = ((it_endostates_rows_n*it_exostates_cols_n)*(0:1:(it_endostates_rows_n*it_exostates_cols_n-1)));
   | 
 |  |  323   | 
 
  | 
 |  |  324   |     % mt_pol_idx_mesh_idx_meshfull is (NxM) by M
   | 
 |  |  325   |     % Full index in (NxM) to (NxM) transition Matrix
   | 
 |  |  326   |     mt_pol_idx_mesh_idx_meshfull = mt_pol_idx_mesh_max + ar_lin_idx_start_point';
   | 
 |  |  327   | 
 
  | 
 |  |  328   |     % Fill mt_pol_idx_mesh_idx to mt_full_trans_mat
   | 
 |  |  329   |     mt_full_trans_mat = zeros([it_endostates_rows_n*it_exostates_cols_n, it_endostates_rows_n*it_exostates_cols_n]);    
   | 
 |  |  330   |     mt_full_trans_mat(mt_pol_idx_mesh_idx_meshfull(:)) = mt_trans_prob(:);
   | 
 |  |  331   |     
   | 
< 0.001   |       1   |  332  | end 
   | 
 |  |  333   | 
 
  | 
 |  |  334   | %% 4. Stationary Distribution *Method A*, Eigenvector Approach
   | 
 |  |  335   | % Given that markov chain we have constructured for all state-space
   | 
 |  |  336   | % elements, we can now find the stationary distribution using standard
   | 
 |  |  337   | % <https://en.wikipedia.org/wiki/Markov_chain#Stationary_distribution_relation_to_eigenvectors_and_simplices
   | 
 |  |  338   | % eigenvector> approach.
   | 
 |  |  339   | 
 
  | 
< 0.001   |       1   |  340  | if (strcmp(st_analytical_stationary_type, 'eigenvector')) 
   | 
  0.493   |       1   |  341  |     [V, ~] = eigs(mt_full_trans_mat,1,1); 
   | 
< 0.001   |       1   |  342  |     ar_stationary = V/sum(V); 
   | 
< 0.001   |       1   |  343  | end 
   | 
 |  |  344   | 
 
  | 
 |  |  345   | %% 5. Stationary Distribution *Method B*, Projection
   | 
 |  |  346   | % This uses Projection. 
   | 
 |  |  347   | 
 
  | 
< 0.001   |       1   |  348  | if (strcmp(st_analytical_stationary_type, 'projection')) 
   | 
 |  |  349   |     
   | 
 |  |  350   |     % a. Transition - I
   | 
 |  |  351   |     % P = P*T
   | 
 |  |  352   |     % 0 = P*T - P
   | 
 |  |  353   |     % 0 = P*(T-1)                
   | 
 |  |  354   |     % Q = trans_prob - np.identity(state_count);
   | 
 |  |  355   | 
 
  | 
 |  |  356   |     mt_diag = eye(it_endostates_rows_n*it_exostates_cols_n);
   | 
 |  |  357   |     if (it_endostates_rows_n*it_exostates_cols_n > it_sparse_threshold)
   | 
 |  |  358   |         % if larger, use sparse matrix
   | 
 |  |  359   |         mt_diag = sparse(mt_diag);
   | 
 |  |  360   |     end
   | 
 |  |  361   |     mt_Q = mt_full_trans_mat' - mt_diag;
   | 
 |  |  362   | 
 
  | 
 |  |  363   |     % b. add all 1 as final column, (because P*1 = 1) 
   | 
 |  |  364   |     % one_col = np.ones((state_count,1))
   | 
 |  |  365   |     % Q = np.column_stack((Q, one_col))
   | 
 |  |  366   | 
 
  | 
 |  |  367   |     ar_one = ones([it_endostates_rows_n*it_exostates_cols_n,1]);
   | 
 |  |  368   |     mt_Q = [mt_Q, ar_one];
   | 
 |  |  369   | 
 
  | 
 |  |  370   |     % c. b is the LHS 
   | 
 |  |  371   |     % b = [0,0,0,...,1]
   | 
 |  |  372   |     % b = np.zeros((1, (state_count+1)))
   | 
 |  |  373   |     % b[0, state_count] = 1
   | 
 |  |  374   | 
 
  | 
 |  |  375   |     ar_b = zeros([1, it_endostates_rows_n*it_exostates_cols_n+1]);
   | 
 |  |  376   |     if (it_endostates_rows_n*it_exostates_cols_n > it_sparse_threshold)
   | 
 |  |  377   |         % if larger, use sparse matrix
   | 
 |  |  378   |         ar_b = sparse(ar_b);
   | 
 |  |  379   |     end    
   | 
 |  |  380   |     ar_b(it_endostates_rows_n*it_exostates_cols_n+1) = 1;
   | 
 |  |  381   | 
 
  | 
 |  |  382   |     % d. solve
   | 
 |  |  383   |     % b = P*Q
   | 
 |  |  384   |     % b*Q^{T} = P*Q*Q^{T}
  | 
 |  |  385   |     % P*Q*Q^{T} = b*Q^{T}
  | 
 |  |  386   |     % P = (b*Q^{T})[(Q*Q^{T})^{-1}]
  | 
 |  |  387   |     % Q_t = np.transpose(Q)
   | 
 |  |  388   |     % b_QT = np.dot(b, Q_t)
   | 
 |  |  389   |     % Q_QT = np.dot(Q, Q_t)
   | 
 |  |  390   | 
 
  | 
 |  |  391   |     % inv_mt_Q_QT = inv(mt_Q*mt_Q');
   | 
 |  |  392   |     ar_stationary = (ar_b*mt_Q')/(mt_Q*mt_Q');
   | 
 |  |  393   | 
 
  | 
 |  |  394   | end
   | 
 |  |  395   | 
 
  | 
 |  |  396   | %% 6. Stationary Distribution *Method C*, Power
   | 
 |  |  397   | % Takes markov chain to Nth power. This is the slowest.
   | 
 |  |  398   | 
 
  | 
< 0.001   |       1   |  399  | if (strcmp(st_analytical_stationary_type, 'power')) 
   | 
 |  |  400   |     
   | 
 |  |  401   |     mt_stationary_full = (mt_full_trans_mat)^it_trans_power_dist;
   | 
 |  |  402   |     ar_stationary = mt_stationary_full(:,1);
   | 
 |  |  403   | end
   | 
 |  |  404   | 
 
  | 
 |  |  405   | %% 7. Stationary Vector to Stationary Matrix in Original Dimensions
   | 
 |  |  406   | 
 
  | 
< 0.001   |       1   |  407  | mt_dist_az = reshape(ar_stationary, size(mt_pol_idx)); 
   | 
 |  |  408   | 
 
  | 
 |  |  409   | %% End Time and Profiler
   | 
 |  |  410   | 
 
  | 
 |  |  411   | % End Timer
   | 
< 0.001   |       1   |  412  | if (bl_time) 
   | 
< 0.001   |       1   |  413  |     toc; 
   | 
< 0.001   |       1   |  414  | end 
   | 
 |  |  415   |  
   | 
 |  |  416   | % End Profile
   | 
< 0.001   |       1   |  417  | if (bl_profile_dist) 
   | 
 |  |  418   |     profile off
   | 
 |  |  419   |     profile viewer
   | 
 |  |  420   |     st_file_name = [st_profile_prefix st_profile_name_main st_profile_suffix];
   | 
 |  |  421   |     profsave(profile('info'), strcat(st_profile_path, st_file_name));
  | 
 |  |  422   | end
   | 
 |  |  423   | 
 
  | 
 |  |  424   | %% *f(y), f(c), f(a)*: Generate Key Distributional Statistics for Each outcome
   | 
 |  |  425   | % Having derived f(a,z) the probability mass function of the joint discrete
   | 
 |  |  426   | % random variables, we now obtain distributional statistics. Note that we
   | 
 |  |  427   | % know f(a,z), and we also know relevant policy functions a'(a,z), c(a,z),
   | 
 |  |  428   | % or other policy functions. We can simulate any choices that are a
   | 
 |  |  429   | % function of the random variables (a,z), using f(a,z). We call function
   | 
 |  |  430   | % <https://fanwangecon.github.io/CodeDynaAsset/m_az/solvepost/html/ff_az_ds_post_stats.html
   | 
 |  |  431   | % ff_az_ds_post_stats> which uses
   | 
 |  |  432   | % <https://fanwangecon.github.io/CodeDynaAsset/tools/html/fft_disc_rand_var_stats.html
   | 
 |  |  433   | % fft_disc_rand_var_stats> and
   | 
 |  |  434   | % <https://fanwangecon.github.io/CodeDynaAsset/tools/html/fft_disc_rand_var_mass2outcomes.html
   | 
 |  |  435   | % fft_disc_rand_var_mass2outcomes> to compute various statistics of
   | 
 |  |  436   | % interest.
   | 
 |  |  437   | 
 
  | 
< 0.001   |       1   |  438  | bl_input_override = true; 
   | 
  0.344   |       1   |  439  | result_map = ff_az_ds_post_stats(support_map, result_map, mt_dist_az, bl_input_override); 
   | 
 |  |  440   | 
 
  | 
  0.001   |       1   |  441  | end 
   | 
Other subfunctions in this file are not included in this listing.