{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "2e9fcc82",
   "metadata": {},
   "source": [
    "\n",
    "File: 03-indicators.py\n",
    "\n",
    "\n",
    "Michel Bierlaire\n",
    "\n",
    "Sat Aug 02 2025, 18:44:59\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6ad672e1",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "from typing import NamedTuple\n",
    "\n",
    "import numpy as np\n",
    "from IPython.core.display_functions import display\n",
    "from biogeme.biogeme import BIOGEME\n",
    "from biogeme.models import logit, loglogit\n",
    "from biogeme.results_processing import (\n",
    "    EstimationResults,\n",
    "    get_pandas_estimated_parameters,\n",
    ")\n",
    "\n",
    "from optima_specification import scenario, v_base\n",
    "from optima_variables import Choice, database, normalizedWeight\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7432afc",
   "metadata": {},
   "source": [
    "We consider the specification from the files `optima_variables.py` and `optima_specification.py`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44d33b40",
   "metadata": {},
   "source": [
    "The objective of this laboratory is to use an estimated choice model to calculate various indicators. We start with\n",
    "the market shares and the revenues."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce8c40eb",
   "metadata": {},
   "source": [
    "We first create a data structure to store the value of an indicator and the bounds of its confidence interval."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "27718543",
   "metadata": {},
   "outputs": [],
   "source": [
    "class IndicatorTuple(NamedTuple):\n",
    "    \"\"\"Tuple storing the value of an indicator, and the bounds on its confidence interval.\"\"\"\n",
    "\n",
    "    value: float\n",
    "    lower: float\n",
    "    upper: float\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88885748",
   "metadata": {},
   "source": [
    "We build the loglikelihood function for the base model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d897f7a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "logprob = loglogit(v_base, None, Choice)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e1474ac",
   "metadata": {},
   "source": [
    "We estimate the parameters of the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f7970ca6",
   "metadata": {},
   "outputs": [],
   "source": [
    "biogeme = BIOGEME(database, logprob)\n",
    "model_name = 'optima_base'\n",
    "biogeme.model_name = model_name\n",
    "results: EstimationResults = biogeme.estimate(run_bootstrap=True, recycle=True)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "551db13b",
   "metadata": {},
   "source": [
    "General statistics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f359f336",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(results.short_summary())\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9eca26d4",
   "metadata": {},
   "source": [
    "Estimated parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a758642",
   "metadata": {},
   "outputs": [],
   "source": [
    "display(get_pandas_estimated_parameters(estimation_results=results))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59f0822a",
   "metadata": {},
   "source": [
    "# Scenarios"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd6789f5",
   "metadata": {},
   "source": [
    "We are interested in the market shares of public transportation, as well as the revenues generated by this\n",
    "alternative."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "75acab98",
   "metadata": {},
   "source": [
    "First, we calculate the market shares of each alternative for the current scenario, as well as the 90% confidence\n",
    "intervals."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5bb85e8f",
   "metadata": {},
   "source": [
    "We write the expression for the choice probability of each alternative."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1739cd87",
   "metadata": {},
   "outputs": [],
   "source": [
    "prob_PT = logit(v_base, None, 0)\n",
    "prob_CAR = logit(v_base, None, 1)\n",
    "prob_SM = logit(v_base, None, 2)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bfd8c1f9",
   "metadata": {},
   "source": [
    "We build a dictionary will all quantities to be simulated, that is, the choice probability of each alternative, as\n",
    "well as the weight of each observation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a654575f",
   "metadata": {},
   "outputs": [],
   "source": [
    "simulate = {\n",
    "    'weight': normalizedWeight,\n",
    "    'Prob. PT': prob_PT,\n",
    "    'Prob. car': prob_CAR,\n",
    "    'Prob. SM': prob_SM,\n",
    "}\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "218a5d8a",
   "metadata": {},
   "source": [
    "We perform the simulation and collect the simulated values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0c1e306a",
   "metadata": {},
   "outputs": [],
   "source": [
    "biosim = BIOGEME(database, simulate)\n",
    "simulated_values = biosim.simulate(results.get_beta_values())\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35549e76",
   "metadata": {},
   "source": [
    "We also calculate confidence intervals for the calculated quantities"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9f309185",
   "metadata": {},
   "outputs": [],
   "source": [
    "b = results.get_betas_for_sensitivity_analysis()\n",
    "left, right = biosim.confidence_intervals(b, 0.9)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d404a49",
   "metadata": {},
   "source": [
    "Market shares are calculated using the weighted mean of the individual probabilities. We first calculate the\n",
    "weighted quantities in an additional column of the data frame. Then, we calculate the mean of those columns."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e930f2a9",
   "metadata": {},
   "source": [
    "Alternative car"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d809805f",
   "metadata": {},
   "outputs": [],
   "source": [
    "simulated_values['Weighted choice_prob. car'] = (\n",
    "    simulated_values['weight'] * simulated_values['Prob. car']\n",
    ")\n",
    "left['Weighted choice_prob. car'] = left['weight'] * left['Prob. car']\n",
    "right['Weighted choice_prob. car'] = right['weight'] * right['Prob. car']\n",
    "\n",
    "marketShare_car = IndicatorTuple(\n",
    "    value=simulated_values['Weighted choice_prob. car'].mean(),\n",
    "    lower=left['Weighted choice_prob. car'].mean(),\n",
    "    upper=right['Weighted choice_prob. car'].mean(),\n",
    ")\n",
    "print(\n",
    "    f'Market share for car: {100*marketShare_car.value:.1f}% '\n",
    "    f'[{100*marketShare_car.lower:.1f}%, '\n",
    "    f'{100*marketShare_car.upper:.1f}%]'\n",
    ")\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aae10cd6",
   "metadata": {},
   "source": [
    "Alternative public transportation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "68765d2d",
   "metadata": {},
   "outputs": [],
   "source": [
    "simulated_values['Weighted choice_prob. PT'] = (\n",
    "    simulated_values['weight'] * simulated_values['Prob. PT']\n",
    ")\n",
    "left['Weighted choice_prob. PT'] = left['weight'] * left['Prob. PT']\n",
    "right['Weighted choice_prob. PT'] = right['weight'] * right['Prob. PT']\n",
    "\n",
    "marketShare_PT = IndicatorTuple(\n",
    "    value=simulated_values['Weighted choice_prob. PT'].mean(),\n",
    "    lower=left['Weighted choice_prob. PT'].mean(),\n",
    "    upper=right['Weighted choice_prob. PT'].mean(),\n",
    ")\n",
    "print(\n",
    "    f'Market share for public transportation: {100*marketShare_PT.value:.1f}% '\n",
    "    f'[{100*marketShare_PT.lower:.1f}%, '\n",
    "    f'{100*marketShare_PT.upper:.1f}%]'\n",
    ")\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0214b84d",
   "metadata": {},
   "source": [
    "Alternative slow modes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4b9d816e",
   "metadata": {},
   "outputs": [],
   "source": [
    "simulated_values['Weighted choice_prob. SM'] = (\n",
    "    simulated_values['weight'] * simulated_values['Prob. SM']\n",
    ")\n",
    "left['Weighted choice_prob. SM'] = left['weight'] * left['Prob. SM']\n",
    "right['Weighted choice_prob. SM'] = right['weight'] * right['Prob. SM']\n",
    "\n",
    "marketShare_SM = IndicatorTuple(\n",
    "    value=simulated_values['Weighted choice_prob. SM'].mean(),\n",
    "    lower=left['Weighted choice_prob. SM'].mean(),\n",
    "    upper=right['Weighted choice_prob. SM'].mean(),\n",
    ")\n",
    "print(\n",
    "    f'Market share for slow modes: {100*marketShare_SM.value:.1f}% '\n",
    "    f'[{100*marketShare_SM.lower:.1f}%, '\n",
    "    f'{100*marketShare_SM.upper:.1f}%]'\n",
    ")\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "315ce485",
   "metadata": {},
   "source": [
    "Now, consider various scenarios where the price of public transportation is multiplied for each individual by a\n",
    "scale factor. We advise you to build a Python function that takes the specification of the utility as an argument,\n",
    "and returns the market shares as well as the bounds of the confidence intervals."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "031baa09",
   "metadata": {},
   "source": [
    "The function `scenario`, imported from `optima_specification`, takes a scale factor as an argument and returns a\n",
    "`ScenarioTuple` that contains\n",
    "- the expression for the utility functions,\n",
    "- the expression for the chosen alternative,\n",
    "- the expression for the cost:\n",
    "\n",
    "```\n",
    "class ScenarioTuple(NamedTuple):\n",
    "\"\"\"Structure storing the expressions for a scenario\"\"\"\n",
    "\n",
    "utilities: dict[int, Expression]\n",
    "choice: Expression\n",
    "cost: Expression\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d9cb2190",
   "metadata": {},
   "source": [
    "Utility functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94d5ca80",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(scenario(factor=1.2).utilities)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ddc35024",
   "metadata": {},
   "source": [
    "Choice"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cdc4bfb9",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(scenario(factor=1.2).choice)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed499482",
   "metadata": {},
   "source": [
    "Cost"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c4cee3db",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(scenario(factor=1.2).cost)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1952107e",
   "metadata": {},
   "source": [
    "We consider scales ranging from 0 to 5, with a step of 0.2."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6651b3a6",
   "metadata": {},
   "outputs": [],
   "source": [
    "scales = np.arange(0, 5.2, 0.2)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7775012f",
   "metadata": {},
   "source": [
    "- Calculate the market share of public transportation, as well as the 90% confidence interval, for each scenario. Plot the results.\n",
    "- Calculate the market share of car, as well as the 90% confidence interval, for each scenario. Plot the results.\n",
    "- Calculate the revenues generated by public transportation, as well as the 90% confidence interval, for each scenario. Plot the results."
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 5
}
