Skip to Content

BRUTE

Overview

The BRUTE function conducts a grid search over a Cartesian grid to approximate the global minimum of a multivariate function, wrapping scipy.optimize.brute. It evaluates the objective at evenly spaced points across the specified bounds and optionally refines the best grid point with a local optimizer. This example function is provided as-is without any representation of accuracy.

Usage

To perform a brute-force search in Excel:

=BRUTE(func_expr, bounds, [ns], [finish])
  • func_expr (string, required): Objective expression using x[i] to reference each variable.
  • bounds (2D list, required): Each row is [min, max] defining the search interval for a variable.
  • ns (int, optional, default=20): Number of equally spaced grid points per dimension (must be at least 2).
  • finish (string (enum) or blank, optional, default="fmin"): Local refinement applied to the best grid point. Valid options: fmin, fmin_powell, or leave blank to skip refinement.

The function returns a single-row 2D list containing the optimal variable values followed by the objective value, or an error message string if validation fails.

Function Expressions

The func_expr parameter accepts mathematical expressions using any of the following functions and constants. All functions are case-sensitive.

Function/ConstantDescriptionExample
sin(x)Sine function (radians)sin(x[0])
cos(x)Cosine function (radians)cos(x[1])
tan(x)Tangent function (radians)tan(x[0])
asin(x) or arcsin(x)Arc sine function (radians)asin(x[0])
acos(x) or arccos(x)Arc cosine function (radians)acos(x[1])
atan(x) or arctan(x)Arc tangent function (radians)atan(x[0])
sinh(x)Hyperbolic sinesinh(x[0])
cosh(x)Hyperbolic cosinecosh(x[1])
tanh(x)Hyperbolic tangenttanh(x[0])
exp(x)Exponential function (exe^x)exp(x[0])
log(x) or ln(x)Natural logarithm (base ee)log(x[0])
log10(x)Base-10 logarithmlog10(x[0])
sqrt(x)Square rootsqrt(x[0])
abs(x)Absolute valueabs(x[0] - x[1])
pow(x, y)Power function (x raised to power y)pow(x[0], 2)
piMathematical constant π (≈3.14159)x[0] * pi
eMathematical constant e (≈2.71828)e**x[0]

Important Notes:

  • All trigonometric functions use radians, not degrees
  • Use ** (double asterisk) or ^ (caret) for exponentiation. Both work equivalently.
  • For multi-variable functions, use indexed variable notation: x[0], x[1], etc.

Expression Examples

Common mathematical expressions and their func_expr notation:

  • f(x0,x1)=(x01)2+(x1+2)2f(x_0, x_1) = (x_0-1)^2 + (x_1+2)^2"(x[0]-1)**2 + (x[1]+2)**2" or "(x[0]-1)^2 + (x[1]+2)^2"
  • f(x0,x1)=x02+x12f(x_0, x_1) = x_0^2 + x_1^2"x[0]**2 + x[1]**2"
  • f(x0,x1)=sin(x0)+cos(x1)f(x_0, x_1) = \sin(x_0) + \cos(x_1)"sin(x[0]) + cos(x[1])"
  • f(x0,x1,x2)=x042x02+2x12+x22f(x_0, x_1, x_2) = x_0^4 - 2x_0^2 + 2x_1^2 + x_2^2"x[0]**4 - 2*x[0]**2 + 2*x[1]**2 + x[2]**2"

Examples

Example 1: Quadratic Bowl with Powell Refinement

Inputs:

func_exprboundsnsfinish
(x[0]-1)**2 + (x[1]+2)**2-3325fmin_powell
-33

Excel formula:

=BRUTE("(x[0]-1)**2 + (x[1]+2)**2", {-3,3;-3,3}, 25, "fmin_powell")

Expected output:

x₁x₂Objective
1.000-2.0000.000

This example uses a non-default finish method for local refinement.

Example 2: Skipping Local Refinement

Inputs:

func_exprboundsnsfinish
(x[0]-2)**2 + (x[1]-1)**2-4415(blank)
-44

Excel formula:

=BRUTE("(x[0]-2)**2 + (x[1]-1)**2", {-4,4;-4,4}, 15, )

Expected output:

x₁x₂Objective
2.2861.1430.102

Example 3: Three Variables

Inputs:

func_exprboundsns
(x[0]+1)**2 + (x[1]-0.5)**2 + (x[2]-2)**2-2212
-22
04

Excel formula:

=BRUTE("(x[0]+1)**2 + (x[1]-0.5)**2 + (x[2]-2)**2", {-2,2;-2,2;0,4}, 12)

Expected output:

x₁x₂x₃Objective
-1.0000.5002.0000.000

Example 4: Powell Refinement

Inputs:

func_exprboundsnsfinish
x[0]**2 + x[1]**2-5510fmin_powell
-55

Excel formula:

=BRUTE("x[0]**2 + x[1]**2", {-5,5;-5,5}, 10, "fmin_powell")

Expected output:

x₁x₂Objective
0.0000.0000.000

Python Code

import math from typing import List, Optional import numpy as np from scipy.optimize import brute as scipy_brute from scipy.optimize import fmin as scipy_fmin from scipy.optimize import fmin_powell as scipy_fmin_powell def brute( func_expr: str, bounds: List[List[float]], ns: int = 20, finish: Optional[str] = 'fmin', ): """ Perform a brute-force grid search to approximate the global minimum of a function. This function wraps scipy.optimize.brute to perform global optimization over a specified domain. For more information, see: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.brute.html Args: func_expr: Objective expression using `x[i]` for variable access. bounds: 2D list of [min, max] pairs describing each variable's domain. ns: Number of grid points per dimension (must be >= 2). finish: Optional local optimizer applied to the best grid point. Choices: 'fmin', 'fmin_powell', None. Returns: list[list[float]] or str: [[x1, x2, ..., objective]] on success, otherwise an error message string. This example function is provided as-is without any representation of accuracy. """ # Validate func_expr if not isinstance(func_expr, str): return "Invalid input: func_expr must be a string." if 'x' not in func_expr: return "Invalid input: func_expr must reference variable x (e.g., x[0])." # Validate bounds if not isinstance(bounds, list) or len(bounds) == 0: return "Invalid input: bounds must be a 2D list of [min, max] pairs." slices = [] for idx, bound in enumerate(bounds): if not isinstance(bound, list) or len(bound) != 2: return "Invalid input: each bound must be a [min, max] pair." try: lower = float(bound[0]) upper = float(bound[1]) except (TypeError, ValueError): return "Invalid input: bounds must contain numeric values." if lower > upper: return f"Invalid input: lower bound must not exceed upper bound for variable index {idx}." slices.append(slice(lower, upper, complex(0, ns))) dimension = len(slices) # Validate ns try: ns = int(ns) except (TypeError, ValueError): return "Invalid input: ns must be an integer." if ns < 2: return "Invalid input: ns must be at least 2." # Validate finish option finish_map = { 'fmin': scipy_fmin, 'fmin_powell': scipy_fmin_powell, None: None, 'none': None, } if finish not in finish_map: return "Invalid input: finish must be one of 'fmin', 'fmin_powell', or None." finish_callable = finish_map[finish] # Objective evaluation def objective(x_vector): try: local_x = [float(val) for val in np.atleast_1d(x_vector)] value = eval(func_expr, {"x": local_x, "math": math, "np": np}) except Exception as exc: raise ValueError(f"Error evaluating func_expr: {exc}") try: result_value = float(value) except (TypeError, ValueError): raise ValueError("Objective expression must return a scalar numeric value.") if math.isnan(result_value) or math.isinf(result_value): raise ValueError("Objective evaluation produced NaN or infinity.") return result_value try: result = scipy_brute( objective, ranges=slices, Ns=ns, full_output=True, finish=finish_callable, disp=False, ) except ValueError as exc: return f"Error during brute optimization: {exc}" except Exception as exc: return f"Error during brute optimization: {exc}" if not isinstance(result, tuple) or len(result) < 2: return "Brute optimization failed: unexpected result structure." solution_vector, objective_value = result[0], result[1] try: solution_list = [float(val) for val in np.atleast_1d(solution_vector)] except (TypeError, ValueError): return "Error converting solution vector to floats." objective_value = float(objective_value) return [solution_list + [objective_value]]

Example Workbook

Link to Workbook 

Last updated on