SENSITIVITY
Overview
The SENSITIVITY function evaluates how a scalar model output responds to changes in its parameters by wrapping CasADi ’s automatic differentiation. For a model with variables and parameters , the sensitivity row vector contains the partial derivatives evaluated at a selected point. This example function is provided as-is without any representation of accuracy.
Usage
In Excel, the function is entered as:
=SENSITIVITY(model, variables, parameters, [variable_names], [parameter_names])model(string, required): Expression defining the model output. CasADi symbols such asca.expare supported.variables(2D list of float, required): Single row of variable values where the sensitivity is evaluated.parameters(2D list of float, required): Single row of parameter values that define the evaluation point.variable_names(2D list of string, optional): Names of the variables in order; defaults tox1,x2, … if omitted.parameter_names(2D list of string, optional): Names of the parameters in order; defaults toa1,a2, … if omitted.
The function returns a 2D list containing one row of partial derivatives with respect to each parameter, or an error message string when validation fails.
Examples
Example 1: Polynomial Single Point
Inputs:
| model | variables | parameters | variable_names | parameter_names |
|---|---|---|---|---|
| x1^2 + a1*x1 | 2 | 3 | x1 | a1 |
Excel formula:
=SENSITIVITY("x1^2 + a1*x1", {2}, {3}, {"x1"}, {"a1"})Expected output:
| Result |
|---|
| 2.000 |
Example 2: Exponential Sum
Inputs:
| model | variables | parameters | variable_names | parameter_names | ||||
|---|---|---|---|---|---|---|---|---|
| ca.exp(ax) + by^2 | 1 | 2 | 0.5 | 2 | x | y | a | b |
Excel formula:
=SENSITIVITY("ca.exp(a*x) + b*y^2", {1,2}, {0.5,2}, {"x","y"}, {"a","b"})Expected output:
| Result | |
|---|---|
| 1.649 | 4.000 |
Example 3: Power Law Expression
Inputs:
| model | variables | parameters | variable_names | parameter_names | ||||
|---|---|---|---|---|---|---|---|---|
| ax^3 + bx^2 + c*x | 2 | 1 | 2 | 3 | x | a | b | c |
Excel formula:
=SENSITIVITY("a*x^3 + b*x^2 + c*x", {2}, {1,2,3}, {"x"}, {"a","b","c"})Expected output:
| Result | ||
|---|---|---|
| 8.000 | 4.000 | 2.000 |
Example 4: Mixed Operations
Inputs:
| model | variables | parameters | variable_names | parameter_names | ||
|---|---|---|---|---|---|---|
| x^2 + a*ca.sin(x) + b | 1 | 2 | 5 | x | a | b |
Excel formula:
=SENSITIVITY("x^2 + a*ca.sin(x) + b", {1}, {2,5}, {"x"}, {"a","b"})Expected output:
| Result | |
|---|---|
| 0.841 | 1.000 |
Python Code
import re
import casadi as ca
def sensitivity(model, variables, parameters, variable_names=None, parameter_names=None):
"""Compute the sensitivity of a scalar model with respect to its parameters using CasADi.
Wraps CasADi automatic differentiation to return the row vector of partial derivatives
of a scalar expression f(x, a) with respect to parameters `a` evaluated at the provided
point.
Args:
model: String expression representing the model output. The expression may use
CasADi functions via the `ca` namespace (for example `ca.exp`, `ca.sin`).
variables: 2D list or scalar containing the evaluation point for each independent variable.
parameters: 2D list or scalar containing the parameter values at which the sensitivity is evaluated.
variable_names: Optional 2D list of strings specifying the variable names in order.
parameter_names: Optional 2D list of strings specifying the parameter names in order.
Returns:
A 2D list containing a single row of partial derivatives (floats) with respect to each parameter,
or an error message string if validation fails or CasADi encounters an error.
Notes:
This function exposes a minimal wrapper around CasADi. See https://web.casadi.org/ for
CasADi documentation. This example function is provided as-is without any representation of accuracy.
"""
# Helper to normalize values that may be passed as scalars by Excel for single-cell ranges.
def to2d(x):
return [[x]] if not isinstance(x, list) else x
if not isinstance(model, str) or model.strip() == "":
return "Invalid input: model must be a non-empty string."
# Normalize inputs that may be passed as scalars.
variables = to2d(variables)
parameters = to2d(parameters)
try:
variable_values = [float(v) for v in variables[0]]
except Exception:
return "Invalid input: variables must contain numeric values."
try:
parameter_values = [float(p) for p in parameters[0]]
except Exception:
return "Invalid input: parameters must contain numeric values."
if len(variable_values) == 0:
return "Invalid input: variables must include at least one value."
if len(parameter_values) == 0:
return "Invalid input: parameters must include at least one value."
# Validate and normalize names
if variable_names is not None:
variable_names = to2d(variable_names)
variable_names_list = variable_names[0]
if len(variable_names_list) != len(variable_values):
return "Invalid input: number of variable names must match number of variable values."
if not all(isinstance(n, str) and n.strip() for n in variable_names_list):
return "Invalid input: variable_names must contain non-empty strings."
else:
variable_names_list = [f"x{i+1}" for i in range(len(variable_values))]
if parameter_names is not None:
parameter_names = to2d(parameter_names)
parameter_names_list = parameter_names[0]
if len(parameter_names_list) != len(parameter_values):
return "Invalid input: number of parameter names must match number of parameter values."
if not all(isinstance(n, str) and n.strip() for n in parameter_names_list):
return "Invalid input: parameter_names must contain non-empty strings."
else:
parameter_names_list = [f"a{i+1}" for i in range(len(parameter_values))]
# Create CasADi symbols
variable_symbols = [ca.MX.sym(n) for n in variable_names_list]
parameter_symbols = [ca.MX.sym(n) for n in parameter_names_list]
# Build evaluation context for eval() so user can reference variable and parameter names
evaluation_context = {name: variable_symbols[idx] for idx, name in enumerate(variable_names_list)}
evaluation_context.update({name: parameter_symbols[idx] for idx, name in enumerate(parameter_names_list)})
evaluation_context["ca"] = ca
# Convert Excel exponentiation (^) to Python exponentiation (**)
model = re.sub(r'\^', '**', model)
try:
expression = eval(model, evaluation_context)
except Exception as exc:
return f"Invalid model expression: {exc}"
try:
jac = ca.jacobian(expression, ca.vertcat(*parameter_symbols))
sensitivity_fn = ca.Function("sensitivity_fn", variable_symbols + parameter_symbols, [jac])
casadi_result = sensitivity_fn(*(variable_values + parameter_values))
except Exception as exc:
return f"Error during CasADi calculation: {exc}"
# casadi_result is typically a DM; return as nested Python lists
try:
if isinstance(casadi_result, ca.DM):
return casadi_result.full().tolist()
# Some CasADi versions return a list/tuple with one element
if isinstance(casadi_result, (list, tuple)) and len(casadi_result) == 1 and isinstance(casadi_result[0], ca.DM):
return casadi_result[0].full().tolist()
except Exception:
return "Error during CasADi calculation: Unexpected result type."
return "Error during CasADi calculation: Unexpected result type."