{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Using custom fixed points\n",
    "\n",
    "Sometimes, cleverly choosing the points to do the computation can result in more efficient process.\n",
    "For example, around the region where the canyon curves, we would want to have more points to capture the shape of the canyon.\n",
    "On the other hand, in some region the canyon might look like a line (the canyon doesn't curve significantly).\n",
    "In this case, we don't need as much point to capture the shape of the canyon.\n",
    "This can possibly speed up the computation, because we can require fewer number of points in our computation.\n",
    "\n",
    "To show this, we will compare the results of profile likelihood computation using the sum of exponentials model.\n",
    "We will run the computation using linearly spaced points (using the internal algorithm to generate the points) and some custom points.\n",
    "We will compare the time to run for each computation.\n",
    "Additionally, we will also compare the results qualitatively by plotting the profile likelihood paths on the cost contour and comparing the profile likelihood."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Define the model, profile likelihood object, and cost contour data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:11.419304Z",
     "start_time": "2022-01-27T04:20:11.400888Z"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from profile_likelihood import profile_likelihood\n",
    "import model_trigonometric as model\n",
    "import manifold\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Define the model\n",
    "\n",
    "The model is defined as the sum of trigonometric functions, in the form of\n",
    "$$ f\\left(t; \\vec{\\theta}\\right) = \\sin(\\theta_0 t) + \\cos(\\theta_1 t), $$\n",
    "where we sample at 3 time points $t = [1.0, 1.2, 2.0]^T$.\n",
    "The default parameters are chosen to be $\\vec{\\theta} = [1.0, 2.5]^T$.\n",
    "The data is set to be the predictions of the model at the default parameters and the standard deviation is chosen to be 30% of the data.\n",
    "The implementation of this model is given in `model_trigonometric.py`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:11.427763Z",
     "start_time": "2022-01-27T04:20:11.422890Z"
    }
   },
   "outputs": [],
   "source": [
    "# Define the variables from model\n",
    "best_fit = model.best_fit\n",
    "param_names = model.param_names\n",
    "nparams = model.nparams\n",
    "npred = model.npred\n",
    "\n",
    "# Define the likelihood object\n",
    "likelihood = profile_likelihood(model.residuals, nparams, npred)\n",
    "bounds = [-5, 5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:11.729072Z",
     "start_time": "2022-01-27T04:20:11.431482Z"
    }
   },
   "outputs": [],
   "source": [
    "# Get cost contour data\n",
    "Theta0, Theta1, Cost = manifold.cost_contour_data(\n",
    "    model.cost,\n",
    "    xlist=np.linspace(-5, 5, 100),\n",
    "    ylist=np.linspace(-5, 5, 100),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Run computation using linearly spaced points"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:12.134425Z",
     "start_time": "2022-01-27T04:20:11.732128Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Task for parameter1 is done by Process-3\n",
      "Task for parameter0 is done by Process-2\n",
      "CPU times: user 21.4 ms, sys: 24.5 ms, total: 45.9 ms\n",
      "Wall time: 396 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# Run the computation\n",
    "results_linspace = likelihood.compute(best_fit, bounds=bounds, dt=0.1, processes=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:12.141262Z",
     "start_time": "2022-01-27T04:20:12.137195Z"
    }
   },
   "outputs": [],
   "source": [
    "ldata0_linspace = likelihood.results[\"parameter0\"]\n",
    "ldata1_linspace = likelihood.results[\"parameter1\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Run computation using custom points"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:12.152608Z",
     "start_time": "2022-01-27T04:20:12.144045Z"
    }
   },
   "outputs": [],
   "source": [
    "# Define function to map linearly spaced points to the desired points\n",
    "def f(x, x0):\n",
    "    # return 2 / np.pi * np.arctan(x - x0) * abs(x - x0) + x0\n",
    "    return (x - x0) ** 3 / 200\n",
    "\n",
    "\n",
    "# Define the points that will be used\n",
    "ll = np.arange(-10, 10 + 0.3 / 2, 0.3)\n",
    "points = [[f(x + x0, x0) for x in ll] for x0 in [-np.pi / 2, 0]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:12.434817Z",
     "start_time": "2022-01-27T04:20:12.155719Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Task for parameter0 is done by Process-5\n",
      "Task for parameter1 is done by Process-6\n",
      "CPU times: user 13.2 ms, sys: 21.6 ms, total: 34.8 ms\n",
      "Wall time: 270 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# Run the computation\n",
    "results_custom = likelihood.compute(best_fit, points=points, processes=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:12.443401Z",
     "start_time": "2022-01-27T04:20:12.439063Z"
    }
   },
   "outputs": [],
   "source": [
    "ldata0_custom = likelihood.results[\"parameter0\"]\n",
    "ldata1_custom = likelihood.results[\"parameter1\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The computation using the custom points is faster, but it is because we use fewer number of points here.\n",
    "Next, we will qualitatively compare the results."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comparison of the profile likelihood paths"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:13.431444Z",
     "start_time": "2022-01-27T04:20:12.447341Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 93284 characters]\n",
      "text/plain": [
       "<Figure size 900x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot the profile likelihood paths using linearly spaced points\n",
    "ax, clb = manifold.plot_cost_contour(Theta0, Theta1, Cost, levels=25, scale=\"log\")\n",
    "plt.title(\"Using linearly spaced points\")\n",
    "ax.plot(\n",
    "    ldata0_linspace[\"parameters\"][:, 0],\n",
    "    ldata0_linspace[\"parameters\"][:, 1],\n",
    "    \"r--\",\n",
    "    label=f\"scan {param_names[0]}\",\n",
    "    zorder=10,\n",
    ")\n",
    "ax.plot(\n",
    "    ldata1_linspace[\"parameters\"][:, 0],\n",
    "    ldata1_linspace[\"parameters\"][:, 1],\n",
    "    \"k-\",\n",
    "    label=f\"scan {param_names[1]}\",\n",
    ")\n",
    "ax.plot(best_fit[0], best_fit[1], \"wx\", label=\"best fit\", zorder=20)\n",
    "ax.set_xlim((-5, 5))\n",
    "ax.set_ylim((-5, 5))\n",
    "ax.set_xlabel(param_names[0])\n",
    "ax.set_ylabel(param_names[0])\n",
    "clb.set_label(r\"$cost$\")\n",
    "plt.legend(fontsize=8)\n",
    "plt.show()\n",
    "plt.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:14.157556Z",
     "start_time": "2022-01-27T04:20:13.434521Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 93180 characters]\n",
      "text/plain": [
       "<Figure size 900x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot the profile likelihood paths using linearly spaced points\n",
    "ax, clb = manifold.plot_cost_contour(Theta0, Theta1, Cost, levels=25, scale=\"log\")\n",
    "plt.title(\"Using custom points\")\n",
    "ax.plot(\n",
    "    ldata0_custom[\"parameters\"][:, 0],\n",
    "    ldata0_custom[\"parameters\"][:, 1],\n",
    "    \"r--\",\n",
    "    label=f\"scan {param_names[0]}\",\n",
    "    zorder=10,\n",
    ")\n",
    "ax.plot(\n",
    "    ldata1_custom[\"parameters\"][:, 0],\n",
    "    ldata1_custom[\"parameters\"][:, 1],\n",
    "    \"k-\",\n",
    "    label=f\"scan {param_names[0]}\",\n",
    ")\n",
    "ax.plot(best_fit[0], best_fit[1], \"wx\", label=\"best fit\")\n",
    "ax.set_xlim((-5, 5))\n",
    "ax.set_ylim((-5, 5))\n",
    "ax.set_xlabel(param_names[0])\n",
    "ax.set_ylabel(param_names[1])\n",
    "clb.set_label(r\"$\\log(cost)$\")\n",
    "plt.legend(fontsize=8)\n",
    "plt.show()\n",
    "plt.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In short, the profile likelihood paths from the 2 computations are comparable."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comparison of the cost values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:14.630983Z",
     "start_time": "2022-01-27T04:20:14.160552Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 51948 characters]\n",
      "text/plain": [
       "<Figure size 900x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot the cost along theta_0 direction\n",
    "plt.figure(dpi=150, facecolor=\"w\")\n",
    "plt.plot(\n",
    "    ldata0_linspace[\"parameters\"][:, 0],\n",
    "    ldata0_linspace[\"cost\"],\n",
    "    label=\"linearly spaced\",\n",
    ")\n",
    "plt.plot(ldata0_custom[\"parameters\"][:, 0], ldata0_custom[\"cost\"], \"--\", label=\"custom\")\n",
    "plt.xlim(-5, 5)\n",
    "plt.yscale(\"log\")\n",
    "plt.ylim(1e-7, 1e7)\n",
    "plt.xlabel(param_names[0])\n",
    "plt.ylabel(\"Cost\")\n",
    "plt.legend()\n",
    "plt.show()\n",
    "plt.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-01-27T04:20:15.264396Z",
     "start_time": "2022-01-27T04:20:14.633815Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 64916 characters]\n",
      "text/plain": [
       "<Figure size 900x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot the cost along theta_0 direction\n",
    "plt.figure(dpi=150, facecolor=\"w\")\n",
    "plt.plot(\n",
    "    ldata1_linspace[\"parameters\"][:, 1],\n",
    "    ldata1_linspace[\"cost\"],\n",
    "    label=\"linearly spaced\",\n",
    ")\n",
    "plt.plot(ldata1_custom[\"parameters\"][:, 1], ldata1_custom[\"cost\"], \"--\", label=\"custom\")\n",
    "plt.xlim(-5, 5)\n",
    "plt.yscale(\"log\")\n",
    "plt.ylim(1e-2, 1e3)\n",
    "plt.xlabel(param_names[1])\n",
    "plt.ylabel(\"Cost\")\n",
    "plt.legend()\n",
    "plt.show()\n",
    "plt.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "On these plots, the two results are comparable."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
