Learn R Programming

bbotk (version 1.7.0)

local_search: Local Search

Description

Runs a local search on the objective function. Somewhat similar to what is used in SMAC for acquisition function optimization of mixed type search spaces with hierarchical dependencies.

The function always minimizes. If the objective is to be maximized, we handle it by multiplying with "obj_mult" (which will be -1).

'Currently, automatically applying the search space transformations is not supported, if you need this, do this yourself in the objective function or use OptimInstanceBatchLocalSearch.

Usage

local_search(
  objective,
  search_space,
  control = local_search_control(),
  init_points = NULL
)

Value

(named list). List with elements:

  • 'x': (list)
    The best point found, length and element names and their order correspond exactly to the search space.

  • 'y': (numeric(1))
    The objective value of the best point.

Arguments

objective

(function(xdt))
Objective to optimize. The first arg (name 'xdt' is not enforced) will be a data.table with (scalar) columns corresponding exactly the search space, in the same order. The function should must return numeric vector of exactly the same length as the number of rows in the dt, containing the objective values.

search_space

(paradox::ParamSet)
Search space for decision variables. Must be non-empty, can only contain p_int, p_dbl, p_fct, p_lgl, all must be bounded.

control

(local_search_control)
Control parameters for the local search, generated by local_search_control().

init_points

(data.table)
Initial points to start the local search from, same format as described for the argument of 'objective'. Must have as many rows as 'control$n_searches'. If NULL, we generate "n_searches" random points.

Details

We run "n_searches" in parallel. Each search runs "n_steps" iterations. For each search in every iteration we generate "n_neighs" neighbors. A neighbor is the current point, but with exactly one parameter mutated.

Mutation works like this: For num params: we scale to 0,1, add Gaussian noise with sd "mut_sd", and scale back. We then clip to the lower and upper bounds. For int params: We do the same as for numeric parameters, but round at the end. For factor params: We sample a new level from the unused levels of the parameter. For logical params: We flip the bit.

Hierarchical dependencies are handled like this: Only active params can be mutated. After a mutation has happened, we check the conditions of the search space in topological order. If a condition is not met, we set the param to NA (making it inactive); if all conditions are met for a param, but it currently has is NA, we set it a random valid value.

After the neighbors are generated, we evaluate them. We go to the best neighbor, or stay at the current point if the best neighbor is worse.

There is a restart mechanism to avoid local minima. For each search, we keep track of the number of no-improvement steps. If this number exceeds "stagnate_max", we restart the search with a random point.