Fixed a XOR issue

Bug: sometimes, if the files had different database units, the XOR
tool was showing differences while there are none.

This was due to a sloppy computation of the tile boxes. The solution
is to properly round the tile size to a common database unit and
to use a common effective size for both inputs.
This commit is contained in:
Matthias Koefferlein 2017-07-18 22:33:54 +02:00
parent 7d31825b11
commit 45b774a3af
4 changed files with 186 additions and 46 deletions

View File

@ -1792,7 +1792,7 @@ OASISWriter::write (const Repetition &rep)
x = -x;
}
if (x != 0) {
g = (g == 0) ? x : tl::lcd (g, x);
g = (g == 0) ? x : tl::gcd (g, x);
}
db::Coord y = safe_scale (m_sf, p->y ());
@ -1800,7 +1800,7 @@ OASISWriter::write (const Repetition &rep)
y = -y;
}
if (y != 0) {
g = (g == 0) ? y : tl::lcd (g, y);
g = (g == 0) ? y : tl::gcd (g, y);
}
}

View File

@ -31,6 +31,7 @@
#include "tlProgress.h"
#include "tlThreadedWorkers.h"
#include "tlExceptions.h"
#include "tlMath.h"
#include "layCellView.h"
#include "layLayoutView.h"
#include "layApplication.h"
@ -1181,7 +1182,12 @@ XORToolDialog::run_xor ()
}
XORJob job (nworkers, output_mode, op, el_handling, dbu, cva, cvb, tolerances, sub_categories, layer_categories, sub_cells, sub_output_layers, rdb, rdb_cell);
for (std::vector<db::DBox>::const_iterator box = boxes.begin (); box != boxes.end (); ++box) {
double common_dbu = tl::lcm (cva->layout ().dbu (), cvb->layout ().dbu ());
for (std::vector<db::DBox>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
db::DBox box (tl::round_down (b->left (), common_dbu), tl::round_down (b->bottom (), common_dbu),
tl::round_up (b->right (), common_dbu), tl::round_up (b->top (), common_dbu));
// compute the tiles if required
db::Box box_a, box_b, box_out;
@ -1189,33 +1195,34 @@ XORToolDialog::run_xor ()
db::Coord box_width_b = 0, box_height_b = 0, box_height_out = 0;
size_t ntiles_w = 1, ntiles_h = 1;
if (box->empty ()) {
if (box.empty ()) {
ntiles_w = ntiles_h = 0;
} else if (tile_size > 0.0) {
box_a = db::Box (*box * (1.0 / cva->layout ().dbu ()));
box_b = db::Box (*box * (1.0 / cvb->layout ().dbu ()));
box_out = db::Box (*box * (1.0 / dbu));
ntiles_w = std::max (size_t (1), size_t (floor (box->width () / tile_size + 0.5)));
ntiles_h = std::max (size_t (1), size_t (floor (box->height () / tile_size + 0.5)));
box_width_a = box_a.width () / ntiles_w;
box_height_a = box_a.height () / ntiles_h;
box_width_b = box_b.width () / ntiles_w;
box_height_b = box_b.height () / ntiles_h;
box_width_out = box_out.width () / ntiles_w;
box_height_out = box_out.height () / ntiles_h;
} else {
box_a = db::Box (*box * (1.0 / cva->layout ().dbu ()));
box_b = db::Box (*box * (1.0 / cvb->layout ().dbu ()));
box_out = db::Box (*box * (1.0 / dbu));
box_a = db::Box (box * (1.0 / cva->layout ().dbu ()));
box_b = db::Box (box * (1.0 / cvb->layout ().dbu ()));
box_out = db::Box (box * (1.0 / dbu));
if (tile_size > 0.0) {
ntiles_w = std::max (size_t (1), size_t (floor (box.width () / tile_size + 0.5)));
ntiles_h = std::max (size_t (1), size_t (floor (box.height () / tile_size + 0.5)));
double box_width = tl::round_up (box.width () / ntiles_w, common_dbu);
double box_height = tl::round_up (box.height () / ntiles_h, common_dbu);
box_width_a = db::coord_traits<db::Coord>::rounded (box_width / cva->layout ().dbu ());
box_height_a = db::coord_traits<db::Coord>::rounded (box_height / cva->layout ().dbu ());
box_width_b = db::coord_traits<db::Coord>::rounded (box_width / cvb->layout ().dbu ());
box_height_b = db::coord_traits<db::Coord>::rounded (box_height / cvb->layout ().dbu ());
box_width_out = db::coord_traits<db::Coord>::rounded (box_width / dbu);
box_height_out = db::coord_traits<db::Coord>::rounded (box_height / dbu);
}
}

View File

@ -26,30 +26,116 @@
#include "tlAssert.h"
#include <cmath>
namespace tl
{
/**
* @brief Compute the largest common divider of two numbers using the euclidian method
* @brief A generic less operator
*/
template <class T>
T lcd (T a, T b)
bool less (T a, T b)
{
while (true) {
if (a < b) {
b %= a;
if (b == 0) {
return a;
}
} else if (b < a) {
a %= b;
if (a == 0) {
return b;
}
} else {
return a;
}
return a < b;
}
/**
* @brief A generic equal operator
*/
template <class T>
bool equal (T a, T b)
{
return a == b;
}
/**
* @brief A generalization of the modulo operator
*/
template <class T>
T modulo (T a, T b)
{
return a % b;
}
/**
* @brief A common uncertainty value for double compares
* This implementation uses an uncertainty value of 1e-10
* which is suitable for values in the order of 1.
*/
const double epsilon = 1e-10;
/**
* @brief A specialization for double values
*/
bool less (double a, double b)
{
return a < b - tl::epsilon;
}
/**
* @brief A specialization for double values
*/
bool equal (double a, double b)
{
return fabs (a - b) < tl::epsilon;
}
/**
* @brief A specialization of the modulo operator for doubles
* a % b == a - b * floor (a / b)
*/
double modulo (double a, double b)
{
return a - b * floor (a / b + tl::epsilon);
}
/**
* @brief Compute the greatest common divider of two numbers using the euclidian method
*/
template <class T>
T gcd (T a, T b)
{
while (! equal (b, T (0))) {
T h = modulo (a, b);
a = b;
b = h;
}
return a;
}
/**
* @brief Compute the lowest common multiple of two numbers using the euclidian method
*/
template <class T>
T lcm (T a, T b)
{
return a * (b / gcd (a, b));
}
/**
* @brief Rounding down to the closest multiple of g
*/
double round_down (double x, double g)
{
return g * floor (x / g + tl::epsilon);
}
/**
* @brief Rounding up to the closest multiple of g
*/
double round_up (double x, double g)
{
return g * ceil (x / g - tl::epsilon);
}
/**
* @brief Rounding to the closest multiple of g
* A value of (n+1/2)*g is rounded down.
*/
double round (double x, double g)
{
return g * floor (0.5 + x / g - tl::epsilon);
}
}

View File

@ -26,15 +26,62 @@
TEST(1)
{
int x;
x = tl::lcd (17, 6);
x = tl::gcd (17, 6);
EXPECT_EQ (x, 1);
x = tl::lcd (27, 6);
x = tl::gcd (27, 6);
EXPECT_EQ (x, 3);
x = tl::lcd (30, 6);
x = tl::gcd (30, 6);
EXPECT_EQ (x, 6);
x = tl::lcd (31*17, 371*17);
x = tl::gcd (31*17, 371*17);
EXPECT_EQ (x, 17);
x = tl::lcd (702*17, 372*17);
x = tl::gcd (702*17, 372*17);
EXPECT_EQ (x, 102);
EXPECT_EQ (tl::less (100, 200), true);
EXPECT_EQ (tl::less (200, 100), false);
EXPECT_EQ (tl::less (100, 100), false);
EXPECT_EQ (tl::equal (200, 100), false);
EXPECT_EQ (tl::equal (100, 100), true);
EXPECT_EQ (tl::less (0.1, 0.2), true);
EXPECT_EQ (tl::less (0.2, 0.1), false);
EXPECT_EQ (tl::less (0.1, 0.1), false);
EXPECT_EQ (tl::less (0.1, 0.1 + 1e-7), true);
EXPECT_EQ (tl::less (0.1, 0.1 + 1e-10), false);
EXPECT_EQ (tl::equal (0.2, 0.1), false);
EXPECT_EQ (tl::equal (0.1, 0.1), true);
EXPECT_EQ (tl::equal (0.1, 0.1 + 1e-7), false);
EXPECT_EQ (tl::equal (0.1, 0.1 + 1e-12), true);
double d;
d = tl::gcd (702*1.7, 372*1.7);
EXPECT_EQ (tl::equal (d, 10.2), true);
d = tl::gcd (0.0025, 0.001);
EXPECT_EQ (tl::equal (d, 0.0005), true);
d = tl::gcd (0.0025, 0.001 + 1e-12);
EXPECT_EQ (tl::equal (d, 0.0005), true);
d = tl::lcm (0.0025, 0.001);
EXPECT_EQ (tl::equal (d, 0.005), true);
d = tl::lcm (0.0025, 0.001 + 1e-12);
EXPECT_EQ (tl::equal (d, 0.005), true);
EXPECT_EQ (tl::equal (tl::round_down (1.3, 1.0), 1.0), true);
EXPECT_EQ (tl::equal (tl::round_down (-1.3, 1.0), -2.0), true);
EXPECT_EQ (tl::equal (tl::round_down (1.0 + 1e-7, 1.0), 1.0), true);
EXPECT_EQ (tl::equal (tl::round_down (1.0 - 1e-7, 1.0), 0.0), true);
EXPECT_EQ (tl::equal (tl::round_down (1.0 - 1e-12, 1.0), 1.0), true);
EXPECT_EQ (tl::equal (tl::round_up (1.3, 1.0), 2.0), true);
EXPECT_EQ (tl::equal (tl::round_up (-1.3, 1.0), -1.0), true);
EXPECT_EQ (tl::equal (tl::round_up (1.0 - 1e-7, 1.0), 1.0), true);
EXPECT_EQ (tl::equal (tl::round_up (1.0 + 1e-7, 1.0), 2.0), true);
EXPECT_EQ (tl::equal (tl::round_up (1.0 + 1e-12, 1.0), 1.0), true);
EXPECT_EQ (tl::equal (tl::round (1.3, 1.0), 1.0), true);
EXPECT_EQ (tl::equal (tl::round (1.5, 1.0), 1.0), true);
EXPECT_EQ (tl::equal (tl::round (1.5 + 1e-12, 1.0), 1.0), true);
EXPECT_EQ (tl::equal (tl::round (1.5 + 1e-7, 1.0), 2.0), true);
EXPECT_EQ (tl::equal (tl::round (1.7, 1.0), 2.0), true);
EXPECT_EQ (tl::equal (tl::round (-1.3, 1.0), -1.0), true);
EXPECT_EQ (tl::equal (tl::round (-1.7, 1.0), -2.0), true);
}