For a scalar function of explicitly ordered variables, the gradient is the column vector of its partial derivatives:
\[ \nabla f(x_1,\ldots,x_n)= \begin{pmatrix} \frac{\partial f}{\partial x_1}\\ \vdots\\ \frac{\partial f}{\partial x_n} \end{pmatrix}. \]
SymPy's matrix Jacobian provides a compact implementation. A scalar function is represented as a one-element matrix, so its Jacobian is a row matrix; transposing it produces the conventional column gradient.
from sympy import Matrix, symbols
x, y = symbols("x y", real=True)
variables = Matrix([x, y])
f = 8 * x**2 + 4 * y**2 - 9
gradient_f = Matrix([f]).jacobian(variables).T
print(gradient_f)
# Matrix([[16*x], [8*y]]) The order of variables defines the meaning of the components. This is important: f.free_symbols is a set, not a coordinate system. Constructing the variable list with list(f.free_symbols) therefore does not establish whether the first component means \(\partial f/\partial x\) or \(\partial f/\partial y\).
Direct differentiation
The same gradient can be written directly from the definition. This form is useful when the code should make the component construction obvious:
from sympy import Matrix, diff
gradient_f = Matrix([diff(f, variable) for variable in variables]) Both forms return a \(2\times1\) matrix. For a vector-valued function \(F:\mathbb{R}^n\to\mathbb{R}^m\), keep the full \(m\times n\) Jacobian instead of transposing it:
from sympy import Matrix
F = Matrix([x**2 + y, x * y])
jacobian_F = F.jacobian(variables)
print(jacobian_F)
# Matrix([[2*x, 1], [y, x]]) Gradient in a coordinate system
sympy.vector.gradient() is a different interface for scalar fields expressed in a CoordSys3D coordinate system. Its result includes basis vectors:
from sympy.vector import CoordSys3D, gradient
N = CoordSys3D("N")
scalar_field = N.x**2 + N.y**2
print(gradient(scalar_field))
# 2*N.x*N.i + 2*N.y*N.j Use the matrix form when variables and component order are the relevant representation. Use the vector module when basis vectors, coordinate systems, divergence, curl, or related vector-calculus operations are part of the model.
Second derivatives
The derivative of the gradient is the Hessian. SymPy exposes it directly and uses the same explicit variable order:
from sympy import hessian
hessian_f = hessian(f, variables)
print(hessian_f)
# Matrix([[16, 0], [0, 8]]) The positive diagonal entries show that the example function is strictly convex. Its only stationary point, obtained from gradient_f = 0, is \((0,0)\), and the Hessian confirms that this point is the global minimum.