{ "cells": [ { "cell_type": "markdown", "id": "header", "metadata": {}, "source": [ "# Matrices as Transformations\n", "\n", "One of the most powerful ways to think about matrices is as **transformations** of space. When you multiply a matrix by a vector, you're transforming that vector to a new location.\n", "\n", "## The Key Insight\n", "\n", "A matrix $A$ transforms a vector $\\mathbf{v}$ into a new vector $\\mathbf{w}$:\n", "\n", "$$\n", "\\mathbf{w} = A\\mathbf{v}\n", "$$\n", "\n", "Different matrices perform different transformations: rotations, scalings, reflections, shears, and more." ] }, { "cell_type": "code", "execution_count": null, "id": "imports", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "def plot_transformation(A, vectors=None, title=\"\"):\n", " \"\"\"Plot original and transformed vectors.\"\"\"\n", " if vectors is None:\n", " # Default: unit vectors and a test vector\n", " vectors = np.array([[1, 0], [0, 1], [1, 1]]).T\n", " \n", " transformed = A @ vectors\n", " origins = np.zeros(vectors.shape[1])\n", " \n", " fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))\n", " \n", " # Original vectors\n", " ax1.quiver(origins, origins, vectors[0], vectors[1], angles='xy', scale_units='xy', \n", " scale=1, color=['red', 'blue', 'green'], width=0.006)\n", " ax1.set_xlim(-3, 3)\n", " ax1.set_ylim(-3, 3)\n", " ax1.grid(True, alpha=0.3)\n", " ax1.axhline(0, color='black', linewidth=0.5)\n", " ax1.axvline(0, color='black', linewidth=0.5)\n", " ax1.set_aspect('equal')\n", " ax1.set_title('Original Vectors')\n", " \n", " # Transformed vectors\n", " ax2.quiver(origins, origins, transformed[0], transformed[1], angles='xy', \n", " scale_units='xy', scale=1, color=['red', 'blue', 'green'], \n", " width=0.006)\n", " ax2.set_xlim(-3, 3)\n", " ax2.set_ylim(-3, 3)\n", " ax2.grid(True, alpha=0.3)\n", " ax2.axhline(0, color='black', linewidth=0.5)\n", " ax2.axvline(0, color='black', linewidth=0.5)\n", " ax2.set_aspect('equal')\n", " ax2.set_title('Transformed Vectors')\n", " \n", " if title:\n", " fig.suptitle(title, fontsize=14, fontweight='bold')\n", " \n", " plt.tight_layout()\n", " plt.show()" ] }, { "cell_type": "markdown", "id": "scaling", "metadata": {}, "source": [ "## Scaling\n", "\n", "A diagonal matrix scales vectors along each axis:\n", "\n", "$$\n", "A = \\begin{bmatrix}\n", "2 & 0 \\\\\n", "0 & 0.5\n", "\\end{bmatrix}\n", "$$\n", "\n", "This doubles the $x$-component and halves the $y$-component." ] }, { "cell_type": "code", "execution_count": null, "id": "scaling-demo", "metadata": {}, "outputs": [], "source": [ "# Scaling matrix\n", "S = np.array([[2, 0],\n", " [0, 0.5]])\n", "\n", "print(\"Scaling matrix:\")\n", "print(S)\n", "\n", "plot_transformation(S, title=\"Scaling: 2x horizontal, 0.5x vertical\")" ] }, { "cell_type": "markdown", "id": "rotation", "metadata": {}, "source": [ "## Rotation\n", "\n", "A rotation matrix rotates vectors by an angle $\\theta$:\n", "\n", "$$\n", "R(\\theta) = \\begin{bmatrix}\n", "\\cos\\theta & -\\sin\\theta \\\\\n", "\\sin\\theta & \\cos\\theta\n", "\\end{bmatrix}\n", "$$\n", "\n", "Let's rotate by 90 degrees ($\\pi/2$ radians):" ] }, { "cell_type": "code", "execution_count": null, "id": "rotation-demo", "metadata": {}, "outputs": [], "source": [ "# 90 degree rotation\n", "theta = np.pi / 2\n", "R = np.array([[np.cos(theta), -np.sin(theta)],\n", " [np.sin(theta), np.cos(theta)]])\n", "\n", "print(\"Rotation matrix (90°):\")\n", "print(R)\n", "\n", "plot_transformation(R, title=\"Rotation: 90° counterclockwise\")" ] }, { "cell_type": "markdown", "id": "reflection", "metadata": {}, "source": [ "## Reflection\n", "\n", "Reflection across the $x$-axis flips the $y$-coordinate:\n", "\n", "$$\n", "F = \\begin{bmatrix}\n", "1 & 0 \\\\\n", "0 & -1\n", "\\end{bmatrix}\n", "$$" ] }, { "cell_type": "code", "execution_count": null, "id": "reflection-demo", "metadata": {}, "outputs": [], "source": [ "# Reflection across x-axis\n", "F = np.array([[1, 0],\n", " [0, -1]])\n", "\n", "print(\"Reflection matrix:\")\n", "print(F)\n", "\n", "plot_transformation(F, title=\"Reflection: across x-axis\")" ] }, { "cell_type": "markdown", "id": "shear", "metadata": {}, "source": [ "## Shear\n", "\n", "A shear transformation \"skews\" space:\n", "\n", "$$\n", "H = \\begin{bmatrix}\n", "1 & 1 \\\\\n", "0 & 1\n", "\\end{bmatrix}\n", "$$\n", "\n", "This adds the $y$-coordinate to the $x$-coordinate, creating a slant." ] }, { "cell_type": "code", "execution_count": null, "id": "shear-demo", "metadata": {}, "outputs": [], "source": [ "# Horizontal shear\n", "H = np.array([[1, 1],\n", " [0, 1]])\n", "\n", "print(\"Shear matrix:\")\n", "print(H)\n", "\n", "plot_transformation(H, title=\"Shear: horizontal\")" ] }, { "cell_type": "markdown", "id": "composition", "metadata": {}, "source": [ "## Composing Transformations\n", "\n", "You can combine transformations by multiplying matrices. The order matters!\n", "\n", "Let's rotate by 45° and then scale:" ] }, { "cell_type": "code", "execution_count": null, "id": "composition-demo", "metadata": {}, "outputs": [], "source": [ "# Rotation by 45 degrees\n", "theta = np.pi / 4\n", "R45 = np.array([[np.cos(theta), -np.sin(theta)],\n", " [np.sin(theta), np.cos(theta)]])\n", "\n", "# Scaling\n", "S = np.array([[2, 0],\n", " [0, 0.5]])\n", "\n", "# Combined: scale THEN rotate\n", "combined = R45 @ S\n", "\n", "print(\"Combined transformation (rotate after scale):\")\n", "print(combined)\n", "\n", "plot_transformation(combined, title=\"Combined: Scale then Rotate 45°\")" ] }, { "cell_type": "markdown", "id": "grid", "metadata": {}, "source": [ "## Transforming the Grid\n", "\n", "Let's visualize how a transformation affects an entire grid of points:" ] }, { "cell_type": "code", "execution_count": null, "id": "grid-demo", "metadata": {}, "outputs": [], "source": [ "def plot_grid_transformation(A, title=\"\"):\n", " \"\"\"Plot how a grid is transformed.\"\"\"\n", " # Create a grid of points\n", " x = np.linspace(-2, 2, 9)\n", " y = np.linspace(-2, 2, 9)\n", " X, Y = np.meshgrid(x, y)\n", " \n", " # Flatten to column vectors\n", " points = np.vstack([X.ravel(), Y.ravel()])\n", " \n", " # Transform\n", " transformed = A @ points\n", " \n", " fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))\n", " \n", " # Original grid\n", " ax1.scatter(points[0], points[1], c='blue', s=20, alpha=0.6)\n", " ax1.set_xlim(-3, 3)\n", " ax1.set_ylim(-3, 3)\n", " ax1.grid(True, alpha=0.3)\n", " ax1.axhline(0, color='black', linewidth=0.5)\n", " ax1.axvline(0, color='black', linewidth=0.5)\n", " ax1.set_aspect('equal')\n", " ax1.set_title('Original Grid')\n", " \n", " # Transformed grid\n", " ax2.scatter(transformed[0], transformed[1], c='red', s=20, alpha=0.6)\n", " ax2.set_xlim(-3, 3)\n", " ax2.set_ylim(-3, 3)\n", " ax2.grid(True, alpha=0.3)\n", " ax2.axhline(0, color='black', linewidth=0.5)\n", " ax2.axvline(0, color='black', linewidth=0.5)\n", " ax2.set_aspect('equal')\n", " ax2.set_title('Transformed Grid')\n", " \n", " if title:\n", " fig.suptitle(title, fontsize=14, fontweight='bold')\n", " \n", " plt.tight_layout()\n", " plt.show()\n", "\n", "# Try with a shear transformation\n", "H = np.array([[1, 0.5],\n", " [0.5, 1]])\n", "\n", "plot_grid_transformation(H, title=\"How a grid is sheared\")" ] }, { "cell_type": "markdown", "id": "identity", "metadata": {}, "source": [ "## The Identity Matrix\n", "\n", "The identity matrix $I$ leaves vectors unchanged:\n", "\n", "$$\n", "I = \\begin{bmatrix}\n", "1 & 0 \\\\\n", "0 & 1\n", "\\end{bmatrix}\n", "$$\n", "\n", "$$\n", "I\\mathbf{v} = \\mathbf{v}\n", "$$\n", "\n", "It's the \"do nothing\" transformation." ] }, { "cell_type": "code", "execution_count": null, "id": "identity-demo", "metadata": {}, "outputs": [], "source": [ "I = np.eye(2)\n", "\n", "v = np.array([2, 3])\n", "result = I @ v\n", "\n", "print(f\"I @ {v} = {result}\")\n", "print(\"\\nThe identity matrix leaves vectors unchanged.\")" ] }, { "cell_type": "markdown", "id": "why-it-matters", "metadata": {}, "source": [ "## Why This Matters\n", "\n", "Thinking of matrices as transformations is incredibly powerful:\n", "\n", "- **Computer Graphics**: Every 3D rotation, translation, and projection is a matrix\n", "- **Robotics**: Transforming coordinates between robot joints\n", "- **Data Science**: PCA and dimensionality reduction are geometric transformations\n", "- **Physics**: State transformations in quantum mechanics\n", "\n", "When you see matrix multiplication, think: \"What transformation is happening here?\"" ] }, { "cell_type": "markdown", "id": "next-steps", "metadata": {}, "source": [ "## Next Steps\n", "\n", "Now that you understand matrices as transformations, you're ready to explore:\n", "- {doc}`../applications/solving-systems` - Using matrices to solve equations\n", "- {doc}`../applications/least-squares` - Finding best-fit solutions\n", "- Applications in graphics, signal processing, and engineering" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.12.0" } }, "nbformat": 4, "nbformat_minor": 5 }