Contents

function out = inventories()
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This code simulates the Inventory Model as specified in
% Grasselli and Nguyen-Huu (2018)
%
%
% authors: M. Grasselli and A. Nguyen-Huu
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clear all
close all
clc
warning off

Base Parameters

This is a combination of Grasselli and Nguyen-Huu (2015) and Giraud and Grasselli (2019)

phi0 = 0.0401;       %Phillips curve parameter
phi1 = 6.41e-05;     %Phillips curve parameter

kappa0 = -0.0065;    % constant parameter in investment function
kappa1 = -5;         % affine parameter in exponent of investment function
kappa2 = 20;         % coefficient in the exponent of investment function
eta_u = 0.2;        % adjustment speed for investment as function of utilization
u_b = 0.9;           % baseline utilization

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;

Other definitions

TOL = 1E-7;
options = odeset('RelTol', TOL);
txt_format = '%3.3g';

Functions of interest

inflation = @(x1,x2,x3) eta_p*(markup*x1-1)+eta_q*(x2-x3);    % inflation, equation (31)

phillips = @(x) phi1./(1-x).^2- phi0;                         % Phillips curve, equation (32)
phillips_prime = @(x) 2*phi1./(1-x).^3;                       % derivative of phillips curve
phillips_inv = @(x) 1 - (phi1./(x+phi0)).^(1/2);              % inverse of phillips curve

investment= @(x1,x2) kappa0+exp(kappa1+kappa2.*x1)+eta_u*(x2-u_b); % investment function, equation (25)

% consumption, equation (24) with generalised logistic function depending
% on income only
consumption =@(x) max(c_minus,A_c + ((K_c-A_c)./(C_c+Q_c*exp(-B_c*x)).^(1/nu_c)));
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

Example 1

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.8;     % adjustment speed for prices with respect to cost
eta_q = 0.2;     % adjustment speed for prices with respect to demand
eta_e = 0.8;     % adjustment speed for expected sales
eta_d = 0.7;     % adjustment speed for desired inventory
markup = 1.2;    % mark-up value
gamma = 0.4;     % (1-gamma) is the degree of money illusion
f_d = 0.1;       % desired inventories as a fraction of expected sales

% Functions of interest

inflation = @(x1,x2,x3) eta_p*(markup*x1-1)+eta_q*(x2-x3);    % inflation, equation (31)

phillips = @(x) phi1./(1-x).^2- phi0;                         % Phillips curve, equation (32)
phillips_prime = @(x) 2*phi1./(1-x).^3;                       % derivative of phillips curve
phillips_inv = @(x) 1 - (phi1./(x+phi0)).^(1/2);              % inverse of phillips curve

investment= @(x1,x2) kappa0+exp(kappa1+kappa2.*x1)+eta_u*(x2-u_b); % investment function, equation (25)

% consumption, equation (24) with generalised logistic function depending
% on income only
consumption =@(x) max(c_minus,A_c + ((K_c-A_c)./(C_c+Q_c*exp(-B_c*x)).^(1/nu_c)));
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


% Numerical Values of Interest

ydbar = 1/(1+(alpha+beta)*f_d);
yebar = 1/(1+(alpha+beta)*f_d)

x=fsolve(@system2d, [0.9,0.1]);

omegabar=x(1)
dbar=x(2)

ibar=inflation(omegabar,ydbar,yebar);

ubar=(nu*(alpha+beta+delta)*(1+(alpha+beta)*f_d))/(1-consumption(omegabar)*(1+(alpha+beta)*f_d))

kbar=investment(yebar*(1-omegabar)-r*dbar,ubar);

cbar = consumption(omegabar);

lambdabar = phillips_inv(alpha+(1-gamma)*ibar)


% Sample paths of the Keen model with inventories

omega0 = 0.9;
lambda0 = 0.9;
d0 = 0.5;
ye0 = 0.9;
u0 = 0.8;
y0=[convert([omega0, lambda0]),d0,ye0,u0];

Y0 = 100;
T = 200;

[tK,yK] = ode15s(@(t,y) keen_inventory(y), [0 T], y0, options);
sol = retrieve([yK(:,1),yK(:,2)]);
yK(:,1)=sol(:,1);
yK(:,2)=sol(:,2);
Y_output = Y0*yK(:,2)/lambda0.*exp((alpha+beta)*tK);

n=length(yK(:,3));

omega_eq = yK(n,1)
lambda_eq = yK(n,2)
d_eq = yK(n,3)
ye_eq = yK(n,4)
u_eq = yK(n,5)

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(:,4),tK,yK(:,5))
ylabel('\omega,\lambda,y_e,u')

yyaxis left
plot(tK, yK(:,3))
ylabel('d')

title(['\omega_0 = ', num2str(omega0,txt_format), ...
    ', \lambda_0 = ', num2str(lambda0, txt_format), ...
    ', ye_0 = ', num2str(ye0, txt_format), ...
    ', u_0 = ', num2str(u0, txt_format)])
legend('d','\omega', '\lambda','y_e','u')

% print('dual_keen_time_convergent','-depsc')
yebar =

    0.9955


Equation solved.

fsolve completed because the vector of function values is near zero
as measured by the default value of the function tolerance, and
the problem appears regular as measured by the gradient.




omegabar =

    0.8522


dbar =

    0.3503


ubar =

    1.8399


lambdabar =

    0.9710


omega_eq =

    0.8521


lambda_eq =

    0.9710


d_eq =

    0.3503


ye_eq =

    0.9955


u_eq =

    1.8399

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 = keen_inventory(y)
    f = zeros(5,1);
    log_omega = y(1);
    tan_lambda = y(2);
    d = y(3);
    ye = y(4);
    u = y(5);

    lambda = atan(tan_lambda)/pi+0.5;
    omega = exp(log_omega);
    pi_e = ye*(1-omega)-r*d;
    yd = consumption(omega)+investment(pi_e,u)/u;
    g_Y = (f_d*(alpha+beta+eta_d)+1)*(ye*(alpha+beta)+eta_e*(yd-ye))+eta_d*(yd-1);

    f(1) = phillips(lambda)-alpha-(1-gamma)*inflation(omega,yd,ye); %d(log_omega)/dt
    f(2) = (1+tan_lambda^2)*pi*lambda*(g_Y-alpha-beta); %d(tan_lambda)/dt
    f(3) = d*(r-g_Y-inflation(omega,yd,ye))+omega-consumption(omega); %d(d)/dt
    f(4) = ye*(alpha+beta-g_Y)+eta_e*(yd-ye);  % dy_e/dt
    f(5) = u*(g_Y-investment(pi_e,u)/nu+delta);  % du/dt
end

function  F = system2d(x)
        F(1) = investment(yebar*(1-x(1))-r*x(2),(nu*(alpha+beta+delta)*(1+(alpha+beta)*f_d))/(1-consumption(x(1))*(1+(alpha+beta)*f_d))) - nu*(alpha+beta+delta);
        F(2) = x(2) - (x(1)-consumption(x(1)))/(alpha+beta+inflation(x(1),ydbar,yebar)-r);
end
end