{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ba081591",
   "metadata": {},
   "source": [
    "# Risk and Model Uncertainty"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b46d481a",
   "metadata": {},
   "source": [
    "## Overview\n",
    "\n",
    "As an introduction to one possible approach to modeling **Knightian  uncertainty**,\n",
    "this lecture describes static representations of five classes of preferences over risky prospects.\n",
    "\n",
    "These preference specifications  allow  us to distinguish **risk** from **uncertainty** along lines proposed by\n",
    "[[Knight, 1921](https://python-advanced.quantecon.org/zreferences.html#id11)].\n",
    "\n",
    "All  five preference specifications incorporate **risk aversion**, meaning displeasure from  risks governed by  well known probability distributions.\n",
    "\n",
    "Two of them also incorporate  **uncertainty aversion**, meaning  dislike of not knowing a  probability distribution.\n",
    "\n",
    "The preference orderings are\n",
    "\n",
    "- Expected utility preferences  \n",
    "- Constraint preferences  \n",
    "- Multiplier preferences  \n",
    "- Risk-sensitive preferences  \n",
    "- Ex post Bayesian expected utility preferences  \n",
    "\n",
    "\n",
    "This labeling  scheme is taken from [[Hansen and Sargent, 2001](https://python-advanced.quantecon.org/zreferences.html#id62)].\n",
    "\n",
    "Constraint and multiplier preferences express  aversion to not knowing a unique probability distribution\n",
    "that describes random outcomes.\n",
    "\n",
    "Expected utility, risk-sensitive, and ex post Bayesian expected utility preferences all attribute a unique known\n",
    "probability distribution to a decision maker.\n",
    "\n",
    "We present things in a simple before-and-after one-period setting.\n",
    "\n",
    "In addition to learning about these preference orderings, this lecture also describes some interesting code for computing and graphing some representations  of indifference curves, utility functions, and related objects.\n",
    "\n",
    "Staring at these indifference curves provides insights into the different preferences.\n",
    "\n",
    "Watch for the presence of a kink at the $ 45 $ degree line for the constraint preference indifference curves.\n",
    "\n",
    "We begin with some that we’ll use to create some graphs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7af461ad",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Package imports\n",
    "import numpy as np\n",
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "from matplotlib import rc, cm\n",
    "from mpl_toolkits.mplot3d import Axes3D\n",
    "from scipy import optimize, stats\n",
    "from scipy.io import loadmat\n",
    "from matplotlib.collections import LineCollection\n",
    "from matplotlib.colors import ListedColormap, BoundaryNorm\n",
    "from numba import njit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fc395fd7",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Plotting parameters\n",
    "%config InlineBackend.figure_format='retina'\n",
    "\n",
    "plt.rc('text', usetex=True)\n",
    "\n",
    "label_size = 20\n",
    "label_tick_size = 18\n",
    "title_size = 24\n",
    "legend_size = 16\n",
    "text_size = 18\n",
    "\n",
    "mpl.rcParams['axes.labelsize'] = label_size \n",
    "mpl.rcParams['ytick.labelsize'] = label_tick_size \n",
    "mpl.rcParams['xtick.labelsize'] = label_tick_size \n",
    "mpl.rcParams['axes.titlesize'] = title_size\n",
    "mpl.rcParams['legend.fontsize'] = legend_size\n",
    "mpl.rcParams['font.size'] = text_size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9e712466",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Useful functions\n",
    "@njit\n",
    "def ent(π, π_hat):\n",
    "    \"\"\"\n",
    "    Compute the relative entropy of a probability vector `π_hat` with respect to `π`. JIT-compiled using Numba.\n",
    "    \n",
    "    \"\"\"\n",
    "    ent_val = -np.sum(π_hat * (np.log(π) - np.log(π_hat)))\n",
    "    \n",
    "    return ent_val\n",
    "\n",
    "\n",
    "def T_θ_factory(θ, π):\n",
    "    \"\"\"\n",
    "    Return an operator `T_θ` for a given penalty parameter `θ` and probability distribution vector `π`.\n",
    "    \n",
    "    \"\"\"\n",
    "    def T_θ(u):  \n",
    "        \"\"\"\n",
    "        Risk-sensitivity operator of Jacobson (1973) and Whittle (1981) taking a function `u` as argument.\n",
    "        \n",
    "        \"\"\"\n",
    "        return lambda c: -θ * np.log(np.sum(π * np.exp(-u(c) / θ)))\n",
    "    \n",
    "    return T_θ\n",
    "\n",
    "\n",
    "def compute_change_measure(u, c, θ, π):\n",
    "    \"\"\"\n",
    "    Compute the channge of measure given a utility function `u`, a consumption vector `c`,\n",
    "    a penalty parameter `θ` and a baseline probability vector `π` \n",
    "    \n",
    "    \"\"\"\n",
    "    \n",
    "    m_unnormalized = np.exp(-u(c) / θ)\n",
    "    m =  m_unnormalized / (π * m_unnormalized).sum()\n",
    "    return m\n",
    "\n",
    "\n",
    "def utility_function_factory(α):\n",
    "    \"\"\"\n",
    "    Return a CRRA utility function parametrized by `α` \n",
    "    \n",
    "    \"\"\"\n",
    "    if α == 1.:\n",
    "        return lambda c: np.log(c)\n",
    "    else: \n",
    "        return lambda c: c ** (1 - α) / (1 - α)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2bb6b3a5",
   "metadata": {},
   "source": [
    "## Basic objects\n",
    "\n",
    "Basic ingredients are\n",
    "\n",
    "- a set of states of the world  \n",
    "- plans describing outcomes as functions of the state of the world,  \n",
    "- a utility function mapping outcomes into utilities  \n",
    "- either a probability distribution or a **set** of probability distributions over states of the world; and  \n",
    "- a way of measuring a discrepancy between two probability distributions.  \n",
    "\n",
    "\n",
    "In more detail, we’ll work with the following setting.\n",
    "\n",
    "- A finite set of possible **states** $ {\\cal I} = \\{i= 1, \\ldots, I\\} $.  \n",
    "- A (consumption) **plan** is a function $ c: {\\cal I} \\rightarrow {\\mathbb R} $.  \n",
    "- $ u: {\\mathbb R} \\rightarrow {\\mathbb R} $  is a **utility function**.  \n",
    "- $ \\pi $ is an $ I \\times 1 $ vector of nonnegative **probabilities** over  states, with $ \\pi_ i \\geq 0, \\sum_{i=1}^I \\pi_i = 1 $.  \n",
    "- **Relative entropy**  $ \\textrm{ent}(\\pi, \\hat \\pi) $ of a probability vector  $ \\hat \\pi $ with respect to a probability vector $ \\pi $ is the expected value of the logarithm of the  likelihood ratio $ m_i \\doteq \\Bigl( \\frac{\\hat \\pi_i}{\\pi_i} \\Bigr) $  under   distribution $ \\hat \\pi $ defined as:  \n",
    "\n",
    "\n",
    "$$\n",
    "\\textrm{ent}(\\pi, \\hat \\pi) = \\sum_{i=1}^I \\hat \\pi_i  \\log \\Bigl( \\frac{\\hat \\pi_i}{\\pi_i} \\Bigr)   = \\sum_{i=1}^I \\pi_i \\Bigl( \\frac{\\hat \\pi_i}{\\pi_i} \\Bigr) \\log \\Bigl( \\frac{\\hat \\pi_i}{\\pi_i} \\Bigr)\n",
    "$$\n",
    "\n",
    "or\n",
    "\n",
    "$$\n",
    "\\textrm{ent}(\\pi, \\hat \\pi) = \\sum_{i=1}^I \\pi_i m_i \\log m_i  .\n",
    "$$\n",
    "\n",
    "**Remark:** A likelihood ratio $ m_i $ is a discrete random variable. For any discrete random variable $ \\{x_i\\}_{i=1}^I $, the expected  value of $ x $  under the $ \\hat \\pi_i $ distribution can be represented as the expected  value  under the $ \\pi $ distribution of the product of  $ x_i $ times the `shock’  $ m_i $:\n",
    "\n",
    "$$\n",
    "\\hat E x = \\sum_{i=1}^I x_i \\hat \\pi_i = \\sum_{i=1}^I m_i x_i  \\pi_i = E m x ,\n",
    "$$\n",
    "\n",
    "where $ \\hat E $ is the mathematical  expectation under the $ \\hat \\pi $ distribution and $ E $ is the expectation under the $ \\pi $ distribution.\n",
    "\n",
    "Evidently,\n",
    "\n",
    "$$\n",
    "\\hat E 1 = E m = 1\n",
    "$$\n",
    "\n",
    "and relative entropy is\n",
    "\n",
    "$$\n",
    "E m \\log m  = \\hat E \\log m .\n",
    "$$\n",
    "\n",
    "In the three figures below, we plot relative entropy from several perspectives.\n",
    "\n",
    "Our first figure depicts  entropy as a function of $ \\hat \\pi_1 $ when $ I=2 $ and $ \\pi_1 = .5 $.\n",
    "\n",
    "When $ \\pi_1 \\in (0,1) $, entropy is finite for both $ \\hat \\pi_1 = 0 $  and $ \\hat \\pi_1 = 1 $ because $ \\lim_{x\\rightarrow 0} x \\log x = 0 $\n",
    "\n",
    "However, when $ \\pi_1=0 $ or $ \\pi_1=1 $, entropy  is infinite."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1aabf034",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Specify baseline probability vector `π`\n",
    "π = np.array([0.5, 0.5])\n",
    "\n",
    "# Construct grid for `π_hat_0` values\n",
    "min_prob = 1e-2\n",
    "π_hat_0_nb = 201\n",
    "π_hat_0_vals = np.linspace(min_prob, 1 - min_prob, num=π_hat_0_nb)\n",
    "\n",
    "# Initialize `π_hat` vector with arbitrary values\n",
    "π_hat = np.empty(2)\n",
    "\n",
    "# Initialize `ent_vals` to store entropy values\n",
    "ent_vals = np.empty(π_hat_0_vals.size)\n",
    "\n",
    "for i in range(π_hat_0_vals.size):  # Loop over all possible values for `π_hat_0` \n",
    "    # Update `π_hat` values\n",
    "    π_hat[0] = π_hat_0_vals[i]\n",
    "    π_hat[1] = 1 - π_hat_0_vals[i]\n",
    "    \n",
    "    # Compute and store entropy value\n",
    "    ent_vals[i] = ent(π, π_hat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "776bcfb2",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(5, 3))\n",
    "plt.plot(π_hat_0_vals, ent_vals, color='blue');\n",
    "plt.ylabel(r'entropy ($\\pi_{1}=%.2f$)' % π[0] );\n",
    "plt.xlabel(r'$\\hat{\\pi}_1$');\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2357ec67",
   "metadata": {},
   "source": [
    "The heat maps in  the next two  figures vary both $ \\hat{\\pi}_1 $ and $ \\pi_1 $.\n",
    "\n",
    "The following figure plots  entropy."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4500bb6e",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Use same grid for `π_0_vals` as for `π_hat_0_vals` \n",
    "π_0_vals = π_hat_0_vals.copy() \n",
    "\n",
    "# Initialize matrix of entropy values\n",
    "ent_vals_mat = np.empty((π_0_vals.size, π_hat_0_vals.size))\n",
    "\n",
    "for i in range(π_0_vals.size):  # Loop over all possible values for `π_0` \n",
    "    # Update `π` values\n",
    "    π[0] = π_0_vals[i]\n",
    "    π[1] = 1 - π_0_vals[i]\n",
    "    \n",
    "    for j in range(π_hat_0_vals.size):  # Loop over all possible values for `π_hat_0` \n",
    "        # Update `π_hat` values\n",
    "        π_hat[0] = π_hat_0_vals[j]\n",
    "        π_hat[1] = 1 - π_hat_0_vals[j]\n",
    "        \n",
    "        # Compute and store entropy value\n",
    "        ent_vals_mat[i, j] = ent(π, π_hat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8e34cb46",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "x, y = np.meshgrid(π_0_vals, π_hat_0_vals)\n",
    "plt.figure(figsize=(10, 8))\n",
    "plt.pcolormesh(x, y, ent_vals_mat.T, cmap='seismic', shading='gouraud')\n",
    "plt.colorbar();\n",
    "plt.ylabel(r'$\\hat{\\pi}_1$');\n",
    "plt.xlabel(r'$\\pi_1$');\n",
    "plt.title('Entropy Heat Map');\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "07524cb8",
   "metadata": {},
   "source": [
    "The next figure plots  the logarithm of entropy."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d3986514",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Check the point (0.01, 0.9)\n",
    "π = np.array([0.01, 0.99])\n",
    "π_hat = np.array([0.9, 0.1])\n",
    "ent(π, π_hat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f59fae0",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 8))\n",
    "plt.pcolormesh(x, y, np.log(ent_vals_mat.T), shading='gouraud', cmap='seismic')\n",
    "plt.colorbar()\n",
    "plt.ylabel(r'$\\hat{\\pi}_1$');\n",
    "plt.xlabel(r'$\\pi_1$');\n",
    "plt.title('Log Entropy Heat Map');\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc296c1d",
   "metadata": {},
   "source": [
    "## Five preference specifications\n",
    "\n",
    "We describe five types of preferences over plans.\n",
    "\n",
    "- Expected utility preferences  \n",
    "- Constraint preferences  \n",
    "- Multiplier preferences  \n",
    "- Risk-sensitive preferences  \n",
    "- Ex post Bayesian expected utility preferences  \n",
    "\n",
    "\n",
    "Expected utility, risk-sensitive, and ex post Bayesian prefernces are  each cast in terms of a unique probability distribution, so they can express risk-aversion, but not model ambiguity aversion.\n",
    "\n",
    "Multiplier and constraint prefernces both  express aversion to\n",
    "concerns about model misppecification, i.e., model uncertainty;  both are cast  in terms of a set or sets  of probability distributions.\n",
    "\n",
    "- The set of distributions expresses the decision maker’s ambiguity about the probability model.  \n",
    "- Minimization over probability distributions expresses his aversion to ambiguity.  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7eb41ea7",
   "metadata": {},
   "source": [
    "## Expected utility\n",
    "\n",
    "A decision maker is said to have **expected utility preferences** when he ranks plans $ c $ by their expected utilities\n",
    "\n",
    "\n",
    "<a id='equation-tom1'></a>\n",
    "$$\n",
    "\\sum_{i=1}^I u(c_i) \\pi_i, \\tag{25.1}\n",
    "$$\n",
    "\n",
    "where $ u $ is a unique utility function and $ \\pi $ is a unique probability measure over states.\n",
    "\n",
    "- A known $ \\pi $ expresses risk.  \n",
    "- Curvature of $ u $ expresses\n",
    "  risk aversion.  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "795fda98",
   "metadata": {},
   "source": [
    "## Constraint preferences\n",
    "\n",
    "A decision maker is said to have **constraint preferences** when he ranks plans $ c $ according to\n",
    "\n",
    "\n",
    "<a id='equation-tom2'></a>\n",
    "$$\n",
    "\\min_{\\{m_i \\geq 0\\}_{i=1}^I}  \\sum_{i=1}^I m_i\\pi_i  u(c_i) \\tag{25.2}\n",
    "$$\n",
    "\n",
    "subject to\n",
    "\n",
    "\n",
    "<a id='equation-tom3'></a>\n",
    "$$\n",
    "\\sum_{i=1}^I \\pi_i m_i \\log m_i \\leq \\eta \\tag{25.3}\n",
    "$$\n",
    "\n",
    "and\n",
    "\n",
    "\n",
    "<a id='equation-tom4'></a>\n",
    "$$\n",
    "\\sum_{i=1}^I \\pi_i m_i = 1 . \\tag{25.4}\n",
    "$$\n",
    "\n",
    "In [(25.3)](#equation-tom3),  $ \\eta \\geq 0 $ defines an  entropy ball of probability distributions $ \\hat \\pi = m \\pi $  that surround a baseline distribution $ \\pi $.\n",
    "\n",
    "As noted earlier,     $ \\sum_{i=1}^I m_i\\pi_i  u(c_i) $ is the expected value of $ u(c) $ under a twisted probability distribution $ \\{\\hat \\pi_i\\}_{i=1}^I = \\{m_i \\pi_i\\}_{i=1}^I $.\n",
    "\n",
    "Larger values of the entropy constraint $ \\eta $ indicate more apprehension about the baseline probability distribution $ \\{\\pi_i\\}_{i=1}^I $.\n",
    "\n",
    "Following [[Hansen and Sargent, 2001](https://python-advanced.quantecon.org/zreferences.html#id62)] and [[Hansen and Sargent, 2008](https://python-advanced.quantecon.org/zreferences.html#id160)], we call minimization problem  [(25.2)](#equation-tom2) subject to [(25.3)](#equation-tom3) and[(25.4)](#equation-tom4) a **constraint problem**.\n",
    "\n",
    "To find  minimizing probabilities, we form a Lagrangian\n",
    "\n",
    "\n",
    "<a id='equation-tom5'></a>\n",
    "$$\n",
    "L = \\sum_{i=1}^I m_i \\pi_i u(c_i) +  \\tilde \\theta\\bigl[\\sum_{i=1}^I \\pi_i m_i \\log m_i - \\eta \\bigr] \\tag{25.5}\n",
    "$$\n",
    "\n",
    "where $ \\tilde \\theta \\geq 0 $ is a Lagrange multiplier associated     with the entropy constraint.\n",
    "\n",
    "Subject to the additional constraint that $ \\sum_{i=1}^I m_i  \\pi_i =1 $, we want to minimize [(25.5)](#equation-tom5) with respect to     $ \\{m_i\\}_{i=1}^I $ and to maximize it with respect to   $ \\tilde \\theta $.\n",
    "\n",
    "The minimizing probability distortions (likelihood ratios) are\n",
    "\n",
    "\n",
    "<a id='equation-tom6'></a>\n",
    "$$\n",
    "\\tilde m_i(c;\\tilde \\theta)\n",
    "= \\frac{ \\exp \\bigl(- u(c_i)/\\tilde \\theta\\bigr)}{\\sum_j \\pi_j \\exp \\bigl(- u(c_j) /\\tilde \\theta\\bigr) } . \\tag{25.6}\n",
    "$$\n",
    "\n",
    "To compute the Lagrange multiplier $ \\tilde \\theta(c, \\eta) $, we must\n",
    "solve\n",
    "\n",
    "$$\n",
    "\\sum_i \\pi_i \\tilde m_i (c;\\tilde \\theta ) \\log (\\tilde m_i (c;\\tilde \\theta ))  = \\eta\n",
    "$$\n",
    "\n",
    "or\n",
    "\n",
    "\n",
    "<a id='equation-tom7'></a>\n",
    "$$\n",
    "\\sum_i \\pi_i \\frac{ \\exp \\bigl(- u(c_i)/\\tilde \\theta\\bigr)}{\\sum_j \\pi_j \\exp \\bigl(- u(c_j)/\\tilde \\theta\\bigr) }\n",
    "\\log \\biggl[\\frac{ \\exp \\bigl(- u(c_i)/\\tilde \\theta\\bigr)}{\\sum_j \\pi_j \\exp \\bigl(- u(c_j)/\\tilde \\theta\\bigr) }\n",
    "\\biggr] = \\eta \\tag{25.7}\n",
    "$$\n",
    "\n",
    "for $ \\tilde \\theta = \\tilde \\theta(c; \\eta) $.\n",
    "\n",
    "For a fixed $ \\eta $, the $ \\tilde \\theta $ that solves equation [(25.7)](#equation-tom7) is evidently a function of the consumption plan $ c $.\n",
    "\n",
    "With $ \\tilde \\theta(c;\\eta) $ in hand we can obtain worst-case  probabilities as functions $ \\pi_i\\tilde m_i(c;\\eta) $ of $ \\eta $.\n",
    "\n",
    "The **indirect (expected) utility function** under constraint preferences is\n",
    "\n",
    "\n",
    "<a id='equation-tom8'></a>\n",
    "$$\n",
    "\\sum_{i=1}^I   \\pi_i \\tilde m_i(c_i;\\eta) u(c_i) = \\sum_{i=1}^I  \\pi_i \\left[\\frac{\\exp(-\\tilde \\theta^{-1} u(c_i))}\n",
    "    {\\sum_{j=1}^I \\exp(-\\tilde \\theta^{-1} u(c_j) ) \\pi_j } \\right]    u(c_i) . \\tag{25.8}\n",
    "$$\n",
    "\n",
    "Entropy evaluated at the minimizing probability distortion\n",
    "[(25.6)](#equation-tom6) equals $ E \\tilde m \\log \\tilde m $ or\n",
    "\n",
    "\n",
    "<a id='equation-tom9'></a>\n",
    "$$\n",
    "\\begin{aligned}\n",
    "& & \\sum_{i=1}^I   \\left[\\frac{\\exp(-\\tilde \\theta^{-1} u(c_i))}\n",
    "    {\\sum_{j=1}^I \\exp(-\\tilde \\theta^{-1} u(c_j) ) \\pi_j } \\right]  \\times \\cr\n",
    "    & & \\left\\{ -\\tilde \\theta^{-1} u(c_i) + \\log \\left(\\sum_{j=1}^I \\exp(-\\tilde \\theta^{-1} u(c_j) ) \\pi_j \\right)\n",
    "        \\right\\}  \\pi_i \\cr\n",
    "    & = & -\\tilde \\theta^{-1} \\sum_{i=1}^I  \\pi_i \\left[\\frac{\\exp(-\\tilde \\theta^{-1} u(c_i))}\n",
    "    {\\sum_{j=1}^I \\exp(-\\tilde \\theta^{-1} u(c_j) ) \\pi_j } \\right]    u(c_i)  \\cr\n",
    "    & & + \\log \\left(\\sum_{j=1}^I \\exp(-\\tilde \\theta^{-1} u(c_j) ) \\pi_j \\right) .\n",
    "\\end{aligned} \\tag{25.9}\n",
    "$$\n",
    "\n",
    "Expression [(25.9)](#equation-tom9) implies that\n",
    "\n",
    "\n",
    "<a id='equation-tom10'></a>\n",
    "$$\n",
    "\\begin{aligned} \n",
    "    - \\tilde \\theta \\log \\left(\\sum_{j=1}^I \\exp(-\\tilde \\theta^{-1} u(c_j) ) \\pi_j \\right) & = &\n",
    "    \\sum_{i=1}^I  \\pi_i \\left[\\frac{\\exp(-\\tilde \\theta^{-1} u(c_i))}\n",
    "    {\\sum_{j=1}^I \\exp(-\\tilde \\theta^{-1} u(c_j) ) \\pi_j } \\right]    u(c_i) \\cr\n",
    "    &   &   + \\tilde \\theta (c;\\eta) \\sum_{i=1}^I \\log \\tilde m_i(c;\\eta) \\tilde m_i(c;   \\eta) \\pi_i ,\n",
    "\\end{aligned} \\tag{25.10}\n",
    "$$\n",
    "\n",
    "where the last term is $ \\tilde \\theta $ times the entropy of the worst-case probability distribution."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2514e55c",
   "metadata": {},
   "source": [
    "## Multiplier preferences\n",
    "\n",
    "A decision maker is said to have **multiplier preferences** when he ranks consumption plans $ c $    according to\n",
    "\n",
    "\n",
    "<a id='equation-tom11'></a>\n",
    "$$\n",
    "{\\sf T}u(c) \\doteq \\min_{\\{m_i \\geq 0\\}_{i=1}^I}  \\sum_{i=1}^I \\pi_i m_i [  u(c_i) + \\theta \\log m_i ] \\tag{25.11}\n",
    "$$\n",
    "\n",
    "where minimization is subject to\n",
    "\n",
    "$$\n",
    "\\sum_{i=1}^I \\pi_i m_i = 1 .\n",
    "$$\n",
    "\n",
    "Here $ \\theta \\in (\\underline \\theta, +\\infty ) $ is a ‘penalty parameter’  that governs a ‘cost’ to an ‘evil alter ego’ who distorts probabilities  by choosing $ \\{m_i\\}_{i=1}^I $.\n",
    "\n",
    "Lower values of the penalty parameter $ \\theta $ express more apprehension about the baseline probability  distribution $ \\pi $.\n",
    "\n",
    "Following [[Hansen and Sargent, 2001](https://python-advanced.quantecon.org/zreferences.html#id62)] and [[Hansen and Sargent, 2008](https://python-advanced.quantecon.org/zreferences.html#id160)], we call the minimization problem on the right side of [(25.11)](#equation-tom11) a **multiplier problem**.\n",
    "\n",
    "The minimizing probability distortion that solves the multiplier problem is\n",
    "\n",
    "\n",
    "<a id='equation-tom12'></a>\n",
    "$$\n",
    "\\hat m_i(c; \\theta) = \\frac{ \\exp \\bigl(- u(c_i)/\\theta\\bigr)}{\\sum_j \\pi_j \\exp \\bigl(- u(c_j)/\\theta\\bigr) } . \\tag{25.12}\n",
    "$$\n",
    "\n",
    "We can solve\n",
    "\n",
    "\n",
    "<a id='equation-tom20'></a>\n",
    "$$\n",
    "\\sum_i \\pi_i \\frac{ \\exp \\bigl(- u(c_i)/ \\theta\\bigr)}{\\sum_j \\pi_j \\exp \\bigl(- u(c_j)/ \\theta\\bigr) }\n",
    "\\log \\biggl[\\frac{ \\exp \\bigl(- u(c_i)/\\theta\\bigr)}{\\sum_j \\pi_j \\exp \\bigl(- u(c_j)/\\theta\\bigr) }\n",
    "\\biggr] = \\tilde \\eta \\tag{25.13}\n",
    "$$\n",
    "\n",
    "to find an entropy level  $ \\tilde \\eta (c; \\theta) $ associated with multiplier preferences with penalty parameter $ \\theta $ and allocation $ c $.\n",
    "\n",
    "For a fixed $ \\theta $, the $ \\tilde \\eta $ that solves equation [(25.13)](#equation-tom20) is a function of the consumption plan $ c $\n",
    "\n",
    "The forms of expressions [(25.6)](#equation-tom6)  and [(25.12)](#equation-tom12) are identical, but the Lagrange multiplier $ \\tilde \\theta $ appears in [(25.6)](#equation-tom6),  while the penalty parameter $ \\theta $ appears in [(25.12)](#equation-tom12).\n",
    "\n",
    "Formulas [(25.6)](#equation-tom6)  and [(25.12)](#equation-tom12) show that worst-case probabilities are **context specific** in the sense that they depend  on both the utility function $ u $ and the consumption plan $ c $.\n",
    "\n",
    "If we add $ \\theta $ times entropy under the worst-case model to expected utility under the worst-case model, we find that the\n",
    "**indirect expected utility function** under multiplier preferences is\n",
    "\n",
    "\n",
    "<a id='equation-tom13'></a>\n",
    "$$\n",
    "-  \\theta \\log \\left(\\sum_{j=1}^I \\exp(- \\theta^{-1} u(c_j) ) \\pi_j \\right) . \\tag{25.14}\n",
    "$$"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a575f44",
   "metadata": {},
   "source": [
    "## Risk-sensitive preferences\n",
    "\n",
    "Substituting $ \\hat m_i $ into $ \\sum_{i=1}^I \\pi_i \\hat m_i [  u(c_i) + \\theta \\log \\hat m_i ] $ gives the indirect utility function\n",
    "\n",
    "\n",
    "<a id='equation-tom14'></a>\n",
    "$$\n",
    "{\\sf T} u(c) \\doteq - \\theta \\log \\sum_{i=1}^I \\pi_i \\exp\\bigl(- u(c_i)/\\theta  \\bigr). \\tag{25.15}\n",
    "$$\n",
    "\n",
    "Here $ {\\sf T} u $ in    [(25.15)](#equation-tom14) is the **risk-sensitivity** operator of  [[Jacobson, 1973](https://python-advanced.quantecon.org/zreferences.html#id245)], [[Whittle, 1981](https://python-advanced.quantecon.org/zreferences.html#id87)],  and [[Whittle, 1990](https://python-advanced.quantecon.org/zreferences.html#id89)].\n",
    "\n",
    "It defines a **risk-sensitive** preference    ordering over plans $ c $.\n",
    "\n",
    "Because it is not linear in utilities $ u(c_i) $ and probabilities $ \\pi_i $, it is said not to be separable across states.\n",
    "\n",
    "Because risk-sensitive preferences use a unique probability distribution, they apparently express no model distrust or ambiguity.\n",
    "\n",
    "Instead, they make an additional adjustment for risk-aversion beyond that embedded in the curvature of $ u $.\n",
    "\n",
    "For $ I=2, c_1=2, c_2=1 $, $ u(c) = \\ln c $, the following figure plots the risk-sensitive criterion $ {\\sf T} u(c) $ defined in    [(25.15)](#equation-tom14) as a function of $ \\pi_1 $ for values of $ \\theta $ of 100 and .6."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7212c650",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "c_bundle = np.array([2., 1.])  # Consumption bundle\n",
    "θ_vals = np.array([100, 0.6])  # Array containing the different values of θ\n",
    "u = utility_function_factory(1.)  # Utility function\n",
    "\n",
    "# Intialize arrays containing values for Tu(c)\n",
    "Tuc_vals = np.empty((θ_vals.size, π_hat_0_vals.size))\n",
    "\n",
    "for i in range(θ_vals.size):  # Loop over θ values\n",
    "    for j in range(π_hat_0_vals.size):  # Loop over `π_hat_0` values\n",
    "        # Update `π` values\n",
    "        π[0] = π_0_vals[j]\n",
    "        π[1] = 1 - π_0_vals[j]\n",
    "\n",
    "        # Create T operator\n",
    "        T = T_θ_factory(θ_vals[i], π)\n",
    "        \n",
    "        # Apply T operator to utility function\n",
    "        Tu = T(u)\n",
    "        \n",
    "        # Compute and store Tu(c)\n",
    "        Tuc_vals[i, j] = Tu(c_bundle)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f77d93d5",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 8))\n",
    "plt.plot(π_0_vals, Tuc_vals[0], label=r'$\\theta=100$', color='blue');\n",
    "plt.plot(π_0_vals, Tuc_vals[1], label=r'$\\theta=0.6$', color='red');\n",
    "plt.ylabel(r'$\\mathbf{T}u\\left(c\\right)$');\n",
    "plt.xlabel(r'$\\pi_1$');\n",
    "plt.legend();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ef06e4f",
   "metadata": {},
   "source": [
    "For large values of $ \\theta $, $ {\\sf T} u(c) $ is approximately linear in the probability $ \\pi_1 $, but for lower values of $ \\theta $, $ {\\sf T} u(c) $ has considerable    curvature as a function of $ \\pi_1 $.\n",
    "\n",
    "Under expected utility, i.e., $ \\theta =+\\infty $, $ {\\sf T}u(c) $ is linear in $ \\pi_1 $, but it is convex as a function of $ \\pi_1 $ when $ \\theta< + \\infty $.\n",
    "\n",
    "The two  panels in the next  figure below  can help us to visualize the extra adjustment for risk that the risk-sensitive operator entails.\n",
    "\n",
    "This will help us understand  how the $ \\mathbf{T} $ transformation works by envisioning  what function is being averaged."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "19c7ce11",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Parameter values\n",
    "θ= 0.8\n",
    "π = np.array([0.5, 0.5])\n",
    "c_bundle = np.array([2., 1.])  # Consumption bundle\n",
    "\n",
    "# Compute the average consumption level implied by `c_bundle` wrt to `π` \n",
    "avg_c_bundle = np.sum(π * c_bundle)\n",
    "\n",
    "# Construct grid for consumption values\n",
    "c_grid_nb = 101\n",
    "c_grid = np.linspace(0.5, 2.5, num=c_grid_nb)\n",
    "\n",
    "# Evaluate utility function on the grid\n",
    "u_c_grid = u(c_grid)\n",
    "\n",
    "# Evaluate utility function at bundle points\n",
    "u_c_bundle = u(c_bundle)\n",
    "\n",
    "# Compute the average utility level implied by `c_bundle` wrt to `π` \n",
    "avg_u = np.sum(π * u_c_bundle)\n",
    "\n",
    "# Compute the first transformation exp(-u(c) / θ) for grid values\n",
    "first_trnsf_u_c_grid = np.exp(-u_c_grid / θ) \n",
    "\n",
    "# Compute the first transformation exp(-u(c) / θ) for bundle values\n",
    "first_trnsf_u_c_bundle = np.exp(-u_c_bundle/θ)\n",
    "\n",
    "# Take expectations in the transformed space for bundle values (second transformation)\n",
    "second_trnsf_u_c_bundle = np.sum(π * first_trnsf_u_c_bundle)\n",
    "\n",
    "# Send expectation back to the original space (third transformation)\n",
    "third_trnsf_u_c_bundle = -θ * np.log(second_trnsf_u_c_bundle)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5e81e334",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6), sharex=True, sharey=True)\n",
    "\n",
    "ax1.plot(c_grid, u_c_grid, label=r'$\\log\\left(c\\right)$', color='blue')\n",
    "ax1.plot(c_bundle, u_c_bundle, color='red')\n",
    "ax1.plot(avg_c_bundle, third_trnsf_u_c_bundle, 'o', color='green');\n",
    "ax1.annotate(r'$-\\theta\\log E\\left[\\exp\\left(\\frac{-\\log\\left(c\\right)}{\\theta}\\right)\\right]$',\n",
    "             (avg_c_bundle+0.05, third_trnsf_u_c_bundle-0.15))\n",
    "\n",
    "# Consumption dots\n",
    "ax1.plot(c_bundle[0], u_c_bundle[0], 'o', color='black')\n",
    "ax1.plot(c_bundle[1], u_c_bundle[1], 'o', color='black')\n",
    "ax1.annotate(r'$c_1$', (c_bundle[0]-0.08, u_c_bundle[0]+0.03))\n",
    "ax1.annotate(r'$c_2$', (c_bundle[1]-0.08, u_c_bundle[1]+0.03))\n",
    "ax1.set_xlabel(r'$c$')\n",
    "\n",
    "ax1.set_title('Original space')\n",
    "ax1.legend()\n",
    "\n",
    "ax2.plot(c_grid, first_trnsf_u_c_grid, label=r'$\\exp\\left(\\frac{-\\log\\left(c\\right)}{\\theta}\\right)$', color='blue');\n",
    "ax2.plot(c_bundle, first_trnsf_u_c_bundle, color='red')\n",
    "ax2.plot(avg_c_bundle, second_trnsf_u_c_bundle, 'o', color='green')\n",
    "ax2.annotate(r'$E\\left[\\exp\\left(\\frac{-\\log\\left(c\\right)}{\\theta}\\right)\\right]$',\n",
    "             (avg_c_bundle+0.05, second_trnsf_u_c_bundle+0.08))\n",
    "\n",
    "# Consumption dots\n",
    "ax2.plot(c_bundle[0], first_trnsf_u_c_bundle[0], 'o', color='black')\n",
    "ax2.plot(c_bundle[1], first_trnsf_u_c_bundle[1], 'o', color='black')\n",
    "ax2.annotate(r'$c_1$', (c_bundle[0], first_trnsf_u_c_bundle[0]+0.05))\n",
    "ax2.annotate(r'$c_2$', (c_bundle[1], first_trnsf_u_c_bundle[1]+0.05))\n",
    "ax2.set_xlabel(r'$c$')\n",
    "\n",
    "ax2.set_title('Transformed space')\n",
    "ax2.legend();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b93ed1a",
   "metadata": {},
   "source": [
    "The panel on the right portrays how the transformation $ \\exp\\left(\\frac{-u\\left(c\\right)}{\\theta}\\right) $ sends $ u\\left(c\\right) $ to a new function by  (i)  flipping the  sign,  and (ii) increasing curvature in proportion to $ \\theta $.\n",
    "\n",
    "In the left panel, the red line is our tool for computing  the mathematical expectation for different\n",
    "values  of $ \\pi $.\n",
    "\n",
    "The green lot indicates the mathematical expectation of $ \\exp\\left(\\frac{-u\\left(c\\right)}{\\theta}\\right) $\n",
    "when $ \\pi = .5 $.\n",
    "\n",
    "Notice that the distance between the green dot  and the curve is greater in the transformed space than the original space as a result of additional curvature.\n",
    "\n",
    "The inverse transformation  $ \\theta\\log E\\left[\\exp\\left(\\frac{-u\\left(c\\right)}{\\theta}\\right)\\right] $ generates  the green dot on the left panel that constitutes the risk-sensitive utility  index.\n",
    "\n",
    "The gap between the green dot and the red line on the left panel measures the additional adjustment for risk\n",
    "that risk-sensitive preferences make relative to plain vanilla expected utility preferences."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31118945",
   "metadata": {},
   "source": [
    "### Digression on moment generating functions\n",
    "\n",
    "The risk-sensitivity operator $ {\\sf T} $ is intimately connected to a moment generating function.\n",
    "\n",
    "In particular, a principal constinuent of the $ {\\sf T} $ operator, namely,\n",
    "\n",
    "$$\n",
    "E \\exp\\bigl(-u(c_i)/\\theta\\bigr) = \\sum_{i=1}^I \\pi_i \\exp\\bigl(- u(c_i)/\\theta  \\bigr)\n",
    "$$\n",
    "\n",
    "is evidently a **moment generating function** for the random variable $ u(c_i) $, while\n",
    "\n",
    "$$\n",
    "g(\\theta^{-1}) \\doteq  \\log \\sum_{i=1}^I \\pi_i \\exp\\bigl(- u(c_i)/\\theta  \\bigr)\n",
    "$$\n",
    "\n",
    "is a **cumulant generating function**,\n",
    "\n",
    "$$\n",
    "g(\\theta^{-1}) = \\sum_{j=1}^\\infty \\kappa_j \\frac{{(-\\theta^{-1})}^{j}}{j!}.\n",
    "$$\n",
    "\n",
    "where $ \\kappa_j $ is the $ j $th cumulant of the random variable $ u(c) $.\n",
    "\n",
    "Then\n",
    "\n",
    "$$\n",
    "{\\sf T}u(c) = -\\theta g(\\theta^{-1}) = -\\theta \\sum_{j=1}^\\infty \\kappa_j \\frac{{(-\\theta^{-1})}^{j}}{j!}.\n",
    "$$\n",
    "\n",
    "In general, when $ \\theta < +\\infty $, $ {\\sf T} u(c) $ depends on cumulants of all orders.\n",
    "\n",
    "These statements extend to cases with continuous probability distributions for $ c $ and therefore for $ u(c) $.\n",
    "\n",
    "For the special case $ u(c) \\sim {\\mathcal N}(\\mu_u, \\sigma_u^2) $, $ \\kappa_1 = \\mu_u, \\kappa_2 = \\sigma_u^2, $  and $ \\kappa_j = 0 \\ \\forall j \\geq 3 $, so\n",
    "\n",
    "\n",
    "<a id='equation-tom200'></a>\n",
    "$$\n",
    "{\\sf T} u(c) = \\mu_u - \\frac{1}{2 \\theta} \\sigma_u^2, \\tag{25.16}\n",
    "$$\n",
    "\n",
    "which becomes expected utility $ \\mu_u $ when $ \\theta^{-1} = 0 $.\n",
    "\n",
    "The right side of equation [(25.16)](#equation-tom200) is a special case of **stochastic differential utility** preferences in which consumption plans are ranked not just by their expected utilities $ \\mu_u $ but also the variances $ \\sigma_u^2 $  of their expected utilities."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e581173a",
   "metadata": {},
   "source": [
    "## Ex post Bayesian preferences\n",
    "\n",
    "A decision maker is said to have **ex post Bayesian preferences** when he ranks consumption plans according to the expected utility function\n",
    "\n",
    "\n",
    "<a id='equation-tom15'></a>\n",
    "$$\n",
    "\\sum_i \\hat \\pi_i (c^*) u(c_i) \\tag{25.17}\n",
    "$$\n",
    "\n",
    "where $ \\hat \\pi(c^*) $ is the worst-case probability distribution associated with multiplier or constraint preferences evaluated at a particular consumption plan $ c^* = \\{c_i^*\\}_{i=1}^I $.\n",
    "\n",
    "At $ c^* $, an ex post Bayesian’s indifference curves are tangent to those for multiplier and constraint preferences with appropriately chosen $ \\theta $ and $ \\eta $, respectively."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c026916",
   "metadata": {},
   "source": [
    "## Comparing preferences\n",
    "\n",
    "For the special case in which $ I=2 $, $ c_1=2, c_2=1 $, $ u(c) = \\ln c $, and\n",
    "$ \\pi_1 =.5 $, the following two figures depict how worst-case\n",
    "probabilities are determined under  constraint and multiplier preferences, respectively.\n",
    "\n",
    "The first figure  graphs entropy as a function of $ \\hat \\pi_1 $.\n",
    "\n",
    "It also plots expected utility under the twisted probability distribution, namely,\n",
    "$ \\hat E u(c) = u(c_2) + \\hat \\pi_1 (u(c_1) - u(c_2)) $, which is\n",
    "evidently a linear function of $ \\hat \\pi_1 $.\n",
    "\n",
    "The entropy constraint  $ \\sum_{i=1}^I \\pi_i m_i \\log m_i \\leq \\eta $ implies a convex set\n",
    "$ \\hat \\Pi_1 $ of $ \\hat \\pi_1 $’s that constrains the adversary who chooses $ \\hat \\pi_1 $, namely, the set of $ \\hat \\pi_1 $’s for which the\n",
    "entropy curve lies below the horizontal dotted line at an entropy level of $ \\eta = .25 $.\n",
    "\n",
    "Unless $ u(c_1) = u(c_2) $, the $ \\hat \\pi_1 $ that minimizes $ \\hat E u(c) $ is at the boundary of the set $ \\hat \\Pi_1 $."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5e1e04e8",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Parameter \n",
    "η = 0.25\n",
    "π = np.array([0.5, 0.5])\n",
    "c_bundle = np.array([2., 1.])  # Consumption bundle\n",
    "\n",
    "# Create η array for putting an upper bound on entropy values\n",
    "η_line = np.ones_like(π_hat_0_vals.size) * η\n",
    "\n",
    "# Initialize array for storing values for \\hat{E}[u(c)]\n",
    "E_hat_uc = np.empty(π_hat_0_vals.size)\n",
    "\n",
    "for i in range(π_hat_0_vals.size):  # Loop over π_hat_0\n",
    "    # Compute and store \\hat{E}[u(c)]\n",
    "    E_hat_uc[i] = u(c_bundle[1]) + π_hat_0_vals[i] * (u(c_bundle[0]) - u(c_bundle[1]))\n",
    "\n",
    "# Set up a root finding problem to find the solution to the constraint problem\n",
    "# First argument to `root_scalar` is a function that takes a value for π_hat_0 and returns \n",
    "# the entropy of π_hat wrt π minus η\n",
    "root = optimize.root_scalar(lambda x: ent(π, np.array([x, 1-x])) - η, bracket=[1e-4, 0.5]).root"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "26ce318d",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(12, 8))\n",
    "plt.plot(π_hat_0_vals, E_hat_uc, label=r'$\\hat{E}u\\left(c\\right)$', color='blue')\n",
    "plt.fill_between(π_hat_0_vals, η_line, alpha=0.3, label=r'$\\mathrm{ent}\\left(\\pi,\\hat{\\pi}\\right)\\leq\\eta$',\n",
    "                 color='gray',\n",
    "                 linewidth=0.0)\n",
    "plt.plot(π_hat_0_vals, ent_vals, label=r'$\\mathrm{ent}\\left(\\pi,\\hat{\\pi}\\right)$', color='red')\n",
    "plt.plot(root, η, 'o', color='black', label='constraint problem solution')\n",
    "plt.xlabel(r'$\\hat{\\pi}_1$');\n",
    "plt.legend();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2fbf8c3",
   "metadata": {},
   "source": [
    "The next  figure shows the function $ \\sum_{i=1}^I \\pi_i m_i [  u(c_i) + \\theta \\log m_i ] $ that is to be\n",
    "minimized in the multiplier problem.\n",
    "\n",
    "The argument of the function is  $ \\hat \\pi_1 = m_1 \\pi_1 $."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e732dfeb",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Parameter values\n",
    "θ_vals = np.array([0.42, 1.])\n",
    "\n",
    "# Initialize values for storing the multiplier criterion values\n",
    "multi_crit_vals = np.empty((θ_vals.size, π_hat_0_vals.size))\n",
    "\n",
    "for i in range(θ_vals.size):  # Loop over θ values\n",
    "    for j in range(π_hat_0_vals.size):  # Loop over π_hat_0 values\n",
    "        # Update `π_hat` values\n",
    "        π_hat[0] = π_hat_0_vals[j]\n",
    "        π_hat[1] = 1 - π_hat_0_vals[j]\n",
    "        \n",
    "        # Compute distorting measure\n",
    "        m_i = π_hat / π\n",
    "        \n",
    "        # Compute and store multiplier criterion objective value\n",
    "        multi_crit_vals[i, j] = np.sum(π_hat * (u(c_bundle) + θ_vals[i] * np.log(m_i)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fda10efc",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(12, 8))\n",
    "\n",
    "# Expected utility values\n",
    "plt.plot(π_hat_0_vals, E_hat_uc, label=r'$\\hat{E}u\\left(c\\right)$', color='blue')\n",
    "\n",
    "# First multiplier criterion objective values\n",
    "plt.plot(π_hat_0_vals, multi_crit_vals[0],\n",
    "         label=r'$\\sum_{i=1}^{I}\\pi_{i}m_{i}\\left[u\\left(c_{i}\\right)+0.42\\log\\left(m_{i}\\right)\\right]$',\n",
    "         color='green')\n",
    "\n",
    "# Second multiplier criterion objective values\n",
    "plt.plot(π_hat_0_vals, multi_crit_vals[1],\n",
    "         label=r'$\\sum_{i=1}^{I}\\pi_{i}m_{i}\\left[u\\left(c_{i}\\right)+\\log\\left(m_{i}\\right)\\right]$',\n",
    "         color='purple')\n",
    "\n",
    "# Entropy values\n",
    "plt.plot(π_hat_0_vals, ent_vals, label=r'$\\mathrm{ent}\\left(\\pi,\\hat{\\pi}\\right)$', color='red')\n",
    "\n",
    "# Area fill\n",
    "plt.fill_between(π_hat_0_vals, η_line, alpha=0.3, label=r'$\\mathrm{ent}\\left(\\pi,\\hat{\\pi}\\right)\\leq\\eta$', color='gray')\n",
    "\n",
    "# Problem solution dots\n",
    "plt.plot(root, η, 'o', color='black', label='constraint problem solution')\n",
    "plt.plot(π_hat_0_vals[multi_crit_vals[0].argmin()], multi_crit_vals[0].min(), 'o', label='multiplier problem solution', color='darkred')\n",
    "plt.plot(π_hat_0_vals[multi_crit_vals[1].argmin()], multi_crit_vals[1].min(), 'o', color='darkred')\n",
    "\n",
    "plt.xlabel(r'$\\hat{\\pi}_1$');\n",
    "plt.legend();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "acf41998",
   "metadata": {},
   "source": [
    "Evidently, from this figure and also from formula [(25.12)](#equation-tom12), lower values of $ \\theta $ lead to lower,\n",
    "and thus more distorted, minimizing values of $ \\hat \\pi_1 $.\n",
    "\n",
    "The figure\n",
    "indicates how one can construct a Lagrange multiplier $ \\tilde \\theta $\n",
    "associated with a given entropy constraint $ \\eta $ and a given\n",
    "consumption plan.\n",
    "\n",
    "Thus, to draw the figure, we set the penalty parameter for\n",
    "multiplier preferences $ \\theta $ so that the minimizing $ \\hat \\pi_1 $\n",
    "equals the minimizing $ \\hat \\pi_1 $ for the constraint problem from\n",
    "the previous figure.\n",
    "\n",
    "The penalty parameter $ \\theta=.42 $ also equals the\n",
    "Lagrange multiplier $ \\tilde \\theta $ on the entropy constraint for the\n",
    "constraint preferences depicted in the previous figure\n",
    "because the $ \\hat \\pi_1 $ that minimizes the\n",
    "asymmetric curve associated with penalty parameter $ \\theta=.42 $ is the\n",
    "same $ \\hat \\pi_1 $ associated with the intersection of the entropy curve\n",
    "and the entropy constraint dashed vertical\n",
    "line."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3bc2808e",
   "metadata": {},
   "source": [
    "## Risk aversion and misspecification aversion\n",
    "\n",
    "All five types of preferences use curvature of $ u $ to express risk\n",
    "aversion.\n",
    "\n",
    "Constraint preferences express **concern about misspecification** or **ambiguity** for short with a positive\n",
    "$ \\eta $ that circumscribes an entropy ball around an approximating\n",
    "probability distribution $ \\pi $, and *aversion aversion to model misspecification* through\n",
    "minimization with respect to a likelihood ratio $ m $.\n",
    "\n",
    "Multiplier preferences express misspecification concerns with a parameter $ \\theta<+\\infty $ that\n",
    "penalizes deviations from the approximating model as measured by\n",
    "relative entropy, and they express  aversion to misspecification  concerns with minimization\n",
    "over a probability distortion $ m $.\n",
    "\n",
    "By penalizing minimization over the\n",
    "likelihood ratio $ m $, a decrease in $ \\theta $ represents an **increase** in\n",
    "ambiguity (or what [[Knight, 1921](https://python-advanced.quantecon.org/zreferences.html#id11)] called uncertainty) about the specification of the baseline\n",
    "approximating model $ \\{\\pi_i\\}_{i=1}^I $.\n",
    "\n",
    "Formulas [(25.6)](#equation-tom6)  assert that the decision maker acts as if\n",
    "he is pessimistic relative to an approximating model $ \\pi $.\n",
    "\n",
    "It expresses what [[Bucklew, 2004](https://python-advanced.quantecon.org/zreferences.html#id10)] [p. 27] calls a statistical version of *Murphy’s law*:\n",
    "\n",
    "**$ \\quad \\quad $ The probability of anything happening is in inverse ratio to its desirability.**\n",
    "\n",
    "The minimizing likelihood ratio $ \\hat m $ slants worst-case probabilities\n",
    "$ \\hat \\pi $ exponentially to increase probabilities of events that give\n",
    "lower utilities.\n",
    "\n",
    "As expressed by the value function bound [(25.19)](#equation-eqn-bound1) to be displayed below, the decision maker uses **pessimism** instrumentally to protect himself against model misspecification.\n",
    "\n",
    "The penalty parameter $ \\theta $ for multipler preferences or the entropy level $ \\eta $ that determines the\n",
    "Lagrange multiplier $ \\tilde \\theta $ for constraint  preferences controls how adversely the decision maker exponentially slants probabilities.\n",
    "\n",
    "A decision rule is said to be **undominated** in the sense of Bayesian\n",
    "decision theory if there exists a probability distribution $ \\pi $ for\n",
    "which it is optimal.\n",
    "\n",
    "A decision rule is said to be **admissible** if it is undominated.\n",
    "\n",
    "[[Hansen and Sargent, 2008](https://python-advanced.quantecon.org/zreferences.html#id160)] use ex post Bayesian preferences to show that robust\n",
    "decision rules are undominated and therefore admissible."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66c529da",
   "metadata": {},
   "source": [
    "## Indifference curves\n",
    "\n",
    "Indifference curves illuminate how concerns about robustness affect\n",
    "asset pricing and utility costs of fluctuations. For $ I=2 $, the slopes\n",
    "of the indifference curves for our five preference specifications are\n",
    "\n",
    "- Expected utility:  \n",
    "  $$\n",
    "  \\frac{d c_2}{d c_1} = - \\frac{\\pi_1}{\\pi_2}\\frac{u'(c_1)}{u'(c_2)}\n",
    "  $$\n",
    "- Constraint and ex post Bayesian preferences:  \n",
    "  $$\n",
    "  \\frac{d c_2}{d c_1} = - \\frac{\\hat \\pi_1}{\\hat \\pi_2}\\frac{u'(c_1)}{u'(c_2)}\n",
    "  $$\n",
    "  where $ \\hat \\pi_1, \\hat \\pi_2 $ are the minimizing probabilities\n",
    "  computed from the worst-case distortions [(25.6)](#equation-tom6) from the constraint problem at  $ (c_1, c_2) $.  \n",
    "- Multiplier and risk-sensitive preferences:  \n",
    "  $$\n",
    "  \\frac{d c_2}{d c_1} = - \\frac{\\pi_1}{\\pi_2} \\frac{\\exp(- u(c_1)/\\theta)}{\\exp (- u(c_2)/\\theta)}    \\frac{u'(c_1)}{u'(c_2)}\n",
    "  $$\n",
    "\n",
    "\n",
    "When $ c_1 > c_2 $, the exponential twisting formula [(25.12)](#equation-tom12)\n",
    "implies that $ \\hat \\pi_1 < \\pi_1 $, which in\n",
    "turn implies that the indifference curves through $ (c_1, c_2) $ for both\n",
    "constraint and multiplier preferences are flatter than the indifference\n",
    "curve associated with expected utility preferences.\n",
    "\n",
    "As we shall see soon when we discuss state price\n",
    "deflators, this gives rise to higher estimates of prices of risk.\n",
    "\n",
    "For an example with $ u(c) = \\ln c $, $ I=2 $, and $ \\pi_1 = .5 $, the next two  figures show indifference curves for expected\n",
    "utility, multiplier, and constraint preferences.\n",
    "\n",
    "The following figure shows indifference curves going through a\n",
    "point along the 45 degree line."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ddfd3ed2",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "def multiplier_criterion_factory(θ, π, u):\n",
    "    \"\"\"\n",
    "    Return a function to compute the multiplier preferences objective function parametrized \n",
    "    by a penalty parameter `θ`, a probability vector `π` and a utility function `u`\n",
    "    \n",
    "    \"\"\"\n",
    "    def criterion(c_1, c_2, return_entropy=False):\n",
    "        \"\"\"\n",
    "        Compute the multiplier preferences objective function and\n",
    "        associated entropy level if return_entropy=True for a\n",
    "        consumption bundle (c_1, c_2).\n",
    "        \n",
    "        \"\"\"\n",
    "        # Compute the distorting measure\n",
    "        m = compute_change_measure(u, np.array([c_1, c_2]), θ, π)\n",
    "        \n",
    "        # Compute objective value\n",
    "        obj = π[0] * m[0] * (u(c_1) + θ * np.log(m[0])) + π[1] * m[1] * (u(c_2) + θ * np.log(m[1]))\n",
    "        \n",
    "        if return_entropy:        \n",
    "            # Compute associated entropy value\n",
    "            π_hat = np.array([π[0] * m[0], π[1] * m[1]])\n",
    "            ent_val = ent(π, π_hat)\n",
    "        \n",
    "            return ent_val\n",
    "        \n",
    "        else:\n",
    "            return obj\n",
    "    \n",
    "    return criterion\n",
    "\n",
    "\n",
    "def constraint_criterion_factory(η, π, u):\n",
    "    \"\"\"\n",
    "    Return a function to compute the constraint preferences objective function parametrized \n",
    "    by a penalty parameter `η`, a probability vector `π` and a utility function `u`\n",
    "    \n",
    "    \"\"\"\n",
    "    \n",
    "    def inner_root_problem(θ_tilde, c_1, c_2):\n",
    "        \"\"\"\n",
    "        Inner root problem associated with the constraint preferences objective function. \n",
    "        \n",
    "        \"\"\"\n",
    "        # Compute the change of measure\n",
    "        m = compute_change_measure(u, np.array([c_1, c_2]), θ_tilde, π)\n",
    "            \n",
    "        # Compute the associated entropy value\n",
    "        π_hat = np.array([π[0] * m[0], π[1] * m[1]])\n",
    "        ent_val = ent(π, π_hat)\n",
    "        \n",
    "        # Compute the error\n",
    "        Δ = ent_val - η\n",
    "        \n",
    "        return ent_val - η\n",
    "    \n",
    "    def criterion(c_1, c_2, return_θ_tilde=False):\n",
    "        try:\n",
    "            # Solve for the Lagrange multiplier\n",
    "            res = optimize.root_scalar(inner_root_problem, args=(c_1, c_2), bracket=[3e-3, 10.], method='bisect')\n",
    "            \n",
    "            if res.converged:\n",
    "                θ_tilde = res.root\n",
    "\n",
    "                # Compute change of measure\n",
    "                m = compute_change_measure(u, np.array([c_1, c_2]), θ_tilde, π)\n",
    "\n",
    "                obj = π[0] * m[0] * u(c_1) + π[1] * m[1] * u(c_2)\n",
    "\n",
    "                if return_θ_tilde: \n",
    "                    return θ_tilde\n",
    "\n",
    "                else: \n",
    "                    return obj\n",
    "\n",
    "            else: \n",
    "                return np.nan\n",
    "            \n",
    "        except: \n",
    "            return np.nan\n",
    "        \n",
    "    return criterion\n",
    "\n",
    "\n",
    "def solve_root_problem(problem, u_bar, c_1_grid, method='bisect', bracket=[0.5, 3.]):\n",
    "    \"\"\"\n",
    "    Solve root finding problem `problem` for all values in `c_1_grid` taking `u_bar` as\n",
    "    given and using `method`.\n",
    "    \n",
    "    \"\"\"\n",
    "    \n",
    "    # Initialize array to be filled with c_2 values\n",
    "    c_2_grid = np.empty(c_1_grid.size)\n",
    "    \n",
    "    for i in range(c_1_grid.size):  # Loop over c_1 values\n",
    "        c_1 = c_1_grid[i]\n",
    "        \n",
    "        try: \n",
    "            # Solve root problem given c_1 and u_bar\n",
    "            res = optimize.root_scalar(problem, args=(c_1, u_bar), bracket=bracket, method=method)\n",
    "\n",
    "            if res.converged:  # Store values if successfully converged\n",
    "                c_2_grid[i] = res.root\n",
    "            else:  # Store np.nan otherwise\n",
    "                c_2_grid[i] = np.nan\n",
    "                \n",
    "        except:\n",
    "            c_2_grid[i] = np.nan\n",
    "            \n",
    "    return c_2_grid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "42303e90",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Parameters\n",
    "c_bundle = np.array([1., 1.])  # Consumption bundle\n",
    "u_inv = lambda x: np.exp(x)  # Inverse of the utility function\n",
    "θ = 1.\n",
    "η = 0.12\n",
    "\n",
    "\n",
    "# Conustruct grid for c_1\n",
    "c_1_grid_nb = 102\n",
    "c_1_grid = np.linspace(0.5, 2., num=c_1_grid_nb)\n",
    "\n",
    "# Compute \\bar{u}\n",
    "u_bar = u(c_bundle) @ π\n",
    "\n",
    "# Compute c_2 values for the expected utility case\n",
    "c_2_grid_EU = u_inv((u_bar - u(c_1_grid) * π[0]) / π[1])\n",
    "\n",
    "# Compute c_2 values for the multiplier preferences case\n",
    "multi_pref_crit = multiplier_criterion_factory(θ, π, u)  # Create criterion\n",
    "multi_pref_root_problem = lambda c_2, c_1, u_bar: u_bar - multi_pref_crit(c_1, c_2)  # Formulate root problem\n",
    "c_2_grid_mult = solve_root_problem(multi_pref_root_problem, u_bar, c_1_grid)  # Solve root problem for all c_1 values\n",
    "\n",
    "# Compute c_2 values for the constraint preferences case\n",
    "constraint_pref_crit = constraint_criterion_factory(η, π, u)  # Create criterion\n",
    "constraint_pref_root_problem = lambda c_2, c_1, u_bar: u_bar - constraint_pref_crit(c_1, c_2)  # Formulate root problem\n",
    "# Solve root problem for all c_1 values\n",
    "c_2_grid_cons = solve_root_problem(constraint_pref_root_problem, u_bar, c_1_grid, method='bisect', bracket=[0.5, 2.5])  \n",
    "\n",
    "# Compute associated η and θ values\n",
    "ηs = np.empty(c_1_grid.size)\n",
    "θs = np.empty(c_1_grid.size)\n",
    "\n",
    "for i in range(c_1_grid.size):\n",
    "    ηs[i] = multi_pref_crit(c_1_grid[i], c_2_grid_mult[i], return_entropy=True)\n",
    "    θs[i] = constraint_pref_crit(c_1_grid[i], c_2_grid_cons[i], return_θ_tilde=True)\n",
    "    \n",
    "θs[~np.isfinite(c_2_grid_cons)] = np.nan"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f10e1f7",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "f, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8), sharex=True)\n",
    "\n",
    "ax1.plot(c_1_grid, c_1_grid, '--', color='black')\n",
    "ax1.plot(c_1_grid, c_2_grid_EU, label='Expected Utility', color='blue')\n",
    "ax1.plot(c_1_grid, c_2_grid_mult, label='Multiplier Preferences', color='red')\n",
    "ax1.plot(c_1_grid, c_2_grid_cons, label='Constraint Preferences', color='green')\n",
    "ax1.plot(1., 1., 'o', color='black')\n",
    "ax1.set_xlabel(r'$c_1$')\n",
    "ax1.set_ylabel(r'$c_2$')\n",
    "ax1.annotate('(1, 1)', (1-0.16, 1-0.02))\n",
    "ax1.set_ylim(0.5, 2.)\n",
    "ax1.set_xlim(0.5, 2.)\n",
    "ax1.legend();\n",
    "\n",
    "ax2.plot(c_1_grid, ηs, label=r'$\\eta^{*}$', color='red')\n",
    "ax2.plot(c_1_grid, θs, label=r'$\\theta^{*}$', color='green')\n",
    "ax2.set_xlabel(r'$c_1$')\n",
    "ax2.legend();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84b1ae21",
   "metadata": {},
   "source": [
    "**Kink at 45 degree line**\n",
    "\n",
    "Notice the kink in the indifference curve for constraint  preferences at the 45 degree line.\n",
    "\n",
    "To understand the source of the kink, consider how the Lagrange multiplier and worst-case probabilities vary with the consumption plan under  constraint preferences.\n",
    "\n",
    "For fixed $ \\eta $, a given plan $ c $, and a utility function increasing in $ c $,  worst case probabilities are **fixed numbers** $ \\hat \\pi_1 < .5 $ when $ c_1 > c_2 $ and $ \\hat \\pi_1 > .5 $ when\n",
    "$ c_2 > c_1 $.\n",
    "\n",
    "This pattern makes the Lagrange multiplier $ \\tilde \\theta $ vary discontinuously at $ \\hat \\pi_1 = .5 $.\n",
    "\n",
    "The  discontinuity in the worst case $ \\hat \\pi_1 $ at the 45 degree line accounts for the kink at the 45 degree line in an indifference curve for constraint preferences associated with a given positive entropy constraint $ \\eta $.\n",
    "\n",
    "The code for generating the preceding figure is somewhat intricate we formulate a root finding problem for finding indifference curves.\n",
    "\n",
    "Here is a brief literary  description of the method we use.\n",
    "\n",
    "**Parameters**\n",
    "\n",
    "- Consumption bundle $ c=\\left(1,1\\right) $  \n",
    "- Penalty parameter $ θ=2 $  \n",
    "- Utility function $ u=\\log $  \n",
    "- Probability vector $ \\pi=\\left(0.5,0.5\\right) $  \n",
    "\n",
    "\n",
    "**Algorithm:**\n",
    "\n",
    "- Compute $ \\bar{u}=\\pi_{1}u\\left(c_{1}\\right)+\\pi_{2}u\\left(c_{2}\\right) $  \n",
    "- Given values for $ c_{1} $, solve for values of $ c_{2} $ such that $ \\bar{u}=u\\left(c_{1},c_{2}\\right) $:  \n",
    "  - Expected utility: $ c_{2,EU}=u^{-1}\\left(\\frac{\\bar{u}-\\pi_{1}u\\left(c_{1}\\right)}{\\pi_{2}}\\right) $  \n",
    "  - Multiplier preferences: solve $ \\bar{u}-\\sum_{i}\\pi_{i}\\frac{\\exp\\left(\\frac{-u\\left(c_{i}\\right)}{\\theta}\\right)}{\\sum_{j}\\exp\\left(\\frac{-u\\left(c_{j}\\right)}{\\theta}\\right)}\\left(u\\left(c_{i}\\right)+\\theta\\log\\left(\\frac{\\exp\\left(\\frac{-u\\left(c_{i}\\right)}{\\theta}\\right)}{\\sum_{j}\\exp\\left(\\frac{-u\\left(c_{j}\\right)}{\\theta}\\right)}\\right)\\right)=0 $ numerically  \n",
    "  - Constraint preference: solve $ \\bar{u}-\\sum_{i}\\pi_{i}\\frac{\\exp\\left(\\frac{-u\\left(c_{i}\\right)}{\\theta^{*}}\\right)}{\\sum_{j}\\exp\\left(\\frac{-u\\left(c_{j}\\right)}{\\theta^{*}}\\right)}u\\left(c_{i}\\right)=0 $ numerically where $ \\theta^{*} $ solves $ \\sum_{i}\\pi_{i}\\frac{\\exp\\left(\\frac{-u\\left(c_{i}\\right)}{\\theta^{*}}\\right)}{\\sum_{j}\\exp\\left(\\frac{-u\\left(c_{j}\\right)}{\\theta^{*}}\\right)}\\log\\left(\\frac{\\exp\\left(\\frac{-u\\left(c_{i}\\right)}{\\theta^{*}}\\right)}{\\sum_{j}\\exp\\left(\\frac{-u\\left(c_{j}\\right)}{\\theta^{*}}\\right)}\\right)-\\eta=0 $ numerically.  \n",
    "\n",
    "\n",
    "**Remark:** It seems that the constraint problem is hard to solve in its original form, i.e. by finding the distorting measure that minimizes the expected utility.\n",
    "\n",
    "It seems that viewing equation [(25.7)](#equation-tom7) as a root finding problem works much better.\n",
    "\n",
    "But notice that  equation [(25.7)](#equation-tom7) does not always have a solution.\n",
    "\n",
    "Under $ u=\\log $, $ c_{1}=c_{2}=1 $, we have:\n",
    "\n",
    "$$\n",
    "\\sum_{i}\\pi_{i}\\frac{\\exp\\left(\\frac{-u\\left(c_{i}\\right)}{\\tilde{\\theta}}\\right)}{\\sum_{j}\\pi_{j}\\exp\\left(\\frac{-u\\left(c_{j}\\right)}{\\tilde{\\theta}}\\right)}\\log\\left(\\frac{\\exp\\left(\\frac{-u\\left(c_{i}\\right)}{\\tilde{\\theta}}\\right)}{\\sum_{j}\\pi_{j}\\exp\\left(\\frac{-u\\left(c_{j}\\right)}{\\tilde{\\theta}}\\right)}\\right)=0\n",
    "$$\n",
    "\n",
    "**Conjecture:** when our numerical  method fails it  because the derivative of the objective doesn’t exist for our choice of  parameters.\n",
    "\n",
    "**Remark:** It is tricky to get the algorithm  to work properly for all values of $ c_{1} $. In particular, parameters were chosen with [graduate student descent](https://sciencedryad.wordpress.com/2014/01/25/grad-student-descent/).\n",
    "\n",
    "**Tangent indifference curves off 45 degree line**\n",
    "\n",
    "For a given $ \\eta $ and a given allocatin $ (c_1, c_2) $ off the 45 degree line, by solving\n",
    "equations [(25.7)](#equation-tom7) and [(25.13)](#equation-tom20), we can find $ \\tilde \\theta (\\eta, c) $\n",
    "and $ \\tilde \\eta(\\theta,c) $ that make indifference curves for\n",
    "multiplier and constraint preferences be tangent to one another.\n",
    "\n",
    "The following figure shows indifference curves for\n",
    "multiplier and constraint preferences through a point off the 45 degree\n",
    "line, namely, $ (c(1),c(2)) = (3,1) $, at which $ \\eta $ and $ \\theta $ are\n",
    "adjusted to render the indifference curves for constraint and multiplier\n",
    "preferences tangent."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4adc32f0",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Parameters\n",
    "θ = 2.\n",
    "η = 0.036\n",
    "c_bundle = np.array([3., 1.])\n",
    "\n",
    "# Conustruct grid for c_1\n",
    "c_1_grid_num = 101\n",
    "c_1_grid = np.linspace(0.5, 4., num=c_1_grid_num)\n",
    "\n",
    "# Compute u_bar\n",
    "u_bar = u(c_bundle) @ π\n",
    "\n",
    "# Compute c_2 values for the expected utility case\n",
    "c_2_grid_EU = u_inv((u_bar - u(c_1_grid) * π[0]) / π[1])\n",
    "\n",
    "# Compute c_2 values for the multiplier preferences case\n",
    "multi_pref_crit = multiplier_criterion_factory(θ, π, u)  # Create criterion\n",
    "multi_crit_bar = multi_pref_crit(*c_bundle)  # Evaluate criterion at consumption bundle\n",
    "multi_pref_root_problem = lambda c_2, c_1, u_bar: u_bar - multi_pref_crit(c_1, c_2)  # Formulate root problem\n",
    "# Solve root problem for all c_1 values\n",
    "c_2_grid_mult = solve_root_problem(multi_pref_root_problem, multi_crit_bar, c_1_grid, bracket=[1e-5, 5.])  \n",
    "\n",
    "# Compute c_2 values for the constraint preferences case\n",
    "constraint_pref_crit = constraint_criterion_factory(η, π, u)  # Create criterion\n",
    "cons_crit_bar = constraint_pref_crit(*c_bundle)  # Evaluate criterion at consumption bundle\n",
    "constraint_pref_root_problem = lambda c_2, c_1, u_bar: u_bar - constraint_pref_crit(c_1, c_2)  # Formulate root problem\n",
    "# Solve root problem for all c_1 values\n",
    "c_2_grid_cons = solve_root_problem(constraint_pref_root_problem, cons_crit_bar, c_1_grid, method='bisect', bracket=[0.47, 4.5])  \n",
    "\n",
    "# Compute associated η and θ values\n",
    "ηs = np.empty(c_1_grid.size)\n",
    "θs = np.empty(c_1_grid.size)\n",
    "\n",
    "for i in range(c_1_grid.size):\n",
    "    ηs[i] = multi_pref_crit(c_1_grid[i], c_2_grid_mult[i], return_entropy=True)\n",
    "    θs[i] = constraint_pref_crit(c_1_grid[i], c_2_grid_cons[i], return_θ_tilde=True)\n",
    "    \n",
    "θs[~np.isfinite(c_2_grid_cons)] = np.nan"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "16132b34",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "f, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8), sharex=True)\n",
    "\n",
    "ax1.plot(c_1_grid, c_1_grid, '--', color='black')\n",
    "ax1.plot(c_1_grid, c_2_grid_EU, label='Expected Utility', color='blue')\n",
    "ax1.plot(c_1_grid, c_2_grid_mult, label='Multiplier Preferences', color='red')\n",
    "ax1.plot(c_1_grid, c_2_grid_cons, label='Constraint Preferences', color='green')\n",
    "ax1.plot(3., 1., 'o', color='black')\n",
    "ax1.set_xlabel(r'$c_1$')\n",
    "ax1.set_ylabel(r'$c_2$')\n",
    "ax1.annotate('(3, 1)', (3, 1+0.07))\n",
    "ax1.set_ylim(0.75, 4.)\n",
    "ax1.set_xlim(0.75, 4.)\n",
    "ax1.legend();\n",
    "\n",
    "ax2.plot(c_1_grid, ηs, label=r'$\\eta^{*}$', color='red')\n",
    "ax2.plot(c_1_grid, θs, label=r'$\\theta^{*}$', color='green')\n",
    "ax2.set_xlabel(r'$c_1$')\n",
    "ax2.legend();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5f02a52",
   "metadata": {},
   "source": [
    "Note that all three lines of the left graph intersect at (1, 3). While the intersection at (3, 1) is hard-coded, the intersection at (1,3) arises from the computation,  which confirms that the code seems to be\n",
    "working properly.\n",
    "\n",
    "As we move along the (kinked) indifference curve for the constraint\n",
    "preferences for a given $ \\eta $, the worst-case probabilities remain\n",
    "constant, but the Lagrange multiplier $ \\tilde \\theta $ on the entropy\n",
    "constraint $ \\sum_{i=1}^I m_i \\log m_i \\leq \\eta $ varies with\n",
    "$ (c_1, c_2) $.\n",
    "\n",
    "As we move along the (smooth) indifference curve for the\n",
    "multiplier preferences for a given penalty parameter $ \\theta $, the\n",
    "implied entropy $ \\tilde \\eta $ from equation [(25.13)](#equation-tom20) and the worst-case probabilities both\n",
    "change with $ (c_1, c_2) $.\n",
    "\n",
    "For constraint preferences, there is a kink in the indifference curve.\n",
    "\n",
    "For ex post Bayesian preferences, there are effectively two sets of indifference curves depending on which\n",
    "side of the 45 degree line the $ (c_1, c_2) $ endowment point sits.\n",
    "\n",
    "There are two sets of indifference curves because, while the worst-case\n",
    "probabilities differ above and below the 45 degree line, the idea of ex\n",
    "post Bayesian preferences is to use a *single* probability distribution\n",
    "to compute expected utilities for all consumption bundles.\n",
    "\n",
    "Indifference curves through point $ (c_1, c_2) = (3,1) $ for expected\n",
    "logarithmic utility (less curved smooth line), multiplier (more curved\n",
    "line), constraint (solid line kinked at 45 degree line), and *ex post*\n",
    "Bayesian (dotted lines) preferences. The worst-case probability\n",
    "$ \\hat \\pi_1 < .5 $ when $ c_1 =3 > c_2 =1 $ and $ \\hat \\pi_1 > .5 $ when\n",
    "$ c_1=1 < c_2 = 3 $."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e9952c98",
   "metadata": {},
   "source": [
    "## State price deflators\n",
    "\n",
    "Concerns about model uncertainty boost prices of risk that are embedded\n",
    "in state-price deflators. With complete markets, let $ q_i $ be the price\n",
    "of consumption in state $ i $.\n",
    "\n",
    "The budget set of a representative consumer\n",
    "having endowment $ \\bar c = \\{\\bar c_i\\}_{i=1}^I $ is expressed by\n",
    "$ \\sum_{i}^I q_i (c_i - \\bar c_i) \\leq 0 $.\n",
    "\n",
    "When a representative consumer has multiplier preferences, the state prices are\n",
    "\n",
    "\n",
    "<a id='equation-eqn-state-price'></a>\n",
    "$$\n",
    "q_i = \\pi_i \\hat m_i u'(\\bar c_i) = \\pi_i \\Biggl(\\frac{\\exp(-u(\\bar c_i)/\\theta)}{\\sum_j  \\pi_j \\exp(-u(\\bar c_j)/\\theta)}\\Biggr) u'(\\bar c_i) . \\tag{25.18}\n",
    "$$\n",
    "\n",
    "The worst-case likelihood ratio $ \\hat m_i $ operates to increase prices\n",
    "$ q_i $ in relatively low utility states $ i $.\n",
    "\n",
    "State prices agree under multiplier and constraint preferences when $ \\eta $ and $ \\theta $ are\n",
    "adjusted according to [(25.7)](#equation-tom7) or [(25.13)](#equation-tom20) to make the indifference curves tangent\n",
    "at the endowment point.\n",
    "\n",
    "The next figure can help us think about state-price deflators under our different preference orderings.\n",
    "\n",
    "In this figure, budget line and indifference curves through point $ (c_1, c_2) = (3,1) $\n",
    "for expected logarithmic utility, multiplier, constraint (kinked at 45\n",
    "degree line), and *ex post* Bayesian (dotted lines) preferences.\n",
    "\n",
    "**Figure 2.7:**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d71d22f2",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Parameters\n",
    "θ = 2.\n",
    "η = 0.036\n",
    "c_bundle = np.array([3., 1.])\n",
    "u = utility_function_factory(1.)\n",
    "u_prime = lambda c: 1 / c  # Derivative of the utility function\n",
    "\n",
    "# Compute value of θ at c_1=3\n",
    "θ = np.interp(3., c_1_grid, θs)\n",
    "\n",
    "# Compute change of measure\n",
    "m = compute_change_measure(u, c_bundle, θ, π)\n",
    "\n",
    "# Compute budget constraint\n",
    "q = π * m * u_prime(c_bundle)\n",
    "endowment = (c_bundle * q).sum()\n",
    "intercept = endowment / q[1]\n",
    "slope = -q[0] / q[1]\n",
    "budget_constraint = slope * c_1_grid + intercept"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a14bcc41",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(10, 8))\n",
    "\n",
    "plt.plot(c_1_grid, c_1_grid, '--', color='black')\n",
    "plt.plot(c_1_grid, c_2_grid_mult, label='Multiplier Preferences', color='red')\n",
    "plt.plot(c_1_grid, c_2_grid_cons, label='Constraint Preferences', color='green')\n",
    "plt.plot(c_1_grid, budget_constraint, label='Budget Constraint', color='darkblue')\n",
    "plt.plot(3., 1., 'o', color='black')\n",
    "plt.xlabel(r'$c_1$')\n",
    "plt.ylabel(r'$c_2$')\n",
    "plt.annotate('(3, 1)', (3, 1+0.07))\n",
    "plt.ylim(0.75, 4.)\n",
    "plt.xlim(0.75, 4.)\n",
    "plt.legend();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eecd86d7",
   "metadata": {},
   "source": [
    "Because budget constraints are linear, asset prices are identical under\n",
    "multiplier and constraint preferences for which $ \\theta $ and $ \\eta $ are\n",
    "adjusted to verify [(25.7)](#equation-tom7) or [(25.13)](#equation-tom20) at a given consumption endowment\n",
    "$ \\{c_i\\}_{i=1}^I $.\n",
    "\n",
    "However, as we note next, though they are tangent at\n",
    "the endowment point, the fact that indifference curves differ for\n",
    "multiplier and constraint preferences means that certainty equivalent\n",
    "consumption compensations of the kind that [[Lucas, 1987](https://python-advanced.quantecon.org/zreferences.html#id105)],\n",
    "[[Hansen *et al.*, 1999](https://python-advanced.quantecon.org/zreferences.html#id16)], [[Tallarini, 2000](https://python-advanced.quantecon.org/zreferences.html#id104)], and [[Barillas *et al.*, 2009](https://python-advanced.quantecon.org/zreferences.html#id15)] used to measure the costs of\n",
    "business cycles must differ."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "916bb6c0",
   "metadata": {},
   "source": [
    "### Consumption-equivalent measures of uncertainty aversion\n",
    "\n",
    "For each of our five types of preferences, the following figure allows us to construct a certainty\n",
    "equivalent point $ (c^*, c^*) $ on the 45 degree line that renders the consumer indifferent between it and the risky point\n",
    "$ (c(1), c(2)) = (3,1) $.\n",
    "\n",
    "**Figure 2.8:**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "44ee16a3",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Compute values for the certainty equivalent line \n",
    "intercept = 4.  # Intercept value\n",
    "mask = (1. <= c_1_grid) & (c_1_grid <= 3.)  # Mask to keep only data between c_1=1 and c_1=3\n",
    "\n",
    "# Initialize array \n",
    "certainty_equiv = np.ones(c_1_grid.size) * np.nan\n",
    "\n",
    "# Fill relevant locations\n",
    "certainty_equiv[mask] = (intercept - c_1_grid)[mask]\n",
    "\n",
    "\n",
    "# Set up a fixed point problem to find intersections with x=x line\n",
    "# Function used to approximate indifference curves using linear interpolation\n",
    "func_approx = lambda c_1, fp: np.interp(c_1, c_1_grid, fp)  \n",
    "x0 = 2.  # Initial guess\n",
    "\n",
    "# Solve for fixed points\n",
    "fp_CE = optimize.fixed_point(func_approx, x0, args=([certainty_equiv]))\n",
    "fp_EU = optimize.fixed_point(func_approx, x0, args=([c_2_grid_EU]))\n",
    "fp_mult = optimize.fixed_point(func_approx, x0, args=([c_2_grid_mult]))\n",
    "fp_cons = optimize.fixed_point(func_approx, x0, args=([c_2_grid_cons]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7ae8aeff",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(8, 8))\n",
    "\n",
    "plt.plot(c_1_grid, c_1_grid, '--', color='black')\n",
    "plt.plot(c_1_grid, c_2_grid_EU, label='Expected Utility', color='blue')\n",
    "plt.plot(c_1_grid, c_2_grid_mult, label='Multiplier Preferences', color='red')\n",
    "plt.plot(c_1_grid, c_2_grid_cons, label='Constraint Preferences', color='green')\n",
    "plt.plot(c_1_grid, certainty_equiv, color='black')\n",
    "plt.plot(3., 1., 'o', color='black')\n",
    "plt.plot(1., 3., 'o', color='black')\n",
    "plt.xlabel(r'$c_1$')\n",
    "plt.ylabel(r'$c_2$')\n",
    "plt.annotate('(3, 1)', (3, 1+0.07))\n",
    "plt.annotate('(1, 3)', (1+0.02, 3+0.07))\n",
    "plt.ylim(0.75, 4.)\n",
    "plt.xlim(0.75, 4.)\n",
    "\n",
    "plt.plot(fp_CE, fp_CE, 'o')\n",
    "plt.plot(fp_EU, fp_EU, 'o')\n",
    "plt.plot(fp_mult, fp_mult, 'o')\n",
    "plt.plot(fp_cons, fp_cons, 'o')\n",
    "\n",
    "plt.annotate('A', (fp_CE-0.01, fp_CE+0.06))\n",
    "plt.annotate('B', (fp_EU-0.01, fp_EU+0.06))\n",
    "plt.annotate('C', (fp_mult-0.01, fp_mult+0.06))\n",
    "plt.annotate('D', (fp_cons-0.01, fp_cons+0.06))\n",
    "\n",
    "plt.legend();"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7db6afb8",
   "metadata": {},
   "source": [
    "The figure indicates that the certainty equivalent\n",
    "level $ c^* $ is higher for the consumer with expected utility preferences\n",
    "than for the consumer with multiplier preferences, and that it is higher\n",
    "for the consumer with multiplier preferences than for the consumer with\n",
    "constraint preferences.\n",
    "\n",
    "The gap between these certainty equivalents\n",
    "measures the uncertainty aversion of the multiplier preferences or\n",
    "constraint preferences consumer.\n",
    "\n",
    "The gap between the expected value\n",
    "$ .5 c(1) + .5 c(2) $ at point A and the certainty equivalent for the\n",
    "expected utility decision maker at point B is a measure of his risk\n",
    "aversion.\n",
    "\n",
    "The gap between points $ B $ and $ C $ measures the multiplier\n",
    "preference consumer’s aversion to model uncertainty.\n",
    "\n",
    "The gap between\n",
    "points B and D measures the constraint preference consumer’s aversion to\n",
    "model uncertainty."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8758f472",
   "metadata": {},
   "source": [
    "## Iso-utility and iso-entropy curves and expansion paths\n",
    "\n",
    "The following figures show iso-entropy and iso-utility lines for the special case in which $ I = 3 $, $ \\pi_1 = .3, \\pi_2 = .4 $, and the utility function is $ u(c)= \\frac{c^{1-\\alpha}}{1-\\alpha} $ with $ \\alpha =0 $ and $ \\alpha =3 $, respectively, for the fixed plan $ c(1) = 1, c(2) =2 , c(3) =3 $.\n",
    "\n",
    "The iso-utility lines are the level curves of\n",
    "\n",
    "$$\n",
    "\\hat \\pi_1 c_1 + \\hat \\pi_2 c_2 + (1-\\hat \\pi_1 - \\hat \\pi_2) c_3\n",
    "$$\n",
    "\n",
    "and are linear in $ (\\hat \\pi_1, \\hat \\pi_2) $.\n",
    "\n",
    "This is what it means to say ‘expected utility is linear in probabilities.’\n",
    "\n",
    "Both figures plot the locus of points of tangency between the iso-entropy and the iso-utility\n",
    "curves that is traced out as one varies $ \\theta^{-1} $ in the interval\n",
    "$ [0, 2] $.\n",
    "\n",
    "While the iso-entropy lines are identical in the two figures, these ‘expansion paths’ differ because the utility functions differ,\n",
    "meaning that for a given $ \\theta $ and $ (c_1, c_2, c_3) $ triple, the worst-case probabilities $ \\hat \\pi_i(\\theta) =  \\pi_i \\frac{\\exp(-u(c_i)/\\theta )} {E\\exp(-u(c)/\\theta )} $ differ as we vary $ \\theta $, causing the associated entropies to differ.\n",
    "\n",
    "**Color bars:**\n",
    "\n",
    "- First color bar: variation in $ \\theta $  \n",
    "- Second color bar: variation in utility levels  \n",
    "- Third color bar: variation in entropy levels  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f865f46b",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Plotting functions\n",
    "def make_segments(x, y):\n",
    "    '''\n",
    "    Create list of line segments from x and y coordinates, in the correct format for LineCollection:\n",
    "    an array of the form   numlines x (points per line) x 2 (x and y) array\n",
    "    '''\n",
    "\n",
    "    points = np.array([x, y]).T.reshape(-1, 1, 2)\n",
    "    segments = np.concatenate([points[:-1], points[1:]], axis=1)\n",
    "    \n",
    "    return segments\n",
    "\n",
    "\n",
    "def colorline(x, y, z=None, cmap=plt.get_cmap('copper'), norm=plt.Normalize(0.0, 1.0), linewidth=3, alpha=1.0):\n",
    "    '''\n",
    "    Plot a colored line with coordinates x and y\n",
    "    Optionally specify colors in the array z\n",
    "    Optionally specify a colormap, a norm function and a line width\n",
    "    '''\n",
    "    \n",
    "    # Default colors equally spaced on [0,1]:\n",
    "    if z is None:\n",
    "        z = np.linspace(0.0, 1.0, len(x))\n",
    "           \n",
    "    # Special case if a single number:\n",
    "    if not hasattr(z, \"__iter__\"):  # to check for numerical input -- this is a hack\n",
    "        z = np.array([z])\n",
    "        \n",
    "    z = np.asarray(z)\n",
    "    \n",
    "    segments = make_segments(x, y)\n",
    "    lc = LineCollection(segments, array=z, cmap=cmap, linewidth=linewidth, alpha=alpha)\n",
    "    \n",
    "    ax = plt.gca()\n",
    "    ax.add_collection(lc)\n",
    "    plt.colorbar(lc)\n",
    "    \n",
    "    return lc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9e7cf703",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Parameters\n",
    "π_1 = 0.3\n",
    "π_2 = 0.4\n",
    "π_3 = 1 - π_1 - π_2\n",
    "π_base = np.array([π_1, π_2, π_3])\n",
    "c_bundle = np.array([1., 2., 3.])\n",
    "\n",
    "\n",
    "def contour_plot(α, π_vals_nb=200, levels_nb=20, min_π_val=1e-8):\n",
    "    \"\"\"\n",
    "    Create a contour plot containing iso-utility and iso-entropy curves given utility\n",
    "    function parameter `α`.\n",
    "    \n",
    "    \"\"\"\n",
    "    \n",
    "    # Create utility function\n",
    "    u = utility_function_factory(α)\n",
    "\n",
    "    # Initialize arrays \n",
    "    π_hat = np.empty(3)\n",
    "    EU_levels = np.empty((π_vals_nb, π_vals_nb))\n",
    "    ent_levels = np.empty_like(EU_levels)\n",
    "\n",
    "    # Create grids for π_hat_1 and π_hat_2 values\n",
    "    π_hat_1_vals = np.linspace(min_π_val, 1.-min_π_val, π_vals_nb)\n",
    "    π_hat_2_vals = np.linspace(min_π_val, 1.-min_π_val, π_vals_nb)\n",
    "\n",
    "    # Evaluate utility function at consumption bundle\n",
    "    u_c_bundle = u(c_bundle)\n",
    "\n",
    "    # Loop over all (π_hat_1,  π_hat_2) pairs\n",
    "    for i, π_hat_1 in enumerate(π_hat_1_vals):\n",
    "        for j, π_hat_2 in enumerate(π_hat_2_vals):\n",
    "            # Update π_hat vector with current values\n",
    "            π_hat[0] = π_hat_1\n",
    "            π_hat[1] = π_hat_2\n",
    "            π_hat[2] = 1 - π_hat[0] - π_hat[1]\n",
    "\n",
    "            # Compute and store expected utility and entropy level if π_hat is a valid probability vector\n",
    "            if 0. <= π_hat[2] <= 1:\n",
    "                EU_levels[j, i] = np.sum(π_hat * u_c_bundle)\n",
    "                ent_levels[j, i] = ent(π_base, π_hat)\n",
    "            else: \n",
    "                EU_levels[j, i] = np.nan\n",
    "                ent_levels[j, i] = np.nan\n",
    "                \n",
    "    # Create grid of θ values\n",
    "    θ_vals = np.linspace(1e-4, 2., num=50)\n",
    "    π_hat_coord = np.empty((π_base.size, θ_vals.size))\n",
    "    \n",
    "    # For each θ, compute distorted probability distribution\n",
    "    for i in range(θ_vals.size):  \n",
    "        m = compute_change_measure(u, c_bundle, θ_vals[i], π_base)\n",
    "        π_hat_coord[:, i] = π_base * m\n",
    "    \n",
    "    # Create contour plot\n",
    "    plt.figure(figsize=(14, 6))\n",
    "    plt.contour(π_hat_1_vals, π_hat_2_vals, EU_levels, levels=levels_nb, cmap='spring')\n",
    "    plt.colorbar()\n",
    "    plt.contour(π_hat_1_vals, π_hat_2_vals, ent_levels, levels=levels_nb, cmap='winter')\n",
    "    plt.colorbar()\n",
    "    colorline(π_hat_coord[0, :], π_hat_coord[1, :], z=θ_vals)\n",
    "    plt.xlabel(r'$\\hat{\\pi}_{1}$')\n",
    "    plt.ylabel(r'$\\hat{\\pi}_{2}$')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "90448b3c",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "α = 0.\n",
    "\n",
    "contour_plot(α)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9dc65ee6",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "α = 3.\n",
    "\n",
    "contour_plot(α)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab431323",
   "metadata": {},
   "source": [
    "## Bounds on expected utility\n",
    "\n",
    "Suppose that a decision maker wants a lower bound on expected utility\n",
    "$ \\sum_{i=1}^I  \\hat \\pi_i u(c_i) $ that is satisfied for **any**\n",
    "distribution $ \\hat \\pi $ with relative entropy less than or equal to\n",
    "$ \\eta $.\n",
    "\n",
    "An attractive feature of multiplier and constraint preferences\n",
    "is that they carry with them such a bound.\n",
    "\n",
    "To show this, it is useful to collect some findings in the following\n",
    "string of inequalities associated with multiplier preferences:\n",
    "\n",
    "$$\n",
    "\\begin{aligned}\n",
    "{\\sf T}_\\theta u(c) & = & -\\theta \\log \\sum_{i=1}^I \\exp\\Biggl(\\frac{-u(c_i)}{\\theta}\\Biggr) \\pi_i \\nonumber \\\\\n",
    "    & = & \\sum_{i=1}^I m_i^* \\pi_i \\bigl( u(c_i) + \\theta \\log m_i^* \\bigr) \\nonumber \\\\\n",
    "    & \\leq & \\sum_{i=1}^I m_i \\pi_i u(c_i) + \\theta \\sum_{i=1}^i m_i \\log m_i \\pi_i\n",
    "\\end{aligned}\n",
    "$$\n",
    "\n",
    "where $ m_i^* \\propto \\exp \\Bigl( \\frac{- u(c_i)}{\\theta} \\Bigr) $ are the\n",
    "worst-case distortions to probabilities.\n",
    "\n",
    "The inequality in the last line just asserts that minimizers minimize.\n",
    "\n",
    "Therefore, we have the following useful bound:\n",
    "\n",
    "\n",
    "<a id='equation-eqn-bound1'></a>\n",
    "$$\n",
    "\\sum_{i=1}^I m_i \\pi_i u(c_i ) \\geq {\\sf T}_\\theta u(c) - \\theta \\sum_{i=1}^I \\pi_i m_i \\log m_i . \\tag{25.19}\n",
    "$$\n",
    "\n",
    "The left side is expected utility under the probability distribution $ \\{ m_i \\pi_i\\} $.\n",
    "\n",
    "The right side is a *lower bound* on expected utility\n",
    "under *all* distributions expressed as an affine function of relative\n",
    "entropy $ \\sum_{i=1}^I \\pi_i m_i \\log m_i $.\n",
    "\n",
    "The bound is attained for $ m_i =  m_i^* \\propto \\exp \\Bigl(\\frac{- u (c_i)}{\\theta} \\Bigr) $.\n",
    "\n",
    "The *intercept* in the bound is the risk-sensitive criterion $ {\\sf T}_\\theta u(c) $, while the *slope* is the penalty parameter $ \\theta $.\n",
    "\n",
    "Lowering $ \\theta $ does two things:\n",
    "\n",
    "- it lowers the intercept $ {\\sf T}_\\theta u(c) $, which makes the bound less informative for small\n",
    "  values of entropy; and  \n",
    "- it lowers the absolute value of the slope, which makes the bound more informative for larger values of relative\n",
    "  entropy $ \\sum_{i=1}^I \\pi_i m_i \\log m_i $.  \n",
    "\n",
    "\n",
    "The following figure reports  best-case and worst-case expected utilities.\n",
    "\n",
    "We calculate the lines in this figure  numerically by solving optimization problems with respect to the change of measure."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2717ab74",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Parameters\n",
    "α = 3\n",
    "u = utility_function_factory(α)\n",
    "u_c_bundle = u(c_bundle)\n",
    "\n",
    "# Create grid for η values \n",
    "η_vals_nb = 100\n",
    "η_vals = np.linspace(1e-10, 0.08, η_vals_nb)\n",
    "\n",
    "\n",
    "# Initialize arrays to be filled by minimum and maximum expected utility values\n",
    "min_EU = np.empty(η_vals_nb)\n",
    "min_EU[:] = np.nan\n",
    "max_EU = min_EU.copy()\n",
    "\n",
    "\n",
    "@njit\n",
    "def objective(m_0_and_1, η):\n",
    "    \"\"\"\n",
    "    Compute expected utility with respect to the distorted probability measure\n",
    "    given the first two values of the change of measure `m_0_and_1`. \n",
    "    \n",
    "    \"\"\"\n",
    "    # Back out third implied value for the change of measure\n",
    "    m_2 = (1 - (π_base[:2] * m_0_and_1).sum()) / π_base[2]\n",
    "    \n",
    "    # Compute distorted probability measure π_hat\n",
    "    m = np.array([m_0_and_1[0], m_0_and_1[1], m_2])\n",
    "    π_hat = π_base * m\n",
    "    \n",
    "    # Compute expected utility wrt π_hat\n",
    "    EU = np.sum(π_hat * u_c_bundle)\n",
    "    \n",
    "    # Return np.inf if entropy constraint is violated\n",
    "    if ent(π_base, π_hat) > η:\n",
    "        return np.inf\n",
    "    \n",
    "    # Return np.inf if π_hat is not a valid probability vector\n",
    "    if not ((0. <= π_hat) & (π_hat <= 1.)).all():\n",
    "        return np.inf\n",
    "    \n",
    "    return EU\n",
    "\n",
    "\n",
    "@njit\n",
    "def max_obj_wrapper(m_0_and_1, η):\n",
    "    \"\"\"\n",
    "    Wrap `objective` to make it suitable for maximization using minimization routines.\n",
    "    \n",
    "    \"\"\"\n",
    "    obj_val = objective(m_0_and_1, η)\n",
    "    if np.isfinite(obj_val):\n",
    "        return -obj_val\n",
    "    else:\n",
    "        return obj_val"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a2f1328c",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "method = 'Nelder-Mead'\n",
    "m_0_and_1 = np.ones(2)  # Initial guess\n",
    "\n",
    "# Compute worst-case expected utility values\n",
    "for i in range(η_vals_nb):\n",
    "    opt_res = optimize.minimize(objective, m_0_and_1, method=method, args=(η_vals[i]))\n",
    "    opt_res = optimize.minimize(objective, opt_res.x, method=method, args=(η_vals[i]))\n",
    "    if opt_res.success:\n",
    "        min_EU[i] = opt_res.fun\n",
    "         \n",
    "# Compute best-case expected utility values\n",
    "for i in range(η_vals_nb):\n",
    "    opt_res = optimize.minimize(max_obj_wrapper, m_0_and_1, method=method, args=(η_vals[i]))\n",
    "    opt_res = optimize.minimize(max_obj_wrapper, opt_res.x, method=method, args=(η_vals[i]))\n",
    "    if opt_res.success:\n",
    "        max_EU[i] = -opt_res.fun"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8353645b",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Compute lower bound line\n",
    "θ = 1.269230769133136\n",
    "T_θ = T_θ_factory(θ, π_base)\n",
    "intercept = T_θ(u)(c_bundle)\n",
    "lower_bound = intercept - θ * η_vals"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5a3cfa67",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "plt.figure(figsize=(8, 6))\n",
    "plt.plot(η_vals, min_EU, color='blue')\n",
    "plt.plot(η_vals, max_EU, color='blue')\n",
    "plt.fill_between(η_vals, min_EU, max_EU, color='lightgray');\n",
    "plt.plot(η_vals, lower_bound, color='green')\n",
    "plt.ylabel(r'$E\\left[mu\\left(c\\right)\\right]$');\n",
    "plt.xlabel(r'$\\eta$');"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "966a64f2",
   "metadata": {},
   "source": [
    "In this figure, expected utility is on the co-ordinate axis\n",
    "while entropy is on the ordinate axis.\n",
    "\n",
    "The *lower* curved line depicts\n",
    "expected utility under the worst-case model associated with each value\n",
    "of entropy $ \\eta $ recorded on the ordinate axis, i.e., it is\n",
    "$ \\sum_{i=1}^I \\pi_i \\tilde m_i (\\tilde \\theta(c,\\eta)) u(c_i) $, where\n",
    "$ \\tilde m_i (\\tilde \\theta(\\eta)) \\propto \\exp \\Bigl(\\frac{-u(c_i)}{\\tilde \\theta}\\Bigr) $\n",
    "and $ \\tilde \\theta $ is the Lagrange multiplier associated with the\n",
    "constraint that entropy cannot exceed the value on the ordinate axis.\n",
    "\n",
    "The *higher* curved line depicts expected utility under the *best*-case\n",
    "model indexed by the value of the Lagrange multiplier $ \\check \\theta >0 $\n",
    "associated with each value of entropy less than or equal to $ \\eta $\n",
    "recorded on the ordinate axis, i.e., it is\n",
    "$ \\sum_{i=1}^I \\pi_i \\check m_i (\\check \\theta(\\eta)) u(c_i) $ where\n",
    "$ \\check m_i (\\check \\theta(c,\\eta)) \\propto \\exp \\Bigl(\\frac{u(c_i)}{\\check \\theta}\\Bigr) $.\n",
    "\n",
    "(Here $ \\check \\theta $ is the Lagrange multiplier associated with\n",
    "max-max expected utility.)\n",
    "\n",
    "Points between these two curves are\n",
    "possible values of expected utility for some distribution with entropy\n",
    "less than or equal to the value $ \\eta $ on the ordinate axis.\n",
    "\n",
    "The straight line depicts the right side of inequality [(25.19)](#equation-eqn-bound1) for a particular value of the penalty parameter\n",
    "$ \\theta $.\n",
    "\n",
    "As noted, when one lowers $ \\theta $, the intercept $ {\\sf T}_\\theta u(c) $ and the absolute value of the slope both decrease.\n",
    "\n",
    "Thus, as $ \\theta $ is lowered, $ {\\sf T}_\\theta u(c) $ becomes a more\n",
    "conservative estimate of expected utility under the approximating model\n",
    "$ \\pi $.\n",
    "\n",
    "However, as $ \\theta $ is lowered, the robustness bound [(25.19)](#equation-eqn-bound1) becomes more informative for sufficiently large\n",
    "values of entropy.\n",
    "\n",
    "The slope of straight line depicting a bound is $ -\\theta $ and the projection of the point of tangency with the curved\n",
    "depicting the lower bound of expected utility is the entropy associated\n",
    "with that $ \\theta $ when it is interpreted as a Lagrange multiplier on\n",
    "the entropy constraint in the constraint problem .\n",
    "\n",
    "This is an application of the envelope theorem."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cbc1c7e4",
   "metadata": {},
   "source": [
    "## Why entropy?\n",
    "\n",
    "Beyond the helpful mathematical fact that it leads directly to\n",
    "convenient exponential twisting formulas [(25.6)](#equation-tom6) and\n",
    "[(25.12)](#equation-tom12) for worst-case probability distortions,\n",
    "there are two related justifications for using entropy to measure\n",
    "discrepancies between probability distribution.\n",
    "\n",
    "One arises from the role of entropy in statistical tests for discriminating between models.\n",
    "\n",
    "The other comes from axioms."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b17a6e24",
   "metadata": {},
   "source": [
    "### Entropy and statistical detection\n",
    "\n",
    "Robust control theory starts with a decision maker who has constructed a\n",
    "good baseline approximating model whose free parameters he has estimated\n",
    "to fit historical data well.\n",
    "\n",
    "The decision maker recognizes that actual outcomes might be generated by one of a vast number of other models that fit the historical data nearly as well as his.\n",
    "\n",
    "Therefore, he wants to evaluate outcomes under a set of alternative models that are plausible\n",
    "in the sense of being statistically close to his model.\n",
    "\n",
    "He uses relative entropy to quantify what  close means.\n",
    "\n",
    "[[Anderson *et al.*, 2003](https://python-advanced.quantecon.org/zreferences.html#id14)] and [[Barillas *et al.*, 2009](https://python-advanced.quantecon.org/zreferences.html#id15)]describe links between entropy and large deviations\n",
    "bounds on test statistics for discriminating between models, in particular, statistics that describe the probability of making an error in applying a likelihood ratio test to decide whether model A or model B\n",
    "generated a data record of length $ T $.\n",
    "\n",
    "For a given sample size, an\n",
    "informative bound on the detection error probability is a function of\n",
    "the entropy parameter $ \\eta $ in constraint preferences. [[Anderson *et al.*, 2003](https://python-advanced.quantecon.org/zreferences.html#id14)] and [[Barillas *et al.*, 2009](https://python-advanced.quantecon.org/zreferences.html#id15)]\n",
    "use detection error probabilities to calibrate reasonable values of $ \\eta $.\n",
    "\n",
    "[[Anderson *et al.*, 2003](https://python-advanced.quantecon.org/zreferences.html#id14)]  and  [[Hansen and Sargent, 2008](https://python-advanced.quantecon.org/zreferences.html#id160)] also\n",
    "use detection error probabilities to calibrate reasonable values of the\n",
    "penalty parameter $ \\theta $ in multiplier preferences.\n",
    "\n",
    "For a fixed sample size and a fixed $ \\theta $, they would calculate the worst-case\n",
    "$ \\hat m_i(\\theta) $, an associated entropy $ \\eta(\\theta) $, and an\n",
    "associated detection error probability. In this way they build up a\n",
    "detection error probability as a function of $ \\theta $.\n",
    "\n",
    "They then invert this function to calibrate $ \\theta $ to deliver a reasonable detection\n",
    "error probability.\n",
    "\n",
    "To indicate outcomes from this approach, the following figure\n",
    "plots the histogram for U.S. quarterly consumption growth along with a\n",
    "representative agent’s approximating density and a worst-case density\n",
    "that [[Barillas *et al.*, 2009](https://python-advanced.quantecon.org/zreferences.html#id15)] show imply high measured market prices of risk even when a\n",
    "representative consumer has the unit coefficient of relative risk\n",
    "aversion associated with a logarithmic one-period utility function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "12efa1f1",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Load data\n",
    "data = loadmat('dataBHS.mat')\n",
    "\n",
    "# Set parameter values\n",
    "μ_c = 0.004952\n",
    "σ_c = 0.005050;\n",
    "μ_c_tilde = μ_c - σ_c * 0.304569723799467"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "62039ad6",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "# Compute consumption growth\n",
    "c = data['c']\n",
    "c_growth = c[1:] - c[:-1]\n",
    "\n",
    "# Create histogram of consumption growth\n",
    "nb_bins = 30\n",
    "cnt, bins = np.histogram(c_growth, bins=nb_bins)\n",
    "\n",
    "bins_min = bins.min()\n",
    "bins_max = bins.max()\n",
    "\n",
    "# Create grid for PDF values\n",
    "pdf_x = np.linspace(bins_min, bins_max, num=100)\n",
    "\n",
    "# Evaluate PDF at grid points\n",
    "approx = stats.norm(loc=μ_c, scale=σ_c).pdf(pdf_x)\n",
    "worst_case = stats.norm(loc=μ_c_tilde, scale=σ_c).pdf(pdf_x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "82a8325a",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "fig = plt.figure(figsize=(10, 8))\n",
    "ax = fig.add_subplot(111)\n",
    "lns1 = ax.hist(c_growth, bins=bins, alpha=0.5, label='consumption growth (LHS)')\n",
    "ax.set_ylim(0, 30.)\n",
    "ax2 = ax.twinx()\n",
    "lns2 = ax2.plot(pdf_x, approx, color='blue', label='approximating model (RHS)')\n",
    "lns3 = ax2.plot(pdf_x, worst_case, color='green', label='worst case model (RHS)')\n",
    "ax2.set_ylim(0, 90.)\n",
    "\n",
    "lns = [lns1[2][0]]+lns2+lns3\n",
    "labs = [l.get_label() for l in lns]\n",
    "ax.legend(lns, labs, loc=0);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "811f55c9",
   "metadata": {
    "hide-output": false
   },
   "outputs": [],
   "source": [
    "rc('text',usetex=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "692b830a",
   "metadata": {},
   "source": [
    "The density for the approximating model is\n",
    "$ \\log c_{t+1} - \\log c_t = \\mu + \\sigma_c \\epsilon_{t+1} $ where\n",
    "$ \\epsilon_{t+1} \\sim {\\cal N}(0,1) $ and $ \\mu $ and $ \\sigma_c $ are\n",
    "estimated by maximum likelihood from the U.S. quarterly data in the\n",
    "histogram over the period 1948.I-2006.IV.\n",
    "\n",
    "The consumer’s value function under logarithmic utility implies that the worst-case model is\n",
    "$ \\log c_{t+1} - \\log c_t = (\\mu + \\sigma_c w)  + \\sigma_c \\tilde \\epsilon_{t+1} $\n",
    "where $ \\{\\tilde \\epsilon_{t+1}\\} $ is also a normalized Gaussian random\n",
    "sequence and where $ w $ is calculated by setting a detection error\n",
    "probability to $ .05 $.\n",
    "\n",
    "The worst-case model appears to fit the histogram nearly as well as the approximating model."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d8b4968",
   "metadata": {},
   "source": [
    "### Axiomatic justifications\n",
    "\n",
    "Multiplier and constraint preferences are both special cases of what\n",
    "[[Maccheroni *et al.*, 2006](https://python-advanced.quantecon.org/zreferences.html#id12)] call variational preferences.\n",
    "\n",
    "They provide an axiomatic foundation for variational preferences and describe how they\n",
    "express ambiguity aversion.\n",
    "\n",
    "Constraint preferences are particular instances of the multiple priors model of [[Gilboa and Schmeidler, 1989](https://python-advanced.quantecon.org/zreferences.html#id13)]."
   ]
  }
 ],
 "metadata": {
  "date": 1754298588.5433936,
  "filename": "five_preferences.md",
  "kernelspec": {
   "display_name": "Python",
   "language": "python3",
   "name": "python3"
  },
  "title": "Risk and Model Uncertainty"
 },
 "nbformat": 4,
 "nbformat_minor": 5
}