Spiral Optimization

Spiral Optimization moves each particle along a spiral trajectory centered on the current global best position. At each iteration, the optimizer maps the particle and center positions into normalized coordinates, rotates the particle around the center, then maps the result back to the original search space. A decay factor reduces the normalized spiral radius over time. The combination of rotation and contraction produces a deterministic path that sweeps through the neighborhood of the best known solution. The decay rate controls how quickly the spiral tightens: values close to 1.0 produce wide, slow spirals while lower values contract rapidly.

Spiral Optimization on Sphere function

Convex function: Particles spiral inward toward the optimum.

Spiral Optimization on Ackley function

Multi-modal function: Spiral trajectories explore the region around the best known position.

Compared to PSO and the evolutionary algorithms in this library, Spiral Optimization has no stochastic component in its position updates. The particle trajectories are fully determined by the rotation matrix and decay factor, which makes the search behavior predictable and reproducible. This deterministic structure is effective when the global optimum lies within a broad basin of attraction, because the spiral systematically covers the surrounding region. On multi-modal landscapes with many isolated basins, PSO or Differential Evolution will typically perform better due to their stochastic exploration. Spiral Optimization has three movement parameters: spiral_radius controls the initial normalized search radius, decay_rate controls how quickly that radius contracts, and rotation_degrees controls the angular stride of the spiral path.

Algorithm

Each particle follows a spiral path toward the global best:

  1. Normalize current position and global best into [0, 1] coordinates

  2. Compute the normalized offset from the global best

  3. Rotate the offset by the spiral rotation matrix

  4. Scale the rotated offset by spiral_radius * decay_rate^t

  5. Denormalize the candidate back into the search space

  6. Update if new position is better

offset_norm = current_norm - center_norm
rotated_offset = rotate(offset_norm, rotation_degrees)
new_norm = center_norm + radius_t * rotated_offset
new_pos = denormalize(new_norm)

Note

The spiral trajectory is a structured way to explore the neighborhood of the global best. Unlike PSO where particles can overshoot and oscillate, spiral particles follow a smooth, contracting path that naturally transitions from exploration (outer rings) to exploitation (inner rings approaching the center).

The spiral motion ensures particles explore the region around the best solution while gradually converging.

Parameters

Parameter

Type

Default

Description

population

int

10

Number of particles

decay_rate

float

0.99

How quickly spirals contract (closer to 1 = slower)

spiral_radius

float

1.0

Initial radius multiplier in normalized search-space coordinates

rotation_degrees

float

90.0

Angle applied to the normalized offset at each spiral step

Rotation Angle

The default rotation_degrees=90.0 preserves the historical behavior in two dimensions. With slow or no contraction, this produces a square-like path around the center because four 90 degree rotations return to the original direction. Lower values such as 45 or 30 degrees produce smoother spiral paths because the particle takes more angular steps before completing a full turn.

In more than two dimensions there is no single natural “90 degree turn” around a point. Spiral Optimization therefore derives a deterministic rotation plane from the current offset vector: it keeps the offset as one axis of the plane and constructs a perpendicular direction from the coordinate axis least aligned with that offset. The particle is then rotated inside that plane. This keeps the rotation reproducible and norm-preserving without introducing random orientation choices.

Example

import numpy as np
from gradient_free_optimizers import SpiralOptimization

def objective(para):
    return -(para["x"]**2 + para["y"]**2)

search_space = {
    "x": np.linspace(-10, 10, 100),
    "y": np.linspace(-10, 10, 100),
}

opt = SpiralOptimization(
    search_space,
    population=15,
    decay_rate=0.98,
    spiral_radius=1.0,
    rotation_degrees=45.0,
)

opt.search(objective, n_iter=200)
print(f"Best: {opt.best_para}, Score: {opt.best_score}")

When to Use

Good for:

  • Continuous optimization

  • When you want balanced exploration around the best solution

  • Problems where the optimum has a basin of attraction

Compared to PSO:

Spiral Optimization provides more structured exploration around the global best, while PSO balances personal and global best attractions.

3D Example with Larger Population

import numpy as np
from gradient_free_optimizers import SpiralOptimization

def schwefel_3d(para):
    vals = [para["x"], para["y"], para["z"]]
    return sum(
        v * np.sin(np.sqrt(abs(v))) for v in vals
    )

search_space = {
    "x": np.linspace(-500, 500, 300),
    "y": np.linspace(-500, 500, 300),
    "z": np.linspace(-500, 500, 300),
}

opt = SpiralOptimization(
    search_space,
    population=25,
    decay_rate=0.995,
    spiral_radius=1.0,
    rotation_degrees=60.0,
)

opt.search(schwefel_3d, n_iter=500)
print(f"Best: {opt.best_para}")
print(f"Score: {opt.best_score}")

Trade-offs

  • Exploration vs. exploitation: Controlled by spiral_radius and decay_rate. Larger initial radii explore more broadly; values close to 1.0 for decay_rate give slow contraction, while lower values contract quickly. rotation_degrees controls whether the path is coarse and polygonal or smoother.

  • Computational overhead: Low. Each particle update is a simple matrix multiplication.

  • Parameter sensitivity: spiral_radius controls the initial movement scale in normalized coordinates. decay_rate controls how quickly that movement shrinks. rotation_degrees controls the angular resolution of the spiral path. Population size affects coverage of the spiral region.