{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7ce917a3",
   "metadata": {},
   "source": [
    "\n",
    "File: 04-asv.py\n",
    "\n",
    "\n",
    "Michel Bierlaire\n",
    "\n",
    "Tue Aug 05 2025, 15:55:33\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "071ec783",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "import biogeme.biogeme_logging as blog\n",
    "from IPython.core.display_functions import display\n",
    "from biogeme import models\n",
    "from biogeme.biogeme import BIOGEME\n",
    "from biogeme.expressions import Beta, Draws\n",
    "from biogeme.results_processing import (\n",
    "    EstimationResults,\n",
    "    get_pandas_estimated_parameters,\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "09b0c406",
   "metadata": {},
   "source": [
    "The variables of the model are available from the file `airline_variables.py`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d5970c89",
   "metadata": {},
   "outputs": [],
   "source": [
    "from airline_variables import (\n",
    "    Fare_1,\n",
    "    Fare_2,\n",
    "    Fare_3,\n",
    "    Legroom_1,\n",
    "    Legroom_2,\n",
    "    Legroom_3,\n",
    "    Opt1_SchedDelayEarly,\n",
    "    Opt1_SchedDelayLate,\n",
    "    Opt2_SchedDelayEarly,\n",
    "    Opt2_SchedDelayLate,\n",
    "    Opt3_SchedDelayEarly,\n",
    "    Opt3_SchedDelayLate,\n",
    "    TripTimeHours_1,\n",
    "    TripTimeHours_2,\n",
    "    TripTimeHours_3,\n",
    "    chosenAlternative,\n",
    "    database,\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1cb5ba53",
   "metadata": {},
   "source": [
    "The objective of this laboratory is to investigate various normalizations of an alternative specific variance model."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e7a4e93",
   "metadata": {},
   "source": [
    "Consider the logit model presented below.\n",
    "\n",
    "1. Include error components to obtain a model with alternative specific variances.\n",
    "2. Estimate the model without any normalization.\n",
    "3. Identify the scale parameter that must be normalized to zero.\n",
    "4. Compare the entries of the variance-covariance matrix for both models.\n",
    "5. Perform the same analysis when the wrong scale parameter is normalized to zero."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7b115800",
   "metadata": {},
   "source": [
    "As the estimation time may be long, we ask Biogeme to report the details of the iterations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f76780bf",
   "metadata": {},
   "outputs": [],
   "source": [
    "logger = blog.get_screen_logger(level=blog.INFO)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aee12c73",
   "metadata": {},
   "source": [
    "# The model"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32fa27b0",
   "metadata": {},
   "source": [
    "Parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "acdca78a",
   "metadata": {},
   "outputs": [],
   "source": [
    "constant2 = Beta('constant2', 0, None, None, 0)\n",
    "constant3 = Beta('constant3', 0, None, None, 0)\n",
    "fare = Beta('fare', 0, None, None, 0)\n",
    "legroom = Beta('legroom', 0, None, None, 0)\n",
    "schedule_delay_early = Beta('schedule_delay_early', 0, None, None, 0)\n",
    "schedule_delay_late = Beta('schedule_delay_late', 0, None, None, 0)\n",
    "total_tt1 = Beta('total_tt1', 0, None, None, 0)\n",
    "total_tt2 = Beta('total_tt2', 0, None, None, 0)\n",
    "total_tt3 = Beta('total_tt3', 0, None, None, 0)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c14d20df",
   "metadata": {},
   "source": [
    "Error components"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "71ae430f",
   "metadata": {},
   "outputs": [],
   "source": [
    "sigma_1 = Beta('sigma_1', 1, None, None, 0)\n",
    "ec_1 = sigma_1 * Draws('ec_1', 'NORMAL')\n",
    "sigma_2 = Beta('sigma_2', 1, None, None, 0)\n",
    "ec_2 = sigma_2 * Draws('ec_2', 'NORMAL')\n",
    "sigma_3 = Beta('sigma_3', 1, None, None, 0)\n",
    "ec_3 = sigma_3 * Draws('ec_3', 'NORMAL')\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3629ef38",
   "metadata": {},
   "source": [
    "Utility functions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "19710b08",
   "metadata": {},
   "outputs": [],
   "source": [
    "opt1 = (\n",
    "    fare * Fare_1\n",
    "    + legroom * Legroom_1\n",
    "    + schedule_delay_early * Opt1_SchedDelayEarly\n",
    "    + schedule_delay_late * Opt1_SchedDelayLate\n",
    "    + total_tt1 * TripTimeHours_1\n",
    ")\n",
    "opt2 = (\n",
    "    constant2\n",
    "    + fare * Fare_2\n",
    "    + legroom * Legroom_2\n",
    "    + schedule_delay_early * Opt2_SchedDelayEarly\n",
    "    + schedule_delay_late * Opt2_SchedDelayLate\n",
    "    + total_tt2 * TripTimeHours_2\n",
    ")\n",
    "opt3 = (\n",
    "    constant3\n",
    "    + fare * Fare_3\n",
    "    + legroom * Legroom_3\n",
    "    + schedule_delay_early * Opt3_SchedDelayEarly\n",
    "    + schedule_delay_late * Opt3_SchedDelayLate\n",
    "    + total_tt3 * TripTimeHours_3\n",
    ")\n",
    "v = {1: opt1, 2: opt2, 3: opt3}\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "546790a5",
   "metadata": {},
   "source": [
    "# Estimation of the logit model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9aa3cf25",
   "metadata": {},
   "outputs": [],
   "source": [
    "logprob = models.loglogit(v, None, chosenAlternative)\n",
    "biogeme = BIOGEME(database, logprob)\n",
    "biogeme.modelName = 'logit'\n",
    "\n",
    "results: EstimationResults = biogeme.estimate()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "256fc33f",
   "metadata": {},
   "source": [
    "General statistics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33bc39dc",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(results.short_summary())\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3bccf593",
   "metadata": {},
   "source": [
    "Estimated parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e0683c7a",
   "metadata": {},
   "outputs": [],
   "source": [
    "estimated_parameters = get_pandas_estimated_parameters(estimation_results=results)\n",
    "display(estimated_parameters)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bee5f30b",
   "metadata": {},
   "source": [
    "Hints:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4705370b",
   "metadata": {},
   "source": [
    "- It is advised to start working with a low number of draws, until the script is working well.\n",
    "Then, increase the number of draws to 10000, say. Then, execute the script overnight.\n",
    "- In order to avoid repeating the same code, we suggest to write a Python function that takes as argument the\n",
    "id of the alternative that is normalized:\n",
    "`def estimate(normalization: int) -> bioResults:`\n",
    "Then, depending on the normalization, you provide the corresponding specification to Biogeme."
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 5
}
