Skip to main content

solverforge_solver/heuristic/selector/
list_precedence.rs

1//! Public static facade for the canonical critical-path precedence kernel.
2
3use std::fmt::Debug;
4
5use solverforge_core::domain::PlanningSolution;
6use solverforge_scoring::Director;
7
8use crate::heuristic::r#move::ListMoveUnion;
9use crate::heuristic::selector::list_kernel::{
10    critical_analysis, filtered_move_count, filtered_multi_support_swap_count,
11    multi_critical_ruin_count, CriticalAnalysis, NativePrecedenceEmitter, PrecedenceCursor,
12};
13
14use super::entity::EntitySelector;
15use super::move_selector::{
16    CandidateId, MoveCandidateRef, MoveCursor, MoveSelector, MoveStreamContext,
17};
18use super::precedence_route::PrecedenceRouteHooks;
19
20/// Generates move families around critical same-list precedence arcs.
21///
22/// The public constructor and static move union are unchanged. Critical-path
23/// analysis, ordering, cycle pruning, candidate ownership, and mixed move
24/// emission are shared with the future runtime-list leaf.
25pub struct ListPrecedenceMoveSelector<S, V, ES> {
26    entity_selector: ES,
27    element_count: fn(&S) -> usize,
28    index_to_element: fn(&S, usize) -> V,
29    node_duration: fn(&S, V) -> usize,
30    fixed_successors: fn(&S, V, &mut Vec<V>),
31    entity_count: fn(&S) -> usize,
32    list_len: fn(&S, usize) -> usize,
33    list_get: fn(&S, usize, usize) -> Option<V>,
34    list_remove: fn(&mut S, usize, usize) -> Option<V>,
35    list_insert: fn(&mut S, usize, usize, V),
36    list_set: fn(&mut S, usize, usize, V),
37    list_reverse: fn(&mut S, usize, usize, usize),
38    ruin_remove: fn(&mut S, usize, usize) -> V,
39    ruin_insert: fn(&mut S, usize, usize, V),
40    element_owner_fn: Option<fn(&S, &V) -> Option<usize>>,
41    sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
42    sublist_insert: fn(&mut S, usize, usize, Vec<V>),
43    variable_name: &'static str,
44    descriptor_index: usize,
45}
46
47/// Public cursor facade over the canonical precedence stream.
48pub struct ListPrecedenceMoveCursor<S, V>
49where
50    S: PlanningSolution,
51    V: Clone + PartialEq + Send + Sync + Debug + 'static,
52{
53    inner: PrecedenceCursor<S, NativePrecedenceEmitter<S, V>>,
54}
55
56impl<S, V> ListPrecedenceMoveCursor<S, V>
57where
58    S: PlanningSolution,
59    V: Clone + PartialEq + Send + Sync + Debug + 'static,
60{
61    fn new(inner: PrecedenceCursor<S, NativePrecedenceEmitter<S, V>>) -> Self {
62        Self { inner }
63    }
64}
65
66impl<S, V> MoveCursor<S, ListMoveUnion<S, V>> for ListPrecedenceMoveCursor<S, V>
67where
68    S: PlanningSolution,
69    V: Clone + PartialEq + Send + Sync + Debug + 'static,
70{
71    fn next_candidate(&mut self, solution: &S) -> Option<CandidateId> {
72        self.inner.next_candidate(solution)
73    }
74
75    fn candidate(&self, id: CandidateId) -> Option<MoveCandidateRef<'_, S, ListMoveUnion<S, V>>> {
76        self.inner.candidate(id)
77    }
78
79    fn take_candidate(&mut self, id: CandidateId) -> ListMoveUnion<S, V> {
80        self.inner.take_candidate(id)
81    }
82
83    fn next_owned_candidate(&mut self, solution: &S) -> Option<ListMoveUnion<S, V>> {
84        self.inner.next_owned_candidate(solution)
85    }
86
87    fn next_owned_candidate_matching(
88        &mut self,
89        solution: &S,
90        predicate: for<'a> fn(MoveCandidateRef<'a, S, ListMoveUnion<S, V>>) -> bool,
91    ) -> Option<ListMoveUnion<S, V>> {
92        self.inner
93            .next_owned_candidate_matching(solution, predicate)
94    }
95
96    fn release_candidate(&mut self, id: CandidateId) -> bool {
97        self.inner.release_candidate(id)
98    }
99}
100
101impl<S, V: Debug, ES: Debug> Debug for ListPrecedenceMoveSelector<S, V, ES> {
102    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        formatter
104            .debug_struct("ListPrecedenceMoveSelector")
105            .field("entity_selector", &self.entity_selector)
106            .field("variable_name", &self.variable_name)
107            .finish()
108    }
109}
110
111impl<S, V, ES> ListPrecedenceMoveSelector<S, V, ES> {
112    #[allow(clippy::too_many_arguments)]
113    pub fn new(
114        entity_selector: ES,
115        element_count: fn(&S) -> usize,
116        index_to_element: fn(&S, usize) -> V,
117        node_duration: fn(&S, V) -> usize,
118        fixed_successors: fn(&S, V, &mut Vec<V>),
119        entity_count: fn(&S) -> usize,
120        list_len: fn(&S, usize) -> usize,
121        list_get: fn(&S, usize, usize) -> Option<V>,
122        list_remove: fn(&mut S, usize, usize) -> Option<V>,
123        list_insert: fn(&mut S, usize, usize, V),
124        list_set: fn(&mut S, usize, usize, V),
125        list_reverse: fn(&mut S, usize, usize, usize),
126        ruin_remove: fn(&mut S, usize, usize) -> V,
127        ruin_insert: fn(&mut S, usize, usize, V),
128        element_owner_fn: Option<fn(&S, &V) -> Option<usize>>,
129        sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
130        sublist_insert: fn(&mut S, usize, usize, Vec<V>),
131        variable_name: &'static str,
132        descriptor_index: usize,
133    ) -> Self {
134        Self {
135            entity_selector,
136            element_count,
137            index_to_element,
138            node_duration,
139            fixed_successors,
140            entity_count,
141            list_len,
142            list_get,
143            list_remove,
144            list_insert,
145            list_set,
146            list_reverse,
147            ruin_remove,
148            ruin_insert,
149            element_owner_fn,
150            sublist_remove,
151            sublist_insert,
152            variable_name,
153            descriptor_index,
154        }
155    }
156}
157
158impl<S, V, ES> MoveSelector<S, ListMoveUnion<S, V>> for ListPrecedenceMoveSelector<S, V, ES>
159where
160    S: PlanningSolution,
161    V: Clone + PartialEq + Send + Sync + Debug + 'static,
162    ES: EntitySelector<S>,
163{
164    type Cursor<'a>
165        = ListPrecedenceMoveCursor<S, V>
166    where
167        Self: 'a;
168
169    fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
170        self.open_cursor_with_context(score_director, MoveStreamContext::default())
171    }
172
173    fn open_cursor_with_context<'a, D: Director<S>>(
174        &'a self,
175        score_director: &D,
176        context: MoveStreamContext,
177    ) -> Self::Cursor<'a> {
178        let analysis = self.analysis(score_director);
179        let emitter = self.emitter();
180        ListPrecedenceMoveCursor::new(PrecedenceCursor::new(
181            analysis.blocks,
182            analysis.route_graph,
183            context,
184            emitter,
185            self.descriptor_index,
186        ))
187    }
188
189    fn size<D: Director<S>>(&self, score_director: &D) -> usize {
190        let mut analysis = self.analysis(score_director);
191        analysis
192            .blocks
193            .iter()
194            .copied()
195            .map(|block| filtered_move_count(block, &mut analysis.route_graph))
196            .sum::<usize>()
197            + filtered_multi_support_swap_count(&analysis.blocks, &mut analysis.route_graph)
198            + multi_critical_ruin_count(&analysis.blocks)
199    }
200}
201
202impl<S, V, ES> ListPrecedenceMoveSelector<S, V, ES>
203where
204    S: PlanningSolution,
205    V: Clone + PartialEq + Send + Sync + Debug + 'static,
206    ES: EntitySelector<S>,
207{
208    fn analysis<D: Director<S>>(&self, score_director: &D) -> CriticalAnalysis {
209        critical_analysis(
210            score_director,
211            &self.entity_selector,
212            self.element_count,
213            self.index_to_element,
214            self.node_duration,
215            self.list_len,
216            PrecedenceRouteHooks::new(
217                self.fixed_successors,
218                self.entity_count,
219                self.list_len,
220                self.list_get,
221            ),
222        )
223    }
224
225    fn emitter(&self) -> NativePrecedenceEmitter<S, V> {
226        NativePrecedenceEmitter::new(
227            self.element_count,
228            self.index_to_element,
229            self.fixed_successors,
230            self.entity_count,
231            self.list_len,
232            self.list_get,
233            self.list_remove,
234            self.list_insert,
235            self.list_set,
236            self.list_reverse,
237            self.ruin_remove,
238            self.ruin_insert,
239            self.element_owner_fn,
240            self.sublist_remove,
241            self.sublist_insert,
242            self.variable_name,
243            self.descriptor_index,
244        )
245    }
246}