steiner_tree/
net_breaking_medium_degree.rs1use super::lut::LookupTable;
9use super::point::*;
10use itertools::Itertools;
11use num_traits::{FromPrimitive, Num, ToPrimitive, Zero};
12use std::iter::Sum;
13
14impl LookupTable {
15 pub fn rsmt_medium_degree<T>(
20 &self,
21 mut pins: Vec<Point<T>>,
22 accuracy: usize,
23 ) -> (Vec<(Point<T>, Point<T>)>, T)
24 where
25 T: Ord + Copy + Num + Zero + Sum + std::fmt::Debug + FromPrimitive + ToPrimitive,
26 {
27 assert!(accuracy > 0);
28
29 pins.sort_unstable_by_key(|p| (p.y, p.x));
30 pins.dedup();
31
32 let num_pins = pins.len();
33
34 if num_pins <= self.max_degree() {
35 return self.rsmt_low_degree(pins);
37 }
38
39 let xs = {
41 let mut xs: Vec<_> = pins.iter().map(|p| p.x).collect();
42 xs.sort_unstable();
43 xs
44 };
45 let ys = {
46 let mut ys: Vec<_> = pins.iter().map(|p| p.y).collect();
47 ys.sort_unstable();
48 ys
49 };
50
51 let pin_rank = {
53 let mut r: Vec<_> = (0..pins.len()).collect();
54 r.sort_by_key(|&i| pins[i].x);
55 r
56 };
57
58 let score_0 = |r: usize| -> T { hplw(&pins[..r + 1]) + hplw(&pins[r..]) };
59
60 let score_1 = |r: usize| -> T { pins[r + 1].y - pins[r - 1].y };
61
62 let score_2 = |r: usize| -> T {
63 let s_r = pin_rank[r];
64 if s_r < 2 {
65 T::from_usize(2).unwrap() * (xs[2] - xs[1])
66 } else if pin_rank[r] > num_pins - 2 {
67 T::from_usize(2).unwrap() * (xs[num_pins - 2] - xs[num_pins - 3])
68 } else {
69 xs[s_r + 1] - xs[s_r - 1]
70 }
71 };
72
73 let score_3 = |r: usize| -> f64 {
74 let dx: f64 = (xs[num_pins - 2] - xs[1]).to_f64().unwrap() / (num_pins - 4) as f64;
75 let dy: f64 = (ys[num_pins - 2] - ys[1]).to_f64().unwrap() / (num_pins - 4) as f64;
76
77 let s_r = (pin_rank[r] + 1) as f64;
78 let n = num_pins as f64;
79
80 (s_r - ((n + 2.) / 2.)).abs() * dx + ((r + 1) as f64 - ((n + 2.) / 2.)).abs() * dy
81 };
82
83 let score = |r: usize| -> f64 {
84 let n = num_pins as f64;
85
86 score_1(r).to_f64().unwrap()
88 - 0.3 * score_2(r).to_f64().unwrap()
89 - 7.5 / n * (score_3(r) + 12. * score_0(r).to_f64().unwrap() / (n - 3.))
90 };
91
92 let mut breaking_scores: Vec<_> = (1..num_pins - 1).map(|r| (r, score(r))).collect();
94 breaking_scores.sort_by_key(|(_, score)| (1e3 * score) as i64);
96
97 let trees = breaking_scores
98 .into_iter()
99 .take(accuracy)
100 .map(|(r, _score)| {
101 let pins_left = pins[0..r + 1].to_vec();
102 let pins_right = pins[r..].to_vec();
103
104 let (mut tree_left, tree_left_weight) =
106 self.rsmt_medium_degree(pins_left, accuracy / 2);
107 let (mut tree_right, tree_right_weight) =
108 self.rsmt_medium_degree(pins_right, accuracy / 2);
109
110 tree_left.sort();
112 tree_right.sort();
113
114 let merged_tree =
116 super::iterator_set_operations::union(tree_left, tree_right).collect();
117
118 let merged_weight = tree_left_weight + tree_right_weight;
119
120 (merged_tree, merged_weight)
121 });
122
123 let best_tree = trees.min_by_key(|(_, weight)| *weight).unwrap();
124
125 best_tree
126 }
127}
128
129fn hplw<T>(pins: &[Point<T>]) -> T
131where
132 T: Ord + Num + Zero + Copy,
133{
134 if pins.is_empty() {
135 T::zero()
136 } else {
137 let mut lower_left = pins[0];
138 let mut upper_right = pins[pins.len() - 1];
139 for p in &pins[1..] {
140 lower_left.x = lower_left.x.min(p.x);
141 upper_right.x = upper_right.x.max(p.x);
142 lower_left.y = lower_left.y.min(p.y);
143 upper_right.y = upper_right.y.max(p.y);
144 }
145 upper_right.x - lower_left.x + upper_right.y - lower_left.y
146 }
147}
148
149#[test]
150fn test_rsmt_medium_degree() {
151 let lut = super::gen_lut::gen_full_lut(3);
152
153 let points = vec![(0, 0).into(), (2, 1).into(), (2, 4).into(), (4, 2).into()];
155 let (rsmt, wl) = lut.rsmt_medium_degree(points, 4);
156 assert_eq!(rsmt.len(), 5);
157 assert_eq!(wl, 8);
158
159 let points = vec![
161 (10, 5).into(),
162 (5, 0).into(),
163 (5, 5).into(),
164 (0, 5).into(),
165 (5, 10).into(),
166 ];
167 let (rsmt, wl) = lut.rsmt_medium_degree(points, 4);
168 assert_eq!(rsmt.len(), 4);
169 assert_eq!(wl, 20);
170}