layir/
connectivity.rs

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
12/// Returns true if two shapes overlap on a flat plane, and false otherwise.
13fn 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
19/// Returns a vector of all shapes from a given cell instance and its children
20/// with their coordinates transformed into the coordinate system of the instance's parent.
21fn 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    // Add all shape elements directly from child cell after applying the instances transformation
31    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    // Recursively flatten child instances and apply cumulative transformations
39    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
50/// Returns a vector of all shapes from a single cell's transformed child instances and itself.
51fn 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    // No transformation needed
58    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    /// Returns a vector of layers connected to a given layer.
77    fn connected(&self, other: &Self) -> bool {
78        self.connected_layers().contains(other)
79    }
80
81    /// Returns a vector of unique hashsets of all connected groups of connected child shapes in a given cell.
82    fn connected_components(cell: &Cell<Self>, lib: &Library<Self>) -> Vec<HashSet<Shape<Self>>>
83    where
84        Self: Clone,
85    {
86        // All sub-shapes contained in given cell
87        let all_shapes = flatten_cell::<Self>(cell, lib);
88        let mut djs = DisjointSet::new(all_shapes.len());
89
90        // Build disjoint sets based on overlap and layer connectivity
91        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    // This struct helps check if two shapes are connected after connected_components has been run
121    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        /// Creates a new ComponentLookup from a vector of connected components.
130        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        /// Returns true if both shapes are found and belong to the same component, and false otherwise.
143        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                // If both shapes are found, check if their component IDs are the same
149                (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        // Build small cell first and add to big cell
181        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        // Build big cell
191        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        // Build fixed library
203        let lib = lib_builder.clone().build().unwrap();
204
205        // Add an outside shape for testing
206        let outside_shape = Shape::new(Layer::Outside, Rect::from_sides(0, 0, 100, 100));
207
208        // Find all connected components of big_cell's child shapes
209        let components_vec = Layer::connected_components(&big_cell, &lib);
210
211        let component_lookup = ComponentLookup::new(components_vec.clone());
212
213        // Expected connections
214        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), // m2_shape1 is from the instance
224            "m1_shape should be connected to m2_shape1"
225        );
226
227        // Expected disconnection
228        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        // Double check number of connected components in library
238        assert_eq!(
239            components_vec.len(),
240            2,
241            "Expected 2 total connected components."
242        );
243    }
244}