1#![warn(warnings)]
7#![warn(clippy::all, clippy::pedantic)]
8#![allow(non_upper_case_globals)]
9#![allow(clippy::needless_return)]
10#![allow(clippy::items_after_statements)]
11#![allow(unused_variables, unused_imports, dead_code)]
12
13use std::cell::Cell;
14use std::cmp;
15use std::cmp::Ordering;
16use binary_heap_plus::BinaryHeap;
17use std::fmt::{Debug};
18use std::marker::PhantomData;
19use petgraph::stable_graph::EdgeIndex;
20use petgraph::stable_graph::EdgeReference;
21use petgraph::stable_graph::StableGraph;
22use petgraph::prelude::{EdgeRef, NodeIndex};
23use typed_arena::Arena;
24
25pub type GraphType<NodeWeight, EdgeWeight> = StableGraph::<NodeWeight, EdgeWeight, petgraph::Directed, u32>;
27
28pub trait InitialLabelGenerator<T> {
30 fn default(problem : &T) -> Self;
32}
33
34
35pub trait UserProblem<LabelMeta: Meta, NodeWeight,EdgeWeight, BranchFilter>
44{
45 fn create_graph(&mut self) -> ProblemGraph<NodeWeight, EdgeWeight>;
49
50 fn is_dominating(label_a: &Label<LabelMeta>, label_b: &Label<LabelMeta>, active_filters : &[BranchFilter]) -> bool;
53
54 fn extend_label<'arena>(
59 &self,
60 existing_label : &'arena Label<'arena, LabelMeta>,
61 edge : &EdgeReference<EdgeWeight>,
62 source : &NodeWeight,
63 target : &NodeWeight,
64 active_filters : &[BranchFilter],
65 sink : NodeIndex
66 ) -> Option<Label<'arena,LabelMeta>>;
67
68}
69
70pub struct ProblemGraph<NodeWeight,EdgeWeight > {
72 pub dag : GraphType<NodeWeight,EdgeWeight>,
73 pub start : NodeIndex,
74 pub end : NodeIndex
75}
76
77pub struct RcspSolver<Problem,LabelMeta : Meta, NodeWeight,EdgeWeight , BranchFilter>
79 where
80 Problem : UserProblem<LabelMeta, NodeWeight, EdgeWeight, BranchFilter>,
81
82{
83 user_problem : Problem,
84 graph : ProblemGraph<NodeWeight,EdgeWeight>,
85 _meta : PhantomData<LabelMeta>,
86 _ew : PhantomData<EdgeWeight>,
87 _nw : PhantomData<NodeWeight>,
88 _ft : PhantomData<BranchFilter>
89}
90
91impl<Problem : UserProblem<LabelMeta,NodeWeight, EdgeWeight, BranchFilter>,LabelMeta : Meta, NodeWeight,EdgeWeight, BranchFilter>
92 RcspSolver<Problem,LabelMeta, NodeWeight, EdgeWeight, BranchFilter>
93{
94
95 pub fn new(mut problem : Problem) -> Self {
96
97 let graph = problem.create_graph();
98 Self {
99 user_problem : problem,
100 graph,
101 _meta: PhantomData,
102 _ew: PhantomData,
103 _nw: PhantomData,
104 _ft : PhantomData
105 }
106 }
107
108 pub fn get_graph(&self) -> &ProblemGraph<NodeWeight,EdgeWeight> {
110 &self.graph
111 }
112
113 pub fn get_graph_mut(&mut self) -> &mut ProblemGraph<NodeWeight,EdgeWeight> {
115 &mut self.graph
116 }
117
118 pub fn get_problem_mut(&mut self) -> &mut Problem {
120 &mut self.user_problem
121 }
122
123 pub fn get_problem(&self) -> &Problem {
125 &self.user_problem
126 }
127
128}
129
130#[derive(Clone, PartialEq)]
131pub struct FeasiblePath {
133 pub path: Vec<(NodeIndex,Option<EdgeIndex>)>
134}
135
136impl Debug for FeasiblePath{
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 f.write_str("\nFeasiblePath\n")?;
139 f.write_str("Visiting: ")?;
140 for (node,_edge) in &self.path {
141 f.write_fmt(format_args!("{}-", node.index()))?;
142 }
143 f.write_str("\n")?;
144 Ok(())
145 }
146}
147
148pub trait Meta : Clone + Debug {}
150
151
152
153
154impl< Problem : UserProblem<LabelMeta, NodeWeight,EdgeWeight, BranchFilter> ,LabelMeta : Meta + InitialLabelGenerator<Problem>, NodeWeight,EdgeWeight, BranchFilter>
155 RcspSolver< Problem,LabelMeta, NodeWeight,EdgeWeight, BranchFilter>
156 where NodeWeight: Debug + Clone ,
157{
158
159
160 pub fn find_paths<const EARLY_EXIT: bool>(&mut self, filters : &[BranchFilter], path_start_cost : f64) -> Vec<(f64,FeasiblePath)> {
164
165
166 let raw_problem_graph = &self.graph;
167
168 let start_node = raw_problem_graph.start;
169 let end_node = raw_problem_graph.end;
170
171 let dag = &raw_problem_graph.dag;
172
173 let mut labels_at : Vec<Vec<&Label<LabelMeta>>> = vec![
175 Vec::with_capacity(128); dag.node_count()
176 ];
177
178 debug_assert_eq!(start_node.index(), 0);
179
180 let arena = Arena::new();
181
182 let initial_label = arena.alloc(Label {
183 node : start_node,
184 extended_along_edge : None,
185 parent : None,
186 meta : LabelMeta::default(&self.user_problem),
187 costs: path_start_cost,
188 was_dominated : Cell::new(false)
189 });
190
191
192 let mut unprocessed_labels: BinaryHeap<&Label<LabelMeta>, _> = BinaryHeap::with_capacity_by(4096, |a : &&Label<LabelMeta>, b : &&Label<LabelMeta>| {
193 b.costs.partial_cmp(&a.costs).unwrap_or(Ordering::Equal)
195 });
196
197 unprocessed_labels.push(initial_label);
198 'main: loop {
199
200 let process_opt = unprocessed_labels.pop();
201
202 let potential_next_labels = match process_opt {
204 Some(process) => {
205
206 if process.was_dominated.get() {
207 continue
208 }
209
210 dag.edges_directed(
211 process.node, petgraph::Direction::Outgoing).into_iter().filter_map(|edge : EdgeReference<_>| {
212
213 return self.user_problem.extend_label(process, &edge, &dag[edge.source()], &dag[edge.target()], filters, end_node)
214 })
215
216
217
218
219 },
220 None => break,
221 };
222
223 for new_label in potential_next_labels {
225
226 if let Some(added_label) = Self::add_with_dominance_check(&mut labels_at[new_label.node.index()], &arena,new_label, filters) {
227 if EARLY_EXIT {
228 if added_label.node == end_node && added_label.costs < -0.000_001 {
229 break 'main;
230 }
231 }
232 unprocessed_labels.push(added_label);
233 }
234 }
235 }
236
237
238 let labels_at_end = &labels_at[end_node.index()];
240 let mut output : Vec<(f64,FeasiblePath)> = labels_at_end.iter().map(|label| {
241 let mut path = Vec::new();
242 Self::get_parent(&mut path, label);
243
244 path.reverse();
245
246
247 (label.costs, FeasiblePath {
248 path: path
249 })
250 }).collect();
251
252
253 output.sort_unstable_by(|a,b| a.0.partial_cmp(&b.0).unwrap_or(cmp::Ordering::Equal) );
254
255 output
256 }
257
258
259
260
261 #[inline(always)]
262 fn get_parent(nodes : &mut Vec<(NodeIndex,Option<EdgeIndex>)>, label : &Label<LabelMeta>) {
263 nodes.push((label.node, label.extended_along_edge));
264 if let Some(parent) = label.parent {
265 Self::get_parent(nodes, parent);
266 }
267 }
268
269
270 fn add_with_dominance_check<'arena>(
283 labels: & mut Vec<&'arena Label<'arena, LabelMeta>>,
284 arena : &'arena Arena<Label<'arena, LabelMeta>>,
285 candidate: Label<'arena, LabelMeta>,
286 active_filters : &[BranchFilter]
287 ) -> Option<&'arena Label<'arena, LabelMeta>>
288 {
289
290
291
292 let mut i = 0;
293 while i < labels.len() {
297 if labels[i].costs > candidate.costs {
298 break;
299 } else if Problem::is_dominating(labels[i], &candidate, active_filters) {
300 return None;
301 } else if labels[i].costs == candidate.costs {
302 break;
303 } else {
304 i += 1;
305 }
306 }
307
308 let added_label = arena.alloc(candidate);
312
313 let mut candidate = &*added_label;
314 let s_idx = i; let mut tmp = if i == labels.len() {
319 labels.push(candidate);
322 return Some(added_label);
323 } else if Problem::is_dominating(candidate, labels[i], active_filters) {
324 labels[i] = candidate; None } else {
329 std::mem::swap(&mut labels[i], &mut candidate);
331 Some(candidate) };
333
334
335 let mut removed = 0;
336 i += 1; while i < labels.len() {
338
339
340 if Problem::is_dominating(labels[s_idx], labels[i], active_filters) {
342
343
344 if tmp.is_some() {
346 let val = tmp.take().unwrap();
348 labels[i] = val;
351 } else {
352 removed += 1;
356 }
357 } else {if tmp.is_some() {
359 std::mem::swap(&mut labels[i], tmp.as_mut().unwrap());
363 } else if removed > 0 {
364 labels.swap(i, i - removed);
367 }
368 }
369 i += 1;
370 }
371 if let Some(label) = tmp {
373 labels.push(label);
374 } else if removed > 0 {
375 let kept = labels.len() - removed;
376 for i in labels.iter().skip(kept) {
378 i.was_dominated.set(true);
379 }
380
381 unsafe {
382 labels.set_len(kept);
383 }
384 }
385
386 return Some(added_label)
387
388 }
389
390
391}
392
393
394
395
396
397#[derive(Clone, Debug)]
398pub struct Label<'a, M : Meta> {
402 pub costs: f64,
403 pub node : NodeIndex,
404 pub extended_along_edge : Option<EdgeIndex>,
405 pub parent : Option<&'a Label<'a,M>>,
406 pub meta : M,
407 was_dominated : Cell<bool>,
408}
409
410
411impl<'a,M : Meta> Label<'a, M> {
412
413 pub fn extend<T>( parent : &'a Label<'a,M>,edge : &EdgeReference<T>, delta_cost : f64, new_meta : M ) -> Self {
415 Self {
416 costs: parent.costs + delta_cost ,
417 node: edge.target(),
418 extended_along_edge: Some(edge.id()),
419 parent : Some(parent),
420 meta: new_meta,
421 was_dominated: Cell::new(false)
422 }
423 }
424
425 pub fn new( cost : f64, node : NodeIndex,extended_along_edge : Option<EdgeIndex>, parent : Option<&'a Label<'a,M>>, meta : M) -> Self {
427 Self{
428 costs: cost,
429 node,
430 extended_along_edge,
431 parent,
432 meta,
433 was_dominated : Cell::new(false)
434 }
435 }
436
437
438
439}
440
441
442
443
444
445