From 1b485e81a64cccfa99958a7135a4848ebcddeee4 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Tue, 9 Sep 2025 15:50:44 +0200 Subject: [PATCH] feat(autorouter/permuter): Implement permutation by ratline cut Not yet used, and can get stuck in an infinite loop, but the cut seems to work. --- .../src/navmesh/ordered_pair.rs | 2 +- src/autorouter/autoroute.rs | 3 + src/autorouter/autorouter.rs | 8 +- src/autorouter/permutator.rs | 16 ++- src/autorouter/permuter.rs | 105 +++++++++++++++--- src/autorouter/presorter.rs | 11 +- src/autorouter/ratline.rs | 10 ++ src/autorouter/ratsnest.rs | 23 ++-- 8 files changed, 134 insertions(+), 44 deletions(-) diff --git a/crates/planar-incr-embed/src/navmesh/ordered_pair.rs b/crates/planar-incr-embed/src/navmesh/ordered_pair.rs index df4300a..41e3a24 100644 --- a/crates/planar-incr-embed/src/navmesh/ordered_pair.rs +++ b/crates/planar-incr-embed/src/navmesh/ordered_pair.rs @@ -9,7 +9,7 @@ feature = "serde", serde(bound(deserialize = "T: serde::Deserialize<'de> + Ord")) )] -pub struct OrderedPair(T, T); +pub struct OrderedPair(pub T, pub T); impl core::ops::Index for OrderedPair { type Output = T; diff --git a/src/autorouter/autoroute.rs b/src/autorouter/autoroute.rs index a210125..220ee50 100644 --- a/src/autorouter/autoroute.rs +++ b/src/autorouter/autoroute.rs @@ -7,6 +7,8 @@ use std::ops::ControlFlow; +use derive_getters::Getters; + use crate::{ board::{ edit::{BoardDataEdit, BoardEdit}, @@ -38,6 +40,7 @@ pub enum AutorouteContinueStatus { } /// Manages the autorouting process across multiple ratlines. +#[derive(Getters)] pub struct AutorouteExecutionStepper { /// The ratlines which we are routing. ratlines: Vec, diff --git a/src/autorouter/autorouter.rs b/src/autorouter/autorouter.rs index 2a95a5d..6c3070e 100644 --- a/src/autorouter/autorouter.rs +++ b/src/autorouter/autorouter.rs @@ -130,13 +130,7 @@ impl Autorouter { ratlines: Vec, ) -> Result<(), AutorouterError> { for ratline in ratlines.iter() { - let band = self - .ratsnest - .graph() - .edge_weight(*ratline) - .unwrap() - .band_termseg - .unwrap(); + let band = ratline.ref_(self).band_termseg(); self.board .layout_mut() .remove_band(&mut LayoutEdit::new(), band) diff --git a/src/autorouter/permutator.rs b/src/autorouter/permutator.rs index 0e25242..d45ece4 100644 --- a/src/autorouter/permutator.rs +++ b/src/autorouter/permutator.rs @@ -10,7 +10,8 @@ use crate::{ autorouter::{ autoroute::{AutorouteContinueStatus, AutorouteExecutionStepper}, invoker::GetDebugOverlayData, - permuter::{PermuteRatlines, RatlinesPermuter, SccPermutationsRatlinePermuter}, + permuter::{PermuteRatlines, RatlinesPermuter}, + presorter::{PresortRatlines, SccIntersectionsAndLengthPresorter}, ratline::RatlineIndex, Autorouter, AutorouterError, AutorouterOptions, }, @@ -33,10 +34,12 @@ impl AutorouteExecutionPermutator { ratlines: Vec, options: AutorouterOptions, ) -> Result { - let mut permuter = RatlinesPermuter::SccPermutations(SccPermutationsRatlinePermuter::new( - autorouter, ratlines, &options, - )); - let initially_sorted_ratlines = permuter.next_ratlines_permutation(autorouter).unwrap(); + let presorter = SccIntersectionsAndLengthPresorter::new(autorouter, &ratlines); + let initially_sorted_ratlines = presorter.presort_ratlines(autorouter, &ratlines); + /*let permuter = RatlinesPermuter::SccPermutations(SccPermutationsRatlinePermuter::new( + autorouter, ratlines, presorter, &options, + ));*/ + let permuter = RatlinesPermuter::new(autorouter, ratlines, presorter, &options); Ok(Self { stepper: AutorouteExecutionStepper::new( @@ -68,7 +71,8 @@ impl Step, Option, AutorouteContinue } loop { - let Some(permutation) = self.permuter.next_ratlines_permutation(autorouter) + let Some(permutation) = + self.permuter.permute_ratlines(autorouter, &self.stepper) else { return Ok(ControlFlow::Break(None)); }; diff --git a/src/autorouter/permuter.rs b/src/autorouter/permuter.rs index 23d1a2f..c94e08d 100644 --- a/src/autorouter/permuter.rs +++ b/src/autorouter/permuter.rs @@ -2,26 +2,35 @@ // // SPDX-License-Identifier: MIT +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::{ - presorter::SccIntersectionsAndLengthPresorter, ratline::RatlineIndex, Autorouter, - AutorouterOptions, +use crate::{ + autorouter::{ + autoroute::AutorouteExecutionStepper, presorter::SccIntersectionsAndLengthPresorter, + ratline::RatlineIndex, Autorouter, AutorouterOptions, + }, + drawing::graph::MakePrimitive, + geometry::{GenericNode, GetLayer}, + graph::MakeRef, }; #[enum_dispatch] pub trait PermuteRatlines { - fn next_ratlines_permutation( + fn permute_ratlines( &mut self, autorouter: &mut Autorouter, + stepper: &AutorouteExecutionStepper, ) -> Option>; } #[enum_dispatch(PermuteRatlines)] pub enum RatlinesPermuter { + RatlineCuts(RatlineCutsRatlinePermuter), SccPermutations(SccPermutationsRatlinePermuter), } @@ -29,48 +38,53 @@ impl RatlinesPermuter { pub fn new( autorouter: &mut Autorouter, ratlines: Vec, + presorter: SccIntersectionsAndLengthPresorter, options: &AutorouterOptions, ) -> Self { RatlinesPermuter::SccPermutations(SccPermutationsRatlinePermuter::new( - autorouter, ratlines, options, + autorouter, ratlines, presorter, options, )) + /*RatlinesPermuter::RatlineCuts(RatlineCutsRatlinePermuter::new( + autorouter, ratlines, presorter, options, + ))*/ } } pub struct SccPermutationsRatlinePermuter { - sccs_permutations_iter: Permutations>>>, - ratlines: Vec, + sccs_permutations_iter: Skip>>>>, + original_ratlines: Vec, } impl SccPermutationsRatlinePermuter { pub fn new( - autorouter: &mut Autorouter, + _autorouter: &mut Autorouter, ratlines: Vec, + presorter: SccIntersectionsAndLengthPresorter, _options: &AutorouterOptions, ) -> Self { // TODO: Instead of instantiating presorter again here, get it from // an argument. - let presorter = SccIntersectionsAndLengthPresorter::new(autorouter, &ratlines); let sccs = presorter.dissolve(); let sccs_len = sccs.len(); Self { - sccs_permutations_iter: sccs.into_iter().permutations(sccs_len), - ratlines, + sccs_permutations_iter: sccs.into_iter().permutations(sccs_len).skip(1), + original_ratlines: ratlines, } } } impl PermuteRatlines for SccPermutationsRatlinePermuter { - fn next_ratlines_permutation( + fn permute_ratlines( &mut self, autorouter: &mut Autorouter, + _stepper: &AutorouteExecutionStepper, ) -> Option> { let scc_permutation = self.sccs_permutations_iter.next()?; let mut ratlines = vec![]; for scc in scc_permutation { - for ratline in self.ratlines.iter() { + for ratline in self.original_ratlines.iter() { if scc.contains( &autorouter .ratsnest() @@ -94,3 +108,68 @@ impl PermuteRatlines for SccPermutationsRatlinePermuter { Some(ratlines) } } + +pub struct RatlineCutsRatlinePermuter { + //sccs: Vec>>, +} + +impl RatlineCutsRatlinePermuter { + pub fn new( + _autorouter: &mut Autorouter, + _ratlines: Vec, + _presorter: SccIntersectionsAndLengthPresorter, + _options: &AutorouterOptions, + ) -> Self { + /*Self { + sccs: presorter.dissolve(), + }*/ + Self {} + } +} + +impl PermuteRatlines for RatlineCutsRatlinePermuter { + fn permute_ratlines( + &mut self, + autorouter: &mut Autorouter, + stepper: &AutorouteExecutionStepper, + ) -> Option> { + let curr_ratline = stepper.ratlines()[*stepper.curr_ratline_index()]; + let endpoint_dots = curr_ratline.ref_(autorouter).endpoint_dots(); + let bands_cut_by_ratline: Vec<_> = autorouter + .board() + .layout() + .bands_between_nodes( + endpoint_dots + .0 + .primitive(autorouter.board().layout().drawing()) + .layer(), + GenericNode::Primitive(endpoint_dots.0.into()), + GenericNode::Primitive(endpoint_dots.1.into()), + ) + .collect(); + + // Find the first ratline corresponding to a band that is cut. + let first_cut_ratline_index = stepper + .ratlines() + .iter() + .position(|ratline| { + for (band_uid, _) in &bands_cut_by_ratline { + if ratline.ref_(autorouter).band_termseg() == band_uid.0 + || ratline.ref_(autorouter).band_termseg() == band_uid.1 + { + return true; + } + } + + false + }) + .unwrap(); + + // Swap the first ratline corresponding to a band that is cut with the + // ratline that we have failed routing. + let mut ratlines = stepper.ratlines().clone(); + ratlines.swap(*stepper.curr_ratline_index(), first_cut_ratline_index); + + Some(ratlines) + } +} diff --git a/src/autorouter/presorter.rs b/src/autorouter/presorter.rs index 776f9b3..0f1e817 100644 --- a/src/autorouter/presorter.rs +++ b/src/autorouter/presorter.rs @@ -18,9 +18,9 @@ use crate::{ #[enum_dispatch] pub trait PresortRatlines { fn presort_ratlines( - &mut self, + &self, autorouter: &mut Autorouter, - ratlines: Vec, + ratlines: &[RatlineIndex], ) -> Vec; } @@ -37,14 +37,13 @@ pub struct SccIntersectionsAndLengthPresorter { impl SccIntersectionsAndLengthPresorter { pub fn new( autorouter: &mut Autorouter, - ratlines: &Vec, + ratlines: &[RatlineIndex], ) -> Self { // FIXME: Unnecessary copy. 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 sccs_len = sccs.len(); sccs.sort_unstable_by(|a, b| { // FIXME: These calculations should probably be stored somewhere @@ -149,9 +148,9 @@ impl SccIntersectionsAndLengthPresorter { impl PresortRatlines for SccIntersectionsAndLengthPresorter { fn presort_ratlines( - &mut self, + &self, autorouter: &mut Autorouter, - ratlines: Vec, + ratlines: &[RatlineIndex], ) -> Vec { let mut presorted_ratlines = vec![]; diff --git a/src/autorouter/ratline.rs b/src/autorouter/ratline.rs index 8f080ea..3efbda9 100644 --- a/src/autorouter/ratline.rs +++ b/src/autorouter/ratline.rs @@ -39,6 +39,16 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { Self { index, autorouter } } + pub fn band_termseg(&self) -> BandTermsegIndex { + self.autorouter + .ratsnest() + .graph() + .edge_weight(self.index) + .unwrap() + .band_termseg + .unwrap() + } + pub fn endpoint_dots(&self) -> (FixedDotIndex, FixedDotIndex) { let (source, target) = self .autorouter diff --git a/src/autorouter/ratsnest.rs b/src/autorouter/ratsnest.rs index e1763d0..ac3889e 100644 --- a/src/autorouter/ratsnest.rs +++ b/src/autorouter/ratsnest.rs @@ -89,22 +89,23 @@ impl Ratsnest { let node_bound = layout.drawing().geometry().graph().node_bound(); for layer in 0..layout.drawing().layer_count() { - let mut handle_rvw = |maybe_net: Option, vertex: RatvertexIndex, pos: Point| { - if let Some(net) = maybe_net { - triangulations - .entry((layer, net)) - .or_insert_with(|| Triangulation::new(node_bound)) - .add_vertex(RatvertexWeight { vertex, pos })?; - } - Ok(()) - }; + let mut handle_ratvertex_weight = + |maybe_net: Option, vertex: RatvertexIndex, pos: Point| { + if let Some(net) = maybe_net { + triangulations + .entry((layer, net)) + .or_insert_with(|| Triangulation::new(node_bound)) + .add_vertex(RatvertexWeight { vertex, pos })?; + } + Ok(()) + }; for node in layout.drawing().layer_primitive_nodes(layer) { if let PrimitiveIndex::FixedDot(dot) = node { // Dots that are parts of polys are ignored because ratlines // should only go to their centerpoints. if layout.drawing().compounds(dot).next().is_none() { - handle_rvw( + handle_ratvertex_weight( layout.drawing().primitive(dot).maybe_net(), RatvertexIndex::FixedDot(dot), node.primitive(layout.drawing()).shape().center(), @@ -114,7 +115,7 @@ impl Ratsnest { } for poly in layout.layer_poly_nodes(layer) { - handle_rvw( + handle_ratvertex_weight( layout.drawing().compound_weight(poly.into()).maybe_net(), RatvertexIndex::Poly(poly), poly.ref_(layout).shape().center(),