{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# MATH 4242 Python Lab 7: Projection and least squares\n",
        "\n",
        "**Course sections:** 4.3--4.4 and 5.2\n",
        "\n",
        "This notebook accompanies LEAP Assignment 7. LEAP supplies your\n",
        "parameter values and grades your mathematical responses. Copy those\n",
        "values into the indicated cell below. Run a cell with **Shift+Enter**.\n",
        "\n",
        "The notebook is a computational scratchpad: your graded answers are\n",
        "entered in LEAP unless your instructor says otherwise.\n",
        "\n",
        "**Programming support:** Supported independence. The mathematical goal and useful NumPy tools are supplied; you assemble several lines.\n",
        "\n",
        "A cell marked `TODO` is intentionally unfinished. Read the directions\n",
        "immediately above it before running it. Placeholders such as zero keep\n",
        "the notebook runnable, but their output is not an answer. If you are\n",
        "new to notebooks,\n",
        "complete `00_Getting_Started.ipynb` before this lab.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "\n",
        "np.set_printoptions(precision=6, suppress=True)\n",
        "print(\"NumPy version:\", np.__version__)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 1. Fit a line to three data points\n",
        "\n",
        "Copy `a` and `k` from LEAP. We fit $y\\approx c_0+c_1t$. The first\n",
        "column of the design matrix represents the intercept and the second\n",
        "represents the slope.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Replace these example values with your LEAP values.\n",
        "a = 3\n",
        "k = 2\n",
        "\n",
        "t = np.array([0, 1, 2], dtype=float)\n",
        "y = np.array([a, a + k, a + 2*k + 1], dtype=float)\n",
        "X = np.column_stack((np.ones_like(t), t))\n",
        "\n",
        "print(\"X =\\n\", X)\n",
        "print(\"y =\", y)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "`np.linalg.lstsq` returns the least-squares coefficients. The starred\n",
        "argument below silences a version-dependent default for the rank\n",
        "tolerance.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# TODO: compute the least-squares coefficient vector.\n",
        "# TODO: replace this placeholder with np.linalg.lstsq.\n",
        "coefficients = np.zeros(2)\n",
        "c0, c1 = coefficients\n",
        "\n",
        "y_hat = X @ coefficients\n",
        "residual = y - y_hat\n",
        "\n",
        "print(\"c0, c1 =\", coefficients)\n",
        "print(\"fitted values =\", y_hat)\n",
        "print(\"residual =\", residual)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 2. Verify the geometric condition\n",
        "\n",
        "The residual of a least-squares solution is orthogonal to every\n",
        "column of `X`, which is expressed compactly as $X^Tr=0$.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# TODO: compute the normal-equation residual and squared error.\n",
        "orthogonality_check = np.zeros(2)  # TODO: compute X.T @ residual\n",
        "squared_error = 0                  # TODO: compute residual @ residual\n",
        "\n",
        "print(\"X.T @ residual =\", orthogonality_check)\n",
        "print(\"squared error =\", squared_error)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 3. Plot the data and fitted line\n",
        "\n",
        "A plot is a diagnostic, not a replacement for the algebraic residual\n",
        "and orthogonality checks.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "\n",
        "plt.scatter(t, y, s=60, label=\"data\")\n",
        "plt.plot(t, y_hat, color=\"tab:orange\", label=\"least-squares line\")\n",
        "plt.xlabel(\"t\")\n",
        "plt.ylabel(\"y\")\n",
        "plt.legend()\n",
        "plt.grid(alpha=0.25)\n",
        "plt.show()\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3",
      "mimetype": "text/x-python",
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "pygments_lexer": "ipython3",
      "nbconvert_exporter": "python",
      "file_extension": ".py"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}
