mirror of https://codeberg.org/topola/topola.git
refactor(autorouter/presorter): Move some SCC code to new file
This commit is contained in:
parent
a703b1ec4e
commit
c120a43d04
|
|
@ -18,6 +18,7 @@ pub mod presorter;
|
||||||
pub mod ratline;
|
pub mod ratline;
|
||||||
pub mod ratsnest;
|
pub mod ratsnest;
|
||||||
pub mod remove_bands;
|
pub mod remove_bands;
|
||||||
|
pub mod scc;
|
||||||
pub mod selection;
|
pub mod selection;
|
||||||
|
|
||||||
pub use autorouter::*;
|
pub use autorouter::*;
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,12 @@ use std::iter::Skip;
|
||||||
|
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use itertools::{Itertools, Permutations};
|
use itertools::{Itertools, Permutations};
|
||||||
use petgraph::graph::NodeIndex;
|
|
||||||
use specctra_core::mesadata::AccessMesadata;
|
use specctra_core::mesadata::AccessMesadata;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
autorouter::{
|
autorouter::{
|
||||||
autoroute::AutorouteExecutionStepper, presorter::SccIntersectionsAndLengthPresorter,
|
autoroute::AutorouteExecutionStepper, presorter::SccIntersectionsAndLengthPresorter,
|
||||||
ratline::RatlineIndex, Autorouter, AutorouterOptions,
|
ratline::RatlineIndex, scc::Scc, Autorouter, AutorouterOptions,
|
||||||
},
|
},
|
||||||
drawing::graph::MakePrimitiveRef,
|
drawing::graph::MakePrimitiveRef,
|
||||||
geometry::{GenericNode, GetLayer},
|
geometry::{GenericNode, GetLayer},
|
||||||
|
|
@ -51,7 +50,7 @@ impl RatlinesPermuter {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SccPermutationsRatlinePermuter {
|
pub struct SccPermutationsRatlinePermuter {
|
||||||
sccs_permutations_iter: Skip<Permutations<std::vec::IntoIter<Vec<NodeIndex<usize>>>>>,
|
sccs_permutations_iter: Skip<Permutations<std::vec::IntoIter<Scc>>>,
|
||||||
original_ratlines: Vec<RatlineIndex>,
|
original_ratlines: Vec<RatlineIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,14 +84,14 @@ impl PermuteRatlines for SccPermutationsRatlinePermuter {
|
||||||
|
|
||||||
for scc in scc_permutation {
|
for scc in scc_permutation {
|
||||||
for ratline in self.original_ratlines.iter() {
|
for ratline in self.original_ratlines.iter() {
|
||||||
if scc.contains(
|
if scc.node_indices().contains(
|
||||||
&autorouter
|
&autorouter
|
||||||
.ratsnest()
|
.ratsnest()
|
||||||
.graph()
|
.graph()
|
||||||
.edge_endpoints(*ratline)
|
.edge_endpoints(*ratline)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.0,
|
.0,
|
||||||
) && scc.contains(
|
) && scc.node_indices().contains(
|
||||||
&autorouter
|
&autorouter
|
||||||
.ratsnest()
|
.ratsnest()
|
||||||
.graph()
|
.graph()
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,10 @@ use std::cmp::Ordering;
|
||||||
|
|
||||||
use derive_getters::{Dissolve, Getters};
|
use derive_getters::{Dissolve, Getters};
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use petgraph::{algo::tarjan_scc, graph::NodeIndex};
|
use petgraph::algo::tarjan_scc;
|
||||||
use specctra_core::mesadata::AccessMesadata;
|
use specctra_core::mesadata::AccessMesadata;
|
||||||
|
|
||||||
use crate::{
|
use crate::autorouter::{ratline::RatlineIndex, scc::Scc, Autorouter};
|
||||||
autorouter::{ratline::RatlineIndex, Autorouter},
|
|
||||||
geometry::shape::MeasureLength,
|
|
||||||
graph::MakeRef,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub trait PresortRatlines {
|
pub trait PresortRatlines {
|
||||||
|
|
@ -31,7 +27,7 @@ pub enum RatlinesPresorter {
|
||||||
|
|
||||||
#[derive(Getters, Dissolve)]
|
#[derive(Getters, Dissolve)]
|
||||||
pub struct SccIntersectionsAndLengthPresorter {
|
pub struct SccIntersectionsAndLengthPresorter {
|
||||||
sccs: Vec<Vec<NodeIndex<usize>>>,
|
sccs: Vec<Scc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SccIntersectionsAndLengthPresorter {
|
impl SccIntersectionsAndLengthPresorter {
|
||||||
|
|
@ -43,103 +39,21 @@ impl SccIntersectionsAndLengthPresorter {
|
||||||
let mut filtered_ratsnest = autorouter.ratsnest().graph().clone();
|
let mut filtered_ratsnest = autorouter.ratsnest().graph().clone();
|
||||||
filtered_ratsnest.retain_edges(|_g, i| ratlines.contains(&i));
|
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| {
|
sccs.sort_unstable_by(|a, b| {
|
||||||
// FIXME: These calculations should probably be stored somewhere
|
let primary_ordering = a.intersector_count().cmp(&b.intersector_count());
|
||||||
// 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);
|
|
||||||
|
|
||||||
if primary_ordering != Ordering::Equal {
|
if primary_ordering != Ordering::Equal {
|
||||||
primary_ordering
|
primary_ordering
|
||||||
} else {
|
} else {
|
||||||
let secondary_ordering = a_length.total_cmp(&b_length);
|
let secondary_ordering = a.length().total_cmp(&b.length());
|
||||||
|
|
||||||
secondary_ordering
|
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 }
|
Self { sccs }
|
||||||
|
|
@ -156,21 +70,7 @@ impl PresortRatlines for SccIntersectionsAndLengthPresorter {
|
||||||
|
|
||||||
for scc in self.sccs.iter() {
|
for scc in self.sccs.iter() {
|
||||||
for ratline in ratlines.iter() {
|
for ratline in ratlines.iter() {
|
||||||
if scc.contains(
|
if scc.scc_ref(autorouter).contains(*ratline) {
|
||||||
&autorouter
|
|
||||||
.ratsnest()
|
|
||||||
.graph()
|
|
||||||
.edge_endpoints(*ratline)
|
|
||||||
.unwrap()
|
|
||||||
.0,
|
|
||||||
) && scc.contains(
|
|
||||||
&autorouter
|
|
||||||
.ratsnest()
|
|
||||||
.graph()
|
|
||||||
.edge_endpoints(*ratline)
|
|
||||||
.unwrap()
|
|
||||||
.1,
|
|
||||||
) {
|
|
||||||
presorted_ratlines.push(*ratline);
|
presorted_ratlines.push(*ratline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<NodeIndex<usize>>,
|
||||||
|
|
||||||
|
length: f64,
|
||||||
|
intersector_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scc {
|
||||||
|
pub fn new(
|
||||||
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
|
ratlines: &[RatlineIndex],
|
||||||
|
filtered_ratsnest: &StableUnGraph<RatvertexWeight, RatlineWeight, usize>,
|
||||||
|
node_indices: Vec<NodeIndex<usize>>,
|
||||||
|
) -> 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<M>,
|
||||||
|
) -> SccRef<'a, M> {
|
||||||
|
SccRef::new(self, autorouter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SccRef<'a, M: AccessMesadata> {
|
||||||
|
scc: &'a Scc,
|
||||||
|
autorouter: &'a Autorouter<M>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, M: AccessMesadata> SccRef<'a, M> {
|
||||||
|
pub fn new(scc: &'a Scc, autorouter: &'a Autorouter<M>) -> 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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue