• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2016 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 #include "tensorflow/core/framework/allocator.h"
17 #include "tensorflow/core/framework/fake_input.h"
18 #include "tensorflow/core/framework/node_def_builder.h"
19 #include "tensorflow/core/framework/op_kernel.h"
20 #include "tensorflow/core/framework/tensor.h"
21 #include "tensorflow/core/framework/tensor_testutil.h"
22 #include "tensorflow/core/framework/types.h"
23 #include "tensorflow/core/kernels/ops_testutil.h"
24 #include "tensorflow/core/lib/core/status_test_util.h"
25 #include "tensorflow/core/platform/test.h"
26 
27 namespace tensorflow {
28 
29 namespace {
30 
31 class SparseAddOpTest : public OpsTestBase {
32  protected:
33   template <typename T>
MakeOp()34   void MakeOp() {
35     DataType value_type = tensorflow::DataTypeToEnum<T>::value;
36     DataType thresh_type = value_type;
37     if (std::is_same<T, std::complex<float>>::value) {
38       thresh_type = DT_FLOAT;
39     } else if (std::is_same<T, std::complex<double>>::value) {
40       thresh_type = DT_DOUBLE;
41     }
42 
43     TF_ASSERT_OK(NodeDefBuilder("sparseadd", "SparseAdd")
44                      .Input(FakeInput(DT_INT64))
45                      .Input(FakeInput(value_type))
46                      .Input(FakeInput(DT_INT64))
47                      .Input(FakeInput(DT_INT64))
48                      .Input(FakeInput(value_type))
49                      .Input(FakeInput(DT_INT64))
50                      .Input(FakeInput(thresh_type))
51                      .Attr("Treal", thresh_type)
52                      .Finalize(node_def()));
53     TF_ASSERT_OK(InitOp());
54   }
55 };
56 
TEST_F(SparseAddOpTest,TwoD_AddSparseTensorWithSelf)57 TEST_F(SparseAddOpTest, TwoD_AddSparseTensorWithSelf) {
58   MakeOp<float>();
59 
60   // [    1]
61   // [2    ]
62   // [3   4]
63 
64   const auto indices_shape = TensorShape({4, 2});
65   std::initializer_list<int64> in{0, 1, 1, 0, 2, 0, 2, 1};
66   const gtl::ArraySlice<int64> indices(in);
67   std::initializer_list<int64> sh{3, 2};
68   const gtl::ArraySlice<int64> shape(sh);
69 
70 #define ADD_TENSOR_INPUT()                                  \
71   AddInputFromArray<int64>(indices_shape, indices);         \
72   AddInputFromArray<float>(TensorShape({4}), {1, 2, 3, 4}); \
73   AddInputFromArray<int64>(TensorShape({2}), shape);
74 
75   ADD_TENSOR_INPUT();
76   ADD_TENSOR_INPUT();
77   AddInputFromArray<float>(TensorShape({}), {0.0});
78 #undef ADD_TENSOR_INPUT
79 
80   TF_ASSERT_OK(RunOpKernel());
81 
82   Tensor expected_indices(allocator(), DT_INT64, indices_shape);
83   test::FillValues<int64>(&expected_indices, indices);
84   test::ExpectTensorEqual<int64>(expected_indices, *GetOutput(0));
85 
86   Tensor expected_values(allocator(), DT_FLOAT, {4});
87   test::FillValues<float>(&expected_values, {2, 4, 6, 8});
88   test::ExpectTensorEqual<float>(expected_values, *GetOutput(1));
89 
90   Tensor expected_shape(allocator(), DT_INT64,
91                         {static_cast<int64>(shape.size())});
92   test::FillValues<int64>(&expected_shape, shape);
93   test::ExpectTensorEqual<int64>(expected_shape, *GetOutput(2));
94 }
95 
96 // [    1]     [5    ]      [5   1]
97 // [2    ]  +  [    6]  ==  [2   6]
98 // [3   4]     [     ]      [3   4]
99 #define RUN_TEST(VALTYPE)                                                   \
100   TEST_F(SparseAddOpTest, TwoD_AddSparseTensorsWithDiffIndices_##VALTYPE) { \
101     MakeOp<VALTYPE>();                                                      \
102     DataType val_dtype = tensorflow::DataTypeToEnum<VALTYPE>::value;        \
103                                                                             \
104     const auto indices_shape = TensorShape({4, 2});                         \
105     std::initializer_list<int64> in{0, 1, 1, 0, 2, 0, 2, 1};                \
106     const gtl::ArraySlice<int64> indices(in);                               \
107     std::initializer_list<int64> sh{3, 2};                                  \
108     const gtl::ArraySlice<int64> shape(sh);                                 \
109                                                                             \
110     AddInputFromArray<int64>(indices_shape, indices);                       \
111     AddInputFromArray<VALTYPE>(TensorShape({4}), {1, 2, 3, 4});             \
112     AddInputFromArray<int64>(TensorShape({2}), shape);                      \
113                                                                             \
114     AddInputFromArray<int64>(TensorShape({2, 2}), {0, 0, 1, 1});            \
115     AddInputFromArray<VALTYPE>(TensorShape({2}), {5, 6});                   \
116     AddInputFromArray<int64>(TensorShape({2}), shape);                      \
117                                                                             \
118     if (val_dtype == DT_COMPLEX64) {                                        \
119       AddInputFromArray<float>(TensorShape({}), {0});                       \
120     } else if (val_dtype == DT_COMPLEX128) {                                \
121       AddInputFromArray<double>(TensorShape({}), {0});                      \
122     } else {                                                                \
123       AddInputFromArray<VALTYPE>(TensorShape({}), {0});                     \
124     }                                                                       \
125                                                                             \
126     TF_ASSERT_OK(RunOpKernel());                                            \
127                                                                             \
128     const int expected_nnz = 6;                                             \
129     Tensor expected_indices(allocator(), DT_INT64,                          \
130                             TensorShape({expected_nnz, 2}));                \
131     test::FillValues<int64>(&expected_indices,                              \
132                             {0, 0, 0, 1, 1, 0, 1, 1, 2, 0, 2, 1});          \
133     test::ExpectTensorEqual<int64>(expected_indices, *GetOutput(0));        \
134                                                                             \
135     Tensor expected_values(allocator(), val_dtype, {expected_nnz});         \
136     test::FillValues<VALTYPE>(&expected_values, {5, 1, 2, 6, 3, 4});        \
137     test::ExpectTensorEqual<VALTYPE>(expected_values, *GetOutput(1));       \
138                                                                             \
139     Tensor expected_shape(allocator(), DT_INT64,                            \
140                           {static_cast<int64>(shape.size())});              \
141     test::FillValues<int64>(&expected_shape, shape);                        \
142     test::ExpectTensorEqual<int64>(expected_shape, *GetOutput(2));          \
143   }
144 
145 RUN_TEST(int64);
146 RUN_TEST(float);
147 RUN_TEST(double);
148 RUN_TEST(complex64);
149 RUN_TEST(complex128);
150 #undef RUN_TEST
151 
152 // Adding
153 //    [    1]
154 //    [2    ]
155 //    [3   4]
156 // to its cwise negation.
157 #define RUN_TEST(VALTYPE, THRESH)                                        \
158   TEST_F(SparseAddOpTest, TwoD_SmallValuesShouldVanish_##VALTYPE) {      \
159     MakeOp<VALTYPE>();                                                   \
160     DataType val_dtype = tensorflow::DataTypeToEnum<VALTYPE>::value;     \
161     const auto indices_shape = TensorShape({4, 2});                      \
162     std::initializer_list<int64> in{0, 1, 1, 0, 2, 0, 2, 1};             \
163     const gtl::ArraySlice<int64> indices(in);                            \
164     std::initializer_list<int64> sh{3, 2};                               \
165     const gtl::ArraySlice<int64> shape(sh);                              \
166                                                                          \
167     auto AddSparseTensor = [indices, indices_shape, shape,               \
168                             this](bool negate) {                         \
169       AddInputFromArray<int64>(indices_shape, indices);                  \
170       if (!negate) {                                                     \
171         AddInputFromArray<VALTYPE>(TensorShape({4}), {1, 2, 3, 4});      \
172       } else {                                                           \
173         AddInputFromArray<VALTYPE>(TensorShape({4}), {-1, -2, -3, -4});  \
174       }                                                                  \
175       AddInputFromArray<int64>(TensorShape({2}), shape);                 \
176     };                                                                   \
177     AddSparseTensor(false);                                              \
178     AddSparseTensor(true);                                               \
179     if (val_dtype == DT_COMPLEX64) {                                     \
180       AddInputFromArray<float>(TensorShape({}), {THRESH});               \
181     } else if (val_dtype == DT_COMPLEX128) {                             \
182       AddInputFromArray<double>(TensorShape({}), {THRESH});              \
183     } else {                                                             \
184       AddInputFromArray<VALTYPE>(TensorShape({}), {THRESH});             \
185     }                                                                    \
186                                                                          \
187     TF_ASSERT_OK(RunOpKernel());                                         \
188                                                                          \
189     Tensor expected_indices(allocator(), DT_INT64, TensorShape({0, 2})); \
190     test::ExpectTensorEqual<int64>(expected_indices, *GetOutput(0));     \
191                                                                          \
192     Tensor expected_values(allocator(), val_dtype, TensorShape({0}));    \
193     test::ExpectTensorEqual<VALTYPE>(expected_values, *GetOutput(1));    \
194                                                                          \
195     Tensor expected_shape(allocator(), DT_INT64,                         \
196                           {static_cast<int64>(shape.size())});           \
197     test::FillValues<int64>(&expected_shape, shape);                     \
198     test::ExpectTensorEqual<int64>(expected_shape, *GetOutput(2));       \
199   }
200 
201 RUN_TEST(int64, 1);
202 RUN_TEST(float, 1e-3f);
203 RUN_TEST(double, 1e-3f);
204 RUN_TEST(complex64, 1e-3f);
205 RUN_TEST(complex128, 1e-3f);
206 #undef RUN_TEST
207 
208 }  // namespace
209 
210 }  // namespace tensorflow
211