ZLayout EDA Library v1.0.0
Advanced Electronic Design Automation Layout Library with Bilingual Documentation
Loading...
Searching...
No Matches
advanced_spatial.cpp
Go to the documentation of this file.
1
5
7#include <algorithm>
8#include <chrono>
9#include <iostream>
10#include <stdexcept>
11
12namespace zlayout {
13namespace spatial {
14
15// ThreadPool implementation
16ThreadPool::ThreadPool(size_t threads) : stop(false) {
17 for (size_t i = 0; i < threads; ++i) {
18 workers.emplace_back([this] {
19 for (;;) {
20 std::function<void()> task;
21 {
22 std::unique_lock<std::mutex> lock(this->queue_mutex);
23 this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
24
25 if (this->stop && this->tasks.empty()) return;
26
27 task = std::move(this->tasks.front());
28 this->tasks.pop();
29 }
30 task();
31 }
32 });
33 }
34}
35
37 {
38 std::unique_lock<std::mutex> lock(queue_mutex);
39 stop = true;
40 }
41 condition.notify_all();
42 for (std::thread& worker : workers) {
43 worker.join();
44 }
45}
46
47template<class F, class... Args>
48auto ThreadPool::enqueue(F&& f, Args&&... args) const -> std::future<typename std::result_of<F(Args...)>::type> {
49 using return_type = typename std::result_of<F(Args...)>::type;
50
51 auto task = std::make_shared<std::packaged_task<return_type()>>(
52 std::bind(std::forward<F>(f), std::forward<Args>(args)...)
53 );
54
55 std::future<return_type> res = task->get_future();
56 {
57 std::unique_lock<std::mutex> lock(queue_mutex);
58
59 if (stop) {
60 throw std::runtime_error("enqueue on stopped ThreadPool");
61 }
62
63 tasks.emplace([task]() { (*task)(); });
64 }
65 condition.notify_one();
66 return res;
67}
68
70 std::unique_lock<std::mutex> lock(queue_mutex);
71 condition.wait(lock, [this] { return tasks.empty(); });
72}
73
74// R-tree implementation
75template<typename T>
76void RTree<T>::insert(const T& object, const geometry::Rectangle& bbox) {
77 if (root->is_full() && !root->is_leaf) {
78 // Split root
79 auto new_root = std::make_unique<RTreeNode<T>>(false);
80 new_root->children.push_back(std::move(root));
81 auto sibling = split_node(new_root->children[0].get());
82 new_root->children.push_back(std::move(sibling));
83 new_root->update_mbr();
84 root = std::move(new_root);
85 }
86
87 insert_recursive(root.get(), object, bbox);
88 object_count++;
89}
90
91template<typename T>
92void RTree<T>::insert_recursive(RTreeNode<T>* node, const T& object, const geometry::Rectangle& bbox) {
93 if (node->is_leaf) {
94 node->entries.emplace_back(object, bbox);
95 node->update_mbr();
96 return;
97 }
98
99 // Find child with minimum area increase
100 double min_increase = std::numeric_limits<double>::max();
101 size_t best_child = 0;
102
103 for (size_t i = 0; i < node->children.size(); ++i) {
104 double increase = calculate_area_increase(node->children[i]->mbr, bbox);
105 if (increase < min_increase) {
106 min_increase = increase;
107 best_child = i;
108 }
109 }
110
111 // Check if child needs splitting
112 if (node->children[best_child]->is_full()) {
113 auto sibling = split_node(node->children[best_child].get());
114 node->children.push_back(std::move(sibling));
115
116 // Recalculate best child after split
117 min_increase = std::numeric_limits<double>::max();
118 best_child = 0;
119
120 for (size_t i = 0; i < node->children.size(); ++i) {
121 double increase = calculate_area_increase(node->children[i]->mbr, bbox);
122 if (increase < min_increase) {
123 min_increase = increase;
124 best_child = i;
125 }
126 }
127 }
128
129 insert_recursive(node->children[best_child].get(), object, bbox);
130 node->update_mbr();
131}
132
133template<typename T>
134std::unique_ptr<RTreeNode<T>> RTree<T>::split_node(RTreeNode<T>* node) {
135 auto new_node = std::make_unique<RTreeNode<T>>(node->is_leaf);
136
137 if (node->is_leaf) {
138 // Split leaf node entries
139 size_t mid = node->entries.size() / 2;
140 new_node->entries.assign(node->entries.begin() + mid, node->entries.end());
141 node->entries.erase(node->entries.begin() + mid, node->entries.end());
142 } else {
143 // Split internal node children
144 size_t mid = node->children.size() / 2;
145 new_node->children.assign(
146 std::make_move_iterator(node->children.begin() + mid),
147 std::make_move_iterator(node->children.end())
148 );
149 node->children.erase(node->children.begin() + mid, node->children.end());
150 }
151
152 node->update_mbr();
153 new_node->update_mbr();
154
155 return new_node;
156}
157
158template<typename T>
159std::vector<T> RTree<T>::query_range(const geometry::Rectangle& range) const {
160 std::vector<T> result;
161 query_recursive(root.get(), range, result);
162 return result;
163}
164
165template<typename T>
166void RTree<T>::query_recursive(const RTreeNode<T>* node, const geometry::Rectangle& range, std::vector<T>& result) const {
167 if (!node->mbr.intersects(range)) {
168 return;
169 }
170
171 if (node->is_leaf) {
172 for (const auto& entry : node->entries) {
173 if (entry.second.intersects(range)) {
174 result.push_back(entry.first);
175 }
176 }
177 } else {
178 for (const auto& child : node->children) {
179 query_recursive(child.get(), range, result);
180 }
181 }
182}
183
184template<typename T>
185std::vector<T> RTree<T>::query_point(const geometry::Point& point) const {
186 geometry::Rectangle point_rect(point.x, point.y, 0, 0);
187 return query_range(point_rect);
188}
189
190template<typename T>
191double RTree<T>::calculate_area_increase(const geometry::Rectangle& current, const geometry::Rectangle& new_rect) const {
192 double current_area = current.area();
193 double union_area = current.union_with(new_rect).area();
194 return union_area - current_area;
195}
196
197template<typename T>
199 root = std::make_unique<RTreeNode<T>>(true);
200 object_count = 0;
201}
202
203template<typename T>
204bool RTree<T>::remove(const T& /*object*/, const geometry::Rectangle& /*bbox*/) {
205 // Implementation of removal is complex and would require rebalancing
206 // For now, we'll implement a simple version
207 // In production, you'd want a more sophisticated removal algorithm
208 return false; // Not implemented yet
209}
210
211// HierarchicalSpatialIndex implementation
212template<typename T>
214 const geometry::Rectangle& boundary,
215 const std::string& parent_name) {
216 IPBlock* parent = find_block(parent_name);
217 if (!parent) {
218 throw std::runtime_error("Parent block not found: " + parent_name);
219 }
220
221 auto new_block = std::make_unique<IPBlock>(name, boundary, parent->level + 1);
222 parent->add_sub_block(std::move(new_block));
223
224 // Create spatial index for this block
225 create_block_index(name, boundary);
226}
227
228template<typename T>
229void HierarchicalSpatialIndex<T>::create_block_index(const std::string& block_name,
230 const geometry::Rectangle& boundary) {
231 // Create both QuadTree and R-tree indices for comparison
232 auto bbox_func = [](const T& obj) -> geometry::Rectangle {
233 // This assumes T has a bounding_box() method or is itself a Rectangle
234 if constexpr (std::is_same_v<T, geometry::Rectangle>) {
235 return obj;
236 } else if constexpr (std::is_same_v<T, geometry::Point>) {
237 return geometry::Rectangle(obj.x, obj.y, 0.0, 0.0);
238 } else {
239 return obj.bounding_box();
240 }
241 };
242
243 block_indices[block_name] = std::make_unique<QuadTree<T>>(boundary, bbox_func, 100, 8);
244 rtree_indices[block_name] = std::make_unique<RTree<T>>();
245}
246
247template<typename T>
248IPBlock* HierarchicalSpatialIndex<T>::find_block(const std::string& name) const {
249 if (name == "root") {
250 return root_block.get();
251 }
252
253 // Simple recursive search - in production, you'd want a hash map
254 std::function<IPBlock*(IPBlock*, const std::string&)> search =
255 [&](IPBlock* block, const std::string& target_name) -> IPBlock* {
256 if (block->name == target_name) {
257 return block;
258 }
259 for (const auto& sub_block : block->sub_blocks) {
260 if (auto found = search(sub_block.get(), target_name)) {
261 return found;
262 }
263 }
264 return nullptr;
265 };
266
267 return search(root_block.get(), name);
268}
269
270template<typename T>
271std::string HierarchicalSpatialIndex<T>::find_optimal_block(const geometry::Rectangle& /*bbox*/) const {
272 // For now, simply return "root". In a real implementation, you would:
273 // 1. Traverse the hierarchy to find the best-fitting block
274 // 2. Consider load balancing across blocks
275 // 3. Check spatial locality
276 return "root";
277}
278
279template<typename T>
281 std::vector<std::future<std::vector<std::pair<T, T>>>> futures;
282
283 // Dispatch intersection finding to different threads for each block
284 for (const auto& block_pair : block_indices) {
285 const auto& index = block_pair.second;
286 auto future = thread_pool.enqueue([&index]() {
287 return index->find_potential_intersections();
288 });
289 futures.push_back(std::move(future));
290 }
291
292 // Collect results
293 std::vector<std::pair<T, T>> result;
294 for (auto& future : futures) {
295 auto block_intersections = future.get();
296 result.insert(result.end(), block_intersections.begin(), block_intersections.end());
297 }
298
299 return result;
300}
301
302template<typename T>
303std::vector<std::future<std::vector<T>>> HierarchicalSpatialIndex<T>::dispatch_parallel_queries(
304 const geometry::Rectangle& range) const {
305
306 std::vector<std::future<std::vector<T>>> futures;
307
308 for (const auto& block_pair : block_indices) {
309 const auto& block_name = block_pair.first;
310 const auto& index = block_pair.second;
311 // Check if block intersects with query range
312 IPBlock* block = find_block(block_name);
313 if (block && block->intersects(range)) {
314 auto future = thread_pool.enqueue([&index, range]() {
315 return index->query_range(range);
316 });
317 futures.push_back(std::move(future));
318 }
319 }
320
321 return futures;
322}
323
324template<typename T>
326 // Analyze current structure and optimize
327 // This is a simplified version - real optimization would be much more complex
328
329 std::function<void(IPBlock*)> optimize_block = [&](IPBlock* block) {
330 // If block has too many components, create sub-blocks
331 if (block->component_ids.size() > max_objects_per_block &&
332 block->level < max_hierarchy_levels) {
333
334 // Create 4 sub-blocks (quadrants)
335 double half_width = block->boundary.width / 2.0;
336 double half_height = block->boundary.height / 2.0;
337
338 std::vector<geometry::Rectangle> quadrants = {
339 geometry::Rectangle(block->boundary.x, block->boundary.y + half_height,
340 half_width, half_height),
341 geometry::Rectangle(block->boundary.x + half_width, block->boundary.y + half_height,
342 half_width, half_height),
343 geometry::Rectangle(block->boundary.x, block->boundary.y,
344 half_width, half_height),
345 geometry::Rectangle(block->boundary.x + half_width, block->boundary.y,
346 half_width, half_height)
347 };
348
349 for (size_t i = 0; i < 4; ++i) {
350 std::string sub_name = block->name + "_q" + std::to_string(i);
351 auto sub_block = std::make_unique<IPBlock>(sub_name, quadrants[i], block->level + 1);
352 block->add_sub_block(std::move(sub_block));
353 create_block_index(sub_name, quadrants[i]);
354 }
355 }
356
357 // Recursively optimize sub-blocks
358 for (const auto& sub_block : block->sub_blocks) {
359 optimize_block(sub_block.get());
360 }
361 };
362
363 optimize_block(root_block.get());
364}
365
366template<typename T>
368 Statistics stats = {0, 0, 0, 0, 0.0, 0.0};
369
370 // Count total objects and blocks
371 std::function<void(const IPBlock*)> count_block = [&](const IPBlock* block) {
372 stats.total_blocks++;
373 stats.total_objects += block->component_ids.size();
374 stats.max_depth = std::max(stats.max_depth, block->level);
375
376 for (const auto& sub_block : block->sub_blocks) {
377 count_block(sub_block.get());
378 }
379 };
380
381 count_block(root_block.get());
382
383 if (stats.total_blocks > 0) {
385 }
386
387 // Estimate memory usage (simplified)
388 stats.memory_usage_mb = (stats.total_objects * sizeof(T) +
389 stats.total_blocks * sizeof(IPBlock)) / (1024.0 * 1024.0);
390
391 return stats;
392}
393
394template<typename T>
395void HierarchicalSpatialIndex<T>::partition_objects_by_zorder(const std::vector<std::pair<T, geometry::Rectangle>>& objects) {
396 // Simple implementation: bucket objects by Z-order curve
397 for (const auto& obj_pair : objects) {
398 uint64_t z_order = ZOrderCurve::encode_point(obj_pair.second.center(), world_bounds);
399 zorder_buckets[z_order].push_back(obj_pair.first);
400 }
401}
402
403template<typename T>
405 const std::vector<geometry::Rectangle>& query_patterns) {
406
407 // Analyze query patterns and optimize index structure
408 // This is a simplified implementation
409
410 std::unordered_map<std::string, int> block_access_count;
411
412 for (const auto& query_rect : query_patterns) {
413 for (const auto& block_pair : block_indices) {
414 const auto& block_name = block_pair.first;
415 IPBlock* block = find_block(block_name);
416 if (block && block->intersects(query_rect)) {
417 block_access_count[block_name]++;
418 }
419 }
420 }
421
422 // Reorganize frequently accessed blocks for better performance
423 // In a real implementation, you might:
424 // 1. Adjust block boundaries based on query patterns
425 // 2. Change the spatial index type for hot blocks
426 // 3. Pre-cache results for common queries
427 // 4. Adjust memory allocation patterns
428}
429
430// Explicit template instantiations for common types
431template class RTree<geometry::Rectangle>;
432template class RTree<geometry::Point>;
435
436} // namespace spatial
437} // namespace zlayout
Advanced spatial indexing for ultra-large scale EDA layouts.
2D point with high-precision coordinates and utility methods
Definition point.hpp:23
double x
X coordinate.
Definition point.hpp:25
double y
Y coordinate.
Definition point.hpp:26
Axis-aligned rectangle for bounding boxes and simple EDA components.
Definition rectangle.hpp:26
double area() const
Calculate rectangle area.
double y
Y coordinate of bottom-left corner.
Definition rectangle.hpp:29
double height
Height of rectangle.
Definition rectangle.hpp:31
Rectangle union_with(const Rectangle &other) const
Calculate union rectangle that contains both rectangles.
bool intersects(const Rectangle &other) const
Check if this rectangle intersects with another rectangle.
double x
X coordinate of bottom-left corner.
Definition rectangle.hpp:28
double width
Width of rectangle.
Definition rectangle.hpp:30
Hierarchical spatial index for ultra-large datasets.
void create_ip_block(const std::string &name, const geometry::Rectangle &boundary, const std::string &parent_name="root")
void optimize_for_query_pattern(const std::vector< geometry::Rectangle > &query_patterns)
std::vector< std::pair< T, T > > parallel_find_intersections() const
High-performance R-tree implementation.
void insert(const T &object, const geometry::Rectangle &bbox)
std::vector< T > query_point(const geometry::Point &point) const
bool remove(const T &object, const geometry::Rectangle &bbox)
std::vector< T > query_range(const geometry::Rectangle &range) const
auto enqueue(F &&f, Args &&... args) const -> std::future< typename std::result_of< F(Args...)>::type >
ThreadPool(size_t threads=std::thread::hardware_concurrency())
static uint64_t encode_point(const geometry::Point &point, const geometry::Rectangle &bounds)
Main namespace for ZLayout library.
Definition component.hpp:20
IP Block represents a hierarchical design block.
std::vector< size_t > component_ids
bool intersects(const geometry::Rectangle &rect) const
void add_sub_block(std::unique_ptr< IPBlock > block)
std::vector< std::unique_ptr< IPBlock > > sub_blocks
R-tree node for efficient rectangle indexing.
std::vector< std::pair< T, geometry::Rectangle > > entries
std::vector< std::unique_ptr< RTreeNode< T > > > children