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