Purpose

For the mathematical definitions behind these NumPy operations, see Elementary Linear Algebra and the more comprehensive Matrix Theory reference.

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]])
v_col_from_row = np.array([v_row]).T
assert np.array_equal(v_col, v_col_from_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