From c120a43d04ff214f96e8b2015e5167f9e98dc983 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Thu, 25 Sep 2025 14:32:35 +0200 Subject: [PATCH] refactor(autorouter/presorter): Move some SCC code to new file --- src/autorouter/mod.rs | 1 + src/autorouter/permuter.rs | 9 ++- src/autorouter/presorter.rs | 120 +++--------------------------------- src/autorouter/scc.rs | 96 +++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 115 deletions(-) create mode 100644 src/autorouter/scc.rs diff --git a/src/autorouter/mod.rs b/src/autorouter/mod.rs index 32b2cf1..180fdbc 100644 --- a/src/autorouter/mod.rs +++ b/src/autorouter/mod.rs @@ -18,6 +18,7 @@ pub mod presorter; pub mod ratline; pub mod ratsnest; pub mod remove_bands; +pub mod scc; pub mod selection; pub use autorouter::*; diff --git a/src/autorouter/permuter.rs b/src/autorouter/permuter.rs index c05d86c..fd8f501 100644 --- a/src/autorouter/permuter.rs +++ b/src/autorouter/permuter.rs @@ -6,13 +6,12 @@ use std::iter::Skip; use enum_dispatch::enum_dispatch; use itertools::{Itertools, Permutations}; -use petgraph::graph::NodeIndex; use specctra_core::mesadata::AccessMesadata; use crate::{ autorouter::{ autoroute::AutorouteExecutionStepper, presorter::SccIntersectionsAndLengthPresorter, - ratline::RatlineIndex, Autorouter, AutorouterOptions, + ratline::RatlineIndex, scc::Scc, Autorouter, AutorouterOptions, }, drawing::graph::MakePrimitiveRef, geometry::{GenericNode, GetLayer}, @@ -51,7 +50,7 @@ impl RatlinesPermuter { } pub struct SccPermutationsRatlinePermuter { - sccs_permutations_iter: Skip>>>>, + sccs_permutations_iter: Skip>>, original_ratlines: Vec, } @@ -85,14 +84,14 @@ impl PermuteRatlines for SccPermutationsRatlinePermuter { for scc in scc_permutation { for ratline in self.original_ratlines.iter() { - if scc.contains( + if scc.node_indices().contains( &autorouter .ratsnest() .graph() .edge_endpoints(*ratline) .unwrap() .0, - ) && scc.contains( + ) && scc.node_indices().contains( &autorouter .ratsnest() .graph() diff --git a/src/autorouter/presorter.rs b/src/autorouter/presorter.rs index 38f4234..c16a59d 100644 --- a/src/autorouter/presorter.rs +++ b/src/autorouter/presorter.rs @@ -6,14 +6,10 @@ use std::cmp::Ordering; use derive_getters::{Dissolve, Getters}; use enum_dispatch::enum_dispatch; -use petgraph::{algo::tarjan_scc, graph::NodeIndex}; +use petgraph::algo::tarjan_scc; use specctra_core::mesadata::AccessMesadata; -use crate::{ - autorouter::{ratline::RatlineIndex, Autorouter}, - geometry::shape::MeasureLength, - graph::MakeRef, -}; +use crate::autorouter::{ratline::RatlineIndex, scc::Scc, Autorouter}; #[enum_dispatch] pub trait PresortRatlines { @@ -31,7 +27,7 @@ pub enum RatlinesPresorter { #[derive(Getters, Dissolve)] pub struct SccIntersectionsAndLengthPresorter { - sccs: Vec>>, + sccs: Vec, } impl SccIntersectionsAndLengthPresorter { @@ -43,103 +39,21 @@ impl SccIntersectionsAndLengthPresorter { let mut filtered_ratsnest = autorouter.ratsnest().graph().clone(); filtered_ratsnest.retain_edges(|_g, i| ratlines.contains(&i)); - let mut sccs = tarjan_scc(&filtered_ratsnest); + let mut sccs: Vec<_> = tarjan_scc(&filtered_ratsnest) + .into_iter() + .map(|node_indices| Scc::new(autorouter, ratlines, &filtered_ratsnest, node_indices)) + .collect(); sccs.sort_unstable_by(|a, b| { - // FIXME: These calculations should probably be stored somewhere - // instead of being done every time. - - let mut a_intersector_count = 0; - let mut b_intersector_count = 0; - let mut a_length = 0.0; - let mut b_length = 0.0; - - // FIXME: It's inefficient to iterate over the ratlines on every - // sort comparison. But this is the simplest solution I arrived - // at after realizing that `.tarjan_scc(...)` does not sort nodes - // inside components. - for ratline in ratlines.iter() { - if a.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().0) - && a.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().1) - { - a_length += ratline.ref_(autorouter).length(); - a_intersector_count += - ratline.ref_(autorouter).interiorly_cut_ratlines().count(); - a_intersector_count += - ratline.ref_(autorouter).cut_other_net_primitives().count(); - } - } - - for ratline in ratlines.iter() { - if b.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().0) - && b.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().1) - { - b_length += ratline.ref_(autorouter).length(); - b_intersector_count += - ratline.ref_(autorouter).interiorly_cut_ratlines().count(); - b_intersector_count += - ratline.ref_(autorouter).cut_other_net_primitives().count(); - } - } - - let primary_ordering = a_intersector_count.cmp(&b_intersector_count); + let primary_ordering = a.intersector_count().cmp(&b.intersector_count()); if primary_ordering != Ordering::Equal { primary_ordering } else { - let secondary_ordering = a_length.total_cmp(&b_length); + let secondary_ordering = a.length().total_cmp(&b.length()); secondary_ordering } - - // Below is how I tried to do this before I realized that - // `.tarjan_scc(...)` does not sort nodes inside components. - - /*let a_intersector_count: usize = a - .windows(2) - .map(|window| { - let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap(); - ratline - .ref_(autorouter) - .interior_obstacle_ratlines() - .count() - }) - .sum(); - let b_intersector_count: usize = b - .windows(2) - .map(|window| { - let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap(); - ratline - .ref_(autorouter) - .interior_obstacle_ratlines() - .count() - }) - .sum(); - - let primary_ordering = a_intersector_count.cmp(&b_intersector_count); - - if primary_ordering != Ordering::Equal { - primary_ordering - } else { - let a_length: f64 = a - .windows(2) - .map(|window| { - let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap(); - ratline.ref_(autorouter).length() - }) - .sum(); - let b_length: f64 = b - .windows(2) - .map(|window| { - let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap(); - ratline.ref_(autorouter).length() - }) - .sum(); - - let secondary_ordering = a_length.total_cmp(&b_length); - - secondary_ordering - }*/ }); Self { sccs } @@ -156,21 +70,7 @@ impl PresortRatlines for SccIntersectionsAndLengthPresorter { for scc in self.sccs.iter() { for ratline in ratlines.iter() { - if scc.contains( - &autorouter - .ratsnest() - .graph() - .edge_endpoints(*ratline) - .unwrap() - .0, - ) && scc.contains( - &autorouter - .ratsnest() - .graph() - .edge_endpoints(*ratline) - .unwrap() - .1, - ) { + if scc.scc_ref(autorouter).contains(*ratline) { presorted_ratlines.push(*ratline); } } diff --git a/src/autorouter/scc.rs b/src/autorouter/scc.rs new file mode 100644 index 0000000..3219ed2 --- /dev/null +++ b/src/autorouter/scc.rs @@ -0,0 +1,96 @@ +// SPDX-FileCopyrightText: 2025 Topola contributors +// +// SPDX-License-Identifier: MIT + +use derive_getters::Getters; +use petgraph::{graph::NodeIndex, prelude::StableUnGraph}; +use specctra_core::mesadata::AccessMesadata; + +use crate::{ + autorouter::{ + ratline::{RatlineIndex, RatlineWeight}, + ratsnest::RatvertexWeight, + Autorouter, + }, + geometry::shape::MeasureLength, + graph::MakeRef, +}; + +#[derive(Clone, Debug, Getters)] +pub struct Scc { + node_indices: Vec>, + + length: f64, + intersector_count: usize, +} + +impl Scc { + pub fn new( + autorouter: &mut Autorouter, + ratlines: &[RatlineIndex], + filtered_ratsnest: &StableUnGraph, + node_indices: Vec>, + ) -> Self { + let mut this = Self { + node_indices, + length: 0.0, + intersector_count: 0, + }; + + for ratline in ratlines.iter() { + if this + .node_indices + .contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().0) + && this + .node_indices + .contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().1) + { + this.length += ratline.ref_(autorouter).length(); + this.intersector_count += + ratline.ref_(autorouter).interiorly_cut_ratlines().count(); + this.intersector_count += + ratline.ref_(autorouter).cut_other_net_primitives().count(); + } + } + + this + } + + pub fn scc_ref<'a, M: AccessMesadata>( + &'a self, + autorouter: &'a Autorouter, + ) -> SccRef<'a, M> { + SccRef::new(self, autorouter) + } +} + +pub struct SccRef<'a, M: AccessMesadata> { + scc: &'a Scc, + autorouter: &'a Autorouter, +} + +impl<'a, M: AccessMesadata> SccRef<'a, M> { + pub fn new(scc: &'a Scc, autorouter: &'a Autorouter) -> Self { + Self { scc, autorouter } + } + + pub fn contains(&self, ratline: RatlineIndex) -> bool { + self.scc.node_indices().contains( + &self + .autorouter + .ratsnest() + .graph() + .edge_endpoints(ratline) + .unwrap() + .0, + ) && self.scc.node_indices().contains( + &self + .autorouter + .ratsnest() + .graph() + .edge_endpoints(ratline) + .unwrap() + .1, + ) + } +}