Skip to Content

DUAL_ANNEALING

Overview

The DUAL_ANNEALING function performs global optimization by combining generalized simulated annealing with local search, wrapping scipy.optimize.dual_annealing. It explores the search space using temperature-driven jumps and periodically refines the incumbent solution with deterministic polishing, providing robust performance on multimodal landscapes. This example function is provided as-is without any representation of accuracy.

Usage

To apply the solver in Excel:

=DUAL_ANNEALING(func_expr, bounds, [maxiter], [initial_temp], [restart_temp_ratio], [visit], [accept], [seed], [no_local_search], [x_zero])
  • func_expr (string, required): Objective expression using x[i] to address variables.
  • bounds (2D list, required): Each row is [min, max] specifying bounds for a variable.
  • maxiter (int, optional, default=1000): Maximum number of global search iterations.
  • initial_temp (float, optional, default=5230.0): Starting temperature controlling exploration scale.
  • restart_temp_ratio (float, optional, default=2e-5): Restart threshold ratio in (0, 1].
  • visit (float, optional, default=2.62): Visiting distribution parameter (must be > 0).
  • accept (float, optional, default=-5.0): Acceptance bias parameter (negative values favor downhill moves).
  • seed (int, optional): Random seed for reproducible results.
  • no_local_search (bool, optional, default=FALSE): Set to TRUE to skip the polishing local optimizer.
  • x_zero (2D list, optional): Initial guess for the search; provide a single row with one value per variable.

The function returns a single-row 2D list with the optimal variables followed by the objective value, or an error message string if inputs are invalid or the solver 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)=x02+x12f(x_0, x_1) = x_0^2 + x_1^2"x[0]**2 + x[1]**2" or "x[0]^2 + x[1]^2"
  • 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"
  • 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)=ex02x12f(x_0, x_1) = e^{-x_0^2 - x_1^2}"exp(-x[0]**2 - x[1]**2)" or "e^(-x[0]^2 - x[1]^2)"

Examples

Example 1: Basic Quadratic with All Parameters

Inputs:

func_exprboundsmaxiterinitial_temprestart_temp_ratiovisitacceptseedno_local_searchx_zero
(x[0]-1)**2 + (x[1]+2)**2-55150060001.5E-052.5-4.5101FALSE0, 0
-55

Excel formula:

=DUAL_ANNEALING("(x[0]-1)**2 + (x[1]+2)**2", {-5,5;-5,5}, 1500, 6000, 0.000015, 2.5, -4.5, 101, FALSE, {0;0})

Expected output:

x₁x₂Objective
1.000-2.0000.000

This example demonstrates using non-default values for all optional parameters.

Inputs:

func_exprboundsseedno_local_searchmaxiter
(x[0])**2 + (x[1]-3)**2-44202TRUE200
06

Excel formula:

=DUAL_ANNEALING("(x[0])**2 + (x[1]-3)**2", {-4,4;0,6}, , , , , , 202, TRUE, , 200)

Expected output:

x₁x₂Objective
0.0373.0240.002

Example 3: Custom Temperature Parameters

Inputs:

func_exprboundsinitial_temprestart_temp_ratiovisitacceptseed
(x[0]-2)**2 + (x[1]-1)**2-6670001E-052.7-3.0404
-66

Excel formula:

=DUAL_ANNEALING("(x[0]-2)**2 + (x[1]-1)**2", {-6,6;-6,6}, , 7000, 0.00001, 2.7, -3, 404)

Expected output:

x₁x₂Objective
2.0001.0000.000

Example 4: Using an Initial Guess

Inputs:

func_exprboundsx_zeroseedmaxiter
(x[0]+1)**2 + (x[1]-2)**2 + (x[2]-0.5)**2-55-0.51.5909300
-550.0
-55

Excel formula:

=DUAL_ANNEALING("(x[0]+1)**2 + (x[1]-2)**2 + (x[2]-0.5)**2", {-5,5;-5,5;-5,5}, , , , , , 909, FALSE, {-0.5,1.5,0}, 300)

Expected output:

x₁x₂x₃Objective
-1.0002.0000.5000.000

Python Code

import math from typing import List, Optional import numpy as np from scipy.optimize import dual_annealing as scipy_dual_annealing def dual_annealing( func_expr: str, bounds: List[List[float]], maxiter: int = 1000, initial_temp: float = 5230.0, restart_temp_ratio: float = 2e-5, visit: float = 2.62, accept: float = -5.0, seed: Optional[int] = None, no_local_search: bool = False, x_zero: Optional[List[List[float]]] = None, ): """ Minimize a multivariate function using dual annealing. Args: func_expr: Objective expression in terms of `x` (use `x[i]` for components). bounds: 2D list of [min, max] pairs defining the search domain. maxiter: Maximum number of global search iterations. initial_temp: Initial temperature controlling the search scope. restart_temp_ratio: Temperature ratio triggering restarts. visit: Parameter governing visiting distribution (must be > 0). accept: Parameter controlling acceptance probability of new states. seed: Optional random seed for reproducibility. no_local_search: If True, skip the local minimization polish stage. x_zero: Optional initial point as 2D list or list matching the number of variables. Returns: list[list[float]] or str: [[x1, x2, ..., objective]] on success, otherwise an informative error message. 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." processed_bounds = [] 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}." processed_bounds.append((lower, upper)) dimension = len(processed_bounds) # Validate numeric parameters try: maxiter = int(maxiter) except (TypeError, ValueError): return "Invalid input: maxiter must be an integer." if maxiter <= 0: return "Invalid input: maxiter must be positive." try: initial_temp = float(initial_temp) restart_temp_ratio = float(restart_temp_ratio) visit = float(visit) accept = float(accept) except (TypeError, ValueError): return "Invalid input: initial_temp, restart_temp_ratio, visit, and accept must be numeric." if initial_temp <= 0: return "Invalid input: initial_temp must be positive." if not (0 < restart_temp_ratio <= 1): return "Invalid input: restart_temp_ratio must be in the interval (0, 1]." if visit <= 0: return "Invalid input: visit must be positive." rng_seed = None if seed is not None: try: rng_seed = int(seed) except (TypeError, ValueError): return "Invalid input: seed must be an integer." if not isinstance(no_local_search, bool): return "Invalid input: no_local_search must be a boolean." x0_vector = None if x_zero is not None: try: arr = np.array(x_zero, dtype=float).flatten() except Exception: return "Invalid input: x_zero must contain numeric values." if arr.size != dimension: return "Invalid input: x_zero length must match number of variables." x0_vector = arr 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_dual_annealing( objective, bounds=processed_bounds, maxiter=maxiter, initial_temp=initial_temp, restart_temp_ratio=restart_temp_ratio, visit=visit, accept=accept, seed=rng_seed, no_local_search=no_local_search, x0=x0_vector, ) except ValueError as exc: return f"Error during dual annealing: {exc}" except Exception as exc: return f"Error during dual annealing: {exc}" if not result.success: return f"Dual annealing failed: {result.message}" if result.x is None or result.fun is None: return "Dual annealing failed: missing solution data." try: solution_vector = [float(val) for val in result.x] except (TypeError, ValueError): return "Error converting solution vector to floats." objective_value = float(result.fun) return [solution_vector + [objective_value]]

Example Workbook

Link to Workbook 

Last updated on