| 1249 | |
| 1250 | template <typename DataType> |
| 1251 | bool StridedFloatTensorContentEquals(const int dim_index, int64_t left_offset, |
| 1252 | int64_t right_offset, const Tensor& left, |
| 1253 | const Tensor& right, const EqualOptions& opts) { |
| 1254 | using c_type = typename DataType::c_type; |
| 1255 | static_assert(std::is_floating_point<c_type>::value, |
| 1256 | "DataType must be a floating point type"); |
| 1257 | |
| 1258 | const auto n = left.shape()[dim_index]; |
| 1259 | const auto left_stride = left.strides()[dim_index]; |
| 1260 | const auto right_stride = right.strides()[dim_index]; |
| 1261 | if (dim_index == left.ndim() - 1) { |
| 1262 | // Leaf dimension, compare values |
| 1263 | auto left_data = left.raw_data(); |
| 1264 | auto right_data = right.raw_data(); |
| 1265 | bool result = true; |
| 1266 | |
| 1267 | auto visitor = [&](auto&& compare_func) { |
| 1268 | for (int64_t i = 0; i < n; ++i) { |
| 1269 | c_type left_value = |
| 1270 | *reinterpret_cast<const c_type*>(left_data + left_offset + i * left_stride); |
| 1271 | c_type right_value = *reinterpret_cast<const c_type*>(right_data + right_offset + |
| 1272 | i * right_stride); |
| 1273 | if (!compare_func(left_value, right_value)) { |
| 1274 | result = false; |
| 1275 | return; |
| 1276 | } |
| 1277 | } |
| 1278 | }; |
| 1279 | |
| 1280 | VisitFloatingEquality<c_type>(opts, std::move(visitor)); |
| 1281 | return result; |
| 1282 | } |
| 1283 | |
| 1284 | // Outer dimension, recurse into inner |
| 1285 | for (int64_t i = 0; i < n; ++i) { |
| 1286 | if (!StridedFloatTensorContentEquals<DataType>(dim_index + 1, left_offset, |
| 1287 | right_offset, left, right, opts)) { |
| 1288 | return false; |
| 1289 | } |
| 1290 | left_offset += left_stride; |
| 1291 | right_offset += right_stride; |
| 1292 | } |
| 1293 | return true; |
| 1294 | } |
| 1295 | |
| 1296 | template <typename DataType> |
| 1297 | bool FloatTensorEquals(const Tensor& left, const Tensor& right, |