$Title A Standard CGE Model in Calibrated Share Format

$ontext

Thomas F. Rutherford
Center for Energy Policy and Economics
Department of Management, Technology and Economics
ETH Zurich

It seems that students are nearly always looking for a "cook book" on
how to implement and analyze equilibrium models.  I have posted lots
of models on the internet over the years, figuring that this should
provide enough clues for the interested student. (For a recent post,
see http://www.mpsge.org/oecdio.zip.)  

Students seem so convinced that the process of numerical modeling is
something mysterious and requires special incantations rather than
just logic and attention to detail.  Well, let them eat cake.

So here is yet another attempt at codifying the steps involved in
implementing a GAMS/MGE equilibrium model.  The same steps are
involved whether working with a small or large scale dataset.  My
notes from 2003 on a larger scale example are here:

http://www.mpsge.org/tza/index.html

STEPS

1. Read the source benchmark data (The oecdio model illustrates
yet another method for extracting data from Excel workbooks.)

2. Verify consistency of the benchmark dataset in original format
and balance as necessary.  (See the TZA example for an example of the
balancing procedure.)

3. Partition the source data into model-relevant parameters.  This
typically involves use of GAMS tuples which link the address space of
the source data to the labels used in the model.

4. Verify consistency of the benchmark dataset in model-consistent
format.

5. Read "free parameters" (i.e. elasticties).

6. Define the GAMS/MPSGE model.

7. Write out the corresponding algebraic model in GAMS/MCP.  This is
really just a mechanical process, relying on the calibrated share
format. (Google for "calibrated share for nested CES" and you find
some lecture notes from 1995).

8. Replicate the benchmark equilibrium in both the MGE and MCP
formats, using .iterlim=0 approach.

9. Compute a counterfactual simulation with either the MGE or MCP model and
then verify (using .iterlim=0) that the equilibrum conditions are 
satisfied in the other format.

For a worked example on how to debug MPSGE and MCP models in parallel,
see http://www.mpsge.org/mcpdebug.html

I've included a homework assignment below.  This was a question on the
University of Colorado computational economics PhD field exam in 1996.

$offtext

*       -----------------------------------------------------------------
*       1. Read the source data.  In this case, we have a balanced social
*       accounting matrix.

set     u       SAM accounts    / BRD, MLK, CAP, LAB, IDT, TRF, HOH, GOV, INV, EXT/

alias (u,v);

table   sam(u,v)        social accounting matrix

        BRD     MLK     CAP     LAB     IDT
BRD     21      8
MLK     17      9
CAP     20      30
LAB     15      25
IDT     5       4
TRF     1       2
HOH                     50      40
GOV                                     9
INV
EXT     13      11

+       TRF     HOH     GOV     INV     EXT
BRD             20      19      16      8
MLK             30      14      15      4
CAP
LAB
IDT
TRF
HOH
GOV     3       23
INV             17      2               12
EXT;

*       -----------------------------------------------------------------
*       2. Verify consistency of the social accounting matrix.

parameter       samchk  Consistency check on the SAM;
samchk(u,"rowsum") = sum(v, sam(u,v));
samchk(u,"colsum") = sum(v, sam(v,u));
samchk(u,"diff") = samchk(u,"rowsum") - samchk(u,"colsum") + eps;
display samchk;


*       -----------------------------------------------------------------
*       3. Partition the source data into matrices defined over
*       sets employed in the model.

set     i(u)    Goods          /BRD, MLK/
        h(u)    Factors        /CAP, LAB/;

alias (i,j), (h,k);

parameter       y0(j)           composite factor
                f0(h,j)         the h-th factor input by the j-th firm
                x0(i,j)         intermediate input
                z0(j)           output of the j-th good
                xp0(i)          household consumption of the i-th good
                xg0(i)          government consumption
                xv0(i)          investment demand
                e0(i)           exports
                m0(i)           imports
                q0(i)           Armington's composite good
                d0(i)           domestic good
                sp0             private saving
                sg0             government saving
                td0             direct tax
                tz0(j)          production tax
                tm0(j)          import tariff

                ff(h)           factor endowment of the h-th factor
                Sf              foreign saving in US dollars
                pWe(i)          export price in US dollars
                pWm(i)          import price in US dollars
                tauz(i)         production tax rate
                taum(i)         import tariff rate,
                taud            Direct tax rate,
                pm0(i)          Reference price of imports;

td0     =sam("gov","hoh");
tz0(j)  =sam("idt",j);
tm0(j)  =sam("trf",j);

f0(h,j) =sam(h,j);
y0(j)   =sum(h, f0(h,j));
x0(i,j) =sam(i,j);
z0(j)   =y0(j) +sum(i, x0(i,j));
m0(i)   =sam("ext",i);

tauz(j) =tz0(j)/z0(j);
taum(j) =tm0(j)/m0(j);

xp0(i)  =sam(i,"hoh");
ff(h)   =sam("hoh",h);

xg0(i)  =sam(i,"gov");
xv0(i)  =sam(i,"inv");
e0(i)   =sam(i,"ext");
q0(i)   =xp0(i)+xg0(i)+xv0(i)+sum(j, x0(i,j));
d0(i)   =(1+tauz(i))*z0(i)-e0(i);
sp0     =sam("inv","hoh");
sg0     =sam("inv","gov");
sf      =sam("inv","ext");

pwe(i)  =1;
pwm(i)  =1;

taud    =td0/sum(h, ff(h));
pm0(i) = 1 + taum(i);

*       -----------------------------------------------------------------
*       4. Verify benchmark consistency of the partitioned data.
*       The accounting identities employed here are the same which
*       enter into the modl.

parameter       profit(i,*)     Zero profit for domestic production
                market(i,*)     Goods market clearance,
                income          Income balance;

profit(i,"d0") = d0(i);
profit(i,"e0") = e0(i);
profit(i,"tauz") = -tauz(i)*z0(i);
profit(i,"x0") = -sum(j,x0(j,i));
profit(i,"f0") = -sum(h, f0(h,i));
alias (uni,*);
profit(i,"chk") = sum(uni, profit(i,uni)) + eps;
display profit;

*       Convert the production tax from a net to a gross basis:

tauz(i) = tauz(i)*z0(i)/(e0(i)+d0(i));

market(i,"d0") = d0(i);
market(i,"m0") = m0(i);
market(i,"taum") = taum(i)*m0(i);
market(i,"x0") = -sum(j,x0(i,j));
market(i,"xp0") = -xp0(i);
market(i,"xg0") = -xg0(i);
market(i,"xv0") = -xv0(i);
market(i,"chk") = sum(uni, market(i,uni)) + eps;
display market;

income("ra","ff") = sum(h, ff(h));
income("ra","taud") = -sum(h,taud*ff(h));
income("ra","sp0") = -sp0;
income("ra","xp0") = -sum(i,xp0(i));

income("govt","tauz") = sum(i,tauz(i)*z0(i));
income("govt","taum") = sum(i,taum(i)*m0(i));
income("govt","xg0") = -sum(i,xg0(i));
income("govt","taud") = taud*sum(h,ff(h));
income("govt","sg0") = -sg0;

income("investor","sg0") = sg0;
income("investor","sp0") = sp0;
income("investor","sf") = sf;
income("investor","xv0") = -sum(i,xv0(i));

set agent /ra, govt, investor/;
income(agent,"chk") = sum(uni, income(agent,uni)) + eps;
display income;

*       -----------------------------------------------------------------
*       5. Read in the "free parameters" -- elasticities of substitution
*       and trnasformation:

parameter       sigma(i)        Elasticity of substitution
                psi(i)          Elasticity of transformation
                eta(i)          Substitution elasticity parameter
                phi(i)          Transformation elasticity parameter;

sigma(i)=2;
psi(i)  =2;
eta(i)=(sigma(i)-1)/sigma(i);
phi(i)=(psi(i)+1)/psi(i);

*       -----------------------------------------------------------------
*       6. Define the model using MPSGE.

$ONTEXT
$MODEL: stdmge
$SECTORS:
        Z(j)            ! Output of the j-th good
        Q(i)            ! Armington's composite good

$COMMODITIES:
        PD(i)           ! Domestic good price
        PQ(i)           ! Armington's composite good price
        PF(h)           ! Factor price
        ER              ! Exchange rate

$CONSUMERS:
        RA
        GOVT
        Investor

*       Production:

$prod:Z(i)  t:psi(i) s:0 a(s):1
        o:PD(i)         q:d0(i)                         a:govt  t:tauz(i)
        o:ER            q:(pwe(i)*e0(i))  p:(1/pwe(i))  a:govt  t:tauz(i)
        i:PQ(j)         q:x0(j,i)
        i:PF(h)         q:f0(h,i)   a:

*       Armington composite:

$prod:Q(i)  s:sigma(i)
        o:PQ(i)         q:q0(i)
        i:PD(i)         q:d0(i)
        i:ER            q:(pwm(i)*m0(i))   a:govt       p:(pm0(i)/pwm(i)) t:taum(i)

$report:
        v:E(i)          o:ER    PROD:Z(i)
        v:M(i)          I:ER    PROD:Q(i)

*       Private households:

$demand:RA  s:1
        d:PQ(i)         q:xp0(i)
        e:PF(h)         q:((1-taud)*ff(h))
        e:ER            q:(-sp0)

*       government - public goods demands are fixed.  any
*       excess of tax
$demand:GOVT   s:0
        d:PQ(i)         q:xg0(i)
        e:PF(h)         q:(taud*ff(h))
        e:ER            q:(-sg0)

*       investor allocates savings among new capital goods
*       with fixed budget shares:
$demand:INVESTOR  s:0
        e:ER            q:(sg0+sp0+sf)
        d:PQ(i)         q:xv0(i)

$offtext
$sysinclude mpsgeset stdmge

*       -----------------------------------------------------------------
*       7. Write out the corresponding algebraic model so that
*       we are sure that we know hat we are doing.

*       There is one equation for each variable in the model --
*       zero profit for each $sector, market clearance for each
*       $commodity and and income balance for each $consumer:

equations
        prf_Z(j)        Output of the j-th good
        prf_Q(i)        Armington's composite good

        mkt_PD(i)       Domestic good price
        mkt_PQ(i)       Armington's composite good price
        mkt_PF(h)       Factor price
        mkt_ER          Exchange rate

        bal_RA          Income balance for the representative agent,
        bal_GOVT        Income balance for the government
        bal_Investor    Income balance for the investor;

*       At this point we need to calculate benchmark value shares:

parameter       thetad(i)       Domestic output value share,
                thetaf(h,i)     Primary factor value share;

thetad(i) = d0(i)/(d0(i)+e0(i));
thetaf(h,i) = f0(h,i)/sum(k,f0(k,i));

*       Unit revenue revenue function (calibrated CET format):

$macro R(i) ((thetad(i)*PD(i)**(1+psi(i)) + \
           (1-thetad(i))*(ER*pwe(i))**(1+psi(i)))**(1/(1+psi(i))))

*       Unit cost function for facgtors (Cobb Douglas):

alias (h,h_);
$macro C(i) (prod(h_, PF(h_)**thetaf(h_,i)))

prf_Z(i)..      C(i)*sum(h,f0(h,i)) + sum(j, PQ(j)*x0(j,i)) =e=
                        (d0(i)+e0(i)) * R(i) * (1-tauz(i));

*       Compensated supply functions (CET):

$macro ZD(i)    (d0(i)*(PD(i)/R(i))**psi(i))
$macro ZE(i)    (pwe(i)*e0(i)*(ER*pwe(i)/R(i))**psi(i))

*       Compensated factor demand function (Cobb Douglas):
$macro FD(h,i)  (f0(h,i)*C(i)/PF(h))

parameter       thetam(i)       Import value share;
thetam(i) = m0(i)*pm0(i)/(m0(i)*pm0(i)+d0(i));

*       Armington unit cost function (calibrated share CES format):

$MACRO CDM(i) (((1-thetam(i))*PD(i)**(1-sigma(i)) + \
            thetam(i)*(ER*(1+taum(i))*pwm(i)/pm0(i))**(1-sigma(i)))**(1/(1-sigma(i))))

*       Zero profit condition for Armington supply:

prf_Q(i)..      CDM(i)*(d0(i)+m0(i)*pm0(i)) =e= PQ(i)*q0(i);

*       Compensated demand functions for domestic and imported 
*       goods (CES):

$macro  QD(i)   (d0(i)*(CDM(i)/PD(i))**sigma(i))
$macro  QM(i)   (pwm(i)*m0(i)*(CDM(i)*pm0(i)/(ER*(1+taum(i))*pwm(i)))**sigma(i))

*       Market clearance condition for domestic goods:

mkt_PD(i)..     Z(i)*ZD(i) =e= QD(i)*Q(i);

*       Cobb-Douglas final demand -- we need value shares to
*       write down the demand function:

parameter       alphac(i)       Consumption budget shares;
alphac(i) = xp0(i)/sum(j,xp0(j));

*       Market clearance for goods:

mkt_PQ(i)..     q0(i)*Q(i) =e= sum(j, x0(i,j)*Z(j)) + alphac(i)*RA/PQ(i) 
                        + xg0(i)*GOVT/sum(j,PQ(j)*xg0(j)) 
                        + xv0(i)*INVESTOR/sum(j,PQ(j)*xv0(j));

*       Market clearance for primary factors:

mkt_PF(h)..     ff(h) =e= sum(i, FD(h,i)*Z(i));

*       Current account balance:

mkt_ER..        sf + sum(i, ZE(i)*Z(i)) =e= sum(i, QM(i)*Q(i));
                
*       Private income:

bal_RA..        RA =e= (1-taud)*sum(h,PF(h)*ff(h)) - ER*sp0;

*       Government income (including tax flows):

bal_GOVT..      GOVT =e= taud*sum(h,PF(h)*ff(h)) - ER*sg0 
                        + ER*sum(i,taum(i)*QM(i)*Q(i)) 
                        + sum(i, R(i)*Z(i)*tauz(i)*(d0(i)+e0(i)));

*       Investor income:

bal_Investor..  INVESTOR =e= ER*(sg0+sp0+sf);

model stdmcp /
        prf_Z.Z,   prf_Q.Q,
        mkt_PD.PD, mkt_PQ.PQ,
        mkt_PF.PF, mkt_ER.ER,
        bal_RA.RA, bal_GOVT.GOVT, bal_Investor.Investor /;

*       -----------------------------------------------------------------
*       8. Replicate the benchmark equilibrium with both the
*       MGE and MCP models.

stdmge.iterlim = 0;
$include stdmge.gen
solve stdmge using MCP;
abort$(stdmge.objval > 1e-4) "MGE model does not calibrate.";

stdmcp.iterlim = 0;
SOLVE stdmcp USING MCP;
abort$(stdmcp.objval > 1e-4) "MCP model does not calibrate.";

*       Note: if you want to evaluate macros which depend on 
*       variables, you can do so with the $ondotl macro:

$ondotl
parameter       calibchk        Cross check on algebraic calibration;
calibchk("R",i) = R(i);
calibchk("C",i) = C(i);
calibchk("ZE",i) = ZE(i)/e0(i);
calibchk("ZD",i) = ZD(i)/d0(i);
calibchk("QD",i) = QD(i)/d0(i);
calibchk("QM",i) = QM(i)/m0(i);
calibchk("cdm",i) = CDM(i);
display calibchk;

*       -----------------------------------------------------------------
*       9. Compute a counterfactual with the MGE model and then
*       verify that the MCP model is consistent.

taum(i) = 0;
stdmge.iterlim = 10000;
$include stdmge.gen
solve stdmge using MCP;

stdmcp.iterlim = 0;
SOLVE stdmcp USING MCP;
abort$(stdmcp.objval > 1e-4) "MCP model inconsistent with the MGE model.";

$ontext

Homework exercise:

Show that the model as specified is equivalent toon in which the
import and export activities are explicitly represented:

$prod:Z(i)  t:psi(i) s:0 a(s):1
        o:PD(i)         q:d0(i)         a:govt  t:tauz(i)
        o:PE(i)         q:e0(i)         a:govt  t:tauz(i)
        i:PQ(j)         q:x0(j,i)
        i:PF(h)         q:f0(h,i)   a:

$prod:Q(i)  s:sigma(i)
        o:PQ(i)         q:q0(i)
        i:PD(i)         q:d0(i)
        i:PM(i)         q:(pm0(i)*m0(i))

$prod:E(i)
        o:ER            q:(pwe(i)*e0(i))
        i:PE(i)         q:e0(i)

$prod:M(i)
        o:PM(i)         q:(m0(i)*pm0(i))
        i:ER            q:(pwm(i)*m0(i))   a:govt t:taum(i)

Proof by testimonial (implement and verify consistency) is a good
starting point, but to answer the homework assignment you need to
explain why the world market price levels, pwe(i) and pwm(i), enter
the MPSGE model above in both the Q: and P: fields of the associated
foreign exchange coefficient, but in this alternative formulation, the
world market prices only enter the Q: field.

$offtext