From 42b7290fe56f781ec1a738bc3fa15220b33412a4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 27 Jul 2021 22:15:59 +0200 Subject: [PATCH] Device parameter comparer now also compares other (primary) parameters, parameters primary in both netlists are considered to be compared by default, 'ignore' feature in tolerance --- src/db/db/dbDeviceClass.cc | 110 ++++++++++++++++++---------------- src/db/db/dbDeviceClass.h | 13 +++- src/db/db/gsiDeclDbNetlist.cc | 17 +++++- testdata/ruby/dbNetlist.rb | 13 ++++ 4 files changed, 100 insertions(+), 53 deletions(-) diff --git a/src/db/db/dbDeviceClass.cc b/src/db/db/dbDeviceClass.cc index 4c27c7409..27900a7c9 100644 --- a/src/db/db/dbDeviceClass.cc +++ b/src/db/db/dbDeviceClass.cc @@ -30,8 +30,20 @@ namespace db // -------------------------------------------------------------------------------- // EqualDeviceParameters implementation -static int compare_parameters (double pa, double pb, double absolute, double relative) +// NOTE: to allow rounding errors for parameter comparison, we use +// a default relative tolerance. +const double default_relative_tolerance = 1e-6; + +const double default_absolute_tolerance = 0.0; + + +static int compare_parameters (double pa, double pb, double absolute = default_absolute_tolerance, double relative = default_relative_tolerance) { + // absolute value < 0 means: ignore this parameter (= always match) + if (absolute < 0.0) { + return 0; + } + double pa_min = pa - absolute; double pa_max = pa + absolute; @@ -57,14 +69,31 @@ EqualDeviceParameters::EqualDeviceParameters () // .. nothing yet .. } -EqualDeviceParameters::EqualDeviceParameters (size_t parameter_id) +EqualDeviceParameters::EqualDeviceParameters (size_t parameter_id, bool ignore) { - m_compare_set.push_back (std::make_pair (parameter_id, std::make_pair (0.0, 0.0))); + m_compare_set.push_back (std::make_pair (parameter_id, std::make_pair (ignore ? -1.0 : 0.0, 0.0))); } -EqualDeviceParameters::EqualDeviceParameters (size_t parameter_id, double relative, double absolute) +EqualDeviceParameters::EqualDeviceParameters (size_t parameter_id, double absolute, double relative) { - m_compare_set.push_back (std::make_pair (parameter_id, std::make_pair (relative, absolute))); + m_compare_set.push_back (std::make_pair (parameter_id, std::make_pair (std::max (0.0, absolute), std::max (0.0, relative)))); +} + +std::string EqualDeviceParameters::to_string () const +{ + std::string res; + for (std::vector > >::const_iterator c = m_compare_set.begin (); c != m_compare_set.end (); ++c) { + if (!res.empty ()) { + res += ";"; + } + res += "#" + tl::to_string (c->first) + ":"; + if (c->second.first < 0.0) { + res += "ignore"; + } else { + res += "A" + tl::to_string (c->second.first) + "/R" + tl::to_string (c->second.second); + } + } + return res; } bool EqualDeviceParameters::less (const db::Device &a, const db::Device &b) const @@ -76,6 +105,30 @@ bool EqualDeviceParameters::less (const db::Device &a, const db::Device &b) cons } } + // compare the remaining parameters with a default precision + + std::set seen; + for (std::vector > >::const_iterator c = m_compare_set.begin (); c != m_compare_set.end (); ++c) { + seen.insert (c->first); + } + + const std::vector &pd = a.device_class ()->parameter_definitions (); + for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { + + if (seen.find (p->id ()) != seen.end ()) { + continue; + } + + const db::DeviceParameterDefinition *pdb = b.device_class ()->parameter_definition (p->id ()); + if (pdb && pdb->is_primary () && p->is_primary ()) { + int cmp = compare_parameters (a.parameter_value (p->id ()), b.parameter_value (p->id ())); + if (cmp != 0) { + return cmp < 0; + } + } + + } + return false; } @@ -109,47 +162,6 @@ bool AllDeviceParametersAreEqual::less (const db::Device &a, const db::Device &b return false; } -// -------------------------------------------------------------------------------- -// PrimaryDeviceParametersAreEqual class implementation - -class DB_PUBLIC PrimaryDeviceParametersAreEqual - : public DeviceParameterCompareDelegate -{ -public: - PrimaryDeviceParametersAreEqual (double relative); - - virtual bool less (const db::Device &a, const db::Device &b) const; - -private: - double m_relative; -}; - -PrimaryDeviceParametersAreEqual::PrimaryDeviceParametersAreEqual (double relative) - : m_relative (relative) -{ - // .. nothing yet .. -} - -bool PrimaryDeviceParametersAreEqual::less (const db::Device &a, const db::Device &b) const -{ - const std::vector &pd = a.device_class ()->parameter_definitions (); - for (std::vector::const_iterator p = pd.begin (); p != pd.end (); ++p) { - const db::DeviceParameterDefinition *pdb = b.device_class ()->parameter_definition (p->id ()); - if (! pdb) { - continue; - } - if (! pdb->is_primary () && ! p->is_primary ()) { - continue; - } - int cmp = compare_parameters (a.parameter_value (p->id ()), b.parameter_value (p->id ()), 0.0, m_relative); - if (cmp != 0) { - return cmp < 0; - } - } - - return false; -} - // -------------------------------------------------------------------------------- // DeviceClass class implementation @@ -279,12 +291,8 @@ size_t DeviceClass::terminal_id_for_name (const std::string &name) const throw tl::Exception (tl::to_string (tr ("Invalid terminal name")) + ": '" + name + "'"); } -// NOTE: to allow rounding errors for parameter comparison, we use -// a default relative tolerance. -const double relative_tolerance = 1e-6; - // The default compare delegate -static PrimaryDeviceParametersAreEqual default_compare (relative_tolerance); +static EqualDeviceParameters default_compare; bool DeviceClass::less (const db::Device &a, const db::Device &b) { diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index a6306cdf8..2ab2fbd2f 100644 --- a/src/db/db/dbDeviceClass.h +++ b/src/db/db/dbDeviceClass.h @@ -309,11 +309,14 @@ class DB_PUBLIC EqualDeviceParameters { public: EqualDeviceParameters (); - EqualDeviceParameters (size_t parameter_id); + EqualDeviceParameters (size_t parameter_id, bool ignore = false); EqualDeviceParameters (size_t parameter_id, double relative, double absolute); virtual bool less (const db::Device &a, const db::Device &b) const; + // for test purposes + std::string to_string () const; + EqualDeviceParameters &operator+= (const EqualDeviceParameters &other); EqualDeviceParameters operator+ (const EqualDeviceParameters &other) const @@ -507,6 +510,14 @@ public: return m_parameter_definitions; } + /** + * @brief Gets the parameter definitions + */ + std::vector ¶meter_definitions_non_const () + { + return m_parameter_definitions; + } + /** * @brief Adds a parameter definition */ diff --git a/src/db/db/gsiDeclDbNetlist.cc b/src/db/db/gsiDeclDbNetlist.cc index 2162bb342..c98c967bf 100644 --- a/src/db/db/gsiDeclDbNetlist.cc +++ b/src/db/db/gsiDeclDbNetlist.cc @@ -908,6 +908,11 @@ db::EqualDeviceParameters *make_equal_dp (size_t param_id, double absolute, doub return new db::EqualDeviceParameters (param_id, absolute, relative); } +db::EqualDeviceParameters *make_ignore_dp (size_t param_id) +{ + return new db::EqualDeviceParameters (param_id, true); +} + Class decl_dbEqualDeviceParameters ("db", "EqualDeviceParameters", gsi::constructor ("new", &make_equal_dp, gsi::arg ("param_id"), gsi::arg ("absolute", 0.0), gsi::arg ("relative", 0.0), "@brief Creates a device parameter comparer for a single parameter.\n" @@ -921,6 +926,15 @@ Class decl_dbEqualDeviceParameters ("db", "EqualDevic "For example, when comparing parameter values of 40 and 60, a relative deviation of 0.35 means an absolute " "deviation of 17.5 (= 0.35 * average of 40 and 60) which does not make both values match." ) + + gsi::constructor ("ignore", &make_ignore_dp, gsi::arg ("param_id"), + "@brief Creates a device parameter comparer which ignores the parameter.\n" + "\n" + "This specification can be used to make a parameter ignored. Starting with version 0.27.4, all primary parameters " + "are compared. Before 0.27.4, giving a tolerance meant only those parameters are compared. To exclude a primary " + "parameter from the compare, use the 'ignore' specification for that parameter.\n" + "\n" + "This constructor has been introduced in version 0.27.4.\n" + ) + gsi::method ("+", &db::EqualDeviceParameters::operator+, gsi::arg ("other"), "@brief Combines two parameters for comparison.\n" "The '+' operator will join the parameter comparers and produce one that checks the combined parameters.\n" @@ -928,7 +942,8 @@ Class decl_dbEqualDeviceParameters ("db", "EqualDevic gsi::method ("+=", &db::EqualDeviceParameters::operator+, gsi::arg ("other"), "@brief Combines two parameters for comparison (in-place).\n" "The '+=' operator will join the parameter comparers and produce one that checks the combined parameters.\n" - ), + ) + + gsi::method ("to_string", &db::EqualDeviceParameters::to_string, "@hide"), "@brief A device parameter equality comparer.\n" "Attach this object to a device class with \\DeviceClass#equal_parameters= to make the device " "class use this comparer:\n" diff --git a/testdata/ruby/dbNetlist.rb b/testdata/ruby/dbNetlist.rb index d5820f71f..dab25415d 100644 --- a/testdata/ruby/dbNetlist.rb +++ b/testdata/ruby/dbNetlist.rb @@ -1168,6 +1168,19 @@ END end + def test_15_deviceParameterCompare + + dpc = RBA::EqualDeviceParameters::new(1) + assert_equal(dpc.to_string, "#1:A0/R0") + + dpc += RBA::EqualDeviceParameters::new(2, 1.0, 0.25) + assert_equal(dpc.to_string, "#1:A0/R0;#2:A1/R0.25") + + dpc += RBA::EqualDeviceParameters::ignore(3) + assert_equal(dpc.to_string, "#1:A0/R0;#2:A1/R0.25;#3:ignore") + + end + end load("test_epilogue.rb")