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

This commit is contained in:
Matthias Koefferlein 2021-07-27 22:15:59 +02:00
parent 37457aa02f
commit 42b7290fe5
4 changed files with 100 additions and 53 deletions

View File

@ -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<std::pair<size_t, std::pair<double, double> > >::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<size_t> seen;
for (std::vector<std::pair<size_t, std::pair<double, double> > >::const_iterator c = m_compare_set.begin (); c != m_compare_set.end (); ++c) {
seen.insert (c->first);
}
const std::vector<db::DeviceParameterDefinition> &pd = a.device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::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<db::DeviceParameterDefinition> &pd = a.device_class ()->parameter_definitions ();
for (std::vector<db::DeviceParameterDefinition>::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)
{

View File

@ -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<DeviceParameterDefinition> &parameter_definitions_non_const ()
{
return m_parameter_definitions;
}
/**
* @brief Adds a parameter definition
*/

View File

@ -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<db::EqualDeviceParameters> 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<db::EqualDeviceParameters> 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<db::EqualDeviceParameters> 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"

View File

@ -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")