MINIMIZE_SCALAR

Overview

The MINIMIZE_SCALAR function finds the local minimum of a single-variable (univariate) function using SciPy’s optimize.minimize_scalar algorithm. This is useful for optimization problems where you need to find the input value x that produces the smallest output from a mathematical expression.

The function supports three optimization methods:

Brent’s method (default for unbounded problems) combines the reliability of the golden section search with the speed of inverse parabolic interpolation. When the function is well-behaved, it uses parabolic interpolation to accelerate convergence; otherwise, it falls back to the more robust golden section approach. This method is based on Richard Brent’s classic algorithm described in Algorithms for Minimization Without Derivatives (1973).

Golden section search uses a divide-and-conquer strategy based on the golden ratio \phi = \frac{1 + \sqrt{5}}{2} \approx 1.618. It successively narrows the search interval by maintaining points that divide each interval in the golden ratio, guaranteeing convergence at a predictable rate. While reliable, Brent’s method is generally preferred as it typically converges faster.

Bounded method performs constrained minimization within a specified interval [a, b]. It uses Brent’s algorithm internally but restricts the search to ensure the solution satisfies a \leq x_{opt} \leq b. This is essential when the objective function is only defined or meaningful within certain bounds.

The function accepts a mathematical expression as a string (e.g., "x^2 - 4*x + 4" or "sin(x) + x/10"), supporting standard mathematical functions from NumPy and Python’s math module. It returns both the optimal input value x^* and the corresponding minimum function value f(x^*).

For multivariate optimization problems, see the related scipy.optimize.minimize function. For global optimization (finding the absolute minimum rather than a local one), consider SciPy’s global optimization methods.

This example function is provided as-is without any representation of accuracy.

Excel Usage

=MINIMIZE_SCALAR(func_expr, bounds, minimize_scalar_m)
  • func_expr (str, required): Mathematical expression of the objective function in variable x.
  • bounds (list[list], optional, default: null): Search interval as 2D list [[lower, upper]] for bounded method.
  • minimize_scalar_m (str, optional, default: “brent”): Optimization algorithm to use.

Returns (list[list]): 2D list [[x, f(x)]], or error message string.

Example 1: Quadratic with bounds using bounded method

Inputs:

func_expr bounds minimize_scalar_m
x^2 + 3*x + 2 -3 1 bounded

Excel formula:

=MINIMIZE_SCALAR("x^2 + 3*x + 2", {-3,1}, "bounded")

Expected output:

Result
-1.5 -0.25
Example 2: Shifted quadratic with bounded search

Inputs:

func_expr bounds minimize_scalar_m
(x-5)^2 + 10 0 10 bounded

Excel formula:

=MINIMIZE_SCALAR("(x-5)^2 + 10", {0,10}, "bounded")

Expected output:

Result
5 10
Example 3: Absolute value function without bounds

Inputs:

func_expr
abs(x-2) + 1

Excel formula:

=MINIMIZE_SCALAR("abs(x-2) + 1")

Expected output:

Result
2 1
Example 4: Quartic polynomial with bounded method

Inputs:

func_expr bounds minimize_scalar_m
x^4 - 8*x^2 + 16 -3 3 bounded

Excel formula:

=MINIMIZE_SCALAR("x^4 - 8*x^2 + 16", {-3,3}, "bounded")

Expected output:

Result
-2 2.20588e-11

Python Code

Show Code
import math
import re

import numpy as np
from scipy.optimize import minimize_scalar as scipy_minimize_scalar

def minimize_scalar(func_expr, bounds=None, minimize_scalar_m='brent'):
    """
    Minimize a single-variable function using SciPy's minimize_scalar.

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize_scalar.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        func_expr (str): Mathematical expression of the objective function in variable x.
        bounds (list[list], optional): Search interval as 2D list [[lower, upper]] for bounded method. Default is None.
        minimize_scalar_m (str, optional): Optimization algorithm to use. Valid options: Brent, Bounded, Golden Section. Default is 'brent'.

    Returns:
        list[list]: 2D list [[x, f(x)]], or error message string.
    """
    try:
        if not isinstance(func_expr, str) or func_expr.strip() == "":
            return "Error: Invalid input: func_expr must be a non-empty string."
        if not re.search(r'\bx\b', func_expr):
            return "Error: Invalid input: func_expr must reference variable x."

        func_expr = re.sub(r'\^', '**', func_expr)

        allowed_methods = {"brent", "bounded", "golden"}
        solver_method = minimize_scalar_m.lower() if isinstance(minimize_scalar_m, str) else "brent"
        if solver_method not in allowed_methods:
            return "Error: Invalid input: minimize_scalar_m must be one of 'brent', 'bounded', or 'golden'."

        interval = 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 "Error: 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 "Error: Invalid input: bounds values must be numeric."
            if not math.isfinite(lower_val) or not math.isfinite(upper_val):
                return "Error: Invalid input: bounds values must be finite."
            if lower_val >= upper_val:
                return "Error: Invalid input: lower bound must be less than upper bound."
            interval = (lower_val, upper_val)

        if solver_method == "bounded" and interval is None:
            return "Error: Invalid input: method 'bounded' requires bounds to be provided."
        if solver_method in {"brent", "golden"} and interval is not None:
            return f"Error: Invalid input: method '{solver_method}' cannot be used with bounds. Use 'bounded' instead."

        safe_globals = {
            "math": math,
            "np": np,
            "numpy": np,
            "__builtins__": {},
        }

        safe_globals.update({
            name: getattr(math, name)
            for name in dir(math)
            if not name.startswith("_")
        })

        safe_globals.update({
            "sin": np.sin,
            "cos": np.cos,
            "tan": np.tan,
            "asin": np.arcsin,
            "arcsin": np.arcsin,
            "acos": np.arccos,
            "arccos": np.arccos,
            "atan": np.arctan,
            "arctan": np.arctan,
            "sinh": np.sinh,
            "cosh": np.cosh,
            "tanh": np.tanh,
            "exp": np.exp,
            "log": np.log,
            "ln": np.log,
            "log10": np.log10,
            "sqrt": np.sqrt,
            "abs": np.abs,
            "pow": np.power,
            "pi": math.pi,
            "e": math.e,
            "inf": math.inf,
            "nan": math.nan,
        })

        def _objective(x_value):
            try:
                result = eval(func_expr, safe_globals, {"x": x_value})
            except Exception:
                return float("inf")
            try:
                numeric_value = float(result)
            except (TypeError, ValueError):
                return float("inf")
            if not math.isfinite(numeric_value):
                return float("inf")
            return numeric_value

        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."

        minimize_kwargs = {"method": solver_method}
        if interval is not None:
            minimize_kwargs["bounds"] = interval

        try:
            result = scipy_minimize_scalar(_objective, **minimize_kwargs)
        except ValueError as exc:
            return f"Error: minimize_scalar error: {exc}"
        except Exception as exc:
            return f"Error: 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"Error: minimize_scalar failed: {message}"

        if not math.isfinite(result.x) or not math.isfinite(result.fun):
            return "Error: minimize_scalar failed: solver returned non-finite results."

        return [[float(result.x), float(result.fun)]]
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

Mathematical expression of the objective function in variable x.
Search interval as 2D list [[lower, upper]] for bounded method.
Optimization algorithm to use.