refactor(autorouter/ratsnest): Move unionfind to new file, don't use `.graph()` there

This commit is contained in:
Mikolaj Wielgus 2025-09-14 01:40:39 +02:00
parent e0cfc521ef
commit 71fdec2f06
6 changed files with 75 additions and 49 deletions

View File

@ -21,6 +21,7 @@ allowed_scopes = [
"autorouter/autoroute",
"autorouter/autorouter",
"autorouter/compare_detours",
"autorouter/conncomps",
"autorouter/execution",
"autorouter/history",
"autorouter/invoker",

View File

@ -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<usize>,
}
impl Conncomps {
pub fn new(layout: &Layout<impl AccessRules>) -> 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 }
}
}

View File

@ -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;

View File

@ -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<impl AccessRules>) -> Result<Self, InsertionError> {
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
}

View File

@ -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<PW: Copy + Retag<Index = PI>, DW, SW, BW, CW, Cel, PI, DI, SI, BI>

View File

@ -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<impl AccessMesadata>,
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<impl AccessMesadata>) -> UnionFind<usize> {
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
}