mirror of https://codeberg.org/topola/topola.git
fix(autorouter/planar_reconfigurer): Use heap-based best-first search for ratline permutations
This fixes an infinite loop bug.
This commit is contained in:
parent
6e948d3228
commit
2f4b016a8b
|
|
@ -14,6 +14,7 @@ pub mod multilayer_autoroute;
|
||||||
pub mod multilayer_preconfigurer;
|
pub mod multilayer_preconfigurer;
|
||||||
pub mod multilayer_reconfigurator;
|
pub mod multilayer_reconfigurator;
|
||||||
pub mod multilayer_reconfigurer;
|
pub mod multilayer_reconfigurer;
|
||||||
|
pub mod permsearch;
|
||||||
pub mod place_via;
|
pub mod place_via;
|
||||||
pub mod planar_autoroute;
|
pub mod planar_autoroute;
|
||||||
pub mod planar_preconfigurer;
|
pub mod planar_preconfigurer;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Topola contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use std::{cmp::Ordering, collections::BinaryHeap, iter::Skip, iter::Take};
|
||||||
|
|
||||||
|
use itertools::{Itertools, Permutations};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct PermsearchNode<T> {
|
||||||
|
curr_permutation: Vec<T>,
|
||||||
|
permutations: Skip<Permutations<Take<std::vec::IntoIter<T>>>>,
|
||||||
|
length: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Eq> PartialEq for PermsearchNode<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.curr_permutation == other.curr_permutation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Eq> Eq for PermsearchNode<T> {}
|
||||||
|
|
||||||
|
impl<T: Eq> Ord for PermsearchNode<T> {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.length.cmp(&other.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Eq> PartialOrd for PermsearchNode<T> {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
self.length.partial_cmp(&other.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> PermsearchNode<T> {
|
||||||
|
fn permute(mut self) -> Option<Self> {
|
||||||
|
for (i, element) in self.permutations.next()?.iter().enumerate() {
|
||||||
|
self.curr_permutation[i] = element.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(self, length: usize) -> Option<Self> {
|
||||||
|
if length == self.length {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Get rid of `self.curr_permutation` clone somehow?
|
||||||
|
|
||||||
|
Some(Self {
|
||||||
|
curr_permutation: self.curr_permutation.clone(),
|
||||||
|
permutations: self
|
||||||
|
.curr_permutation
|
||||||
|
.into_iter()
|
||||||
|
.take(length)
|
||||||
|
.permutations(length)
|
||||||
|
.skip(1),
|
||||||
|
length,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Permsearch<T> {
|
||||||
|
curr_node: PermsearchNode<T>,
|
||||||
|
frontier: BinaryHeap<PermsearchNode<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Eq + Clone> Permsearch<T> {
|
||||||
|
pub fn new(original: Vec<T>) -> Self {
|
||||||
|
let len = original.len();
|
||||||
|
|
||||||
|
// TODO: Get rid of `original` clone somehow?
|
||||||
|
|
||||||
|
Self {
|
||||||
|
curr_node: PermsearchNode {
|
||||||
|
curr_permutation: original.clone(),
|
||||||
|
permutations: original.into_iter().take(len).permutations(0).skip(0),
|
||||||
|
length: 0,
|
||||||
|
},
|
||||||
|
frontier: BinaryHeap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn step(&mut self, len: usize) -> Option<&[T]> {
|
||||||
|
// TODO: Get rid of `self.curr_node` clones somehow?
|
||||||
|
|
||||||
|
if let Some(resized_curr_node) = self.curr_node.clone().resize(len) {
|
||||||
|
if let Some(permuted_resized_curr_node) = resized_curr_node.permute() {
|
||||||
|
self.frontier.push(permuted_resized_curr_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(permuted_curr_node) = self.curr_node.clone().permute() {
|
||||||
|
self.frontier.push(permuted_curr_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.curr_node = self.frontier.pop()?;
|
||||||
|
Some(&self.curr_node.curr_permutation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn curr_permutation(&self) -> &[T] {
|
||||||
|
&self.curr_node.curr_permutation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ use itertools::{Itertools, Permutations};
|
||||||
use specctra_core::mesadata::AccessMesadata;
|
use specctra_core::mesadata::AccessMesadata;
|
||||||
|
|
||||||
use crate::autorouter::{
|
use crate::autorouter::{
|
||||||
|
permsearch::Permsearch,
|
||||||
planar_autoroute::{PlanarAutorouteConfiguration, PlanarAutorouteExecutionStepper},
|
planar_autoroute::{PlanarAutorouteConfiguration, PlanarAutorouteExecutionStepper},
|
||||||
planar_preconfigurer::SccIntersectionsAndLengthRatlinePlanarAutoroutePreconfigurer,
|
planar_preconfigurer::SccIntersectionsAndLengthRatlinePlanarAutoroutePreconfigurer,
|
||||||
scc::Scc,
|
scc::Scc,
|
||||||
|
|
@ -52,7 +53,7 @@ impl PlanarAutorouteReconfigurer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SccPermutationsPlanarAutorouteReconfigurer {
|
pub struct SccPermutationsPlanarAutorouteReconfigurer {
|
||||||
sccs_permutations_iter: Skip<Permutations<std::vec::IntoIter<Scc>>>,
|
sccs_permsearch: Permsearch<Scc>,
|
||||||
preconfiguration: PlanarAutorouteConfiguration,
|
preconfiguration: PlanarAutorouteConfiguration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,10 +67,9 @@ impl SccPermutationsPlanarAutorouteReconfigurer {
|
||||||
// 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 sccs = presorter.dissolve();
|
let sccs = presorter.dissolve();
|
||||||
let sccs_len = sccs.len();
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
sccs_permutations_iter: sccs.into_iter().permutations(sccs_len).skip(1),
|
sccs_permsearch: Permsearch::new(sccs),
|
||||||
preconfiguration,
|
preconfiguration,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -79,9 +79,19 @@ impl MakeNextPlanarAutorouteConfiguration for SccPermutationsPlanarAutorouteReco
|
||||||
fn next_configuration(
|
fn next_configuration(
|
||||||
&mut self,
|
&mut self,
|
||||||
autorouter: &Autorouter<impl AccessMesadata>,
|
autorouter: &Autorouter<impl AccessMesadata>,
|
||||||
_stepper: &PlanarAutorouteExecutionStepper,
|
stepper: &PlanarAutorouteExecutionStepper,
|
||||||
) -> Option<PlanarAutorouteConfiguration> {
|
) -> Option<PlanarAutorouteConfiguration> {
|
||||||
let scc_permutation = self.sccs_permutations_iter.next()?;
|
let scc_index = self
|
||||||
|
.sccs_permsearch
|
||||||
|
.curr_permutation()
|
||||||
|
.iter()
|
||||||
|
.position(|scc| {
|
||||||
|
scc.scc_ref(autorouter)
|
||||||
|
.contains(self.preconfiguration.ratlines[*stepper.curr_ratline_index()])
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let scc_permutation = self.sccs_permsearch.step(scc_index + 1)?;
|
||||||
let mut ratlines = vec![];
|
let mut ratlines = vec![];
|
||||||
|
|
||||||
for scc in scc_permutation {
|
for scc in scc_permutation {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,14 @@ pub struct Scc {
|
||||||
length: f64,
|
length: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Scc {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.node_indices == other.node_indices
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Scc {}
|
||||||
|
|
||||||
impl Scc {
|
impl Scc {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue