pm21-dragon/lectures/lecture-07/2 - optimization.ipynb
2024-12-02 10:47:50 +01:00

688 lines
66 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Optimization\n",
"\n",
"Let's consider the following code:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Text(0, 0.5, 'y')"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXsAAAEmCAYAAACDLjAiAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAmeElEQVR4nO3de1RU5f4/8PcwwE4EBkFhBhmREstL3k3xeAFNjC4njydXZqmsWl5KTaJz9Gito7lM1E6m51iUdY63TDt5KStTaCljhhf0SBKZQo6JCqFmDCINyjy/P/iyfww3GZz7fr/W2gtm72dmPg/qm8fn2bO3SgghQEREXs3H1QUQEZHjMeyJiBSAYU9EpAAMeyIiBWDYExEpAMOeiEgBGPZERArAsCciUgBfVxfgTBaLBZcuXUJQUBBUKpWryyEiumNCCJSXlyMyMhI+Pk2P3xUV9pcuXYJer3d1GUREdldUVISoqKgmj7tF2KenpyM9PR3nzp0DAPTo0QN///vfkZSUBKDmN9drr72GtWvX4tq1axg0aBDefvtt9OjRw6b3CQoKAlDzQwkODrZrH4iIXMFkMkGv18v51hS3CPuoqCgsW7YMXbp0AQBs2LABjz/+OE6cOIEePXpgxYoVWLlyJdavX4+uXbtiyZIlGD16NE6fPn3bDtZVO3UTHBzMsCcir3K7qWmVu14ILTQ0FG+88QaeffZZREZGIiUlBfPmzQMAmM1mREREYPny5Zg+fXqLX9NkMkGj0aCsrIxhT0ReoaW55nZn41RXV2Pr1q2oqKhAXFwcjEYjSkpKkJiYKLeRJAkjRoxAdnZ2s69lNpthMpmsNiIiJXKbsM/Ly0NgYCAkScKMGTOwc+dOdO/eHSUlJQCAiIgIq/YRERHysaakpaVBo9HIGxdniUip3GLOHgDuvfde5Obm4rfffsP27dsxZcoUGAwG+Xj9+SghxG3nqObPn4/U1FT5ce1CBhHdOSEEbt26herqaleX4tXUajV8fX3v+HRxtwl7f39/eYF2wIAByMnJwerVq+V5+pKSEuh0Orl9aWlpg9F+fZIkQZIkxxVNpFBVVVUoLi7GjRs3XF2KIgQEBECn08Hf37/Vr+E2YV+fEAJmsxkxMTHQarXIzMxE3759AdT8RTMYDFi+fLmLqyRSHovFAqPRCLVajcjISPj7+/NDig4ihEBVVRUuX74Mo9GI2NjYZj841Ry3CPsFCxYgKSkJer0e5eXl2Lp1K7KysrBnzx6oVCqkpKRg6dKliI2NRWxsLJYuXYqAgABMnDjR1aUTKU5VVRUsFgv0ej0CAgJcXY7Xa9OmDfz8/PDzzz+jqqoKd911V6texy3C/pdffsGkSZNQXFwMjUaDXr16Yc+ePRg9ejQAYO7cuaisrMQLL7wgf6gqIyPDpnPsici+WjvCJNvZ42fttufZOwLPsye6c7///juMRiNiYmJaPcok2zT3M/fY8+yJiMj+GPZE5BrV1UBWFrBlS81XJ5zCKYTAtGnTEBoaCpVKhZCQEKSkpDj8fd0Bw56InG/HDqBzZyAhAZg4seZr5841+x1oz549WL9+Pb744gsUFxejZ8+eDn0/d8KwJyLn2rEDeOIJ4MIF6/0XL9bsd2Dg//TTT9DpdBgyZAi0Wi18fd3iHBXZzZs3HfbaDHsicp7qamDOHKCx80Jq96WkOGRKJzk5GbNnz8b58+ehUqnQuXPnBm2uXbuGyZMno127dggICEBSUhIKCgr+rzyBDh06YPv27XL7Pn36IDw8XH586NAh+Pn54fr16wCAsrIyTJs2DeHh4QgODsbIkSPx3Xffye0XLVqEPn364D//+Q/uvvtuSJIER50zw7AnIuf55puGI/q6hACKimra2dnq1auxePFiREVFobi4GDk5OQ3aJCcn49ixY9i1axcOHToEIQQefvhh3Lx5EyqVCsOHD0dWVhaAml8MP/zwA27evIkffvgBAJCVlYX+/fsjMDAQQgg88sgjKCkpwe7du3H8+HH069cPo0aNwq+//iq/Z2FhIf773/9i+/btyM3NtXu/a7nX/2GIyLsVF9u3nQ00Gg2CgoKgVquh1WobHC8oKMCuXbvw7bffYsiQIQCAzZs3Q6/X49NPP8X48eMRHx+PtWvXAgAOHDiA3r17o1OnTsjKykL37t2RlZWF+Ph4AMD+/fuRl5eH0tJS+bIt//jHP/Dpp59i27ZtmDZtGoCaD6lt2rQJHTp0sHuf6+LInoicp871rezSzo5OnToFX19fDBo0SN4XFhaGe++9F6dOnQIAxMfHIz8/H1euXIHBYEB8fDzi4+NhMBhw69YtZGdnY8SIEQCA48eP4/r16wgLC0NgYKC8GY1G/PTTT/J7REdHOzzoAY7siciZhg0DoqJqFmMbm5tWqWqODxvm9NKamiuve4Xdnj17IiwsDAaDAQaDAYsXL4Zer8frr7+OnJwcVFZWYujQoQBqriGk0+nkaZ+6QkJC5O/btm1r9740hmFPRM6jVgOrV9ecdaNSWQd+7cXUVq2qaedk3bt3x61bt3DkyBF5Gufq1as4c+YMunXr9n8l1szbf/bZZ/j+++8xbNgwBAUF4ebNm3j33XfRr18/+TIu/fr1Q0lJCXx9fRtdDHY2TuMQkXONGwds2wZ07Gi9PyqqZv+4cS4pKzY2Fo8//jimTp2KgwcP4rvvvsMzzzyDjh074vHHH5fbxcfH46OPPkKvXr0QHBws/wLYvHmzPF8PAA8++CDi4uIwduxY7N27F+fOnUN2djZeffVVHDt2zOn9Y9gTkfONGwecOwfs3w989FHNV6PRZUFfa926dejfvz8effRRxMXFQQiB3bt3w8/PT26TkJCA6upqq2AfMWIEqqur5fl6oOZ/Abt378bw4cPx7LPPomvXrpgwYQLOnTt323txOAIvhEZENuGF0JyPF0IjIqIWYdgTESkAw56ISAEY9kRECsCwJyJSAIY9EZECuEXYp6WlYeDAgQgKCkJ4eDjGjh2L06dPW7VJTk6GSqWy2gYPHuyiiomIPItbhL3BYMDMmTNx+PBhZGZm4tatW0hMTERFRYVVu4ceegjFxcXytnv3bhdVTETkWdzi2jh79uyxerxu3TqEh4fj+PHjGD58uLxfkqRGL01KRETNc4uRfX1lZWUAgNDQUKv9WVlZCA8PR9euXTF16lSUlpY2+zpmsxkmk8lqIyLlio+PV8wNxutzu7AXQiA1NRVDhw61uhlwUlISNm/ejH379uHNN99ETk4ORo4cCbPZ3ORrpaWlQaPRyJter3dGF4iI3I5bTOPUNWvWLJw8eRIHDx602v/kk0/K3/fs2RMDBgxAdHQ0vvzyS4xr4uJJ8+fPR2pqqvzYZDIx8IncyIULF1BQUIDY2FhERUW5uhyv5lYj+9mzZ2PXrl3Yv3//bf/gdTodoqOj5ZsBN0aSJAQHB1ttRGRfQghUVFTYvL3zzjuIjo7GyJEjER0djXfeecfm12jNdRxv3bqFWbNmISQkBGFhYXj11Vfl16mqqsLcuXPRsWNHtG3bFoMGDWpw85Hs7GwMHz4cbdq0gV6vx4svvtjgZBK3JNyAxWIRM2fOFJGRkeLMmTMtes6VK1eEJEliw4YNLX6fsrIyAUCUlZW1tlQixausrBQ//PCDqKysFEIIcf36dQHAJdv169dtqn3EiBEiMDBQzJkzR/z444/iww8/FAEBAWLt2rVCCCEmTpwohgwZIg4cOCAKCwvFG2+8ISRJknPp5MmTIjAwULz11lvizJkz4ttvvxV9+/YVycnJ9v0h11P/Z15XS3PNLcL++eefFxqNRmRlZYni4mJ5u3HjhhBCiPLycvHyyy+L7OxsYTQaxf79+0VcXJzo2LGjMJlMLX4fhj3RnfP0sO/WrZuwWCzyvnnz5olu3bqJwsJCoVKpxMWLF62eM2rUKDF//nwhhBCTJk0S06ZNszr+zTffCB8fn0aD2F7sEfZuMWefnp4OAFY3AwBqTsFMTk6GWq1GXl4eNm7ciN9++w06nQ4JCQn4+OOP5VuAEZFrBAQE4Pr16zY95+LFi+jWrRssFou8T61W44cffkDH+newus1722rw4MHyPWUBIC4uDm+++SaOHTsGIQS6du1q1d5sNiMsLAxAzU3ECwsLsXnzZvm4EAIWiwVGo1G+faE7couwF7eZd2vTpg327t3rpGqIyBYqlcrmm2Z37doVa9euxfTp01FdXQ21Wo333nuvQdA6m1qtxvHjx6Gudw/cwMBAADU3EZ8+fTpefPHFBs/t1KmTU2psLbcIeyJSnueeew5jxoxBYWEhunTp4rSzcQ4fPtzgcWxsLPr27Yvq6mqUlpZi2LBhjT63X79+yM/PR5cuXZxRql251dk4RKQsUVFRiI+Pd+ppl0VFRUhNTcXp06exZcsW/Otf/8KcOXPQtWtXPP3005g8eTJ27NgBo9GInJwcLF++XL40y7x583Do0CHMnDkTubm5KCgowK5duzB79myn1d9aHNkTkaJMnjwZlZWVeOCBB6BWqzF79mxMmzYNQM064ZIlS/Dyyy/j4sWLCAsLQ1xcHB5++GEAQK9evWAwGPDKK69g2LBhEELgnnvusfockLviDceJyCa84bjz8YbjRETUIgx7IiIFYNgTESkAw56ISAEY9kTUKgo6t8Pl7PGzZtgTkU38/PwAADdu3HBxJcpR+7Ou/dm3Bs+zJyKbqNVqhISEyHeKCwgIsLrWDNmPEAI3btxAaWkpQkJCGlzGwRYMeyKyWe29oG93a1Cyj5CQkDu+/zbDnohsplKpoNPpEB4ejps3b7q6HK/m5+d3RyP6Wgx7Imo1tVptlyAix+MCLRGRAjDsiYgUgGFPRKQADHsiIgVg2BMRKQDDnohIAdwi7NPS0jBw4EAEBQUhPDwcY8eOxenTp63aCCGwaNEiREZGok2bNoiPj0d+fr6LKiYi8ixuEfYGgwEzZ87E4cOHkZmZiVu3biExMREVFRVymxUrVmDlypVYs2YNcnJyoNVqMXr0aJSXl7uwciIiz+CWtyW8fPkywsPDYTAYMHz4cAghEBkZiZSUFMybNw8AYDabERERgeXLl2P69Oktel3elpCIvI1H35awrKwMABAaGgoAMBqNKCkpQWJiotxGkiSMGDEC2dnZTb6O2WyGyWSy2oiIlMjtwl4IgdTUVAwdOhQ9e/YEAJSUlAAAIiIirNpGRETIxxqTlpYGjUYjb3q93nGFk2NUVwNZWcCWLTVfq6tdXRGRR3K7sJ81axZOnjyJLVu2NDhW/zKqQohmL606f/58lJWVyVtRUZHd6yUH2rED6NwZSEgAJk6s+dq5c81+IrKJW4X97NmzsWvXLuzfvx9RUVHy/tpLe9YfxZeWljYY7dclSRKCg4OtNvIQO3YATzwBXLhgvf/ixZr9DHwim7hF2AshMGvWLOzYsQP79u1DTEyM1fGYmBhotVpkZmbK+6qqqmAwGDBkyBBnl0uOVl0NzJkDNHbuQO2+lBRO6RDZwC0ucTxz5kx89NFH+OyzzxAUFCSP4DUaDdq0aQOVSoWUlBQsXboUsbGxiI2NxdKlSxEQEICJEye6uHqyu2++aTiir0sIoKiopl18vNPKIvJkbhH26enpAID4ev9w161bh+TkZADA3LlzUVlZiRdeeAHXrl3DoEGDkJGRgaCgICdXSw5XXGzfdkTknufZOwrPs/cQWVk1i7G3s38/R/akeB59nj0p3LBhQFQU0NSZVioVoNfXtCOiFmHYk/tRq4HVq2u+rx/4tY9XrappR0QtwrAn9zRuHLBtG9Cxo/X+qKia/ePGuaYuIg/lFgu0RI0aNw54/PGas26KiwGdrmbqhiN6Ipsx7Mm9qdVchCWyA07jEBEpAMOeiEgBGPZERArAsCciUgCGPRGRAjDsiYgUgGFPRKQADHsiIgVg2BMRKQDDnohIARj2REQKwLAnIlIAhj0RkQIw7ImIFMBtwv7AgQN47LHHEBkZCZVKhU8//dTqeHJyMlQqldU2ePBg1xRLRORh3CbsKyoq0Lt3b6xZs6bJNg899BCKi4vlbffu3U6skIjIc7nNzUuSkpKQlJTUbBtJkqDVap1UERGR93CbkX1LZGVlITw8HF27dsXUqVNRWlrabHuz2QyTyWS1EREpkceEfVJSEjZv3ox9+/bhzTffRE5ODkaOHAmz2dzkc9LS0qDRaORNr9c7sWIiIvehEkIIVxdRn0qlws6dOzF27Ngm2xQXFyM6Ohpbt27FuHHjGm1jNputfhmYTCbo9XqUlZUhODjY3mUTETmdyWSCRqO5ba65zZy9rXQ6HaKjo1FQUNBkG0mSIEmSE6siInJPHjONU9/Vq1dRVFQEnU7n6lKIiNye24zsr1+/jsLCQvmx0WhEbm4uQkNDERoaikWLFuHPf/4zdDodzp07hwULFqB9+/b405/+5MKqiYg8g9uE/bFjx5CQkCA/Tk1NBQBMmTIF6enpyMvLw8aNG/Hbb79Bp9MhISEBH3/8MYKCglxVMhGRx3DLBVpHaelCBhGRp2hprnnsnD0REbUcw56ISAEY9kRECsCwJyJSAIY9EZECMOyJiBSAYU9EpAAMeyIiBWDYExEpAMOeiEgBbA775ORkHDhwwBG1EBGRg9gc9uXl5UhMTERsbCyWLl2KixcvOqIuIiKyI5vDfvv27bh48SJmzZqFTz75BJ07d0ZSUhK2bduGmzdvOqJGIiK6Q62asw8LC8OcOXNw4sQJHD16FF26dMGkSZMQGRmJl156qdm7RxERkfPd0QJtcXExMjIykJGRAbVajYcffhj5+fno3r073nrrLXvVSEREd8jmsL958ya2b9+ORx99FNHR0fjkk0/w0ksvobi4GBs2bEBGRgY2bdqExYsXO6JeIiJqBZvvVKXT6WCxWPDUU0/h6NGj6NOnT4M2Y8aMQUhIiB3KIyIie7A57N966y2MHz8ed911V5Nt2rVrB6PReEeFERGR/dgc9pMmTXJEHURE5EBu8wnaAwcO4LHHHkNkZCRUKhU+/fRTq+NCCCxatAiRkZFo06YN4uPjkZ+f75piiYg8jNuEfUVFBXr37o01a9Y0enzFihVYuXIl1qxZg5ycHGi1WowePRrl5eVOrpSIyPPYPI3jKElJSUhKSmr0mBACq1atwiuvvIJx48YBADZs2ICIiAh89NFHmD59ujNLJSLyOG4zsm+O0WhESUkJEhMT5X2SJGHEiBHIzs5u8nlmsxkmk8lqIyJSIo8I+5KSEgBARESE1f6IiAj5WGPS0tKg0WjkTa/XO7ROIiJ35RFhX0ulUlk9FkI02FfX/PnzUVZWJm9FRUWOLpGIyC25zZx9c7RaLYCaEb5Op5P3l5aWNhjt1yVJEiRJcnh9RETuziNG9jExMdBqtcjMzJT3VVVVwWAwYMiQIS6sjIjIM7jNyP769esoLCyUHxuNRuTm5iI0NBSdOnVCSkoKli5ditjYWPla+gEBAZg4caILqyYi8gxuE/bHjh1DQkKC/Dg1NRUAMGXKFKxfvx5z585FZWUlXnjhBVy7dg2DBg1CRkYGgoKCXFUyEZHHUAkhhKuLcBaTyQSNRoOysjIEBwe7uhwiojvW0lzziDl7IiK6Mwx7IiI3cOHCBezfvx8XLlxwyOu7zZw9EZESWCwWXLt2DZcvX8aVK1dw+fJl7Ny5Ex9++CGEEPDx8cHatWvx3HPP2fV9OWdPRISakXVBQQFiY2MRFRXV4ueZzWY5tOsGeN3v6+67evUqLBZLs6+pVqtx7ty5FtXR0lzjyJ6IFO/f//43pk2bBovFAh8fHyxZsgQJCQlNhnfd71t75V2NRoMOHTrAz88Pp06dsjpWXV2NwsJCm37p3A7Dnoi81q1bt3D16tVmQ/vChQv49ttv5edYLBYsWLDApvdRq9Vo3749OnTogA4dOtz2+7CwMPj7+wOo+R9FdHS01WhfrVajS5cu9vkh/B+GPRG5jdtNpVRUVNx2pF33+2vXrrW6loiICOj1+haFd0hISLPX6WpOVFQU1q5di+nTp6O6uhpqtRrvvfeeXUf1AOfsichF6i9UbtmyBenp6fIFDh944AGEhIRYhXdlZaXN76NSqRAaGtpkUPv4+CAlJQV1o9CWOXN7uXDhAgoLC9GlSxeb3pdz9kTUKvZYqGzJ6Lu5hUohBI4cOdLoMX9/fzmwmwrwuvtCQ0OhVqubrb1t27YOH1nfTlRUlEPfkyN7IpK5aqGybdu2uHTpUoNj8+bNw7Bhw6wCPDAwsNVTJs1p7cja1Vqaawx7IgVozUJla9RdqGzJgmXtQmVTi5TOnkrxRJzGIfJQLZlGqaioaPI8bmcvVNbdp9Fo4ONj+wfznbVIqWQc2RO5WN2FynXr1uGNN96QFylHjRqFiIiIBgHurQuVnjqV4koc2RPdgdYuUgIt+0Rl3e+bWqgUQuDrr79u8n3qLlS2ZMrEExYqHb1IqWQc2RPVU3+RctWqVUhKSmrxR+Jbu1DZtm1bVFRUNNg/ffp0DB48uEF4c6GSAC7QNophT7dbqPz555/x+eef3/H7NLZQ2dzou3379igtLeUiJdmM0zjk8Vq6UOmMT1RKkgStVtviKZPWLFRykZIciSN7cht1FyrXr1+PFStWWC1UarXaBuFtr4XK2q9+fn5YvHgxFynJY3BkT3fsThYpgaYXKm39ROXtFiolSWrxdElLFir1ej0XKcnrcGRPjaq/SPnee+9h/PjxNp3bbe+FyhkzZmDw4MENAtwRC5UcXZOn8LoF2kWLFuG1116z2hcREYGSkpIWvwbD/v+ru1BZP8CNRiPWr19vl/dpzaVfuVBJ1HJeOY3To0cPq//O3+6cYW/Q0qkUZy1Utm3b1qbwbs2lX7lQSWR/HhX2vr6+0Gq1ri7D4WoXKtPT07Fw4UJYLBaoVCqMHTsW0dHRjQb4nSxU1g9pSZLw9ttvN1ikPHXqFGJjY+3Z1SY999xzGDNmDKdSiOzEo8K+oKAAkZGRkCQJgwYNwtKlS3H33Xc32d5sNsNsNsuPTSZTq97XUQuVttyjUgiBnTt3Nvs+tnyisn379ggNDYWvb+N/Bfr06dNgZO2soK/FhUoi+/GYOfuvvvoKN27cQNeuXfHLL79gyZIl+PHHH5Gfn4+wsLBGn9PYPD8Am+bsW7JQ6ahPVDZmwoQJ6NevX6NBbu+FSi5SErk/r1ugra+iogL33HMP5s6di9TU1EbbNDay1+v1LQ77xi672lq2fqLy999/R2xsLBcpiahZXrlAW1fbtm1x//33o6CgoMk2kiRBkqRWv0dBQUGTQV93odJRn6jkIiUR2YvHhr3ZbMapU6cwbNgwh71HbGwsfHx8GoyunbVQyUVKIrIX2+8y4CJ/+ctfYDAYYDQaceTIETzxxBMwmUyYMmWKw96z9hTA2lM8XbFQGRUVhfj4eAY9Ed0RjxnZX7hwAU899RSuXLmCDh06YPDgwTh8+DCio6Md+r4cXRORN/DYBdrW4CdoicjbtDTXPGYah4iIWo9hT0SkAAx7IiIFYNgTESkAw56ISAEY9kRECsCwJyJSAIY9EZECMOyJiBSAYU9EpAAMeyIiBWDYExEpAMOeiEgBGPZERArAsCciUgCGPRGRAjDsiYgUgGFPRKQADHsiIgXwuLB/5513EBMTg7vuugv9+/fHN9984+qSiIjcnkeF/ccff4yUlBS88sorOHHiBIYNG4akpCScP3/e1aUREbk1lRBCuLqIlho0aBD69euH9PR0eV+3bt0wduxYpKWl3fb5Lb0LOxGRp2hprnnMyL6qqgrHjx9HYmKi1f7ExERkZ2c3+hyz2QyTyWS1EREpkceE/ZUrV1BdXY2IiAir/RERESgpKWn0OWlpadBoNPKm1+udUSoRkdvxmLCvpVKprB4LIRrsqzV//nyUlZXJW1FRkTNKJCJyO76uLqCl2rdvD7Va3WAUX1pa2mC0X0uSJEiS5IzyiIjcmseM7P39/dG/f39kZmZa7c/MzMSQIUNcVBURkWfwmJE9AKSmpmLSpEkYMGAA4uLisHbtWpw/fx4zZsxwdWlERG7No8L+ySefxNWrV7F48WIUFxejZ8+e2L17N6Kjo11dGhGRW/Oo8+zvFM+zJyJv43Xn2RMRUesx7ImIFIBhT0SkAAx7IiIFYNgTESkAw56ISAEY9kRECsCwJyJSAIY9EZECMOyJiBSAYU9EpAAMeyIiBWDYExEpAMOeiEgBGPZERArAsCciUgCGPRGRAjDsiYgUgGFPRKQAHhP2nTt3hkqlstr+9re/ubosIiKP4OvqAmyxePFiTJ06VX4cGBjowmqIiDyHR4V9UFAQtFqtq8sgIvI4HjONAwDLly9HWFgY+vTpg9dffx1VVVXNtjebzTCZTFYbEZESeczIfs6cOejXrx/atWuHo0ePYv78+TAajfjggw+afE5aWhpee+01J1ZJROSeVEII4ao3X7Ro0W3DOCcnBwMGDGiwf/v27XjiiSdw5coVhIWFNfpcs9kMs9ksPzaZTNDr9SgrK0NwcPCdFU9E5AZMJhM0Gs1tc82lI/tZs2ZhwoQJzbbp3Llzo/sHDx4MACgsLGwy7CVJgiRJd1QjEZE3cGnYt2/fHu3bt2/Vc0+cOAEA0Ol09iyJiMgrecSc/aFDh3D48GEkJCRAo9EgJycHL730Ev74xz+iU6dOri6PiMjteUTYS5KEjz/+GK+99hrMZjOio6MxdepUzJ0719WlERF5BI8I+379+uHw4cOuLoOIyGN51Hn2RETUOgx7IiIFYNgTESkAw56ISAEY9kRECsCwJyJSAI849dJeai8DxKtfEpG3qM2z213mTFFhX15eDgDQ6/UuroSIyL7Ky8uh0WiaPO7Sq146m8ViwaVLlxAUFASVSuXqcuyq9oqeRUVFirmip9L6rLT+Asrrc2v6K4RAeXk5IiMj4ePT9My8okb2Pj4+iIqKcnUZDhUcHKyIfxR1Ka3PSusvoLw+29rf5kb0tbhAS0SkAAx7IiIFYNh7CUmSsHDhQkXdrEVpfVZafwHl9dmR/VXUAi0RkVJxZE9EpAAMeyIiBWDYExEpAMOeiEgBGPYeJC0tDQMHDkRQUBDCw8MxduxYnD592qqNEAKLFi1CZGQk2rRpg/j4eOTn57uo4juXnp6OXr16yR8yiYuLw1dffSUf97b+1peWlgaVSoWUlBR5n7f1edGiRVCpVFabVquVj3tbf2tdvHgRzzzzDMLCwhAQEIA+ffrg+PHj8nG791uQxxgzZoxYt26d+P7770Vubq545JFHRKdOncT169flNsuWLRNBQUFi+/btIi8vTzz55JNCp9MJk8nkwspbb9euXeLLL78Up0+fFqdPnxYLFiwQfn5+4vvvvxdCeF9/6zp69Kjo3Lmz6NWrl5gzZ46839v6vHDhQtGjRw9RXFwsb6WlpfJxb+uvEEL8+uuvIjo6WiQnJ4sjR44Io9Eovv76a1FYWCi3sXe/GfYerLS0VAAQBoNBCCGExWIRWq1WLFu2TG7z+++/C41GI959911XlWl37dq1Ex988IFX97e8vFzExsaKzMxMMWLECDnsvbHPCxcuFL179270mDf2Vwgh5s2bJ4YOHdrkcUf0m9M4HqysrAwAEBoaCgAwGo0oKSlBYmKi3EaSJIwYMQLZ2dkuqdGeqqursXXrVlRUVCAuLs6r+ztz5kw88sgjePDBB632e2ufCwoKEBkZiZiYGEyYMAFnz54F4L393bVrFwYMGIDx48cjPDwcffv2xfvvvy8fd0S/GfYeSgiB1NRUDB06FD179gQAlJSUAAAiIiKs2kZERMjHPFFeXh4CAwMhSRJmzJiBnTt3onv37l7b361bt+J///sf0tLSGhzzxj4PGjQIGzduxN69e/H++++jpKQEQ4YMwdWrV72yvwBw9uxZpKenIzY2Fnv37sWMGTPw4osvYuPGjQAc8+esqKteepNZs2bh5MmTOHjwYINj9S/fLITw6Es633vvvcjNzcVvv/2G7du3Y8qUKTAYDPJxb+pvUVER5syZg4yMDNx1111NtvOmPiclJcnf33///YiLi8M999yDDRs2YPDgwQC8q79AzeXWBwwYgKVLlwIA+vbti/z8fKSnp2Py5MlyO3v2myN7DzR79mzs2rUL+/fvt7pkc+0ZDPV/85eWljYYIXgSf39/dOnSBQMGDEBaWhp69+6N1atXe2V/jx8/jtLSUvTv3x++vr7w9fWFwWDAP//5T/j6+sr98qY+19e2bVvcf//9KCgo8Mo/YwDQ6XTo3r271b5u3brh/PnzABzzb5lh70GEEJg1axZ27NiBffv2ISYmxup4TEwMtFotMjMz5X1VVVUwGAwYMmSIs8t1GCEEzGazV/Z31KhRyMvLQ25urrwNGDAATz/9NHJzc3H33Xd7XZ/rM5vNOHXqFHQ6nVf+GQPAH/7whwanTZ85cwbR0dEAHPRvuVXLuuQSzz//vNBoNCIrK8vqNLUbN27IbZYtWyY0Go3YsWOHyMvLE0899ZRHn6Y2f/58ceDAAWE0GsXJkyfFggULhI+Pj8jIyBBCeF9/G1P3bBwhvK/PL7/8ssjKyhJnz54Vhw8fFo8++qgICgoS586dE0J4X3+FqDmt1tfXV7z++uuioKBAbN68WQQEBIgPP/xQbmPvfjPsPQiARrd169bJbSwWi1i4cKHQarVCkiQxfPhwkZeX57qi79Czzz4roqOjhb+/v+jQoYMYNWqUHPRCeF9/G1M/7L2tz7Xnj/v5+YnIyEgxbtw4kZ+fLx/3tv7W+vzzz0XPnj2FJEnivvvuE2vXrrU6bu9+8xLHREQKwDl7IiIFYNgTESkAw56ISAEY9kRECsCwJyJSAIY9EZECMOyJiBSAYU9EpAAMeyIiBWDYExEpAMOeyE4uX74MrVYrX6McAI4cOQJ/f39kZGS4sDIigNfGIbKj3bt3Y+zYscjOzsZ9992Hvn374pFHHsGqVatcXRopHMOeyM5mzpyJr7/+GgMHDsR3332HnJycZu86ReQMDHsiO6usrETPnj1RVFSEY8eOoVevXq4uiYhz9kT2dvbsWVy6dAkWiwU///yzq8shAsCRPZFdVVVV4YEHHkCfPn1w3333YeXKlcjLy/Po+6WSd2DYE9nRX//6V2zbtg3fffcdAgMDkZCQgKCgIHzxxReuLo0UjtM4RHaSlZWFVatWYdOmTQgODoaPjw82bdqEgwcPIj093dXlkcJxZE9EpAAc2RMRKQDDnohIARj2REQKwLAnIlIAhj0RkQIw7ImIFIBhT0SkAAx7IiIFYNgTESkAw56ISAEY9kRECsCwJyJSgP8HG74xE3Q9X3cAAAAASUVORK5CYII=",
"text/plain": [
"<Figure size 400x300 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# position of flower in 2D\n",
"flower = np.array([29.1, 19.1])\n",
"\n",
"def make_bee_track(t):\n",
" \"\"\"Find bee position at time t\"\"\"\n",
" pos0 = (13.21, 4.56)\n",
" velocity = (3.1, 0.25)\n",
" pos_x = pos0[0] + t*velocity[0]\n",
" pos_y = pos0[1] + t*velocity[1]\n",
" return np.array([pos_x,pos_y])\n",
"\n",
"t = np.linspace(0,15,10)\n",
"bee_track = make_bee_track(t)\n",
"\n",
"fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(4,3))\n",
"ax.plot( [flower[0]], [flower[1]], 'or', label='flower' )\n",
"ax.plot( bee_track[0], bee_track[1], '.-k', label='bee')\n",
"ax.axis('equal')\n",
"ax.legend()\n",
"ax.set_xlabel('x')\n",
"ax.set_ylabel('y')\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the above code, we *parameterized* the bee trajectory by the variable `t` in the function `make_bee_track()`. This means we could get a new point on the track by choosing a new value of `t`. For example:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[13.21 4.56]\n",
"[13.52 4.585]\n",
"[13.83 4.61]\n",
"[16.31 4.81]\n"
]
}
],
"source": [
"print(make_bee_track(0.0))\n",
"print(make_bee_track(0.1))\n",
"print(make_bee_track(0.2))\n",
"print(make_bee_track(1.0))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's measure the distance between the bee and the flower."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([21.5384238 , 17.73297556, 14.79017429, 13.29572112, 13.73095975,\n",
" 15.93858282, 19.32029244, 23.37188672, 27.80202491, 32.45606569])"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Text(0, 0.5, 'distance')"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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",
"text/plain": [
"<Figure size 400x300 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def compute_distance(a,b):\n",
" a = np.array(a)\n",
" b = np.array(b)\n",
" return np.sqrt(np.sum((a-b)**2))\n",
"\n",
"n_time_steps = bee_track.shape[1]\n",
"distance = np.zeros(n_time_steps)\n",
"for i in range(n_time_steps):\n",
" bee_pos = bee_track[:,i]\n",
" distance[i] = compute_distance(bee_pos, flower)\n",
"display(distance)\n",
"\n",
"fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(4,3))\n",
"ax.plot( t, distance )\n",
"ax.set_xlabel('t')\n",
"ax.set_ylabel('distance')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Given the plot of distance versus t above, we can see the distance is minimized when t is near 5. What is the bee's position when t is 5?"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[28.71 5.81]\n"
]
}
],
"source": [
"print(make_bee_track(5))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can check back to the xy plot to see, indeed, this point is pretty close to the flower.\n",
"\n",
"What if we want to know, however, exactly the closest point? There are several ways to find this. Here we are going to use a \"brute force\" approach which will work on many different problems. Specifically, we will use [scipy.optimize.minimize_scalar](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize_scalar.html). The overall idea of this kind of *numerical optimization* is that we find the best fitting parameter to minimize our \"error\".\n",
"\n",
"In this example, we are not so much concerned with the exact algorithm being used, but with the way we call this algorithm.\n",
"\n",
"Let's create a function which uses the `flower` location to compute distance:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"def calc_distance_func(t):\n",
" # assume variable 'flower' in our global scope\n",
" # calculate bee position (also assuming 'make_bee_track' in scope)\n",
" dist = compute_distance(flower, make_bee_track(t))\n",
" print(f't: {t} -> dist: {dist}')\n",
" return dist"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"t: 0 -> dist: 21.538423804912004\n"
]
},
{
"data": {
"text/plain": [
"21.538423804912004"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"calc_distance_func(0)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"t: 5 -> dist: 13.295721116208782\n"
]
},
{
"data": {
"text/plain": [
"13.295721116208782"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"calc_distance_func(5)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"t: 0.0 -> dist: 21.538423804912004\n",
"t: 1.0 -> dist: 19.17780487959975\n",
"t: 2.6180339999999998 -> dist: 15.913623755962107\n",
"t: 9.502603885705089 -> dist: 18.222622377854467\n",
"t: 5.24770562096323 -> dist: 13.233470063982764\n",
"t: 6.8729320915536185 -> dist: 13.918754747176704\n",
"t: 5.437736318938615 -> dist: 13.215989304828\n",
"t: 5.47123644934229 -> dist: 13.215645882055249\n",
"t: 5.468503780784455 -> dist: 13.215643128079853\n",
"t: 5.468493134264144 -> dist: 13.2156431280385\n",
"t: 5.468493215207842 -> dist: 13.215643128038504\n",
"t: 5.468493053320446 -> dist: 13.215643128038506\n"
]
}
],
"source": [
"import scipy.optimize\n",
"result = scipy.optimize.minimize_scalar(calc_distance_func)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
" message: \n",
" Optimization terminated successfully;\n",
" The returned value satisfies the termination criteria\n",
" (using xtol = 1.48e-08 )\n",
" success: True\n",
" fun: 13.2156431280385\n",
" x: 5.468493134264144\n",
" nit: 8\n",
" nfev: 12"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"result"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\u001b[0;31mSignature:\u001b[0m\n",
"\u001b[0mscipy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moptimize\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mminimize_scalar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0mfun\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0mbracket\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0mbounds\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0mtol\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m \u001b[0moptions\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n",
"\u001b[0;34m\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mDocstring:\u001b[0m\n",
"Local minimization of scalar function of one variable.\n",
"\n",
"Parameters\n",
"----------\n",
"fun : callable\n",
" Objective function.\n",
" Scalar function, must return a scalar.\n",
"bracket : sequence, optional\n",
" For methods 'brent' and 'golden', `bracket` defines the bracketing\n",
" interval and is required.\n",
" Either a triple ``(xa, xb, xc)`` satisfying ``xa < xb < xc`` and\n",
" ``func(xb) < func(xa) and func(xb) < func(xc)``, or a pair\n",
" ``(xa, xb)`` to be used as initial points for a downhill bracket search\n",
" (see `scipy.optimize.bracket`).\n",
" The minimizer ``res.x`` will not necessarily satisfy\n",
" ``xa <= res.x <= xb``.\n",
"bounds : sequence, optional\n",
" For method 'bounded', `bounds` is mandatory and must have two finite\n",
" items corresponding to the optimization bounds.\n",
"args : tuple, optional\n",
" Extra arguments passed to the objective function.\n",
"method : str or callable, optional\n",
" Type of solver. Should be one of:\n",
"\n",
" - :ref:`Brent <optimize.minimize_scalar-brent>`\n",
" - :ref:`Bounded <optimize.minimize_scalar-bounded>`\n",
" - :ref:`Golden <optimize.minimize_scalar-golden>`\n",
" - custom - a callable object (added in version 0.14.0), see below\n",
"\n",
" Default is \"Bounded\" if bounds are provided and \"Brent\" otherwise.\n",
" See the 'Notes' section for details of each solver.\n",
"\n",
"tol : float, optional\n",
" Tolerance for termination. For detailed control, use solver-specific\n",
" options.\n",
"options : dict, optional\n",
" A dictionary of solver options.\n",
"\n",
" maxiter : int\n",
" Maximum number of iterations to perform.\n",
" disp : bool\n",
" Set to True to print convergence messages.\n",
"\n",
" See :func:`show_options()` for solver-specific options.\n",
"\n",
"Returns\n",
"-------\n",
"res : OptimizeResult\n",
" The optimization result represented as a ``OptimizeResult`` object.\n",
" Important attributes are: ``x`` the solution array, ``success`` a\n",
" Boolean flag indicating if the optimizer exited successfully and\n",
" ``message`` which describes the cause of the termination. See\n",
" `OptimizeResult` for a description of other attributes.\n",
"\n",
"See also\n",
"--------\n",
"minimize : Interface to minimization algorithms for scalar multivariate\n",
" functions\n",
"show_options : Additional options accepted by the solvers\n",
"\n",
"Notes\n",
"-----\n",
"This section describes the available solvers that can be selected by the\n",
"'method' parameter. The default method is the ``\"Bounded\"`` Brent method if\n",
"`bounds` are passed and unbounded ``\"Brent\"`` otherwise.\n",
"\n",
"Method :ref:`Brent <optimize.minimize_scalar-brent>` uses Brent's\n",
"algorithm [1]_ to find a local minimum. The algorithm uses inverse\n",
"parabolic interpolation when possible to speed up convergence of\n",
"the golden section method.\n",
"\n",
"Method :ref:`Golden <optimize.minimize_scalar-golden>` uses the\n",
"golden section search technique [1]_. It uses analog of the bisection\n",
"method to decrease the bracketed interval. It is usually\n",
"preferable to use the *Brent* method.\n",
"\n",
"Method :ref:`Bounded <optimize.minimize_scalar-bounded>` can\n",
"perform bounded minimization [2]_ [3]_. It uses the Brent method to find a\n",
"local minimum in the interval x1 < xopt < x2.\n",
"\n",
"Note that the Brent and Golden methods do not guarantee success unless a\n",
"valid ``bracket`` triple is provided. If a three-point bracket cannot be\n",
"found, consider `scipy.optimize.minimize`. Also, all methods are intended\n",
"only for local minimization. When the function of interest has more than\n",
"one local minimum, consider :ref:`global_optimization`.\n",
"\n",
"**Custom minimizers**\n",
"\n",
"It may be useful to pass a custom minimization method, for example\n",
"when using some library frontend to minimize_scalar. You can simply\n",
"pass a callable as the ``method`` parameter.\n",
"\n",
"The callable is called as ``method(fun, args, **kwargs, **options)``\n",
"where ``kwargs`` corresponds to any other parameters passed to `minimize`\n",
"(such as `bracket`, `tol`, etc.), except the `options` dict, which has\n",
"its contents also passed as `method` parameters pair by pair. The method\n",
"shall return an `OptimizeResult` object.\n",
"\n",
"The provided `method` callable must be able to accept (and possibly ignore)\n",
"arbitrary parameters; the set of parameters accepted by `minimize` may\n",
"expand in future versions and then these parameters will be passed to\n",
"the method. You can find an example in the scipy.optimize tutorial.\n",
"\n",
".. versionadded:: 0.11.0\n",
"\n",
"References\n",
"----------\n",
".. [1] Press, W., S.A. Teukolsky, W.T. Vetterling, and B.P. Flannery.\n",
" Numerical Recipes in C. Cambridge University Press.\n",
".. [2] Forsythe, G.E., M. A. Malcolm, and C. B. Moler. \"Computer Methods\n",
" for Mathematical Computations.\" Prentice-Hall Series in Automatic\n",
" Computation 259 (1977).\n",
".. [3] Brent, Richard P. Algorithms for Minimization Without Derivatives.\n",
" Courier Corporation, 2013.\n",
"\n",
"Examples\n",
"--------\n",
"Consider the problem of minimizing the following function.\n",
"\n",
">>> def f(x):\n",
"... return (x - 2) * x * (x + 2)**2\n",
"\n",
"Using the *Brent* method, we find the local minimum as:\n",
"\n",
">>> from scipy.optimize import minimize_scalar\n",
">>> res = minimize_scalar(f)\n",
">>> res.fun\n",
"-9.9149495908\n",
"\n",
"The minimizer is:\n",
"\n",
">>> res.x\n",
"1.28077640403\n",
"\n",
"Using the *Bounded* method, we find a local minimum with specified\n",
"bounds as:\n",
"\n",
">>> res = minimize_scalar(f, bounds=(-3, -1), method='bounded')\n",
">>> res.fun # minimum\n",
"3.28365179850e-13\n",
">>> res.x # minimizer\n",
"-2.0000002026\n",
"\u001b[0;31mFile:\u001b[0m ~/anaconda3/envs/pm21-dragon/lib/python3.11/site-packages/scipy/optimize/_minimize.py\n",
"\u001b[0;31mType:\u001b[0m function"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"scipy.optimize.minimize_scalar?"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
" message: \n",
" Optimization terminated successfully;\n",
" The returned value satisfies the termination criteria\n",
" (using xtol = 1.48e-08 )\n",
" success: True\n",
" fun: 13.2156431280385\n",
" x: 5.468493134264144\n",
" nit: 8\n",
" nfev: 12"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"result"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"scipy.optimize._optimize.OptimizeResult"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(result)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"5.468493134264144"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"result.x"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"t: 5 -> dist: 13.295721116208782\n",
"13.295721116208782\n"
]
}
],
"source": [
"print(calc_distance_func(5))"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"t: 5.468493134264144 -> dist: 13.2156431280385\n"
]
},
{
"data": {
"text/plain": [
"13.2156431280385"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"calc_distance_func(5.468493134264144)"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([30.16232872, 5.92712328])"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Where is the bee for this value of `t`?\n",
"make_bee_track(5.468493134264144)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Text(0, 0.5, 'y')"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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",
"text/plain": [
"<Figure size 400x300 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(4,3))\n",
"ax.plot( [flower[0]], [flower[1]], 'or', label='flower' )\n",
"ax.plot( bee_track[0], bee_track[1], '.-k', label='bee')\n",
"\n",
"x,y = make_bee_track(5.468493134264144)\n",
"ax.plot( [x], [y] ,'x', label='closest')\n",
"ax.axis('equal')\n",
"ax.legend()\n",
"ax.set_xlabel('x')\n",
"ax.set_ylabel('y')\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"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.11.10"
}
},
"nbformat": 4,
"nbformat_minor": 4
}