COMPMID-695:  Update Phase and Validation Wrapping

Simplify Phase reference implementation so that its results are more
inline with the CL implementation (note: NEON uses a fast arctan
approximation).

Modify validate_wrap function to limit use to Integer types only.

Change-Id: Ie4222568a8ef2587cab8e6d478745c5d0ded3d57
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/110192
Tested-by: BSG Visual Compute Jenkins server to access repositories on http://mpd-gerrit.cambridge.arm.com <bsgcomp@arm.com>
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
Reviewed-by: Gian Marco Iodice <gianmarco.iodice@arm.com>
diff --git a/tests/validation/CL/PixelWiseMultiplication.cpp b/tests/validation/CL/PixelWiseMultiplication.cpp
index 79e30c1..7431a09 100644
--- a/tests/validation/CL/PixelWiseMultiplication.cpp
+++ b/tests/validation/CL/PixelWiseMultiplication.cpp
@@ -44,7 +44,7 @@
 
 // *INDENT-OFF*
 // clang-format off
-#define WRAP_VALIDATE(TYPE, TOLERANCE) validate_wrap(CLAccessor(_target), _reference, AbsoluteTolerance<TYPE>(TOLERANCE), 0.f);
+#define VALIDATE(TYPE, TOLERANCE) validate(CLAccessor(_target), _reference, AbsoluteTolerance<TYPE>(TOLERANCE), 0.f);
 
 #define PIXEL_WISE_MULTIPLICATION_FIXTURE_DATA_TEST_CASE(TEST_NAME, FIXTURE, MODE, SHAPES, DT1, DT2, SCALE, RP, VALIDATE) \
     FIXTURE_DATA_TEST_CASE(TEST_NAME, CLPixelWiseMultiplication##FIXTURE, framework::DatasetMode::MODE,                   \
@@ -136,7 +136,7 @@
 TEST_SUITE(F16toF16)
 
 TEST_SUITE(Scale255)
-PIXEL_WISE_MULTIPLICATION_FIXTURE_DATA_TEST_CASE(RunSmall, ToF16Fixture<half_float::half>, PRECOMMIT, SmallShapes(), F16, F16, scale_255, TO_NEAREST_UP, WRAP_VALIDATE(float, 1.f))
+PIXEL_WISE_MULTIPLICATION_FIXTURE_DATA_TEST_CASE(RunSmall, ToF16Fixture<half_float::half>, PRECOMMIT, SmallShapes(), F16, F16, scale_255, TO_NEAREST_UP, VALIDATE(float, 1.f))
 TEST_SUITE_END() // Scale255
 
 TEST_SUITE_END() // F16toF16
@@ -144,7 +144,7 @@
 TEST_SUITE(F32toF32)
 
 TEST_SUITE(Scale255)
-PIXEL_WISE_MULTIPLICATION_FIXTURE_DATA_TEST_CASE(RunSmall, ToF32Fixture<float>, PRECOMMIT, SmallShapes(), F32, F32, scale_255, TO_NEAREST_UP, WRAP_VALIDATE(float, 1.f))
+PIXEL_WISE_MULTIPLICATION_FIXTURE_DATA_TEST_CASE(RunSmall, ToF32Fixture<float>, PRECOMMIT, SmallShapes(), F32, F32, scale_255, TO_NEAREST_UP, VALIDATE(float, 1.f))
 TEST_SUITE_END() // Scale255
 
 TEST_SUITE_END() // F32toF32
diff --git a/tests/validation/CPP/Phase.cpp b/tests/validation/CPP/Phase.cpp
index 4311ef0..7827cd2 100644
--- a/tests/validation/CPP/Phase.cpp
+++ b/tests/validation/CPP/Phase.cpp
@@ -34,50 +34,25 @@
 template <typename T>
 SimpleTensor<uint8_t> phase(const SimpleTensor<T> &gx, const SimpleTensor<T> &gy, PhaseType phase_type)
 {
-    const float pi           = std::atan(1) * 4;
-    const float rad_to_deg   = 180.0f / pi;
-    const float scale_factor = 128.f / 180.f;
-    const float epsilon      = 1e-9f; // used to avoid division by zero
-
-    const float ninety      = scale_factor * 90.f;
-    const float one_eighty  = scale_factor * 180.f;
-    const float two_seventy = scale_factor * 270.f;
-
-    // unsigned: map to [0-255)
-    // signed:   map to [0-180) degrees
-    const float scale = (phase_type == PhaseType::UNSIGNED) ? rad_to_deg : rad_to_deg * scale_factor;
-
+    const float           PI = std::atan(1) * 4;
     SimpleTensor<uint8_t> phase(gx.shape(), DataType::U8);
 
-    for(int i = 0; i < gx.num_elements(); ++i)
+    if(phase_type == PhaseType::UNSIGNED) // unsigned: map to [0-255)
     {
-        bool quad_two   = std::signbit(gx[i]) && !std::signbit(gy[i]);
-        bool quad_three = std::signbit(gx[i]) && std::signbit(gy[i]);
-        bool quad_four  = !std::signbit(gx[i]) && std::signbit(gy[i]);
-
-        float  x      = gy[i] / (gx[i] + epsilon);
-        double arctan = std::atan(x);
-
-        const bool is_negative = std::signbit(arctan);
-
-        // Radians to degrees conversion with applied scale factor
-        arctan = arctan * scale;
-
-        if(phase_type == PhaseType::UNSIGNED)
+        for(int i = 0; i < gx.num_elements(); ++i)
         {
-            arctan = is_negative ? arctan + 180.f : arctan;
+            float angle_deg = (std::atan2(float(gy[i]), float(gx[i])) / PI) * 180.0f;
+            phase[i]        = (angle_deg < 0.0f) ? 180.f + angle_deg : angle_deg;
         }
-        else
+    }
+    else // signed: map to [0-180) degrees
+    {
+        for(int i = 0; i < gx.num_elements(); ++i)
         {
-            arctan = is_negative ? arctan + ninety : arctan;
-
-            // Choose correct quandrant
-            arctan = quad_two ? ninety + arctan : arctan;
-            arctan = quad_three ? one_eighty + arctan : arctan;
-            arctan = quad_four ? two_seventy + arctan : arctan;
+            float angle_pi = std::atan2(gy[i], gx[i]) / PI;
+            angle_pi       = (angle_pi < 0.0f) ? 2 + angle_pi : angle_pi;
+            phase[i]       = lround(angle_pi * 128) & 0xFFu;
         }
-
-        phase[i] = saturate_cast<uint8_t>(arctan + 0.5f);
     }
 
     return phase;
diff --git a/tests/validation/NEON/PixelWiseMultiplication.cpp b/tests/validation/NEON/PixelWiseMultiplication.cpp
index 8d2ece5..b712632 100644
--- a/tests/validation/NEON/PixelWiseMultiplication.cpp
+++ b/tests/validation/NEON/PixelWiseMultiplication.cpp
@@ -43,6 +43,7 @@
 const float scale_other = 1.f / 32768.f;
 
 #define DEFAULT_VALIDATE validate(Accessor(_target), _reference);
+#define VALIDATE(TYPE, TOLERANCE) validate(Accessor(_target), _reference, AbsoluteTolerance<TYPE>(TOLERANCE), 0.f);
 #define WRAP_VALIDATE(TYPE, TOLERANCE) validate_wrap(Accessor(_target), _reference, AbsoluteTolerance<TYPE>(TOLERANCE), 0.f);
 
 // *INDENT-OFF*
@@ -190,7 +191,7 @@
 TEST_SUITE(F16toF16)
 
 TEST_SUITE(Scale255)
-PIXEL_WISE_MULTIPLICATION_FIXTURE_DATA_TEST_CASE(RunSmall, ToF16Fixture<half_float::half>, PRECOMMIT, SmallShapes(), F16, F16, scale_255, TO_NEAREST_UP, WRAP_VALIDATE(float, 1.f))
+PIXEL_WISE_MULTIPLICATION_FIXTURE_DATA_TEST_CASE(RunSmall, ToF16Fixture<half_float::half>, PRECOMMIT, SmallShapes(), F16, F16, scale_255, TO_NEAREST_UP, VALIDATE(float, 1.f))
 TEST_SUITE_END() // Scale255
 
 TEST_SUITE_END() // F16toF16
@@ -200,8 +201,8 @@
 
 TEST_SUITE(Scale255)
 PIXEL_WISE_MULTIPLICATION_DATA_TEST_CASE(F32, F32, scale_255, TO_NEAREST_UP)
-PIXEL_WISE_MULTIPLICATION_FIXTURE_DATA_TEST_CASE(RunSmall, ToF32Fixture<float>, PRECOMMIT, SmallShapes(), F32, F32, scale_255, TO_NEAREST_UP, WRAP_VALIDATE(float, 1.f))
-PIXEL_WISE_MULTIPLICATION_FIXTURE_DATA_TEST_CASE(RunLarge, ToF32Fixture<float>, NIGHTLY, LargeShapes(), F32, F32, scale_255, TO_NEAREST_UP, WRAP_VALIDATE(float, 1.f))
+PIXEL_WISE_MULTIPLICATION_FIXTURE_DATA_TEST_CASE(RunSmall, ToF32Fixture<float>, PRECOMMIT, SmallShapes(), F32, F32, scale_255, TO_NEAREST_UP, VALIDATE(float, 1.f))
+PIXEL_WISE_MULTIPLICATION_FIXTURE_DATA_TEST_CASE(RunLarge, ToF32Fixture<float>, NIGHTLY, LargeShapes(), F32, F32, scale_255, TO_NEAREST_UP, VALIDATE(float, 1.f))
 TEST_SUITE_END() // Scale255
 
 TEST_SUITE(ScaleUnity)
diff --git a/tests/validation/Validation.h b/tests/validation/Validation.h
index 7a01085..4a96dd3 100644
--- a/tests/validation/Validation.h
+++ b/tests/validation/Validation.h
@@ -236,15 +236,14 @@
 template <typename T>
 struct compare_base
 {
-    compare_base(typename T::value_type target, typename T::value_type reference, T tolerance = T(0), bool wrap_range = false)
-        : _target{ target }, _reference{ reference }, _tolerance{ tolerance }, _wrap_range{ wrap_range }
+    compare_base(typename T::value_type target, typename T::value_type reference, T tolerance = T(0))
+        : _target{ target }, _reference{ reference }, _tolerance{ tolerance }
     {
     }
 
     typename T::value_type _target{};
     typename T::value_type _reference{};
     T                      _tolerance{};
-    bool                   _wrap_range{};
 };
 
 template <typename T>
@@ -268,12 +267,6 @@
 
         using comparison_type = typename std::conditional<std::is_integral<U>::value, int64_t, U>::type;
 
-        if(this->_wrap_range)
-        {
-            const comparison_type abs_difference(std::abs(static_cast<comparison_type>(this->_target)) - std::abs(static_cast<comparison_type>(this->_reference)));
-            return abs_difference <= static_cast<comparison_type>(this->_tolerance);
-        }
-
         const comparison_type abs_difference(std::abs(static_cast<comparison_type>(this->_target) - static_cast<comparison_type>(this->_reference)));
 
         return abs_difference <= static_cast<comparison_type>(this->_tolerance);
@@ -323,7 +316,7 @@
     validate(tensor, reference, shape_to_valid_region(tensor.shape()), tolerance_value, tolerance_number);
 }
 
-template <typename T, typename U>
+template <typename T, typename U, typename = typename std::enable_if<std::is_integral<T>::value>::type>
 void validate_wrap(const IAccessor &tensor, const SimpleTensor<T> &reference, U tolerance_value, float tolerance_number)
 {
     // Validate with valid region covering the entire shape
@@ -391,7 +384,7 @@
     }
 }
 
-template <typename T, typename U>
+template <typename T, typename U, typename = typename std::enable_if<std::is_integral<T>::value>::type>
 void validate_wrap(const IAccessor &tensor, const SimpleTensor<T> &reference, const ValidRegion &valid_region, U tolerance_value, float tolerance_number)
 {
     int64_t num_mismatches = 0;
@@ -426,9 +419,23 @@
 
                 bool equal = compare<U>(target_value, reference_value, tolerance_value);
 
+                // check for wrapping
                 if(!equal)
                 {
-                    equal = compare<U>(target_value, reference_value, tolerance_value, true);
+                    if(!support::cpp11::isfinite(target_value) || !support::cpp11::isfinite(reference_value))
+                    {
+                        equal = false;
+                    }
+                    else
+                    {
+                        using limits_type = typename std::make_unsigned<T>::type;
+
+                        uint64_t max             = std::numeric_limits<limits_type>::max();
+                        uint64_t abs_sum         = std::abs(static_cast<int64_t>(target_value)) + std::abs(static_cast<int64_t>(reference_value));
+                        uint64_t wrap_difference = max - abs_sum;
+
+                        equal = wrap_difference < static_cast<uint64_t>(tolerance_value);
+                    }
                 }
 
                 if(!equal)
@@ -437,7 +444,7 @@
                     ARM_COMPUTE_TEST_INFO("channel = " << c);
                     ARM_COMPUTE_TEST_INFO("target = " << std::setprecision(5) << framework::make_printable(target_value));
                     ARM_COMPUTE_TEST_INFO("reference = " << std::setprecision(5) << framework::make_printable(reference_value));
-                    ARM_COMPUTE_TEST_INFO("tolerance = " << std::setprecision(5) << framework::make_printable(static_cast<typename U::value_type>(tolerance_value)));
+                    ARM_COMPUTE_TEST_INFO("wrap_tolerance = " << std::setprecision(5) << framework::make_printable(static_cast<typename U::value_type>(tolerance_value)));
                     framework::ARM_COMPUTE_PRINT_INFO();
 
                     ++num_mismatches;