{ "cells": [ { "cell_type": "markdown", "id": "header", "metadata": {}, "source": [ "# Matrix Multiplication\n", "\n", "Matrix multiplication is different from element-by-element multiplication. It's more powerful and represents composition of transformations.\n", "\n", "## The Key Idea\n", "\n", "Matrix multiplication combines two matrices to create a new one. It's not just multiplying corresponding elements—it involves **rows times columns**.\n", "\n", "For matrices $A$ (size $m \\times n$) and $B$ (size $n \\times p$), the product $C = AB$ has size $m \\times p$.\n", "\n", "**Important**: The number of columns in $A$ must equal the number of rows in $B$." ] }, { "cell_type": "markdown", "id": "rule", "metadata": {}, "source": [ "## The Multiplication Rule\n", "\n", "To compute element $(i, j)$ of $C = AB$:\n", "\n", "$$\n", "c_{ij} = \\sum_{k=1}^{n} a_{ik} b_{kj}\n", "$$\n", "\n", "In words: **take row $i$ of $A$ and column $j$ of $B$, multiply corresponding elements, and sum them.**\n", "\n", "### Example\n", "\n", "$$\n", "\\begin{bmatrix}\n", "1 & 2 \\\\\n", "3 & 4\n", "\\end{bmatrix}\n", "\\begin{bmatrix}\n", "5 & 6 \\\\\n", "7 & 8\n", "\\end{bmatrix}\n", "=\n", "\\begin{bmatrix}\n", "1 \\cdot 5 + 2 \\cdot 7 & 1 \\cdot 6 + 2 \\cdot 8 \\\\\n", "3 \\cdot 5 + 4 \\cdot 7 & 3 \\cdot 6 + 4 \\cdot 8\n", "\\end{bmatrix}\n", "=\n", "\\begin{bmatrix}\n", "19 & 22 \\\\\n", "43 & 50\n", "\\end{bmatrix}\n", "$$" ] }, { "cell_type": "code", "execution_count": null, "id": "example", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "A = np.array([[1, 2],\n", " [3, 4]])\n", "\n", "B = np.array([[5, 6],\n", " [7, 8]])\n", "\n", "C = A @ B # Matrix multiplication using @\n", "\n", "print(\"A =\")\n", "print(A)\n", "print(\"\\nB =\")\n", "print(B)\n", "print(\"\\nA @ B =\")\n", "print(C)" ] }, { "cell_type": "markdown", "id": "step-by-step", "metadata": {}, "source": [ "## Step-by-Step Calculation\n", "\n", "Let's compute each element manually to see how it works:" ] }, { "cell_type": "code", "execution_count": null, "id": "manual-calc", "metadata": {}, "outputs": [], "source": [ "# Element (0, 0): row 0 of A, column 0 of B\n", "c_00 = A[0, 0] * B[0, 0] + A[0, 1] * B[1, 0]\n", "print(f\"c[0,0] = {A[0,0]} * {B[0,0]} + {A[0,1]} * {B[1,0]} = {c_00}\")\n", "\n", "# Element (0, 1): row 0 of A, column 1 of B\n", "c_01 = A[0, 0] * B[0, 1] + A[0, 1] * B[1, 1]\n", "print(f\"c[0,1] = {A[0,0]} * {B[0,1]} + {A[0,1]} * {B[1,1]} = {c_01}\")\n", "\n", "# Element (1, 0): row 1 of A, column 0 of B\n", "c_10 = A[1, 0] * B[0, 0] + A[1, 1] * B[1, 0]\n", "print(f\"c[1,0] = {A[1,0]} * {B[0,0]} + {A[1,1]} * {B[1,0]} = {c_10}\")\n", "\n", "# Element (1, 1): row 1 of A, column 1 of B\n", "c_11 = A[1, 0] * B[0, 1] + A[1, 1] * B[1, 1]\n", "print(f\"c[1,1] = {A[1,0]} * {B[0,1]} + {A[1,1]} * {B[1,1]} = {c_11}\")" ] }, { "cell_type": "markdown", "id": "properties", "metadata": {}, "source": [ "## Key Properties\n", "\n", "### Not Commutative\n", "\n", "**Important**: $AB \\neq BA$ in general. Order matters!" ] }, { "cell_type": "code", "execution_count": null, "id": "commutative-test", "metadata": {}, "outputs": [], "source": [ "AB = A @ B\n", "BA = B @ A\n", "\n", "print(\"A @ B =\")\n", "print(AB)\n", "print(\"\\nB @ A =\")\n", "print(BA)\n", "print(\"\\nAre they equal?\", np.allclose(AB, BA))" ] }, { "cell_type": "markdown", "id": "associative", "metadata": {}, "source": [ "### Associative\n", "\n", "$(AB)C = A(BC)$ — you can group multiplications however you want." ] }, { "cell_type": "code", "execution_count": null, "id": "associative-test", "metadata": {}, "outputs": [], "source": [ "C_mat = np.array([[1, 0],\n", " [0, 1]])\n", "\n", "# (AB)C\n", "result1 = (A @ B) @ C_mat\n", "\n", "# A(BC)\n", "result2 = A @ (B @ C_mat)\n", "\n", "print(\"(A @ B) @ C =\")\n", "print(result1)\n", "print(\"\\nA @ (B @ C) =\")\n", "print(result2)\n", "print(\"\\nAre they equal?\", np.allclose(result1, result2))" ] }, { "cell_type": "markdown", "id": "matrix-vector", "metadata": {}, "source": [ "## Matrix-Vector Multiplication\n", "\n", "A common case: multiply a matrix by a vector. This transforms the vector." ] }, { "cell_type": "code", "execution_count": null, "id": "matrix-vector-example", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "\n", "# Original vector\n", "v = np.array([1, 2])\n", "\n", "# Transformation matrix (rotation by 45 degrees)\n", "theta = np.pi / 4\n", "R = np.array([[np.cos(theta), -np.sin(theta)],\n", " [np.sin(theta), np.cos(theta)]])\n", "\n", "# Transform the vector\n", "v_transformed = R @ v\n", "\n", "print(\"Original vector:\", v)\n", "print(\"Transformed vector:\", v_transformed)\n", "\n", "# Visualize\n", "plt.figure(figsize=(6, 6))\n", "plt.quiver(0, 0, v[0], v[1], angles='xy', scale_units='xy', scale=1, \n", " color='blue', width=0.006, label='Original')\n", "plt.quiver(0, 0, v_transformed[0], v_transformed[1], angles='xy', \n", " scale_units='xy', scale=1, color='red', width=0.006, \n", " label='Rotated 45°')\n", "plt.xlim(-1, 3)\n", "plt.ylim(-1, 3)\n", "plt.grid(True)\n", "plt.axhline(0, color='black', linewidth=0.5)\n", "plt.axvline(0, color='black', linewidth=0.5)\n", "plt.legend()\n", "plt.title('Matrix-Vector Multiplication as Transformation')\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "why-this-way", "metadata": {}, "source": [ "## Why This Definition?\n", "\n", "Matrix multiplication is defined this way because it represents **composition of linear transformations**.\n", "\n", "If matrix $A$ transforms vector $\\mathbf{v}$ to $A\\mathbf{v}$, and matrix $B$ transforms $A\\mathbf{v}$ to $B(A\\mathbf{v})$, then:\n", "\n", "$$\n", "B(A\\mathbf{v}) = (BA)\\mathbf{v}\n", "$$\n", "\n", "The product matrix $BA$ represents doing transformation $A$ followed by transformation $B$." ] }, { "cell_type": "markdown", "id": "shape-compatibility", "metadata": {}, "source": [ "## Shape Compatibility\n", "\n", "For $C = AB$:\n", "- $A$ is $m \\times n$\n", "- $B$ is $n \\times p$\n", "- $C$ is $m \\times p$\n", "\n", "The **inner dimensions must match** ($n$), and the result has the **outer dimensions** ($m \\times p$)." ] }, { "cell_type": "code", "execution_count": null, "id": "shape-example", "metadata": {}, "outputs": [], "source": [ "# Example: (2x3) @ (3x4) -> (2x4)\n", "A = np.random.rand(2, 3)\n", "B = np.random.rand(3, 4)\n", "C = A @ B\n", "\n", "print(f\"A shape: {A.shape}\")\n", "print(f\"B shape: {B.shape}\")\n", "print(f\"C = A @ B shape: {C.shape}\")\n", "\n", "# This would fail:\n", "# D = np.random.rand(2, 5)\n", "# E = A @ D # Error: shapes (2,3) and (2,5) not aligned" ] }, { "cell_type": "markdown", "id": "next-steps", "metadata": {}, "source": [ "## Next Steps\n", "\n", "Now that you understand matrix multiplication, you can see how matrices represent transformations in {doc}`matrix-as-transform`." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.12.0" } }, "nbformat": 4, "nbformat_minor": 5 }