Optional include center search (LS/SHC switch)
This also moves the search function into a separate file.
This commit is contained in:
parent
6cb016d5e9
commit
9258805802
2 changed files with 68 additions and 48 deletions
|
@ -1,51 +1,5 @@
|
||||||
from collections.abc import Iterator
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
from src.function import Function
|
|
||||||
from src.functions import available_functions
|
from src.functions import available_functions
|
||||||
from src.types import INPUT_VECTOR
|
from src.search import min_search
|
||||||
from src.utils import generate_bounded_points
|
|
||||||
|
|
||||||
|
|
||||||
def search(
|
|
||||||
function: Function,
|
|
||||||
x0: INPUT_VECTOR,
|
|
||||||
iterations: int,
|
|
||||||
neighbors_count: int,
|
|
||||||
std_dev: float,
|
|
||||||
rng: np.random.Generator | None = None,
|
|
||||||
) -> Iterator[INPUT_VECTOR]:
|
|
||||||
"""Search for the minimum value of the function using the local search algorithm.
|
|
||||||
|
|
||||||
On each iteration, N neighboring points will be generated around the starting point. These points
|
|
||||||
will then be evaluated on the function, finding the smallest one. This smallest point will become
|
|
||||||
the new starting point, repeating until we run out of iterations.
|
|
||||||
|
|
||||||
Params:
|
|
||||||
x0: Starting point (N-dimensional).
|
|
||||||
iterations: Maximum number of iterations.
|
|
||||||
include_origin: When searching for the next minimum, should the origin point be checked too?
|
|
||||||
neighbors_count: The amount of neighbor points.
|
|
||||||
std_dev: Standard deviation for the normal distribution for neighbor generating.
|
|
||||||
rng: Random generator instance (None for a new rng).
|
|
||||||
|
|
||||||
Yields:
|
|
||||||
Minimum input vector (x) found so far, yielded from each iteration.
|
|
||||||
"""
|
|
||||||
if rng is None:
|
|
||||||
rng = np.random.default_rng()
|
|
||||||
x_center = x0
|
|
||||||
|
|
||||||
for _ in range(iterations):
|
|
||||||
y_min = function(x_center)
|
|
||||||
for point in generate_bounded_points(x_center, neighbors_count, std_dev, function.definition_interval, rng):
|
|
||||||
y_point = function(point)
|
|
||||||
if y_point < y_min:
|
|
||||||
y_min = y_point
|
|
||||||
x_center = point
|
|
||||||
|
|
||||||
yield x_center
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
@ -56,8 +10,15 @@ def main() -> None:
|
||||||
stddev = 1
|
stddev = 1
|
||||||
|
|
||||||
for func_name, function in available_functions.items():
|
for func_name, function in available_functions.items():
|
||||||
|
print("-" * 80)
|
||||||
print(func_name)
|
print(func_name)
|
||||||
for x in search(function, function.definition_interval.random_point(dims), iters, neighbors, stddev):
|
for x in min_search(
|
||||||
|
function,
|
||||||
|
function.definition_interval.random_point(dims),
|
||||||
|
iterations=iters,
|
||||||
|
neighbors_count=neighbors,
|
||||||
|
std_dev=stddev,
|
||||||
|
):
|
||||||
y = function(x)
|
y = function(x)
|
||||||
print(f"{x} -> {y}")
|
print(f"{x} -> {y}")
|
||||||
|
|
||||||
|
|
59
src/search.py
Normal file
59
src/search.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
from collections.abc import Iterator
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from src.function import Function
|
||||||
|
from src.types import INPUT_VECTOR
|
||||||
|
from src.utils import generate_bounded_points
|
||||||
|
|
||||||
|
|
||||||
|
def min_search(
|
||||||
|
function: Function,
|
||||||
|
x0: INPUT_VECTOR,
|
||||||
|
*,
|
||||||
|
iterations: int,
|
||||||
|
neighbors_count: int,
|
||||||
|
std_dev: float,
|
||||||
|
include_center: bool = True,
|
||||||
|
rng: np.random.Generator | None = None,
|
||||||
|
) -> Iterator[INPUT_VECTOR]:
|
||||||
|
"""Search for the minimum value of the function using the Local Search / Stochastic Hill Climber algorithm.
|
||||||
|
|
||||||
|
On each iteration, N neighboring points will be generated around the starting point. These points
|
||||||
|
will then be evaluated on the function, finding the smallest one. This smallest point will become
|
||||||
|
the new starting point, repeating until we run out of iterations.
|
||||||
|
|
||||||
|
Params:
|
||||||
|
x0: Starting point (N-dimensional).
|
||||||
|
iterations: Maximum number of iterations.
|
||||||
|
include_origin: When searching for the next minimum, should the origin point be checked too?
|
||||||
|
neighbors_count: The amount of neighbor points.
|
||||||
|
std_dev: Standard deviation for the normal distribution for neighbor generating.
|
||||||
|
include_center:
|
||||||
|
- When False, this algorithm works as Stochastic Hill Climber, always picking the minimum
|
||||||
|
from the newly generated points only, ignoring the current point.
|
||||||
|
- When True, this algorithm works as Local Search, picking the minimum from all of the
|
||||||
|
newly generated points and also from the center point.
|
||||||
|
rng: Random generator instance (None for a new rng).
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
Minimum input vector (x) found so far, yielded from each iteration.
|
||||||
|
"""
|
||||||
|
if rng is None:
|
||||||
|
rng = np.random.default_rng()
|
||||||
|
x_center = x0
|
||||||
|
y_min = function(x_center) if include_center else float("inf")
|
||||||
|
|
||||||
|
for _ in range(iterations):
|
||||||
|
for point in generate_bounded_points(x_center, neighbors_count, std_dev, function.definition_interval, rng):
|
||||||
|
y_point = function(point)
|
||||||
|
if y_point < y_min:
|
||||||
|
y_min = y_point
|
||||||
|
x_center = point
|
||||||
|
|
||||||
|
# If we're using Stochastic Hill Climber, reset the minimum value, to only
|
||||||
|
# pick it from the newly generated points, not the current center
|
||||||
|
if not include_center:
|
||||||
|
y_min = float("inf")
|
||||||
|
|
||||||
|
yield x_center
|
Loading…
Add table
Reference in a new issue