Contents
function out = dual_keen()
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This code simulates the dual Keen model as specified in % Giraud and Grasselli (2019) % % % authors: G. Giraud and M. Grasselli %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% clear all close all clc warning off
Base Parameters - Table 3
nu = 3; %capital to output ratio alpha = 0.025; %productivity growth rate beta = 0.02; %population growth rate delta = 0.05; %depreciation rate r = 0.03; %real interest rate eta_p = 0.35; % adjustment speed for prices markup = 1.6; % mark-up value gamma = 0.8; % (1-gamma) is the degree of money ilusion phi0 = 0.04/(1-0.04^2); %Phillips curve parameter phi1 = 0.04^3/(1-0.04^2); %Phillips curve parameter c_minus= 0.03; % consumption share hard-lower bound A_c = 0; %Consumption share asymptotic lower bound B_c = 5; % Consumption share growth rate C_c = 1; K_c = 0.9; %Consumption share upper bound nu_c = 0.2; Q_c= ((K_c-A_c)/(c_minus-A_c))^nu_c-C_c;
Functions of interest
fun_consumption =@(x) max(c_minus,A_c + ((K_c-A_c)./(C_c+Q_c*exp(-B_c*x)).^(1/nu_c))); %----first specification : generalised logistic consumption function------% fun_consumption_inv = @(x) -log((((K_c-A_c)./(x-A_c)).^nu_c-C_c)./Q_c)./B_c; % inverse of the consumption function over positive income fun_Phi = @(x) phi1./(1-x).^2- phi0; fun_Phi_prime = @(x) 2*phi1./(1-x).^3; fun_Phi_inv = @(x) 1 - (phi1./(x+phi0)).^(1/2);
Other definitions
TOL = 1E-7; options = odeset('RelTol', TOL); txt_format = '%3.3g';
Example 1
% Parameters as in Table 3 nu = 3; %capital to output ratio alpha = 0.025; %productivity growth rate beta = 0.02; %population growth rate delta = 0.05; %depreciation rate r = 0.03; %real interest rate eta_p = 0.35; % adjustment speed for prices markup = 1.6; % mark-up value gamma = 0.8; % (1-gamma) is the degree of money ilusion % Numerical Values of Interest c_eq=1-nu*(alpha+beta+delta) eta_1 = fun_consumption_inv(c_eq) A_w = eta_p*markup; % Coefficients in the quadratic equation A_w omega^2 + B_w omega + C_w = 0 B_w = alpha+beta-eta_p*(1+eta_1*markup); C_w = eta_1*(eta_p-alpha-beta)+r*(eta_1-c_eq); x=[]; syms x omega_1 = vpasolve(A_w*x^2+B_w*x+C_w ==0,x) i_omega_1 = eta_p*(markup*omega_1-1) g_nominal_1 = alpha+beta+i_omega_1 lambda_1 = fun_Phi_inv(alpha+(1-gamma)*eta_p*(markup*omega_1-1)) d_1 = (omega_1-eta_1)./r eta_1_calc=omega_1-r.*d_1; % verification step c_eq_calc=fun_consumption(eta_1_calc); %verification step % Sample paths of the dual Keen model omega0 = 0.75; lambda0 = 0.9; d0 = 0.5; Y0 = 100; T = 200; [tK,yK] = ode15s(@(t,y) dual_keen(y), [0 T], convert([omega0, lambda0, d0]), options); yK = retrieve(yK); Y_output = Y0*yK(:,2)/lambda0.*exp((alpha+beta)*tK); n=length(yK(:,3)) omega_bar = yK(n,1) lambda_bar = yK(n,2) d_bar = yK(n,3) figure(1) plot(yK(:,1), yK(:,2)), hold on; %plot(bar_omega_K, bar_lambda_K, 'ro') xlabel('\omega') ylabel('\lambda') title(['\omega_0 = ', num2str(omega0, txt_format), ... ', \lambda_0 = ', num2str(lambda0, txt_format), ... ', d_0 = ', num2str(d0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) print('dual_keen_phase_convergent','-depsc') figure(2) yyaxis right plot(tK, yK(:,1),tK,yK(:,2),tK,yK(:,3)) ylabel('\omega,\lambda,d') yyaxis left plot(tK, Y_output) ylabel('Y') title(['\omega_0 = ', num2str(omega0,txt_format), ... ', \lambda_0 = ', num2str(lambda0, txt_format), ... ', d_0 = ', num2str(d0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) legend('Y','\omega', '\lambda','d') print('dual_keen_time_convergent','-depsc')
c_eq =
0.7150
eta_1 =
0.6059
omega_1 =
0.49291938520463741461070997693151
0.65763195476319826831120345628563
i_omega_1 =
-0.073965144285403047818002412918353
0.018273894667391030254273935519954
g_nominal_1 =
-0.028965144285403047818002412918353
0.063273894667391030254273935519954
lambda_1 =
0.96429092337337114586046395893964
0.96945784620030614474363301296987
d_1 =
-3.7663032540113713771463174119765
1.7241157312739904128701318998274
n =
2556
omega_bar =
0.6567
lambda_bar =
0.9696
d_bar =
1.7244
Example 2
% Parameters as in Table 3 except for eta_p and gamma nu = 3; %capital to output ratio alpha = 0.025; %productivity growth rate beta = 0.02; %population growth rate delta = 0.05; %depreciation rate r = 0.03; %real interest rate eta_p = 0.45; % adjustment speed for prices - MODIFIED markup = 1.6; % mark-up value gamma = .96; % (1-gamma) is the degree of money ilusion - MODIFIED % Numerical Values of Interest c_eq=1-nu*(alpha+beta+delta) eta_1 = fun_consumption_inv(c_eq) A_w = eta_p*markup; % Coefficients in the quadratic equation A_w omega^2 + B_w omega + C_w = 0 B_w = alpha+beta-eta_p*(1+eta_1*markup); C_w = eta_1*(eta_p-alpha-beta)+r*(eta_1-c_eq); x=[]; syms x omega_1 = vpasolve(A_w*x^2+B_w*x+C_w ==0,x) i_omega_1 = eta_p*(markup*omega_1-1) g_nominal_1 = alpha+beta+i_omega_1 lambda_1 = fun_Phi_inv(alpha+(1-gamma)*eta_p*(markup*omega_1-1)) d_1 = (omega_1-eta_1)./r eta_1_calc=omega_1-r.*d_1; % verification step c_eq_calc=fun_consumption(eta_1_calc); %verification step % Sample paths of the dual Keen model omega0 = 0.75; lambda0 = 0.9; d0 = 0.5; Y0 = 100; T = 200; [tK,yK] = ode15s(@(t,y) dual_keen(y), [0 T], convert([omega0, lambda0, d0]), options); yK = retrieve(yK); Y_output = Y0*yK(:,2)/lambda0.*exp((alpha+beta)*tK); n=length(yK(:,3)) omega_bar = yK(n,1) lambda_bar = yK(n,2) d_bar = yK(n,3) figure(3) plot(yK(:,1), yK(:,2)), hold on; %plot(bar_omega_K, bar_lambda_K, 'ro') xlabel('\omega') ylabel('\lambda') title(['\omega_0 = ', num2str(omega0, txt_format), ... ', \lambda_0 = ', num2str(lambda0, txt_format), ... ', d_0 = ', num2str(d0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) print('dual_keen_phase_cycle','-depsc') figure(4) yyaxis right plot(tK, yK(:,1),tK,yK(:,2),tK,yK(:,3)) ylabel('\omega,\lambda,d') yyaxis left plot(tK, Y_output) ylabel('Y') title(['\omega_0 = ', num2str(omega0,txt_format), ... ', \lambda_0 = ', num2str(lambda0, txt_format), ... ', d_0 = ', num2str(d0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) legend('Y','\omega', '\lambda','d') print('dual_keen_time_cycle','-depsc') %
c_eq =
0.7150
eta_1 =
0.6059
omega_1 =
0.51337660572143848603532778591854
0.65503187710354006988977171337227
i_omega_1 =
-0.08036884388056429005456399413865
0.021622951514548850320635633628032
g_nominal_1 =
-0.03536884388056429005456399413865
0.066622951514548850320635633628032
lambda_1 =
0.96780635616165993232539783359532
0.96881832873512291925191143457792
d_1 =
-3.0843959034513356629923904457422
1.6374464759520504654890738027153
n =
4963
omega_bar =
0.4805
lambda_bar =
0.9126
d_bar =
1.1803
Example 3
Parameters as in Table 3 except for nu AND delta
nu = 15; % capital to output ratio - MODIFIED alpha = 0.025; % productivity growth rate beta = 0.02; % population growth rate delta = 0.10; % depreciation rate - MODIFIED (NOTE: this is 0.05 in the paper) r = 0.03; % real interest rate eta_p = 0.35; % adjustment speed for prices markup = 1.6; % mark-up value gamma = 0.8; % (1-gamma) is the degree of money ilusion % Numerical Values of Interest c_eq=1-nu*(alpha+beta+delta) eta_1 = fun_consumption_inv(c_eq) A_w = eta_p*markup; % Coefficients in the quadratic equation A_w omega^2 + B_w omega + C_w = 0 B_w = alpha+beta-eta_p*(1+eta_1*markup); C_w = eta_1*(eta_p-alpha-beta)+r*(eta_1-c_eq); x=[]; syms x omega_1 = vpasolve(A_w*x^2+B_w*x+C_w ==0,x) i_omega_1 = eta_p*(markup*omega_1-1) g_nominal_1 = alpha+beta+i_omega_1 lambda_1 = fun_Phi_inv(alpha+(1-gamma)*eta_p*(markup*omega_1-1)) d_1 = (omega_1-eta_1)./r eta_1_calc=omega_1-r.*d_1; % verification step c_eq_calc=fun_consumption(eta_1_calc); %verification step % Sample paths of the dual Keen model omega0 = 0.75; lambda0 = 0.7; d0 = 0.5; Y0 = 100; T = 200; [tK,yK] = ode15s(@(t,y) dual_keen(y), [0 T], convert([omega0, lambda0, d0]), options); yK = retrieve(yK); Y_output = Y0*yK(:,2)/lambda0.*exp((alpha+beta)*tK); n=length(yK(:,3)) omega_bar = yK(n,1) lambda_bar = yK(n,2) d_bar = yK(n,3) g_bar=(1-c_minus)/nu-delta figure(5) plot(yK(:,1), yK(:,2)), hold on; %plot(bar_omega_K, bar_lambda_K, 'ro') xlabel('\omega') ylabel('\lambda') title(['\omega_0 = ', num2str(omega0, txt_format), ... ', \lambda_0 = ', num2str(lambda0, txt_format), ... ', d_0 = ', num2str(d0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) print('dual_keen_phase_divergent','-depsc') figure(6) yyaxis right plot(tK, yK(:,1),tK,yK(:,2),tK,yK(:,3)) ylabel('\omega,\lambda,d') yyaxis left plot(tK, Y_output) ylabel('Y') title(['\omega_0 = ', num2str(omega0,txt_format), ... ', \lambda_0 = ', num2str(lambda0, txt_format), ... ', d_0 = ', num2str(d0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) legend('Y','\omega', '\lambda','d') print('dual_keen_time_divergent','-depsc') %
c_eq =
-1.1750
eta_1 =
0.0956 - 0.3934i
omega_1 =
0.1375268793268625106771715577569 - 0.49617911095986802963355036671393i
0.50275218583166006178002563156168 + 0.10281657191707506091722022599555i
i_omega_1 =
- 0.27298494757695699402078392765613 - 0.2778603021375260965947882053598i
- 0.06845877593427036540318564632546 + 0.057577280273562034113643326557506i
g_nominal_1 =
- 0.22798494757695699402078392765613 - 0.2778603021375260965947882053598i
- 0.02345877593427036540318564632546 + 0.057577280273562034113643326557506i
lambda_1 =
0.97408289957607732385023306587867 - 0.021491278192165304543281057486094i
0.96531792041637275646895074345848 + 0.0038394716601090056851942825208078i
d_1 =
1.3963557103732356393956844389596 - 3.4272190639025027575057498472755i
13.570532593866487342824153565785 + 16.539303698662266927519936576374i
n =
830
omega_bar =
0.0683
lambda_bar =
4.7264e-08
d_bar =
5.0107e+28
g_bar =
-0.0353
Auxiliary functions
Instead of integrating the system in terms of omega, lambda and d, we decided to use:
log_omega = log(omega), tan_lambda = tan((lambda-0.5)*pi), and y_h=omega-r*d disposable income of households
Experiments show that the numerical methods work better with these variables.
function new = convert(old) % This function converts % [omega, lambda, d, p] % to % [log_omega, tan_lambda, y] % It also work with the first 2 components alone. % each of these variables might also be a time-dependent vector n = size(old,2); %number of variables new = zeros(size(old)); new(:,1) = log(old(:,1)); new(:,2) = tan((old(:,2)-0.5)*pi); if n>2 new(:,3) = old(:,1)-r.*old(:,3); end end function old = retrieve(new) % This function retrieves [omega, lambda, d, p] % from % [log_omega, tan_lambda, pi_n, log_p] % % It also work with the first 2 or 3 elements alone. % each of these variables might also be a time-dependent vector n = size(new,2); %number of variables old = zeros(size(new)); old(:,1) = exp(new(:,1)); old(:,2) = atan(new(:,2))/pi+0.5; if n>2 old(:,3) = (old(:,1)-new(:,3))./r; end end function f = dual_keen(y) f = zeros(3,1); log_omega = y(1); tan_lambda = y(2); y_h = y(3); lambda = atan(tan_lambda)/pi+0.5; omega = exp(log_omega); g_Y = (1-fun_consumption(y_h))./nu-delta; f(1) = fun_Phi(lambda)-alpha-(1-gamma)*eta_p*(markup*omega-1); %d(log_omega)/dt f(2) = (1+tan_lambda^2)*pi*lambda*(g_Y-alpha-beta); %d(tan_lambda)/dt f(3) = omega*f(1)-r*(fun_consumption(y_h)-y_h)+(omega-y_h)*(g_Y+eta_p*(markup*omega-1)); %d(y_h)/dt end
end