mirror of https://codeberg.org/topola/topola.git
Compare commits
2 Commits
9ad5c2088c
...
f2c67ed81d
| Author | SHA1 | Date |
|---|---|---|
|
|
f2c67ed81d | |
|
|
88f8b3610d |
|
|
@ -312,7 +312,7 @@ impl<'a> Displayer<'a> {
|
||||||
.get(&navnode)
|
.get(&navnode)
|
||||||
.map_or_else(String::new, |s| format!("g={:.2}", s));
|
.map_or_else(String::new, |s| format!("g={:.2}", s));
|
||||||
let estimate_score_text = thetastar
|
let estimate_score_text = thetastar
|
||||||
.cost_to_goal_estimate_scores()
|
.estimated_costs()
|
||||||
.get(&navnode)
|
.get(&navnode)
|
||||||
.map_or_else(String::new, |s| format!("(f={:.2})", s));
|
.map_or_else(String::new, |s| format!("(f={:.2})", s));
|
||||||
let debug_text = activity.navnode_debug_text(navnode).unwrap_or("");
|
let debug_text = activity.navnode_debug_text(navnode).unwrap_or("");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Topola contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
collections::{btree_map::Entry, BTreeMap, BinaryHeap},
|
||||||
|
ops::Add,
|
||||||
|
};
|
||||||
|
|
||||||
|
use derive_getters::Getters;
|
||||||
|
|
||||||
|
use crate::scored::MinScored;
|
||||||
|
|
||||||
|
#[derive(Getters)]
|
||||||
|
pub struct Astar<N, S> {
|
||||||
|
#[getter(skip)]
|
||||||
|
frontier: BinaryHeap<MinScored<S, N>>,
|
||||||
|
#[getter(skip)]
|
||||||
|
g_scores: BTreeMap<N, S>,
|
||||||
|
curr_node: N,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: Clone + Ord, S: Add<S, Output = S> + Copy + Default + PartialOrd> Astar<N, S> {
|
||||||
|
pub fn new(start: N) -> Self {
|
||||||
|
let mut frontier = BinaryHeap::new();
|
||||||
|
let mut scores = BTreeMap::new();
|
||||||
|
|
||||||
|
scores.insert(start.clone(), S::default());
|
||||||
|
frontier.push(MinScored(S::default(), start.clone()));
|
||||||
|
|
||||||
|
Self {
|
||||||
|
frontier,
|
||||||
|
g_scores: scores,
|
||||||
|
curr_node: start,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand(&mut self, new_nodes: &[(S, S, N)]) -> Option<N> {
|
||||||
|
let curr_g_score = self.g_scores.get(&self.curr_node).unwrap().clone();
|
||||||
|
|
||||||
|
for (edge_g_cost, h_heuristic, node) in new_nodes {
|
||||||
|
match self.g_scores.entry(node.clone()) {
|
||||||
|
Entry::Occupied(mut entry) => {
|
||||||
|
let entry_score = *entry.get();
|
||||||
|
|
||||||
|
if curr_g_score + *edge_g_cost >= entry_score {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.insert(curr_g_score + *edge_g_cost);
|
||||||
|
}
|
||||||
|
Entry::Vacant(entry) => {
|
||||||
|
entry.insert(curr_g_score + *edge_g_cost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.frontier.push(MinScored(
|
||||||
|
curr_g_score + *edge_g_cost + *h_heuristic,
|
||||||
|
node.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
MinScored(_ /*f_score*/, self.curr_node) = self.frontier.pop()?;
|
||||||
|
Some(self.curr_node.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,6 @@ pub mod multilayer_autoroute;
|
||||||
pub mod multilayer_preconfigurer;
|
pub mod multilayer_preconfigurer;
|
||||||
pub mod multilayer_reconfigurator;
|
pub mod multilayer_reconfigurator;
|
||||||
pub mod multilayer_reconfigurer;
|
pub mod multilayer_reconfigurer;
|
||||||
pub mod permsearch;
|
|
||||||
pub mod place_via;
|
pub mod place_via;
|
||||||
pub mod planar_autoroute;
|
pub mod planar_autoroute;
|
||||||
pub mod planar_preconfigurer;
|
pub mod planar_preconfigurer;
|
||||||
|
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2025 Topola contributors
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
use std::{cmp::Ordering, collections::BinaryHeap, iter::Skip, iter::Take};
|
|
||||||
|
|
||||||
use itertools::{Itertools, Permutations};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct PermsearchNode<T> {
|
|
||||||
curr_permutation: Vec<T>,
|
|
||||||
permutations: Skip<Permutations<Take<std::vec::IntoIter<T>>>>,
|
|
||||||
length: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Eq> PartialEq for PermsearchNode<T> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.curr_permutation == other.curr_permutation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Eq> Eq for PermsearchNode<T> {}
|
|
||||||
|
|
||||||
impl<T: Eq> Ord for PermsearchNode<T> {
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||||
self.length.cmp(&other.length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Eq> PartialOrd for PermsearchNode<T> {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||||
self.length.partial_cmp(&other.length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> PermsearchNode<T> {
|
|
||||||
fn permute(mut self) -> Option<Self> {
|
|
||||||
for (i, element) in self.permutations.next()?.iter().enumerate() {
|
|
||||||
self.curr_permutation[i] = element.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resize(self, length: usize) -> Option<Self> {
|
|
||||||
if length == self.length {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Get rid of `self.curr_permutation` clone somehow?
|
|
||||||
|
|
||||||
Some(Self {
|
|
||||||
curr_permutation: self.curr_permutation.clone(),
|
|
||||||
permutations: self
|
|
||||||
.curr_permutation
|
|
||||||
.into_iter()
|
|
||||||
.take(length)
|
|
||||||
.permutations(length)
|
|
||||||
.skip(1),
|
|
||||||
length,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Permsearch<T> {
|
|
||||||
curr_node: PermsearchNode<T>,
|
|
||||||
frontier: BinaryHeap<PermsearchNode<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Eq + Clone> Permsearch<T> {
|
|
||||||
pub fn new(original: Vec<T>) -> Self {
|
|
||||||
let len = original.len();
|
|
||||||
|
|
||||||
// TODO: Get rid of `original` clone somehow?
|
|
||||||
|
|
||||||
Self {
|
|
||||||
curr_node: PermsearchNode {
|
|
||||||
curr_permutation: original.clone(),
|
|
||||||
permutations: original.into_iter().take(len).permutations(0).skip(0),
|
|
||||||
length: 0,
|
|
||||||
},
|
|
||||||
frontier: BinaryHeap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn step(&mut self, len: usize) -> Option<&[T]> {
|
|
||||||
// TODO: Get rid of `self.curr_node` clones somehow?
|
|
||||||
|
|
||||||
if let Some(resized_curr_node) = self.curr_node.clone().resize(len) {
|
|
||||||
if let Some(permuted_resized_curr_node) = resized_curr_node.permute() {
|
|
||||||
self.frontier.push(permuted_resized_curr_node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(permuted_curr_node) = self.curr_node.clone().permute() {
|
|
||||||
self.frontier.push(permuted_curr_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.curr_node = self.frontier.pop()?;
|
|
||||||
Some(&self.curr_node.curr_permutation)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn curr_permutation(&self) -> &[T] {
|
|
||||||
&self.curr_node.curr_permutation
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,15 +2,24 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
cmp::Ordering,
|
||||||
|
iter::{Skip, Take},
|
||||||
|
};
|
||||||
|
|
||||||
|
use derive_getters::Getters;
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
|
use itertools::{Itertools, Permutations};
|
||||||
use specctra_core::mesadata::AccessMesadata;
|
use specctra_core::mesadata::AccessMesadata;
|
||||||
|
|
||||||
use crate::autorouter::{
|
use crate::{
|
||||||
permsearch::Permsearch,
|
astar::Astar,
|
||||||
planar_autoroute::{PlanarAutorouteConfiguration, PlanarAutorouteExecutionStepper},
|
autorouter::{
|
||||||
planar_preconfigurer::SccIntersectionsAndLengthRatlinePlanarAutoroutePreconfigurer,
|
planar_autoroute::{PlanarAutorouteConfiguration, PlanarAutorouteExecutionStepper},
|
||||||
scc::Scc,
|
planar_preconfigurer::SccIntersectionsAndLengthRatlinePlanarAutoroutePreconfigurer,
|
||||||
Autorouter, PlanarAutorouteOptions,
|
scc::Scc,
|
||||||
|
Autorouter, PlanarAutorouteOptions,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
|
|
@ -49,8 +58,100 @@ impl PlanarAutorouteReconfigurer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Getters)]
|
||||||
|
struct SccSearchNode {
|
||||||
|
curr_permutation: Vec<Scc>,
|
||||||
|
#[getter(skip)]
|
||||||
|
permutations: Skip<Permutations<Take<std::vec::IntoIter<Scc>>>>,
|
||||||
|
#[getter(skip)]
|
||||||
|
length: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for SccSearchNode {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.curr_permutation
|
||||||
|
.cmp(&other.curr_permutation)
|
||||||
|
.then(self.length.cmp(&other.length))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for SccSearchNode {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for SccSearchNode {}
|
||||||
|
|
||||||
|
impl PartialEq for SccSearchNode {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.curr_permutation == other.curr_permutation && self.length == other.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SccSearchNode {
|
||||||
|
pub fn new(sccs: Vec<Scc>) -> Self {
|
||||||
|
let len = sccs.len();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
curr_permutation: sccs.clone(),
|
||||||
|
permutations: sccs.into_iter().take(len).permutations(0).skip(0),
|
||||||
|
length: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expand(&self, length: usize) -> Vec<(f64, f64, Self)> {
|
||||||
|
let mut expanded_nodes = vec![];
|
||||||
|
|
||||||
|
if let Some(resized) = self.clone().resize(length) {
|
||||||
|
if let Some(permuted_resized) = resized.permute() {
|
||||||
|
expanded_nodes.push((
|
||||||
|
0.1,
|
||||||
|
(self.curr_permutation.len() - length) as f64,
|
||||||
|
permuted_resized,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(permuted) = self.clone().permute() {
|
||||||
|
expanded_nodes.push((
|
||||||
|
0.1,
|
||||||
|
(self.curr_permutation.len() - self.length) as f64,
|
||||||
|
permuted,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
expanded_nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(self, length: usize) -> Option<Self> {
|
||||||
|
if length == self.length {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Self {
|
||||||
|
curr_permutation: self.curr_permutation.clone(),
|
||||||
|
permutations: self
|
||||||
|
.curr_permutation
|
||||||
|
.into_iter()
|
||||||
|
.take(length)
|
||||||
|
.permutations(length)
|
||||||
|
.skip(1),
|
||||||
|
length,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permute(mut self) -> Option<Self> {
|
||||||
|
for (i, element) in self.permutations.next()?.iter().enumerate() {
|
||||||
|
self.curr_permutation[i] = element.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SccPermutationsPlanarAutorouteReconfigurer {
|
pub struct SccPermutationsPlanarAutorouteReconfigurer {
|
||||||
sccs_permsearch: Permsearch<Scc>,
|
sccs_search: Astar<SccSearchNode, f64>,
|
||||||
preconfiguration: PlanarAutorouteConfiguration,
|
preconfiguration: PlanarAutorouteConfiguration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,7 +167,7 @@ impl SccPermutationsPlanarAutorouteReconfigurer {
|
||||||
let sccs = presorter.dissolve();
|
let sccs = presorter.dissolve();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
sccs_permsearch: Permsearch::new(sccs),
|
sccs_search: Astar::new(SccSearchNode::new(sccs)),
|
||||||
preconfiguration,
|
preconfiguration,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +180,8 @@ impl MakeNextPlanarAutorouteConfiguration for SccPermutationsPlanarAutorouteReco
|
||||||
stepper: &PlanarAutorouteExecutionStepper,
|
stepper: &PlanarAutorouteExecutionStepper,
|
||||||
) -> Option<PlanarAutorouteConfiguration> {
|
) -> Option<PlanarAutorouteConfiguration> {
|
||||||
let scc_index = self
|
let scc_index = self
|
||||||
.sccs_permsearch
|
.sccs_search
|
||||||
|
.curr_node()
|
||||||
.curr_permutation()
|
.curr_permutation()
|
||||||
.iter()
|
.iter()
|
||||||
.position(|scc| {
|
.position(|scc| {
|
||||||
|
|
@ -88,10 +190,13 @@ impl MakeNextPlanarAutorouteConfiguration for SccPermutationsPlanarAutorouteReco
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let scc_permutation = self.sccs_permsearch.step(scc_index + 1)?;
|
let next_search_node = self
|
||||||
|
.sccs_search
|
||||||
|
.expand(&self.sccs_search.curr_node().expand(scc_index + 1))?;
|
||||||
|
let next_permutation = next_search_node.curr_permutation();
|
||||||
let mut ratlines = vec![];
|
let mut ratlines = vec![];
|
||||||
|
|
||||||
for scc in scc_permutation {
|
for scc in next_permutation {
|
||||||
for ratline in self.preconfiguration.ratlines.iter() {
|
for ratline in self.preconfiguration.ratlines.iter() {
|
||||||
if scc.node_indices().contains(
|
if scc.node_indices().contains(
|
||||||
&autorouter
|
&autorouter
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::{cmp::Ordering, collections::BTreeSet};
|
||||||
|
|
||||||
use derive_getters::Getters;
|
use derive_getters::Getters;
|
||||||
use petgraph::{graph::NodeIndex, prelude::StableUnGraph};
|
use petgraph::{graph::NodeIndex, prelude::StableUnGraph};
|
||||||
|
|
@ -26,6 +26,18 @@ pub struct Scc {
|
||||||
length: f64,
|
length: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Ord for Scc {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.node_indices.cmp(&other.node_indices)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Scc {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for Scc {
|
impl PartialEq for Scc {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.node_indices == other.node_indices
|
self.node_indices == other.node_indices
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
pub mod graph;
|
pub mod graph;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod drawing;
|
pub mod drawing;
|
||||||
|
pub mod astar;
|
||||||
pub mod autorouter;
|
pub mod autorouter;
|
||||||
pub mod bimapset;
|
pub mod bimapset;
|
||||||
pub mod board;
|
pub mod board;
|
||||||
|
|
@ -29,6 +30,7 @@ pub mod interactor;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
pub mod router;
|
pub mod router;
|
||||||
|
pub mod scored;
|
||||||
pub mod specctra;
|
pub mod specctra;
|
||||||
pub mod stepper;
|
pub mod stepper;
|
||||||
pub mod triangulation;
|
pub mod triangulation;
|
||||||
|
|
|
||||||
|
|
@ -18,52 +18,9 @@ use petgraph::algo::Measure;
|
||||||
use petgraph::visit::{EdgeRef, GraphBase, IntoEdgeReferences, IntoEdges};
|
use petgraph::visit::{EdgeRef, GraphBase, IntoEdgeReferences, IntoEdges};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use crate::scored::MinScored;
|
||||||
|
|
||||||
use crate::stepper::{EstimateProgress, LinearScale, Step};
|
use crate::stepper::{EstimateProgress, LinearScale, Step};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct MinScored<K, T>(pub K, pub T);
|
|
||||||
|
|
||||||
impl<K: PartialOrd, T> PartialEq for MinScored<K, T> {
|
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &MinScored<K, T>) -> bool {
|
|
||||||
self.cmp(other) == Ordering::Equal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K: PartialOrd, T> Eq for MinScored<K, T> {}
|
|
||||||
|
|
||||||
impl<K: PartialOrd, T> PartialOrd for MinScored<K, T> {
|
|
||||||
#[inline]
|
|
||||||
fn partial_cmp(&self, other: &MinScored<K, T>) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<K: PartialOrd, T> Ord for MinScored<K, T> {
|
|
||||||
#[inline]
|
|
||||||
fn cmp(&self, other: &MinScored<K, T>) -> Ordering {
|
|
||||||
let a = &self.0;
|
|
||||||
let b = &other.0;
|
|
||||||
if a == b {
|
|
||||||
Ordering::Equal
|
|
||||||
} else if a < b {
|
|
||||||
Ordering::Greater
|
|
||||||
} else if a > b {
|
|
||||||
Ordering::Less
|
|
||||||
} else if a.ne(a) && b.ne(b) {
|
|
||||||
// these are the NaN cases
|
|
||||||
Ordering::Equal
|
|
||||||
} else if a.ne(a) {
|
|
||||||
// Order NaN less, so that it is last in the MinScore order
|
|
||||||
Ordering::Less
|
|
||||||
} else {
|
|
||||||
Ordering::Greater
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PathTracker<G>
|
pub struct PathTracker<G>
|
||||||
where
|
where
|
||||||
|
|
@ -179,7 +136,7 @@ where
|
||||||
/// Also known as the g-scores, or just g.
|
/// Also known as the g-scores, or just g.
|
||||||
scores: BTreeMap<G::NodeId, K>,
|
scores: BTreeMap<G::NodeId, K>,
|
||||||
/// Also known as the f-scores, or just f.
|
/// Also known as the f-scores, or just f.
|
||||||
cost_to_goal_estimate_scores: BTreeMap<G::NodeId, K>,
|
estimated_costs: BTreeMap<G::NodeId, K>,
|
||||||
#[getter(skip)]
|
#[getter(skip)]
|
||||||
path_tracker: PathTracker<G>,
|
path_tracker: PathTracker<G>,
|
||||||
// FIXME: To work around edge references borrowing from the graph we collect then reiterate over them.
|
// FIXME: To work around edge references borrowing from the graph we collect then reiterate over them.
|
||||||
|
|
@ -218,7 +175,7 @@ where
|
||||||
graph,
|
graph,
|
||||||
frontier: BinaryHeap::new(),
|
frontier: BinaryHeap::new(),
|
||||||
scores: BTreeMap::new(),
|
scores: BTreeMap::new(),
|
||||||
cost_to_goal_estimate_scores: BTreeMap::new(),
|
estimated_costs: BTreeMap::new(),
|
||||||
path_tracker: PathTracker::<G>::new(),
|
path_tracker: PathTracker::<G>::new(),
|
||||||
edge_ids: Vec::new(),
|
edge_ids: Vec::new(),
|
||||||
progress_estimate_value: K::default(),
|
progress_estimate_value: K::default(),
|
||||||
|
|
@ -288,7 +245,7 @@ where
|
||||||
return Ok(ControlFlow::Break((cost, path, result)));
|
return Ok(ControlFlow::Break((cost, path, result)));
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.cost_to_goal_estimate_scores.entry(navnode) {
|
match self.estimated_costs.entry(navnode) {
|
||||||
Entry::Occupied(mut entry) => {
|
Entry::Occupied(mut entry) => {
|
||||||
// If the node has already been visited with an equal or lower
|
// If the node has already been visited with an equal or lower
|
||||||
// estimated score than now, then we do not need to re-visit it.
|
// estimated score than now, then we do not need to re-visit it.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
// SPDX-FileCopyrightText: (None)
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||||
|
//
|
||||||
|
// Copied verbatim from petgraph-0.8.3.
|
||||||
|
|
||||||
|
use core::cmp::Ordering;
|
||||||
|
|
||||||
|
/// `MinScored<K, T>` holds a score `K` and a scored object `T` in
|
||||||
|
/// a pair for use with a `BinaryHeap`.
|
||||||
|
///
|
||||||
|
/// `MinScored` compares in reverse order by the score, so that we can
|
||||||
|
/// use `BinaryHeap` as a min-heap to extract the score-value pair with the
|
||||||
|
/// least score.
|
||||||
|
///
|
||||||
|
/// **Note:** `MinScored` implements a total order (`Ord`), so that it is
|
||||||
|
/// possible to use float types as scores.
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct MinScored<K, T>(pub K, pub T);
|
||||||
|
|
||||||
|
impl<K: PartialOrd, T> PartialEq for MinScored<K, T> {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &MinScored<K, T>) -> bool {
|
||||||
|
self.cmp(other) == Ordering::Equal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: PartialOrd, T> Eq for MinScored<K, T> {}
|
||||||
|
|
||||||
|
impl<K: PartialOrd, T> PartialOrd for MinScored<K, T> {
|
||||||
|
#[inline]
|
||||||
|
fn partial_cmp(&self, other: &MinScored<K, T>) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: PartialOrd, T> Ord for MinScored<K, T> {
|
||||||
|
#[inline]
|
||||||
|
fn cmp(&self, other: &MinScored<K, T>) -> Ordering {
|
||||||
|
let a = &self.0;
|
||||||
|
let b = &other.0;
|
||||||
|
if a == b {
|
||||||
|
Ordering::Equal
|
||||||
|
} else if a < b {
|
||||||
|
Ordering::Greater
|
||||||
|
} else if a > b {
|
||||||
|
Ordering::Less
|
||||||
|
} else if a.ne(a) && b.ne(b) {
|
||||||
|
// these are the NaN cases
|
||||||
|
Ordering::Equal
|
||||||
|
} else if a.ne(a) {
|
||||||
|
// Order NaN less, so that it is last in the MinScore order
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct MaxScored<K, T>(pub K, pub T);
|
||||||
|
|
||||||
|
impl<K: PartialOrd, T> PartialEq for MaxScored<K, T> {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &MaxScored<K, T>) -> bool {
|
||||||
|
self.cmp(other) == Ordering::Equal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: PartialOrd, T> Eq for MaxScored<K, T> {}
|
||||||
|
|
||||||
|
impl<K: PartialOrd, T> PartialOrd for MaxScored<K, T> {
|
||||||
|
#[inline]
|
||||||
|
fn partial_cmp(&self, other: &MaxScored<K, T>) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: PartialOrd, T> Ord for MaxScored<K, T> {
|
||||||
|
#[inline]
|
||||||
|
fn cmp(&self, other: &MaxScored<K, T>) -> Ordering {
|
||||||
|
let a = &self.0;
|
||||||
|
let b = &other.0;
|
||||||
|
if a == b {
|
||||||
|
Ordering::Equal
|
||||||
|
} else if a < b {
|
||||||
|
Ordering::Less
|
||||||
|
} else if a > b {
|
||||||
|
Ordering::Greater
|
||||||
|
} else if a.ne(a) && b.ne(b) {
|
||||||
|
// these are the NaN cases
|
||||||
|
Ordering::Equal
|
||||||
|
} else if a.ne(a) {
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue