MINIMIZE_SCALAR
Overview
The MINIMIZE_SCALAR function locates a local minimum of a single-variable objective by wrapping scipy.optimize.minimize_scalar. Depending on the chosen algorithm—Brent, golden-section, or bounded Brent—it searches the real line or a specified interval to find the point that minimizes . This example function is provided as-is without any representation of accuracy.
Usage
To evaluate the function in Excel:
=MINIMIZE_SCALAR(func_expr, [bounds], [minimize_scalar_method])func_expr(string, required): Objective expression in the scalar variablex(e.g.,"x**2 + 3*x + 2").bounds(2D list of float, optional): Single row[[lower, upper]]defining the search interval for the bounded method.minimize_scalar_method(string (enum), optional, default="brent"): Solver algorithm. Valid options:Brent,Bounded,Golden Section.
The function returns a single-row 2D list [[x*, f(x*)]] where x* minimizes the objective, or a string error message if validation fails or the solver cannot converge.
Function Expressions
The func_expr parameter accepts mathematical expressions using any of the following functions and constants. All functions are case-sensitive.
| Function/Constant | Description | Example |
|---|---|---|
sin(x) | Sine function (radians) | sin(x) |
cos(x) | Cosine function (radians) | cos(x) |
tan(x) | Tangent function (radians) | tan(x) |
asin(x) or arcsin(x) | Arc sine function (radians) | asin(x) or arcsin(x) |
acos(x) or arccos(x) | Arc cosine function (radians) | acos(x) or arccos(x) |
atan(x) or arctan(x) | Arc tangent function (radians) | atan(x) or arctan(x) |
sinh(x) | Hyperbolic sine | sinh(x) |
cosh(x) | Hyperbolic cosine | cosh(x) |
tanh(x) | Hyperbolic tangent | tanh(x) |
exp(x) | Exponential function () | exp(x) |
log(x) or ln(x) | Natural logarithm (base ) | log(x) or ln(x) |
log10(x) | Base-10 logarithm | log10(x) |
sqrt(x) | Square root | sqrt(x) |
abs(x) | Absolute value | abs(x) |
pow(x, y) | Power function (x raised to power y) | pow(x, 2) |
pi | Mathematical constant π (≈3.14159) | x * pi |
e | Mathematical constant e (≈2.71828) | e**x |
Important Notes:
- All trigonometric functions use radians, not degrees
- Use
**(double asterisk) or^(caret) for exponentiation. Both work equivalently. - Examples:
"x**2 + sin(x)"or"x^2 + sin(x)","exp(-x)"or"e^(-x)"
Expression Examples
Common mathematical expressions and their func_expr notation:
- →
"x**2 + 3*x + 2" - →
"exp(-x)"or"e^(-x)" - →
"sin(x) + cos(2*x)" - →
"x**4 - 2*x**2 + 1"
Examples
Example 1: Quadratic with Bounds and Bounded Method
Inputs:
| func_expr | bounds | method | |
|---|---|---|---|
| x**2 + 3*x + 2 | -3 | 1 | bounded |
Excel formula:
=MINIMIZE_SCALAR("x**2 + 3*x + 2", {-3,1}, "bounded")Expected output:
| x | f(x) |
|---|---|
| -1.500 | -0.250 |
This example demonstrates using non-default values for all optional parameters.
Example 2: Quadratic with Bounded Search
Inputs:
| func_expr | bounds | |
|---|---|---|
| (x-5)**2 + 10 | 0 | 10 |
Excel formula:
=MINIMIZE_SCALAR("(x-5)**2 + 10", {0,10}, "bounded")Expected output:
| x | f(x) |
|---|---|
| 5.000 | 10.000 |
Example 3: Absolute Value without Bounds
Inputs:
| func_expr |
|---|
| abs(x-2) + 1 |
Excel formula:
=MINIMIZE_SCALAR("abs(x-2) + 1")Expected output:
| x | f(x) |
|---|---|
| 2.000 | 1.000 |
Example 4: Quartic with Bounded Method
Inputs:
| func_expr | bounds | method | |
|---|---|---|---|
| x4 - 8*x2 + 16 | -3 | 3 | bounded |
Excel formula:
=MINIMIZE_SCALAR("x**4 - 8*x**2 + 16", {-3,3}, "bounded")Expected output:
| x | f(x) |
|---|---|
| -2.000 | 0.000 |
Python Code
import math
from typing import List, Optional, Tuple, Union
from scipy.optimize import minimize_scalar as scipy_minimize_scalar
Number = Union[int, float]
def minimize_scalar(
func_expr: str,
bounds: Optional[List[List[Optional[Number]]]] = None,
minimize_scalar_method: Optional[str] = None,
) -> Union[List[List[float]], str]:
"""Minimize a single-variable function using SciPy's ``minimize_scalar``.
Args:
func_expr: Expression representing the objective function of one variable ``x``.
bounds: Optional 2D list ``[[lower, upper]]`` specifying a bounded search interval.
minimize_scalar_method: Optional solver name. Valid choices are ``brent``, ``bounded``, and ``golden``.
Returns:
2D list ``[[x, f(x)]]`` containing the minimizing point and objective value, or an
error message string if validation fails or the solver cannot complete.
This example function is provided as-is without any representation of accuracy.
"""
if not isinstance(func_expr, str) or func_expr.strip() == "":
return "Invalid input: func_expr must be a non-empty string."
if "x" not in func_expr:
return "Invalid input: function expression must contain the variable 'x'."
allowed_methods = {"brent", "bounded", "golden"}
solver_method = minimize_scalar_method.lower() if isinstance(minimize_scalar_method, str) else "brent"
if solver_method not in allowed_methods:
return "Invalid input: minimize_scalar_method must be one of 'brent', 'bounded', or 'golden'."
interval: Optional[Tuple[float, float]] = None
if bounds is not None:
if not (
isinstance(bounds, list)
and len(bounds) == 1
and isinstance(bounds[0], list)
and len(bounds[0]) == 2
):
return "Invalid input: bounds must be a 2D list [[min, max]]."
lower_raw, upper_raw = bounds[0]
try:
lower_val = float(lower_raw)
upper_val = float(upper_raw)
except (TypeError, ValueError):
return "Invalid input: bounds values must be numeric."
if not math.isfinite(lower_val) or not math.isfinite(upper_val):
return "Invalid input: bounds values must be finite."
if lower_val >= upper_val:
return "Invalid input: lower bound must be less than upper bound."
interval = (lower_val, upper_val)
if solver_method == "bounded" and interval is None:
return "Invalid input: method 'bounded' requires bounds to be provided."
if solver_method in {"brent", "golden"} and interval is not None:
return f"Invalid input: method '{solver_method}' cannot be used with bounds. Use 'bounded' instead."
safe_globals = {
name: getattr(math, name)
for name in dir(math)
if not name.startswith("_")
}
def _objective(x_value: float) -> float:
try:
result = eval(func_expr, safe_globals, {"x": x_value})
except Exception:
return float("nan")
try:
numeric_value = float(result)
except (TypeError, ValueError):
return float("nan")
if not math.isfinite(numeric_value):
return float("nan")
return numeric_value
minimize_kwargs = {"method": solver_method}
if interval is not None:
minimize_kwargs["bounds"] = interval
# Pre-evaluate to catch parse/eval errors early
try:
initial_eval = eval(func_expr, safe_globals, {"x": (interval[0] + interval[1]) / 2 if interval is not None else 0.0})
except Exception as exc:
return f"Error: Invalid model expression: {exc}"
try:
_ = float(initial_eval)
except (TypeError, ValueError):
return "Error: Invalid model expression: objective did not return a numeric value."
try:
result = scipy_minimize_scalar(_objective, **minimize_kwargs)
except ValueError as exc:
return f"minimize_scalar error: {exc}"
except Exception as exc:
return f"minimize_scalar error: {exc}"
if not result.success or result.x is None or result.fun is None:
message = result.message if hasattr(result, "message") else "Optimization failed."
return f"minimize_scalar failed: {message}"
if not math.isfinite(result.x) or not math.isfinite(result.fun):
return "minimize_scalar failed: solver returned non-finite results."
return [[float(result.x), float(result.fun)]]