Contents
function out = keen()
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This code simulates the Keen model as specified in Grasselli and Costa Lima (2012) % % % authors: B. Costa Lima and M. Grasselli %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% close all clc warning off
Parameters attribution
Equations (24), (26), (63) and (65)
nu = 3; % capital-to-output ratio alpha = 0.025; % productivity growth rate beta = 0.02; % population growth rate delta = 0.01; % depreciation rate phi0 = 0.04/(1-0.04^2); %Phillips curve parameter, Phi(0.96)=0 phi1 = 0.04^3/(1-0.04^2); %Phillips curve parameter, Phi(0)=-0.04 r = 0.03; %real interest rate kappa0 = -0.0065 ; % investment function parameter kappa1 = exp(-5); % investment function parameter kappa2 = 20; % investment function parameter
Other definitions
TOL = 1E-7; options = odeset('RelTol', TOL); txt_format = '%3.3g';
Functions Definition
fun_Phi = @(x) phi1./(1-x).^2- phi0; % Phillips curve, equation (25) fun_Phi_prime = @(x) 2*phi1./(1-x).^3; % derivative of Phillips curve fun_Phi_inv = @(x) 1 - (phi1/(x+phi0)).^(1/2); % inverse of Phillips curve fun_kappa = @(x) kappa0+kappa1.*exp(kappa2.*x); % Investment function, equation (64) fun_kappa_prime = @(x) kappa1.*kappa2.*exp(kappa2.*x); % Derivative of investment function fun_kappa_inv = @(x) log((x-kappa0)./kappa1)./kappa2; % Inverse of investment function
Numerical Values of Interest
kappa_eq = nu*(alpha+beta+delta) % investment at interior equilibrium pi_eq=fun_kappa_inv(nu*(alpha+beta+delta)) % profit at interior equilibrium, equation (41) d_eq = (fun_kappa(pi_eq)-pi_eq)/(alpha+beta) % debt ratio at interior equilibirum, equation (42) omega_eq = 1-pi_eq-r*d_eq % wage share at interior equilibrium, equation (42) lambda_eq=fun_Phi_inv(alpha) % employment at interior equilibirum, equation (42) d=[]; syms d d_sols(1) = vpasolve(d*(r+delta-fun_kappa(1-r*d)/nu)+fun_kappa(1-r*d)-1,d) ; % solution to equation (40) given in equation (66) d_sols(2) = vpasolve(d*(r+delta-fun_kappa(1-r*d)/nu)+fun_kappa(1-r*d)-1,[20 40]) ; % solution to equation (40) given in equation (66) d_sols J = @(x,y,z) [fun_Phi(y)-alpha, x.*fun_Phi_prime(y), 0; -y.*fun_kappa_prime(1-x-r*z)/nu, (fun_kappa(1-x-r*z)-nu*(alpha+beta+delta))/nu, -r*y.*fun_kappa_prime(1-x-r*z)/nu; ((z-nu).*fun_kappa_prime(1-x-r*z)+nu)/nu, 0, (nu*(r+delta)-fun_kappa(1-x-r*z)+r*(z-nu).*fun_kappa_prime(1-x-r*z))/nu]; E1=eig(J(omega_eq,lambda_eq,d_eq)) % eigenvalues of the Jacobian at the interior equilibrium E2=eig(J(0,0,d_sols(1))) % eigenvalues of the Jacobian at the first d0 equilibrium E3=eig(J(0,0,d_sols(2))) % eigenvalues of the Jacobian at the second d0 equilibrium cond59= fun_kappa_prime(pi_eq)/nu*(pi_eq-nu*delta)-(alpha+beta) % expression in brackets in condition (59)
kappa_eq = 0.1650 pi_eq = 0.1618 d_eq = 0.0702 omega_eq = 0.8361 lambda_eq = 0.9686 d_sols = [ 2.999995114426015986641604626889, 30.767016452389481647975528982775] E1 = -0.0352 + 1.9581i -0.0352 - 1.9581i -0.0450 + 0.0000i E2 = -180122.65958170398076808544264108 -13/200 180122.11658158037574626271733576 E3 = -13/200 -0.046692277832906022704348899916326 0.20619779407835991738362093529345 cond59 = 0.1057
Sample paths of the Keen model
bar_pi_n_K = fun_kappa_inv(nu*(alpha+beta+delta)); bar_d_K = (fun_kappa(bar_pi_n_K)-bar_pi_n_K)/(alpha+beta); bar_omega_K = 1-bar_pi_n_K-r*bar_d_K; bar_lambda_K = fun_Phi_inv(alpha); omega0 = 0.75; lambda0 = 0.75; d0 = 0.1; Y0 = 100; T = 300; [tK,yK] = ode15s(@(t,y) keen(y), [0 T], convert([omega0, lambda0, d0]), options); yK = retrieve(yK); Y_output = Y0*yK(:,2)/lambda0.*exp((alpha+beta)*tK); % Figure 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('keen_phase_convergent','-depsc') % Figure 4 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('keen_time_convergent','-depsc') omega0 = 0.75; lambda0 = 0.70; d0 = 0.1; Y0 = 100; T = 300; [tK,yK] = ode15s(@(t,y) keen(y), [0 T], convert([omega0, lambda0, d0]), options); yK = retrieve(yK); Y_output = Y0*yK(:,2)/lambda0.*exp((alpha+beta)*tK); % Figure 5 figure(3) yyaxis right plot(tK, yK(:,1),tK,yK(:,2)) ylabel('\omega,\lambda') yyaxis left plot(tK,yK(:,3),tK, Y_output) ylabel('d,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('d', 'Y','\omega','\lambda') print('keen_time_divergent','-depsc')
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 pi_n=1-omega-r*d log_p = log(p)
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, 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(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) = 1-old(:,1)-r*old(:,3); if n==4 new(:,4) = log(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) = (1-old(:,1)-new(:,3))/r; if n==4 old(:,4) = exp(new(:,4)); end end end function f = keen(y) f = zeros(3,1); log_omega = y(1); tan_lambda = y(2); pi_n = y(3); lambda = atan(tan_lambda)/pi+0.5; omega = exp(log_omega); g_Y = fun_kappa(pi_n)/nu-delta; % Equation (47) f(1) = fun_Phi(lambda)-alpha; %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_kappa(pi_n)-pi_n)+(1-omega-pi_n)*g_Y; %d(pi_n)/dt end
end