{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4c60ff49",
   "metadata": {},
   "source": [
    "# Exercise Session 8 – Input/Output Analysis\n",
    "### ENV–501 Material and Energy Flow Analysis\n",
    "\n",
    "The goal of this exercise session is to illustrate the basics of input-output analysis, using an example given by Wassily Leontief, who is at the origin of this method. Source: Leontief, Wassily. \"Environmental repercussions and the economic structure: an input-output approach.\" Green accounting. Routledge, 2018. 385-394.\n",
    "\n",
    "Let's consider a simple economy, composed of two sectors (agriculture and manufacturing). The input-output table, extended with environmental and employment impacts, is given below.\n",
    "\n",
    "|    From\\Into                | Agriculture    |  Manufacturing | Households demand | Total Outputs | \n",
    "| ---                |    :-:       |         :-:        |      :-:    |         :-:          | \n",
    "| Agriculture          |     25      |         20          |      55      |              100   | \n",
    "| Manufacturing  |     14     |         6      |      30 |              50 | \n",
    "| Air pollution  |     50     |        10      |       -  |              - | \n",
    "| Labor inputs  |     80     |        180      |       - |              - | \n",
    "\n",
    "Table 1: Input-output of a national economy (in physical units)\n",
    "\n",
    "**Question 0**: Identify the matrix of transaction $Z$, the vector of total outputs $X$, and the factor of production matrix $F$ (environmental and employment impacts here).\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "8d64dada",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "X = np.array([[100],\n",
    "              [50]])\n",
    "\n",
    "Z = np.array([[25, 20],\n",
    "              [14, 6]])\n",
    "\n",
    "F = np.array([[50, 10],\n",
    "              [80, 180]])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9254988b",
   "metadata": {},
   "source": [
    "### Input-output analysis\n",
    "\n",
    "The direct requirement matrix A is given by multiplication of the transaction matrix $Z$ with the diagonalised and inverted industry output $X$:\n",
    "\n",
    "$A = Z\\hat{X}^{-1}$,\n",
    "\n",
    "where the hat means that the vector $X$ has been transformed to a diagonal matrix.\n",
    "\n",
    "**Question 1**: Compute A in the cell below (make sure you would know how to do the computations by hand).\n",
    "\n",
    "Hints: \n",
    "- using np.diagflat(X), you obtain a matrix with the vector $X$ in the diagonal\n",
    "- np.linalg.inv(A) computes the inverse of a matrix A\n",
    "- if A and B are two matrices of compatible sizes, A @ B computes the matrix product."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "82bea819",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Direct requirement matrix A:\n",
      "[[0.25 0.4 ]\n",
      " [0.14 0.12]]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "A = Z @ np.linalg.inv(np.diagflat(X))\n",
    "print(\"Direct requirement matrix A:\")\n",
    "print(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f8dfcc3e",
   "metadata": {},
   "source": [
    "You should get the following result:\n",
    "\n",
    "|      From\\Into              | Agriculture    |  Manufacturing |\n",
    "| ---                |    :-:       |         :-:        |\n",
    "| Agriculture          |     0.25      |         0.40          |\n",
    "| Manufacturing  |     0.14     |         0.12      |\n",
    "\n",
    "Table 1: Input requirements per unit of output.\n",
    "\n",
    "**Question 2**:  What do the entries of this matrix mean? How many units of manufacturing products are needed to produce one unit of agricultural product?\n",
    "\n",
    "**Answer 2**: $a_{ij}$ is the number of units of product of sector i required to produce one unit of product of sector j. We need 0.14 units of manufacturing products by units of agricultural products.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12d06f8f",
   "metadata": {},
   "source": [
    "The factor of production coefficients $S$ are obtained as:\n",
    "\n",
    "$S = F\\hat{X}^{-1}$\n",
    "\n",
    "**Question 3**: Compute the matrix $S$ in the cell below (make sure you would now how to do the computations by hand)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f3c633a9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Factor of production coefficients S:\n",
      "[[0.5 0.2]\n",
      " [0.8 3.6]]\n"
     ]
    }
   ],
   "source": [
    "S = F @ np.linalg.inv(np.diagflat(X))\n",
    "print(\"\\nFactor of production coefficients S:\")\n",
    "print(S)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8e6fcb4",
   "metadata": {},
   "source": [
    "You should get the following result:\n",
    "\n",
    "|      From\\Into              | Agriculture    |  Manufacturing |\n",
    "| ---                |    :-:       |         :-:        |\n",
    "| Air pollutant          |     0.5      |         0.2          |\n",
    "| Labor input  |     0.8     |         3.6      |\n",
    "\n",
    "Table 1: Input requirements per unit of output.\n",
    "\n",
    "**Question 4**: What do these coefficients mean? How many units of labor input are needed for one unit of manufacturing product?\n",
    "\n",
    "**Answer 4**: $s_{ij}$ is the number of units of production factor i required to produce one unit of product of sector j. We need 3.6 units of labor by unit of manufacturing product."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44553df1",
   "metadata": {},
   "source": [
    "--------------------------------------\n",
    "# SCENARIOS\n",
    "\n",
    "Under the assumption that these matrices ($A$ and $S$) remain constant, we can use them to compute impacts of changes in the final demand $Y_{new}$.\n",
    "\n",
    "**Question 5**: According to you, is it reasonable that they remain constant in time? What could make this assumption fail?\n",
    "\n",
    " **Answer 5**: A and S can change if the production system changes (i.e. less units of product i are required by unit of product j).\n",
    "\n",
    "The total industry output $X_{new}$ can be calculated for any arbitrary vector of final demand $Y_{new}$ by multiplying with the total requirement matrix (Leontief matrix) $L$.\n",
    "\n",
    "$X_{new} = (I-A)^{-1}Y_{new} = LY_{new}$\n",
    "\n",
    "**Question 6**: Where does this formula come from? In the cell below, compute the Leontief matrix $L$. Then, compute the total output $X$ using the current final demand $Y$ and under modified scenarios of your choice.\n",
    "\n",
    "Hint:\n",
    "- you can obtain the identity matrix of dimension n x n using np.eye(n)\n",
    "\n",
    "**Answer 6**: It comes from the balance equation: X = AX + Y, i.e. total output = intermediate demand + final demand."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "aa7b7182",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Leontief matrix L:\n",
      "[[1.45695364 0.66225166]\n",
      " [0.23178808 1.24172185]]\n",
      "\n",
      "Total output X with current final demand Y:\n",
      "[[100.]\n",
      " [ 50.]]\n",
      "\n",
      "Total output X with modified final demand Y:\n",
      "[[106.62251656]\n",
      " [ 62.41721854]]\n"
     ]
    }
   ],
   "source": [
    "L = np.linalg.inv(np.eye(2) - A)\n",
    "print(\"\\nLeontief matrix L:\")\n",
    "print(L)\n",
    "\n",
    "# current demand\n",
    "Y = np.array([[55],\n",
    "              [30]])\n",
    "\n",
    "X_baseline = L @ Y\n",
    "print(\"\\nTotal output X with current final demand Y:\")\n",
    "print(X_baseline)\n",
    "\n",
    "# Modified final demand scenario\n",
    "Y_new = np.array([[55],\n",
    "                       [40]])\n",
    "X_new = L @ Y_new\n",
    "print(\"\\nTotal output X with modified final demand Y:\")\n",
    "print(X_new)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "72c1cb9c",
   "metadata": {},
   "source": [
    "The required labor and air pollution $D$ to meet a final demand $Y_{new}$ can be computed as follows:\n",
    "\n",
    "$$D = SX_{new} = SLY_{new} := MY_{new}$$\n",
    "\n",
    "The matrix $M$ is called the matrix of multipliers. It allows to directly compute the impact of a final demand change on the factors of production (here, labor and air pollution).\n",
    "\n",
    "**Question 7**: In the cell below, compute the required labor and air pollution $D$ for the final demand $Y$ in the baseline and modified scenarios."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "0f7dd0d6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Multipliers matrix M:\n",
      "[[0.77483444 0.5794702 ]\n",
      " [2.         5.        ]]\n",
      "\n",
      "Required labor and air pollution D with current final demand Y:\n",
      "[[ 60.]\n",
      " [260.]]\n",
      "\n",
      "Required labor and air pollution D with modified final demand Y:\n",
      "[[ 65.79470199]\n",
      " [310.        ]]\n"
     ]
    }
   ],
   "source": [
    "M = S @ L\n",
    "print(\"\\nMultipliers matrix M:\")\n",
    "print(M)\n",
    "\n",
    "D_baseline = M @ Y\n",
    "print(\"\\nRequired labor and air pollution D with current final demand Y:\")\n",
    "print(D_baseline)\n",
    "\n",
    "D_new = M @ Y_new\n",
    "print(\"\\nRequired labor and air pollution D with modified final demand Y:\")\n",
    "print(D_new)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d26ba598",
   "metadata": {},
   "source": [
    "----------------------------------------------------------\n",
    "**Python package**\n",
    "\n",
    "Comment: As seen in class, the analysis performed above can be extended to multiple regions that have connected economies. The python package \"pymrio\" performs all these calculations and more. The cells below just illustrate the most basic components."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1fe689f6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Run this if you have not installed pymrio yet\n",
    "\n",
    "# Using pip:\n",
    "\n",
    "#pip install pymrio\n",
    "\n",
    "# Using conda:\n",
    "\n",
    "#conda install -c conda-forge pymrio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "01b3186c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Index(['food', 'mining', 'manufactoring', 'electricity', 'construction',\n",
      "       'trade', 'transport', 'other'],\n",
      "      dtype='object', name='sector')\n",
      "Index(['reg1', 'reg2', 'reg3', 'reg4', 'reg5', 'reg6'], dtype='object', name='region')\n"
     ]
    }
   ],
   "source": [
    "import pymrio \n",
    "\n",
    "# load the example multi-regional input-output database\n",
    "test_mrio = pymrio.load_test()\n",
    "\n",
    "# the test mrio consists of six regions and eight sectors:\n",
    "print(test_mrio.get_sectors())\n",
    "print(test_mrio.get_regions())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "95f488de",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['Z', 'Y', 'unit', 'population']\n",
      "['F', 'F_Y', 'unit']\n"
     ]
    }
   ],
   "source": [
    "# Quantities that are initially available\n",
    "print(test_mrio.DataFrames)\n",
    "print(test_mrio.emissions.DataFrames) # Sum over sectors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3cc364cd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<pymrio.core.mriosystem.IOSystem at 0x173ff406540>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Perform all calculations (computes A, L, etc.)\n",
    "\n",
    "test_mrio.calc_all()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ad00bdf1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['Z', 'Y', 'x', 'A', 'L', 'unit', 'population']\n",
      "['F', 'F_Y', 'S', 'S_Y', 'M', 'D_cba', 'D_pba', 'D_imp', 'D_exp', 'unit', 'D_cba_reg', 'D_pba_reg', 'D_imp_reg', 'D_exp_reg', 'D_cba_cap', 'D_pba_cap', 'D_imp_cap', 'D_exp_cap']\n"
     ]
    }
   ],
   "source": [
    "# Quantities available after calculations\n",
    "\n",
    "print(test_mrio.DataFrames)\n",
    "print(test_mrio.emissions.DataFrames)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
