Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions scala-source/com/barrybecker4/optimization/Optimizer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ class Optimizer(val optimizee: Optimizee, optimizationLogFile: Option[String] =
* @param params the initial guess at the solution; also defines the bounds of the search space
* @param fitnessRange approximate scale of the objective (e.g. max − min fitness over the domain of interest).
* Used by strategies that need a temperature or stopping threshold in the same units as
* fitness: e.g. [[SimulatedAnnealingStrategy]]
* fitness: e.g. [[com.barrybecker4.optimization.strategy.annealing.SimulatedAnnealingStrategy]]
* scales initial temperature from `fitnessRange / 10`, and
* [[GeneticSearchStrategy]] derives improvement
* [[com.barrybecker4.optimization.strategy.genetic.GeneticSearchStrategy]] derives improvement
* epsilon from `fitnessRange / 100_000_000`. It need not be exact; order-of-magnitude is enough.
* @param rnd random source for stochastic strategies
* @param maxEvaluations if set, wraps the optimizee so each call to `evaluateFitness` or `compareFitness`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ object BudgetedOptimizee {

/**
* Wrap `delegate` with an evaluation budget. When `delegate` mixes in [[DiscreteStateSpace]],
* the wrapper also does so (needed for [[StateSpaceSearchStrategy]]).
* the wrapper also does so (needed for [[com.barrybecker4.optimization.strategy.statespace.StateSpaceSearchStrategy]]).
*/
def wrap(delegate: Optimizee, maxEvaluations: Int): BudgetedOptimizee =
delegate match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import scala.util.Random
* production: it does the full evaluations that the delta exists to avoid.
*
* It also checks that the fitness the strategy passes in for the current array is the true one.
* Any mismatch throws an [[IllegalStateException]] that names the move.
* Any mismatch throws an `IllegalStateException` that names the move.
* @param delegate the optimizee with the delta to check
* @param tolerance how far apart, relative to the size of the fitness, two values may be and still count as equal
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.barrybecker4.optimization.strategy.statespace.{StateSpaceSearchMode,

/**
* Mix in with an [[Optimizee]] when the search space is a discrete graph, and you can enumerate
* one-step transitions. Used by [[StateSpaceSearchStrategy]].
* one-step transitions. Used by [[com.barrybecker4.optimization.strategy.statespace.StateSpaceSearchStrategy]].
* Successor lists should stay small; this API is for structured, low-branching problems—not huge graphs.
*/
trait DiscreteStateSpace {
Expand All @@ -18,7 +18,7 @@ trait DiscreteStateSpace {
* Optional A* heuristic: lower means closer to the goal.
* Default `0` keeps uninformed best-first behavior.
* Must be admissible (never overestimate remaining cost) when using
* [[StateSpaceSearchMode.AStar]].
* [[com.barrybecker4.optimization.strategy.statespace.StateSpaceSearchMode.AStar]].
*/
def heuristic(state: ParameterArray): Double = 0.0
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ trait Optimizee {

/**
* The fitness that `current` would have after `move`, for an optimizee that does not evaluate by comparison.
* A strategy that can describe a neighbor as a [[Move]] asks this instead of building the neighbor and calling
* A strategy that can describe a neighbor as a [[com.barrybecker4.optimization.parameter.Move]] asks this instead of building the neighbor and calling
* [[evaluateFitness]] on it, and builds the neighbor only if it keeps the move.
*
* The default builds the neighbor and evaluates it all over, so no optimizee has to change. Override it when the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import scala.collection.mutable

/**
* A set of parameter arrays where two are the same member when they are the same candidate, as told by
* [[ParameterArray.candidateIdentity]]. A strategy uses it to skip candidates it has already tried.
* [[com.barrybecker4.optimization.parameter.ParameterArray.candidateIdentity]]. A strategy uses it to skip candidates it has already tried.
*
* A plain hash set of arrays would hash and compare every parameter object of the case class for each lookup. This one
* hashes the primitive values of the identity once per candidate, which is much cheaper on long arrays.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ case class GlobalSimulatedAnnealingConfig(
require(multistartCount >= 1, s"multistartCount must be at least 1, got $multistartCount")
require(globalSampleBudget > 0, s"globalSampleBudget must be positive, got $globalSampleBudget")

/** [[SeedSelection.DiverseFromTopM.topM]] uses `max(10 * multistartCount, 50)` when `topM <= 0`. */
/** `SeedSelection.DiverseFromTopM.topM` uses `max(10 * multistartCount, 50)` when `topM <= 0`. */
def effectiveSeedSelection: SeedSelection =
seedSelection match {
case SeedSelection.TopFitness =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ object GlobalSimulatedAnnealingStrategy {
* Prefer this over [[GLOBAL_HILL_CLIMBING]] when local optima are deep and annealing can escape them;
* prefer [[SIMULATED_ANNEALING]] alone when a single chain with the evaluation budget is enough.
*
* Extra multistart seeds often share the same [[Random]] as the initial guess; annealing mutates that RNG.
* Extra multistart seeds often share the same [[scala.util.Random]] as the initial guess; annealing mutates that RNG.
* Fork per seed (after the primary) so the first local run matches single-start behavior and later starts
* do not depend on how many draws earlier seeds consumed.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ object SimulatedAnnealingStrategy {
* in the [[com.barrybecker4.optimization.parameter.ParameterArray]] (e.g. [[com.barrybecker4.optimization.parameter.NumericParameterArray]]).
*
* Budget: when the optimizee is wrapped with an evaluation budget, this strategy catches
* [[EvaluationBudgetExceededException]] and returns best-so-far (seeded via [[notifyOfChange]] after the initial eval).
* [[com.barrybecker4.optimization.optimizee.EvaluationBudgetExceededException]] and returns best-so-far (seeded via [[notifyOfChange]] after the initial eval).
*
* @param optimizee the thing to be optimized.
* @author Barry Becker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import scala.util.{Failure, Random, Success, Try}
* [[NeighborSelection.GreedyImproveAbsolute]] each mutation is a short sequential chain of retries, so it is not
* parallelized; choose [[NeighborSelection.SingleSample]] to get parallel speed-up for absolute fitness.
*
* '''Thread safety:''' the [[Optimizee]] must be safe for concurrent `evaluateFitness` /
* '''Thread safety:''' the [[com.barrybecker4.optimization.optimizee.Optimizee]] must be safe for concurrent `evaluateFitness` /
* `compareFitness` calls (typical for immutable puzzle/sim objectives). If the optimizee
* mutates shared state, use [[GeneticSearchStrategy]] instead or synchronize externally.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ object IteratedLocalSearchStrategy {
/**
* Iterated local search (ILS) and variable neighborhood search (VNS) for discrete problems such as permutations
* ([[com.barrybecker4.optimization.parameter.PermutedParameterArray]]) and variable length integer sets
* ([[com.barrybecker4.optimization.parameter.VariableLengthIntSet]]). It works with any [[ParameterArray]],
* but for continuous parameters [[ParticleSwarmStrategy]] or [[DifferentialEvolutionStrategy]] are better choices.
* ([[com.barrybecker4.optimization.parameter.VariableLengthIntSet]]). It works with any [[com.barrybecker4.optimization.parameter.ParameterArray]],
* but for continuous parameters [[com.barrybecker4.optimization.strategy.particleswarm.ParticleSwarmStrategy]] or [[com.barrybecker4.optimization.strategy.DifferentialEvolutionStrategy]] are better choices.
*
* One round of the search:
* 1. ''Shake'': from the current solution make `k` successive random neighbor moves (the shake level `k`).
Expand All @@ -37,30 +37,30 @@ object IteratedLocalSearchStrategy {
*
* With a fixed shake level this is iterated local search. With the level rising after each failed round and
* resetting after an improvement it is variable neighborhood search. See [[IteratedLocalSearchConfig]] for the two
* presets that [[OptimizationStrategyType.ITERATED_LOCAL_SEARCH]] and
* [[OptimizationStrategyType.VARIABLE_NEIGHBORHOOD_SEARCH]] use. If no new best solution has been found for a while,
* presets that [[com.barrybecker4.optimization.strategy.OptimizationStrategyType.ITERATED_LOCAL_SEARCH]] and
* [[com.barrybecker4.optimization.strategy.OptimizationStrategyType.VARIABLE_NEIGHBORHOOD_SEARCH]] use. If no new best solution has been found for a while,
* the search restarts from a random solution (the best found is never lost).
*
* How it relates to the other strategies for discrete problems: the local search is the same random neighbor,
* first improvement descent with a cache of tried solutions that [[HillClimbingStrategy]] uses; what is added is
* first improvement descent with a cache of tried solutions that [[com.barrybecker4.optimization.strategy.hillclimbing.HillClimbingStrategy]] uses; what is added is
* the shake and accept loop, which keeps exploring around good solutions instead of stopping at the first local
* optimum (like [[SimulatedAnnealingStrategy]], it can escape local optima, but it decides per local optimum, not per
* move) and instead of restarting from unrelated samples (like [[GlobalHillClimbingStrategy]]).
* optimum (like [[com.barrybecker4.optimization.strategy.annealing.SimulatedAnnealingStrategy]], it can escape local optima, but it decides per local optimum, not per
* move) and instead of restarting from unrelated samples (like [[com.barrybecker4.optimization.strategy.hillclimbing.GlobalHillClimbingStrategy]]).
*
* The parameter array only offers random neighbors, not an enumeration of all neighbors, so "local optimum" means
* `maxStaleNeighbors` failed tries in a row; for a very large neighborhood, raise it. Every distinct solution is
* evaluated at most once: a shake or neighbor that was already visited is skipped (which also stops a local search
* from walking back into a local optimum that was already explored).
*
* '''Comparison mode (`evaluateByComparison == true`):''' like [[HillClimbingStrategy]], a neighbor is an improvement
* '''Comparison mode (`evaluateByComparison == true`):''' like [[com.barrybecker4.optimization.strategy.hillclimbing.HillClimbingStrategy]], a neighbor is an improvement
* when `compareFitness(neighbor, current) < 0`, and the reported fitness of a solution is
* `compareFitness(solution, initialGuess)`.
*
* The [[rnd]] parameter is used for the Metropolis acceptance coin flips; neighbors and random samples come from the
* [[scala.util.Random]] embedded in the [[ParameterArray]] (as for [[SimulatedAnnealingStrategy]]).
* The `rnd` parameter is used for the Metropolis acceptance coin flips; neighbors and random samples come from the
* [[scala.util.Random]] embedded in the [[com.barrybecker4.optimization.parameter.ParameterArray]] (as for [[com.barrybecker4.optimization.strategy.annealing.SimulatedAnnealingStrategy]]).
*
* Budget: when the optimizee is wrapped with an evaluation budget, this strategy catches
* [[EvaluationBudgetExceededException]] and returns the best solution found so far.
* [[com.barrybecker4.optimization.optimizee.EvaluationBudgetExceededException]] and returns the best solution found so far.
*
* @param optimizee the thing to be optimized.
* @param rnd random source for the Metropolis acceptance decisions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ import scala.util.Random
* meaningfully for `stagnationIterations` iterations (see [[ParticleSwarmConfig]]).
*
* Limitations: the fitness must be absolute (`evaluateByComparison == false`) and the parameters must be a
* [[NumericParameterArray]]; permutations and variable-length sets are not supported (use a genetic or annealing
* [[com.barrybecker4.optimization.parameter.NumericParameterArray]]; permutations and variable-length sets are not supported (use a genetic or annealing
* strategy for those). Violations are reported with an `IllegalArgumentException`.
*
* Budget: when the optimizee is wrapped with an evaluation budget, this strategy catches
* [[EvaluationBudgetExceededException]] and returns the best position found so far.
* [[com.barrybecker4.optimization.optimizee.EvaluationBudgetExceededException]] and returns the best position found so far.
*
* @param optimizee the thing to be optimized.
* @param rnd source of randomness for the initial swarm and the stochastic velocity updates.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object StateSpaceSearchStrategy {

/**
* Canonical key for visited-set dedup (`ParameterArray` often lacks value equality). It is the array's
* [[ParameterArray.candidateIdentity]], so a state is the same exactly when genetic search would call it the same.
* [[com.barrybecker4.optimization.parameter.ParameterArray.candidateIdentity]], so a state is the same exactly when genetic search would call it the same.
*/
private[strategy] def stateKey(pa: ParameterArray): Any = Solutions.key(pa)
}
Expand All @@ -22,10 +22,10 @@ object StateSpaceSearchStrategy {
* [[com.barrybecker4.optimization.optimizee.DiscreteStateSpace]] and its `successors` method.
* Intended for small or structured state spaces with low branching factor.
*
* Visited states are keyed by [[stateKey]] (the candidate identity) so newly allocated successors that
* Visited states are keyed by `stateKey` (the candidate identity) so newly allocated successors that
* represent the same logical state are not re-evaluated.
*
* Budget: catches [[EvaluationBudgetExceededException]] and returns best-so-far
* Budget: catches [[com.barrybecker4.optimization.optimizee.EvaluationBudgetExceededException]] and returns best-so-far
* (seeded via [[notifyOfChange]] after the initial evaluation).
*
* A*: when [[StateSpaceSearchMode.AStar]] is selected and fitness is absolute,
Expand Down
Loading