Section B.11 SymPy Symbolic Computation
This section helps you read SymPy commands for exact symbolic formulas, matrices, Jacobians, substitutions, and null spaces.
SymPy is for exact symbolic expressions. NumPy is for numerical arrays and numerical linear algebra.
Row reduction and entry indexing.
Use integer entries in
sp.Matrix for exact arithmetic. The assignment R, pivots = M.rref() unpacks two results: the reduced matrix and a tuple of pivot-column indices. Both row and column indices start at zero. The expression R[i, j] selects the scalar entry in row i, column j.
import sympy as sp
M = sp.Matrix([
[1, 1, -2, 4],
[2, 3, -3, 9],
])
R, pivots = M.rref()
z = -1
solution = [R[0, 3] - R[0, 2]*z,
R[1, 3] - R[1, 2]*z,
z]
solution
Here
pivots is (0, 1), and the reduced equations are \(x-3z=3\) and \(y+z=1\text{.}\) Thus solution is the Python list [0, 2, -1]. For example, R[0, 3] is the first rowβs right-hand side, \(3\text{.}\) The fourth column is the augmented column, not a fourth variable. Here * multiplies individual numbers. For reading row-reduction output, see 2.2.54; for entry indexing, see 2.4.41.
Column slices and list comprehensions.
For a SymPy matrix,
A[:, j] selects all rows of column j, producing a column matrix. The colon means βall entries along this direction.β In contrast, A[j, :] selects a row. A list comprehension evaluates one expression for each item in a collection and collects the results in a Python list.
import sympy as sp
A = sp.Matrix([
[2, 4, 0],
[1, 2, 1],
[3, 6, 2],
])
R, pivots = A.rref()
columns = [A[:, j] for j in pivots]
columns
Read the last assignment as βfor each pivot index
j, select column j of A.β Here pivots is (0, 2), so the list contains the first and third columns of A, a basis for \(\operatorname{col}(A)\text{.}\) Use these indices unchanged in Python. Adding one is only for reporting mathematical column numbers. Select columns from the original A, since row operations can change the column space. See 2.4.41.
The equivalent loop starts with an empty list and uses
append to add each column:
columns = []
for j in pivots:
columns.append(A[:, j])
Null-space lists and matrix-vector products.
A.nullspace() returns a Python list containing a basis for the null space, with each vector stored as a SymPy column matrix. basis[0] selects the first vector from a nonempty list; len(basis) counts the vectors and gives the nullity. The zero subspace has an empty basis list [], so there is no basis[0] in that case.
import sympy as sp
A = sp.Matrix([
[1, 0, 2],
[0, 1, -1],
[2, 1, 3],
])
basis = A.nullspace()
z = basis[0]
A * z
Here
basis contains one vector, z is the column sp.Matrix([-2, 1, 1]), and A * z is the \(3\times1\) zero column. Passing a flat list to sp.Matrix creates a column matrix. With two numbers, * is ordinary multiplication; with a number and a matrix, it scales every entry. With two SymPy matrices, * means matrix multiplication, whereas NumPy arrays use @ for matrix multiplication and * for entrywise multiplication. A * basis is an error: the list of vectors is not itself a column matrix.
z.shape gives (3, 1), the pair (rows, columns). z.T transposes the column to a \(1\times3\) row. The product z.T * A is therefore a row and need not be zero when A * z is zero. sp.ones(3, 1) creates a SymPy column of three ones; this is generally a different vector from basis[0]. Practice these distinctions in 2.4.56.
import sympy as sp
import numpy as np
x, y = sp.symbols("x y")
F = sp.Matrix([
x**2 * y,
x * sp.exp(y)
])
J = F.jacobian([x, y])
J_at_a = J.subs({x: 1.0, y: 0.0})
J_at_a = np.array(J_at_a, dtype=float)
sp.diff(x**3 + x*y, x)
B = sp.Matrix([[1, 2, 3],
[2, 4, 6],
[0, 1, 1]])
B.rref()
B.nullspace()
sp.eye(3)
A = [[1, 2, 3],
[2, 4, 6],
[0, 1, 1]]
sp.Matrix(A).nullspace()
Symbols.
sp.symbols("x y")
Read as. Create symbolic variables.
Shape/return. Symbols.
Used for. Symbolic formulas.
Symbolic matrix.
sp.Matrix([...])
Read as. A symbolic vector or matrix.
Shape/return. A SymPy Matrix.
Used for. Exact linear algebra.
Jacobian.
F.jacobian([x, y])
Read as. A symbolic Jacobian.
Shape/return. A SymPy Matrix.
Used for. Local linearization.
Symbolic derivative.
sp.diff(f, x)
Read as. Differentiate a symbolic expression with respect to
x.
Shape/return. A symbolic expression.
Used for. Exact derivative checks.
Substitution.
J.subs({...})
Read as. Substitute values.
Shape/return. A symbolic or numeric expression.
Used for. Evaluate at a point.
NumPy conversion.
np.array(J_at_a, dtype=float)
Read as. Convert to NumPy.
Shape/return. A NumPy array.
Used for. Numerical matrix multiplication.
Reduced row echelon form.
M.rref()
Read as. Compute the reduced row echelon form exactly.
Output. A pair
(R, pivots).
Used for. Pivot columns, free variables, and solution sets.
Watch for. Pivot indices are zero-based; 0 means the first column.
Nullspace.
M.nullspace()
Read as. Return a basis for the null space.
Shape/return. A list of SymPy column vectors.
Used for. Exact null-space directions.
Symbolic identity matrix.
sp.eye(n)
Read as. The \(n\times n\) identity matrix in SymPy.
Shape/return. A SymPy Matrix.
Used for. Exact matrix examples.
To switch from exact SymPy calculations to numerical NumPy calculations, convert with
np.array(..., dtype=float) and use NumPyβs @ operator for matrix multiplication. Exact SymPy matrix products do not require this conversion.
