mirror of https://codeberg.org/topola/topola.git
refactor(autorouter/ratsnest): Move unionfind to new file, don't use `.graph()` there
This commit is contained in:
parent
e0cfc521ef
commit
71fdec2f06
|
|
@ -21,6 +21,7 @@ allowed_scopes = [
|
||||||
"autorouter/autoroute",
|
"autorouter/autoroute",
|
||||||
"autorouter/autorouter",
|
"autorouter/autorouter",
|
||||||
"autorouter/compare_detours",
|
"autorouter/compare_detours",
|
||||||
|
"autorouter/conncomps",
|
||||||
"autorouter/execution",
|
"autorouter/execution",
|
||||||
"autorouter/history",
|
"autorouter/history",
|
||||||
"autorouter/invoker",
|
"autorouter/invoker",
|
||||||
|
|
|
||||||
|
|
@ -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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
pub mod autoroute;
|
pub mod autoroute;
|
||||||
mod autorouter;
|
mod autorouter;
|
||||||
pub mod compare_detours;
|
pub mod compare_detours;
|
||||||
|
pub mod conncomps;
|
||||||
pub mod execution;
|
pub mod execution;
|
||||||
pub mod history;
|
pub mod history;
|
||||||
pub mod invoker;
|
pub mod invoker;
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,11 @@ use std::collections::BTreeMap;
|
||||||
|
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use geo::Point;
|
use geo::Point;
|
||||||
use petgraph::{
|
use petgraph::{data::Element, prelude::StableUnGraph, visit::NodeIndexable};
|
||||||
data::Element,
|
|
||||||
prelude::StableUnGraph,
|
|
||||||
unionfind::UnionFind,
|
|
||||||
visit::{EdgeRef, IntoEdgeReferences, NodeIndexable},
|
|
||||||
};
|
|
||||||
use spade::{HasPosition, InsertionError, Point2};
|
use spade::{HasPosition, InsertionError, Point2};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
autorouter::conncomps::Conncomps,
|
||||||
drawing::{
|
drawing::{
|
||||||
band::BandTermsegIndex,
|
band::BandTermsegIndex,
|
||||||
dot::FixedDotIndex,
|
dot::FixedDotIndex,
|
||||||
|
|
@ -74,11 +70,7 @@ pub struct Ratsnest {
|
||||||
|
|
||||||
impl Ratsnest {
|
impl Ratsnest {
|
||||||
pub fn new(layout: &Layout<impl AccessRules>) -> Result<Self, InsertionError> {
|
pub fn new(layout: &Layout<impl AccessRules>) -> Result<Self, InsertionError> {
|
||||||
let mut unionfind = UnionFind::new(layout.drawing().geometry().graph().node_bound());
|
let conncomps = Conncomps::new(layout);
|
||||||
|
|
||||||
for edge in layout.drawing().geometry().graph().edge_references() {
|
|
||||||
unionfind.union(edge.source().index(), edge.target().index());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
graph: StableUnGraph::default(),
|
graph: StableUnGraph::default(),
|
||||||
|
|
@ -145,7 +137,7 @@ impl Ratsnest {
|
||||||
if let Some((source, target)) = g.edge_endpoints(i) {
|
if let Some((source, target)) = g.edge_endpoints(i) {
|
||||||
let source_index = g.node_weight(source).unwrap().node_index().index();
|
let source_index = g.node_weight(source).unwrap().node_index().index();
|
||||||
let target_index = g.node_weight(target).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 {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use enum_dispatch::enum_dispatch;
|
||||||
use geo::Point;
|
use geo::Point;
|
||||||
use petgraph::{
|
use petgraph::{
|
||||||
stable_graph::StableDiGraph,
|
stable_graph::StableDiGraph,
|
||||||
visit::{EdgeRef, Walker},
|
visit::{EdgeRef, NodeIndexable, Walker},
|
||||||
Direction::{Incoming, Outgoing},
|
Direction::{Incoming, Outgoing},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -518,6 +518,18 @@ impl<
|
||||||
pub fn bend_joints(&self, bend: BI) -> (DI, DI) {
|
pub fn bend_joints(&self, bend: BI) -> (DI, DI) {
|
||||||
self.joints(bend.into())
|
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>
|
impl<PW: Copy + Retag<Index = PI>, DW, SW, BW, CW, Cel, PI, DI, SI, BI>
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
use std::{fs::File, io::BufReader};
|
use std::{fs::File, io::BufReader};
|
||||||
|
|
||||||
use petgraph::{unionfind::UnionFind, visit::NodeIndexable};
|
|
||||||
use topola::{
|
use topola::{
|
||||||
autorouter::{
|
autorouter::{
|
||||||
|
conncomps::Conncomps,
|
||||||
history::{History, HistoryError},
|
history::{History, HistoryError},
|
||||||
invoker::{Invoker, InvokerError},
|
invoker::{Invoker, InvokerError},
|
||||||
Autorouter,
|
Autorouter,
|
||||||
|
|
@ -160,7 +160,7 @@ pub fn assert_single_layer_groundless_autoroute(
|
||||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
layername: &str,
|
layername: &str,
|
||||||
) {
|
) {
|
||||||
let unionfind = unionfind(autorouter);
|
let conncomps = Conncomps::new(autorouter.board().layout());
|
||||||
|
|
||||||
for ratline in autorouter.ratsnest().graph().edge_indices() {
|
for ratline in autorouter.ratsnest().graph().edge_indices() {
|
||||||
let (origin_dot, destination_dot) = ratline.ref_(autorouter).endpoint_dots();
|
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) {
|
if let Some(netname) = autorouter.board().layout().rules().net_netname(net) {
|
||||||
// We don't route ground.
|
// We don't route ground.
|
||||||
let org = unionfind.find(origin_dot.index());
|
let org = conncomps.unionfind().find(origin_dot.index());
|
||||||
let desc = unionfind.find(destination_dot.index());
|
let desc = conncomps.unionfind().find(destination_dot.index());
|
||||||
|
|
||||||
if netname != "GND" {
|
if netname != "GND" {
|
||||||
assert_eq!(org, desc);
|
assert_eq!(org, desc);
|
||||||
|
|
@ -256,35 +256,3 @@ pub fn assert_band_length(
|
||||||
rel_err
|
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
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue