{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# MATH 4242 Python Lab 2: Solving systems and measuring residuals\n",
        "\n",
        "**Course sections:** 1.4--1.6\n",
        "\n",
        "This notebook accompanies LEAP Assignment 2. 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:** Highly guided. Read each worked line, run it, and change only the values or expressions specifically marked.\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": [
        "## 0. Learn the solver on a complete example\n",
        "\n",
        "The command **np.linalg.solve(C, d)** returns the vector that solves\n",
        "the system $Cz=d$. First run this fully worked example. Notice that\n",
        "the code verifies the result by computing $Cz-d$.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "C = np.array([[2, 1],\n",
        "              [1, 3]], dtype=float)\n",
        "d = np.array([5, 5], dtype=float)\n",
        "z = np.linalg.solve(C, d)\n",
        "\n",
        "print(\"solution z =\", z)\n",
        "print(\"check C @ z - d =\", C @ z - d)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 1. Enter your randomized system\n",
        "\n",
        "LEAP generated `k`, `p`, and `q`, then constructed the right-hand side\n",
        "so the exact solution is hidden in the data. Copy all three values.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Replace these three example values with your LEAP values.\n",
        "k = 3\n",
        "p = 2\n",
        "q = -2\n",
        "\n",
        "A = np.array([[1, k],\n",
        "              [2, 2*k + 1]], dtype=float)\n",
        "bvec = np.array([p + k*q,\n",
        "                 2*p + (2*k + 1)*q], dtype=float)\n",
        "\n",
        "print(\"A =\\n\", A)\n",
        "print(\"b =\", bvec)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 2. Solve and verify\n",
        "\n",
        "`np.linalg.solve(A, b)` solves the system without explicitly forming\n",
        "an inverse. The residual is $r=b-A\\hat{x}$. A small residual confirms\n",
        "that the computed vector satisfies the equations closely.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Worked line: solve A xhat = bvec.\n",
        "xhat = np.linalg.solve(A, bvec)\n",
        "\n",
        "# TODO: replace the 0 with bvec - A @ xhat.\n",
        "residual = 0\n",
        "\n",
        "print(\"computed solution:\", xhat)\n",
        "print(\"residual:\", residual)\n",
        "print(\"residual norm:\", np.linalg.norm(residual))\n",
        "print(\"det(A):\", np.linalg.det(A))\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 3. Sensitivity experiment\n",
        "\n",
        "Change only the second entry of the right-hand side by $0.01$. Compare\n",
        "the two solutions. This distinguishes a residual from a change in the\n",
        "solution caused by changed data.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "b_tilde = bvec + np.array([0.0, 0.01])\n",
        "\n",
        "# TODO: imitate the earlier solve line for the new right-hand side.\n",
        "x_tilde = np.linalg.solve(A, b_tilde)\n",
        "\n",
        "# TODO: replace the 0 with the new solution minus the old solution.\n",
        "delta_x = 0\n",
        "\n",
        "print(\"perturbed solution:\", x_tilde)\n",
        "print(\"change in solution:\", delta_x)\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
}
