@@ -15,23 +15,50 @@ limitations under the License.
1515#ifndef TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ARG_MIN_MAX_H_
1616#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ARG_MIN_MAX_H_
1717
18+ #include < cmath>
1819#include < functional>
20+ #include < type_traits>
1921
2022#include " tensorflow/lite/kernels/internal/types.h"
2123
2224namespace tflite {
2325
2426namespace reference_ops {
2527
28+ // Default comparator for non-floating-point types (no NaN possible).
2629template <typename T>
27- std::function<bool (T, T)> GetComparefunction (bool is_arg_max) {
30+ typename std::enable_if<!std::is_floating_point<T>::value,
31+ std::function<bool (T, T)>>::type
32+ GetComparefunction (bool is_arg_max) {
2833 if (is_arg_max) {
2934 return std::greater<T>();
3035 } else {
3136 return std::less<T>();
3237 }
3338}
3439
40+ // NaN-aware comparator for floating-point types.
41+ // Matches TensorFlow eager semantics: NaN is treated as "less than any finite
42+ // value" for ArgMax and "greater than any finite value" for ArgMin. A NaN
43+ // candidate never replaces anything; a finite candidate always replaces a NaN
44+ // accumulator. For all-NaN inputs the first index is returned.
45+ template <typename T>
46+ typename std::enable_if<std::is_floating_point<T>::value,
47+ std::function<bool (T, T)>>::type
48+ GetComparefunction (bool is_arg_max) {
49+ if (is_arg_max) {
50+ return [](T candidate, T current) {
51+ return !std::isnan (candidate) &&
52+ (std::isnan (current) || candidate > current);
53+ };
54+ } else {
55+ return [](T candidate, T current) {
56+ return !std::isnan (candidate) &&
57+ (std::isnan (current) || candidate < current);
58+ };
59+ }
60+ }
61+
3562template <typename T1 , typename T2 , typename T3 , typename Cmp>
3663void ArgMinMax (const RuntimeShape& input1_shape, const T1 * input1_data,
3764 const T3 * input2_data, const RuntimeShape& output_shape,
0 commit comments