1use crate::CellId;
2use crate::Instance;
3use aph_disjoint_set::DisjointSet;
4use geometry::bbox::Bbox;
5use geometry::rect::Rect;
6use std::collections::{HashMap, HashSet};
7use std::hash::Hash;
8
9use crate::Element;
10use crate::{Cell, Library, Shape, TransformRef, Transformation};
11
12fn intersect_shapes<L>(shape1: &Shape<L>, shape2: &Shape<L>) -> bool {
14 let shape1_bbox: Rect = shape1.bbox_rect();
15 let shape2_bbox: Rect = shape2.bbox_rect();
16 shape1_bbox.intersection(shape2_bbox).is_some()
17}
18
19fn flatten_instance<L>(inst: &Instance, lib: &Library<L>) -> Vec<Shape<L>>
22where
23 L: Connectivity + Clone,
24{
25 let mut ret: Vec<Shape<L>> = vec![];
26
27 let cellid: CellId = inst.child();
28 let transform: Transformation = inst.transformation();
29
30 for elem in lib.cell(cellid).elements() {
32 if let Element::Shape(shape) = elem {
33 let transformed_shape = shape.transform_ref(transform);
34 ret.push(transformed_shape);
35 }
36 }
37
38 for instance in lib.cell(cellid).instances() {
40 let mut flattened_shapes = flatten_instance::<L>(instance.1, lib);
41 for flattened_shape in &mut flattened_shapes {
42 *flattened_shape = flattened_shape.transform_ref(transform);
43 }
44 ret.append(&mut flattened_shapes);
45 }
46
47 ret
48}
49
50fn flatten_cell<L>(cell: &Cell<L>, lib: &Library<L>) -> Vec<Shape<L>>
52where
53 L: Connectivity + Clone,
54{
55 let mut ret: Vec<Shape<L>> = vec![];
56
57 for elem in cell.elements() {
59 if let Element::Shape(shape) = elem {
60 ret.push(shape.clone());
61 }
62 }
63
64 for inst in cell.instances() {
65 for flattened_shape in flatten_instance::<L>(inst.1, lib) {
66 ret.push(flattened_shape);
67 }
68 }
69
70 ret
71}
72
73pub trait Connectivity: Sized + PartialEq + Eq + Clone + Hash {
74 fn connected_layers(&self) -> Vec<Self>;
75
76 fn connected(&self, other: &Self) -> bool {
78 self.connected_layers().contains(other)
79 }
80
81 fn connected_components(cell: &Cell<Self>, lib: &Library<Self>) -> Vec<HashSet<Shape<Self>>>
83 where
84 Self: Clone,
85 {
86 let all_shapes = flatten_cell::<Self>(cell, lib);
88 let mut djs = DisjointSet::new(all_shapes.len());
89
90 for (start_index, start_shape) in all_shapes.clone().into_iter().enumerate() {
92 for (other_index, other_shape) in all_shapes.clone().into_iter().enumerate() {
93 if start_index != other_index
94 && intersect_shapes::<Self>(&start_shape, &other_shape)
95 && start_shape.layer().connected(other_shape.layer())
96 {
97 djs.union(start_index, other_index);
98 }
99 }
100 }
101
102 let mut component_map: HashMap<usize, HashSet<Shape<Self>>> = HashMap::new();
103
104 for (start_index, start_shape) in all_shapes.into_iter().enumerate() {
105 let root: usize = djs.get_root(start_index).into_inner();
106 component_map.entry(root).or_default().insert(start_shape);
107 }
108
109 component_map.into_values().collect()
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::{Cell, Instance, LibraryBuilder, Shape};
117 use geometry::rect::Rect;
118 use std::collections::{HashMap, HashSet};
119
120 struct ComponentLookup<L> {
122 shape_to_component_id: HashMap<Shape<L>, usize>,
123 }
124
125 impl<L> ComponentLookup<L>
126 where
127 L: Connectivity + Clone,
128 {
129 fn new(components: Vec<HashSet<Shape<L>>>) -> Self {
131 let mut shape_to_component_id = HashMap::new();
132 for (component_id, component_set) in components.into_iter().enumerate() {
133 for shape in component_set.into_iter() {
134 shape_to_component_id.insert(shape, component_id);
135 }
136 }
137 ComponentLookup {
138 shape_to_component_id,
139 }
140 }
141
142 fn are_connected(&self, s1: &Shape<L>, s2: &Shape<L>) -> bool {
144 let comp_id1 = self.shape_to_component_id.get(s1);
145 let comp_id2 = self.shape_to_component_id.get(s2);
146
147 match (comp_id1, comp_id2) {
148 (Some(&id1), Some(&id2)) => id1 == id2,
150 _ => false,
151 }
152 }
153 }
154
155 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
156 enum Layer {
157 Met1,
158 Via1,
159 Met2,
160 Outside,
161 }
162
163 impl Connectivity for Layer {
164 fn connected_layers(&self) -> Vec<Self> {
165 match self {
166 Self::Met1 => vec![Self::Met1, Self::Via1],
167 Self::Via1 => vec![Self::Met1, Self::Via1, Self::Met2],
168 Self::Met2 => vec![Self::Via1, Self::Met2],
169 Self::Outside => vec![],
170 }
171 }
172 }
173
174 #[test]
175 fn test_complete() {
176 let mut small_cell: Cell<Layer> = Cell::new("small cell test");
177 let mut big_cell: Cell<Layer> = Cell::new("big cell test");
178 let mut lib_builder: LibraryBuilder<Layer> = LibraryBuilder::new();
179
180 let m2_shape1 = Shape::new(Layer::Met2, Rect::from_sides(0, 0, 30, 30));
182 small_cell.add_element(m2_shape1.clone());
183
184 lib_builder.add_cell(small_cell.clone());
185 let small_cell_id = lib_builder.cells().next().unwrap().0;
186
187 let small_cell_instance = Instance::new(small_cell_id, "small_cell_test");
188 big_cell.add_instance(small_cell_instance);
189
190 let m1_shape = Shape::new(Layer::Met1, Rect::from_sides(0, 0, 100, 100));
192 let v1_shape = Shape::new(Layer::Via1, Rect::from_sides(10, 10, 100, 100));
193 let m2_shape2 = Shape::new(Layer::Met2, Rect::from_sides(10, 10, 50, 50));
194 let m2_shape3 = Shape::new(Layer::Met2, Rect::from_sides(1000, 1000, 5000, 5000));
195 big_cell.add_element(m1_shape.clone());
196 big_cell.add_element(v1_shape.clone());
197 big_cell.add_element(m2_shape2.clone());
198 big_cell.add_element(m2_shape3.clone());
199
200 lib_builder.add_cell(big_cell.clone());
201
202 let lib = lib_builder.clone().build().unwrap();
204
205 let outside_shape = Shape::new(Layer::Outside, Rect::from_sides(0, 0, 100, 100));
207
208 let components_vec = Layer::connected_components(&big_cell, &lib);
210
211 let component_lookup = ComponentLookup::new(components_vec.clone());
212
213 assert!(
215 component_lookup.are_connected(&m1_shape, &v1_shape),
216 "m1_shape should be connected to v1_shape"
217 );
218 assert!(
219 component_lookup.are_connected(&m1_shape, &m2_shape2),
220 "m1_shape should be connected to m2_shape2"
221 );
222 assert!(
223 component_lookup.are_connected(&m1_shape, &m2_shape1), "m1_shape should be connected to m2_shape1"
225 );
226
227 assert!(
229 !component_lookup.are_connected(&m1_shape, &m2_shape3),
230 "m1_shape should not be connected to m2_shape3 (isolated)"
231 );
232 assert!(
233 !component_lookup.are_connected(&m1_shape, &outside_shape),
234 "m1_shape should not be connected to outside_shape"
235 );
236
237 assert_eq!(
239 components_vec.len(),
240 2,
241 "Expected 2 total connected components."
242 );
243 }
244}