Contents
function out = two_class_dual_keen()
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This code simulates the dual Keen model with two classes of % households as specified in Giraud and Grasselli (2019) % % % authors: G. Giraud and M. Grasselli %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% clear all close all clc warning off
Base Parameters - Table 3 (modified for two classes)
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 theta = 0.2; % proportion of profits paid to investors - MODIFIED phi0 = 0.04/(1-0.04^2); %Phillips curve parameter phi1 = 0.04^3/(1-0.04^2); %Phillips curve parameter c_minus_w = 0.02; % consumption share hard-lower bound for workers - MODIFIED c_minus_i = 0.01; % consumption share hard-lower bound for investors - MODIFIED A_c = 0; %Consumption share asymptotic lower bound B_c = 5; % Consumption share growth rate C_c = 1; K_w = 0.75; % Consumption share upper bound for workers - MODIFIED K_i = 0.15; % Consumption share upper bound for investors - MODIFED nu_c = 0.2; Q_w= ((K_w-A_c)/(c_minus_w-A_c))^nu_c-C_c; Q_i= ((K_i-A_c)/(c_minus_i-A_c))^nu_c-C_c; % Other definitions TOL = 1E-7; options = odeset('RelTol', TOL); txt_format = '%3.3g';
Functions of interest
fun_consumption_w =@(x) max(c_minus_w,A_c + ((K_w-A_c)./(C_c+Q_w*exp(-B_c*x)).^(1/nu_c))); %----first specification : generalised logistic consumption function------% fun_consumption_w_inv = @(x) -log((((K_w-A_c)./(x-A_c)).^nu_c-C_c)./Q_w)./B_c; % inverse of the consumption function over positive income fun_consumption_i =@(x) max(c_minus_i,A_c + ((K_i-A_c)./(C_c+Q_i*exp(-B_c*x)).^(1/nu_c))); %----first specification : generalised logistic consumption function------% fun_consumption_i_inv = @(x) -log((((K_i-A_c)./(x-A_c)).^nu_c-C_c)./Q_i)./B_c; % inverse of the consumption function over positive income total_consumption =@(x) fun_consumption_w(x)+fun_consumption_i(x); 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);
Example 1
% Parameters as in Table 3 (modified for two classes) 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 theta = 0.2; % proportion of profits paid to investors - MODIFIED % Numerical Values of Interest c_eq=1-nu*(alpha+beta+delta) w_0=((r-alpha-beta)/eta_p+1)/markup % Sample paths of the dual Keen model omega0 = 0.75; lambda0 = 0.9; dw0 = 0.5; di0 = 0.5; Y0 = 100; T = 200; [tK,yK] = ode15s(@(t,y) two_class_dual_keen(y), [0 T], convert([omega0, lambda0, dw0,di0]), 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) dw_bar = yK(n,3) di_bar = yK(n,4) 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), ... ', dw_0 = ', num2str(dw0, txt_format), ... ', di_0 = ', num2str(di0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) print('two_keen_phase_convergent','-depsc') figure(2) yyaxis right plot(tK, yK(:,1),tK,yK(:,2),tK,yK(:,3),tK,yK(:,4)) ylabel('\omega,\lambda,dw,di') yyaxis left plot(tK, Y_output) ylabel('Y') print('two_keen_time_convergent','-depsc') title(['\omega_0 = ', num2str(omega0,txt_format), ... ', \lambda_0 = ', num2str(lambda0, txt_format), ... ', d_0 = ', num2str(dw0, txt_format), ... ', di_0 = ', num2str(di0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) legend('Y','\omega', '\lambda','dw','di') %print('dual_keen_time_convergent','-depsc')
c_eq = 0.7150 w_0 = 0.5982 n = 1420 omega_bar = 0.8581 lambda_bar = 0.9735 dw_bar = -1.0520 di_bar = 0.1183
Example 2
% Parameters as in Table 3 (modified for two classes), except for eta_p, 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.5; % adjustment speed for prices - MODIFIED (this is 0.45 in the paper) markup = 1.6; % mark-up value gamma = 0.96; % (1-gamma) is the degree of money ilusion - MODIFIED theta = 0.2; % proportion of profits paid to investors - MODIFIED x=[]; phi0 = 0.04/(1-0.04^2); %Phillips curve parameter phi1 = 0.04^3/(1-0.04^2); %Phillips curve parameter c_minus_w = 0.02; % consumption share hard-lower bound for workers - MODIFIED c_minus_i = 0.01; % consumption share hard-lower bound for investors - MODIFIED A_c = 0; %Consumption share asymptotic lower bound B_c = 8; % Consumption share growth rate (NOTE: this is 5 in the paper) C_c = 1; K_w = 0.75; % Consumption share upper bound for workers - MODIFIED K_i = 0.15; % Consumption share upper bound for investors - MODIFIED nu_c = 0.2; Q_w= ((K_w-A_c)/(c_minus_w-A_c))^nu_c-C_c; Q_i= ((K_i-A_c)/(c_minus_i-A_c))^nu_c-C_c; fun_consumption_w =@(x) max(c_minus_w,A_c + ((K_w-A_c)./(C_c+Q_w*exp(-B_c*x)).^(1/nu_c))); %----first specification : generalised logistic consumption function------% fun_consumption_w_inv = @(x) -log((((K_w-A_c)./(x-A_c)).^nu_c-C_c)./Q_w)./B_c; % inverse of the consumption function over positive income fun_consumption_i =@(x) max(c_minus_i,A_c + ((K_i-A_c)./(C_c+Q_i*exp(-B_c*x)).^(1/nu_c))); %----first specification : generalised logistic consumption function------% fun_consumption_i_inv = @(x) -log((((K_i-A_c)./(x-A_c)).^nu_c-C_c)./Q_i)./B_c; % inverse of the consumption function over positive income total_consumption =@(x) fun_consumption_w(x)+fun_consumption_i(x); % Numerical Values of Interest c_eq=1-nu*(alpha+beta+delta) w_0=((r-alpha-beta)/eta_p+1)/markup % Sample paths of the dual Keen model omega0 = 0.75; lambda0 = 0.9; dw0 = 0.5; di0 = 0.5; Y0 = 100; T = 200; [tK,yK] = ode15s(@(t,y) two_class_dual_keen(y), [0 T], convert([omega0, lambda0, dw0,di0]), 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) dw_bar = yK(n,3) di_bar = yK(n,4) 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), ... ', dw_0 = ', num2str(dw0, txt_format), ... ', di_0 = ', num2str(di0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) print('two_keen_phase_cycle','-depsc') figure(4) yyaxis right plot(tK, yK(:,1),tK,yK(:,2),tK,yK(:,3),tK,yK(:,4)) ylabel('\omega,\lambda,dw,di') yyaxis left plot(tK, Y_output) ylabel('Y') title(['\omega_0 = ', num2str(omega0,txt_format), ... ', \lambda_0 = ', num2str(lambda0, txt_format), ... ', d_0 = ', num2str(dw0, txt_format), ... ', di_0 = ', num2str(di0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) legend('Y','\omega', '\lambda','dw','di') print('two_keen_time_cycle','-depsc')
c_eq = 0.7150 w_0 = 0.6062 n = 3228 omega_bar = 0.5668 lambda_bar = 0.7906 dw_bar = -0.3172 di_bar = 0.0224
Example 3
% Parameters as in Table 3 (modified for two classes), except for nu nu = 15; %capital to output ratio - MODIFIED 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 theta = 0.2; % proportion of profits paid to investors - MODIFIED x=[]; phi0 = 0.04/(1-0.04^2); %Phillips curve parameter phi1 = 0.04^3/(1-0.04^2); %Phillips curve parameter c_minus_w = 0.02; % consumption share hard-lower bound for workers - MODIFIED c_minus_i = 0.01; % consumption share hard-lower bound for investors - MODIFIED A_c = 0; %Consumption share asymptotic lower bound B_c = 5; % Consumption share growth rate C_c = 1; K_w = 0.75; % Consumption share upper bound for workers - MODIFIED K_i = 0.15; % Consumption share upper bound for investors - MODIFIED nu_c = 0.2; Q_w= ((K_w-A_c)/(c_minus_w-A_c))^nu_c-C_c; Q_i= ((K_i-A_c)/(c_minus_i-A_c))^nu_c-C_c; fun_consumption_w =@(x) max(c_minus_w,A_c + ((K_w-A_c)./(C_c+Q_w*exp(-B_c*x)).^(1/nu_c))); %----first specification : generalised logistic consumption function------% fun_consumption_w_inv = @(x) -log((((K_w-A_c)./(x-A_c)).^nu_c-C_c)./Q_w)./B_c; % inverse of the consumption function over positive income fun_consumption_i =@(x) max(c_minus_i,A_c + ((K_i-A_c)./(C_c+Q_i*exp(-B_c*x)).^(1/nu_c))); %----first specification : generalised logistic consumption function------% fun_consumption_i_inv = @(x) -log((((K_i-A_c)./(x-A_c)).^nu_c-C_c)./Q_i)./B_c; % inverse of the consumption function over positive income total_consumption =@(x) fun_consumption_w(x)+fun_consumption_i(x); % Numerical Values of Interest c_eq=1-nu*(alpha+beta+delta) w_0=((r-alpha-beta)/eta_p+1)/markup % Sample paths of the dual Keen model omega0 = 0.75; lambda0 = 0.9; dw0 = 0.75; di0 = -0.25; Y0 = 100; T = 200; [tK,yK] = ode15s(@(t,y) two_class_dual_keen(y), [0 T], convert([omega0, lambda0, dw0,di0]), 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) dw_bar = yK(n,3) di_bar = yK(n,4) 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), ... ', dw_0 = ', num2str(dw0, txt_format), ... ', di_0 = ', num2str(di0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) print('two_keen_phase_divergent','-depsc') figure(6) yyaxis right plot(tK, yK(:,1),tK,yK(:,2),tK,yK(:,3),tK,yK(:,4)) ylabel('\omega,\lambda,dw,di') yyaxis left plot(tK, Y_output) ylabel('Y') title(['\omega_0 = ', num2str(omega0,txt_format), ... ', \lambda_0 = ', num2str(lambda0, txt_format), ... ', d_0 = ', num2str(dw0, txt_format), ... ', di_0 = ', num2str(di0, txt_format), ... ', Y_0 = ', num2str(Y0, txt_format)]) legend('Y','\omega', '\lambda','dw','di') print('two_keen_time_divergent','-depsc')
c_eq = -0.4250 w_0 = 0.5982 n = 870 omega_bar = 0.0683 lambda_bar = 0.0020 dw_bar = 1.0148e+24 di_bar = -5.6200e+22
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); if n==4 new(:,4) = theta*(1-old(:,1)+r*(old(:,3)+old(:,4))-delta*nu)-r*old(:,4); end 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; if n==4 old(:,4) = (theta*(1-old(:,1)+r*old(:,3)-delta*nu)-new(:,4))/(r*(1-theta)); end end end function f = two_class_dual_keen(y) f = zeros(4,1); log_omega = y(1); tan_lambda = y(2); y_w = y(3); y_i = y(4); lambda = atan(tan_lambda)/pi+0.5; omega = exp(log_omega); g_Y = (1-fun_consumption_w(y_w)-fun_consumption_i(y_i))./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_w(y_w)-y_w)+(omega-y_w)*(g_Y+eta_p*(markup*omega-1)); %d(y_w)/dt f(4) = -theta*omega*f(1)+theta*r*(fun_consumption_w(y_w)-y_w)-(1-theta)*r*(fun_consumption_i(y_i)-y_i)+(theta*(1-omega-delta*nu)-y_i)*(g_Y+eta_p*(markup*omega-1)); %d(y_i)/dt end
end