Compare commits

...

2 Commits

Author SHA1 Message Date
Outbreak2096 3208d55272
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (72 of 72 strings)

Translation: Topola/Topola
Translate-URL: https://translate.codeberg.org/projects/topola/topola/zh_Hans/
2025-11-20 02:00:03 +00:00
Mikolaj Wielgus 64669d5d0b feat(autorouter/multilayer_reconfigurer): Use A* to search for multilayer configurations 2025-11-20 02:54:52 +01:00
6 changed files with 106 additions and 84 deletions

View File

@ -51,17 +51,17 @@ tr-menu-route-options-squeeze-through-under-bends = 弯曲处挤线
tr-menu-view-kdb-scroll-delta-factor = 键盘滚动增量因子
tr-menu-debug-show-pathfinding-scores = 显示路径查找分数
tr-menu-place-place-route-plan = 放置布线规划
tr-menu-route-topo-autoroute = 拓扑平面自动布线
tr-menu-route-topo-autoroute = 拓扑平面自动布线
tr-menu-debug-show-triangulation = 显示三角剖分
tr-menu-debug-show-triangulation-constraints = 显示三角剖分约束条件
tr-menu-route-options-presort-by = 预排序依据
tr-menu-route-options-presort-by-ratline-intersection-count-and-length = 交叉点数量及长度
tr-menu-route-options-presort-by-ratline-intersection-count-and-length = 交叉点数量及长度
tr-menu-route-options-permutate = 排列组合
tr-menu-debug-show-guide-circles = 显示辅助圆
tr-menu-debug-show-guide-bitangents = 显示双切线
tr-menu-debug-show-primitive-indices = 显示图元索引
tr-menu-debug-show-primitive-indices = 显示图元索引
tr-menu-route-planar-autoroute = 平面自动布线
tr-menu-route-fanout-clearance = 扇出间距
tr-menu-route-fanout-clearance = 扇出间距
tr-menu-debug = 调试
tr-menu-debug-fix-step-rate = 固定步进速率
tr-menu-debug-highlight-obstacles = 高亮障碍物

View File

@ -35,7 +35,7 @@ pub struct AnterouterOptions {
pub fanout_clearance: f64,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct AnterouterPlan {
pub layer_map: BTreeMap<RatlineUid, usize>,
pub static_terminating_dot_map: BTreeMap<(RatlineUid, FixedDotIndex, usize), FixedDotIndex>,

View File

@ -28,7 +28,7 @@ use crate::{
},
};
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct MultilayerAutorouteConfiguration {
pub plan: AnterouterPlan,
pub planar: PlanarAutoroutePreconfigurerInput,

View File

@ -2,16 +2,21 @@
//
// SPDX-License-Identifier: MIT
use std::collections::BTreeMap;
use std::{cmp::Ordering, collections::BTreeMap};
use derive_getters::Getters;
use enum_dispatch::enum_dispatch;
use specctra_core::mesadata::AccessMesadata;
use crate::autorouter::{
multilayer_autoroute::{MultilayerAutorouteConfiguration, MultilayerAutorouteOptions},
planar_autoroute::PlanarAutorouteConfigurationStatus,
planar_preconfigurer::PlanarAutoroutePreconfigurerInput,
Autorouter, AutorouterError,
use crate::{
astar::Astar,
autorouter::{
multilayer_autoroute::{MultilayerAutorouteConfiguration, MultilayerAutorouteOptions},
planar_autoroute::PlanarAutorouteConfigurationStatus,
planar_preconfigurer::PlanarAutoroutePreconfigurerInput,
ratline::RatlineUid,
Autorouter, AutorouterError,
},
};
#[enum_dispatch]
@ -33,10 +38,56 @@ pub enum MultilayerAutorouteReconfigurer {
UniformRandomLayers(IncrementFailedRatlineLayersMultilayerAutorouteReconfigurer),
}
#[derive(Clone, Debug, Getters)]
struct SearchNode {
configuration: MultilayerAutorouteConfiguration,
}
impl Ord for SearchNode {
fn cmp(&self, other: &Self) -> Ordering {
self.configuration.cmp(&other.configuration)
}
}
impl PartialOrd for SearchNode {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Eq for SearchNode {}
impl PartialEq for SearchNode {
fn eq(&self, other: &Self) -> bool {
self.configuration == other.configuration
}
}
impl SearchNode {
pub fn new(configuration: MultilayerAutorouteConfiguration) -> Self {
Self { configuration }
}
pub fn revise_ratline(self, ratline_uid: RatlineUid, layer_count: usize) -> Self {
let mut new_anterouter_plan = self.configuration.plan.clone();
*new_anterouter_plan.layer_map.get_mut(&ratline_uid).unwrap() += 1;
*new_anterouter_plan.layer_map.get_mut(&ratline_uid).unwrap() %= layer_count;
Self {
configuration: MultilayerAutorouteConfiguration {
plan: new_anterouter_plan,
planar: PlanarAutoroutePreconfigurerInput {
ratlines: self.configuration.planar.ratlines.clone(),
terminating_dot_map: BTreeMap::new(),
},
},
}
}
}
pub struct IncrementFailedRatlineLayersMultilayerAutorouteReconfigurer {
last_configuration: MultilayerAutorouteConfiguration,
maybe_last_planar_status: Option<PlanarAutorouteConfigurationStatus>,
maybe_best_planar_status: Option<PlanarAutorouteConfigurationStatus>,
configuration_search: Astar<SearchNode, f64>,
}
impl IncrementFailedRatlineLayersMultilayerAutorouteReconfigurer {
@ -46,9 +97,7 @@ impl IncrementFailedRatlineLayersMultilayerAutorouteReconfigurer {
_options: &MultilayerAutorouteOptions,
) -> Self {
Self {
last_configuration: preconfiguration,
maybe_last_planar_status: None,
maybe_best_planar_status: None,
configuration_search: Astar::new(SearchNode::new(preconfiguration)),
}
}
}
@ -58,57 +107,32 @@ impl MakeNextMultilayerAutorouteConfiguration
{
fn process_planar_result(
&mut self,
_autorouter: &Autorouter<impl AccessMesadata>,
autorouter: &Autorouter<impl AccessMesadata>,
planar_result: Result<PlanarAutorouteConfigurationStatus, AutorouterError>,
) {
let Ok(planar_status) = planar_result else {
return;
};
self.maybe_last_planar_status = Some(planar_status.clone());
if self
.maybe_best_planar_status
.as_ref()
.is_none_or(|status| status.costs.lengths.len() < planar_status.costs.lengths.len())
{
self.maybe_best_planar_status = Some(planar_status.clone());
}
self.configuration_search.push((
0.1,
(planar_status.configuration.ratlines.len() - planar_status.costs.lengths.len()) as f64,
self.configuration_search
.curr_node()
.clone()
.revise_ratline(
planar_status.configuration.ratlines[planar_status.costs.lengths.len()],
autorouter.board().layout().drawing().layer_count(),
),
));
}
fn next_configuration(
&mut self,
autorouter: &Autorouter<impl AccessMesadata>,
_autorouter: &Autorouter<impl AccessMesadata>,
) -> Option<MultilayerAutorouteConfiguration> {
let mut new_anterouter_plan = self.last_configuration.plan.clone();
let Some(ref last_planar_status) = self.maybe_last_planar_status else {
return None;
};
if let Some(ref best_planar_status) = self.maybe_best_planar_status {
for ratline_index in best_planar_status.costs.lengths.len()
..last_planar_status.configuration.ratlines.len()
{
*new_anterouter_plan
.layer_map
.get_mut(&last_planar_status.configuration.ratlines[ratline_index])
.unwrap() += 1;
*new_anterouter_plan
.layer_map
.get_mut(&last_planar_status.configuration.ratlines[ratline_index])
.unwrap() %= autorouter.board().layout().drawing().layer_count();
}
}
self.last_configuration = MultilayerAutorouteConfiguration {
plan: new_anterouter_plan,
planar: PlanarAutoroutePreconfigurerInput {
ratlines: self.last_configuration.planar.ratlines.clone(),
terminating_dot_map: BTreeMap::new(),
},
};
Some(self.last_configuration.clone())
self.configuration_search
.pop()
.map(|node| node.configuration().clone())
}
}

View File

@ -17,7 +17,7 @@ use crate::{
drawing::dot::FixedDotIndex,
};
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct PlanarAutoroutePreconfigurerInput {
pub ratlines: BTreeSet<RatlineUid>,
pub terminating_dot_map: BTreeMap<(RatlineUid, FixedDotIndex), FixedDotIndex>,

View File

@ -60,17 +60,17 @@ impl PlanarAutorouteReconfigurer {
#[derive(Clone, Debug, Getters)]
struct SccSearchNode {
curr_permutation: Vec<Scc>,
permutation: Vec<Scc>,
#[getter(skip)]
permutations: Skip<Permutations<Take<std::vec::IntoIter<Scc>>>>,
permutations_iter: Skip<Permutations<Take<std::vec::IntoIter<Scc>>>>,
#[getter(skip)]
length: usize,
}
impl Ord for SccSearchNode {
fn cmp(&self, other: &Self) -> Ordering {
self.curr_permutation
.cmp(&other.curr_permutation)
self.permutation
.cmp(&other.permutation)
.then(self.length.cmp(&other.length))
}
}
@ -85,7 +85,7 @@ impl Eq for SccSearchNode {}
impl PartialEq for SccSearchNode {
fn eq(&self, other: &Self) -> bool {
self.curr_permutation == other.curr_permutation && self.length == other.length
self.permutation == other.permutation && self.length == other.length
}
}
@ -94,8 +94,8 @@ impl SccSearchNode {
let len = sccs.len();
Self {
curr_permutation: sccs.clone(),
permutations: sccs.into_iter().take(len).permutations(0).skip(0),
permutation: sccs.clone(),
permutations_iter: sccs.into_iter().take(len).permutations(0).skip(0),
length: 0,
}
}
@ -107,7 +107,7 @@ impl SccSearchNode {
if let Some((permuted_resized, changed_count)) = resized.permute() {
expanded_nodes.push((
changed_count as f64 / 100.0,
(self.curr_permutation.len() - permuted_resized.length) as f64,
(self.permutation.len() - permuted_resized.length) as f64,
permuted_resized,
));
}
@ -116,7 +116,7 @@ impl SccSearchNode {
if let Some((permuted, changed_count)) = self.clone().permute() {
expanded_nodes.push((
changed_count as f64 / 100.0,
(self.curr_permutation.len() - permuted.length) as f64,
(self.permutation.len() - permuted.length) as f64,
permuted,
));
}
@ -130,9 +130,9 @@ impl SccSearchNode {
}
Some(Self {
curr_permutation: self.curr_permutation.clone(),
permutations: self
.curr_permutation
permutation: self.permutation.clone(),
permutations_iter: self
.permutation
.into_iter()
.take(length)
.permutations(length)
@ -144,11 +144,9 @@ impl SccSearchNode {
fn permute(mut self) -> Option<(Self, usize)> {
let mut changed_count = 0;
for (i, element) in self.permutations.next()?.iter().enumerate() {
if self.curr_permutation[i] != *element {
self.curr_permutation[i] = element.clone();
// FIXME: Uncommenting this breaks the 4x4_1206_led_matrix test.
for (i, element) in self.permutations_iter.next()?.iter().enumerate() {
if self.permutation[i] != *element {
self.permutation[i] = element.clone();
changed_count += 1;
}
}
@ -158,7 +156,7 @@ impl SccSearchNode {
}
pub struct SccPermutationsPlanarAutorouteReconfigurer {
sccs_search: Astar<SccSearchNode, f64>,
configuration_search: Astar<SccSearchNode, f64>,
preconfiguration: PlanarAutorouteConfiguration,
}
@ -174,7 +172,7 @@ impl SccPermutationsPlanarAutorouteReconfigurer {
let sccs = presorter.dissolve();
Self {
sccs_search: Astar::new(SccSearchNode::new(sccs)),
configuration_search: Astar::new(SccSearchNode::new(sccs)),
preconfiguration,
}
}
@ -187,9 +185,9 @@ impl MakeNextPlanarAutorouteConfiguration for SccPermutationsPlanarAutorouteReco
stepper: &PlanarAutorouteExecutionStepper,
) -> Option<PlanarAutorouteConfiguration> {
let scc_index = self
.sccs_search
.configuration_search
.curr_node()
.curr_permutation()
.permutation()
.iter()
.position(|scc| {
scc.scc_ref(autorouter)
@ -198,9 +196,9 @@ impl MakeNextPlanarAutorouteConfiguration for SccPermutationsPlanarAutorouteReco
.unwrap();
let next_search_node = self
.sccs_search
.expand(&self.sccs_search.curr_node().expand(scc_index + 1))?;
let next_permutation = next_search_node.curr_permutation();
.configuration_search
.expand(&self.configuration_search.curr_node().expand(scc_index + 1))?;
let next_permutation = next_search_node.permutation();
let mut ratlines = vec![];
for scc in next_permutation {