$title	Public Infrastructure, Services and Distortionary Taxation

$ontext

Ghosh and Roy (2002) present a planning model incorporating both
public capital (a stock) and public services (a flow) in addition to
private capital and labor.  In their planning framework with an
omniscient social planner, nothing distinguishes public and private
goods, as the planner is fully informed and optimizes on all margins.
In this GAMS program I demonstrate that their portrayal of the problem
may fall far short of reality.  When public goods are non-excludible,
there are serious constraints related to financing.  Incentives
effects of taxation may have a first order impact on the growth
effects of accumulation.  A concrete numerical example illustrates
this point.

Here is the model.

References:

Optimal Growth with Public Capital and Public Services
Sugata Ghosh and Udayan Roy
Economics of Planning 35: 271-292, 2002.

$offtext

set	t	Time (years) /0*100/,
	tf(t)	First year
	tl(t)	Last year;

parameters
	alpha		Stock share of public goods /0.3/
	beta		Private capital value share /0.4/
	rho		Intertemporal discount rate /0.03/
	delta		Capital depreciation rate /0.05/
	k0		Base year private capital /1/
	kg0		Base year public capital  /1/
	tax(t)		Output tax in second best setting 
	df(t)		Discount factor to year t;

tf(t) = yes$(ord(t)=1);
tl(t) = yes$(ord(t)=card(t));
df(t) = exp(-rho*(ord(t)-1));

variables
	U	Intertemporal utility
	TAU	Public output share
	C(t)	Consumption,
	G(t)	Public services,
	Y(t)	Output,
	I(t)	Private Investment,
	IG(t)	Public investment,
	K(t)	Private capital stock,
	KG(t)	Public capital stock,
	KT	Terminal private capital stock,
	KGT	Terminal public capital stock;

positive variables I,IG;

equations welfare, output, provision, private, public, production, termk, termkg;

welfare..	U =E= - (sum(t, df(t) * log(C(t))) - sum(t, tax(t)*Y(t)));

output(t)..	(1-TAU) * Y(t) =e= C(t) + I(t);

provision(t)..	TAU*Y(t) =e= G(t) + IG(t);

private(t)..	k0$tf(t) + K(t-1) * (1 - delta) + I(t-1) =E= K(t);

public(t)..	kg0$tf(t) + KG(t-1) * (1 - delta) + IG(t-1) =E= KG(t);

termk..		sum(tl, K(tl) * (1 - delta) + I(tl)) =E= KT;

termkg..	sum(tl, KG(tl) * (1 - delta) + IG(tl)) =E= KGT;

production(t)..	(KG(t)**alpha * G(t)**(1-alpha))**(1-beta) * K(t)**beta =E= Y(t);

TAU.LO = 0;
TAU.UP = 1;

C.L(t) = 1;
G.L(t) = 1;
KG.L(t) = 1;
K.L(t) = 1;

C.LO(t) = 0.00001;
G.LO(t) = 0.00001;
KG.LO(t) = 0.001;
K.LO(t) = 0.001;	

*	Begin with a naive assumption:

KT.FX  = 10;
KGT.FX = 10;


*	We first evaluate the first-best:

tax(t) = 0;

MODEL growth /all/;
SOLVE growth USING nlp MINIMIZING u; 

*	Scale equations and variables to improve robustness:

growth.scaleopt = 1; 

output.scale(t) = C.L(t) + I.L(t); provision.scale(t) = G.L(t) +
IG.L(t); private.scale(t) = K.L(t); public.scale(t) = KG.L(t);
termk.scale = KT.L; termkg.scale = KGT.L; production.scale(t) =
Y.L(t); U.SCALE = max(1,U.L); TAU.SCALE = max(1,TAU.L); C.SCALE(t) =
max(1,C.L(t)); G.SCALE(t) = max(1,G.L(t)); Y.SCALE(t) = max(1,Y.L(t));
I.SCALE(t) = max(1,I.L(t)); IG.SCALE(t) = max(1,IG.L(t)); K.SCALE(t) =
max(1,K.L(t)); KG.SCALE(t) = max(1,KG.L(t));

SOLVE growth USING nlp MINIMIZING u; 

*	we are not memory-constrained with this model, so we can 
*	keep GAMS in core to minimize the time cost of loading and unloading 
*	the program:

option solvelink=2;

parameter	itlog	Iteration log of terminal targets;
set		itradj	Iterative adjustments of terminal capital /it0*it20/;

loop(itradj,
	itlog(itradj,"K") = KT.L;
	itlog(itradj,"KG") = KGT.L;

*	Impose a constant growth rate over private and public capital
*	in the last half of the planning period:

	loop(tl(t),
	  KT.FX  = K.L(t-50)  * (Y.L(t-40)/Y.L(t-50))**5;
	  KGT.FX = KG.L(t-50) * (Y.L(t-40)/Y.L(t-50))**5;
	);
	SOLVE growth USING nlp MINIMIZING u; 
);
display itlog;

PARAMETER	gamma		Growth rates of primal variables; 
gamma(t+1,"Y") = 100 * (Y.L(t+1)/Y.L(t)-1);
gamma(t+1,"C") = 100 * (C.L(t+1)/C.L(t)-1);
gamma(t+1,"G") = 100 * (G.L(t+1)/G.L(t)-1);
gamma(t+1,"K") = 100 * (K.L(t+1)/K.L(t)-1);
gamma(t+1,"KG") = 100 * (KG.L(t+1)/KG.L(t)-1);
$setglobal domain itradj
$libinclude plot itlog

set	tlbl(t)		Labels for graphical output /0,20,40,60,80,100/;
$setglobal domain t
$setglobal labels tlbl
$libinclude plot gamma

scalar		taxlvl	Homotopy parameter used to move the economy to a second best solution /0/;

VARIABLES	P(t)	Private output price
		PG(t)	Public output price
		MC(t)	Marginal cost of production
		PK(t)	Private capital price
		PKG(t)	Public capital price
		PKT	Salvage value of private capital
		PKGT	Salvage value of public capital;

POSITIVE VARIABLES PK,PKG;

EQUATIONS	OPTC, OPTTAU, OPTY, OPTG, OPTK, OPTKG, OPTI, OPTIG, OPTKT, OPTKGT;

*	Write down first-order conditions for the first-best model:

OPTC(t)..	P(t)*C(t) =E= df(t);
OPTTAU..	sum(t, P(t)*Y(t)) =E= sum(t,PG(t)*Y(t));
OPTY(t)..	MC(t) =E= (1-TAU) * P(t) + TAU * PG(t) * (1-taxlvl);
OPTG(t)..	PG(t) * G(t) =E= MC(t) * Y(t) * (1-alpha)*(1-beta);
OPTI(t)..	P(t) =E= PK(t+1) + PKT$tl(t);
OPTIG(t)..	PG(t) =E= PKG(t+1) + PKGT$tl(t);
OPTK(t)..	PK(t)*K(t) =E= (1-delta)*(PK(t+1) + PKT$tl(t)) * K(t) + beta * MC(t) * Y(t);
OPTKG(t)..	PKG(t)*KG(t) =e= (1-delta)*(PKG(t+1) + PKGT$tl(t)) * KG(t) + (1-beta)*alpha * MC(t) * Y(t);
OPTKT..		KT =E= sum(tl(t), K(t-30)  * (Y.L(t-20)/Y.L(t-30))**3);
OPTKGT..	KGT =E= sum(tl(t), KG(t-30) * (Y(t-20)/Y(t-30))**3);

model PUBLICMCP / OPTC.C,
	OUTPUT.P, PROVISION.PG, PRIVATE.PK, PUBLIC.PKG, TERMK.PKT, TERMKG.PKGT, PRODUCTION.MC,
	OPTTAU.TAU, OPTY.Y, OPTG.G, OPTK.K, OPTKG.KG, OPTI.I, OPTIG.IG, OPTKT.KT, OPTKGT.KGT /;

P.L(t)	= OUTPUT.M(t);
MC.L(t)	= PRODUCTION.M(t);
PG.L(t) = PROVISION.M(t);
PK.L(t)	= PRIVATE.M(t);
PKG.L(t) = PUBLIC.M(t);
PKT.L = TERMK.M;
PKGT.L = TERMKG.M;

*	Scale this model as well:

PUBLICMCP.SCALEOPT = 1;

P.SCALE(t) = P.L(t); MC.SCALE(t) = MC.L(t); PG.SCALE(t) = PG.L(t);
PK.SCALE(t) = PK.L(t); PKG.SCALE(t) = PKG.L(t); PKT.SCALE = PKT.L;
PKGT.SCALE = PKGT.L; OPTC.SCALE(t) = P.L(t)*C.L(t); OPTTAU.SCALE =
sum(t, P.L(t)*Y.L(t)); OPTY.SCALE(t) = MC.L(t); OPTG.SCALE(t) =
PG.L(t) * G.L(t); OPTI.SCALE(t) = P.L(t); OPTIG.SCALE(t) = PG.L(t);
OPTK.SCALE(t) = PK.L(t)*K.L(t); OPTKG.SCALE(t) = PKG.L(t)*KG.L(t);
OPTKT.SCALE = KT.L; OPTKGT.SCALE = KGT.L;


*	Our first solution simply replicates the NLP solution.  It will not
*	be a precise solution because the terminal capital stocks are not 
*	precisely targeted:

PUBLICMCP.ITERLIM = 0;
solve PUBLICMCP using MCP;

*	Compute a precisely targetted solution using the MCP formulation
*	in which non-skew symmetric systems are easily represented and solved:

KT.UP = INF;
KT.LO = 0;
KGT.UP = INF;
KGT.LO = 0;
PUBLICMCP.ITERLIM = 1000000;
solve PUBLICMCP using MCP;

*	OK, we now move to a second-best setting.  First declare parameters 
*	to be used for presenting results:

PARAMETER	utility		Intertemporal welfare,
		gammac		Growth rate in consumption
		gammay		Growth rate in aggregate output
		gammag		Growth rate in public services
		gammak		Growth rate of private capital
		gammakg		Growth rate of public capital
		invshare	Investment share of public output;

*	Declare a set over tax rates to be applied in the second-best model.  
*	The first-best tax rate is 55.1%, and we explore tax rates in the 
*	second-best model ranging from 45% to 60%:
	
set	taulvl	Tax rate in the second best /45*60/;
alias (t,tt);

*	Save the first-best values for comparison:

utility(taulvl,"FirstBest") = prod(t, C.L(t)**(df(t)/sum(tt,df(tt))));
gammac(t,"FirstBest") = 100 * (C.L(t+1)/C.L(t)-1);
gammag(t,"FirstBest") = 100 * (G.L(t+1)/G.L(t)-1);
gammay(t,"FirstBest") = 100 * (Y.L(t+1)/Y.L(t)-1);
gammak(t,"FirstBest") = 100 * (K.L(t+1)/K.L(t)-1);
gammakg(t,"FirstBest") = 100 * (KG.L(t+1)/KG.L(t)-1);
invshare(t,"FirstBest")$(G.L(t)+IG.L(t)) = IG.L(t)/(G.L(t)+IG.L(t));

*	The second-best model is difficult to solve from a poor starting
*	point.  For this reason, it is helpful to solve a sequence of models
*	in which the tax rate on public provision is gradually increased from
*	0 to 100%:

set taxrates /0,10,20,30,40,50,60,70,80,90,100/;
loop(taxrates, 
	TAU.FX = TAU.L;
	taxlvl = 0.1 * (ord(taxrates)-1);
	solve PUBLICMCP using MCP;
*$libinclude plot gamma
);
display taxlvl;

*	Define which tax rates to plot, and define a tuple to relabel the 
*	graphs:

SET	TAUPLOT(TAULVL) /45,50,55,60/;

alias (uu,*);
loop(taulvl,
	TAU.FX = 0.44 + 0.01 * ORD(taulvl);
	solve PUBLICMCP using MCP;
	utility(taulvl,"secondbest") = prod(t, C.L(t)**(df(t)/sum(tt,df(tt))));

*	Save growth rates and public investment shares for selected tax rates:

	if (tauplot(taulvl),
	  gammac(t,taulvl) = 100 * (C.L(t+1)/C.L(t)-1);
	  gammag(t,taulvl) = 100 * (G.L(t+1)/G.L(t)-1);
	  gammay(t,taulvl) = 100 * (Y.L(t+1)/Y.L(t)-1);
	  gammak(t,taulvl) = 100 * (K.L(t+1)/K.L(t)-1);
	  gammakg(t,taulvl) = 100 * (KG.L(t+1)/KG.L(t)-1);
	  invshare(t,taulvl)$(G.L(t)+IG.L(t)) = IG.L(t)/(G.L(t)+IG.L(t));
	);
);
set tplot(t) /0*50/;
$setglobal domain tplot

$setglobal gp_opt0 'set key outside width 3'
$setglobal gp_opt1 "set xlabel 'year'"

*	Generate reports:
$libinclude plot invshare
$libinclude plot gammac
$libinclude plot gammag
$libinclude plot gammay
$libinclude plot gammak
$libinclude plot gammakg

$setglobal domain taulvl
$setglobal labels taulvl
$setglobal gp_opt0 'set yrange[0:1]'
$setglobal gp_opt1 "set xlabel 'tax rate'"
$libinclude plot utility