modify tolerance policy
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
#include "reference_tolerance_policy.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace fesa::test {
|
||||
namespace {
|
||||
|
||||
bool IsFiniteFamily(const ReferenceToleranceFamily& family) {
|
||||
if (family.identity.empty() || family.components.empty() ||
|
||||
family.rows.empty()) {
|
||||
return false;
|
||||
}
|
||||
return std::all_of(family.rows.begin(), family.rows.end(),
|
||||
[](const ReferenceToleranceRow& row) {
|
||||
return std::isfinite(row.fesa_value) &&
|
||||
std::isfinite(row.reference_value);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ReferenceToleranceEvaluation ReferenceTolerancePolicy::Evaluate(
|
||||
const std::vector<ReferenceToleranceFamily>& families) {
|
||||
ReferenceToleranceEvaluation evaluation{true, {}, true, {}};
|
||||
evaluation.families.reserve(families.size());
|
||||
|
||||
for (const auto& family : families) {
|
||||
if (!IsFiniteFamily(family)) {
|
||||
return {false, "nonfinite-comparison-value", false, {}};
|
||||
}
|
||||
|
||||
ReferenceToleranceFamilyDecision decision{};
|
||||
decision.identity = family.identity;
|
||||
decision.components = family.components;
|
||||
decision.blocking = family.blocking;
|
||||
decision.row_count = family.rows.size();
|
||||
decision.rows.reserve(family.rows.size());
|
||||
for (const auto& row : family.rows) {
|
||||
decision.reference_scale =
|
||||
(std::max)(decision.reference_scale, std::abs(row.reference_value));
|
||||
}
|
||||
decision.near_zero_band = kNearZeroRatio * decision.reference_scale;
|
||||
|
||||
double error_norm = 0.0;
|
||||
for (std::size_t index = 0U; index < family.rows.size(); ++index) {
|
||||
const auto& row = family.rows[index];
|
||||
const double absolute_error =
|
||||
std::abs(row.fesa_value - row.reference_value);
|
||||
if (!std::isfinite(absolute_error)) {
|
||||
return {false, "nonfinite-comparison-value", false, {}};
|
||||
}
|
||||
error_norm = std::hypot(error_norm, absolute_error);
|
||||
if (!std::isfinite(error_norm)) {
|
||||
return {false, "nonfinite-comparison-value", false, {}};
|
||||
}
|
||||
if (absolute_error > decision.maximum_absolute_error) {
|
||||
decision.maximum_absolute_error = absolute_error;
|
||||
decision.worst_row = index;
|
||||
}
|
||||
|
||||
ReferenceToleranceRowDecision row_decision{};
|
||||
row_decision.absolute_error = absolute_error;
|
||||
if (decision.reference_scale == 0.0) {
|
||||
++decision.near_zero_count;
|
||||
row_decision.threshold = 0.0;
|
||||
row_decision.branch = ReferenceToleranceBranch::kZeroScaleExact;
|
||||
row_decision.passed = absolute_error == 0.0;
|
||||
} else if (std::abs(row.reference_value) <= decision.near_zero_band) {
|
||||
++decision.near_zero_count;
|
||||
row_decision.threshold = decision.near_zero_band;
|
||||
row_decision.branch = ReferenceToleranceBranch::kNearZero;
|
||||
row_decision.passed = absolute_error <= row_decision.threshold;
|
||||
} else {
|
||||
row_decision.threshold =
|
||||
kRelativeTolerance * std::abs(row.reference_value);
|
||||
row_decision.relative_error =
|
||||
absolute_error / std::abs(row.reference_value);
|
||||
row_decision.relative_error_applicable = true;
|
||||
row_decision.branch = ReferenceToleranceBranch::kRelative;
|
||||
row_decision.passed = row_decision.relative_error <= kRelativeTolerance;
|
||||
}
|
||||
decision.rows.push_back(row_decision);
|
||||
}
|
||||
|
||||
const bool rows_passed = std::all_of(
|
||||
decision.rows.begin(), decision.rows.end(),
|
||||
[](const ReferenceToleranceRowDecision& row) { return row.passed; });
|
||||
if (decision.reference_scale == 0.0) {
|
||||
decision.relative_rms = 0.0;
|
||||
decision.rms_passed = rows_passed;
|
||||
if (!rows_passed) {
|
||||
decision.diagnostic_code = "zero-reference-scale-nonzero-error";
|
||||
}
|
||||
} else {
|
||||
const double rms =
|
||||
error_norm / std::sqrt(static_cast<double>(family.rows.size()));
|
||||
decision.relative_rms = rms / decision.reference_scale;
|
||||
if (!std::isfinite(decision.relative_rms)) {
|
||||
return {false, "nonfinite-comparison-value", false, {}};
|
||||
}
|
||||
decision.rms_passed = decision.relative_rms <= kRelativeRmsTolerance;
|
||||
}
|
||||
decision.passed = rows_passed && decision.rms_passed;
|
||||
if (decision.blocking && !decision.passed) {
|
||||
evaluation.passed = false;
|
||||
}
|
||||
evaluation.families.push_back(std::move(decision));
|
||||
}
|
||||
|
||||
return evaluation;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user