mirror of https://codeberg.org/topola/topola.git
feat(autorouter/permutator): Preorder and permutate over whole ratline conn. comps
This is not enough to autoroute 4x4_1206_led_matrix_breakout, but is as usual, is a step forward.
This commit is contained in:
parent
19c6ede09a
commit
4326925bbf
|
|
@ -91,7 +91,7 @@ impl AutorouteExecutionStepper {
|
|||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||
index: usize,
|
||||
) -> Result<(), AutorouterError> {
|
||||
if index > self.board_data_edits.len() {
|
||||
if index >= self.board_data_edits.len() {
|
||||
return Err(AutorouterError::NothingToUndoForPermutation);
|
||||
}
|
||||
|
||||
|
|
@ -232,11 +232,13 @@ impl<M: AccessMesadata> Permutate<Autorouter<M>> for AutorouteExecutionStepper {
|
|||
autorouter: &mut Autorouter<M>,
|
||||
permutation: Vec<RatlineIndex>,
|
||||
) -> Result<(), AutorouterError> {
|
||||
let new_index = permutation
|
||||
let Some(new_index) = permutation
|
||||
.iter()
|
||||
.zip(self.ratlines.iter())
|
||||
.position(|(permuted, original)| *permuted != *original)
|
||||
.unwrap();
|
||||
else {
|
||||
return Err(AutorouterError::NothingToUndoForPermutation);
|
||||
};
|
||||
self.ratlines = permutation;
|
||||
|
||||
self.backtrace_to_index(autorouter, new_index)?;
|
||||
|
|
|
|||
|
|
@ -7,18 +7,16 @@ use geo::Point;
|
|||
use petgraph::graph::NodeIndex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use spade::InsertionError;
|
||||
use std::{cmp::Ordering, collections::BTreeSet};
|
||||
use std::collections::BTreeSet;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
autorouter::permutator::AutorouteExecutionPermutator,
|
||||
board::{AccessMesadata, Board},
|
||||
drawing::{band::BandTermsegIndex, Infringement},
|
||||
geometry::shape::MeasureLength,
|
||||
graph::MakeRef,
|
||||
layout::{via::ViaWeight, LayoutEdit},
|
||||
router::{navmesh::NavmeshError, ng, thetastar::ThetastarError, RouterOptions},
|
||||
stepper::Step,
|
||||
triangulation::GetTrianvertexNodeIndex,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::{cmp::Ordering, iter::Skip, ops::ControlFlow};
|
||||
use std::{cmp::Ordering, ops::ControlFlow};
|
||||
|
||||
use itertools::{Itertools, Permutations};
|
||||
use petgraph::{algo::tarjan_scc, graph::NodeIndex};
|
||||
use specctra_core::mesadata::AccessMesadata;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -12,7 +13,7 @@ use crate::{
|
|||
autoroute::{AutorouteContinueStatus, AutorouteExecutionStepper},
|
||||
invoker::GetDebugOverlayData,
|
||||
ratline::RatlineIndex,
|
||||
Autorouter, AutorouterError, AutorouterOptions, PresortBy,
|
||||
Autorouter, AutorouterError, AutorouterOptions,
|
||||
},
|
||||
board::edit::BoardEdit,
|
||||
drawing::graph::PrimitiveIndex,
|
||||
|
|
@ -22,54 +23,183 @@ use crate::{
|
|||
stepper::{Abort, EstimateProgress, Permutate, Step},
|
||||
};
|
||||
|
||||
pub struct AutorouteExecutionPermutator {
|
||||
stepper: AutorouteExecutionStepper,
|
||||
permutations_iter: Skip<Permutations<std::vec::IntoIter<RatlineIndex>>>,
|
||||
options: AutorouterOptions,
|
||||
struct RatlineSccPermuter {
|
||||
sccs_permutations_iter: Permutations<std::vec::IntoIter<Vec<NodeIndex<usize>>>>,
|
||||
ratlines: Vec<RatlineIndex>,
|
||||
}
|
||||
|
||||
impl AutorouteExecutionPermutator {
|
||||
impl RatlineSccPermuter {
|
||||
pub fn new(
|
||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||
mut ratlines: Vec<RatlineIndex>,
|
||||
options: AutorouterOptions,
|
||||
) -> Result<Self, AutorouterError> {
|
||||
let ratlines_len = ratlines.len();
|
||||
ratlines: Vec<RatlineIndex>,
|
||||
_options: &AutorouterOptions,
|
||||
) -> Self {
|
||||
// FIXME: Unnecessary copy.
|
||||
let mut filtered_ratsnest = autorouter.ratsnest().graph().clone();
|
||||
filtered_ratsnest.retain_edges(|_g, i| ratlines.contains(&i));
|
||||
|
||||
match options.presort_by {
|
||||
PresortBy::RatlineIntersectionCountAndLength => ratlines.sort_unstable_by(|a, b| {
|
||||
let a_intersector_count = a.ref_(autorouter).interior_obstacle_ratlines().count();
|
||||
let b_intersector_count = b.ref_(autorouter).interior_obstacle_ratlines().count();
|
||||
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
|
||||
// instead of being done every time.
|
||||
|
||||
let mut a_intersector_count = 0;
|
||||
let mut b_intersector_count = 0;
|
||||
let mut a_length = 0.0;
|
||||
let mut b_length = 0.0;
|
||||
|
||||
// FIXME: It's inefficient to iterate over the ratlines on every
|
||||
// sort comparison. But this is the simplest solution I arrived
|
||||
// at after realizing that `.tarjan_scc(...)` does not sort nodes
|
||||
// inside components.
|
||||
for ratline in ratlines.iter() {
|
||||
if a.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().0)
|
||||
&& a.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().1)
|
||||
{
|
||||
a_length += ratline.ref_(autorouter).length();
|
||||
a_intersector_count += ratline
|
||||
.ref_(autorouter)
|
||||
.interior_obstacle_ratlines()
|
||||
.count();
|
||||
}
|
||||
}
|
||||
|
||||
for ratline in ratlines.iter() {
|
||||
if b.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().0)
|
||||
&& b.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().1)
|
||||
{
|
||||
b_length += ratline.ref_(autorouter).length();
|
||||
b_intersector_count += ratline
|
||||
.ref_(autorouter)
|
||||
.interior_obstacle_ratlines()
|
||||
.count();
|
||||
}
|
||||
}
|
||||
|
||||
let primary_ordering = a_intersector_count.cmp(&b_intersector_count);
|
||||
|
||||
if primary_ordering != Ordering::Equal {
|
||||
primary_ordering
|
||||
} else {
|
||||
let a_length = a.ref_(autorouter).length();
|
||||
let b_length = b.ref_(autorouter).length();
|
||||
let secondary_ordering = a_length.total_cmp(&b_length);
|
||||
|
||||
secondary_ordering
|
||||
}
|
||||
}),
|
||||
PresortBy::PairwiseDetours => ratlines.sort_unstable_by(|a, b| {
|
||||
let mut compare_detours = autorouter
|
||||
.compare_detours_ratlines(*a, *b, options)
|
||||
.unwrap();
|
||||
|
||||
if let Ok((al, bl)) = compare_detours.finish(autorouter) {
|
||||
PartialOrd::partial_cmp(&al, &bl).unwrap()
|
||||
// Below is how I tried to do this before I realized that
|
||||
// `.tarjan_scc(...)` does not sort nodes inside components.
|
||||
|
||||
/*let a_intersector_count: usize = a
|
||||
.windows(2)
|
||||
.map(|window| {
|
||||
let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap();
|
||||
ratline
|
||||
.ref_(autorouter)
|
||||
.interior_obstacle_ratlines()
|
||||
.count()
|
||||
})
|
||||
.sum();
|
||||
let b_intersector_count: usize = b
|
||||
.windows(2)
|
||||
.map(|window| {
|
||||
let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap();
|
||||
ratline
|
||||
.ref_(autorouter)
|
||||
.interior_obstacle_ratlines()
|
||||
.count()
|
||||
})
|
||||
.sum();
|
||||
|
||||
let primary_ordering = a_intersector_count.cmp(&b_intersector_count);
|
||||
|
||||
if primary_ordering != Ordering::Equal {
|
||||
primary_ordering
|
||||
} else {
|
||||
Ordering::Equal
|
||||
let a_length: f64 = a
|
||||
.windows(2)
|
||||
.map(|window| {
|
||||
let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap();
|
||||
ratline.ref_(autorouter).length()
|
||||
})
|
||||
.sum();
|
||||
let b_length: f64 = b
|
||||
.windows(2)
|
||||
.map(|window| {
|
||||
let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap();
|
||||
ratline.ref_(autorouter).length()
|
||||
})
|
||||
.sum();
|
||||
|
||||
let secondary_ordering = a_length.total_cmp(&b_length);
|
||||
|
||||
secondary_ordering
|
||||
}*/
|
||||
});
|
||||
|
||||
Self {
|
||||
sccs_permutations_iter: sccs.into_iter().permutations(sccs_len),
|
||||
ratlines,
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
pub fn next_permutation(
|
||||
&mut self,
|
||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||
) -> Option<Vec<RatlineIndex>> {
|
||||
let scc_permutation = self.sccs_permutations_iter.next()?;
|
||||
let mut ratlines = vec![];
|
||||
|
||||
for scc in scc_permutation {
|
||||
for ratline in self.ratlines.iter() {
|
||||
if scc.contains(
|
||||
&autorouter
|
||||
.ratsnest()
|
||||
.graph()
|
||||
.edge_endpoints(*ratline)
|
||||
.unwrap()
|
||||
.0,
|
||||
) && scc.contains(
|
||||
&autorouter
|
||||
.ratsnest()
|
||||
.graph()
|
||||
.edge_endpoints(*ratline)
|
||||
.unwrap()
|
||||
.1,
|
||||
) {
|
||||
ratlines.push(*ratline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(ratlines)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AutorouteExecutionPermutator {
|
||||
stepper: AutorouteExecutionStepper,
|
||||
permuter: RatlineSccPermuter,
|
||||
options: AutorouterOptions,
|
||||
}
|
||||
|
||||
impl AutorouteExecutionPermutator {
|
||||
pub fn new(
|
||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||
ratlines: Vec<RatlineIndex>,
|
||||
options: AutorouterOptions,
|
||||
) -> Result<Self, AutorouterError> {
|
||||
let mut permuter = RatlineSccPermuter::new(autorouter, ratlines, &options);
|
||||
let initially_sorted_ratlines = permuter.next_permutation(autorouter).unwrap();
|
||||
|
||||
Ok(Self {
|
||||
stepper: AutorouteExecutionStepper::new(autorouter, ratlines.clone(), options)?,
|
||||
stepper: AutorouteExecutionStepper::new(
|
||||
autorouter,
|
||||
initially_sorted_ratlines,
|
||||
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),
|
||||
permuter,
|
||||
options,
|
||||
})
|
||||
}
|
||||
|
|
@ -92,7 +222,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, AutorouteContinue
|
|||
}
|
||||
|
||||
loop {
|
||||
let Some(permutation) = self.permutations_iter.next() else {
|
||||
let Some(permutation) = self.permuter.next_permutation(autorouter) else {
|
||||
return Ok(ControlFlow::Break(None));
|
||||
};
|
||||
|
||||
|
|
@ -111,7 +241,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, AutorouteContinue
|
|||
|
||||
impl<M: AccessMesadata> Abort<Autorouter<M>> for AutorouteExecutionPermutator {
|
||||
fn abort(&mut self, autorouter: &mut Autorouter<M>) {
|
||||
self.permutations_iter.all(|_| true);
|
||||
//self.permutations_iter.all(|_| true); // Why did I add this code here???
|
||||
self.stepper.abort(autorouter);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,18 +2,14 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//! Defines data structures and methods for managing a graph
|
||||
//! used in layout triangulation and routing tasks. It includes vertex and edge
|
||||
//! structures for representing graph nodes and edges with associated metadata,
|
||||
//! as well as functions for constructing and manipulating these graphs.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use geo::Point;
|
||||
use petgraph::{
|
||||
data::Element,
|
||||
graph::{NodeIndex, UnGraph},
|
||||
graph::NodeIndex,
|
||||
prelude::StableUnGraph,
|
||||
unionfind::UnionFind,
|
||||
visit::{EdgeRef, IntoEdgeReferences, NodeIndexable},
|
||||
};
|
||||
|
|
@ -74,7 +70,7 @@ impl HasPosition for RatvertexWeight {
|
|||
}
|
||||
|
||||
pub struct Ratsnest {
|
||||
graph: UnGraph<RatvertexWeight, RatlineWeight, usize>,
|
||||
graph: StableUnGraph<RatvertexWeight, RatlineWeight, usize>,
|
||||
}
|
||||
|
||||
impl Ratsnest {
|
||||
|
|
@ -86,7 +82,7 @@ impl Ratsnest {
|
|||
}
|
||||
|
||||
let mut this = Self {
|
||||
graph: UnGraph::default(),
|
||||
graph: StableUnGraph::default(),
|
||||
};
|
||||
|
||||
let mut triangulations = BTreeMap::new();
|
||||
|
|
@ -166,7 +162,7 @@ impl Ratsnest {
|
|||
self.graph.edge_weight_mut(ratline).unwrap().band_termseg = Some(termseg);
|
||||
}
|
||||
|
||||
pub fn graph(&self) -> &UnGraph<RatvertexWeight, RatlineWeight, usize> {
|
||||
pub fn graph(&self) -> &StableUnGraph<RatvertexWeight, RatlineWeight, usize> {
|
||||
&self.graph
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue