pub struct ListCheapestInsertionPhase<S, E>{ /* private fields */ }Expand description
List construction phase using greedy cheapest insertion.
For each unassigned element (in index order), evaluates all possible insertion positions across all entities and inserts it at the position that yields the best score. This is significantly better than round-robin for VRP because:
- Routes are built incrementally with score feedback
- Capacity constraints influence which vehicle receives each visit
- Distance/duration constraints are optimized at the point of insertion
§Algorithm
for each unassigned element e:
for each entity r and each position p in r:
try insert(e, r, p), score, undo
permanently insert e at (r*, p*) with best scoreComplexity: O(E × N × M) where E = elements, N = entities, M = avg route length.
§Example
use solverforge_solver::ListCheapestInsertionPhase;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;
#[derive(Clone)]
struct Vehicle { visits: Vec<usize> }
#[derive(Clone)]
struct Plan { vehicles: Vec<Vehicle>, n_visits: usize, score: Option<SimpleScore> }
impl PlanningSolution for Plan {
type Score = SimpleScore;
fn score(&self) -> Option<Self::Score> { self.score }
fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
}
fn list_len(s: &Plan, e: usize) -> usize {
s.vehicles.get(e).map_or(0, |v| v.visits.len())
}
fn list_insert(s: &mut Plan, e: usize, pos: usize, val: usize) {
if let Some(v) = s.vehicles.get_mut(e) { v.visits.insert(pos, val); }
}
fn list_remove(s: &mut Plan, e: usize, pos: usize) -> usize {
s.vehicles.get_mut(e).map(|v| v.visits.remove(pos)).unwrap_or(0)
}
let phase = ListCheapestInsertionPhase::<Plan, usize>::new(
|p| p.n_visits,
|p| p.vehicles.iter().flat_map(|v| v.visits.iter().copied()).collect(),
|p| p.vehicles.len(),
list_len,
list_insert,
list_remove,
|idx| idx,
"visits",
0,
);Implementations§
Source§impl<S, E> ListCheapestInsertionPhase<S, E>
impl<S, E> ListCheapestInsertionPhase<S, E>
Sourcepub fn new(
element_count: fn(&S) -> usize,
get_assigned: fn(&S) -> Vec<E>,
entity_count: fn(&S) -> usize,
list_len: fn(&S, usize) -> usize,
list_insert: fn(&mut S, usize, usize, E),
list_remove: fn(&mut S, usize, usize) -> E,
index_to_element: fn(usize) -> E,
variable_name: &'static str,
descriptor_index: usize,
) -> Self
pub fn new( element_count: fn(&S) -> usize, get_assigned: fn(&S) -> Vec<E>, entity_count: fn(&S) -> usize, list_len: fn(&S, usize) -> usize, list_insert: fn(&mut S, usize, usize, E), list_remove: fn(&mut S, usize, usize) -> E, index_to_element: fn(usize) -> E, variable_name: &'static str, descriptor_index: usize, ) -> Self
Creates a new cheapest insertion phase.
§Arguments
element_count- Total number of elements to assignget_assigned- Returns currently assigned elementsentity_count- Total number of entities (routes/vehicles)list_len- Length of entity’s listlist_insert- Insert element at position (shifts right)list_remove- Remove element at position (used for undo), returns removed elementindex_to_element- Converts element index to element valuevariable_name- Name of the list variabledescriptor_index- Entity descriptor index
Trait Implementations§
Source§impl<S, E> Debug for ListCheapestInsertionPhase<S, E>
impl<S, E> Debug for ListCheapestInsertionPhase<S, E>
Source§impl<S, E, D> Phase<S, D> for ListCheapestInsertionPhase<S, E>where
S: PlanningSolution,
E: Copy + PartialEq + Eq + Hash + Send + Sync + 'static,
D: ScoreDirector<S>,
impl<S, E, D> Phase<S, D> for ListCheapestInsertionPhase<S, E>where
S: PlanningSolution,
E: Copy + PartialEq + Eq + Hash + Send + Sync + 'static,
D: ScoreDirector<S>,
Source§fn solve(&mut self, solver_scope: &mut SolverScope<'_, S, D>)
fn solve(&mut self, solver_scope: &mut SolverScope<'_, S, D>)
Executes this phase. Read more
Source§fn phase_type_name(&self) -> &'static str
fn phase_type_name(&self) -> &'static str
Returns the name of this phase type.
Auto Trait Implementations§
impl<S, E> Freeze for ListCheapestInsertionPhase<S, E>
impl<S, E> RefUnwindSafe for ListCheapestInsertionPhase<S, E>
impl<S, E> Send for ListCheapestInsertionPhase<S, E>
impl<S, E> Sync for ListCheapestInsertionPhase<S, E>
impl<S, E> Unpin for ListCheapestInsertionPhase<S, E>
impl<S, E> UnsafeUnpin for ListCheapestInsertionPhase<S, E>
impl<S, E> UnwindSafe for ListCheapestInsertionPhase<S, E>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more