LocalSearchPhaseFactory

Struct LocalSearchPhaseFactory 

Source
pub struct LocalSearchPhaseFactory<S, M, F>
where S: PlanningSolution, M: Move<S> + Clone + Send + Sync + 'static, F: Fn() -> Box<dyn MoveSelector<S, M>> + Send + Sync,
{ /* private fields */ }
Expand description

Factory for creating local search phases.

Local search phases improve an existing solution by exploring neighboring solutions. The factory provides fresh phase instances for each solve, ensuring that internal state (like tabu lists or temperature) is reset.

§Type Parameters

  • S - The planning solution type
  • M - The move type (e.g., ChangeMove, SwapMove)
  • F - The closure type that creates move selectors

§Available Acceptors

§Example

use solverforge_solver::manager::{LocalSearchPhaseFactory, SolverPhaseFactory};
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;

#[derive(Clone)]
struct S { values: Vec<Option<i32>>, score: Option<SimpleScore> }
impl PlanningSolution for S {
    type Score = SimpleScore;
    fn score(&self) -> Option<Self::Score> { self.score }
    fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
}

fn get_v(s: &S, idx: usize) -> Option<i32> { s.values.get(idx).copied().flatten() }
fn set_v(s: &mut S, idx: usize, v: Option<i32>) { if let Some(x) = s.values.get_mut(idx) { *x = v; } }

type M = ChangeMove<S, i32>;

// Hill climbing with step limit
let factory = LocalSearchPhaseFactory::<S, M, _>::hill_climbing(|| {
    Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "value", vec![1, 2, 3]))
}).with_step_limit(1000);

// Tabu search
let tabu = LocalSearchPhaseFactory::<S, M, _>::tabu_search(7, || {
    Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "value", vec![1, 2, 3]))
});

// Simulated annealing
let sa = LocalSearchPhaseFactory::<S, M, _>::simulated_annealing(1.0, 0.999, || {
    Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "value", vec![1, 2, 3]))
});

Implementations§

Source§

impl<S, M, F> LocalSearchPhaseFactory<S, M, F>
where S: PlanningSolution, M: Move<S> + Clone + Send + Sync + 'static, F: Fn() -> Box<dyn MoveSelector<S, M>> + Send + Sync,

Source

pub fn new(search_type: LocalSearchType, move_selector_factory: F) -> Self

Creates a new local search phase factory with the specified search type.

§Arguments
  • search_type - The type of local search algorithm
  • move_selector_factory - A closure that creates move selectors
§Example
use solverforge_solver::manager::{LocalSearchType, LocalSearchPhaseFactory};
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;

type M = ChangeMove<S, i32>;

let factory = LocalSearchPhaseFactory::<S, M, _>::new(
    LocalSearchType::TabuSearch { tabu_size: 10 },
    || Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2])),
);
Source

pub fn with_step_limit(self, limit: u64) -> Self

Sets the step limit for this phase.

The phase will terminate after executing this many steps. This is useful for multi-phase configurations where you want to limit time spent in each phase.

§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;

type M = ChangeMove<S, i32>;

let factory = LocalSearchPhaseFactory::<S, M, _>::hill_climbing(|| {
    Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2]))
}).with_step_limit(500);
Source

pub fn hill_climbing(move_selector_factory: F) -> Self

Creates a factory with hill climbing acceptor.

Hill climbing only accepts moves that improve the score. It is simple and fast, but can easily get stuck in local optima.

§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;

type M = ChangeMove<S, i32>;

let factory = LocalSearchPhaseFactory::<S, M, _>::hill_climbing(|| {
    Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "value", vec![1, 2, 3]))
});

Creates a factory with tabu search acceptor.

Tabu search maintains a list of recently made moves and forbids reversing them. This helps escape local optima by forcing exploration.

§Arguments
  • tabu_size - Number of recent moves to remember
  • move_selector_factory - Closure that creates move selectors
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;

type M = ChangeMove<S, i32>;

// Remember last 7 moves
let factory = LocalSearchPhaseFactory::<S, M, _>::tabu_search(7, || {
    Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2, 3]))
});
Source

pub fn simulated_annealing( starting_temp: f64, decay_rate: f64, move_selector_factory: F, ) -> Self

Creates a factory with simulated annealing acceptor.

Simulated annealing accepts worse moves with a probability that decreases over time. Initially, it explores widely; as the “temperature” cools, it becomes more selective.

§Arguments
  • starting_temp - Initial temperature (higher = more exploration)
  • decay_rate - Rate at which temperature decreases (0.0 to 1.0)
  • move_selector_factory - Closure that creates move selectors
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;

type M = ChangeMove<S, i32>;

// Start at temperature 1.0, decay by 0.1% per step
let factory = LocalSearchPhaseFactory::<S, M, _>::simulated_annealing(
    1.0,
    0.999,
    || Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2, 3])),
);
Source

pub fn late_acceptance(size: usize, move_selector_factory: F) -> Self

Creates a factory with late acceptance acceptor.

Late acceptance compares the new score against the score from N steps ago. If the new score is better than or equal to that historical score, the move is accepted. This provides a balance between exploration and exploitation.

§Arguments
  • size - Number of steps to look back
  • move_selector_factory - Closure that creates move selectors
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;

type M = ChangeMove<S, i32>;

// Compare against score from 400 steps ago
let factory = LocalSearchPhaseFactory::<S, M, _>::late_acceptance(400, || {
    Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2, 3]))
});

Creates a factory with value tabu acceptor.

Value tabu remembers recently assigned values and forbids reassigning them. This is different from entity tabu in that it tracks values, not entity-variable combinations.

§Arguments
  • value_tabu_size - Number of recent values to forbid
  • move_selector_factory - Closure that creates move selectors
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;

type M = ChangeMove<S, i32>;

// Forbid last 5 assigned values
let factory = LocalSearchPhaseFactory::<S, M, _>::value_tabu_search(5, || {
    Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2, 3]))
});

Creates a factory with move tabu acceptor.

Move tabu remembers recently made moves (by hash) and forbids making the same move again. Supports aspiration criterion: tabu moves can be accepted if they lead to a new best solution.

§Arguments
  • move_tabu_size - Number of recent moves to forbid
  • aspiration_enabled - Whether to allow tabu moves that reach new best score
  • move_selector_factory - Closure that creates move selectors
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;

type M = ChangeMove<S, i32>;

// Forbid last 10 moves, with aspiration enabled
let factory = LocalSearchPhaseFactory::<S, M, _>::move_tabu_search(10, true, || {
    Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2, 3]))
});

Trait Implementations§

Source§

impl<S, M, F> SolverPhaseFactory<S> for LocalSearchPhaseFactory<S, M, F>
where S: PlanningSolution + 'static, M: Move<S> + Clone + Send + Sync + 'static, F: Fn() -> Box<dyn MoveSelector<S, M>> + Send + Sync,

Source§

fn create_phase(&self) -> Box<dyn Phase<S>>

Creates a new phase instance. Read more

Auto Trait Implementations§

§

impl<S, M, F> Freeze for LocalSearchPhaseFactory<S, M, F>
where F: Freeze,

§

impl<S, M, F> RefUnwindSafe for LocalSearchPhaseFactory<S, M, F>

§

impl<S, M, F> Send for LocalSearchPhaseFactory<S, M, F>

§

impl<S, M, F> Sync for LocalSearchPhaseFactory<S, M, F>

§

impl<S, M, F> Unpin for LocalSearchPhaseFactory<S, M, F>
where F: Unpin, S: Unpin, M: Unpin,

§

impl<S, M, F> UnwindSafe for LocalSearchPhaseFactory<S, M, F>
where F: UnwindSafe, S: UnwindSafe, M: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more