Skip to content

Commit a362e18

Browse files
committed
add DelinearizedIndexesRange
ghstack-source-id: c8e09aa ghstack-comment-id: 2691804929 Pull Request resolved: pytorch/executorch#8859
1 parent 001175f commit a362e18

File tree

6 files changed

+206
-2
lines changed

6 files changed

+206
-2
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
#pragma once
10+
11+
#include <algorithm>
12+
#include <array>
13+
#include <cstdint>
14+
#include <iterator>
15+
16+
#include <executorch/runtime/core/exec_aten/exec_aten.h>
17+
#include <executorch/runtime/core/exec_aten/util/tensor_dimension_limit.h>
18+
19+
namespace torch::executor {
20+
21+
namespace internal {
22+
class DelinearizedIndexesIterator {
23+
public:
24+
using difference_type = ssize_t;
25+
using value_type = std::array<std::size_t, ::executorch::runtime::kTensorDimensionLimit>;
26+
using reference = const value_type&;
27+
using pointer = const value_type*;
28+
using iterator_category = std::forward_iterator_tag;
29+
30+
DelinearizedIndexesIterator() = default;
31+
32+
explicit DelinearizedIndexesIterator(const Tensor& t)
33+
: idx_(0), dim_(t.dim()), shape_(t.sizes()) {
34+
}
35+
36+
struct make_end_t {
37+
explicit constexpr make_end_t() = default;
38+
};
39+
40+
DelinearizedIndexesIterator(make_end_t, const Tensor& t)
41+
: idx_(t.numel()) {}
42+
43+
bool operator==(const DelinearizedIndexesIterator& rhs) const {
44+
return idx_ == rhs.idx_;
45+
}
46+
47+
bool operator!=(const DelinearizedIndexesIterator& rhs) const {
48+
return !operator==(rhs);
49+
}
50+
51+
reference operator*() const {
52+
return repr_;
53+
}
54+
55+
pointer operator->() const {
56+
return &repr_;
57+
}
58+
59+
DelinearizedIndexesIterator& operator++() {
60+
idx_++;
61+
for (auto ii = dim_ - 1; ii >= 0; --ii) {
62+
repr_[ii]++;
63+
ET_DCHECK(repr_[ii] <= shape_[ii]);
64+
if ET_LIKELY (repr_[ii] < shape_[ii]) {
65+
break;
66+
} else {
67+
repr_[ii] = 0;
68+
}
69+
}
70+
return *this;
71+
}
72+
73+
DelinearizedIndexesIterator operator++(int) {
74+
auto it = *this;
75+
operator++();
76+
return it;
77+
}
78+
79+
difference_type operator-(const DelinearizedIndexesIterator& rhs) const {
80+
return difference_type(idx_ - rhs.idx_);
81+
}
82+
83+
private:
84+
std::size_t idx_ = 0;
85+
value_type repr_ = {0,};
86+
ssize_t dim_;
87+
ArrayRef<exec_aten::SizesType> shape_;
88+
};
89+
} // namespace internal
90+
91+
class DelinearizedIndexesRange {
92+
public:
93+
using iterator = internal::DelinearizedIndexesIterator;
94+
95+
DelinearizedIndexesRange(const Tensor& t) :
96+
tensor_(t) {}
97+
98+
iterator begin() const {
99+
return iterator(tensor_);
100+
}
101+
102+
iterator end() {
103+
return iterator(iterator::make_end_t(), tensor_);
104+
}
105+
private:
106+
const Tensor& tensor_;
107+
};
108+
} // namespace torch::executor

kernels/portable/cpu/util/targets.bzl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,19 @@ def define_common_targets():
280280
visibility = ["//executorch/kernels/portable/cpu/..."],
281281
)
282282

283+
runtime.cxx_library(
284+
name = "delinearized_indexes_range",
285+
exported_headers = ["delinearized_indexes_range.h"],
286+
deps = [
287+
"//executorch/runtime/core/exec_aten:lib",
288+
"//executorch/runtime/core/exec_aten/util:tensor_dimension_limit",
289+
],
290+
visibility = [
291+
"//executorch/...",
292+
"@EXECUTORCH_CLIENTS",
293+
],
294+
)
295+
283296
# Utility functions that can be used by operators that perform reduction
284297
for aten_mode in get_aten_mode_options():
285298
suffix = "_aten" if aten_mode else ""

kernels/portable/cpu/util/test/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..)
1919

2020
include(${EXECUTORCH_ROOT}/build/Test.cmake)
2121

22-
set(_test_srcs broadcast_test.cpp reduce_test.cpp)
22+
set(_test_srcs broadcast_test.cpp delinearized_indexes_range_test.cpp
23+
reduce_test.cpp
24+
)
2325

2426
et_cxx_test(
2527
kernels_portable_cpu_util_test SOURCES ${_test_srcs} EXTRA_LIBS
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
#include <executorch/kernels/portable/cpu/util/delinearized_indexes_range.h>
10+
#include <executorch/runtime/core/exec_aten/testing_util/tensor_factory.h>
11+
12+
#include <gtest/gtest.h>
13+
14+
using executorch::aten::ScalarType;
15+
using executorch::aten::Tensor;
16+
using executorch::runtime::testing::TensorFactory;
17+
using torch::executor::DelinearizedIndexesRange;
18+
19+
TEST(DelinearizedIndexesRangeTest, Empty) {
20+
TensorFactory<ScalarType::Int> tf;
21+
22+
Tensor a = tf.make({0}, {});
23+
ASSERT_EQ(a.numel(), 0);
24+
bool loop_entered = false;
25+
for (auto _ : DelinearizedIndexesRange(a)) {
26+
loop_entered = true;
27+
}
28+
EXPECT_FALSE(loop_entered);
29+
}
30+
31+
TEST(DelinearizedIndexesRangeTest, OneD) {
32+
TensorFactory<ScalarType::Int> tf;
33+
34+
Tensor a = tf.zeros({5});
35+
DelinearizedIndexesRange r(a);
36+
std::vector<typename DelinearizedIndexesRange::iterator::value_type> v(r.begin(), r.end());
37+
int idx = 0;
38+
for (const auto& elem: v) {
39+
EXPECT_EQ(elem[0], idx++);
40+
}
41+
}
42+
43+
TEST(DelinearizedIndexesRangeTest, ThreeD) {
44+
TensorFactory<ScalarType::Int> tf;
45+
Tensor a = tf.zeros({3, 2, 3});
46+
DelinearizedIndexesRange r(a);
47+
std::vector<typename DelinearizedIndexesRange::iterator::value_type> v(r.begin(), r.end());
48+
std::vector<typename DelinearizedIndexesRange::iterator::value_type> expected = {
49+
{0, 0, 0},
50+
{0, 0, 1},
51+
{0, 0, 2},
52+
{0, 1, 0},
53+
{0, 1, 1},
54+
{0, 1, 2},
55+
{1, 0, 0},
56+
{1, 0, 1},
57+
{1, 0, 2},
58+
{1, 1, 0},
59+
{1, 1, 1},
60+
{1, 1, 2},
61+
{2, 0, 0},
62+
{2, 0, 1},
63+
{2, 0, 2},
64+
{2, 1, 0},
65+
{2, 1, 1},
66+
{2, 1, 2},
67+
};
68+
EXPECT_EQ(v, expected);
69+
}

kernels/portable/cpu/util/test/targets.bzl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ def define_common_targets():
1212
],
1313
)
1414

15+
runtime.cxx_test(
16+
name = "delinearized_indexes_range_test",
17+
srcs = ["delinearized_indexes_range_test.cpp"],
18+
deps = [
19+
"//executorch/kernels/portable/cpu/util:delinearized_indexes_range",
20+
"//executorch/runtime/core/exec_aten:lib",
21+
"//executorch/runtime/core/exec_aten/testing_util:tensor_util",
22+
],
23+
)
24+
1525
runtime.cxx_test(
1626
name = "reduce_test",
1727
srcs = ["reduce_test.cpp"],

test/utils/OSSTestConfig.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"op_fast_hadamard_transform_test.cpp"
88
],
99
"additional_libs": [
10-
"custom_ops"
10+
"custom_ops",
11+
"dumb_fht"
1112
]
1213
},
1314
{
@@ -62,6 +63,7 @@
6263
"directory": "kernels/portable/cpu/util/test",
6364
"sources": [
6465
"broadcast_test.cpp",
66+
"delinearized_indexes_range_test.cpp",
6567
"reduce_test.cpp"
6668
],
6769
"additional_libs": [

0 commit comments

Comments
 (0)