{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "interactive-link",
   "metadata": {},
   "source": [
    "> **This is a saved, working copy.** Every cell below runs exactly as\n",
    "> shown, just like it did in the browser.\n",
    "> For the live browser version of this guide (handy if you want to\n",
    "> tinker), see [Python Basics guide — interactive](https://math4120.pages.dev/wasm/python_basics_guide.html).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "ipython-import",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.118454Z",
     "iopub.status.busy": "2026-09-29T20:23:38.118198Z",
     "iopub.status.idle": "2026-09-29T20:23:38.123241Z",
     "shell.execute_reply": "2026-09-29T20:23:38.122220Z"
    }
   },
   "outputs": [],
   "source": [
    "from IPython.display import Markdown, HTML\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "Hbol",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "# Python basics\n",
    "## A from-scratch guide to the Python used in this course\n",
    "\n",
    "**MATH4120 — Mathematical Modelling and Programming** Lancaster University, 2026–27\n",
    "\n",
    "---\n",
    "\n",
    "This course assumes no prior programming experience. Every piece of Python that appears anywhere in a MATH4120 lecture or lab — variables, loops, functions, NumPy arrays, plots — is explained here from scratch, roughly in the order you'll first meet it. Nothing here is invented for its own sake: everything below is something a MATH4120 notebook genuinely uses, and nothing genuinely used is left out.\n",
    "\n",
    "This is itself a live Marimo notebook — see the [Working with Marimo](../getting-started/marimo.html) guide for how the \"View\" / \"Run\" buttons work. Every example below is real, runnable Python: read the explanation, look at the code, look at what it prints out. If you're on the \"Run\" version, try changing a number in a cell and re-running it — that's the fastest way any of this actually sticks."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "MJUe",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.125807Z",
     "iopub.status.busy": "2026-09-29T20:23:38.125562Z",
     "iopub.status.idle": "2026-09-29T20:23:38.523656Z",
     "shell.execute_reply": "2026-09-29T20:23:38.522209Z"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "vblA",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 1. Cells, code, and output\n",
    "\n",
    "A notebook is a sequence of **cells**. Each cell holds a small piece of Python; you run it and see its result immediately underneath, rather than running an entire program from top to bottom at once. This is what \"interactive\" means here: write a line, see what it does, adjust, repeat.\n",
    "\n",
    "Whatever the *last* line of a cell evaluates to gets displayed automatically as that cell's output — you don't need to ask for it explicitly. A line starting with `#` is a **comment**: Python ignores it completely: it's a note to whoever reads the code (including you, later)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "bkHC",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.526330Z",
     "iopub.status.busy": "2026-09-29T20:23:38.525991Z",
     "iopub.status.idle": "2026-09-29T20:23:38.531975Z",
     "shell.execute_reply": "2026-09-29T20:23:38.531027Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "7"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# This is a comment — Python skips this line entirely.\n",
    "3 + 4   # the last line of a cell is displayed as its output"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "lEQa",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 2. Variables and arithmetic\n",
    "\n",
    "A **variable** is a name that points to a value. `=` means \"assign\": it does *not* mean mathematical equality (that's `==`, coming up in Section 4). Once a variable holds a value, you can use it in later expressions just like a number.\n",
    "\n",
    "The arithmetic operators are `+ - * /` as expected, `**` for \"to the power of\" (there is no `^` for this in Python), and `//` for integer (whole-number, rounded-down) division."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "PKri",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.533768Z",
     "iopub.status.busy": "2026-09-29T20:23:38.533587Z",
     "iopub.status.idle": "2026-09-29T20:23:38.537857Z",
     "shell.execute_reply": "2026-09-29T20:23:38.536935Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "174.90062499999993"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_N0 = 100        # initial population\n",
    "_r = 0.15        # growth rate\n",
    "_t = 4            # time elapsed\n",
    "\n",
    "_N0 * (1 + _r) ** _t   # ** means \"to the power of\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "Xref",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.539597Z",
     "iopub.status.busy": "2026-09-29T20:23:38.539423Z",
     "iopub.status.idle": "2026-09-29T20:23:38.542957Z",
     "shell.execute_reply": "2026-09-29T20:23:38.542009Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3, 2)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "17 // 5, 17 % 5   # // = whole number division, % = remainder (\"modulo\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "SFPL",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 3. Strings and f-strings\n",
    "\n",
    "Text is written as a **string**, in single or double quotes — `'hello'` and `\"hello\"` mean exactly the same thing. The really useful form is an **f-string**: put an `f` right before the opening quote, and anything inside `{curly braces}` gets evaluated and dropped into the text. A colon inside the braces controls the number format, e.g. `:.2f` means \"2 decimal places\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "BYtC",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.544730Z",
     "iopub.status.busy": "2026-09-29T20:23:38.544531Z",
     "iopub.status.idle": "2026-09-29T20:23:38.549032Z",
     "shell.execute_reply": "2026-09-29T20:23:38.547926Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'With growth rate r = 0.15, the population reached N = 174.9'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_r = 0.15\n",
    "_N = 174.9\n",
    "\n",
    "f\"With growth rate r = {_r}, the population reached N = {_N:.1f}\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "RGSE",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 4. Comparisons and booleans\n",
    "\n",
    "Comparing two values with `< > <= >= ==  !=` gives you a **boolean**: `True` or `False`. Note `==` (equality test) is different from `=` (assignment) — mixing these up is one of the most common early mistakes, and Python won't stop you from writing `=` where you meant `==`, so it's worth double-checking. Combine booleans with `and`, `or`, and `not`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "Kclp",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.551151Z",
     "iopub.status.busy": "2026-09-29T20:23:38.550893Z",
     "iopub.status.idle": "2026-09-29T20:23:38.555201Z",
     "shell.execute_reply": "2026-09-29T20:23:38.554386Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(True, True, True)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_N = 174.9\n",
    "_capacity = 200.0\n",
    "\n",
    "_N < _capacity, _N == 174.9, _N > 100 and _N < _capacity"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "emfo",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 5. `if` / `elif` / `else`\n",
    "\n",
    "An `if` statement runs a block of code only when a condition is `True`. `elif` (\"else if\") checks another condition if the first one was `False`, and `else` catches everything else. Python uses **indentation** (consistent spaces at the start of a line) to mark which lines belong inside the `if` — there are no curly braces `{}` for this, unlike many other languages.\n",
    "\n",
    "A compact one-line version, the **ternary expression**, is also common: `value_if_true if condition else value_if_false`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "Hstk",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.557550Z",
     "iopub.status.busy": "2026-09-29T20:23:38.557363Z",
     "iopub.status.idle": "2026-09-29T20:23:38.561873Z",
     "shell.execute_reply": "2026-09-29T20:23:38.560932Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'approaching capacity'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_N = 174.9\n",
    "_capacity = 200.0\n",
    "\n",
    "if _N < 0.5 * _capacity:\n",
    "    _status = \"growing freely\"\n",
    "elif _N < _capacity:\n",
    "    _status = \"approaching capacity\"\n",
    "else:\n",
    "    _status = \"at or above capacity\"\n",
    "\n",
    "_status"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "nWHF",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.563494Z",
     "iopub.status.busy": "2026-09-29T20:23:38.563311Z",
     "iopub.status.idle": "2026-09-29T20:23:38.567304Z",
     "shell.execute_reply": "2026-09-29T20:23:38.566352Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'cool'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_T = 15\n",
    "\"warm\" if _T > 18 else \"cool\"   # the one-line \"ternary\" form of if/else"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "iLit",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 6. Lists\n",
    "\n",
    "A **list** is an ordered collection of values, written with square brackets: `[10, 20, 30]`. Access an element with `list[index]` — Python counts positions **from 0**, so `[0]` is the first element, and `[-1]` is a shortcut for \"the last one\" (very heavily used throughout this course, e.g. to grab \"the most recent value\" in a step-by-step calculation). A **slice** `list[start:stop]` pulls out a sub-range; leaving `start` or `stop` blank means \"from the beginning\" / \"to the end\". `len(list)` gives the number of elements, and `.append(x)` adds `x` to the end."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ZHCJ",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.569162Z",
     "iopub.status.busy": "2026-09-29T20:23:38.568977Z",
     "iopub.status.idle": "2026-09-29T20:23:38.573099Z",
     "shell.execute_reply": "2026-09-29T20:23:38.572170Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(21.0, 16.1, 5)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_temperatures = [21.0, 19.5, 18.2, 17.0, 16.1]\n",
    "\n",
    "_temperatures[0], _temperatures[-1], len(_temperatures)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "ROlb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.575455Z",
     "iopub.status.busy": "2026-09-29T20:23:38.575251Z",
     "iopub.status.idle": "2026-09-29T20:23:38.579620Z",
     "shell.execute_reply": "2026-09-29T20:23:38.578515Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([19.5, 18.2, 17.0], [21.0, 19.5, 18.2, 17.0, 16.1, 15.4])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_temperatures = [21.0, 19.5, 18.2, 17.0, 16.1]\n",
    "_temperatures.append(15.4)   # add a new value onto the end\n",
    "\n",
    "_temperatures[1:4], _temperatures   # a slice, then the whole (now longer) list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "qnkX",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 7. Tuples and multiple assignment\n",
    "\n",
    "A **tuple** is an ordered collection like a list, but written with parentheses `(a, b)` (or often no brackets at all) and not meant to be changed after it's created. Tuples show up constantly for **multiple assignment** — unpacking several values out of one expression in a single line — and for functions that need to hand back more than one result at once (Section 12)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "TqIu",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.581653Z",
     "iopub.status.busy": "2026-09-29T20:23:38.581505Z",
     "iopub.status.idle": "2026-09-29T20:23:38.585444Z",
     "shell.execute_reply": "2026-09-29T20:23:38.584393Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0.0, 5.0, 1.0, 3.0)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_t0, _T = 0.0, 5.0     # assign two variables in one line\n",
    "_point = (1.0, 3.0)     # an explicit tuple: an (x, y) pair\n",
    "_x, _y = _point          # unpack it into two separate variables\n",
    "\n",
    "_t0, _T, _x, _y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "Vxnm",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 8. Dictionaries\n",
    "\n",
    "A **dictionary** maps keys to values — a lookup table. Write it as `{key: value, ...}`, and look something up with `d[key]`. This course uses dictionaries only occasionally (mostly for small, named lookup tables, like a planet's name mapped to its surface gravity), but it's worth recognising the syntax when you see it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "DnEU",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.587385Z",
     "iopub.status.busy": "2026-09-29T20:23:38.587186Z",
     "iopub.status.idle": "2026-09-29T20:23:38.590979Z",
     "shell.execute_reply": "2026-09-29T20:23:38.590248Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.71"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_planet_gravity = {\"Earth\": 9.81, \"Moon\": 1.62, \"Mars\": 3.71}\n",
    "\n",
    "_planet_gravity[\"Mars\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "ulZA",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.593019Z",
     "iopub.status.busy": "2026-09-29T20:23:38.592868Z",
     "iopub.status.idle": "2026-09-29T20:23:38.596686Z",
     "shell.execute_reply": "2026-09-29T20:23:38.595824Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Earth: 9.81 m/s²', 'Moon: 1.62 m/s²', 'Mars: 3.71 m/s²']"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_planet_gravity = {\"Earth\": 9.81, \"Moon\": 1.62, \"Mars\": 3.71}\n",
    "\n",
    "[f\"{_name}: {_g} m/s²\" for _name, _g in _planet_gravity.items()]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ecfG",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 9. `for` loops\n",
    "\n",
    "A `for` loop repeats a block of code once per item in a collection: `for item in some_list:`. `range(n)` gives the whole numbers from `0` up to (not including) `n`, and is the standard way to \"do something `n` times\". `enumerate(some_list)` gives you both the position and the value as you go; `zip(list_a, list_b)` walks through two lists side by side, pairing them up."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "Pvdt",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.598621Z",
     "iopub.status.busy": "2026-09-29T20:23:38.598447Z",
     "iopub.status.idle": "2026-09-29T20:23:38.602582Z",
     "shell.execute_reply": "2026-09-29T20:23:38.601544Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "rate 0.05 -> after 1 step: 105.0\n",
      "rate 0.1 -> after 1 step: 110.0\n",
      "rate 0.15 -> after 1 step: 115.0\n"
     ]
    }
   ],
   "source": [
    "_rates = [0.05, 0.10, 0.15]\n",
    "\n",
    "for _r in _rates:\n",
    "    print(f\"rate {_r} -> after 1 step: {100 * (1 + _r):.1f}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "ZBYS",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.604715Z",
     "iopub.status.busy": "2026-09-29T20:23:38.604494Z",
     "iopub.status.idle": "2026-09-29T20:23:38.608978Z",
     "shell.execute_reply": "2026-09-29T20:23:38.608095Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "scenario 0: rate 0.05\n",
      "scenario 1: rate 0.1\n",
      "scenario 2: rate 0.15\n",
      "slow: rate 0.05\n",
      "medium: rate 0.1\n",
      "fast: rate 0.15\n"
     ]
    }
   ],
   "source": [
    "_rates = [0.05, 0.10, 0.15]\n",
    "_labels = [\"slow\", \"medium\", \"fast\"]\n",
    "\n",
    "for _i, _r in enumerate(_rates):\n",
    "    print(f\"scenario {_i}: rate {_r}\")\n",
    "\n",
    "for _label, _r in zip(_labels, _rates):\n",
    "    print(f\"{_label}: rate {_r}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aLJB",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 10. `while` loops\n",
    "\n",
    "A `while` loop keeps repeating as long as a condition stays `True`, rather than a fixed number of times. This is exactly how every step-by-step ODE solver in this course is built from Week 7 onwards: keep taking a small time step *while the current time is still less than the end time*. `list[-1]` (Section 6) is what lets the loop always grab \"the most recent value\" to build the next one from."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "nHfw",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.610805Z",
     "iopub.status.busy": "2026-09-29T20:23:38.610605Z",
     "iopub.status.idle": "2026-09-29T20:23:38.615333Z",
     "shell.execute_reply": "2026-09-29T20:23:38.614421Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([0.0, 0.5, 1.0, 1.5, 2.0],\n",
       " [1.0, 1.1, 1.2100000000000002, 1.3310000000000004, 1.4641000000000006])"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_ts = [0.0]\n",
    "_ys = [1.0]\n",
    "_dt = 0.5\n",
    "\n",
    "while _ts[-1] < 2.0:\n",
    "    _ys.append(_ys[-1] * 1.1)     # next value, built from the previous one\n",
    "    _ts.append(_ts[-1] + _dt)\n",
    "\n",
    "_ts, _ys"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "xXTn",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 11. List comprehensions\n",
    "\n",
    "A **list comprehension** builds a new list from an existing one in a single line: `[expression for item in list]`, optionally with an `if` at the end to filter. It's just a compact `for` loop that collects results into a list — the same computation as writing the loop out longhand and calling `.append()` each time, but far more common in practice once it feels natural."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "AjVT",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.617380Z",
     "iopub.status.busy": "2026-09-29T20:23:38.617168Z",
     "iopub.status.idle": "2026-09-29T20:23:38.621642Z",
     "shell.execute_reply": "2026-09-29T20:23:38.620702Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[4, 7, 10, 13, 16]"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_n1_values = range(1, 6)\n",
    "\n",
    "[3 * _n1 + 1 for _n1 in _n1_values]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "pHFh",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.623849Z",
     "iopub.status.busy": "2026-09-29T20:23:38.623623Z",
     "iopub.status.idle": "2026-09-29T20:23:38.628458Z",
     "shell.execute_reply": "2026-09-29T20:23:38.627227Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[15, 23, 16, 42]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_values = [4, 15, 8, 23, 16, 42]\n",
    "\n",
    "[_v for _v in _values if _v > 10]   # keep only values above 10"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "NCOB",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 12. Writing your own functions\n",
    "\n",
    "A **function** packages up a calculation you want to reuse: `def name(inputs):` followed by an indented body, ending in `return result`. Arguments can have a **default value** (`def f(x, y=1):`), used whenever the caller doesn't supply that argument. `return a, b` hands back a tuple of several values at once — exactly the multiple-assignment pattern from Section 7, now coming *out* of a function instead of a literal."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "aqbW",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.630666Z",
     "iopub.status.busy": "2026-09-29T20:23:38.630479Z",
     "iopub.status.idle": "2026-09-29T20:23:38.634650Z",
     "shell.execute_reply": "2026-09-29T20:23:38.633745Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "42"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def _double(_x):\n",
    "    return 2 * _x\n",
    "\n",
    "_double(21)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "TRpd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.636950Z",
     "iopub.status.busy": "2026-09-29T20:23:38.636718Z",
     "iopub.status.idle": "2026-09-29T20:23:38.641424Z",
     "shell.execute_reply": "2026-09-29T20:23:38.640614Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('Hello, Ada!', 'Good morning, Ada!')"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def _greet(_name, _greeting=\"Hello\"):\n",
    "    return f\"{_greeting}, {_name}!\"\n",
    "\n",
    "_greet(\"Ada\"), _greet(\"Ada\", \"Good morning\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "TXez",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.643673Z",
     "iopub.status.busy": "2026-09-29T20:23:38.643471Z",
     "iopub.status.idle": "2026-09-29T20:23:38.648029Z",
     "shell.execute_reply": "2026-09-29T20:23:38.647048Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2.0, 9.0)"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def _min_and_max(_values):\n",
    "    return min(_values), max(_values)\n",
    "\n",
    "_lo, _hi = _min_and_max([3.0, 7.0, 2.0, 9.0, 4.0])\n",
    "_lo, _hi"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dNNg",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 13. NumPy: arrays and vectorised arithmetic\n",
    "\n",
    "A plain Python list is flexible but slow for maths on lots of numbers at once. **NumPy** (imported once, right at the top, as `np`) provides the **array** instead: `np.array([...])` from a list, `np.linspace(start, stop, n)` for `n` evenly-spaced points, `np.arange(start, stop, step)` for a fixed step size, and `np.zeros(n)` for an array of `n` zeros to fill in later.\n",
    "\n",
    "The single most important thing about arrays: arithmetic applies to *every element at once*, with no loop needed. `array * 2` doubles every entry; `array1 + array2` adds them elementwise. This is called **vectorisation**, and it's why every ODE solution, every dataset, and every plotted curve in this course is built from arrays rather than lists."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "yCnT",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.649783Z",
     "iopub.status.busy": "2026-09-29T20:23:38.649565Z",
     "iopub.status.idle": "2026-09-29T20:23:38.654455Z",
     "shell.execute_reply": "2026-09-29T20:23:38.653490Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([100.  , 120.  , 144.  , 172.8 , 207.36])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_n = np.arange(0, 5)         # array([0, 1, 2, 3, 4])\n",
    "_N0, _R = 100.0, 1.2\n",
    "\n",
    "_N0 * _R ** _n   # one line, no loop: computes all 5 values at once"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "wlCL",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.656150Z",
     "iopub.status.busy": "2026-09-29T20:23:38.655968Z",
     "iopub.status.idle": "2026-09-29T20:23:38.660266Z",
     "shell.execute_reply": "2026-09-29T20:23:38.659351Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([0.  , 0.25, 0.5 , 0.75, 1.  ]),\n",
       " array([1.        , 0.77880078, 0.60653066, 0.47236655, 0.36787944]))"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_t = np.linspace(0, 1, 5)   # 5 evenly-spaced points from 0 to 1\n",
    "_t, np.exp(-_t)              # elementwise: e^(-t) for every t at once"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "kqZH",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 14. NumPy: indexing and slicing\n",
    "\n",
    "Arrays support the same `[index]` and `[start:stop]` slicing as lists (Section 6), plus one extra trick used constantly in this course: **boolean masking**. Writing a comparison on an array (`arr > 3`) gives back an array of `True`/`False` values; using *that* as an index, `arr[arr > 3]`, keeps only the entries where the condition holds."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "wAgl",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.661981Z",
     "iopub.status.busy": "2026-09-29T20:23:38.661676Z",
     "iopub.status.idle": "2026-09-29T20:23:38.665746Z",
     "shell.execute_reply": "2026-09-29T20:23:38.664971Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(np.float64(2.0), np.float64(7.0), array([8., 1., 9.]))"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_arr = np.array([2.0, 8.0, 1.0, 9.0, 4.0, 7.0])\n",
    "\n",
    "_arr[0], _arr[-1], _arr[1:4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "rEll",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.667461Z",
     "iopub.status.busy": "2026-09-29T20:23:38.667310Z",
     "iopub.status.idle": "2026-09-29T20:23:38.672186Z",
     "shell.execute_reply": "2026-09-29T20:23:38.671361Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([False,  True, False,  True, False,  True]), array([8., 9., 7.]))"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_arr = np.array([2.0, 8.0, 1.0, 9.0, 4.0, 7.0])\n",
    "\n",
    "_arr > 5, _arr[_arr > 5]   # a boolean mask, then using it to filter the array"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dGlV",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 15. NumPy: useful functions\n",
    "\n",
    "A short reference for the NumPy functions you'll see repeatedly. All of these work elementwise on a whole array at once, just like the arithmetic in Section 13.\n",
    "\n",
    "| Function | What it does |\n",
    "|---|---|\n",
    "| `np.exp(x)`, `np.log(x)`, `np.sqrt(x)` | exponential, natural log, square root |\n",
    "| `np.abs(x)` | absolute value |\n",
    "| `np.sum(x)`, `np.mean(x)` | total, and average, of all elements |\n",
    "| `np.max(x)`, `np.min(x)` (or `x.max()`, `x.min()`) | largest / smallest element |\n",
    "| `np.round(x, 2)` | round every element to 2 decimal places |\n",
    "| `np.sort(x)` | a new array with elements in increasing order |\n",
    "| `np.where(cond, a, b)` | elementwise \"if cond then a else b\" |\n",
    "| `np.clip(x, lo, hi)` | squash every element into the range `[lo, hi]` |\n",
    "\n",
    "`np.where` is the array version of the ternary expression from Section 5 — it works on every element at once instead of one value at a time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "SdmI",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.674675Z",
     "iopub.status.busy": "2026-09-29T20:23:38.674453Z",
     "iopub.status.idle": "2026-09-29T20:23:38.679119Z",
     "shell.execute_reply": "2026-09-29T20:23:38.678170Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-1., -1.,  1.,  1.,  1.])"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_x = np.array([-2.0, -0.5, 0.3, 1.5, 3.0])\n",
    "\n",
    "np.where(_x > 0, 1.0, -1.0)   # +1 where x is positive, -1 where it isn't"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "lgWD",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.680774Z",
     "iopub.status.busy": "2026-09-29T20:23:38.680582Z",
     "iopub.status.idle": "2026-09-29T20:23:38.684772Z",
     "shell.execute_reply": "2026-09-29T20:23:38.683791Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0. , 0. , 0.3, 1.5, 2. ])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_x = np.array([-2.0, -0.5, 0.3, 1.5, 3.0])\n",
    "\n",
    "np.clip(_x, 0.0, 2.0)   # anything below 0 becomes 0, anything above 2 becomes 2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "yOPj",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 16. NumPy: randomness\n",
    "\n",
    "Every \"noisy data\" example in this course starts the same way: `np.random.default_rng(seed)` creates a **random number generator**. The `seed` (any whole number you choose) makes the randomness **reproducible** — the same seed always produces exactly the same sequence of \"random\" numbers, which is essential for a worked example everyone can check against the same answer. From that generator, `.uniform(low, high, size=n)` draws `n` values evenly spread between `low` and `high`, `.normal(loc, scale, size=n)` draws from a bell-curve (mean `loc`, spread `scale`), and `.choice(options, size=n)` picks `n` random entries out of a list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "fwwy",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.686629Z",
     "iopub.status.busy": "2026-09-29T20:23:38.686449Z",
     "iopub.status.idle": "2026-09-29T20:23:38.696094Z",
     "shell.execute_reply": "2026-09-29T20:23:38.695146Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([7.73956049, 4.3887844 , 8.5859792 , 6.97368029, 0.94177348])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_rng = np.random.default_rng(42)   # 42 is just a fixed choice — any number works\n",
    "\n",
    "_rng.uniform(0, 10, size=5)   # 5 random values between 0 and 10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "LJZf",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.698170Z",
     "iopub.status.busy": "2026-09-29T20:23:38.697898Z",
     "iopub.status.idle": "2026-09-29T20:23:38.702542Z",
     "shell.execute_reply": "2026-09-29T20:23:38.701508Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([5.15235854, 4.48000795, 5.3752256 , 5.47028236, 4.02448241])"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_rng = np.random.default_rng(42)\n",
    "_true_values = np.array([5.0, 5.0, 5.0, 5.0, 5.0])\n",
    "_noisy = _true_values + _rng.normal(loc=0.0, scale=0.5, size=5)   # add random \"measurement noise\"\n",
    "\n",
    "_noisy"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "urSm",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 17. NumPy: matrices, `@`, and `.T`\n",
    "\n",
    "An array can have more than one dimension — a 2D array behaves like a matrix. `@` is matrix multiplication (distinct from `*`, which multiplies elementwise), and `.T` transposes a matrix (flips rows and columns). You'll meet this in two places: the Buckingham Π-theorem's dimension matrix (Week 3), and every neural network from Week 9 onwards, where a layer's output is computed as `inputs @ weights`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "jxvo",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.705529Z",
     "iopub.status.busy": "2026-09-29T20:23:38.705319Z",
     "iopub.status.idle": "2026-09-29T20:23:38.714325Z",
     "shell.execute_reply": "2026-09-29T20:23:38.713388Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.0)"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_weights = np.array([0.5, -1.0])\n",
    "_inputs = np.array([2.0, 1.0])\n",
    "\n",
    "_weights @ _inputs   # matrix/vector multiplication: (0.5)(2) + (-1.0)(1) = 0.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "mWxS",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.715985Z",
     "iopub.status.busy": "2026-09-29T20:23:38.715833Z",
     "iopub.status.idle": "2026-09-29T20:23:38.719348Z",
     "shell.execute_reply": "2026-09-29T20:23:38.718542Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1., 3.],\n",
       "       [2., 4.]])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "_M = np.array([[1.0, 2.0], [3.0, 4.0]])\n",
    "\n",
    "_M.T   # transpose: rows become columns"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "CcZR",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 18. SciPy: black-box tools\n",
    "\n",
    "**SciPy** builds on NumPy with ready-made numerical routines. You are never asked to write these yourself — the point is knowing what to hand them and what comes back.\n",
    "\n",
    "- **`solve_ivp(f, t_span, y0)`** (`scipy.integrate`) — numerically solves an ODE $y' = f(t, y)$ from initial condition `y0` over the time range `t_span = (t0, T)`. The result has `.t` (the time points) and `.y` (the solution at each of them).\n",
    "- **`curve_fit(model, x_data, y_data)`** (`scipy.optimize`) — finds the parameters of `model` that best match some noisy data, by least squares.\n",
    "- **`least_squares(residuals, params0)`** (`scipy.optimize`) — the more general version behind `curve_fit`: give it a function that returns the *errors* for a guess at the parameters, and it searches for the guess that makes those errors smallest.\n",
    "- **`null_space(A)`** (`scipy.linalg`) — finds vectors $x$ solving $Ax = 0$; used in Week 3 to find dimensionless Π-groups from the dimension matrix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "YWSi",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.721732Z",
     "iopub.status.busy": "2026-09-29T20:23:38.721441Z",
     "iopub.status.idle": "2026-09-29T20:23:38.985198Z",
     "shell.execute_reply": "2026-09-29T20:23:38.983905Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([0., 1., 2., 3., 4., 5.]),\n",
       " array([10.        ,  6.06526852,  3.67670143,  2.2325709 ,  1.35345635,\n",
       "         0.82172677]))"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from scipy.integrate import solve_ivp\n",
    "\n",
    "def _decay(_t, _y):\n",
    "    return -0.5 * _y   # the ODE y' = -0.5 y\n",
    "\n",
    "_sol = solve_ivp(_decay, (0.0, 5.0), [10.0], t_eval=np.linspace(0, 5, 6))\n",
    "_sol.t, _sol.y[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "zlud",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 19. Matplotlib: making a plot\n",
    "\n",
    "**Matplotlib** draws every figure in this course. The standard pattern is always the same: `fig, ax = plt.subplots()` creates a blank figure and a set of axes to draw on, `ax.plot(x, y)` draws a line through the points, then `ax.set_xlabel(...)`, `ax.set_title(...)`, `ax.legend()`, and `ax.grid(True)` label and tidy it up. `fig.tight_layout()` fixes up the spacing, and the bare `fig` at the end displays it (Section 1's \"last line is the output\", applied to a figure)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "tZnO",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:38.988582Z",
     "iopub.status.busy": "2026-09-29T20:23:38.988118Z",
     "iopub.status.idle": "2026-09-29T20:23:39.250947Z",
     "shell.execute_reply": "2026-09-29T20:23:39.249152Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 600x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "_t = np.linspace(0, 5, 100)\n",
    "_y = np.exp(-_t)\n",
    "\n",
    "_fig, _ax = plt.subplots(figsize=(6, 4))\n",
    "_ax.plot(_t, _y, label=r\"$e^{-t}$\")\n",
    "_ax.set_xlabel(\"$t$\")\n",
    "_ax.set_ylabel(\"$y$\")\n",
    "_ax.set_title(\"A basic Matplotlib plot\")\n",
    "_ax.legend()\n",
    "_ax.grid(True, alpha=0.3)\n",
    "_fig.tight_layout()\n",
    "_fig;"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "xvXZ",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 20. Matplotlib: a quick reference\n",
    "\n",
    "Beyond `ax.plot`, a handful of other plot types and helpers show up repeatedly:\n",
    "\n",
    "| Call | What it draws |\n",
    "|---|---|\n",
    "| `ax.scatter(x, y)` | individual points, not joined by a line |\n",
    "| `ax.step(x, y)` | a staircase — used for Euler's method's discrete steps |\n",
    "| `ax.contour(X, Y, Z)` / `ax.contourf(...)` | level curves / filled regions of a 2D function |\n",
    "| `ax.axhline(y0)` / `ax.axvline(x0)` | a horizontal / vertical reference line |\n",
    "| `ax.errorbar(x, y, yerr=...)` | points with error bars |\n",
    "\n",
    "A label written as `r\"$\\theta$\"` (a *raw string*, `r\"...\"`, containing LaTeX) renders as a proper mathematical symbol rather than plain text — this is how every Greek letter and equation on every plot in this course is produced."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "CLip",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-29T20:23:39.253970Z",
     "iopub.status.busy": "2026-09-29T20:23:39.253733Z",
     "iopub.status.idle": "2026-09-29T20:23:39.426273Z",
     "shell.execute_reply": "2026-09-29T20:23:39.424940Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 600x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "_t_data = np.array([0.5, 1.2, 2.1, 3.0, 3.8])\n",
    "_y_data = np.array([9.1, 7.8, 5.9, 4.2, 3.3])\n",
    "_t_line = np.linspace(0, 4, 50)\n",
    "\n",
    "_fig, _ax = plt.subplots(figsize=(6, 4))\n",
    "_ax.scatter(_t_data, _y_data, color=\"#1a5276\", label=\"data\")\n",
    "_ax.plot(_t_line, 10 * np.exp(-0.3 * _t_line), \"k--\", label=\"model\")\n",
    "_ax.set_xlabel(\"$t$\")\n",
    "_ax.set_ylabel(r\"$\\theta$\")\n",
    "_ax.legend()\n",
    "_ax.grid(True, alpha=0.3)\n",
    "_fig.tight_layout()\n",
    "_fig;"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "YECM",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## 21. Two things you'll notice in every notebook\n",
    "\n",
    "Two conventions appear throughout every MATH4120 notebook that aren't standard Python knowledge — they're specific to how these particular files are packaged, so it's worth knowing what they are even though you'll never need to write them yourself.\n",
    "\n",
    "**Every variable name starting with an underscore, like `_x` or `_fig`.** Marimo (the notebook tool everything is written in) requires every *ordinary* variable name to be unique across an entire notebook — reuse `x` in two different cells and it refuses to run, since it can't tell which one you meant. A leading underscore marks a variable as private scratch space for that one cell only, exempt from that rule. Every example in this guide uses underscore-prefixed names for exactly this reason — feel free to ignore the underscore and just read `_x` as `x`.\n",
    "\n",
    "**Every cell in the raw `.py` source looks like `def _(...): ... return (...)`.** If you ever open a notebook's source file directly, each cell is written as a small function, and the names it takes as arguments are exactly the variables it needs from other cells. This is Marimo's own bookkeeping for figuring out which cells depend on which — it's what makes the notebook reactive (drag a slider, and every cell that depends on it re-runs automatically, like a spreadsheet). You never write this structure yourself; Marimo generates it for you as you type into cells in its own editor."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cEAS",
   "metadata": {
    "marimo": {
     "config": {
      "hide_code": true
     },
     "md_prefix": "r"
    }
   },
   "source": [
    "## Summary\n",
    "\n",
    "- **Core Python:** variables (`=`), arithmetic (`+ - * / ** //`), comparisons (`== < > <= >=`), `if`/`elif`/`else`, `for` and `while` loops, functions (`def` ... `return`).\n",
    "- **Collections:** lists (`[...]`, indexing, slicing, `.append()`), tuples (multiple assignment), dictionaries (`{key: value}`), list comprehensions.\n",
    "- **NumPy (`np`):** arrays instead of lists, vectorised arithmetic with no loop needed, indexing/slicing/boolean masking, a toolbox of elementwise functions, reproducible randomness via `default_rng(seed)`, `@` and `.T` for matrices.\n",
    "- **SciPy:** ready-made numerical routines — `solve_ivp` for ODEs, `curve_fit`/`least_squares` for fitting, `null_space` for linear algebra — used as tools, not built from scratch.\n",
    "- **Matplotlib (`plt`):** `fig, ax = plt.subplots()`, then `ax.plot`/`.scatter`/`.step`/... plus labels, a legend, and a grid.\n",
    "\n",
    "From here, every computing lecture and lab notebook in the course should read as a combination of exactly these pieces — nothing more exotic ever shows up. See [Working with Marimo](../getting-started/marimo.html) for how to actually run those notebooks, and [Working with Jupyter](../getting-started/jupyter.html) for saving and submitting your own work."
   ]
  }
 ],
 "metadata": {
  "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.13.3"
  },
  "marimo": {
   "app_config": {
    "app_title": "Python Basics — Getting Started",
    "width": "medium"
   },
   "marimo_version": "0.25.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
