Book Example: Economic equilibria#

economic_eq_lecture.ipynb Open In Colab Kaggle Gradient Open In SageMaker Studio Lab Hits

Description: economic model using complementarity conditions from Chapter 19 AMPL book

Tags: ampl-only, ampl-book, finance, complementarity-problem

Notebook author: Marcos Dominguez Velad <marcos@ampl.com>

Model author: N/A

# Install dependencies
%pip install -q amplpy
# Google Colab & Kaggle integration
from amplpy import AMPL, ampl_notebook

ampl = ampl_notebook(
    modules=["coin", "gurobi"],  # modules to install
    license_uuid="default",  # license to use
)  # instantiate AMPL object and register magics

Economic equilibria#

This model is based on the models showed in the Chapter 19 of the AMPL book, related to complementarity problems.

Classic model#

The following model does not use complementarity conditions.

  • Sets and parameters:

    • Products PROD and demand[i] for each product i.

    • Activities ACT and cost[j] for each activity j.

    • Amount of product i produced by activity j, io[i,j].

  • Decision variables Level[j]: levels of production activities (for each activity j).

  • Objective: minimize total production cost,

\[ \sum \limits_{j \in ACT} cost_j \cdot Level_j; \]

So the AMPL formulation is implemented as:

%%writefile econmin.mod
set PROD;   # products
set ACT;    # activities

param cost {ACT} > 0;      # cost per unit of each activity
param demand {PROD} >= 0;  # units of demand for each product
param io {PROD,ACT} >= 0;  # units of each product from
                           # 1 unit of each activity

var Level {j in ACT} >= 0;

minimize Total_Cost:  sum {j in ACT} cost[j] * Level[j];

subject to Demand {i in PROD}:
      sum {j in ACT} io[i,j] * Level[j] >= demand[i];
Overwriting econmin.mod
%%writefile econ.dat
data;

param: ACT:   cost :=
        P1    2450
        P1a   1290
        P2    1850
        P2a   3700
        P2b   2150
        P3    2200
        P3c   2370
        P4    2170 ;

param: PROD:  demand :=
       AA1     70000 
       AC1     80000
       BC1     90000 
       BC2     70000 
       NA2    400000 
       NA3    800000  ;

param io (tr):
         AA1  AC1  BC1  BC2   NA2   NA3 :=
   P1     60   20   10   15   938   295
   P1a     8    0   20   20  1180   770
   P2      8   10   15   10   945   440
   P2a    40   40   35   10   278   430
   P2b    15   35   15   15  1182   315
   P3     70   30   15   15   896   400
   P3c    25   40   30   30  1029   370
   P4     60   20   15   10  1397   450 ;
Overwriting econ.dat
%%ampl_eval
model econmin.mod;
data econ.dat;
option solver cbc;
solve;
display Level;
display Demand.dual;
CBC 2.10.5CBC 2.10.5 optimal, objective 6808640.553
3 iterations
Level [*] :=
 P1     0
P1a  1555.3
 P2     0
P2a     0
P2b     0
 P3   147.465
P3c  1889.4
 P4     0
;

Demand.dual [*] :=
AA1  16.7051
AC1   5.44585
BC1  57.818
BC2   0
NA2   0
NA3   0
;

Complementarity model#

Consider the new variables Price[i] for each product, and solve the problem to find an equilibrium instead of an optimum solution. The equilibrium is subject to two conditions:

  • First, for each product, total output must meet demand and price must be nonnegative, and in addition there must be a complementarity between these relationships, where production exceeds demand the price must be zero, or equivalently, if the price is positive, the production must equal the demand.

subject to Pri_Compl {i in PROD}:
   Price[i] >= 0 complements
      sum {j in ACT} io[i,j] * Level[j] >= demand[i];
  • Second, for each activity j, the value of resulting product i is Price[i]*io[i,j], so activity j would produce a total value of

\[\sum \limits_{i \in PROD} Price[i] \cdot io[i,j]\]

When equilibrium happens, the previous value must not exceed the activity’s cost per unit cost[j]. Moreover, there is a complementarity between this relationship and the level of activity j, where cost exceeds total value the activity must be zero, or, where the activity cost is positive then the total value must be equal to the cost. This can be expressed as:

subject to Lev_Compl {j in ACT}:
   Level[j] >= 0 complements
      sum {i in PROD} Price[i] * io[i,j] <= cost[j];
%%writefile econ.mod
set PROD;   # products
set ACT;    # activities

param cost {ACT} > 0;      # cost per unit of each activity
param demand {PROD} >= 0;  # units of demand for each product
param io {PROD,ACT} >= 0;  # units of each product from
                           # 1 unit of each activity
var Price {i in PROD};
var Level {j in ACT};

subject to Pri_Compl {i in PROD}:
   Price[i] >= 0 complements
      sum {j in ACT} io[i,j] * Level[j] >= demand[i];

subject to Lev_Compl {j in ACT}:
   Level[j] >= 0 complements
      sum {i in PROD} Price[i] * io[i,j] <= cost[j];
Overwriting econ.mod

Remark: the model is square, as there are \(n+m\) variables and \(n+m\) constraints (\(n\) number of products and \(m\) number of activities). Some solvers can take advantage of this to use different solving techniques.

Finally, let’s see that the equilibrium model gives also the optimal solution for the first classic formulation.

%%ampl_eval
reset;
model econ.mod;
data econ.dat;
option solver gurobi;
solve;
# Show total cost
display sum {j in ACT} cost[j] * Level[j];
display Level;
Gurobi 10.0.0:Gurobi 10.0.0: optimal solution
0 simplex iterations
Objective = find a feasible point.
sum{j in ACT} cost[j]*Level[j] = 6808640

Level [*] :=
 P1     0
P1a  1555.3
 P2     0
P2a     0
P2b     0
 P3   147.465
P3c  1889.4
 P4     0
;