WIP: More on deep regions & hier processor

- Splitting of shapes on output of booleans
- A bugfix: error happened when pulling intruders from second-next hier level
- Tests added
- Some TODO comments added
This commit is contained in:
Matthias Koefferlein 2018-11-22 01:26:03 +01:00
parent 06c11d0096
commit 7073a74aa5
13 changed files with 206 additions and 37 deletions

View File

@ -346,7 +346,7 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const
{
DeepLayer dl_out (m_deep_layer.derived ());
db::BoolAndOrNotLocalOperation op (and_op);
db::BoolAndOrNotLocalOperation op (and_op, m_deep_layer.store ()->max_area_ratio (), m_deep_layer.store ()->max_vertex_count ());
db::LocalProcessor proc (const_cast <db::Layout *> (m_deep_layer.layout ()), const_cast <db::Cell *> (m_deep_layer.initial_cell ()), other->deep_layer ().layout (), other->deep_layer ().initial_cell ());
proc.set_threads (m_deep_layer.store ()->threads ());

View File

@ -177,7 +177,7 @@ struct DeepShapeStore::LayoutHolder
static size_t s_instance_count = 0;
DeepShapeStore::DeepShapeStore ()
: m_threads (1)
: m_threads (1), m_max_area_ratio (3.0), m_max_vertex_count (16)
{
++s_instance_count;
}
@ -219,6 +219,16 @@ void DeepShapeStore::set_threads (int n)
m_threads = n;
}
void DeepShapeStore::set_max_area_ratio (double ar)
{
m_max_area_ratio = ar;
}
void DeepShapeStore::set_max_vertex_count (size_t n)
{
m_max_vertex_count = n;
}
void DeepShapeStore::add_ref (unsigned int layout, unsigned int layer)
{
tl::MutexLocker locker (&m_lock);
@ -245,6 +255,13 @@ void DeepShapeStore::remove_ref (unsigned int layout, unsigned int layer)
DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count)
{
if (max_area_ratio == 0.0) {
max_area_ratio = m_max_area_ratio;
}
if (max_vertex_count == 0) {
max_vertex_count = m_max_vertex_count;
}
unsigned int layout_index = 0;
layout_map_type::iterator l = m_layout_map.find (si);

View File

@ -195,7 +195,7 @@ public:
* into parts satisfying the area ratio (bounding box vs. polygon area)
* and maximum vertex count constraints.
*/
DeepLayer create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio = 3.0, size_t max_vertex_count = 16);
DeepLayer create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio = 0.0, size_t max_vertex_count = 0);
/**
* @brief Inserts the deep layer's shapes into some target layout
@ -240,6 +240,40 @@ public:
return m_threads;
}
/**
* @brief Sets the maximum vertex count default value
*
* This parameter is used to simplify complex polygons. It is used by
* create_polygon_layer with the default parameters. It's also used by
* boolean operations when they deliver their output.
*/
void set_max_vertex_count (size_t n);
/**
* @brief Gets the maximum vertex count
*/
size_t max_vertex_count () const
{
return m_max_vertex_count;
}
/**
* @brief Sets the max. area ratio for bounding box vs. polygon area
*
* This parameter is used to simplify complex polygons. It is used by
* create_polygon_layer with the default parameters. It's also used by
* boolean operations when they deliver their output.
*/
void set_max_area_ratio (double ar);
/**
* @brief Gets the max. area ratio
*/
double max_area_ratio () const
{
return m_max_area_ratio;
}
private:
friend class DeepLayer;
@ -259,6 +293,8 @@ private:
std::vector<LayoutHolder *> m_layouts;
layout_map_type m_layout_map;
int m_threads;
double m_max_area_ratio;
size_t m_max_vertex_count;
tl::Mutex m_lock;
struct DeliveryMappingCacheKey

View File

@ -101,14 +101,14 @@ public:
template <class Trans>
Ref operator() (const Ref &ref, const Trans &tr) const
{
shape_type sh = ref.obj ().transformed (Trans (ref_trans_type (tr).inverted ()) * tr);
shape_type sh = ref.obj ().transformed (tr * Trans (ref.trans ()));
ref_trans_type red_trans;
sh.reduce (red_trans);
typename std::unordered_map<shape_type, std::pair<const shape_type *, ref_trans_type> >::const_iterator m = m_cache_by_shape.find (sh);
typename std::unordered_map<shape_type, const shape_type *>::const_iterator m = m_cache_by_shape.find (sh);
if (m != m_cache_by_shape.end ()) {
return Ref (m->second.first, ref_trans_type (tr * Trans (ref.trans ())) * m->second.second);
return Ref (m->second, red_trans);
} else {
@ -118,8 +118,8 @@ public:
ptr = mp_layout->shape_repository ().repository (typename shape_type::tag ()).insert (sh);
}
m_cache_by_shape[sh] = std::make_pair (ptr, red_trans);
return Ref (ptr, ref_trans_type (tr * Trans (ref.trans ())) * red_trans);
m_cache_by_shape[sh] = ptr;
return Ref (ptr, red_trans);
}
}
@ -127,7 +127,7 @@ public:
private:
db::Layout *mp_layout;
mutable std::unordered_map<const shape_type *, const shape_type *> m_cache;
mutable std::unordered_map<shape_type, std::pair<const shape_type *, ref_trans_type> > m_cache_by_shape;
mutable std::unordered_map<shape_type, const shape_type *> m_cache_by_shape;
};
template <class Ref, class Trans>
@ -494,9 +494,9 @@ private:
unsigned int m_intruder_layer;
db::Coord m_dist;
ShapeInteractions *mp_result;
std::unordered_map<std::pair<unsigned int, const db::PolygonRef *>, unsigned int> m_inst_shape_ids;
std::unordered_map<db::PolygonRef, unsigned int> m_inst_shape_ids;
void add_shapes_from_intruder_inst (unsigned int id1, const db::Cell &intruder_cell, const db::ICplxTrans &tn, unsigned int inst_id, const db::Box &region)
void add_shapes_from_intruder_inst (unsigned int id1, const db::Cell &intruder_cell, const db::ICplxTrans &tn, unsigned int /*inst_id*/, const db::Box &region)
{
db::shape_reference_translator<db::PolygonRef> rt (mp_subject_layout);
@ -507,18 +507,17 @@ private:
si.shape_flags (polygon_ref_flags ());
while (! si.at_end ()) {
const db::PolygonRef *ref2 = si.shape ().basic_ptr (db::PolygonRef::tag ());
// NOTE: we intentionally rewrite to the *subject* layout - this way polygon refs in the context come from the
// subject, not from the intruder.
db::PolygonRef ref2 = rt (*si.shape ().basic_ptr (db::PolygonRef::tag ()), tn * si.trans ());
// reuse the same id for shapes from the same instance -> this avoid duplicates with different IDs on
// the intruder side.
std::unordered_map<std::pair<unsigned int, const db::PolygonRef *>, unsigned int>::const_iterator k = m_inst_shape_ids.find (std::make_pair (inst_id, ref2));
std::unordered_map<db::PolygonRef, unsigned int>::const_iterator k = m_inst_shape_ids.find (ref2);
if (k == m_inst_shape_ids.end ()) {
k = m_inst_shape_ids.insert (std::make_pair (std::make_pair (inst_id, ref2), mp_result->next_id ())).first;
// NOTE: we intentionally rewrite to the *subject* layout - this way polygon refs in the context come from the
// subject, not from the intruder.
mp_result->add_shape (k->second, rt (*ref2, tn * si.trans ()));
k = m_inst_shape_ids.insert (std::make_pair (ref2, mp_result->next_id ())).first;
mp_result->add_shape (k->second, ref2);
}
@ -887,6 +886,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts,
}
}
// @@@ can we shortcut this if interactions is empty?
{
db::box_scanner2<db::CellInstArray, int, db::CellInstArray, int> scanner;
InteractionRegistrationInst2Inst rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.intruder_layer (), dist, &interactions);
@ -935,6 +935,7 @@ void LocalProcessor::compute_contexts (LocalProcessorContexts &contexts,
scanner.process (rec, dist, inst_bcs, inst_bci);
}
// @@@ can we shortcut this if interactions is empty?
{
db::box_scanner2<db::CellInstArray, int, db::PolygonRef, int> scanner;
InteractionRegistrationInst2Shape rec (mp_subject_layout, contexts.subject_layer (), dist, &interactions);
@ -1136,6 +1137,7 @@ LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db::
scanner.insert (ref, id++);
}
// @@@ TODO: can we confine this search to the subject's (sized) bounding box?
for (std::unordered_set<db::PolygonRef>::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) {
scanner.insert (i.operator-> (), interactions.next_id ());
}
@ -1153,11 +1155,13 @@ LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db::
scanner.insert1 (ref, id++);
}
// @@@ TODO: can we confine this search to the subject's (sized) bounding box?
for (std::unordered_set<db::PolygonRef>::const_iterator i = intruders.second.begin (); i != intruders.second.end (); ++i) {
scanner.insert2 (i.operator-> (), interactions.next_id ());
}
if (intruder_shapes) {
// @@@ TODO: can we confine this search to the subject's (sized) bounding box?
for (db::Shapes::shape_iterator i = intruder_shapes->begin (polygon_ref_flags ()); !i.at_end (); ++i) {
scanner.insert2 (i->basic_ptr (db::PolygonRef::tag ()), interactions.next_id ());
}
@ -1188,6 +1192,7 @@ LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db::
// interactions low in the hierarchy.
} else if (intruder_cell) {
// @@@ TODO: can we confine this search to the subject's (sized) bounding box?
for (db::Cell::const_iterator i = intruder_cell->begin (); !i.at_end (); ++i) {
if (! inst_bci (i->cell_inst ()).empty ()) {
scanner.insert2 (&i->cell_inst (), ++inst_id);
@ -1195,6 +1200,7 @@ LocalProcessor::compute_local_cell (const LocalProcessorContexts &contexts, db::
}
}
// @@@ TODO: can we confine this search to the subject's (sized) bounding box?
for (std::unordered_set<db::CellInstArray>::const_iterator i = intruders.first.begin (); i != intruders.first.end (); ++i) {
if (! inst_bci (*i).empty ()) {
scanner.insert2 (i.operator-> (), ++inst_id);

View File

@ -474,20 +474,10 @@ ReducingHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db:
reduce (shape, region, complex_region, target);
}
static double area_ratio (const db::Polygon &poly)
{
return double (poly.box ().area ()) / double (poly.area ());
}
void
ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
{
size_t npoints = 0;
for (unsigned int c = 0; c < poly.holes () + 1; ++c) {
npoints += poly.contour (c).size ();
}
if (npoints > m_max_vertex_count || area_ratio (poly) > m_area_ratio) {
if (poly.vertices () > m_max_vertex_count || poly.area_ratio () > m_area_ratio) {
std::vector <db::Polygon> split_polygons;
db::split_polygon (poly, split_polygons);

View File

@ -27,6 +27,7 @@
#include "dbBoxConvert.h"
#include "dbEdgeProcessor.h"
#include "dbPolygonGenerators.h"
#include "dbPolygonTools.h"
#include "tlLog.h"
#include "tlTimer.h"
#include "tlInternational.h"
@ -65,12 +66,46 @@ private:
std::unordered_set<db::PolygonRef> *mp_polyrefs;
};
class PolygonSplitter
: public PolygonSink
{
public:
PolygonSplitter (PolygonSink &sink, double max_area_ratio, size_t max_vertex_count)
: mp_sink (&sink), m_max_area_ratio (max_area_ratio), m_max_vertex_count (max_vertex_count)
{
// .. nothing yet ..
}
virtual void put (const db::Polygon &poly)
{
if ((m_max_vertex_count > 0 && poly.vertices () > m_max_vertex_count) || (m_max_area_ratio > 0.0 && poly.area_ratio () > m_max_area_ratio)) {
std::vector <db::Polygon> split_polygons;
db::split_polygon (poly, split_polygons);
for (std::vector <db::Polygon>::const_iterator sp = split_polygons.begin (); sp != split_polygons.end (); ++sp) {
put (*sp);
}
} else {
mp_sink->put (poly);
}
}
virtual void start () { mp_sink->start (); }
virtual void flush () { mp_sink->flush (); }
private:
PolygonSink *mp_sink;
double m_max_area_ratio;
size_t m_max_vertex_count;
};
}
// ---------------------------------------------------------------------------------------------
BoolAndOrNotLocalOperation::BoolAndOrNotLocalOperation (bool is_and)
: m_is_and (is_and)
BoolAndOrNotLocalOperation::BoolAndOrNotLocalOperation (bool is_and, double max_area_ratio, size_t max_vertex_count)
: m_is_and (is_and), m_max_area_ratio (max_area_ratio), m_max_vertex_count (max_vertex_count)
{
// .. nothing yet ..
}
@ -133,7 +168,8 @@ BoolAndOrNotLocalOperation::compute_local (db::Layout *layout, const ShapeIntera
db::BooleanOp op (m_is_and ? db::BooleanOp::And : db::BooleanOp::ANotB);
db::PolygonRefGenerator pr (layout, result);
db::PolygonGenerator pg (pr, true, true);
db::PolygonSplitter splitter (pr, m_max_area_ratio, m_max_vertex_count);
db::PolygonGenerator pg (splitter, true, true);
ep.process (pg, op);
}

View File

@ -114,7 +114,7 @@ class DB_PUBLIC BoolAndOrNotLocalOperation
: public LocalOperation
{
public:
BoolAndOrNotLocalOperation (bool is_and);
BoolAndOrNotLocalOperation (bool is_and, double max_area_ratio = 0.0, size_t max_vertex_count = 0);
virtual void compute_local (db::Layout *layout, const ShapeInteractions &interactions, std::unordered_set<db::PolygonRef> &result) const;
virtual on_empty_intruder_mode on_empty_intruder_hint () const;
@ -122,6 +122,8 @@ public:
private:
bool m_is_and;
double m_max_area_ratio;
size_t m_max_vertex_count;
};
/**

View File

@ -1662,7 +1662,7 @@ public:
}
/**
* @brief Return the number of points in the polygon
* @brief Returns the number of points in the polygon
*/
size_t vertices () const
{
@ -1673,6 +1673,18 @@ public:
return n;
}
/**
* @brief Returns the area ratio between the polygon's bounding box and actual area
*
* This number is a measure how well the polygon is approximated by the bounding box.
* Values are bigger than 1 for well-formed polygons. Bigger values mean worse
* approximation.
*/
double area_ratio () const
{
return double (box ().area ()) / double (area ());
}
/**
* @brief The hull "begin" point iterator
*
@ -2956,6 +2968,18 @@ public:
return m_hull.size ();
}
/**
* @brief Returns the area ratio between the polygon's bounding box and actual area
*
* This number is a measure how well the polygon is approximated by the bounding box.
* Values are bigger than 1 for well-formed polygons. Bigger values mean worse
* approximation.
*/
double area_ratio () const
{
return double (box ().area ()) / double (area ());
}
void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const
{
db::mem_stat (stat, purpose, cat, m_hull, no_self, parent);

View File

@ -288,3 +288,54 @@ TEST(5_BoolXOR)
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au5.gds");
}
TEST(6_Reduction)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/deep_region_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Cell &top_cell = ly.cell (top_cell_index);
db::DeepShapeStore dss;
dss.set_max_vertex_count (4);
dss.set_threads (0);
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
unsigned int l42 = ly.get_layer (db::LayerProperties (42, 0));
unsigned int lbox = ly.insert_layer ();
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
db::Region r42 (db::RecursiveShapeIterator (ly, top_cell, l42), dss);
top_cell.shapes (lbox).insert (db::Box (2000, -1000, 6000, 4000));
db::Region box (db::RecursiveShapeIterator (ly, top_cell, lbox), dss);
db::Region r2xor3 = r2 ^ r3;
db::Region r2xorbox = r2 ^ box;
db::Region r2xor42 = r2 ^ r42;
db::Region rboxxor3 = box ^ r3;
db::Region r42xor3 = r42 ^ r3;
db::Region r42xor42 = r42 ^ r42;
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r2xor3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2xorbox);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2xor42);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), rboxxor3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r42xor3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r42xor42);
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au6.gds");
}

View File

@ -1061,3 +1061,12 @@ TEST(BasicSelfOverlapWithSize10)
run_test_bool_with_size (_this, "hlp10.oas", TMSelfOverlap, 150, 111);
}
TEST(TopWithBelow1)
{
run_test_bool (_this, "hlp12.oas", TMNot, 100);
}
TEST(TopWithBelow2)
{
run_test_bool (_this, "hlp12.oas", TMNotSwapped, 101);
}

View File

@ -235,7 +235,7 @@ TEST(2)
v = e.parse ("var b=B.new; b.bx(-1)").execute ();
EXPECT_EQ (v.to_string (), std::string ("xz"));
/*
@@@ No detailed type analysis for ambiguity resolution so far:
TODO: No detailed type analysis for ambiguity resolution so far:
v = e.parse ("var b=B.new; b.bx('hello', 1)").execute ();
EXPECT_EQ (v.to_string (), std::string ("20.5"));
*/
@ -297,10 +297,8 @@ TEST(2)
v = e.parse ("b.amember_ref.a5(177)").execute ();
EXPECT_EQ (v.to_string (), std::string ("nil"));
// @@@
v = e.parse ("b.amember_or_nil(true)").execute ();
EXPECT_EQ (v.to_string (), std::string ("A: 177"));
// @@@
bool error = false;
try {

BIN
testdata/algo/deep_region_au6.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hlp12.oas vendored Normal file

Binary file not shown.