Python Linear Algebra Cheatsheet

Category: Linear Algebra

Fundamentals of Vectors

Working with Vectors in NumPy

import numpy as np

Creating Vectors

# Row vector
v_row = np.array([1, 2, 3])

# Column vector
v_col = np.array([[1], [2], [3]])
assert v_col = np.transpose(v_row)

Vector Operations

# Addition
v1, v2 = np.array([1, 2, 3]), np.array([4, 5, 6])
v_sum = v1 + v2

# Subtraction
v_diff = v1 - v2

# Scalar multiplication
c = 2
v_scaled = c * v1

# Dot product
dot_product = np.dot(v1, v2)

# Cross product
cross_product = np.cross(v1, v2)

Vector Norms

# L1 norm
l1_norm = np.linalg.norm(v, ord=1)

# L2 norm
l2_norm = np.linalg.norm(v, ord=2)

# Infinity norm
inf_norm = np.linalg.norm(v, ord=np.inf)

Useful Functions

# Normalize vector
normalize = lambda v: v / np.linalg.norm(v)

# Angle between vectors (radians)
angle_rad = lambda v1, v2: np.arccos(np.clip(np.dot(normalize(v1), normalize(v2)), -1.0, 1.0))

# Angle between vectors (degrees)
angle_deg = lambda v1, v2: np.degrees(angle_rad(v1, v2))

# Projection of v1 onto v2
projection = lambda v1, v2: np.dot(v1, normalize(v2)) * normalize(v2)

# Rejection of v1 from v2
rejection = lambda v1, v2: v1 - projection(v1, v2)

# Distance between vectors
distance = lambda v1, v2: np.linalg.norm(v1 - v2)

Visualization with Matplotlib

import matplotlib.pyplot as plt

2D Vectors

import numpy as np
import matplotlib.pyplot as plt

def plot_2d(*vectors, figsize=(10, 10), arrows=True, grid=True, equal_aspect=True):
    """
    Plot multiple 2D vectors on a Cartesian plane.

    Parameters:
    -----------
    *vectors : array-like
        Variable number of 2D vectors to plot. Each vector should be a 2D point
        or array-like object with x and y coordinates.
    figsize : tuple, optional (default=(10, 10))
        Figure size as (width, height)
    arrows : bool, optional (default=True)
        If True, draws vectors as arrows from origin. If False, plots as points/lines.
    grid : bool, optional (default=True)
        Whether to show the grid
    equal_aspect : bool, optional (default=True)
        Whether to maintain equal aspect ratio for x and y axes

    Returns:
    --------
    fig, ax : tuple
        Matplotlib figure and axis objects
    """
    # convert all inputs to numpy arrays
    vectors = [np.array(v, dtype=float) if not isinstance(v, np.ndarray) else v for v in vectors]

    # validate inputs
    for i, v in enumerate(vectors):
        if v.shape != (2,):
            raise ValueError(f"Vector {i} has shape {v.shape}, expected (2,)")

    fig, ax = plt.subplots(figsize=figsize)

    colors = plt.cm.tab10(np.linspace(0, 1, len(vectors)))

    for v, color in zip(vectors, colors):
        if arrows:
            ax.quiver(0, 0, v[0], v[1], angles='xy', scale_units='xy', scale=1,
                     color=color, width=0.005)
        else:
            ax.plot([0, v[0]], [0, v[1]], '-o', color=color)

    all_coords = np.vstack(vectors)
    max_abs_coord = np.max(np.abs(all_coords)) * 1.2  # Add 20% padding
    ax.set_xlim(-max_abs_coord, max_abs_coord)
    ax.set_ylim(-max_abs_coord, max_abs_coord)
    ax.axhline(y=0, color='k', linestyle='-', linewidth=0.5, alpha=0.3)  # x-axis
    ax.axvline(x=0, color='k', linestyle='-', linewidth=0.5, alpha=0.3)  # y-axis

    if grid:
        ax.grid(True, linestyle='--', alpha=0.3)

    if equal_aspect:
        ax.set_aspect('equal')

    ax.set_xlabel('x')
    ax.set_ylabel('y')

    return fig, ax

3D Vectors

import numpy as np
import matplotlib.pyplot as plt

def plot_3d(*vectors):
    """Plot multiple 3D vectors from origin as lines with dots at endpoints."""
    # Convert inputs to numpy arrays
    vectors = [np.array(v) for v in vectors]

    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')

    for v in vectors:
        # Plot line from origin to vector endpoint with dot
        ax.plot([0, v[0]], [0, v[1]], [0, v[2]], '-o')

    # Set equal aspect ratio and add labels
    ax.set_box_aspect([1,1,1])
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')

    return fig, ax

Matrices

Working with Matrices in NumPy

import numpy as np

Creating Matrices

# 2D array
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# Identity matrix
I = np.eye(3)

# Zero matrix
Z = np.zeros((3, 3))

# Ones matrix
O = np.ones((3, 3))

# Random matrix
R = np.random.rand(3, 3)

Matrix Operations

# Addition
A1, A2 = np.array([[1, 2], [3, 4]]), np.array([[5, 6], [7, 8]])
A_sum = A1 + A2

# Subtraction
A_diff = A1 - A2

# Scalar multiplication
c = 2
A_scaled = c * A1

# Matrix multiplication
A_prod = np.dot(A1, A2)

# Transpose
A_transpose = np.transpose(A)

# Inverse
A_inv = np.linalg.inv(A)

# Determinant
det_A = np.linalg.det(A)

# Trace
trace_A = np.trace(A)

# Rank
rank_A = np.linalg.matrix_rank(A)

# Eigenvalues and eigenvectors
eigenvalues, eigenvectors = np.linalg.eig(A)

# Singular value decomposition
U, S, V = np.linalg.svd(A)

# Matrix norms
l1_norm = np.linalg.norm(A, ord=1)

l2_norm = np.linalg.norm(A, ord=2)

inf_norm = np.linalg.norm(A, ord=np.inf)

fro_norm = np.linalg.norm(A, ord='fro')

# Matrix power
A_squared = np.linalg.matrix_power(A, 2)

Systems of Linear Equations

Solving Linear Systems

Matrix Inversion Method

A = np.array([[2, 1], [1, 1]])
b = np.array([3, 2])

x = np.linalg.inv(A).dot(b)

# or, much faster

x = np.linalg.solve(A, b)

print(x)

Vector Spaces

Linear Independence, Span, Basis


# check if set of vectors is linearly independent
is_linearly_independent = lambda *vectors: np.linalg.matrix_rank(np.array(vectors)) == len(vectors[0])

# check if vector is in span of other vectors
is_in_span = lambda v, *S: np.linalg.matrix_rank(np.array([*S, v])) == np.linalg.matrix_rank(S)

# find basis of a set of vectors
basis = lambda *vectors: np.array(vectors).T[:, np.linalg.matrix_rank(np.array(vectors)):]

Matrix Properties (cont. 1)

Dimension, Rank, Nullity, Row Space

# dimension of a vector space
dim = lambda *vectors: np.linalg.matrix_rank(np.array(vectors))
rank = lambda A: np.linalg.matrix_rank(A)
nullity = lambda A: A.shape[1] - rank(A)

Special Transformations

# reflection matrix
reflect = lambda n: np.eye(len(n)) - 2 * np.outer(n, n) / np.dot(n, n)

# projection matrix
project = lambda n: np.outer(n, n) / np.dot(n, n)

# rotation matrix
rotate = lambda theta: np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])

# scaling matrix
scale = lambda s: np.diag(s)

# shearing matrix
shear = lambda s: np.array([[1, s], [0, 1]])

# translation matrix
translate = lambda t: np.array([[1, 0, t[0]], [0, 1, t[1]], [0, 0, 1]])

# homogenous coordinates
homogenize = lambda v: np.append(v, 1)

# dehomogenize
dehomogenize = lambda v: v[:-1] / v[-1]

# affine transformation
affine = lambda A, t: np.block([[A, t], [0, 0, 1]])

# perspective transformation
perspective = lambda d: np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1/d]])

Orthogonality

# check if two vectors are orthogonal
is_orthogonal = lambda u, v: np.dot(u, v) == 0

# check if set of vectors is orthogonal
is_orthogonal_set = lambda *vectors: all(np.dot(v1, v2) == 0 for v1, v2 in itertools.combinations(vectors, 2))

# check if set of vectors is orthonormal
is_orthonormal_set = lambda *vectors: is_orthogonal_set(*vectors) and all(np.linalg.norm(v) == 1 for v in vectors)

# check if matrix is orthogonal
is_orthogonal_matrix = lambda A: np.allclose(np.dot(A, A.T), np.eye(A.shape[0]))

# check if matrix is orthonormal
is_orthonormal_matrix = lambda A: is_orthogonal_matrix(A) and np.allclose(np.linalg.det(A), 1)

Change of Basis

# change of basis matrix
change_of_basis = lambda B, C: np.linalg.inv(C) @ B