{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "fe839e74-b29a-4474-bd76-040d5f1fefde",
   "metadata": {
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "# Theory 1\n",
    "## MSc Python Crash Course: Jupyter Notebooks, Logic, Control Structures, and Lambda Functions.\n",
    "\n",
    "MSc MATLAB Crash Course Originally written by Nick Hale, Oct. 2013.\n",
    "Extended by Asgeir Birkisson, Oct. 2014, 2015.\n",
    "Modified by Behnam Hashemi and Hadrien Montanelli, Sep. 2016.\n",
    "Python Crash Course by Benjamin Walker, Oct. 2025.\n",
    "\n",
    "## Introduction\n",
    "\n",
    "A Jupyter Notebook is an interactive environment, which allows you to write and execute Python code in cells. It is a flexible tool, which allows you to include formatted text, \n",
    "$$\n",
    "e^{i \\pi} = -1, \n",
    "$$\n",
    "and visualisations all in one document. Jupyter lets you experiment with and rerun individual pieces of code while preserving all outputs, like plots, tables, and variable states. \n",
    "\n",
    "## Installation\n",
    "\n",
    "```\n",
    "$ conda install jupyter  # (Anaconda)\n",
    "$ pip install jupyter #  (VS Code)\n",
    "$ jupyter-lab\n",
    "```\n",
    "\n",
    "## Basic Key Bindings for Jupyter Notebooks\n",
    "\n",
    "To work efficiently in Jupyter Notebook, it's helpful to learn some basic key bindings that allow you to quickly add, delete, and format cells:\n",
    "\n",
    "Adding a Cell:\n",
    "- Press a to add a new cell above the current cell.\n",
    "- Press b to add a new cell below the current cell.\n",
    "\n",
    "Deleting a Cell:\n",
    "- Press d twice to delete the selected cell.\n",
    "\n",
    "Changing a Cell to Markdown:\n",
    "- Press m to convert the selected cell into a Markdown cell, where you can write formatted text, headings, lists, and more.\n",
    "- Press y to convert the selected cell back to a code cell.\n",
    "\n",
    "Running a Cell:\n",
    "- Press Shift + Enter to run the selected cell and move to the next one.\n",
    "- Press Ctrl + Enter to run the selected cell without moving to the next one.\n",
    "\n",
    "Command vs. Edit Mode:\n",
    "- Press Esc to enter Command Mode, where these key bindings work.\n",
    "- Press Enter to enter Edit Mode, where you can type code or text inside a cell.\n",
    "\n",
    "## Order of Cells\n",
    "\n",
    "In a Jupyter Notebook, the order in which you run the cells matters because the state of variables is preserved across cells. This means that the value of x can change depending on when and how you run each cell.\n",
    "\n",
    "The numbers in the square brackets to the left of each cell (e.g., [1], [2]) indicate the order in which the cells were executed. This helps you track the sequence of operations and understand the current state of your variables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "3cfe5d3f-cfd7-4a1a-9265-124ca5cdc28a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/home/gillowk/Latex/MSc/2026-27/Induction/Python_Intro/Intro2Py/bin/python3\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "print(sys.executable)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "3fee3879-e016-44a3-8519-ca317eebe291",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "abe8dd18-0052-43e7-bfed-d9db82187f12",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n"
     ]
    }
   ],
   "source": [
    "print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "37dca827-3004-49b5-b6e1-9e43f60ce9a6",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "cd18efe6-7ad8-4532-b5c2-bb7dc92f5b45",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "7\n"
     ]
    }
   ],
   "source": [
    "print(x + 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13747d27-26d1-4131-9635-3d8b36a81dae",
   "metadata": {},
   "source": [
    "## Logic\n",
    "\n",
    "A boolean variable has two possible states, denoted `True` and `False` in python. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "afe4e684-7987-4693-b891-fcff93b68005",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "0e704674-461d-43a3-8e54-af153c90033e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6df16799-898a-4def-a340-2866c9031293",
   "metadata": {},
   "source": [
    "`a == b` will return True is `a` and `b` are the same value, and False otherwise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "097a8fdb-2f50-4938-9f03-14c9ba137139",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "a = 5\n",
    "b = 5\n",
    "print(a == b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "e5b0ea06-3ec9-4131-9c24-0f9dbc83c5af",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n"
     ]
    }
   ],
   "source": [
    "b = 6\n",
    "print(a == b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "86f5d655-6d1c-4ab0-8ee8-024fe24466d1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "a = (1, 2, 4)\n",
    "b = \"hello\"\n",
    "c = (1, 2, 4)\n",
    "print(a == b)\n",
    "print(a == c)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "09b9222f-4c44-41e3-92c6-bc254a048008",
   "metadata": {},
   "source": [
    "Conversely, `a != b` will return True when `a` and `b` are different, and False otherwise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "5621cb5f-363a-4192-8738-9906eab22d0b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n"
     ]
    }
   ],
   "source": [
    "a = 5\n",
    "b = 5\n",
    "print(a != b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "d1c0333c-2de0-4030-b458-22abd2ee78ba",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "b = 6\n",
    "print(a != b)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3779ff48-3b1a-4d69-86b7-32d255f1aaa1",
   "metadata": {},
   "source": [
    "Python has `not` for inverting booleans, and `and` and `or` for combining booleans"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "43eb0d9a-a79b-4f7d-bd44-24c1a12a4721",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "False\n",
      "True\n",
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "print(not True) \n",
    "print(True and False)\n",
    "print(True or False)\n",
    "print(False or False)\n",
    "print(not (True and not (True or False))) "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e14dde8-9dd5-4b01-9975-d376c50df443",
   "metadata": {},
   "source": [
    "Python also has bitwise versions of `and`, `or`, and `not`, which are `&`, `|`, and `~` respectively. However, they can have some unexpected effects on boolean values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "a536b23c-e868-404a-bca3-db714b4e6a96",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "True\n",
      "-2\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_3075148/941954323.py:3: DeprecationWarning: Bitwise inversion '~' on bool is deprecated and will be removed in Python 3.16. This returns the bitwise inversion of the underlying int object and is usually not what you expect from negating a bool. Use the 'not' operator for boolean negation or ~int(x) if you really want the bitwise inversion of the underlying int.\n",
      "  print(~True)\n"
     ]
    }
   ],
   "source": [
    "print(True & False)\n",
    "print(True | False)\n",
    "print(~True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "03d844fb-e7b9-48fd-9c54-7521ecfedec6",
   "metadata": {},
   "source": [
    "Here is a hint:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "3fa24c61-6c43-45f6-a437-e4d662a44ca1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "True + True"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc5ac549-b753-4889-8177-5c522a1815d4",
   "metadata": {},
   "source": [
    "The comparison operators, `<`, `>`, `<=`, `>=`, behave as you would expect"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "dcb9194e-3113-4045-9872-1ceb8721031b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "import math as m\n",
    "\n",
    "print(5 < 8)\n",
    "print(m.pi ** m.e > m.e ** m.pi)\n",
    "print(3 <= 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "086e0435-fd52-46e2-82d2-f1ea9f4152b9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "[ True  True  True]\n",
      "True\n",
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "x = [1, 1, 1]\n",
    "print(x == 1)\n",
    "x = np.array([1, 1, 1])\n",
    "print(x == 1)\n",
    "print(all(x == 1))\n",
    "print(any(x == 2))\n",
    "y = np.array([1, 2, 3])\n",
    "print(any(y == 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "3a943a6d-3ef6-4d26-b94f-7e70f6ab9c2e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.53809917 0.16344181 0.47493019 0.19265476]\n",
      " [0.39357131 0.48118902 0.29450736 0.63235608]\n",
      " [0.03208903 0.40222979 0.62985953 0.08420633]\n",
      " [0.7176534  0.78781203 0.29313798 0.25792295]]\n",
      "[[False  True  True  True]\n",
      " [ True  True  True False]\n",
      " [ True  True False  True]\n",
      " [False False  True  True]]\n",
      "[[0.53809917 0.         0.         0.        ]\n",
      " [0.         0.         0.         0.63235608]\n",
      " [0.         0.         0.62985953 0.        ]\n",
      " [0.7176534  0.78781203 0.         0.        ]]\n"
     ]
    }
   ],
   "source": [
    "A = np.random.rand(4, 4)\n",
    "print(A)\n",
    "print(A < 0.5)\n",
    "A[A < 0.5] = 0\n",
    "print(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bdf8a3ec",
   "metadata": {},
   "source": [
    "## Control Structures\n",
    "\n",
    "Python uses the same control structures as most other languages:\n",
    "- `if`\n",
    "- `while`\n",
    "- `for`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "348563b4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x is not 3\n"
     ]
    }
   ],
   "source": [
    "x = 2\n",
    "if x == 3:\n",
    "    print(\"x is 3\")\n",
    "else:\n",
    "    print(\"x is not 3\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "78b76943",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x is 2\n"
     ]
    }
   ],
   "source": [
    "if x == 3:\n",
    "    print(\"x is 3\")\n",
    "elif x == 2:\n",
    "    print(\"x is 2\")\n",
    "else:\n",
    "    print(\"x is not 2 or 3\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "c1804354",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n",
      "5\n",
      "6\n",
      "7\n",
      "8\n",
      "9\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "i = 0;\n",
    "while i < 10:\n",
    "    i = i + 1\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "93c76abf",
   "metadata": {},
   "source": [
    "For loops work in Python by iterating through an iterable, such as a list, tuple, string, or range, and executing a block of code once for each element in that iterable. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "dc16f3af",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "4\n",
      "9\n"
     ]
    }
   ],
   "source": [
    "numbers = [1, 2, 3]\n",
    "for number in numbers:\n",
    "    print(number ** 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "21476bb7",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n",
      "5\n",
      "6\n",
      "7\n",
      "8\n"
     ]
    }
   ],
   "source": [
    "for x in range(4, 9):\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "d20fc76e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.53809917 0.         0.         0.        ]\n",
      "[0.         0.         0.         0.63235608]\n",
      "[0.         0.         0.62985953 0.        ]\n",
      "[0.7176534  0.78781203 0.         0.        ]\n"
     ]
    }
   ],
   "source": [
    "for row in A:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "5cca445b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "H\n",
      "e\n",
      "l\n",
      "l\n",
      "o\n",
      ",\n",
      " \n",
      "W\n",
      "o\n",
      "r\n",
      "l\n",
      "d\n",
      "!\n"
     ]
    }
   ],
   "source": [
    "string = \"Hello, World!\"\n",
    "for element in string:\n",
    "    print(element)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "4d5fd460",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "3\n",
      "4\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "for i in range(10):\n",
    "    if i == 2:\n",
    "        continue\n",
    "    print(i)\n",
    "    if i == 5:\n",
    "        break"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a9fe497",
   "metadata": {},
   "source": [
    "## Lambda Functions\n",
    "\n",
    "In Python, simple functions which require only one line can be defined using `lambda`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "73241200",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "4\n",
      "9\n",
      "16\n"
     ]
    }
   ],
   "source": [
    "f = lambda x: x ** 2\n",
    "for i in range(5):\n",
    "    print(f(i))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "1221c813",
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "must be real number, not list",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mTypeError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[28]\u001b[39m\u001b[32m, line 4\u001b[39m\n\u001b[32m      1\u001b[39m f = \u001b[38;5;28;01mlambda\u001b[39;00m x, y: m.exp(x) * y\n\u001b[32m      2\u001b[39m x = [\u001b[32m1\u001b[39m, \u001b[32m2\u001b[39m, \u001b[32m3\u001b[39m]\n\u001b[32m      3\u001b[39m y = [\u001b[32m4\u001b[39m, \u001b[32m5\u001b[39m, \u001b[32m6\u001b[39m]\n\u001b[32m----> \u001b[39m\u001b[32m4\u001b[39m f(x, y)\n",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[28]\u001b[39m\u001b[32m, line 1\u001b[39m, in \u001b[36m<lambda>\u001b[39m\u001b[34m(x, y)\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m f = \u001b[38;5;28;01mlambda\u001b[39;00m x, y: m.exp(x) * y\n",
      "\u001b[31mTypeError\u001b[39m: must be real number, not list"
     ]
    }
   ],
   "source": [
    "f = lambda x, y: m.exp(x) * y\n",
    "x = [1, 2, 3]\n",
    "y = [4, 5, 6]\n",
    "f(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "69d61e25",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 10.87312731,  36.94528049, 120.51322154])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f = lambda x, y: np.exp(x) * y\n",
    "x = np.array([1, 2, 3])\n",
    "y = np.array([4, 5, 6])\n",
    "f(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ca2a755-7d6b-4683-b2ed-9595f44ceb4a",
   "metadata": {},
   "source": [
    "This second approach works as numpy vectors are designed for vectorisation, where a function is applied to each element of the array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "68a9bbca",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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Fxd7dvy4AunDDz/U66+/HnWf008/PeFAysvLkyQdPBi+VFhdXa38/PyY92nKlClTNGnSpNDjffv2qUuXLtq+fbun/4FNEwwG1blzZ1VVVamoqCjdbydlOG/OOxNw3px3JggEAjrllFN00kknefo6cQXSddddp+uuu86r96KCggJ17NhR27dvD9u+fft2devWLeZ9mpKXlxeKq+MVFxdn1P+wGhQVFXHeGYTzziycd2bJ1POO9Ye/Ej6+p0ePwebNm/Xmm2+GHg8bNkxLlizR0aPHrsHX1NRo2bJlGjZsWFz7AAAAJMrTm7R37twZ9ruP1q9fr/z8fHXt2lXnnXeeJGnx4sWaM2dO6P6hhx9+WOXl5brmmms0fPhwLVq0SDk5OWGXx2LZBwAAIFGeriB99913WrRokRYtWqRrrrlGX3/9tRYtWqT169eH9undu7dGjhwZenzqqaeqoqJCvXr10qpVqzRo0CCtX79e7dq1i2ufE8nLy9PUqVObvOzmZ5w3550JOG/OOxNw3t6ed5bDr58GAAAIk/Z7kAAAAExDIAEAAEQgkAAAACIY9adGvLBz506tWrVKPXr00LnnnhvTcz7//HN9+OGHat++vX760582+bsWYtknneJ5f+vWrdO2bdsabW/ZsqWuvvpqScduuF+5cmWjfa688kq1adMmeW+8meI573jOyU/jLUl1dXX64IMPtGvXLvXq1Uvdu3cP+75p453If/9M+xxL9o2rGz7HmfXvtrHztONTO3bscMaNG+d06tTJKSkpcSZOnBjT8x588EGnsLDQueyyy5yf/OQnTnl5ubN3796490mneN/fc88954wdOzbsq23bts5ZZ50V2uedd95xJDXa7+uvv07FKcUk3vOO9Zz8Nt6vvvqq061bN6e8vNwZPny406ZNG2fcuHHO4cOHQ/uYNN6J/PfPxM+xbePqhs9x5vy7bfo87dtA2rJli/PKK684NTU1zoABA2L6D79y5UpHkrNmzRrHcRwnEAg4PXv2dO6444649kmnZLy/nTt3Orm5uc6cOXNC2xo+aKZK5LxjOSc/jvfixYvD/oH8/PPPnTZt2jhPPfVUaJsp453I+WXq59imcXXD5ziz/t02fZ42979cEsX6H37ChAlOeXl52Lbf/va3TlFRkVNfXx/zPumUjPf3xBNPOHl5ec6ePXtC2xo+aO+++67zpz/9ydm2bVsy33azJXLesZxTJoy34zjOoEGDnJtvvjn02JTxTuT8+Bz/wNRxdcPn+AeZ8O/28Uycp826AJtmH374oc4888ywbWeddZaCwWDob7/Fsk86JeP9vfDCC7rmmmsa/SHA3NxcTZs2TU888YR69eqlm266SYcPH07ae2+ORM/7ROeUCeO9Z88effDBB42OY8J4J3J+fI6PMXlc3fA5/kEm/LudiFR+vq25SXvHjh1hf7akKeecc45OP/30hF8jEAg0+h9Xw2/nbvhTKLHsk0zxnndz399///d/a/PmzXr22WfDtnfp0kWbN29Wjx49JB37G3o//elPVVZWpoceeijW04lZKs47lnPy+3jX19frF7/4hdq3b6/bbrsttD3V4+0mkfMz8XMcL7+Pqxu/fI7j5Zd/t1MhlZ9vawLpu+++09KlS6PuU1hY2KxAysvLU3V1ddi2hsf5+fkx75NM8Z53c9/f/PnzVVZWposuuihse1lZWdjj3r17a9y4cVq2bJknH7RUnHcs5+Tn8T569KgmTJig//3f/9Xq1avDfqol1ePtJpHzM/FzHC+/j6sbv3yO4+WXf7dTIZWfb2sCqW/fvlq0aJGnr9G9e/dGy2+VlZXKzs5Wly5dYt4nmeI97+a8vwMHDugPf/iDHnroIWVlZZ3wtYqKirRr166Y31s8Unnex4s8J7+Ot+M4uvXWW7V8+XKtXLlSPXv2POFreTnebhI5PxM/x/Hy+7i68cvnOF5++Xc7FVL6+Y75biWLud389c033zgLFy50gsGg4ziO85//+Z9Ofn6+s2vXrtA+Q4cOdS677LLQ41j2SadY3l/keTeYP3++k5ub63z77beNjrtjx46wx7W1tU6vXr2c0aNHJ/kMEpPIecdyTn4c76NHjzoTJkxwOnbs6GzevLnJ45oy3omcX6Z+jm0aVzd8jjPr3+3jmThP+zaQDh8+7CxcuNBZuHCh06NHD+eKK65wFi5c6Lz99tuhfd5++21HkvPJJ584jnPsfzzl5eVOnz59nGeeeca58cYbncLCQmfDhg2h58SyTzrF8v4iz7vBBRdc4FxzzTVNHveOO+5wrr32Wufpp5925s6d65x33nlOp06dnK1bt3p6PrFK5LxjOSc/jvf999/vZGVlOVOnTg19RhYuXOisWrUq9BxTxjuR88vUz7FN4+qGz3Fm/btt+jxtzSW2eNXX14fu5TjvvPMkSUuXLlXnzp01dOhQSdKPf/xjjR07VkVFRZKO/QbSVatWad68efqf//kfdejQQRUVFTrttNNCx41ln3SK5f1Fnrd07Ka2U045RXfffXeTx/2P//gP/elPf9I777yjuro63XzzzRo/frxatWrl+TnFIpHzjuWc/DjerVu31pgxY/Tpp5/q008/De3Xp0+f0D0Mpox3IueXqZ9jm8bVDZ/jzPp32/R5OstxHCcJ5wkAAOAb/B4kAACACAQSAABABAIJAAAgAoEEAAAQgUACAACIQCABAABEIJAAAAAiEEgAAAARCCQAAIAIBBIAAEAEAgkAACACgQQAABDh/wM5kqFjLnsKOgAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "x = np.linspace(-1, 1, 100)\n",
    "y = np.linspace(-1, 1, 100)\n",
    "XX, YY = np.meshgrid(x, y)\n",
    "plt.contourf(XX, YY, f(XX, YY), 20)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cbf54474-722c-490f-be85-ad710132ac9e",
   "metadata": {},
   "source": [
    "## Functions\n",
    "\n",
    "For any function longer than one line, you should use the following syntax"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "a81242f4-092c-44f9-beac-bcc120ce2260",
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "\n",
    "def solve_quadratic(a, b, c):\n",
    "    \"\"\"\n",
    "    Returns the two real roots of a quadratic equation (ax² + bx + c = 0).\n",
    "    Assumes the discriminant is non-negative.\n",
    "    \"\"\"\n",
    "    discriminant = (b**2) - (4 * a * c)\n",
    "    root1 = (-b - math.sqrt(discriminant)) / (2 * a)\n",
    "    root2 = (-b + math.sqrt(discriminant)) / (2 * a)\n",
    "    return root1, root2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "2ad0883e-ef2c-439e-bb72-50115eba0c69",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(-3.0, -2.0)\n"
     ]
    }
   ],
   "source": [
    "print(solve_quadratic(1, 5, 6))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b344910e",
   "metadata": {},
   "source": [
    "## Floating Point Numbers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "d0e6eedd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.220446049250313e-16\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "eps = sys.float_info.epsilon\n",
    "print(eps)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "6c3144ca",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.220446049250313e-16\n",
      "0.0\n",
      "0.0\n",
      "0.0\n",
      "4.440892098500626e-16\n",
      "1.1102230246251565e-16\n"
     ]
    }
   ],
   "source": [
    "print((1 + eps) - 1)\n",
    "print((1 + eps/2) - 1)\n",
    "print((1 + eps/2 + eps/2) - 1)\n",
    "print((2 + eps) - 2)\n",
    "print((2 + 2*eps) - 2)\n",
    "print((0.9 + eps/2) - 0.9)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "db36ff70-0dab-4344-a348-382c45ce911a",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.14.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
