mirror of https://codeberg.org/topola/topola.git
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.
This commit is contained in:
parent
fe7c258851
commit
1b485e81a6
|
|
@ -9,7 +9,7 @@
|
||||||
feature = "serde",
|
feature = "serde",
|
||||||
serde(bound(deserialize = "T: serde::Deserialize<'de> + Ord"))
|
serde(bound(deserialize = "T: serde::Deserialize<'de> + Ord"))
|
||||||
)]
|
)]
|
||||||
pub struct OrderedPair<T>(T, T);
|
pub struct OrderedPair<T>(pub T, pub T);
|
||||||
|
|
||||||
impl<T> core::ops::Index<bool> for OrderedPair<T> {
|
impl<T> core::ops::Index<bool> for OrderedPair<T> {
|
||||||
type Output = T;
|
type Output = T;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use derive_getters::Getters;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
board::{
|
board::{
|
||||||
edit::{BoardDataEdit, BoardEdit},
|
edit::{BoardDataEdit, BoardEdit},
|
||||||
|
|
@ -38,6 +40,7 @@ pub enum AutorouteContinueStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Manages the autorouting process across multiple ratlines.
|
/// Manages the autorouting process across multiple ratlines.
|
||||||
|
#[derive(Getters)]
|
||||||
pub struct AutorouteExecutionStepper {
|
pub struct AutorouteExecutionStepper {
|
||||||
/// The ratlines which we are routing.
|
/// The ratlines which we are routing.
|
||||||
ratlines: Vec<RatlineIndex>,
|
ratlines: Vec<RatlineIndex>,
|
||||||
|
|
|
||||||
|
|
@ -130,13 +130,7 @@ impl<M: AccessMesadata> Autorouter<M> {
|
||||||
ratlines: Vec<RatlineIndex>,
|
ratlines: Vec<RatlineIndex>,
|
||||||
) -> Result<(), AutorouterError> {
|
) -> Result<(), AutorouterError> {
|
||||||
for ratline in ratlines.iter() {
|
for ratline in ratlines.iter() {
|
||||||
let band = self
|
let band = ratline.ref_(self).band_termseg();
|
||||||
.ratsnest
|
|
||||||
.graph()
|
|
||||||
.edge_weight(*ratline)
|
|
||||||
.unwrap()
|
|
||||||
.band_termseg
|
|
||||||
.unwrap();
|
|
||||||
self.board
|
self.board
|
||||||
.layout_mut()
|
.layout_mut()
|
||||||
.remove_band(&mut LayoutEdit::new(), band)
|
.remove_band(&mut LayoutEdit::new(), band)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ use crate::{
|
||||||
autorouter::{
|
autorouter::{
|
||||||
autoroute::{AutorouteContinueStatus, AutorouteExecutionStepper},
|
autoroute::{AutorouteContinueStatus, AutorouteExecutionStepper},
|
||||||
invoker::GetDebugOverlayData,
|
invoker::GetDebugOverlayData,
|
||||||
permuter::{PermuteRatlines, RatlinesPermuter, SccPermutationsRatlinePermuter},
|
permuter::{PermuteRatlines, RatlinesPermuter},
|
||||||
|
presorter::{PresortRatlines, SccIntersectionsAndLengthPresorter},
|
||||||
ratline::RatlineIndex,
|
ratline::RatlineIndex,
|
||||||
Autorouter, AutorouterError, AutorouterOptions,
|
Autorouter, AutorouterError, AutorouterOptions,
|
||||||
},
|
},
|
||||||
|
|
@ -33,10 +34,12 @@ impl AutorouteExecutionPermutator {
|
||||||
ratlines: Vec<RatlineIndex>,
|
ratlines: Vec<RatlineIndex>,
|
||||||
options: AutorouterOptions,
|
options: AutorouterOptions,
|
||||||
) -> Result<Self, AutorouterError> {
|
) -> Result<Self, AutorouterError> {
|
||||||
let mut permuter = RatlinesPermuter::SccPermutations(SccPermutationsRatlinePermuter::new(
|
let presorter = SccIntersectionsAndLengthPresorter::new(autorouter, &ratlines);
|
||||||
autorouter, ratlines, &options,
|
let initially_sorted_ratlines = presorter.presort_ratlines(autorouter, &ratlines);
|
||||||
));
|
/*let permuter = RatlinesPermuter::SccPermutations(SccPermutationsRatlinePermuter::new(
|
||||||
let initially_sorted_ratlines = permuter.next_ratlines_permutation(autorouter).unwrap();
|
autorouter, ratlines, presorter, &options,
|
||||||
|
));*/
|
||||||
|
let permuter = RatlinesPermuter::new(autorouter, ratlines, presorter, &options);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
stepper: AutorouteExecutionStepper::new(
|
stepper: AutorouteExecutionStepper::new(
|
||||||
|
|
@ -68,7 +71,8 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, AutorouteContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let Some(permutation) = self.permuter.next_ratlines_permutation(autorouter)
|
let Some(permutation) =
|
||||||
|
self.permuter.permute_ratlines(autorouter, &self.stepper)
|
||||||
else {
|
else {
|
||||||
return Ok(ControlFlow::Break(None));
|
return Ok(ControlFlow::Break(None));
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,35 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
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 petgraph::graph::NodeIndex;
|
||||||
use specctra_core::mesadata::AccessMesadata;
|
use specctra_core::mesadata::AccessMesadata;
|
||||||
|
|
||||||
use crate::autorouter::{
|
use crate::{
|
||||||
presorter::SccIntersectionsAndLengthPresorter, ratline::RatlineIndex, Autorouter,
|
autorouter::{
|
||||||
AutorouterOptions,
|
autoroute::AutorouteExecutionStepper, presorter::SccIntersectionsAndLengthPresorter,
|
||||||
|
ratline::RatlineIndex, Autorouter, AutorouterOptions,
|
||||||
|
},
|
||||||
|
drawing::graph::MakePrimitive,
|
||||||
|
geometry::{GenericNode, GetLayer},
|
||||||
|
graph::MakeRef,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub trait PermuteRatlines {
|
pub trait PermuteRatlines {
|
||||||
fn next_ratlines_permutation(
|
fn permute_ratlines(
|
||||||
&mut self,
|
&mut self,
|
||||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
|
stepper: &AutorouteExecutionStepper,
|
||||||
) -> Option<Vec<RatlineIndex>>;
|
) -> Option<Vec<RatlineIndex>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[enum_dispatch(PermuteRatlines)]
|
#[enum_dispatch(PermuteRatlines)]
|
||||||
pub enum RatlinesPermuter {
|
pub enum RatlinesPermuter {
|
||||||
|
RatlineCuts(RatlineCutsRatlinePermuter),
|
||||||
SccPermutations(SccPermutationsRatlinePermuter),
|
SccPermutations(SccPermutationsRatlinePermuter),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,48 +38,53 @@ impl RatlinesPermuter {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
ratlines: Vec<RatlineIndex>,
|
ratlines: Vec<RatlineIndex>,
|
||||||
|
presorter: SccIntersectionsAndLengthPresorter,
|
||||||
options: &AutorouterOptions,
|
options: &AutorouterOptions,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
RatlinesPermuter::SccPermutations(SccPermutationsRatlinePermuter::new(
|
RatlinesPermuter::SccPermutations(SccPermutationsRatlinePermuter::new(
|
||||||
autorouter, ratlines, options,
|
autorouter, ratlines, presorter, options,
|
||||||
))
|
))
|
||||||
|
/*RatlinesPermuter::RatlineCuts(RatlineCutsRatlinePermuter::new(
|
||||||
|
autorouter, ratlines, presorter, options,
|
||||||
|
))*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SccPermutationsRatlinePermuter {
|
pub struct SccPermutationsRatlinePermuter {
|
||||||
sccs_permutations_iter: Permutations<std::vec::IntoIter<Vec<NodeIndex<usize>>>>,
|
sccs_permutations_iter: Skip<Permutations<std::vec::IntoIter<Vec<NodeIndex<usize>>>>>,
|
||||||
ratlines: Vec<RatlineIndex>,
|
original_ratlines: Vec<RatlineIndex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SccPermutationsRatlinePermuter {
|
impl SccPermutationsRatlinePermuter {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
_autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
ratlines: Vec<RatlineIndex>,
|
ratlines: Vec<RatlineIndex>,
|
||||||
|
presorter: SccIntersectionsAndLengthPresorter,
|
||||||
_options: &AutorouterOptions,
|
_options: &AutorouterOptions,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// TODO: Instead of instantiating presorter again here, get it from
|
// TODO: Instead of instantiating presorter again here, get it from
|
||||||
// an argument.
|
// an argument.
|
||||||
let presorter = SccIntersectionsAndLengthPresorter::new(autorouter, &ratlines);
|
|
||||||
let sccs = presorter.dissolve();
|
let sccs = presorter.dissolve();
|
||||||
let sccs_len = sccs.len();
|
let sccs_len = sccs.len();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
sccs_permutations_iter: sccs.into_iter().permutations(sccs_len),
|
sccs_permutations_iter: sccs.into_iter().permutations(sccs_len).skip(1),
|
||||||
ratlines,
|
original_ratlines: ratlines,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PermuteRatlines for SccPermutationsRatlinePermuter {
|
impl PermuteRatlines for SccPermutationsRatlinePermuter {
|
||||||
fn next_ratlines_permutation(
|
fn permute_ratlines(
|
||||||
&mut self,
|
&mut self,
|
||||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
|
_stepper: &AutorouteExecutionStepper,
|
||||||
) -> Option<Vec<RatlineIndex>> {
|
) -> Option<Vec<RatlineIndex>> {
|
||||||
let scc_permutation = self.sccs_permutations_iter.next()?;
|
let scc_permutation = self.sccs_permutations_iter.next()?;
|
||||||
let mut ratlines = vec![];
|
let mut ratlines = vec![];
|
||||||
|
|
||||||
for scc in scc_permutation {
|
for scc in scc_permutation {
|
||||||
for ratline in self.ratlines.iter() {
|
for ratline in self.original_ratlines.iter() {
|
||||||
if scc.contains(
|
if scc.contains(
|
||||||
&autorouter
|
&autorouter
|
||||||
.ratsnest()
|
.ratsnest()
|
||||||
|
|
@ -94,3 +108,68 @@ impl PermuteRatlines for SccPermutationsRatlinePermuter {
|
||||||
Some(ratlines)
|
Some(ratlines)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RatlineCutsRatlinePermuter {
|
||||||
|
//sccs: Vec<Vec<NodeIndex<usize>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RatlineCutsRatlinePermuter {
|
||||||
|
pub fn new(
|
||||||
|
_autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
|
_ratlines: Vec<RatlineIndex>,
|
||||||
|
_presorter: SccIntersectionsAndLengthPresorter,
|
||||||
|
_options: &AutorouterOptions,
|
||||||
|
) -> Self {
|
||||||
|
/*Self {
|
||||||
|
sccs: presorter.dissolve(),
|
||||||
|
}*/
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PermuteRatlines for RatlineCutsRatlinePermuter {
|
||||||
|
fn permute_ratlines(
|
||||||
|
&mut self,
|
||||||
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
|
stepper: &AutorouteExecutionStepper,
|
||||||
|
) -> Option<Vec<RatlineIndex>> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ use crate::{
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
pub trait PresortRatlines {
|
pub trait PresortRatlines {
|
||||||
fn presort_ratlines(
|
fn presort_ratlines(
|
||||||
&mut self,
|
&self,
|
||||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
ratlines: Vec<RatlineIndex>,
|
ratlines: &[RatlineIndex],
|
||||||
) -> Vec<RatlineIndex>;
|
) -> Vec<RatlineIndex>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,14 +37,13 @@ pub struct SccIntersectionsAndLengthPresorter {
|
||||||
impl SccIntersectionsAndLengthPresorter {
|
impl SccIntersectionsAndLengthPresorter {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
ratlines: &Vec<RatlineIndex>,
|
ratlines: &[RatlineIndex],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// FIXME: Unnecessary copy.
|
// FIXME: Unnecessary copy.
|
||||||
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 = tarjan_scc(&filtered_ratsnest);
|
||||||
let sccs_len = sccs.len();
|
|
||||||
|
|
||||||
sccs.sort_unstable_by(|a, b| {
|
sccs.sort_unstable_by(|a, b| {
|
||||||
// FIXME: These calculations should probably be stored somewhere
|
// FIXME: These calculations should probably be stored somewhere
|
||||||
|
|
@ -149,9 +148,9 @@ impl SccIntersectionsAndLengthPresorter {
|
||||||
|
|
||||||
impl PresortRatlines for SccIntersectionsAndLengthPresorter {
|
impl PresortRatlines for SccIntersectionsAndLengthPresorter {
|
||||||
fn presort_ratlines(
|
fn presort_ratlines(
|
||||||
&mut self,
|
&self,
|
||||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
ratlines: Vec<RatlineIndex>,
|
ratlines: &[RatlineIndex],
|
||||||
) -> Vec<RatlineIndex> {
|
) -> Vec<RatlineIndex> {
|
||||||
let mut presorted_ratlines = vec![];
|
let mut presorted_ratlines = vec![];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,16 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> {
|
||||||
Self { index, autorouter }
|
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) {
|
pub fn endpoint_dots(&self) -> (FixedDotIndex, FixedDotIndex) {
|
||||||
let (source, target) = self
|
let (source, target) = self
|
||||||
.autorouter
|
.autorouter
|
||||||
|
|
|
||||||
|
|
@ -89,22 +89,23 @@ impl Ratsnest {
|
||||||
let node_bound = layout.drawing().geometry().graph().node_bound();
|
let node_bound = layout.drawing().geometry().graph().node_bound();
|
||||||
|
|
||||||
for layer in 0..layout.drawing().layer_count() {
|
for layer in 0..layout.drawing().layer_count() {
|
||||||
let mut handle_rvw = |maybe_net: Option<usize>, vertex: RatvertexIndex, pos: Point| {
|
let mut handle_ratvertex_weight =
|
||||||
if let Some(net) = maybe_net {
|
|maybe_net: Option<usize>, vertex: RatvertexIndex, pos: Point| {
|
||||||
triangulations
|
if let Some(net) = maybe_net {
|
||||||
.entry((layer, net))
|
triangulations
|
||||||
.or_insert_with(|| Triangulation::new(node_bound))
|
.entry((layer, net))
|
||||||
.add_vertex(RatvertexWeight { vertex, pos })?;
|
.or_insert_with(|| Triangulation::new(node_bound))
|
||||||
}
|
.add_vertex(RatvertexWeight { vertex, pos })?;
|
||||||
Ok(())
|
}
|
||||||
};
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
for node in layout.drawing().layer_primitive_nodes(layer) {
|
for node in layout.drawing().layer_primitive_nodes(layer) {
|
||||||
if let PrimitiveIndex::FixedDot(dot) = node {
|
if let PrimitiveIndex::FixedDot(dot) = node {
|
||||||
// Dots that are parts of polys are ignored because ratlines
|
// Dots that are parts of polys are ignored because ratlines
|
||||||
// should only go to their centerpoints.
|
// should only go to their centerpoints.
|
||||||
if layout.drawing().compounds(dot).next().is_none() {
|
if layout.drawing().compounds(dot).next().is_none() {
|
||||||
handle_rvw(
|
handle_ratvertex_weight(
|
||||||
layout.drawing().primitive(dot).maybe_net(),
|
layout.drawing().primitive(dot).maybe_net(),
|
||||||
RatvertexIndex::FixedDot(dot),
|
RatvertexIndex::FixedDot(dot),
|
||||||
node.primitive(layout.drawing()).shape().center(),
|
node.primitive(layout.drawing()).shape().center(),
|
||||||
|
|
@ -114,7 +115,7 @@ impl Ratsnest {
|
||||||
}
|
}
|
||||||
|
|
||||||
for poly in layout.layer_poly_nodes(layer) {
|
for poly in layout.layer_poly_nodes(layer) {
|
||||||
handle_rvw(
|
handle_ratvertex_weight(
|
||||||
layout.drawing().compound_weight(poly.into()).maybe_net(),
|
layout.drawing().compound_weight(poly.into()).maybe_net(),
|
||||||
RatvertexIndex::Poly(poly),
|
RatvertexIndex::Poly(poly),
|
||||||
poly.ref_(layout).shape().center(),
|
poly.ref_(layout).shape().center(),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue