"""
## GAMSSOURCE: https://www.gams.com/latest/noalib_ml/libhtml/noalib_macro.html
## LICENSETYPE: Demo
## MODELTYPE: NLP
Macro - A Small Linear Dynamic Macroeconomic Model of the U.S. Economy in Which Both Monetary and Fiscal Policy Variables Are Used
A small linear dynamic macroeconomic model of U.S. economy in which
both monetary and fiscal policy variables are used.
Linear Quadratic Riccati Equations are solved as a General Nonlinear
Programming Problem instead of the usual Matrix Recursion.
Please see:
Kendrick, D, Caution and Probing in a Macroeconomic Model.
Journal of Economic Dynamics and Control 4, 2 (1982) pp.149-170.
"""
from __future__ import annotations
import os
import gamspy.math as gams_math
import numpy as np
from gamspy import (
Alias,
Card,
Container,
Equation,
Model,
Number,
Ord,
Parameter,
Set,
Sum,
Variable,
)
def main():
cont = Container(
system_directory=os.getenv("SYSTEM_DIRECTORY", None),
)
# SETS #
n = Set(
cont, name="n", records=["consumpt", "invest"], description="states"
)
m = Set(
cont, name="m", records=["gov-expend", "money"], description="controls"
)
k = Set(
cont,
name="k",
records=[
"1964-i",
"1964-ii",
"1964-iii",
"1964-iv",
"1965-i",
"1965-ii",
"1965-iii",
"1965-iv",
],
description="horizon",
)
ku = Set(cont, name="ku", domain=k, description="control horizon")
ki = Set(cont, name="ki", domain=k, description="initial period")
kt = Set(cont, name="kt", domain=k, description="terminal period")
# ALIASES #
nn = Alias(cont, name="nn", alias_with=n)
mp = Alias(cont, name="mp", alias_with=m)
ku[k] = Number(1).where[Ord(k) < Card(k)]
ki[k] = Number(1).where[Ord(k) == 1]
kt[k] = ~ku[k]
# PARAMETERS #
a = Parameter(
cont,
name="a",
domain=[n, nn],
records=np.array([[0.914, -0.016], [0.097, 0.424]]),
description="state vector matrix",
)
b = Parameter(
cont,
name="b",
domain=[n, m],
records=np.array([[0.305, 0.424], [-0.101, 1.459]]),
description="control vector matrix",
)
wk = Parameter(
cont,
name="wk",
domain=[n, nn],
records=np.array([[0.0625, 0], [0, 1]]),
description="penalty matrix for states - input",
)
rk = Parameter(
cont,
name="rk",
domain=[m, mp],
records=np.array([[1, 0], [0, 0.444]]),
description="penalty matrix for controls",
)
c = Parameter(
cont,
name="c",
domain=n,
records=[("consumpt", -59.4), ("invest", -184.7)],
description="constant term",
)
xinit = Parameter(
cont,
name="xinit",
domain=n,
records=[("consumpt", 387.9), ("invest", 85.3)],
description="initial value",
)
uinit = Parameter(
cont,
name="uinit",
domain=m,
records=[("gov-expend", 110.5), ("money", 147.1)],
description="initial controls",
)
xtilde = Parameter(
cont, name="xtilde", domain=[n, k], description="desired path for x"
)
utilde = Parameter(
cont, name="utilde", domain=[m, k], description="desired path for u"
)
w = Parameter(
cont,
name="w",
domain=[n, nn, k],
description="penalty matrix on states",
)
w[n, nn, ku] = wk[n, nn]
w[n, nn, kt] = 10000 * wk[n, nn]
xtilde[n, k] = xinit[n] * gams_math.power(1.0075, Ord(k) - 1)
utilde[m, k] = uinit[m] * gams_math.power(1.0075, Ord(k) - 1)
# VARIABLES #
x = Variable(cont, name="x", domain=[n, k], description="state variable")
u = Variable(cont, name="u", domain=[m, k], description="control variable")
# EQUATIONS #
stateq = Equation(
cont,
name="stateq",
type="regular",
domain=[n, k],
description="state equation",
)
criterion = 0.5 * Sum(
[k, n, nn],
(x[n, k] - xtilde[n, k]) * w[n, nn, k] * (x[nn, k] - xtilde[nn, k]),
) + 0.5 * Sum(
[ku, m, mp],
(u[m, ku] - utilde[m, ku]) * rk[m, mp] * (u[mp, ku] - utilde[mp, ku]),
)
stateq[n, k.lead(1)] = (
x[n, k.lead(1)]
== Sum(nn, a[n, nn] * x[nn, k]) + Sum(m, b[n, m] * u[m, k]) + c[n]
)
macro = Model(
cont,
name="macro",
equations=cont.getEquations(),
problem="nlp",
sense="MIN",
objective=criterion,
)
x.l[n, k] = xinit[n]
u.l[m, k] = uinit[m]
x.fx[n, ki] = xinit[n]
macro.solve()
import math
assert math.isclose(macro.objective_value, 273.2724, rel_tol=0.001)
# REPORTING PARAMETER
rep = Parameter(cont, name="rep", domain=["*", k])
rep["xtilde_consumpt", k] = xtilde["consumpt", k]
rep["xtilde_invest", k] = xtilde["invest", k]
rep["x_consumpt", k] = x.l["consumpt", k]
rep["x_invest", k] = x.l["invest", k]
rep["utilde_gov-expend", k] = utilde["gov-expend", k]
rep["utilde_money", k] = utilde["money", k]
rep["u_gov-expend", k] = u.l["gov-expend", k]
rep["u_money", k] = u.l["money", k]
print("Objective Function Value: ", round(macro.objective_value, 4))
print("Solution Summary:\n", rep.pivot().round(3))
# End Macro
if __name__ == "__main__":
main()