This is a static copy of a profile report

Home

Function details for ff_abzr_fibs_vf_vecsvThis is a static copy of a profile report

Home

ff_abzr_fibs_vf_vecsv (Calls: 1, Time: 11.220 s)
Generated 14-Jul-2019 00:14:42 using performance time.
function in file C:\Users\fan\CodeDynaAsset\m_fibs\m_abzr_solve\ff_abzr_fibs_vf_vecsv.m
Copy to new window for comparing multiple runs

Parents (calling functions)
No parent
Lines where the most time was spent

Line NumberCodeCallsTotal Time% TimeTime Plot
438
[ar_opti_val_z, ar_opti_idx_z]...
91503.397 s30.3%
428
mt_utility = mt_utility.*(~mt_...
91502.030 s18.1%
418
mt_utility = cl_u_c_store{it_z...
91501.514 s13.5%
383
mt_utility = f_util_crra(mt_c)...
750.917 s8.2%
336
bl_display_minccost, bl_input_...
750.416 s3.7%
All other lines  2.946 s26.3%
Totals  11.220 s100% 
Children (called functions)

Function NameFunction TypeCallsTotal Time% TimeTime Plot
...c)(((c).^(1-fl_crra)-1)./(1-fl_crra))anonymous function1500.875 s7.8%
ffs_fibs_min_c_costfunction750.405 s3.6%
linspacefunction91500.139 s1.2%
ffs_fibs_inf_bridgefunction750.082 s0.7%
..._save)(coh-ar_for_save./(1+fl_r_fsv))anonymous function750.081 s0.7%
...tions>@(ar_z,ar_b)(ar_z*fl_w+ar_b)anonymous function91500.048 s0.4%
...h,ar_bprime_in_c)(coh+ar_bprime_in_c)anonymous function750.027 s0.2%
Self time (built-ins, overhead, etc.)  9.563 s85.2%
Totals  11.220 s100% 
Code Analyzer results
Line numberMessage
292The value assigned to variable 'ar_coh_neg' might be unused.
354Use of brackets [] is unnecessary. Use parentheses to group, if needed.
Coverage results
Show coverage for parent directory
Total lines in function618
Non-code lines (comments, blank lines)376
Code lines (lines that can run)242
Code lines that did run106
Code lines that did not run136
Coverage (did run/can run)43.80 %
Function listing
time 
Calls 
 line
   7 
function result_map = ff_abzr_fibs_vf_vecsv(varargin)
   8 
%% FF_ABZ_FIBS_VF_VECSV solve infinite horizon exo shock + endo asset problem
   9 
% This program solves the infinite horizon dynamic single asset and single
  10 
% shock problem with vectorized codes.
  11 
% <https://fanwangecon.github.io/CodeDynaAsset/m_abzr/solve/html/ff_abzr_fibs_vf.html
  12 
% ff_abzr_fibs_vf> shows looped codes. The solution is the same.
  13 
%
  14 
% The model could be invoked mainly in sveral ways:
  15 
%
  16 
% # param_map('bl_default') = true;  param_map('bl_bridge') = false;
  17 
% param_map('bl_rollover') = true; Given these, default is possible, bridge
  18 
% loans are not needed because rollover is allowed for formal loans (or
  19 
% informal loans)
  20 
% # we change param_map('bl_bridge') = true, that means
  21 
% rollover is still allowed, but only allowed using informal sources,
  22 
% formal loans no longer allow for roll-over. Furthermore, if both
  23 
% bl_bridge and bl_rollover are false, that means we are not allowing for
  24 
% rollover at all, so households can not borrow such that they end up with
  25 
% negative cash-on-hand.
  26 
%
  27 
% Default simulation bl_bridge = false.
  28 
%
  29 
% @param param_map container parameter container
  30 
%
  31 
% @param support_map container support container
  32 
%
  33 
% @param armt_map container container with states, choices and shocks
  34 
% grids that are inputs for grid based solution algorithm
  35 
%
  36 
% @param func_map container container with function handles for
  37 
% consumption cash-on-hand etc.
  38 
%
  39 
% @return result_map container contains policy function matrix, value
  40 
% function matrix, iteration results, and policy function, value function
  41 
% and iteration results tables.
  42 
%
  43 
% @example
  44 
%
  45 
%    % Get Default Parameters
  46 
%    it_param_set = 4;
  47 
%    [param_map, support_map] = ffs_abzr_fibs_set_default_param(it_param_set);
  48 
%    % Chnage param_map keys for borrowing
  49 
%    param_map('fl_b_bd') = -20; % borrow bound
  50 
%    param_map('bl_default') = false; % true if allow for default
  51 
%    param_map('fl_c_min') = 0.0001; % u(c_min) when default
  52 
%    % Change Keys in param_map
  53 
%    param_map('it_a_n') = 500;
  54 
%    param_map('fl_z_r_infbr_n') = 5;
  55 
%    param_map('it_z_wage_n') = 15;
  56 
%    param_map('it_z_n') = param_map('it_z_wage_n') * param_map('fl_z_r_infbr_n');
  57 
%    param_map('fl_a_max') = 100;
  58 
%    param_map('fl_w') = 1.3;
  59 
%    param_map('fl_r_fsv') = 0.01;
  60 
%    param_map('fl_r_fbr') = 0.035;
  61 
%    param_map('bl_b_is_principle') = false;
  62 
%    % see: ffs_for_br_block.m
  63 
%    param_map('st_forbrblk_type') = 'seg3';
  64 
%    param_map('fl_forbrblk_brmost') = -10;
  65 
%    param_map('fl_forbrblk_brleast') = -1;
  66 
%    param_map('fl_forbrblk_gap') = -1;
  67 
%    % Change Keys support_map
  68 
%    support_map('bl_display') = false;
  69 
%    support_map('bl_post') = true;
  70 
%    support_map('bl_display_final') = false;
  71 
%    % Call Program with external parameters that override defaults.
  72 
%    ff_abzr_fibs_vf_vecsv(param_map, support_map);
  73 
%
  74 
%
  75 
% @include
  76 
%
  77 
% * <https://fanwangecon.github.io/CodeDynaAsset/m_fibs/paramfunc/html/ffs_abzr_fibs_set_default_param.html ffs_abzr_fibs_set_default_param>
  78 
% * <https://fanwangecon.github.io/CodeDynaAsset/m_fibs/paramfunc/html/ffs_abzr_fibs_get_funcgrid.html ffs_abzr_fibs_get_funcgrid>
  79 
% * <https://fanwangecon.github.io/CodeDynaAsset/m_fibs/paramfunc_fibs/html/ffs_fibs_min_c_cost_bridge.html ffs_fibs_min_c_cost_bridge>
  80 
% * <https://fanwangecon.github.io/CodeDynaAsset/m_fibs/paramfunc_fibs/html/ffs_fibs_inf_bridge.html ffs_fibs_inf_bridge>
  81 
% * <https://fanwangecon.github.io/CodeDynaAsset/m_fibs/paramfunc_fibs/html/ffs_fibs_min_c_cost.html ffs_fibs_min_c_cost>
  82 
% * <https://fanwangecon.github.io/CodeDynaAsset/m_az/solvepost/html/ff_az_vf_post.html ff_az_vf_post>
  83 
%
  84 
% @seealso
  85 
%
  86 
% * for/inf + save + borr loop: <https://fanwangecon.github.io/CodeDynaAsset/m_fibs/m_abzr_solve/html/ff_abzr_fibs_vf.html ff_abzr_fibs_vf>
  87 
% * for/inf + borr vectorized: <https://fanwangecon.github.io/CodeDynaAsset/m_fibs/m_abzr_solve/html/ff_abzr_fibs_vf_vec.html ff_abzr_fibs_vf_vec>
  88 
% * for/inf + borr optimized-vectorized: <https://fanwangecon.github.io/CodeDynaAsset/m_fibs/m_abzr_solve/html/ff_abzr_fibs_vf_vecsv.html ff_abzr_fibs_vf_vecsv>
  89 
%
  90 

  91 
%% Default
  92 
%
  93 
% * it_param_set = 1: quick test
  94 
% * it_param_set = 2: benchmark run
  95 
% * it_param_set = 3: benchmark profile
  96 
% * it_param_set = 4: press publish button
  97 
%
  98 
% go to
  99 
% <https://fanwangecon.github.io/CodeDynaAsset/m_fibs/paramfunc/html/ffs_abzr_fibs_fibs_set_default_param.html
 100 
% ffs_abzr_fibs_fibs_set_default_param> to change parameters in param_map container.
 101 
% The parameters can also be updated here directly after obtaining them
 102 
% from ffs_abzr_fibs_set_default_param as we possibly change it_a_n and it_z_n
 103 
% here.
 104 
%
 105 

 106 
it_param_set = 3;
 107 
bl_input_override = true;
 108 
[param_map, support_map] = ffs_abzr_fibs_set_default_param(it_param_set);
 109 

 110 
% Note: param_map and support_map can be adjusted here or outside to override defaults
 111 
% To generate results as if formal informal do not matter
 112 
% param_map('fl_r_fsv') = 0.025;
 113 
% param_map('fl_r_fbr') = 0.035;
 114 
% param_map('bl_b_is_principle') = false;
 115 
% param_map('st_forbrblk_type') = 'seg3';
 116 
% param_map('fl_forbrblk_brmost') = -19;
 117 
% param_map('fl_forbrblk_brleast') = -1;
 118 
% param_map('fl_forbrblk_gap') = -1.5;
 119 
% param_map('bl_b_is_principle') = false;
 120 
% param_map('it_a_n') = 750;
 121 
% param_map('fl_z_r_infbr_n') = 5;
 122 
% param_map('it_z_wage_n') = 15;
 123 
% param_map('it_z_n') = param_map('it_z_wage_n') * param_map('fl_z_r_infbr_n');
 124 

 125 
[armt_map, func_map] = ffs_abzr_fibs_get_funcgrid(param_map, support_map, bl_input_override); % 1 for override
 126 
default_params = {param_map support_map armt_map func_map};
 127 

 128 
%% Parse Parameters 1
 129 

 130 
% if varargin only has param_map and support_map,
 131 
params_len = length(varargin);
 132 
[default_params{1:params_len}] = varargin{:};
 133 
param_map = [param_map; default_params{1}];
 134 
support_map = [support_map; default_params{2}];
 135 
if params_len >= 1 && params_len <= 2
 136 
    % If override param_map, re-generate armt and func if they are not
 137 
    % provided
 138 
    bl_input_override = true;
 139 
    [armt_map, func_map] = ffs_abzr_fibs_get_funcgrid(param_map, support_map, bl_input_override);
 140 
else
 141 
    % Override all
 142 
    armt_map = [armt_map; default_params{3}];
 143 
    func_map = [func_map; default_params{4}];
 144 
end
 145 

 146 
% append function name
 147 
st_func_name = 'ff_abzr_fibs_vf_vecsv';
 148 
support_map('st_profile_name_main') = [st_func_name support_map('st_profile_name_main')];
 149 
support_map('st_mat_name_main') = [st_func_name support_map('st_mat_name_main')];
 150 
support_map('st_img_name_main') = [st_func_name support_map('st_img_name_main')];
 151 

 152 
%% Parse Parameters 2
 153 

 154 
% armt_map
 155 
params_group = values(armt_map, {'ar_a', 'mt_z_trans', 'ar_z_r_infbr_mesh_wage', 'ar_z_wage_mesh_r_infbr'});
 156 
[ar_a, mt_z_trans, ar_z_r_infbr_mesh_wage, ar_z_wage_mesh_r_infbr] = params_group{:};
 157 

 158 
% Formal choice Menu/Grid and Interest Rate Menu/Grid
 159 
params_group = values(armt_map, {'ar_forbrblk_r', 'ar_forbrblk'});
 160 
[ar_forbrblk_r, ar_forbrblk] = params_group{:};
 161 

 162 
% func_map
 163 
params_group = values(func_map, {'f_util_log', 'f_util_crra', 'f_coh', 'f_cons_coh_fbis', 'f_cons_coh_save'});
 164 
[f_util_log, f_util_crra, f_coh, f_cons_coh_fbis, f_cons_coh_save] = params_group{:};
 165 

 166 
% param_map
 167 
params_group = values(param_map, {'it_a_n', 'it_z_n', 'fl_crra', 'fl_beta', 'fl_c_min',...
 168 
    'fl_nan_replace', 'bl_default', 'bl_bridge', 'bl_rollover', 'fl_default_aprime'});
 169 
[it_a_n, it_z_n, fl_crra, fl_beta, fl_c_min, ...
 170 
    fl_nan_replace, bl_default, bl_bridge, bl_rollover, fl_default_aprime] = params_group{:};
 171 
params_group = values(param_map, {'it_maxiter_val', 'fl_tol_val', 'fl_tol_pol', 'it_tol_pol_nochange'});
 172 
[it_maxiter_val, fl_tol_val, fl_tol_pol, it_tol_pol_nochange] = params_group{:};
 173 

 174 
% param_map, Formal informal
 175 
params_group = values(param_map, {'fl_r_fsv', 'bl_b_is_principle'});
 176 
[fl_r_fsv, bl_b_is_principle] = params_group{:};
 177 

 178 
% support_map
 179 
params_group = values(support_map, {'bl_profile', 'st_profile_path', ...
 180 
    'st_profile_prefix', 'st_profile_name_main', 'st_profile_suffix',...
 181 
    'bl_display_minccost', 'bl_display_infbridge', ...
 182 
    'bl_time', 'bl_display_defparam', 'bl_display', 'it_display_every', 'bl_post'});
 183 
[bl_profile, st_profile_path, ...
 184 
    st_profile_prefix, st_profile_name_main, st_profile_suffix, ...
 185 
    bl_display_minccost, bl_display_infbridge, ...
 186 
    bl_time, bl_display_defparam, bl_display, it_display_every, bl_post] = params_group{:};
 187 

 188 
%% Display Parameters
 189 

 190 
if (bl_display_defparam)
 191 
    fft_container_map_display(param_map);
 192 
    fft_container_map_display(support_map);
 193 
end
 194 

 195 
%% Initialize Output Matrixes
 196 
% include mt_pol_idx which we did not have in looped code
 197 

 198 
mt_val_cur = zeros(it_a_n,it_z_n);
 199 
mt_val = mt_val_cur - 1;
 200 
mt_pol_a = zeros(it_a_n,it_z_n);
 201 
mt_pol_a_cur = mt_pol_a - 1;
 202 
mt_pol_idx = zeros(it_a_n,it_z_n);
 203 
mt_pol_cons = zeros(it_a_n,it_z_n);
 204 

 205 
% collect optimal borrowing formal and informal choices
 206 
mt_pol_b_bridge = zeros(it_a_n,it_z_n);
 207 
mt_pol_inf_borr_nobridge = zeros(it_a_n,it_z_n);
 208 
mt_pol_for_borr = zeros(it_a_n,it_z_n);
 209 
mt_pol_for_save = zeros(it_a_n,it_z_n);
 210 

 211 
% We did not need these in ff_abzr_vf or ff_abzr_vf_vec
 212 
% see
 213 
% <https://fanwangecon.github.io/M4Econ/support/speed/partupdate/fs_u_c_partrepeat_main.html
 214 
% fs_u_c_partrepeat_main> for why store using cells.
 215 
cl_u_c_store = cell([it_z_n, 1]);
 216 
cl_c_store = cell([it_z_n, 1]);
 217 
cl_c_valid_idx = cell([it_z_n, 1]);
 218 

 219 
%% Initialize Convergence Conditions
 220 

 221 
bl_vfi_continue = true;
 222 
it_iter = 0;
 223 
ar_val_diff_norm = zeros([it_maxiter_val, 1]);
 224 
ar_pol_diff_norm = zeros([it_maxiter_val, 1]);
 225 
mt_pol_perc_change = zeros([it_maxiter_val, it_z_n]);
 226 

 227 
%% Iterate Value Function
 228 
% Loop solution with 4 nested loops
 229 
%
 230 
% # loop 1: over exogenous states
 231 
% # loop 2: over endogenous states
 232 
% # loop 3: over choices
 233 
% # loop 4: add future utility, integration--loop over future shocks
 234 
%
 235 

 236 
% Start Profile
 237 
if (bl_profile)
 238 
    close all;
 239 
    profile off;
 240 
    profile on;
< 0.001 
      1 
 241
end 
 242 

 243 
% Start Timer
< 0.001 
      1 
 244
if (bl_time) 
< 0.001 
      1 
 245
    tic; 
< 0.001 
      1 
 246
end 
 247 

 248 
% Value Function Iteration
< 0.001 
      1 
 249
while bl_vfi_continue 
< 0.001 
    122 
 250
    it_iter = it_iter + 1; 
 251 

 252 
    %% Solve Optimization Problem Current Iteration
 253 

 254 
    % loop 1: over exogenous states
< 0.001 
    122 
 255
    for it_z_i = 1:it_z_n 
 256 

 257 
        %% Solve the Formal Informal Problem for each a' and coh: c_forinf(a')
 258 
        % find the today's consumption maximizing formal and informal
 259 
        % choices given a' and coh. The formal and informal choices need to
 260 
        % generate exactly a', but depending on which formal and informal
 261 
        % joint choice is used, the consumption cost today a' is different.
 262 
        % Note here, a is principle + interests. Three areas:
 263 
        %
 264 
        % * *CASE A* a' > 0: savings, do not need to optimize over formal and
 265 
        % informal choices
 266 
        % * *CASE B* a' < 0 & coh < 0: need bridge loan to pay for unpaid debt, and
 267 
        % borrowing over-all, need to first pick bridge loan to pay for
 268 
        % debt, if bridge loan is insufficient, go into default. After
 269 
        % bridge loan, optimize over formal+informal, borrow+save joint
 270 
        % choices.
 271 
        % * *CASE C* a' < 0 & coh > 0: do not need to get informal bridge loans,
 272 
        % optimize over for+inf save, for+save+borr, inf+borr only, for
 273 
        % borrow only.
 274 
        %
 275 

 276 
        % 1. Current Shock
  0.002 
   9150 
 277
        fl_z_r_infbr = ar_z_r_infbr_mesh_wage(it_z_i); 
  0.002 
   9150 
 278
        fl_z_wage = ar_z_wage_mesh_r_infbr(it_z_i); 
 279 

 280 
        % 2. cash-on-hand
  0.097 
   9150 
 281
        ar_coh = f_coh(fl_z_wage, ar_a); 
 282 

 283 
        % Consumption and u(c) only need to be evaluated once
  0.003 
   9150 
 284
        if (it_iter == 1) 
 285 

 286 
            % 3. *CASE A* initiate consumption matrix as if all save
  0.083 
     75 
 287
            mt_c = f_cons_coh_save(ar_coh, ar_a'); 
 288 

 289 
            % 4. *CASE B+C* get negative coh index and get borrowing choices index
< 0.001 
     75 
 290
            ar_coh_neg_idx = (ar_coh <= 0); 
< 0.001 
     75 
 291
            ar_a_neg_idx = (ar_a < 0); 
< 0.001 
     75 
 292
            ar_coh_neg = ar_coh(ar_coh_neg_idx); 
< 0.001 
     75 
 293
            ar_a_neg = ar_a(ar_a_neg_idx); 
 294 

 295 
            % 5. if coh > 0 and ap < 0, can allow same for+inf result to all coh.
 296 
            % The procedure below works regardless of how ar_coh is sorted. get
 297 
            % the index of all negative coh elements as well as first
 298 
            % non-negative element. We solve the formal and informal problem at
 299 
            % these points, note that we only need to solve the formal and
 300 
            % informal problem for positive coh level once.
  0.002 
     75 
 301
            ar_coh_first_pos_idx = (cumsum(ar_coh_neg_idx == 0) == 1); 
< 0.001 
     75 
 302
            ar_coh_forinfsolve_idx = (ar_coh_first_pos_idx | ar_coh_neg_idx); 
< 0.001 
     75 
 303
            ar_coh_forinfsolve_a_neg_idx = (ar_coh(ar_coh_forinfsolve_idx) <= 0); 
 304 

 305 
            % 6. *CASE B + C* Negative asset choices (borrowing), 1 col Case C
 306 
            % negp1: negative coh + 1, 1 meaning 1 positive coh, first positive
 307 
            % coh column index element grabbed.
  0.025 
     75 
 308
            mt_coh_negp1_mesh_neg_aprime = zeros(size(ar_a_neg')) + ar_coh(ar_coh_forinfsolve_idx); 
  0.014 
     75 
 309
            mt_neg_aprime_mesh_coh_negp1 = zeros(size(mt_coh_negp1_mesh_neg_aprime)) + ar_a_neg'; 
 310 

< 0.001 
     75 
 311
            if (bl_bridge) 
 312 
                %         mt_neg_aprime_mesh_coh_1col4poscoh = zeros([length(ar_a_neg), (length(ar_coh_neg)+1)]) + ar_a_neg';
 313 
                %         ar_coh_neg_idx_1col4poscoh = ar_coh_neg_idx(1:(length(ar_coh_neg)+1));
 314 

 315 
                % 6. *CASE B* Solve for: if (fl_ap < 0) and if (fl_coh < 0)
  0.121 
     75 
 316
                [mt_aprime_nobridge_negcoh, ~, mt_c_bridge_negcoh] = ffs_fibs_inf_bridge(... 
     75 
 317
                    bl_b_is_principle, fl_z_r_infbr, ... 
     75 
 318
                    mt_neg_aprime_mesh_coh_negp1(:,ar_coh_forinfsolve_a_neg_idx), ... 
     75 
 319
                    mt_coh_negp1_mesh_neg_aprime(:,ar_coh_forinfsolve_a_neg_idx), ... 
     75 
 320
                    bl_display_infbridge, bl_input_override); 
 321 

 322 
                % generate mt_aprime_nobridge
  0.003 
     75 
 323
                mt_neg_aprime_mesh_coh_negp1(:, ar_coh_forinfsolve_a_neg_idx) = mt_aprime_nobridge_negcoh; 
 324 
            else
 325 
                % no bridge loan needed means roll over is allowed.
 326 
                mt_neg_aprime_mesh_coh_negp1 = ar_a_neg';
< 0.001 
     75 
 327
            end 
 328 

 329 
            % 7. *CASE B + C* formal and informal joint choices, 1 col Case C
< 0.001 
     75 
 330
            bl_input_override = true; 
  0.417 
     75 
 331
            [ar_max_c_nobridge, ~, ~, ~] = ... 
 332 
                ffs_fibs_min_c_cost(...
     75 
 333
                bl_b_is_principle, fl_z_r_infbr, fl_r_fsv, ... 
     75 
 334
                ar_forbrblk_r, ar_forbrblk, ... 
     75 
 335
                mt_neg_aprime_mesh_coh_negp1(:), ... 
     75 
 336
                bl_display_minccost, bl_input_override); 
 337 

 338 
            %% Update Consumption Matrix *CASE A + B + C* Consumptions
 339 
            % Current mt_c is assuming all to be case A
 340 
            %
 341 
            % * Update Columns for case B (negative coh)
 342 
            % * Update Columns for case C (1 column): ar_coh_first_pos_idx,
 343 
            % included in ar_coh_forinfsolve_idx
 344 
            % * Update Columns for all case C: ~ar_coh_neg_idx using 1 column
 345 
            % result
 346 
            %
 347 

 348 
            % 1. Initalize all Neg Aprime consumption cost of aprime inputs
 349 
            % Initialize
  0.048 
     75 
 350
            mt_max_c_nobridge_a_neg = zeros([length(ar_a_neg), length(ar_coh)]) + 0; 
  0.039 
     75 
 351
            mt_c_bridge_coh_a_neg = zeros(size(mt_max_c_nobridge_a_neg)) + 0; 
 352 

 353 
            % 2. Fill in *Case B* and *Case C* (one column) Other C-cost
  0.006 
     75 
 354
            mt_max_c_nobridge_negcohp1 = reshape(ar_max_c_nobridge, [size(mt_neg_aprime_mesh_coh_negp1)]); 
 355 

< 0.001 
     75 
 356
            if (bl_bridge) 
 357 
                % 2. Fill in *Case B* Bridge C-cost
  0.004 
     75 
 358
                mt_c_bridge_coh_a_neg(:, ar_coh_neg_idx) = mt_c_bridge_negcoh; 
 359 

 360 
                % 2. Fill in *Case B* and *Case C* (one column) Other C-cost
  0.004 
     75 
 361
                mt_max_c_nobridge_a_neg(:, ar_coh_forinfsolve_idx) = mt_max_c_nobridge_negcohp1; 
  0.081 
     75 
 362
                mt_max_c_nobridge_a_neg(:, ~ar_coh_forinfsolve_idx) = ... 
     75 
 363
                    zeros(size(mt_c(ar_a_neg_idx, ~ar_coh_forinfsolve_idx))) ... 
     75 
 364
                    + mt_max_c_nobridge_negcohp1(:, ~ar_coh_forinfsolve_a_neg_idx); 
 365 
            else
 366 
                mt_max_c_nobridge_a_neg = zeros([length(ar_a_neg), length(ar_coh)]) + mt_max_c_nobridge_negcohp1;
< 0.001 
     75 
 367
            end 
 368 

 369 
            % 3. Consumption for B + C Cases
 370 
            % note, the c cost of aprime is the same for all coh > 0, but mt_c
 371 
            % is different still for each coh and aprime.
  0.081 
     75 
 372
            mt_c_forinfsolve = f_cons_coh_fbis(ar_coh, mt_c_bridge_coh_a_neg + mt_max_c_nobridge_a_neg); 
 373 

 374 
            % 4. Update with Case B and C
  0.015 
     75 
 375
            mt_c(ar_a_neg_idx, :) = mt_c_forinfsolve; 
 376 

 377 
            %% Evaluate u(c) and store
 378 
            % 1. EVAL current utility: N by N, f_util defined earlier
< 0.001 
     75 
 379
            if (fl_crra == 1) 
 380 
                mt_utility = log(mt_c);
 381 
                fl_u_cmin = f_util_log(fl_c_min);
< 0.001 
     75 
 382
            else 
  0.917 
     75 
 383
                mt_utility = f_util_crra(mt_c); 
  0.002 
     75 
 384
                fl_u_cmin = f_util_crra(fl_c_min); 
< 0.001 
     75 
 385
            end 
 386 

 387 
            % 2. Invliad consumption points
  0.027 
     75 
 388
            mt_it_c_valid_idx = (mt_c <= fl_c_min); 
 389 
            % Set below threshold c to c_min
  0.190 
     75 
 390
            mt_c(mt_c < fl_c_min) = fl_c_min; 
 391 

 392 
            % 3. Invalid points if bridge not possible also no rollover
< 0.001 
     75 
 393
            if( ~bl_rollover && ~bl_bridge) 
 394 
                mt_it_c_valid_idx(:, ar_coh_neg_idx) = 1;
 395 
            end
 396 

 397 
            % 4. Eliminate Complex Numbers
  0.335 
     75 
 398
            mt_utility(mt_it_c_valid_idx) = fl_u_cmin; 
 399 

 400 
            % 5. Store in cells
< 0.001 
     75 
 401
            cl_c_store{it_z_i} = mt_c; 
< 0.001 
     75 
 402
            cl_u_c_store{it_z_i} = mt_utility; 
< 0.001 
     75 
 403
            cl_c_valid_idx{it_z_i} = mt_it_c_valid_idx; 
 404 

< 0.001 
     75 
 405
        end 
 406 

 407 
        %% Solve Optimization Problem: max_{a'} (u(c_forinf(a')) + EV(a',z'))
 408 

 409 
        % 1. f(z'|z)
  0.014 
   9150 
 410
        ar_z_trans_condi = mt_z_trans(it_z_i,:); 
 411 

 412 
        % 2. EVAL EV((A',K'),Z'|Z) = V((A',K'),Z') x p(z'|z)', (N by Z) x (Z by 1) = N by 1
 413 
        % Note: transpose ar_z_trans_condi from 1 by Z to Z by 1
 414 
        % Note: matrix multiply not dot multiply
  0.220 
   9150 
 415
        mt_evzp_condi_z = mt_val_cur * ar_z_trans_condi'; 
 416 

 417 
        % 3. EVAL add on future utility, N by N + N by 1, broadcast again
  1.514 
   9150 
 418
        mt_utility = cl_u_c_store{it_z_i} + fl_beta*mt_evzp_condi_z; 
 419 

 420 
        % 4. Index update
 421 
        % using the method below is much faster than index replace
 422 
        % see <https://fanwangecon.github.io/M4Econ/support/speed/index/fs_subscript.html fs_subscript>
  0.012 
   9150 
 423
        mt_it_c_valid_idx = cl_c_valid_idx{it_z_i}; 
 424 
        % Default or Not Utility Handling
  0.002 
   9150 
 425
        if (bl_default) 
 426 
            % if default: only today u(cmin), transition out next period, debt wiped out
  0.085 
   9150 
 427
            fl_v_default = fl_u_cmin + fl_beta*mt_evzp_condi_z(ar_a == fl_default_aprime); 
  2.030 
   9150 
 428
            mt_utility = mt_utility.*(~mt_it_c_valid_idx) + fl_v_default*(mt_it_c_valid_idx); 
 429 
        else
 430 
            % if default is not allowed: v = u(cmin)
 431 
            mt_utility = mt_utility.*(~mt_it_c_valid_idx) + fl_nan_replace*(mt_it_c_valid_idx);
  0.002 
   9150 
 432
        end 
 433 

 434 
        % Optimization: remember matlab is column major, rows must be
 435 
        % choices, columns must be states
 436 
        % <https://en.wikipedia.org/wiki/Row-_and_column-major_order COLUMN-MAJOR>
 437 
        % mt_utility is N by N, rows are choices, cols are states.
  3.397 
   9150 
 438
        [ar_opti_val_z, ar_opti_idx_z] = max(mt_utility); 
  0.064 
   9150 
 439
        [it_choies_n, it_states_n] = size(mt_utility); 
  0.192 
   9150 
 440
        ar_add_grid = linspace(0, it_choies_n*(it_states_n-1), it_states_n); 
  0.017 
   9150 
 441
        ar_opti_linear_idx_z = ar_opti_idx_z + ar_add_grid; 
  0.094 
   9150 
 442
        ar_opti_aprime_z = ar_a(ar_opti_idx_z); 
  0.244 
   9150 
 443
        ar_opti_c_z = cl_c_store{it_z_i}(ar_opti_linear_idx_z); 
 444 

 445 
        % Handle Default is optimal or not
  0.002 
   9150 
 446
        if (bl_default) 
 447 
            % if defaulting is optimal choice, at these states, not required
 448 
            % to default, non-default possible, but default could be optimal
  0.060 
   9150 
 449
            ar_opti_aprime_z(ar_opti_c_z <= fl_c_min) = fl_default_aprime; 
  0.093 
   9150 
 450
            ar_opti_idx_z(ar_opti_c_z <= fl_c_min) = find(ar_a == fl_default_aprime); 
 451 
        else
 452 
            % if default is not allowed, then next period same state as now
 453 
            % this is absorbing state, this is the limiting case, single
 454 
            % state space point, lowest a and lowest shock has this.
 455 
            ar_opti_aprime_z(ar_opti_c_z <= fl_c_min) = min(ar_a);
  0.001 
   9150 
 456
        end 
 457 

 458 
        % 6. no bridge and no rollover allowed
  0.002 
   9150 
 459
        if( ~bl_rollover && ~bl_bridge) 
 460 
            if (bl_default)
 461 
                % if default: only today u(cmin), transition out next period, debt wiped out
 462 
                ar_opti_aprime_z(ar_coh_neg_idx) = fl_default_aprime;
 463 
            else
 464 
                % if default is not allowed: v = fl_nan_replace
 465 
                ar_opti_aprime_z(ar_coh_neg_idx) = ar_a(fl_nan_replace);
 466 
            end
 467 
        end
 468 

 469 
        % store optimal values
  0.061 
   9150 
 470
        mt_val(:,it_z_i) = ar_opti_val_z; 
  0.043 
   9150 
 471
        mt_pol_a(:,it_z_i) = ar_opti_aprime_z; 
  0.026 
   9150 
 472
        mt_pol_cons(:,it_z_i) = ar_opti_c_z; 
 473 

  0.003 
   9150 
 474
        if (it_iter == (it_maxiter_val + 1)) 
< 0.001 
     75 
 475
            mt_pol_idx(:,it_z_i) = ar_opti_idx_z; 
< 0.001 
     75 
 476
        end 
  0.004 
   9150 
 477
    end 
 478 

 479 
    %% Check Tolerance and Continuation
 480 

 481 
    % Difference across iterations
  0.298 
    122 
 482
    ar_val_diff_norm(it_iter) = norm(mt_val - mt_val_cur); 
  0.169 
    122 
 483
    ar_pol_diff_norm(it_iter) = norm(mt_pol_a - mt_pol_a_cur); 
  0.021 
    122 
 484
    mt_pol_perc_change(it_iter, :) = sum((mt_pol_a ~= mt_pol_a_cur))/(it_a_n); 
 485 

 486 
    % Update
  0.008 
    122 
 487
    mt_val_cur = mt_val; 
  0.008 
    122 
 488
    mt_pol_a_cur = mt_pol_a; 
 489 

 490 
    % Print Iteration Results
< 0.001 
    122 
 491
    if (bl_display && (rem(it_iter, it_display_every)==0)) 
 492 
        fprintf('VAL it_iter:%d, fl_diff:%d, fl_diff_pol:%d\n', ...
 493 
            it_iter, ar_val_diff_norm(it_iter), ar_pol_diff_norm(it_iter));
 494 
        tb_valpol_iter = array2table([mean(mt_val_cur,1); mean(mt_pol_a_cur,1); ...
 495 
            mt_val_cur(it_a_n,:); mt_pol_a_cur(it_a_n,:)]);
 496 
        tb_valpol_iter.Properties.VariableNames = strcat('z', string((1:size(mt_val_cur,2))));
 497 
        tb_valpol_iter.Properties.RowNames = {'mval', 'map', 'Hval', 'Hap'};
 498 
        disp('mval = mean(mt_val_cur,1), average value over a')
 499 
        disp('map  = mean(mt_pol_a_cur,1), average choice over a')
 500 
        disp('Hval = mt_val_cur(it_a_n,:), highest a state val')
 501 
        disp('Hap = mt_pol_a_cur(it_a_n,:), highest a state choice')
 502 
        disp(tb_valpol_iter);
 503 
    end
 504 

 505 
    % Continuation Conditions:
 506 
    % 1. if value function convergence criteria reached
 507 
    % 2. if policy function variation over iterations is less than
 508 
    % threshold
< 0.001 
    122 
 509
    if (it_iter == (it_maxiter_val + 1)) 
< 0.001 
      1 
 510
        bl_vfi_continue = false; 
  0.002 
    121 
 511
    elseif ((it_iter == it_maxiter_val) || ... 
    121 
 512
            (ar_val_diff_norm(it_iter) < fl_tol_val) || ... 
    121 
 513
            (sum(ar_pol_diff_norm(max(1, it_iter-it_tol_pol_nochange):it_iter)) < fl_tol_pol)) 
 514 
        % Fix to max, run again to save results if needed
< 0.001 
      1 
 515
        it_iter_last = it_iter; 
< 0.001 
      1 
 516
        it_iter = it_maxiter_val; 
< 0.001 
      1 
 517
    end 
 518 

< 0.001 
    122 
 519
end 
 520 

 521 
% End Timer
< 0.001 
      1 
 522
if (bl_time) 
< 0.001 
      1 
 523
    toc; 
< 0.001 
      1 
 524
end 
 525 

 526 
% End Profile
< 0.001 
      1 
 527
if (bl_profile) 
  0.004 
      1 
 528
    profile off 
 529 
    profile viewer
 530 
    st_file_name = [st_profile_prefix st_profile_name_main st_profile_suffix];
 531 
    profsave(profile('info'), strcat(st_profile_path, st_file_name));
 532 
end
 533 

 534 
%% Process Optimal Choices
 535 

 536 
result_map = containers.Map('KeyType','char', 'ValueType','any');
 537 
result_map('mt_val') = mt_val;
 538 
result_map('mt_pol_idx') = mt_pol_idx;
 539 

 540 
% Find optimal Formal Informal Choices. Could have saved earlier, but was
 541 
% wasteful of resources
 542 
for it_z_i = 1:it_z_n
 543 
    for it_a_j = 1:it_a_n
 544 
        fl_z_r_infbr = ar_z_r_infbr_mesh_wage(it_z_i);
 545 
        fl_z_wage = ar_z_wage_mesh_r_infbr(it_z_i);
 546 

 547 
        fl_a = ar_a(it_a_j);
 548 
        fl_coh = f_coh(fl_z_wage, fl_a);
 549 
        fl_a_opti = mt_pol_a(it_a_j, it_z_i);
 550 

 551 
        param_map('fl_r_inf') = fl_z_r_infbr;
 552 

 553 
        % call formal and informal function.
 554 
        [~, fl_opti_b_bridge, fl_opti_inf_borr_nobridge, fl_opti_for_borr, fl_opti_for_save] = ...
 555 
            ffs_fibs_min_c_cost_bridge(fl_a_opti, fl_coh, ...
 556 
            param_map, support_map, armt_map, func_map, bl_input_override);
 557 

 558 
        % store savings and borrowing formal and inf optimal choices
 559 
        mt_pol_b_bridge(it_a_j,it_z_i) = fl_opti_b_bridge;
 560 
        mt_pol_inf_borr_nobridge(it_a_j,it_z_i) = fl_opti_inf_borr_nobridge;
 561 
        mt_pol_for_borr(it_a_j,it_z_i) = fl_opti_for_borr;
 562 
        mt_pol_for_save(it_a_j,it_z_i) = fl_opti_for_save;
 563 

 564 
    end
 565 
end
 566 

 567 
result_map('cl_mt_pol_a') = {mt_pol_a, zeros(1)};
 568 
result_map('cl_mt_coh') = {f_coh(ar_z_r_infbr_mesh_wage, ar_a'), zeros(1)};
 569 

 570 
result_map('cl_mt_pol_c') = {mt_pol_cons, zeros(1)};
 571 
result_map('cl_mt_pol_b_bridge') = {mt_pol_b_bridge, zeros(1)};
 572 
result_map('cl_mt_pol_inf_borr_nobridge') = {mt_pol_inf_borr_nobridge, zeros(1)};
 573 
result_map('cl_mt_pol_for_borr') = {mt_pol_for_borr, zeros(1)};
 574 
result_map('cl_mt_pol_for_save') = {mt_pol_for_save, zeros(1)};
 575 

 576 
result_map('ar_st_pol_names') = ["cl_mt_pol_a", "cl_mt_coh", "cl_mt_pol_c", ...
 577 
    "cl_mt_pol_b_bridge", "cl_mt_pol_inf_borr_nobridge", "cl_mt_pol_for_borr", "cl_mt_pol_for_save"];
 578 

 579 
% Get Discrete Choice Outcomes
 580 
result_map = ffs_fibs_identify_discrete(result_map, bl_input_override);
 581 

 582 
%% Post Solution Graph and Table Generation
 583 
% Note in comparison with *abzr*, results here, even when using identical
 584 
% parameters would differ because in *abzr* solved where choices are
 585 
% principle. Here choices are principle + interests in order to facilitate
 586 
% using the informal choice functions.
 587 
%
 588 
% Note that this means two things are
 589 
% different, on the one hand, the value of asset for to coh is different
 590 
% based on the grid of assets. If the asset grid is negative, now per grid
 591 
% point, there is more coh because that grid point of asset no longer has
 592 
% interest rates. On the other hand, if one has positive asset grid point
 593 
% on arrival, that is worth less to coh. Additionally, when making choices
 594 
% for the next period, now choices aprime includes interests. What these
 595 
% mean is that the a grid no longer has the same meaning. We should expect
 596 
% at higher savings levels, for the same grid points, if optimal grid
 597 
% choices are the same as before, consumption should be lower when b
 598 
% includes interest rates and principle. This is however, not true when
 599 
% arriving in a period with negative a levels, for the same negative a
 600 
% level and same a prime negative choice, could have higher consumption
 601 
% here becasue have to pay less interests on debt. This tends to happen for
 602 
% smaller levels of borrowing choices.
 603 
%
 604 
% Graphically, when using interest + principle, big difference in
 605 
% consumption as a fraction of (coh - aprime) figure. In those figures,
 606 
% when counting in principles only, the gap in coh and aprime is
 607 
% consumption, but now, as more is borrowed only a small fraction of coh
 608 
% and aprime gap is consumption, becuase aprime/(1+r) is put into
 609 
% consumption.
 610 

 611 
if (bl_post)
 612 
    bl_input_override = true;
 613 
    result_map('ar_val_diff_norm') = ar_val_diff_norm(1:it_iter_last);
 614 
    result_map('ar_pol_diff_norm') = ar_pol_diff_norm(1:it_iter_last);
 615 
    result_map('mt_pol_perc_change') = mt_pol_perc_change(1:it_iter_last, :);
 616 

 617 
    % Standard AZ graphs
 618 
    result_map = ff_az_vf_post(param_map, support_map, armt_map, func_map, result_map, bl_input_override);
 619 

 620 
    % Graphs for results_map with FIBS contents
 621 
    result_map = ff_az_fibs_vf_post(param_map, support_map, armt_map, func_map, result_map, bl_input_override);
 622 
end
 623 

 624 
end

Other subfunctions in this file are not included in this listing.