1use super::hanan_grid::HananGridWithCoords;
8use super::marker_types::Canonical;
9use super::position_sequence::PositionSequence;
10use super::wirelength_vector::*;
11use super::HananCoord;
12use crate::point::Point;
13use crate::tree::Tree;
14use num_traits::{Num, PrimInt, Zero};
15use std::iter::Sum;
16use std::ops::Add;
17
18#[derive(Clone, Debug)]
20pub struct LookupTable {
21 pub(crate) sub_lut_by_degree: Vec<SubLookupTable>,
23}
24
25impl LookupTable {
26 pub fn rsmt_low_degree<T>(&self, mut pins: Vec<Point<T>>) -> (Vec<(Point<T>, Point<T>)>, T)
32 where
33 T: Ord + Copy + Num + Zero + Sum + std::fmt::Debug,
34 {
35 pins.sort();
37 pins.dedup();
38
39 let num_pins = pins.len();
40
41 if num_pins <= 1 {
42 return (vec![], Zero::zero());
43 }
44
45 assert!(
46 pins.len() <= self.max_degree(),
47 "number of pins exceeds the supported maximal net degree"
48 );
49
50 let position_sequence = PositionSequence::from_points(&pins);
51 let group_index = position_sequence.group_index();
52
53 let sub_lut = self.get_sub_lut(num_pins);
54 debug_assert_eq!(sub_lut.values.len(), (1..num_pins + 1).product());
55
56 let (powvs, transform) = sub_lut.resolve_group_index(group_index);
58
59 pins.iter_mut().for_each(|p| {
61 *p = transform.transform_point(*p);
62 });
63
64 let xs = {
66 let mut xs: Vec<_> = pins.iter().map(|p| p.x).collect();
67 xs.sort();
68 xs
69 };
70 let ys = {
71 let mut ys: Vec<_> = pins.iter().map(|p| p.y).collect();
72 ys.sort();
73 ys
74 };
75
76 let best_powv_and_post = {
78 let compute_wire_length = |powv: &WirelenghtVector| -> T {
80 let (h, v) = powv.hv_vectors();
81
82 let edge_widths_horizontal = xs.windows(2).map(|w| w[1] - w[0]);
84 let edge_widths_vertical = ys.windows(2).map(|h| h[1] - h[0]);
85 debug_assert_eq!(h.len(), edge_widths_horizontal.len());
86 debug_assert_eq!(v.len(), edge_widths_vertical.len());
87
88 let wl_horiz: T = h
89 .iter()
90 .zip(edge_widths_horizontal)
91 .map(|(count, w)| (0..*count).map(|_| w).sum())
92 .sum();
94
95 let wl_vert: T = v
96 .iter()
97 .zip(edge_widths_vertical)
98 .map(|(count, w)| (0..*count).map(|_| w).sum())
99 .sum();
100
101 wl_horiz + wl_vert
102 };
103
104 powvs
105 .into_iter()
106 .map(|powv| {
107 (
108 powv,
109 compute_wire_length(&powv.potential_optimal_wirelength_vector),
110 )
111 })
112 .min_by_key(|(_powv, wire_len)| *wire_len)
113 };
114
115 let (best_powv_and_post, wire_length) = best_powv_and_post.expect("no steiner tree found");
116
117 let transform_point_to_original_grid =
119 |p: Point<HananCoord>| -> Point<T> { Point::new(xs[p.x as usize], ys[p.y as usize]) };
120
121 let tree_edges = best_powv_and_post
122 .potential_optimal_steiner_tree
123 .all_edges()
124 .map(|e| (e.start(), e.end())) .map(|(a, b)| {
126 (
127 transform_point_to_original_grid(a),
128 transform_point_to_original_grid(b),
129 )
130 });
131
132 let inverse_transform = transform.inverse();
134
135 let tree = tree_edges
136 .map(|(a, b)| {
137 (
138 inverse_transform.transform_point(a),
139 inverse_transform.transform_point(b),
140 )
141 })
142 .filter(|(a, b)| a != b)
143 .collect();
144
145 (tree, wire_length)
146 }
147
148 pub fn max_degree(&self) -> usize {
150 self.sub_lut_by_degree.len() + 1
151 }
152
153 pub fn get_sub_lut(&self, num_pins: usize) -> &SubLookupTable {
155 assert!(num_pins >= 2, "no LUT for less than 2 pins");
156 &self.sub_lut_by_degree[num_pins - 2]
157 }
158
159 pub fn print_statistics(&self) {
161 for (degree, sub_lut) in self.sub_lut_by_degree.iter().enumerate() {
162 let degree = degree + 2;
163 let max_num_powvs = sub_lut
164 .values
165 .iter()
166 .filter_map(|v| match v {
167 ValuesOrRedirect::Values(v) => Some(v.len()),
168 ValuesOrRedirect::Redirect { .. } => None,
169 })
170 .max()
171 .unwrap_or(0);
172
173 let total_num_powvs: usize = sub_lut
174 .values
175 .iter()
176 .map(|v| match v {
177 ValuesOrRedirect::Values(v) => v.len(),
178 ValuesOrRedirect::Redirect { group_index, .. } => {
179 match &sub_lut.values[*group_index] {
180 ValuesOrRedirect::Values(v) => v.len(),
181 _ => panic!("invalid double-redirect"),
182 }
183 }
184 })
185 .sum();
186 let average_num_pows = (total_num_powvs as f64) / (sub_lut.values.len() as f64);
187
188 println!(
189 "degree={}, max. number of POWVs = {}, avg. num. POWVs = {:.3}",
190 degree, max_num_powvs, average_num_pows
191 );
192 }
193 }
194}
195
196#[test]
197fn test_rsmt_low_degree() {
198 let lut = super::gen_lut::gen_full_lut(5);
199
200 let points = vec![(5, 0).into(), (0, 10).into(), (10, 10).into()];
202 let (rsmt, wl) = lut.rsmt_low_degree(points);
203 assert_eq!(rsmt.len(), 3);
204 assert_eq!(wl, 20);
205
206 let points = vec![(0, 0).into(), (2, 1).into(), (2, 4).into(), (4, 2).into()];
208 let (rsmt, wl) = lut.rsmt_low_degree(points);
209 assert_eq!(rsmt.len(), 5);
210 assert_eq!(wl, 8);
211
212 let points = vec![
214 (10, 5).into(),
215 (5, 0).into(),
216 (5, 5).into(),
217 (0, 5).into(),
218 (5, 10).into(),
219 ];
220 let (rsmt, wl) = lut.rsmt_low_degree(points);
221 assert_eq!(rsmt.len(), 4);
222 assert_eq!(wl, 20);
223}
224
225#[derive(Clone, Debug)]
227pub struct SubLookupTable {
228 pub(crate) values: Vec<ValuesOrRedirect>,
230}
231
232impl SubLookupTable {
233 fn resolve_group_index(&self, group_index: usize) -> (&Vec<LutValue>, Transform) {
238 let lut_value = &self.values[group_index];
239
240 match lut_value {
242 ValuesOrRedirect::Values(values) => (values, Transform::identity()),
243 &ValuesOrRedirect::Redirect {
244 group_index,
245 transform,
246 } => {
247 let values = match &self.values[group_index] {
249 ValuesOrRedirect::Values(values) => values,
250 _ => panic!("lookup-table contains nested redirects"),
251 };
252 (values, transform)
253 }
254 }
255 }
256}
257
258#[derive(Clone, Debug)]
260pub struct LutValue {
261 pub(crate) potential_optimal_wirelength_vector: WirelenghtVector,
263 pub(crate) potential_optimal_steiner_tree: Tree<Canonical>,
265}
266
267#[derive(Debug, Clone)]
270pub enum ValuesOrRedirect {
271 Values(Vec<LutValue>),
273 Redirect {
275 group_index: usize,
277 transform: Transform,
279 },
280}
281
282#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
286pub struct Transform {
287 mirror_x: bool,
289 rotate: u8,
291}
292
293impl Transform {
294 pub fn new(rotate: u8, mirror_x: bool) -> Self {
296 Self {
297 rotate: rotate % 4,
298 mirror_x,
299 }
300 }
301
302 pub fn identity() -> Self {
304 Self::new(0, false)
305 }
306
307 pub fn inverse(&self) -> Self {
309 let r = if self.mirror_x {
310 self.rotate
311 } else {
312 4 - self.rotate
313 };
314 Self::new(r, self.mirror_x)
315 }
316
317 pub fn transform_point<T>(&self, mut p: Point<T>) -> Point<T>
319 where
320 T: Copy + Num + Zero,
321 {
322 for _ in 0..self.rotate {
323 p.rotate_ccw90();
324 }
325
326 if self.mirror_x {
327 p.x = T::zero() - p.x;
328 }
329
330 p
331 }
332}