Skip to content

Linear Transformations

A matrix is not just a grid of numbers — it is a function. When you multiply a matrix by a vector, you are applying a linear transformation: stretching, rotating, reflecting, or projecting the vector into a new position.

panchi makes this concrete.

Applying a transformation

The @ operator applies a matrix to a vector:

import panchi as pan

A = pan.Matrix([[2, 0],
                [0, 3]])

v = pan.Vector([1, 1])
print(A @ v)  # [2, 3]

This scales the x-component by 2 and the y-component by 3. The matrix encodes the transformation; the vector is what gets transformed.

transform(v) is an explicit alias for the same operation, useful when you want to be clear about intent:

print(A.transform(v))  # [2, 3]

Rotation matrices

A rotation matrix rotates vectors without changing their magnitude. panchi provides factory functions for 2D and 3D rotations:

from math import pi

R = pan.rotation_matrix_2d(pi / 2)  # 90° counterclockwise

point = pan.Vector([1, 0])
rotated = R @ point
print(rotated)  # [~0.0, 1.0]

The rotated vector has the same magnitude as the original:

from math import isclose
assert isclose(rotated.magnitude, point.magnitude, abs_tol=1e-10)

For 3D rotations, provide an axis vector:

axis = pan.Vector([0, 0, 1])  # rotate around the z-axis
R3 = pan.rotation_matrix_3d(pi / 2, axis)

The axis is normalized automatically.

Composing transformations

Because matrix multiplication is associative, you can compose transformations by multiplying their matrices. The transformations are applied right to left:

scale = pan.Matrix([[2, 0], [0, 2]])
rotate = pan.rotation_matrix_2d(pi / 2)

# First scale, then rotate
composed = rotate @ scale

v = pan.Vector([1, 0])
print(composed @ v)  # [0, 2]

Verifying mathematical identities

panchi's transparent implementation makes it easy to verify textbook identities experimentally:

A = pan.Matrix([[1, 2], [3, 4]])
B = pan.Matrix([[5, 6], [7, 8]])

# (AB)ᵀ = BᵀAᵀ
assert (A @ B).T == B.T @ A.T