solverforge_solver/heuristic/move/
mod.rs

1//! Move system for modifying planning solutions.
2//!
3//! Moves are the fundamental operations that modify planning variables during
4//! solving. The solver explores the solution space by applying different moves
5//! and evaluating their impact on the score.
6//!
7//! # Architecture
8//!
9//! All moves are fully typed with inline value storage for maximum performance:
10//! - `ChangeMove<S, V>` - assigns a value to a variable
11//! - `SwapMove<S, V>` - swaps values between two entities
12//! - `PillarChangeMove<S, V>` - changes multiple entities with same value
13//! - `PillarSwapMove<S, V>` - swaps between two pillars
14//! - `ListChangeMove<S, V>` - relocates an element in a list variable
15//! - `ListSwapMove<S, V>` - swaps two elements in list variables
16//! - `SubListChangeMove<S, V>` - relocates a contiguous sublist
17//! - `SubListSwapMove<S, V>` - swaps two contiguous sublists
18//! - `ListReverseMove<S, V>` - reverses a segment (2-opt for TSP)
19//! - `RuinMove<S, V>` - unassigns multiple entities (for Large Neighborhood Search)
20//! - `ListRuinMove<S, V>` - removes elements from a list (for LNS on list variables)
21//! - `CompositeMove<S, M1, M2>` - combines two moves in sequence
22//!
23//! Undo is handled by `RecordingScoreDirector`, not by moves returning undo data.
24//!
25//! # Arena Allocation
26//!
27//! Use `MoveArena<M>` for O(1) per-step cleanup. Call `reset()` at each step
28//! instead of allocating a new Vec.
29
30mod arena;
31mod change;
32mod composite;
33mod k_opt;
34pub mod k_opt_reconnection;
35mod list_change;
36mod list_reverse;
37mod list_ruin;
38mod list_swap;
39mod pillar_change;
40mod pillar_swap;
41mod ruin;
42mod sublist_change;
43mod sublist_swap;
44mod swap;
45
46use std::fmt::Debug;
47
48use solverforge_core::domain::PlanningSolution;
49use solverforge_scoring::ScoreDirector;
50
51pub use arena::MoveArena;
52pub use change::ChangeMove;
53pub use composite::CompositeMove;
54pub use k_opt::{CutPoint, KOptMove};
55pub use list_change::ListChangeMove;
56pub use list_reverse::ListReverseMove;
57pub use list_ruin::ListRuinMove;
58pub use list_swap::ListSwapMove;
59pub use pillar_change::PillarChangeMove;
60pub use pillar_swap::PillarSwapMove;
61pub use ruin::RuinMove;
62pub use sublist_change::SubListChangeMove;
63pub use sublist_swap::SubListSwapMove;
64pub use swap::SwapMove;
65
66/// A move that modifies one or more planning variables.
67///
68/// Moves are fully typed for maximum performance - no boxing, no virtual dispatch.
69/// Undo is handled by `RecordingScoreDirector`, not by move return values.
70///
71/// # Type Parameters
72/// * `S` - The planning solution type
73///
74/// # Implementation Notes
75/// - Moves should be lightweight and cloneable
76/// - Use `RecordingScoreDirector` to wrap the score director for automatic undo
77/// - Implement `Clone` for arena allocation support
78pub trait Move<S: PlanningSolution>: Send + Sync + Debug + Clone {
79    /// Returns true if this move can be executed in the current state.
80    ///
81    /// A move is not doable if:
82    /// - The source value equals the destination value (no change)
83    /// - Required entities are pinned
84    /// - The move would violate hard constraints that can be detected early
85    fn is_doable(&self, score_director: &dyn ScoreDirector<S>) -> bool;
86
87    /// Executes this move, modifying the working solution.
88    ///
89    /// This method modifies the planning variables through the score director.
90    /// Use `RecordingScoreDirector` to enable automatic undo via `undo_changes()`.
91    fn do_move(&self, score_director: &mut dyn ScoreDirector<S>);
92
93    /// Returns the descriptor index of the entity type this move affects.
94    fn descriptor_index(&self) -> usize;
95
96    /// Returns the entity indices involved in this move.
97    fn entity_indices(&self) -> &[usize];
98
99    /// Returns the variable name this move affects.
100    fn variable_name(&self) -> &str;
101}