{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "deletable": false,
    "editable": false,
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Initialization cell\n",
    "try:  # for CS1302 JupyterLite pyodide kernel\n",
    "    import piplite\n",
    "\n",
    "    with open(\"requirements.txt\") as f:\n",
    "        for package in f:\n",
    "            package = package.strip()\n",
    "            print(\"Installing\", package)\n",
    "            await piplite.install(package)\n",
    "except ModuleNotFoundError:\n",
    "    pass\n",
    "\n",
    "import math\n",
    "import jupytext\n",
    "import numpy as np\n",
    "import otter\n",
    "from ipywidgets import interact\n",
    "\n",
    "grader = otter.Notebook(\"main.ipynb\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Lab 3a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    },
    "tags": [
     "remove-cell"
    ]
   },
   "source": [
    "**CS1302 Introduction to Computer Programming**\n",
    "___"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-13T01:19:41.712043Z",
     "start_time": "2020-09-13T01:19:41.704733Z"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "In this notebook, we will improve the quadratic equation solver in the previous lab using conditional executions."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Discriminant"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Recall that a quadratic equation is\n",
    "\n",
    "$$\n",
    "ax^2+bx+c=0\n",
    "$$\n",
    "\n",
    "where $a$, $b$, and $c$ are real-valued coefficients, and $x$ is the unknown variable."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "**Definition** (Discriminant)\n",
    "\n",
    "The disciminant of a quadratic equation is defined as\n",
    "\n",
    "$$\n",
    "\\Delta := b^2 - 4ac.\n",
    "$$ (discriminant)\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The discriminant $\\Delta$ discriminates the roots \n",
    "\n",
    "$$\\frac{-b\\pm \\sqrt{\\Delta}}{2a}$$ (roots)\n",
    "\n",
    "of a quadratic equation:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "---\n",
    "\n",
    "**Proposition**\n",
    "\n",
    "The roots of a quadratic equation {eq}`quadratic` are both equal to \n",
    "\n",
    "$$-\\frac{b}{2a}$$ (repeated root)\n",
    "\n",
    "if and only if the discriminant is zero, i.e., $\\Delta=0$.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For example, if $(a,b,c)=(1,-2,1)$, then \n",
    "\n",
    "$$\\Delta = (-2)^2 - 4(1\\cdot 1) = 0$$\n",
    "\n",
    "and so the repeated root is\n",
    "\n",
    "$$\n",
    "- \\frac{b}{2a} = \\frac{2}2 = 1.\n",
    "$$\n",
    "\n",
    "$(x-1)^2 = x^2 - 2x + 1$ as expected."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    },
    "tags": []
   },
   "source": [
    "**Exercise**  (zero-determinant)\n",
    "\n",
    "Complete the following function by assigning `roots` only one root when the discriminant is zero. E.g., if `(a, b, c) == (1, -2, 1)`, then `roots` should be assigned the value `1.0` instead of `1.0, 1.0`.\n",
    "\n",
    "```{note}\n",
    "Replace `...` in the following code cell by your code. If you have a better implementation, you need *not* follow the solution template. E.g., you can write your solution entirely using boolean operations without any `if` statement.\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "deletable": false,
    "editable": false,
    "tags": []
   },
   "outputs": [],
   "source": [
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-20T14:26:27.169016Z",
     "start_time": "2021-03-20T14:26:27.165022Z"
    },
    "nbgrader": {
     "grade": false,
     "grade_id": "zero_determininant",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "slideshow": {
     "slide_type": "fragment"
    },
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "def get_roots(a, b, c):\n",
    "    d = b ** 2 - 4 * a * c  # discriminant\n",
    "    if math.isclose(d, 0):\n",
    "        roots = (-b+d**0.5)/2/a  # repeated root\n",
    "    else:\n",
    "        d **= 0.5\n",
    "        roots = (-b-d**0.5)/2/a , (-b+d**0.5)/2/a  # distinct roots\n",
    "    return roots"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<p><strong><pre style='display: inline;'>zero-determinant</pre></strong> passed!</p>"
      ],
      "text/plain": [
       "zero-determinant results: All test cases passed!"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grader.check(\"zero-determinant\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "**Exercise** (isclose)\n",
    "\n",
    "Why use `math.isclose(d, 0)` instead of `d == 0`?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "floating error may occur when calculating discriminant and cause it not equal to 0 when it should be."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Linear equation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise** (zero-a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Give the name of the error that the formula {eq}`roots` implemented in python would when $a=0$. Explain whether it is a runtime error or not."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "ZeroDivisionError. It is a runtime error as denominator 2a is equal to 0."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nevertheless, the quadratic equation remains valid:\n",
    "\n",
    "$$\n",
    "bx + c=0,\n",
    "$$\n",
    "\n",
    "the root of which is $x = -\\frac{c}b$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise** (linear)\n",
    "\n",
    "Improve the function `get_roots` to return the root $-\\frac{c}{b}$ when $a=0$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false,
    "tags": []
   },
   "outputs": [],
   "source": [
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-20T14:26:30.430592Z",
     "start_time": "2021-03-20T14:26:30.426171Z"
    },
    "nbgrader": {
     "grade": false,
     "grade_id": "linear",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "def get_roots(a, b, c):\n",
    "    d = b**2 - 4 * a * c  # discriminant\n",
    "    if a == 0 :  # linear equation\n",
    "        roots = -c/b\n",
    "    elif math.isclose(d, 0):\n",
    "        roots = (-b+d**0.5)/2/a  # repeated root\n",
    "    else:\n",
    "        d **= 0.5\n",
    "        roots = (-b-d**0.5)/2/a , (-b+d**0.5)/2/a  # distinct roots\n",
    "    return roots"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<p><strong><pre style='display: inline;'>linear</pre></strong> passed!</p>"
      ],
      "text/plain": [
       "linear results: All test cases passed!"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grader.check(\"linear\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Degenerate cases"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What if $a=b=0$? In this case, the equation becomes\n",
    "\n",
    "$$\n",
    "c = 0\n",
    "$$\n",
    "which is always satisfied if $c=0$ but never satisfied if $c\\neq 0$. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "**Exercise** (degenerate)\n",
    "\n",
    "Improve the function `get_roots` to return root(s) under all the following cases:\n",
    "- If $a=0$ and $b\\neq 0$, assign `roots` to the single root $-\\frac{c}{b}$. \n",
    "- If $a=b=0$ and $c\\neq 0$, assign `roots` to `None`.\n",
    "- If $a=b=c=0$, there are infinitely many roots. Assign to `roots` the tuple `-float('inf'), float('inf')`.  \n",
    "    Note that `float('inf')` converts the string `'inf'` to a floating point value that represents $\\infty$.\n",
    "    \n",
    "```{caution}\n",
    "- `None` a *python keyword* that refers to a special object. You should *NOT* regard it as a string or quote it. (~~`\"None\"`~~).\n",
    "- `float('inf')` converts the string `'inf'` to a floating point number no smaller than any other floating point numbers. You should *NOT* write `inf`, which needs not refer to `float('int')`.\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false,
    "tags": []
   },
   "outputs": [],
   "source": [
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-20T14:26:33.456700Z",
     "start_time": "2021-03-20T14:26:33.451234Z"
    },
    "nbgrader": {
     "grade": false,
     "grade_id": "degenerate",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "slideshow": {
     "slide_type": "skip"
    },
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "def get_roots(a, b, c):\n",
    "    d = b ** 2 - 4 * a * c\n",
    "    if a == 0:  # linear\n",
    "        if b == 0:  # degenerate\n",
    "            if c == 0:\n",
    "                roots = -float('inf'), float('inf')\n",
    "            else:  # no roots\n",
    "                roots = None\n",
    "        else:\n",
    "            roots = -c/b\n",
    "    elif math.isclose(d, 0):\n",
    "        roots = (-b+d**0.5)/2/a  # repeated root\n",
    "    else:\n",
    "        d **= 0.5\n",
    "        roots = (-b-d**0.5)/2/a , (-b+d**0.5)/2/a  # distinct roots\n",
    "    return roots"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "deletable": false,
    "editable": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<p><strong><pre style='display: inline;'>degenerate</pre></strong> passed!</p>"
      ],
      "text/plain": [
       "degenerate results: All test cases passed!"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grader.check(\"degenerate\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After you have complete the exercises, you can run your robust solver below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-03-20T14:26:37.374157Z",
     "start_time": "2021-03-20T14:26:37.344554Z"
    },
    "code_folding": [
     0
    ],
    "slideshow": {
     "slide_type": "-"
    },
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "219e5f5a59654785b8b59ddd47bb5eba",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(IntSlider(value=1, description='a', max=10, min=-10), IntSlider(value=2, description='b'…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# quadratic equations solver\n",
    "@interact(a=(-10, 10, 1), b=(-10, 10, 1), c=(-10, 10, 1))\n",
    "def quadratic_equation_solver(a=1, b=2, c=1):\n",
    "    print(\"Root(s):\", get_roots(a, b, c))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "editable": false,
    "tags": [
     "remove-cell"
    ]
   },
   "source": [
    "## Submission\n",
    "\n",
    "Make sure you have run all cells in your notebook in order before running the cell below, so that all images/graphs appear in the output. The cell below will generate a zip file for you to submit. **Please save before exporting!**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": true,
    "tags": []
   },
   "outputs": [],
   "source": [
    "# extra files to submit\n",
    "extra_files = []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false,
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Generate the source main.py necessary for grading and similarity check.\n",
    "jupytext.write(jupytext.read(\"main.ipynb\"), \"main.py\", fmt=\"py:percent\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "deletable": false,
    "editable": false,
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Generate the zip file to submit.\n",
    "grader.export(pdf=False, run_tests=False, files=[\"main.py\", *extra_files])"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Create Assignment",
  "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.10.6"
  },
  "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
  },
  "otter": {
   "OK_FORMAT": true,
   "tests": {
    "degenerate": {
     "name": "degenerate",
     "points": null,
     "suites": [
      {
       "cases": [
        {
         "code": ">>> import numpy as np\n>>> \n>>> assert np.isclose(get_roots(1, 1, 0), (-1.0, 0.0)).all()\n>>> assert np.isclose(get_roots(1, 0, 0), 0.0).all()\n>>> assert np.isclose(get_roots(1, -2, 1), 1.0).all()\n>>> assert np.isclose(get_roots(0, -2, 1), 0.5).all()\n>>> assert np.isclose(get_roots(0, 0, 0), (-float('inf'), float('inf'))).all()\n>>> assert get_roots(0, 0, 1) is None\n",
         "hidden": false,
         "locked": false
        }
       ],
       "scored": true,
       "setup": "",
       "teardown": "",
       "type": "doctest"
      }
     ]
    },
    "linear": {
     "name": "linear",
     "points": null,
     "suites": [
      {
       "cases": [
        {
         "code": ">>> import numpy as np\n>>> \n>>> assert np.isclose(get_roots(1, 1, 0), (-1.0, 0.0)).all()\n>>> assert np.isclose(get_roots(1, 0, 0), 0.0).all()\n>>> assert np.isclose(get_roots(1, -2, 1), 1.0).all()\n>>> assert np.isclose(get_roots(0, -2, 1), 0.5).all()\n",
         "hidden": false,
         "locked": false
        }
       ],
       "scored": true,
       "setup": "",
       "teardown": "",
       "type": "doctest"
      }
     ]
    },
    "zero-determinant": {
     "name": "zero-determinant",
     "points": null,
     "suites": [
      {
       "cases": [
        {
         "code": ">>> import numpy as np\n>>> \n>>> assert np.isclose(get_roots(1, 1, 0), (-1.0, 0.0)).all()\n>>> assert np.isclose(get_roots(1, 0, 0), 0.0).all()\n",
         "hidden": false,
         "locked": false
        }
       ],
       "scored": true,
       "setup": "",
       "teardown": "",
       "type": "doctest"
      }
     ]
    }
   }
  },
  "rise": {
   "enable_chalkboard": true,
   "scroll": true,
   "theme": "white"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {
    "height": "195px",
    "width": "330px"
   },
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": true,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "454.418px",
    "left": "1533px",
    "top": "110.284px",
    "width": "435.327px"
   },
   "toc_section_display": true,
   "toc_window_display": false
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {},
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
