1 /* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #ifndef TENSORFLOW_CORE_KERNELS_MLIR_GENERATED_BASE_OPS_TEST_H_
17 #define TENSORFLOW_CORE_KERNELS_MLIR_GENERATED_BASE_OPS_TEST_H_
18
19 #include <string>
20
21 #include "absl/container/inlined_vector.h"
22 #include "absl/strings/string_view.h"
23 #include "llvm/ADT/STLExtras.h"
24 #include "tensorflow/core/framework/tensor_shape.h"
25
26 namespace tensorflow {
27 namespace test {
28
29 template <typename T>
30 using is_integer = llvm::is_one_of<T, int8_t, int16_t, int32_t, int64_t,
31 uint8_t, uint16_t, uint32_t, uint64_t>;
32
33 /// Helper functions to create or derive inputs of the right type and size.
34
35 template <typename T, typename LiteralT>
InputAsVector(std::initializer_list<LiteralT> input)36 absl::InlinedVector<T, 10> InputAsVector(
37 std::initializer_list<LiteralT> input) {
38 absl::InlinedVector<T, 10> result;
39 result.reserve(input.size());
40 for (const LiteralT& value : input) {
41 result.push_back(static_cast<T>(value));
42 }
43 return result;
44 }
45
46 template <typename T>
RepeatInputToMatchShape(absl::InlinedVector<T,10> input,int size)47 absl::InlinedVector<T, 10> RepeatInputToMatchShape(
48 absl::InlinedVector<T, 10> input, int size) {
49 absl::InlinedVector<T, 10> result;
50 for (int i = 0; i < size; i++) {
51 auto value = input[i % input.size()];
52 result.push_back(value);
53 }
54 return result;
55 }
56
57 template <typename T>
RepeatElements(absl::InlinedVector<T,10> input,int num_repeats)58 absl::InlinedVector<T, 10> RepeatElements(absl::InlinedVector<T, 10> input,
59 int num_repeats) {
60 absl::InlinedVector<T, 10> result;
61 for (T value : input) {
62 for (int i = 0; i < num_repeats; ++i) {
63 result.push_back(value);
64 }
65 }
66 return result;
67 }
68
69 /// Helper functions to get default input shapes.
70
71 TensorShape DefaultInputShape();
72
73 /// Helper functions to configure tests.
74
75 struct OpsTestConfig {
76 bool add_t = true;
77 bool add_tout = false;
78 // Only used for gpu_unary_ops_test.
79 bool expect_buffer_reuse = true;
80 bool expect_strictly_equal = false;
81 bool supress_tolerance = false;
82 // Negative atol/rtol will make ExpectClose use the default.
83 double atol = -1;
84 double rtol = -1;
85 std::string input_attribute = "T";
86 std::string output_attribute = "Tout";
87 bool jit_compilation = false;
ExpectStrictlyEqualOpsTestConfig88 OpsTestConfig ExpectStrictlyEqual() {
89 OpsTestConfig config = *this;
90 config.expect_strictly_equal = true;
91 return config;
92 }
SuppressToleranceOpsTestConfig93 OpsTestConfig SuppressTolerance() {
94 OpsTestConfig config = *this;
95 config.supress_tolerance = true;
96 return config;
97 }
NoBufferReuseOpsTestConfig98 OpsTestConfig NoBufferReuse() {
99 OpsTestConfig config = *this;
100 config.expect_buffer_reuse = false;
101 return config;
102 }
AddToutOpsTestConfig103 OpsTestConfig AddTout() {
104 OpsTestConfig config = *this;
105 config.add_tout = true;
106 return config;
107 }
NoTOpsTestConfig108 OpsTestConfig NoT() {
109 OpsTestConfig config = *this;
110 config.add_t = false;
111 return config;
112 }
RTolOpsTestConfig113 OpsTestConfig RTol(double new_rtol) {
114 OpsTestConfig config = *this;
115 config.rtol = new_rtol;
116 return config;
117 }
ATolOpsTestConfig118 OpsTestConfig ATol(double new_atol) {
119 OpsTestConfig config = *this;
120 config.atol = new_atol;
121 return config;
122 }
InputAttributeOpsTestConfig123 OpsTestConfig InputAttribute(const std::string& attr) {
124 OpsTestConfig config = *this;
125 config.input_attribute = attr;
126 return config;
127 }
OutputAttributeOpsTestConfig128 OpsTestConfig OutputAttribute(const std::string& attr) {
129 OpsTestConfig config = *this;
130 config.output_attribute = attr;
131 return config;
132 }
JITCompilationOpsTestConfig133 OpsTestConfig JITCompilation() {
134 OpsTestConfig config = *this;
135 config.jit_compilation = true;
136 return config;
137 }
138 };
139
140 /// Helper functions to get more specific input data.
141
142 template <typename T, std::enable_if_t<
143 llvm::is_one_of<T, Eigen::half, float, double>::value,
144 bool> = true>
NearZeroAndExtremeInput()145 absl::InlinedVector<T, 10> NearZeroAndExtremeInput() {
146 return InputAsVector<T, double>({-std::numeric_limits<double>::infinity(),
147 -0.1, -0.0, 0.0, 0.1,
148 std::numeric_limits<double>::infinity()});
149 }
150
151 template <typename T, std::enable_if_t<is_integer<T>::value, bool> = true>
NearZeroAndExtremeInput()152 absl::InlinedVector<T, 10> NearZeroAndExtremeInput() {
153 return InputAsVector<T, T>({std::numeric_limits<T>::min(),
154 std::numeric_limits<T>::min() + 1, -1, 0, 1,
155 std::numeric_limits<T>::max()});
156 }
157
158 template <typename T, std::enable_if_t<
159 llvm::is_one_of<T, Eigen::half, float, double>::value,
160 bool> = true>
NearZeroInfAndNanInput()161 absl::InlinedVector<T, 10> NearZeroInfAndNanInput() {
162 return InputAsVector<T, double>({-std::numeric_limits<double>::quiet_NaN(),
163 -std::numeric_limits<double>::infinity(),
164 -0.1, -0.0, 0.0, 0.1,
165 std::numeric_limits<double>::infinity(),
166 std::numeric_limits<double>::quiet_NaN()});
167 }
168
169 template <typename T, std::enable_if_t<
170 llvm::is_one_of<T, Eigen::half, float, double>::value,
171 bool> = true>
DefaultInputGreaterEqualOne()172 absl::InlinedVector<T, 10> DefaultInputGreaterEqualOne() {
173 return test::InputAsVector<T, double>(
174 {18.0, 9.0, 1.0, std::numeric_limits<T>::max(), 42.0, 2.0, 1.0,
175 std::sqrt(std::numeric_limits<T>::max()), 9.0, 18.0});
176 }
177
178 template <typename T, std::enable_if_t<
179 llvm::is_one_of<T, Eigen::half, float, double>::value,
180 bool> = true>
DefaultInputGreaterThanZero()181 absl::InlinedVector<T, 10> DefaultInputGreaterThanZero() {
182 return test::InputAsVector<T, double>({18.0, 9.0, 1e-6, 1.0, 0.1, 1e-6, 0.1,
183 0.2, 0.3, 0.5, 0.7, 0.9, 9.0, 18.0});
184 }
185
186 template <typename T, std::enable_if_t<
187 llvm::is_one_of<T, Eigen::half, float, double>::value,
188 bool> = true>
DefaultInputGreaterOrEqualToZero()189 absl::InlinedVector<T, 10> DefaultInputGreaterOrEqualToZero() {
190 return test::InputAsVector<T, double>({18.0, 9.0, 1e-6, 0.0, 0.1, 1e-6, 0.1,
191 0.2, 0.3, 0.5, 0.7, 0.9, 9.0, 18.0});
192 }
193
194 template <typename T, std::enable_if_t<
195 llvm::is_one_of<T, Eigen::half, float, double>::value,
196 bool> = true>
DefaultInputNonZero()197 absl::InlinedVector<T, 10> DefaultInputNonZero() {
198 return test::InputAsVector<T, double>({18.0, 9.0, 1e-6, -0.1, 0.1, 1e-6, 0.1,
199 0.2, 0.3, 0.5, 0.7, 0.9, 9.0, 18.0});
200 }
201
202 template <typename T, std::enable_if_t<is_integer<T>::value, bool> = true>
DefaultInputNonZero()203 absl::InlinedVector<T, 10> DefaultInputNonZero() {
204 return test::InputAsVector<T, int>({-18, -9, -1, 1, 3, 4, 5, 7, 9, 10, 18});
205 }
206
207 template <typename T, std::enable_if_t<
208 llvm::is_one_of<T, Eigen::half, float, double>::value,
209 bool> = true>
DefaultInputBetweenZeroAndOne()210 absl::InlinedVector<T, 10> DefaultInputBetweenZeroAndOne() {
211 return test::InputAsVector<T, double>({-0.999, -0.9, -0.8, -0.5, -0.1, -0.001,
212 -0, 0, 0.001, 0.1, 0.5, 0.8, 0.9,
213 0.999});
214 }
215
216 template <typename T, std::enable_if_t<is_integer<T>::value, bool> = true>
DefaultInputLessThanBitwidth()217 absl::InlinedVector<T, 10> DefaultInputLessThanBitwidth() {
218 auto max_shift = sizeof(T) * 8 - 1;
219 absl::InlinedVector<T, 10> v;
220 for (auto i = 0; i < max_shift; ++i) v.push_back(i);
221 return v;
222 }
223
224 /// Helper functions to get default input data.
225
226 template <typename T, std::enable_if_t<is_integer<T>::value, bool> = true>
DefaultInput()227 absl::InlinedVector<T, 10> DefaultInput() {
228 return InputAsVector<T, int>({-18, -9, -1, 0, 0, 1, 1, 2, 3, 5, 7, 9, 9, 18});
229 }
230
231 template <typename T, std::enable_if_t<
232 llvm::is_one_of<T, Eigen::half, float, double>::value,
233 bool> = true>
DefaultInput()234 absl::InlinedVector<T, 10> DefaultInput() {
235 return InputAsVector<T, double>({-18.0, -9.0, -0.7, -0.5, -0.3, -0.2, -0.1,
236 -1e-6, -0.0, 0.0, 1e-6, 0.1, 0.2, 0.3, 0.5,
237 0.7, 0.9, 18.0});
238 }
239
240 template <typename T,
241 std::enable_if_t<llvm::is_one_of<T, std::complex<float>,
242 std::complex<double>>::value,
243 bool> = true>
DefaultInput()244 absl::InlinedVector<T, 10> DefaultInput() {
245 using ElementType = typename T::value_type;
246 auto input = test::DefaultInput<ElementType>();
247 absl::InlinedVector<T, 10> complex_input;
248 for (ElementType value : input) {
249 complex_input.emplace_back(value, -value);
250 }
251 return complex_input;
252 }
253
254 template <typename T,
255 std::enable_if_t<llvm::is_one_of<T, std::complex<float>,
256 std::complex<double>>::value,
257 bool> = true>
ComplexInputFromValues(const absl::InlinedVector<typename T::value_type,10> & real,const absl::InlinedVector<typename T::value_type,10> & imag)258 absl::InlinedVector<T, 10> ComplexInputFromValues(
259 const absl::InlinedVector<typename T::value_type, 10>& real,
260 const absl::InlinedVector<typename T::value_type, 10>& imag) {
261 using ElementType = typename T::value_type;
262 auto input = test::DefaultInput<ElementType>();
263 absl::InlinedVector<T, 10> complex_input;
264 CHECK_EQ(real.size(), imag.size());
265 for (size_t i = 0; i < real.size() && i < imag.size(); ++i) {
266 complex_input.emplace_back(real[i], imag[i]);
267 }
268 return complex_input;
269 }
270
271 template <typename T,
272 std::enable_if_t<llvm::is_one_of<T, std::complex<float>,
273 std::complex<double>>::value,
274 bool> = true>
DefaultInputNonZero()275 absl::InlinedVector<T, 10> DefaultInputNonZero() {
276 auto real = test::DefaultInputNonZero<typename T::value_type>();
277 auto imag = real;
278 std::reverse(imag.begin(), imag.end());
279 return test::ComplexInputFromValues<T>(real, imag);
280 }
281
282 template <typename T,
283 std::enable_if_t<llvm::is_one_of<T, std::complex<float>,
284 std::complex<double>>::value,
285 bool> = true>
DefaultInputGreaterOrEqualToZero()286 absl::InlinedVector<T, 10> DefaultInputGreaterOrEqualToZero() {
287 auto real = test::DefaultInputGreaterOrEqualToZero<typename T::value_type>();
288 auto imag = real;
289 std::reverse(imag.begin(), imag.end());
290 return test::ComplexInputFromValues<T>(real, imag);
291 }
292
293 template <typename T,
294 std::enable_if_t<llvm::is_one_of<T, std::complex<float>,
295 std::complex<double>>::value,
296 bool> = true>
NearZeroInfAndNanInput()297 absl::InlinedVector<T, 10> NearZeroInfAndNanInput() {
298 using ElementType = typename T::value_type;
299 auto input = test::NearZeroInfAndNanInput<ElementType>();
300 absl::InlinedVector<ElementType, 10> real;
301 absl::InlinedVector<ElementType, 10> imag;
302 for (ElementType r : input) {
303 for (ElementType i : input) {
304 real.push_back(r);
305 imag.push_back(i);
306 }
307 }
308 return test::ComplexInputFromValues<T>(real, imag);
309 }
310
311 template <typename T,
312 std::enable_if_t<llvm::is_one_of<T, bool>::value, bool> = true>
DefaultInput()313 absl::InlinedVector<T, 10> DefaultInput() {
314 return InputAsVector<T, bool>({true, false, true, true, false});
315 }
316
317 } // namespace test
318 } // namespace tensorflow
319
320 #endif // TENSORFLOW_CORE_KERNELS_MLIR_GENERATED_BASE_OPS_TEST_H_
321