refactor(autorouter/autoroute): Move permutator to new file, `permutator.rs`

This commit is contained in:
Mikolaj Wielgus 2025-09-05 12:33:15 +02:00
parent e5e5f9513e
commit f99f31e356
8 changed files with 130 additions and 108 deletions

View File

@ -25,6 +25,7 @@ allowed_scopes = [
"autorouter/history", "autorouter/history",
"autorouter/invoker", "autorouter/invoker",
"autorouter/measure_length", "autorouter/measure_length",
"autorouter/permutator",
"autorouter/place_via", "autorouter/place_via",
"autorouter/pointroute", "autorouter/pointroute",
"autorouter/ratsnest", "autorouter/ratsnest",

View File

@ -5,8 +5,7 @@
//! Manages autorouting of ratlines in a layout, tracking status and processed //! Manages autorouting of ratlines in a layout, tracking status and processed
//! routing steps. //! routing steps.
use itertools::{Itertools, Permutations}; use std::ops::ControlFlow;
use std::{iter::Skip, ops::ControlFlow};
use crate::{ use crate::{
board::{ board::{
@ -20,7 +19,7 @@ use crate::{
router::{ router::{
navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper, RouteStepper, Router, navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper, RouteStepper, Router,
}, },
stepper::{Abort, EstimateProgress, Permute, Step}, stepper::{Abort, EstimateProgress, Permutate, Step},
}; };
use super::{ use super::{
@ -224,11 +223,11 @@ impl<M: AccessMesadata> Abort<Autorouter<M>> for AutorouteExecutionStepper {
} }
} }
impl<M: AccessMesadata> Permute<Autorouter<M>> for AutorouteExecutionStepper { impl<M: AccessMesadata> Permutate<Autorouter<M>> for AutorouteExecutionStepper {
type Index = RatlineIndex; type Index = RatlineIndex;
type Output = Result<(), AutorouterError>; type Output = Result<(), AutorouterError>;
fn permute( fn permutate(
&mut self, &mut self,
autorouter: &mut Autorouter<M>, autorouter: &mut Autorouter<M>,
permutation: Vec<RatlineIndex>, permutation: Vec<RatlineIndex>,
@ -277,99 +276,3 @@ impl GetDebugOverlayData for AutorouteExecutionStepper {
self.route.as_ref().map_or(&[], |route| route.obstacles()) self.route.as_ref().map_or(&[], |route| route.obstacles())
} }
} }
pub struct AutorouteExecutionPermutator {
stepper: AutorouteExecutionStepper,
permutations_iter: Skip<Permutations<std::vec::IntoIter<RatlineIndex>>>,
options: AutorouterOptions,
}
impl AutorouteExecutionPermutator {
pub fn new(
autorouter: &mut Autorouter<impl AccessMesadata>,
ratlines: Vec<RatlineIndex>,
options: AutorouterOptions,
) -> Result<Self, AutorouterError> {
let ratlines_len = ratlines.len();
Ok(Self {
stepper: AutorouteExecutionStepper::new(autorouter, ratlines.clone(), options)?,
// Note: I assume here that the first permutation is the same as the original order.
permutations_iter: ratlines.into_iter().permutations(ratlines_len).skip(1),
options,
})
}
}
impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, AutorouteContinueStatus>
for AutorouteExecutionPermutator
{
type Error = AutorouterError;
fn step(
&mut self,
autorouter: &mut Autorouter<M>,
) -> Result<ControlFlow<Option<BoardEdit>, AutorouteContinueStatus>, AutorouterError> {
match self.stepper.step(autorouter) {
Ok(ok) => Ok(ok),
Err(err) => {
if !self.options.permutate {
return Err(err);
}
loop {
let Some(permutation) = self.permutations_iter.next() else {
return Ok(ControlFlow::Break(None));
};
match self.stepper.permute(autorouter, permutation) {
Ok(()) => break,
Err(AutorouterError::NothingToUndoForPermutation) => continue,
Err(err) => return Err(err),
}
}
self.stepper.step(autorouter)
}
}
}
}
impl<M: AccessMesadata> Abort<Autorouter<M>> for AutorouteExecutionPermutator {
fn abort(&mut self, autorouter: &mut Autorouter<M>) {
self.permutations_iter.all(|_| true);
self.stepper.abort(autorouter);
}
}
impl EstimateProgress for AutorouteExecutionPermutator {
type Value = f64;
fn estimate_progress_value(&self) -> f64 {
// TODO.
self.stepper.estimate_progress_value()
}
fn estimate_progress_maximum(&self) -> f64 {
// TODO.
self.stepper.estimate_progress_maximum()
}
}
impl GetDebugOverlayData for AutorouteExecutionPermutator {
fn maybe_thetastar(&self) -> Option<&ThetastarStepper<Navmesh, f64>> {
self.stepper.maybe_thetastar()
}
fn maybe_navcord(&self) -> Option<&Navcord> {
self.stepper.maybe_navcord()
}
fn ghosts(&self) -> &[PrimitiveShape] {
self.stepper.ghosts()
}
fn obstacles(&self) -> &[PrimitiveIndex] {
self.stepper.obstacles()
}
}

View File

@ -11,6 +11,7 @@ use std::{cmp::Ordering, collections::BTreeSet};
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
autorouter::permutator::AutorouteExecutionPermutator,
board::{AccessMesadata, Board}, board::{AccessMesadata, Board},
drawing::{band::BandTermsegIndex, Infringement}, drawing::{band::BandTermsegIndex, Infringement},
geometry::shape::MeasureLength, geometry::shape::MeasureLength,
@ -22,7 +23,7 @@ use crate::{
}; };
use super::{ use super::{
autoroute::{AutorouteExecutionPermutator, AutorouteExecutionStepper}, autoroute::AutorouteExecutionStepper,
compare_detours::CompareDetoursExecutionStepper, compare_detours::CompareDetoursExecutionStepper,
measure_length::MeasureLengthExecutionStepper, measure_length::MeasureLengthExecutionStepper,
place_via::PlaceViaExecutionStepper, place_via::PlaceViaExecutionStepper,

View File

@ -8,6 +8,7 @@ use enum_dispatch::enum_dispatch;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
autorouter::permutator::AutorouteExecutionPermutator,
board::{edit::BoardEdit, AccessMesadata}, board::{edit::BoardEdit, AccessMesadata},
layout::via::ViaWeight, layout::via::ViaWeight,
router::ng, router::ng,
@ -15,7 +16,6 @@ use crate::{
}; };
use super::{ use super::{
autoroute::AutorouteExecutionPermutator,
compare_detours::CompareDetoursExecutionStepper, compare_detours::CompareDetoursExecutionStepper,
invoker::{GetDebugOverlayData, Invoker, InvokerError}, invoker::{GetDebugOverlayData, Invoker, InvokerError},
measure_length::MeasureLengthExecutionStepper, measure_length::MeasureLengthExecutionStepper,

View File

@ -28,11 +28,11 @@ use crate::{
}; };
use super::{ use super::{
autoroute::AutorouteExecutionPermutator,
compare_detours::CompareDetoursExecutionStepper, compare_detours::CompareDetoursExecutionStepper,
execution::{Command, ExecutionStepper}, execution::{Command, ExecutionStepper},
history::{History, HistoryError}, history::{History, HistoryError},
measure_length::MeasureLengthExecutionStepper, measure_length::MeasureLengthExecutionStepper,
permutator::AutorouteExecutionPermutator,
place_via::PlaceViaExecutionStepper, place_via::PlaceViaExecutionStepper,
remove_bands::RemoveBandsExecutionStepper, remove_bands::RemoveBandsExecutionStepper,
Autorouter, AutorouterError, Autorouter, AutorouterError,

View File

@ -2,8 +2,6 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
//! Manages autorouting process, under work for now
pub mod autoroute; pub mod autoroute;
mod autorouter; mod autorouter;
pub mod compare_detours; pub mod compare_detours;
@ -11,6 +9,7 @@ pub mod execution;
pub mod history; pub mod history;
pub mod invoker; pub mod invoker;
pub mod measure_length; pub mod measure_length;
pub mod permutator;
pub mod place_via; pub mod place_via;
pub mod pointroute; pub mod pointroute;
pub mod ratline; pub mod ratline;

View File

@ -0,0 +1,118 @@
// SPDX-FileCopyrightText: 2025 Topola contributors
//
// SPDX-License-Identifier: MIT
use std::{iter::Skip, ops::ControlFlow};
use itertools::{Itertools, Permutations};
use specctra_core::mesadata::AccessMesadata;
use crate::{
autorouter::{
autoroute::{AutorouteContinueStatus, AutorouteExecutionStepper},
invoker::GetDebugOverlayData,
ratline::RatlineIndex,
Autorouter, AutorouterError, AutorouterOptions,
},
board::edit::BoardEdit,
drawing::graph::PrimitiveIndex,
geometry::primitive::PrimitiveShape,
router::{navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper},
stepper::{Abort, EstimateProgress, Permutate, Step},
};
pub struct AutorouteExecutionPermutator {
stepper: AutorouteExecutionStepper,
permutations_iter: Skip<Permutations<std::vec::IntoIter<RatlineIndex>>>,
options: AutorouterOptions,
}
impl AutorouteExecutionPermutator {
pub fn new(
autorouter: &mut Autorouter<impl AccessMesadata>,
ratlines: Vec<RatlineIndex>,
options: AutorouterOptions,
) -> Result<Self, AutorouterError> {
let ratlines_len = ratlines.len();
Ok(Self {
stepper: AutorouteExecutionStepper::new(autorouter, ratlines.clone(), options)?,
// Note: I assume here that the first permutation is the same as the original order.
permutations_iter: ratlines.into_iter().permutations(ratlines_len).skip(1),
options,
})
}
}
impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, AutorouteContinueStatus>
for AutorouteExecutionPermutator
{
type Error = AutorouterError;
fn step(
&mut self,
autorouter: &mut Autorouter<M>,
) -> Result<ControlFlow<Option<BoardEdit>, AutorouteContinueStatus>, AutorouterError> {
match self.stepper.step(autorouter) {
Ok(ok) => Ok(ok),
Err(err) => {
if !self.options.permutate {
return Err(err);
}
loop {
let Some(permutation) = self.permutations_iter.next() else {
return Ok(ControlFlow::Break(None));
};
match self.stepper.permutate(autorouter, permutation) {
Ok(()) => break,
Err(AutorouterError::NothingToUndoForPermutation) => continue,
Err(err) => return Err(err),
}
}
self.stepper.step(autorouter)
}
}
}
}
impl<M: AccessMesadata> Abort<Autorouter<M>> for AutorouteExecutionPermutator {
fn abort(&mut self, autorouter: &mut Autorouter<M>) {
self.permutations_iter.all(|_| true);
self.stepper.abort(autorouter);
}
}
impl EstimateProgress for AutorouteExecutionPermutator {
type Value = f64;
fn estimate_progress_value(&self) -> f64 {
// TODO.
self.stepper.estimate_progress_value()
}
fn estimate_progress_maximum(&self) -> f64 {
// TODO.
self.stepper.estimate_progress_maximum()
}
}
impl GetDebugOverlayData for AutorouteExecutionPermutator {
fn maybe_thetastar(&self) -> Option<&ThetastarStepper<Navmesh, f64>> {
self.stepper.maybe_thetastar()
}
fn maybe_navcord(&self) -> Option<&Navcord> {
self.stepper.maybe_navcord()
}
fn ghosts(&self) -> &[PrimitiveShape] {
self.stepper.ghosts()
}
fn obstacles(&self) -> &[PrimitiveIndex] {
self.stepper.obstacles()
}
}

View File

@ -54,11 +54,11 @@ pub trait Abort<Ctx> {
} }
/// Some steppers may be permuted from their initial order. /// Some steppers may be permuted from their initial order.
pub trait Permute<Ctx> { pub trait Permutate<Ctx> {
type Index; type Index;
type Output; type Output;
fn permute(&mut self, context: &mut Ctx, ordering: Vec<Self::Index>) -> Self::Output; fn permutate(&mut self, context: &mut Ctx, ordering: Vec<Self::Index>) -> Self::Output;
} }
/// Steppers that can receive discrete events and act on them implement this /// Steppers that can receive discrete events and act on them implement this