diff --git a/committed.toml b/committed.toml index ab8f2dd..b4b0942 100644 --- a/committed.toml +++ b/committed.toml @@ -21,6 +21,7 @@ allowed_scopes = [ "autorouter/autoroute", "autorouter/autorouter", "autorouter/compare_detours", + "autorouter/conncomps", "autorouter/execution", "autorouter/history", "autorouter/invoker", diff --git a/src/autorouter/conncomps.rs b/src/autorouter/conncomps.rs new file mode 100644 index 0000000..db823c0 --- /dev/null +++ b/src/autorouter/conncomps.rs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2025 Topola contributors +// +// SPDX-License-Identifier: MIT + +use derive_getters::Getters; +use petgraph::unionfind::UnionFind; +use specctra_core::rules::AccessRules; + +use crate::{ + drawing::{graph::PrimitiveIndex, primitive::GetJoints}, + graph::GetIndex, + layout::Layout, +}; + +#[derive(Clone, Getters)] +pub struct Conncomps { + unionfind: UnionFind, +} + +impl Conncomps { + pub fn new(layout: &Layout) -> Self { + let mut unionfind = UnionFind::new(layout.drawing().geometry().dot_index_bound()); + + for primitive in layout.drawing().primitive_nodes() { + match primitive { + PrimitiveIndex::FixedSeg(seg) => { + let joints = layout.drawing().primitive(seg).joints(); + unionfind.union(joints.0.index(), joints.1.index()); + } + PrimitiveIndex::LoneLooseSeg(seg) => { + let joints = layout.drawing().primitive(seg).joints(); + unionfind.union(joints.0.index(), joints.1.index()); + } + PrimitiveIndex::SeqLooseSeg(seg) => { + let joints = layout.drawing().primitive(seg).joints(); + unionfind.union(joints.0.index(), joints.1.index()); + } + PrimitiveIndex::FixedBend(bend) => { + let joints = layout.drawing().primitive(bend).joints(); + unionfind.union(joints.0.index(), joints.1.index()); + } + PrimitiveIndex::LooseBend(bend) => { + let joints = layout.drawing().primitive(bend).joints(); + unionfind.union(joints.0.index(), joints.1.index()); + } + _ => (), + } + } + + Self { unionfind } + } +} diff --git a/src/autorouter/mod.rs b/src/autorouter/mod.rs index 5ce80bd..32b2cf1 100644 --- a/src/autorouter/mod.rs +++ b/src/autorouter/mod.rs @@ -5,6 +5,7 @@ pub mod autoroute; mod autorouter; pub mod compare_detours; +pub mod conncomps; pub mod execution; pub mod history; pub mod invoker; diff --git a/src/autorouter/ratsnest.rs b/src/autorouter/ratsnest.rs index 317d020..b5016ff 100644 --- a/src/autorouter/ratsnest.rs +++ b/src/autorouter/ratsnest.rs @@ -6,15 +6,11 @@ use std::collections::BTreeMap; use enum_dispatch::enum_dispatch; use geo::Point; -use petgraph::{ - data::Element, - prelude::StableUnGraph, - unionfind::UnionFind, - visit::{EdgeRef, IntoEdgeReferences, NodeIndexable}, -}; +use petgraph::{data::Element, prelude::StableUnGraph, visit::NodeIndexable}; use spade::{HasPosition, InsertionError, Point2}; use crate::{ + autorouter::conncomps::Conncomps, drawing::{ band::BandTermsegIndex, dot::FixedDotIndex, @@ -74,11 +70,7 @@ pub struct Ratsnest { impl Ratsnest { pub fn new(layout: &Layout) -> Result { - let mut unionfind = UnionFind::new(layout.drawing().geometry().graph().node_bound()); - - for edge in layout.drawing().geometry().graph().edge_references() { - unionfind.union(edge.source().index(), edge.target().index()); - } + let conncomps = Conncomps::new(layout); let mut this = Self { graph: StableUnGraph::default(), @@ -145,7 +137,7 @@ impl Ratsnest { if let Some((source, target)) = g.edge_endpoints(i) { let source_index = g.node_weight(source).unwrap().node_index().index(); let target_index = g.node_weight(target).unwrap().node_index().index(); - !unionfind.equiv(source_index, target_index) + !conncomps.unionfind().equiv(source_index, target_index) } else { true } diff --git a/src/geometry/geometry.rs b/src/geometry/geometry.rs index 7adfd71..74556a4 100644 --- a/src/geometry/geometry.rs +++ b/src/geometry/geometry.rs @@ -7,7 +7,7 @@ use enum_dispatch::enum_dispatch; use geo::Point; use petgraph::{ stable_graph::StableDiGraph, - visit::{EdgeRef, Walker}, + visit::{EdgeRef, NodeIndexable, Walker}, Direction::{Incoming, Outgoing}, }; use serde::{Deserialize, Serialize}; @@ -518,6 +518,18 @@ impl< pub fn bend_joints(&self, bend: BI) -> (DI, DI) { self.joints(bend.into()) } + + pub fn dot_index_bound(&self) -> usize { + self.graph.node_bound() + } + + pub fn seg_index_bound(&self) -> usize { + self.graph.node_bound() + } + + pub fn bend_index_bound(&self) -> usize { + self.graph.node_bound() + } } impl, DW, SW, BW, CW, Cel, PI, DI, SI, BI> diff --git a/tests/common/mod.rs b/tests/common/mod.rs index b3b1deb..18036b8 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -4,9 +4,9 @@ use std::{fs::File, io::BufReader}; -use petgraph::{unionfind::UnionFind, visit::NodeIndexable}; use topola::{ autorouter::{ + conncomps::Conncomps, history::{History, HistoryError}, invoker::{Invoker, InvokerError}, Autorouter, @@ -160,7 +160,7 @@ pub fn assert_single_layer_groundless_autoroute( autorouter: &mut Autorouter, layername: &str, ) { - let unionfind = unionfind(autorouter); + let conncomps = Conncomps::new(autorouter.board().layout()); for ratline in autorouter.ratsnest().graph().edge_indices() { let (origin_dot, destination_dot) = ratline.ref_(autorouter).endpoint_dots(); @@ -217,8 +217,8 @@ pub fn assert_single_layer_groundless_autoroute( if let Some(netname) = autorouter.board().layout().rules().net_netname(net) { // We don't route ground. - let org = unionfind.find(origin_dot.index()); - let desc = unionfind.find(destination_dot.index()); + let org = conncomps.unionfind().find(origin_dot.index()); + let desc = conncomps.unionfind().find(destination_dot.index()); if netname != "GND" { assert_eq!(org, desc); @@ -256,35 +256,3 @@ pub fn assert_band_length( rel_err ); } - -fn unionfind(autorouter: &mut Autorouter) -> UnionFind { - for ratline in autorouter.ratsnest().graph().edge_indices() { - // Accessing endpoints may create new dots because apex construction is lazy, so we access - // tem all before starting unionfind, as it requires a constant index bound. - let _ = ratline.ref_(autorouter).endpoint_dots(); - } - - let mut unionfind = UnionFind::new( - autorouter - .board() - .layout() - .drawing() - .geometry() - .graph() - .node_bound(), - ); - - for primitive in autorouter.board().layout().drawing().primitive_nodes() { - for joined in autorouter - .board() - .layout() - .drawing() - .geometry() - .joineds(primitive) - { - unionfind.union(primitive.index(), joined.index()); - } - } - - unionfind -}