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