HESSIAN
Overview
The HESSIAN function computes the Hessian matrix of a scalar-valued function using symbolic differentiation provided by CasADi, an open-source framework for nonlinear optimization and algorithmic differentiation. The Hessian matrix contains all second-order partial derivatives of a function and plays a critical role in optimization, sensitivity analysis, and understanding the local curvature of functions.
For a scalar function f: \mathbb{R}^n \to \mathbb{R} with variables x_1, x_2, \ldots, x_n, the Hessian matrix H is defined as:
H_{ij} = \frac{\partial^2 f}{\partial x_i \partial x_j}
This results in an n \times n symmetric matrix. In optimization, the Hessian is essential for second-order methods such as Newton’s method, where the search direction is computed using H^{-1} \nabla f. The eigenvalues of the Hessian at a critical point also determine whether it is a local minimum (all positive), local maximum (all negative), or saddle point (mixed signs). Specifically, if the Hessian is positive definite at a point where the gradient is zero, that point is a local minimum. If it is negative definite, it is a local maximum. If it has both positive and negative eigenvalues, it is a saddle point.
This implementation uses CasADi’s symbolic framework, which builds expression graphs using the SX data type for symbolic primitives. The function accepts a mathematical expression as a string (with support for caret notation for exponentiation), evaluates it symbolically, and then computes the Hessian using CasADi’s built-in hessian function. The result is evaluated numerically at the specified point and returned as a 2D matrix of values. Common mathematical functions including sin, cos, tan, exp, log, sqrt, and hyperbolic functions are supported within expressions.
Beyond optimization, the Hessian is used in various fields such as image processing (for blob detection and corner detection), structural engineering (for stability analysis), and economics (for analyzing utility functions). By providing exact second derivatives through algorithmic differentiation, this function avoids the numerical instability often associated with finite-difference approximations of second-order derivatives.
For more details on CasADi’s differentiation capabilities, see the CasADi documentation on calculus and algorithmic differentiation. The CasADi project is hosted on GitHub.
This example function is provided as-is without any representation of accuracy.
Excel Usage
=HESSIAN(expression, variables, variable_names)
expression(str, required): Scalar function as a string expression (e.g., “x^2 + 3xy + y^2”). Supports caret (^) notation for exponentiation.variables(list[list], required): 2D list of numeric values representing the point at which to evaluate the Hessian (e.g., [[1.0, 2.0]]).variable_names(list[list], optional, default: null): Optional 2D list of variable names as strings (e.g., [[“x”, “y”]]). If not provided, names are inferred from the expression.
Returns (list[list]): The Hessian matrix evaluated at the given point, as a 2D list of floats. str: Error message if calculation fails.
Examples
Example 1: Demo case 1
Inputs:
| expression | variables | |
|---|---|---|
| x^2 + 3xy + y^2 | 1 | 2 |
Excel formula:
=HESSIAN("x^2 + 3*x*y + y^2", {1,2})
Expected output:
| Result | |
|---|---|
| 2 | 3 |
| 3 | 2 |
Example 2: Demo case 2
Inputs:
| expression | variables | variable_names | ||
|---|---|---|---|---|
| x^2 + 3xy + y^2 | 1 | 2 | x | y |
Excel formula:
=HESSIAN("x^2 + 3*x*y + y^2", {1,2}, {"x","y"})
Expected output:
| Result | |
|---|---|
| 2 | 3 |
| 3 | 2 |
Example 3: Demo case 3
Inputs:
| expression | variables | variable_names | ||
|---|---|---|---|---|
| x^4 + y^4 + 2x^2y^2 | 1 | 1 | x | y |
Excel formula:
=HESSIAN("x^4 + y^4 + 2*x^2*y^2", {1,1}, {"x","y"})
Expected output:
| Result | |
|---|---|
| 16 | 8 |
| 8 | 16 |
Example 4: Demo case 4
Inputs:
| expression | variables | variable_names | ||
|---|---|---|---|---|
| x^2 | 2 | 0 | x | y |
Excel formula:
=HESSIAN("x^2", {2,0}, {"x","y"})
Expected output:
| Result | |
|---|---|
| 2 | 0 |
| 0 | 0 |
Python Code
import re
import casadi as ca
def hessian(expression, variables, variable_names=None):
"""
Compute the Hessian matrix (second derivatives) of a scalar function using CasADi symbolic differentiation.
See: https://web.casadi.org/docs/#hessian
This example function is provided as-is without any representation of accuracy.
Args:
expression (str): Scalar function as a string expression (e.g., "x^2 + 3*x*y + y^2"). Supports caret (^) notation for exponentiation.
variables (list[list]): 2D list of numeric values representing the point at which to evaluate the Hessian (e.g., [[1.0, 2.0]]).
variable_names (list[list], optional): Optional 2D list of variable names as strings (e.g., [["x", "y"]]). If not provided, names are inferred from the expression. Default is None.
Returns:
list[list]: The Hessian matrix evaluated at the given point, as a 2D list of floats. str: Error message if calculation fails.
"""
def to2d(x):
return [[x]] if not isinstance(x, list) else x
def create_casadi_context(names):
"""Create evaluation context with CasADi symbolic variables and functions."""
sym_vars = [ca.SX.sym(name) for name in names]
context = {name: sym_vars[idx] for idx, name in enumerate(names)}
context.update({
"ca": ca,
"sin": ca.sin,
"cos": ca.cos,
"tan": ca.tan,
"exp": ca.exp,
"log": ca.log,
"sqrt": ca.sqrt,
"atan": ca.atan,
"asin": ca.asin,
"acos": ca.acos,
"sinh": ca.sinh,
"cosh": ca.cosh,
"tanh": ca.tanh,
"fabs": ca.fabs,
"floor": ca.floor,
"ceil": ca.ceil,
})
return sym_vars, context
if not isinstance(expression, str) or not expression.strip():
return "Error: expression must be a non-empty string."
variables = to2d(variables)
if not variables or len(variables[0]) == 0:
return "Error: variables must be a 2D list of numeric values."
try:
var_vals = [float(v) for v in variables[0]]
except (TypeError, ValueError):
return "Error: variables must contain numeric values."
if len(var_vals) == 0:
return "Error: variables must include at least one value."
if variable_names is not None:
variable_names = to2d(variable_names)
if not variable_names or len(variable_names[0]) == 0:
return "Error: variable_names must be a non-empty 2D list of strings."
names = variable_names[0]
if len(names) != len(var_vals):
return f"Error: Number of variable names ({len(names)}) must equal number of variable values ({len(var_vals)})."
if not all(isinstance(name, str) for name in names):
return "Error: variable_names must contain only string values."
# Check for duplicate names
if len(names) != len(set(names)):
return "Error: variable_names must not contain duplicate names."
else:
# Infer variable names from expression
candidates = re.findall(r"[A-Za-z_]\w*", expression)
names = []
common_functions = {
'sin', 'cos', 'tan', 'exp', 'log', 'sqrt', 'abs', 'pi', 'e',
'ca', 'fabs', 'floor', 'ceil', 'sinh', 'cosh', 'tanh',
'asin', 'acos', 'atan'
}
for candidate in candidates:
if candidate not in names and candidate not in common_functions:
names.append(candidate)
if len(names) != len(var_vals):
return f"Error: Unable to infer variable names matching the number of values. Found {len(names)} names but expected {len(var_vals)}."
if len(names) == 0:
return "Error: No variable names found in expression."
try:
# Convert caret (^) to Python exponentiation (**)
expression = re.sub(r'\^', '**', expression)
# Create symbolic variables and evaluation context
sym_vars, evaluation_context = create_casadi_context(names)
# Evaluate the expression
expr_obj = eval(expression, {"__builtins__": {}}, evaluation_context)
# Compute Hessian
H = ca.hessian(expr_obj, ca.vertcat(*sym_vars))[0]
hess_func = ca.Function('hess_func', sym_vars, [H])
result = hess_func(*var_vals)
if isinstance(result, ca.DM):
return result.full().tolist()
else:
return f"Error: Error during CasADi calculation: Unexpected result type {type(result).__name__}."
except SyntaxError as e:
return f"Error: Invalid expression syntax: {str(e)}"
except NameError as e:
return f"Error: Undefined variable or function in expression: {str(e)}"
except Exception as e:
return f"Error: Error evaluating expression: {str(e)}"