Home | History | Annotate | Download | only in ops
      1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 
      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/node_def_builder.h"
     17 #include "tensorflow/core/framework/node_def_util.h"
     18 #include "tensorflow/core/framework/op.h"
     19 #include "tensorflow/core/framework/shape_inference.h"
     20 #include "tensorflow/core/framework/shape_inference_testutil.h"
     21 #include "tensorflow/core/framework/tensor.pb.h"
     22 #include "tensorflow/core/framework/tensor_shape.pb.h"
     23 #include "tensorflow/core/framework/tensor_testutil.h"
     24 #include "tensorflow/core/lib/core/status_test_util.h"
     25 #include "tensorflow/core/platform/test.h"
     26 #include "tensorflow/core/public/version.h"
     27 
     28 namespace tensorflow {
     29 
     30 TEST(ArrayOpsTest, UnravelIndex_ShapeFn) {
     31   ShapeInferenceTestOp op("UnravelIndex");
     32 
     33   INFER_OK(op, "?;?", "?");
     34 
     35   INFER_OK(op, "[];[?]", "[d1_0]");
     36 
     37   INFER_OK(op, "[4,5];[?]", "[d1_0,20]");
     38   INFER_OK(op, "[2,3,4];[?]", "[d1_0,24]");
     39   INFER_OK(op, "?;[?]", "?");
     40   INFER_OK(op, "[?];[?]", "[d1_0,?]");
     41 
     42   INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;[1,1]");
     43 }
     44 
     45 TEST(ArrayOpsTest, Pack_ShapeFn) {
     46   ShapeInferenceTestOp op("Pack");
     47   auto set_axis = [&op](int axis) {
     48     int n = 3;
     49     std::vector<NodeDefBuilder::NodeOut> src_list;
     50     src_list.reserve(n);
     51     for (int i = 0; i < n; ++i) src_list.emplace_back("a", 0, DT_FLOAT);
     52     TF_ASSERT_OK(NodeDefBuilder("test", "Pack")
     53                      .Input(src_list)
     54                      .Attr("N", n)
     55                      .Attr("axis", axis)
     56                      .Finalize(&op.node_def));
     57   };
     58 
     59   set_axis(0);
     60   INFER_OK(op, "?;?;?", "?");
     61 
     62   for (int axis : {0, -3}) {
     63     set_axis(axis);
     64     INFER_OK(op, "?;?;?", "?");
     65     INFER_OK(op, "[1,3];[1,3];?", "[3,d0_0|d1_0,d0_1|d1_1]");
     66     INFER_OK(op, "[?,3];[1,3];?", "[3,d1_0,d0_1|d1_1]");
     67     INFER_OK(op, "[?,?];[1,3];?", "[3,d1_0,d1_1]");
     68   }
     69   for (int axis : {1, -2}) {
     70     set_axis(axis);
     71     INFER_OK(op, "?;?;?", "?");
     72     INFER_OK(op, "[1,3];[1,3];?", "[d0_0|d1_0,3,d0_1|d1_1]");
     73     INFER_OK(op, "[?,3];[1,3];?", "[d1_0,3,d0_1|d1_1]");
     74     INFER_OK(op, "[?,?];[1,3];?", "[d1_0,3,d1_1]");
     75   }
     76   for (int axis : {2, -1}) {
     77     set_axis(axis);
     78     INFER_OK(op, "?;?;?", "?");
     79     INFER_OK(op, "[1,3];[1,3];?", "[d0_0|d1_0,d0_1|d1_1,3]");
     80     INFER_OK(op, "[?,3];[1,3];?", "[d1_0,d0_1|d1_1,3]");
     81     INFER_OK(op, "[?,?];[1,3];?", "[d1_0,d1_1,3]");
     82   }
     83 
     84   set_axis(-4);
     85   INFER_ERROR("Invalid axis: -4; must be in [-3,3)", op, "[1,3];[1,3];?");
     86   set_axis(3);
     87   INFER_ERROR("Invalid axis: 3; must be in [-3,3)", op, "[1,3];[1,3];?");
     88 
     89   set_axis(0);
     90 
     91   // Check that both components of error message are there.
     92   INFER_ERROR("Shapes must be equal rank, but are 3 and 2", op,
     93               "[1,2,3];?;[1,4]");
     94   INFER_ERROR("From merging shape 0 with other shapes.", op, "[1,2,3];?;[1,4]");
     95 }
     96 
     97 TEST(ArrayOpsTest, UnPack_ShapeFn) {
     98   ShapeInferenceTestOp op("Unpack");
     99   auto set_axis_and_num = [&op](int axis, int num) {
    100     TF_ASSERT_OK(NodeDefBuilder("test", "Unpack")
    101                      .Input("a", 0, DT_FLOAT)
    102                      .Attr("axis", axis)
    103                      .Attr("num", num)
    104                      .Finalize(&op.node_def));
    105   };
    106 
    107   set_axis_and_num(0, 1);
    108   INFER_OK(op, "?", "?");
    109 
    110   for (int axis : {0, -3}) {
    111     set_axis_and_num(axis, 1);
    112     INFER_OK(op, "?", "?");
    113     INFER_OK(op, "[1,2,3]", "[d0_1,d0_2]");
    114     INFER_OK(op, "[?,?,?]", "[d0_1,d0_2]");
    115   }
    116   for (int axis : {1, -2}) {
    117     set_axis_and_num(axis, 2);
    118     INFER_OK(op, "[1,2,3]", "[d0_0,d0_2];[d0_0,d0_2]");
    119     INFER_OK(op, "[?,?,?]", "[d0_0,d0_2];[d0_0,d0_2]");
    120   }
    121   for (int axis : {2, -1}) {
    122     set_axis_and_num(axis, 3);
    123     INFER_OK(op, "[1,2,3]", "[d0_0,d0_1];[d0_0,d0_1];[d0_0,d0_1]");
    124     INFER_OK(op, "[?,?,?]", "[d0_0,d0_1];[d0_0,d0_1];[d0_0,d0_1]");
    125   }
    126 
    127   set_axis_and_num(2, 2);
    128   INFER_ERROR("Dimension must be 2 but is 3", op, "[1,2,3]");
    129 
    130   set_axis_and_num(-4, 3);
    131   INFER_ERROR("Invalid axis: -4; must be in [-3,3)", op, "[1,2,3]");
    132   set_axis_and_num(3, 3);
    133   INFER_ERROR("Invalid axis: 3; must be in [-3,3)", op, "[1,2,3]");
    134 }
    135 
    136 TEST(ArrayOpsTest, Const_ShapeFn) {
    137   ShapeInferenceTestOp op("Const");
    138   TensorProto tensor_proto;
    139   auto* shape_proto = tensor_proto.mutable_tensor_shape();
    140   auto rebuild_node_def = [&op, &tensor_proto]() {
    141     TF_ASSERT_OK(NodeDefBuilder("test", "Const")
    142                      .Attr("value", tensor_proto)
    143                      .Finalize(&op.node_def));
    144   };
    145 
    146   TensorShape{}.AsProto(shape_proto);
    147   rebuild_node_def();
    148   INFER_OK(op, "", "[]");
    149   TensorShape{1, 2, 3, 4}.AsProto(shape_proto);
    150   rebuild_node_def();
    151   INFER_OK(op, "", "[1,2,3,4]");
    152 
    153   shape_proto->add_dim()->set_size(-1);
    154   rebuild_node_def();
    155   INFER_ERROR("Shape [1,2,3,4,?] is not fully defined", op, "");
    156 }
    157 
    158 TEST(ArrayOpsTest, UnchangedShapes_ShapeFn) {
    159   for (const char* op_name : {
    160            "CheckNumerics",
    161            "Identity",
    162            "RefIdentity",
    163            "QuantizeAndDequantize",
    164            "StopGradient",
    165            "ZerosLike",
    166            "OnesLike",
    167        }) {
    168     ShapeInferenceTestOp op(op_name);
    169     INFER_OK(op, "?", "in0");
    170     INFER_OK(op, "[]", "in0");
    171     INFER_OK(op, "[1,2,?,4,5]", "in0");
    172   }
    173 
    174   // inputs 1 and 2 are ignored; input 0 is transferred to output 0.
    175   ShapeInferenceTestOp op("MatrixBandPart");
    176   INFER_OK(op, "?;?;?", "in0");
    177   INFER_OK(op, "[];?;?", "in0");
    178   INFER_OK(op, "[1,2,?,4,5];?;?", "in0");
    179 }
    180 
    181 TEST(ArrayOpsTest, GuaranteeConst_ShapeFn) {
    182   ShapeInferenceTestOp op("GuaranteeConst");
    183   INFER_OK(op, "?", "in0");
    184   INFER_OK(op, "[]", "in0");
    185   INFER_OK(op, "[1,2,?,4,5]", "in0");
    186 }
    187 
    188 TEST(ArrayOpsTest, Identity_ShapeFnHandles) {
    189   const char* op_name = "Identity";
    190   ShapeInferenceTestOp op(op_name);
    191   // Check that handle dtypes are preserved.
    192   const OpRegistrationData* op_reg_data;
    193   TF_ASSERT_OK(OpRegistry::Global()->LookUp(op.name, &op_reg_data));
    194   std::vector<
    195       std::unique_ptr<std::vector<std::pair<TensorShapeProto, DataType>>>>
    196       handle_data;
    197   handle_data.emplace_back(
    198       new std::vector<std::pair<TensorShapeProto, DataType>>{
    199           {TensorShapeProto(), DT_BOOL}});
    200   shape_inference::InferenceContext c(TF_GRAPH_DEF_VERSION, &op.node_def,
    201                                       op_reg_data->op_def, {TensorShapeProto()},
    202                                       {}, {}, handle_data);
    203   TF_ASSERT_OK(c.construction_status());
    204   ASSERT_TRUE(op_reg_data->shape_inference_fn != nullptr);
    205   TF_ASSERT_OK(c.Run(op_reg_data->shape_inference_fn));
    206 
    207   const auto* shapes_and_types = c.output_handle_shapes_and_types(0);
    208   ASSERT_TRUE(shapes_and_types != nullptr);
    209   ASSERT_EQ(1, shapes_and_types->size());
    210   EXPECT_EQ((*shapes_and_types)[0].dtype, DT_BOOL);
    211 }
    212 
    213 TEST(ArrayOpsTest, Diag_ShapeFn) {
    214   ShapeInferenceTestOp op("Diag");
    215   INFER_OK(op, "?", "?");
    216   INFER_OK(op, "[1,?,3]", "[d0_0,d0_1,d0_2,d0_0,d0_1,d0_2]");
    217   INFER_OK(op, "[?,1,2,3]", "[d0_0,d0_1,d0_2,d0_3,d0_0,d0_1,d0_2,d0_3]");
    218   INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, "[]");
    219 }
    220 
    221 TEST(ArrayOpsTest, DiagPart_ShapeFn) {
    222   ShapeInferenceTestOp op("DiagPart");
    223   INFER_OK(op, "?", "?");
    224   INFER_OK(op, "[1,?,?,4]", "[d0_0,d0_3]");
    225   INFER_OK(op, "[1,?,3,?,4,3]", "[d0_0,d0_4,d0_2|d0_5]");
    226   INFER_OK(op, "[1,2,3,?,?,?,?,4]", "[d0_0,d0_1,d0_2,d0_7]");
    227   INFER_ERROR("Input must have even and non-zero rank", op, "[]");
    228   INFER_ERROR("Input must have even and non-zero rank", op, "[?]");
    229   INFER_ERROR("Input must have even and non-zero rank", op, "[1,2,3]");
    230   INFER_ERROR("Dimensions must be equal, but are 2 and 10", op, "[1,2,?,10]");
    231 }
    232 
    233 TEST(ArrayOpsTest, MatrixDiag_ShapeFn) {
    234   ShapeInferenceTestOp op("MatrixDiag");
    235   INFER_OK(op, "?", "?");
    236   INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, "[]");
    237   INFER_OK(op, "[?]", "[d0_0,d0_0]");
    238   INFER_OK(op, "[1,?,?,4]", "[d0_0,d0_1,d0_2,d0_3,d0_3]");
    239 }
    240 
    241 TEST(ArrayOpsTest, MatrixDiagPart_ShapeFn) {
    242   ShapeInferenceTestOp op("MatrixDiagPart");
    243   INFER_OK(op, "?", "?");
    244   INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, "[?]");
    245   INFER_OK(op, "[?,1,2,2]", "[d0_0,d0_1,d0_2|d0_3]");
    246   INFER_OK(op, "[?,1,2,3]", "[d0_0,d0_1,d0_2]");
    247   INFER_OK(op, "[?,1,3,2]", "[d0_0,d0_1,d0_3]");
    248 }
    249 
    250 TEST(ArrayOpsTest, Reverse_ShapeFn) {
    251   ShapeInferenceTestOp op("Reverse");
    252   INFER_OK(op, "?;?", "in0");
    253   INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[]");
    254   INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;[?,2]");
    255   INFER_ERROR("Shape must be rank 4 but is rank 3", op, "[1,2,3];[4]");
    256   INFER_ERROR("reverse does not work on tensors with more than 8 dimensions",
    257               op, "[1,2,3,4,5,6,7,8,9];[9]");
    258   INFER_OK(op, "[1,2,3,?];[4]", "in0");
    259   INFER_OK(op, "[1,2,3,?,5,6,7,8];[8]", "in0");
    260 }
    261 
    262 TEST(ArrayOpsTest, ReverseV2_ShapeFn) {
    263   ShapeInferenceTestOp op("ReverseV2");
    264   INFER_OK(op, "?;?", "in0");
    265   INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[]");
    266   INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;[?,2]");
    267   INFER_OK(op, "[1,2,3];[2]", "in0");
    268   INFER_ERROR("reverse does not work on tensors with more than 8 dimensions",
    269               op, "[1,2,3,4,5,6,7,8,9];[9]");
    270   INFER_OK(op, "[1,2,3,?];[4]", "in0");
    271   INFER_OK(op, "[1,2,3,?,5,6,7,8];[8]", "in0");
    272 }
    273 
    274 TEST(ArrayOpsTest, Fill_ShapeFn) {
    275   ShapeInferenceTestOp op("Fill");
    276   AddNodeAttr("index_type", DT_INT32, &op.node_def);
    277   op.input_tensors.resize(2);
    278   INFER_OK(op, "?;?", "?");
    279   INFER_OK(op, "[?];?", "?");
    280   INFER_OK(op, "[4];?", "[?,?,?,?]");
    281 
    282   Tensor in_t = test::AsTensor<int32>({1, 2, 3, 4});
    283   op.input_tensors[0] = &in_t;
    284   INFER_OK(op, "[4];?", "[1,2,3,4]");
    285 }
    286 
    287 TEST(ArrayOpsTest, Gather_ShapeFn) {
    288   ShapeInferenceTestOp op("Gather");
    289   INFER_OK(op, "?;?", "?");
    290   INFER_OK(op, "[1,?,2];[3]", "[d1_0,d0_1,d0_2]");
    291   INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, "[];[1,2,3]");
    292 }
    293 
    294 TEST(ArrayOpsTest, GatherV2_ShapeFn) {
    295   ShapeInferenceTestOp op("GatherV2");
    296 
    297   // Tests when axis is unknown.
    298   INFER_OK(op, "?;?;?", "?");
    299   INFER_OK(op, "[1,2,3];[3];[]", "[?,?,?]");
    300   INFER_ERROR("Shape must be at least rank 1 but is rank 0", op,
    301               "[];[1,2,3];[]");
    302 
    303   // Non-scalar axis.
    304   INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1];[1,2,3];[1]");
    305 
    306   // Test when axis dim is known.
    307   Tensor axis_dim_t;
    308   op.input_tensors.resize(3);
    309   op.input_tensors[2] = &axis_dim_t;
    310 
    311   // Out of range axis.
    312   axis_dim_t = test::AsScalar(1);
    313   INFER_ERROR("Shape must be at least rank 2 but is rank 1", op,
    314               "[1];[1,2];[]");
    315 
    316   // Rank 0 indices.
    317   axis_dim_t = test::AsScalar(0);
    318   INFER_OK(op, "[1,2,3];[];[]", "[d0_1,d0_2]");
    319   axis_dim_t = test::AsScalar(1);
    320   INFER_OK(op, "[1,2,3];[];[]", "[d0_0,d0_2]");
    321   axis_dim_t = test::AsScalar(2);
    322   INFER_OK(op, "[1,2,3];[];[]", "[d0_0,d0_1]");
    323 
    324   // Rank 1 indices.
    325   axis_dim_t = test::AsScalar(0);
    326   INFER_OK(op, "[1,2,3];[5];[]", "[d1_0,d0_1,d0_2]");
    327   axis_dim_t = test::AsScalar(1);
    328   INFER_OK(op, "[1,2,3];[5];[]", "[d0_0,d1_0,d0_2]");
    329   axis_dim_t = test::AsScalar(2);
    330   INFER_OK(op, "[1,2,3];[5];[]", "[d0_0,d0_1,d1_0]");
    331 
    332   // Rank 2 indices.
    333   axis_dim_t = test::AsScalar(0);
    334   INFER_OK(op, "[1,2,3];[5,6];[]", "[d1_0,d1_1,d0_1,d0_2]");
    335   axis_dim_t = test::AsScalar(1);
    336   INFER_OK(op, "[1,2,3];[5,6];[]", "[d0_0,d1_0,d1_1,d0_2]");
    337   axis_dim_t = test::AsScalar(2);
    338   INFER_OK(op, "[1,2,3];[5,6];[]", "[d0_0,d0_1,d1_0,d1_1]");
    339 
    340   // Negative axis.
    341   axis_dim_t = test::AsScalar(-3);
    342   INFER_OK(op, "[1,2,3];[5,6];[]", "[d1_0,d1_1,d0_1,d0_2]");
    343   axis_dim_t = test::AsScalar(-2);
    344   INFER_OK(op, "[1,2,3];[5,6];[]", "[d0_0,d1_0,d1_1,d0_2]");
    345   axis_dim_t = test::AsScalar(-1);
    346   INFER_OK(op, "[1,2,3];[5,6];[]", "[d0_0,d0_1,d1_0,d1_1]");
    347 }
    348 
    349 TEST(ArrayOpsTest, GatherNd_ShapeFn) {
    350   ShapeInferenceTestOp op("GatherNd");
    351 
    352   // Inputs are (params, indices).
    353   INFER_OK(op, "?;?", "?");
    354   INFER_OK(op, "[1,?,3,?];[?,0]", "[d1_0,d0_0,d0_1,d0_2,d0_3]");
    355   INFER_OK(op, "[1,?,3,?];[?,4]", "[d1_0]");
    356 
    357   // params.rank >= indices.dim(-1).
    358   INFER_ERROR("indices.shape[-1] must be <= params.rank", op, "[1,2,3];[4]");
    359 }
    360 
    361 TEST(ArrayOpsTest, Shape_ShapeFn) {
    362   ShapeInferenceTestOp op("Shape");
    363   INFER_OK(op, "?", "[?]");
    364   INFER_OK(op, "[?]", "[1]");
    365   INFER_OK(op, "[?,2,3,4,5]", "[5]");
    366 }
    367 
    368 TEST(ArrayOpsTest, ShapeN_ShapeFn) {
    369   ShapeInferenceTestOp op("ShapeN");
    370   int n = 3;
    371   std::vector<NodeDefBuilder::NodeOut> src_list;
    372   src_list.reserve(n);
    373   for (int i = 0; i < n; ++i) src_list.emplace_back("a", 0, DT_FLOAT);
    374   TF_ASSERT_OK(NodeDefBuilder("test", "ShapeN")
    375                    .Input(src_list)
    376                    .Attr("N", n)
    377                    .Finalize(&op.node_def));
    378   INFER_OK(op, "?;?;?", "[?];[?];[?]");
    379   INFER_OK(op, "[?];[?];[?]", "[1];[1];[1]");
    380   INFER_OK(op, "[?,2,3,4,5];?;[1,?,3]", "[5];[?];[3]");
    381 }
    382 
    383 TEST(ArrayOpsTest, Unique_ShapeFn) {
    384   ShapeInferenceTestOp op("Unique");
    385   INFER_OK(op, "?", "[?];in0");
    386   INFER_OK(op, "[5]", "[?];in0");
    387   INFER_ERROR(
    388       "Shape must be rank 1 but is rank 5 for '' (op: '') with input shapes: "
    389       "[1,2,3,?,5].",
    390       op, "[1,2,3,?,5]");
    391 }
    392 
    393 TEST(ArrayOpsTest, UniqueWithCounts_ShapeFn) {
    394   ShapeInferenceTestOp op("UniqueWithCounts");
    395   INFER_OK(op, "?", "[?];in0;[?]");
    396   INFER_OK(op, "[1,2,3,?,5]", "[?];in0;[?]");
    397 }
    398 
    399 TEST(ArrayOpsTest, InvertPermutation_ShapeFn) {
    400   ShapeInferenceTestOp op("InvertPermutation");
    401   INFER_OK(op, "?", "[?]");
    402   INFER_OK(op, "[1]", "in0");
    403   INFER_ERROR("Shape must be rank 1 but is rank 0", op, "[]");
    404 }
    405 
    406 TEST(ArrayOpsTest, PadD_ShapeFn) {
    407   for (const char* op_name : {"Pad", "MirrorPad"}) {
    408     ShapeInferenceTestOp op(op_name);
    409     op.input_tensors.resize(2);
    410 
    411     // Inputs are input and paddings.
    412 
    413     INFER_OK(op, "?;?", "?");
    414 
    415     // Check shape of paddings.
    416     INFER_ERROR("Shape must be rank 2 but is rank 3", op, "?;[1,2,3]");
    417     INFER_ERROR("Dimension must be 2 but is 4", op, "?;[1,4]");
    418 
    419     // input.rank and paddings.dim(0) are equal. This is the number of dims in
    420     // output.
    421     INFER_ERROR("Shape must be rank 4 but is rank 3", op, "[1,2,3];[4,2]");
    422     INFER_OK(op, "[1,2,3];?", "[?,?,?]");
    423     INFER_OK(op, "?;[3,2]", "[?,?,?]");
    424 
    425     // Make the paddings tensor known and verify padding values get added.
    426     // E.g., if padding is ((1,10),(2,20),(3,30)) then values 11,22,23 are added
    427     // to input dims to get output.
    428     Tensor paddings_t(DT_INT64, TensorShape{3, 2});
    429     test::FillValues<int64>(&paddings_t, {1, 10, 2, 20, 3, 30});
    430     op.input_tensors[1] = &paddings_t;
    431     INFER_OK(op, "[100,200,300];[3,2]", "[111,222,333]");
    432     INFER_OK(op, "[100,?,300];[3,2]", "[111,?,333]");
    433     INFER_OK(op, "?;[3,2]", "[?,?,?]");
    434     INFER_OK(op, "?;?", "[?,?,?]");
    435   }
    436 }
    437 
    438 TEST(ArrayOpsTest, PadV2_ShapeFn) {
    439   ShapeInferenceTestOp op("PadV2");
    440   op.input_tensors.resize(3);
    441 
    442   // Inputs are input, paddings and constant_values.
    443 
    444   INFER_OK(op, "?;?;?", "?");
    445 
    446   // Check shape of paddings.
    447   INFER_ERROR("Shape must be rank 2 but is rank 3", op, "?;[1,2,3];?");
    448   INFER_ERROR("Dimension must be 2 but is 4", op, "?;[1,4];?");
    449 
    450   // input.rank and paddings.dim(0) are equal. This is the number of dims in
    451   // output.
    452   INFER_ERROR("Shape must be rank 4 but is rank 3", op, "[1,2,3];[4,2];[]");
    453   INFER_OK(op, "[1,2,3];?;[]", "[?,?,?]");
    454   INFER_OK(op, "?;[3,2];[]", "[?,?,?]");
    455 
    456   // Make the paddings tensor known and verify padding values get added.
    457   // E.g., if padding is ((1,10),(2,20),(3,30)) then values 11,22,23 are added
    458   // to input dims to get output.
    459   Tensor paddings_t(DT_INT64, TensorShape{3, 2});
    460   test::FillValues<int64>(&paddings_t, {1, 10, 2, 20, 3, 30});
    461   op.input_tensors[1] = &paddings_t;
    462   INFER_OK(op, "[100,200,300];[3,2];[]", "[111,222,333]");
    463   INFER_OK(op, "[100,?,300];[3,2];[]", "[111,?,333]");
    464   INFER_OK(op, "?;[3,2];[]", "[?,?,?]");
    465   INFER_OK(op, "?;?;[]", "[?,?,?]");
    466 }
    467 
    468 TEST(ArrayOpsTest, MirrorPadGrad_ShapeFn) {
    469   ShapeInferenceTestOp op("MirrorPadGrad");
    470   op.input_tensors.resize(2);
    471 
    472   // Inputs are input and paddings.
    473   INFER_OK(op, "?;?", "?");
    474 
    475   // First padding dimension is unknown, so rank is unknown.
    476   INFER_OK(op, "?;[?,4]", "?");
    477 
    478   // Input tensor rank doesn't match paddings dimension.
    479   INFER_ERROR("must be rank 3 but is rank 2", op, "[?,?];[3,2]");
    480 
    481   // Paddings tensor is not a [rank x 2] matrix.
    482   INFER_ERROR("Dimension 1 in both shapes must be equal, but are 3 and 2", op,
    483               "[?,?,?];[3,3]");
    484 
    485   // Paddings tensor is unknown, but rank is known, so the output
    486   // shape is a rank 3 unknown shape.
    487   INFER_OK(op, "[?,?,?];[3,2]", "[?,?,?]");
    488 
    489   // Make the paddings tensor known and verify padding values get
    490   // subtracted.  E.g., if padding is ((1,10),(2,20),(3,30)) then
    491   // values 11,22,23 are subtracted to input dims to get output.
    492   Tensor paddings_t(DT_INT64, TensorShape{3, 2});
    493   test::FillValues<int64>(&paddings_t, {1, 10, 2, 20, 3, 30});
    494   op.input_tensors[1] = &paddings_t;
    495 
    496   INFER_OK(op, "[111,222,333];[3,2]", "[100,200,300]");
    497   INFER_OK(op, "[111,?,333];[3,2]", "[100,?,300]");
    498 }
    499 
    500 TEST(ArrayOpsTest, BroadcastArgs_ShapeFn) {
    501   ShapeInferenceTestOp op("BroadcastArgs");
    502   INFER_OK(op, "?;?", "[?]");
    503   INFER_OK(op, "[123];[1]", "[123]");
    504   INFER_OK(op, "[1];[123]", "[123]");
    505   INFER_OK(op, "[123];[121]", "[123]");
    506 
    507   // Rank checks
    508   INFER_ERROR("Shape must be rank 1 but is rank 0", op, "[];?");
    509   INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[]");
    510 }
    511 
    512 TEST(ArrayOpsTest, BroadcastTo_ShapeFn) {
    513   ShapeInferenceTestOp op("BroadcastTo");
    514   op.input_tensors.resize(2);
    515 
    516   INFER_OK(op, "?;[?]", "?");
    517   INFER_OK(op, "[];[1]", "[?]");
    518   INFER_OK(op, "[1];[1]", "[?]");
    519   INFER_OK(op, "[1];[2]", "[?,?]");
    520   INFER_OK(op, "[2,2];[3]", "[?,d0_0,d0_1]");
    521 
    522   // Rank checks
    523   INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;[?,?]");
    524   INFER_ERROR("Shape must be rank 1 but is rank 0", op, "[2];[]");
    525   INFER_ERROR("Shape must be at most rank 1 but is rank 2", op, "[2,2];[1]");
    526 
    527   Tensor shape_t(DT_INT64, TensorShape{3});
    528   test::FillValues<int64>(&shape_t, {2, 10, 3});
    529   op.input_tensors[1] = &shape_t;
    530   INFER_OK(op, "[1,?,1];[3]", "[2,10,3]");
    531   INFER_OK(op, "[1,1,1];[3]", "[2,10,3]");
    532   INFER_OK(op, "[10,1];[3]", "[2,d0_0,3]");
    533   INFER_ERROR("Dimensions must be equal, but are 3 and 2 for", op,
    534               "[3,1,1];[3]");
    535   INFER_ERROR("Dimensions must be equal, but are 2 and 10 for", op,
    536               "[2,2,1];[3]");
    537 }
    538 
    539 TEST(ArrayOpsTest, BroadcastGradientArgs_ShapeFn) {
    540   ShapeInferenceTestOp op("BroadcastGradientArgs");
    541   // Output is always two unknown vectors.
    542   INFER_OK(op, "?;?", "[?];[?]");
    543   INFER_OK(op, "[123];[456]", "[?];[?]");
    544 
    545   // Rank checks
    546   INFER_ERROR("Shape must be rank 1 but is rank 0", op, "[];?");
    547   INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[]");
    548 }
    549 
    550 TEST(ArrayOpsTest, ListDiff_ShapeFn) {
    551   ShapeInferenceTestOp op("BroadcastGradientArgs");
    552   // Output is always two matching unknown vectors.
    553   INFER_OK(op, "?;?", "[?];[?]");
    554   INFER_OK(op, "[123];[456]", "[?];[?]");
    555 
    556   // Rank checks
    557   INFER_ERROR("Shape must be rank 1 but is rank 0", op, "[];?");
    558   INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[]");
    559 }
    560 
    561 TEST(ArrayOpsTest, MatrixSetDiag_ShapeFn) {
    562   ShapeInferenceTestOp op("MatrixSetDiag");
    563 
    564   // Inputs are input and diagonal.
    565 
    566   // Rank checks.
    567   INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, "[1];?");
    568   INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, "?;[]");
    569   INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, "[2,2];[]");
    570   INFER_ERROR("Shape must be rank 1 but is rank 2", op, "[2,2];[2,2]");
    571 
    572   // diagonal[-1] must match smallest matrix dimension.
    573   INFER_ERROR("Dimensions must be equal, but are 2 and 3", op, "[2,3];[3]");
    574 
    575   // Output matches input.
    576   INFER_OK(op, "?;?", "in0");
    577   INFER_OK(op, "[1,2,2];[1,2]", "in0");
    578   INFER_OK(op, "[1,2,3];?", "in0");
    579   INFER_OK(op, "[1,3,2];?", "in0");
    580   INFER_OK(op, "[1,?,2];[?,?]", "in0");
    581   INFER_OK(op, "[1,?,?];[?,2]", "in0");
    582 
    583   // Infer batch shape from diag when input is not fully specified.
    584   INFER_OK(op, "?;[1,2]", "[d1_0,?,?]");
    585   INFER_OK(op, "[?,?,3];[1,2]", "[d1_0,d0_1,d0_2]");
    586   INFER_OK(op, "[?,3,?];[1,2]", "[d1_0,d0_1,d0_2]");
    587   INFER_OK(op, "[?,3,2];[1,2]", "[d1_0,d0_1,d0_2]");
    588 }
    589 
    590 TEST(ArrayOpsTest, ExpandDims_ShapeFn) {
    591   ShapeInferenceTestOp op("ExpandDims");
    592   op.input_tensors.resize(2);
    593 
    594   // With unknown dim tensor value, output is unknown.
    595   INFER_OK(op, "?;?", "?");
    596   Tensor dim_t;
    597   op.input_tensors[1] = &dim_t;
    598 
    599   // Expand at front of tensor.
    600   for (int32 idx : {0, -4}) {
    601     dim_t = test::AsScalar<int32>(idx);
    602     INFER_OK(op, "?;?", "?");
    603     INFER_OK(op, "[5,?,7];?", "[1,d0_0,d0_1,d0_2]");
    604   }
    605 
    606   // Expand at middle of tensor.
    607   for (int32 idx : {1, -3}) {
    608     dim_t = test::AsScalar<int32>(idx);
    609     INFER_OK(op, "?;?", "?");
    610     INFER_OK(op, "[5,?,7];?", "[d0_0,1,d0_1,d0_2]");
    611 
    612     // Repeat with int64.
    613     dim_t = test::AsScalar<int64>(idx);
    614     INFER_OK(op, "?;?", "?");
    615     INFER_OK(op, "[5,?,7];?", "[d0_0,1,d0_1,d0_2]");
    616   }
    617   for (int32 idx : {2, -2}) {
    618     dim_t = test::AsScalar<int32>(idx);
    619     INFER_OK(op, "?;?", "?");
    620     INFER_OK(op, "[5,?,7];?", "[d0_0,d0_1,1,d0_2]");
    621 
    622     // Repeat with int64.
    623     dim_t = test::AsScalar<int64>(idx);
    624     INFER_OK(op, "?;?", "?");
    625     INFER_OK(op, "[5,?,7];?", "[d0_0,d0_1,1,d0_2]");
    626   }
    627 
    628   for (int32 idx : {3, -1}) {
    629     // Expand at the end.
    630     dim_t = test::AsScalar<int32>(idx);
    631     INFER_OK(op, "?;?", "?");
    632     INFER_OK(op, "[5,?,7];?", "[d0_0,d0_1,d0_2,1]");
    633 
    634     // Repeat with int64.
    635     dim_t = test::AsScalar<int64>(idx);
    636     INFER_OK(op, "?;?", "?");
    637     INFER_OK(op, "[5,?,7];?", "[d0_0,d0_1,d0_2,1]");
    638   }
    639   for (int32 idx : {4, -5}) {
    640     // Invalid idx.
    641     dim_t = test::AsScalar<int32>(idx);
    642     INFER_ERROR("not in the interval [-4, 3]", op, "[5,?,7];?");
    643     dim_t = test::AsScalar<int64>(idx);
    644     INFER_ERROR("not in the interval [-4, 3]", op, "[5,?,7];?");
    645   }
    646 
    647   // Expand using an input vector tensor.
    648   std::vector<int32> dims;
    649   dims.push_back(0);
    650   dim_t = test::AsTensor<int32>(dims);
    651   INFER_OK(op, "?;?", "?");
    652   INFER_OK(op, "[5,?,7];?", "[1,d0_0,d0_1,d0_2]");
    653 
    654   // Expand using too many input elements.
    655   dims.push_back(1);
    656   dim_t = test::AsTensor<int32>(dims);
    657   INFER_ERROR("'dim' input must be a tensor with a single", op, "?;?");
    658   INFER_ERROR("'dim' input must be a tensor with a single", op, "[5,6,7];?");
    659 
    660   // Examples from ExpandDims doc.
    661   dim_t = test::AsScalar<int32>(0);
    662   INFER_OK(op, "[2];[]", "[1,d0_0]");
    663   dim_t = test::AsScalar<int32>(1);
    664   INFER_OK(op, "[2];[]", "[d0_0,1]");
    665   dim_t = test::AsScalar<int32>(-1);
    666   INFER_OK(op, "[2];[]", "[d0_0,1]");
    667 }
    668 
    669 TEST(ArrayOpsTest, ImmutableConst_ShapeFn) {
    670   ShapeInferenceTestOp op("ImmutableConst");
    671 
    672   TF_ASSERT_OK(NodeDefBuilder("test", "ImmutableConst")
    673                    .Attr("dtype", DT_FLOAT)
    674                    .Attr("shape", TensorShape({1, 2, 3}))
    675                    .Attr("memory_region_name", "test_region")
    676                    .Finalize(&op.node_def));
    677   INFER_OK(op, "", "[1,2,3]");
    678 
    679   TF_ASSERT_OK(NodeDefBuilder("test", "ImmutableConst")
    680                    .Attr("dtype", DT_FLOAT)
    681                    .Attr("shape", TensorShape({}))
    682                    .Attr("memory_region_name", "test_region")
    683                    .Finalize(&op.node_def));
    684   INFER_OK(op, "", "[]");
    685 
    686   TF_ASSERT_OK(NodeDefBuilder("test", "ImmutableConst")
    687                    .Attr("dtype", DT_FLOAT)
    688                    .Attr("shape", "invalid")
    689                    .Attr("memory_region_name", "test_region")
    690                    .Finalize(&op.node_def));
    691   INFER_ERROR("AttrValue had value with type 'string' when 'shape' expected",
    692               op, "");
    693 }
    694 
    695 TEST(ArrayOpsTest, Concat_ShapeFn) {
    696   ShapeInferenceTestOp op("Concat");
    697   auto set_n = [&op](int n) {
    698     std::vector<NodeDefBuilder::NodeOut> src_list;
    699     src_list.reserve(n);
    700     for (int i = 0; i < n; ++i) src_list.emplace_back("a", 0, DT_FLOAT);
    701     TF_ASSERT_OK(NodeDefBuilder("test", "Concat")
    702                      .Input({"concat_dim", 0, DT_INT32})
    703                      .Input(src_list)
    704                      .Attr("n", n)
    705                      .Finalize(&op.node_def));
    706   };
    707 
    708   // Confirm dimension[0] of the input (the concat_dim) is a scalar.
    709   set_n(2);
    710   INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1];?;?");
    711 
    712   // Test with the input concat_dim tensor not known. This takes the known rank
    713   // of the inputs and makes a tensor of that many unknown dims.
    714   set_n(7);
    715   INFER_OK(op, "?;?;?;?;[1,2,3];?;[3,2,1];?", "[?,?,?]");
    716   set_n(4);
    717   INFER_OK(op, "?;?;?;[1,2,3,4];[4,3,2,1]", "[?,?,?,?]");
    718   INFER_OK(op, "?;?;?;?;?", "?");  // output rank unknown
    719   INFER_ERROR("Can't concatenate scalars (use tf.stack instead)", op,
    720               "?;?;?;[];[]");
    721   INFER_ERROR("Shape must be rank 2 but is rank 3", op, "?;?;?;[1,2];[1,2,3]");
    722 
    723   // Test when the concat_dim tensor is known. The concatenated dimension is
    724   // summed across all input tensors, and other dimensions are merged.
    725   Tensor concat_dim_t;
    726   op.input_tensors.push_back(&concat_dim_t);
    727   set_n(2);
    728 
    729   // Sum dim 0, merge the other two dims.
    730   for (int concat_dim : {0, -3}) {
    731     concat_dim_t = test::AsScalar(concat_dim);
    732     INFER_OK(op, "[];[100,2,?];[10,?,3]", "[110,d1_1,d2_2]");
    733     INFER_ERROR("Dimension 1 in both shapes must be equal, but are 5 and 3", op,
    734                 "[];[100,2,5];[10,?,3]");
    735     // concat_dim can't be summed, as one value is unknown.
    736     INFER_OK(op, "[];[100,2,?];[?,?,3]", "[?,d1_1,d2_2]");
    737     INFER_OK(op, "[];[?,2,?];[10,?,3]", "[?,d1_1,d2_2]");
    738   }
    739 
    740   // Test with a higher concat_dim.
    741   for (bool use_negative : {false, true}) {
    742     concat_dim_t = test::AsScalar(use_negative ? -2 : 1);
    743     INFER_OK(op, "[];[1,100,?];[?,10,3]", "[d1_0,110,d2_2]");
    744     concat_dim_t = test::AsScalar(use_negative ? -1 : 1);
    745     INFER_OK(op, "[];[1,100];[?,10]", "[d1_0,110]");
    746     INFER_OK(op, "[];[?,100];[1,10]", "[d2_0,110]");
    747 
    748     // concat_dim is out of bounds.
    749     concat_dim_t = test::AsScalar(use_negative ? -2 : 1);
    750     INFER_ERROR("Shape must be at least rank 2 but is rank 1", op,
    751                 "[];[100];[10,?]");
    752     INFER_ERROR("Shape must be at least rank 2 but is rank 1", op,
    753                 "[];[100,5];[10]");
    754   }
    755 
    756   // concat_dim is too low.
    757   concat_dim_t = test::AsScalar(-2);
    758   INFER_ERROR("Shape must be at least rank 2 but is rank 1", op,
    759               "[];[100];[10,?]");
    760   INFER_ERROR("Shape must be at least rank 2 but is rank 1", op,
    761               "[];[100,5];[10]");
    762 
    763   // Repeat successful case with several unknown inputs.
    764   set_n(5);
    765   concat_dim_t = test::AsScalar(1);
    766   INFER_OK(op, "[];?;[1,100,?];[?,?,?];[?,10,3];?", "[d2_0,?,d4_2]");
    767 }
    768 
    769 TEST(ArrayOpsTest, ConcatV2_ShapeFn) {
    770   ShapeInferenceTestOp op("ConcatV2");
    771   auto set_n = [&op](int n) {
    772     std::vector<NodeDefBuilder::NodeOut> src_list;
    773     src_list.reserve(n);
    774     for (int i = 0; i < n; ++i) src_list.emplace_back("a", 0, DT_FLOAT);
    775     TF_ASSERT_OK(NodeDefBuilder("test", "ConcatV2")
    776                      .Input(src_list)
    777                      .Input({"axis", 0, DT_INT32})
    778                      .Attr("n", n)
    779                      .Finalize(&op.node_def));
    780   };
    781 
    782   // Confirm dimension[0] of the input (the concat_dim) is a scalar.
    783   set_n(2);
    784   INFER_ERROR("Shape must be rank 0 but is rank 1", op, "?;?;[1]");
    785 
    786   // Test with the input concat_dim tensor not known. This takes the known rank
    787   // of the inputs and makes a tensor of that many unknown dims.
    788   set_n(7);
    789   INFER_OK(op, "?;?;?;?;[1,2,3];?;[3,2,1];?", "[?,?,?]");
    790   set_n(4);
    791   INFER_OK(op, "?;?;[1,2,3,4];[4,3,2,1];?", "[?,?,?,?]");
    792   INFER_OK(op, "?;?;?;?;?", "?");  // output rank unknown
    793   INFER_ERROR("Can't concatenate scalars (use tf.stack instead)", op,
    794               "?;?;[];[];?");
    795   INFER_ERROR("Shape must be rank 2 but is rank 3", op, "?;?;[1,2];[1,2,3];?");
    796 
    797   // Test when the concat_dim tensor is known. The concatenated dimension is
    798   // summed across all input tensors, and other dimensions are merged.
    799   Tensor concat_dim_t;
    800   op.input_tensors.resize(3);
    801   op.input_tensors[2] = &concat_dim_t;
    802 
    803   set_n(2);
    804 
    805   // Invalid concat dim value.
    806   // concat_dim_t = test::AsScalar(-1);
    807   // INFER_ERROR("Expected concat_dim >= 0, but got -1", op, "?;?;?");
    808 
    809   // Sum dim 0, merge the other two dims.
    810   concat_dim_t = test::AsScalar(0);
    811   INFER_OK(op, "[100,2,?];[10,?,3];[]", "[110,d0_1,d1_2]");
    812   INFER_ERROR("Dimension 1 in both shapes must be equal, but are 5 and 3", op,
    813               "[100,2,5];[10,?,3];[]");
    814   // concat_dim can't be summed, as one value is unknown.
    815   INFER_OK(op, "[100,2,?];[?,?,3];[]", "[?,d0_1,d1_2]");
    816   INFER_OK(op, "[?,2,?];[10,?,3];[]", "[?,d0_1,d1_2]");
    817 
    818   // Test with a higher concat_dim.
    819   concat_dim_t = test::AsScalar(1);
    820   INFER_OK(op, "[1,100,?];[?,10,3];[]", "[d0_0,110,d1_2]");
    821   INFER_OK(op, "[1,100];[?,10];[]", "[d0_0,110]");
    822   INFER_OK(op, "[?,100];[1,10];[]", "[d1_0,110]");
    823   // concat_dim is too high.
    824   INFER_ERROR("Shape must be at least rank 2 but is rank 1", op,
    825               "[100];[10,?];[]");
    826   INFER_ERROR("Shape must be at least rank 2 but is rank 1", op,
    827               "[100,5];[10];[]");
    828   // concat_dim is too low.
    829   concat_dim_t = test::AsScalar(-2);
    830   INFER_ERROR("Shape must be at least rank 2 but is rank 1", op,
    831               "[100];[10,?];[]");
    832   INFER_ERROR("Shape must be at least rank 2 but is rank 1", op,
    833               "[100,5];[10];[]");
    834 
    835   // Repeat successful case with several unknown inputs.
    836   op.input_tensors.resize(6);
    837   op.input_tensors[3] = nullptr;
    838   op.input_tensors[5] = &concat_dim_t;
    839   concat_dim_t = test::AsScalar(1);
    840 
    841   set_n(5);
    842   INFER_OK(op, "?;[1,100,?];[?,?,?];[?,10,3];?;[]", "[d1_0,?,d3_2]");
    843 }
    844 
    845 TEST(ArrayOpsTest, ConcatOffset_ShapeFn) {
    846   ShapeInferenceTestOp op("ConcatOffset");
    847 
    848   const int n = 4;
    849   std::vector<NodeDefBuilder::NodeOut> src_list;
    850   src_list.reserve(n);
    851   for (int i = 0; i < n; ++i) src_list.emplace_back("a", 0, DT_INT32);
    852   TF_ASSERT_OK(NodeDefBuilder("test", "ConcatOffset")
    853                    .Input({"concat_dim", 0, DT_INT32})
    854                    .Input(src_list)
    855                    .Attr("n", n)
    856                    .Finalize(&op.node_def));
    857   INFER_OK(op, "?;?;?;?;?", "in1;in2;in3;in4");
    858 }
    859 
    860 TEST(ArrayOpsTest, Reshape_ShapeFn) {
    861   ShapeInferenceTestOp op("Reshape");
    862   op.input_tensors.resize(2);
    863 
    864   // No valid shape provided.
    865   INFER_OK(op, "?;?", "?");
    866   INFER_OK(op, "[?];?", "?");
    867   INFER_OK(op, "[?];[?]", "?");
    868   INFER_OK(op, "[4];[?]", "?");
    869 
    870   // All dimensions provided.
    871   Tensor new_shape = test::AsTensor<int32>({1, 2, 3});
    872   op.input_tensors[1] = &new_shape;
    873   INFER_OK(op, "[?];[3]", "[1,2,3]");
    874   INFER_OK(op, "[6];[3]", "[1,2,3]");
    875   // The number of elements should match for the reshape to succeed.
    876   INFER_ERROR(
    877       "Cannot reshape a tensor with 12 elements to shape [1,2,3] (6 elements)",
    878       op, "[3,4];[3]");
    879 
    880   // Unknown dimensions.
    881   // Flatten:
    882   new_shape = test::AsTensor<int32>({-1});
    883   INFER_OK(op, "[?];[1]", "[d0_0]");
    884   INFER_OK(op, "[2,2];[1]", "[4]");
    885   // The first dimension is inferred:
    886   new_shape = test::AsTensor<int32>({2, -1});
    887   INFER_OK(op, "[3,4];[2]", "[2,6]");
    888   // The total number of elements must be evenly divisible by the known
    889   // dimensions.
    890   INFER_ERROR("Dimension size must be evenly divisible by 2 but is 7", op,
    891               "[7];[2]");
    892   // Multiple missing dimensions cannot be inferred.
    893   new_shape = test::AsTensor<int32>({-1, -1, 2});
    894   INFER_OK(op, "[8];[3]", "[?,?,2]");
    895 
    896   // Symbolic shape propagation
    897   new_shape = test::AsTensor<int32>({-1, 2, 3});
    898   INFER_OK(op, "[?,2,3];[3]", "[d0_0,2,3]");
    899 
    900   // Reshaping to a scalar.
    901   new_shape = test::AsTensor<int32>({});
    902   INFER_OK(op, "[1];[0]", "[]");
    903   INFER_ERROR(
    904       "Cannot reshape a tensor with 2 elements to shape [] (1 elements)", op,
    905       "[1,2];[0]");
    906 
    907   // Reshaping a tensor with no elements.
    908   new_shape = test::AsTensor<int32>({-1});
    909   INFER_OK(op, "[0];[1]", "[0]");
    910   new_shape = test::AsTensor<int32>({-1, 6});
    911   INFER_OK(op, "[0,2];[1]", "[0,6]");
    912   new_shape = test::AsTensor<int32>({0, -1});
    913   INFER_OK(op, "[0,2];[1]", "[0,?]");
    914 }
    915 
    916 TEST(ArrayOpsTest, QuantizedReshape_ShapeFn) {
    917   ShapeInferenceTestOp op("QuantizedReshape");
    918   op.input_tensors.resize(2);
    919 
    920   // First test a subset of the Reshape_ShapeFn tests. Not all are tested, as
    921   // QuantizedReshape uses the same code for the reshape part of the operation.
    922   INFER_OK(op, "?;?;?;?", "?;[];[]");
    923   INFER_OK(op, "[?];?;?;?", "?;[];[]");
    924   INFER_OK(op, "[?];[?];?;?", "?;[];[]");
    925   INFER_OK(op, "[4];[?];?;?", "?;[];[]");
    926   Tensor new_shape = test::AsTensor<int32>({1, 2, 3});
    927   op.input_tensors[1] = &new_shape;
    928   INFER_OK(op, "[?];[3];?;?", "[1,2,3];[];[]");
    929   INFER_OK(op, "[6];[3];?;?", "[1,2,3];[];[]");
    930   INFER_ERROR(
    931       "Cannot reshape a tensor with 12 elements to shape [1,2,3] (6 elements)",
    932       op, "[3,4];[3];?;?");
    933 
    934   // Test the scalar rank checks on input_min and input_max.
    935   INFER_ERROR("must be rank 0", op, "?;?;[1];?");
    936   INFER_ERROR("must be rank 0", op, "?;?;?;[1]");
    937 }
    938 
    939 TEST(ArrayOpsTest, Placeholder_ShapeFn) {
    940   {
    941     // 2D shape
    942     ShapeInferenceTestOp op("Placeholder");
    943     TensorShape shape({1, 2});
    944     TF_ASSERT_OK(NodeDefBuilder("test", "Placeholder")
    945                      .Attr("shape", shape)
    946                      .Attr("dtype", DT_FLOAT)
    947                      .Finalize(&op.node_def));
    948     INFER_OK(op, "", "[1,2]");
    949   }
    950 
    951   {
    952     // Scalar shapes are supported
    953     ShapeInferenceTestOp op("Placeholder");
    954     TensorShape shape({});
    955     TF_ASSERT_OK(NodeDefBuilder("test", "Placeholder")
    956                      .Attr("shape", shape)
    957                      .Attr("dtype", DT_FLOAT)
    958                      .Finalize(&op.node_def));
    959     INFER_OK(op, "", "[]");
    960   }
    961 
    962   {
    963     // Partial shape
    964     ShapeInferenceTestOp op("Placeholder");
    965     const int64 dims[2] = {1, -1};
    966     PartialTensorShape shape;
    967     TF_ASSERT_OK(PartialTensorShape::MakePartialShape(dims, 2, &shape));
    968     TF_ASSERT_OK(NodeDefBuilder("test", "Placeholder")
    969                      .Attr("shape", shape)
    970                      .Attr("dtype", DT_FLOAT)
    971                      .Finalize(&op.node_def));
    972     INFER_OK(op, "", "[1,?]");
    973   }
    974 
    975   {
    976     // Unknown shape
    977     ShapeInferenceTestOp op("Placeholder");
    978     PartialTensorShape shape;
    979     TF_ASSERT_OK(NodeDefBuilder("test", "Placeholder")
    980                      .Attr("shape", shape)
    981                      .Attr("dtype", DT_FLOAT)
    982                      .Finalize(&op.node_def));
    983     INFER_OK(op, "", "?");
    984   }
    985 }
    986 
    987 TEST(ArrayOpsTest, Transpose_ShapeFn) {
    988   ShapeInferenceTestOp op("Transpose");
    989   op.input_tensors.resize(2);
    990 
    991   // Missing shape information.
    992   INFER_OK(op, "?;?", "?");
    993   INFER_OK(op, "?;[?]", "?");
    994   INFER_OK(op, "?;[2]", "[?,?]");
    995   INFER_OK(op, "[?];?", "[?]");
    996   INFER_OK(op, "[?,?];[2]", "[?,?]");
    997   INFER_ERROR("Dimension must be 3 but is 2", op, "[1,2,3];[2]");
    998   Tensor perm = test::AsTensor<int32>({0});
    999   op.input_tensors[1] = &perm;
   1000   INFER_OK(op, "[?];[?]", "[d0_0]");
   1001   perm = test::AsTensor<int32>({1, 0});
   1002   INFER_OK(op, "?;[2]", "[?,?]");
   1003   INFER_OK(op, "[?,?];[2]", "[d0_1,d0_0]");
   1004   INFER_OK(op, "[1,?];[2]", "[d0_1,d0_0]");
   1005   INFER_OK(op, "?;[0]", "in0");
   1006 
   1007   // Invalid arguments.
   1008   perm = test::AsTensor<int32>({1, 2});
   1009   INFER_ERROR("perm dim 2 is out of range of input rank 2", op, "[1,2];[2]");
   1010   perm = test::AsTensor<int32>({0});
   1011   INFER_ERROR("Dimension must be 2 but is 1", op, "[1,2];[1]");
   1012 
   1013   // Larger valid cases.
   1014   perm = test::AsTensor<int32>({1, 0, 3, 4, 2});
   1015   INFER_OK(op, "[0,1,2,3,4];[5]", "[d0_1,d0_0,d0_3,d0_4,d0_2]");
   1016   INFER_OK(op, "[0,?,2,3,4];[5]", "[d0_1,d0_0,d0_3,d0_4,d0_2]");
   1017 }
   1018 
   1019 TEST(ArrayOpsTest, Bitcast_ShapeFn) {
   1020   ShapeInferenceTestOp op("Bitcast");
   1021   auto rebuild_node_def = [&op](DataType input_type, DataType output_type) {
   1022     TF_ASSERT_OK(NodeDefBuilder("test", "Bitcast")
   1023                      .Input("input", 0, input_type)
   1024                      .Attr("type", output_type)
   1025                      .Finalize(&op.node_def));
   1026   };
   1027 
   1028   rebuild_node_def(DT_FLOAT, DT_INT32);
   1029   // No valid shape provided, so output is unknown.
   1030   INFER_OK(op, "?", "?");
   1031 
   1032   // Bitcasting from two equal sizes propagates shape.
   1033   INFER_OK(op, "[1,2]", "in0");
   1034 
   1035   // Bitcasting from smaller to larger reduces the size of the last dimension.
   1036   rebuild_node_def(DT_INT32, DT_INT64);
   1037   INFER_OK(op, "[1,2]", "[d0_0]");  // last dimension matches divisor.
   1038   // TODO(vrv): Seems like a bug, or at least, too lenient.
   1039   INFER_OK(op, "[1,?]", "[d0_0]");
   1040   // 4 is divisible by 2, but the shape function signature requires
   1041   // that the last dimension matches the last value exactly.
   1042   INFER_ERROR("does not match", op, "[1,4]");
   1043   INFER_ERROR("does not match", op, "[1,3]");
   1044 
   1045   // Bitcasting from a larger type to a smaller type extends the dimension
   1046   rebuild_node_def(DT_INT64, DT_INT32);
   1047   INFER_OK(op, "[4,5]", "[d0_0,d0_1,2]");
   1048   rebuild_node_def(DT_COMPLEX128, DT_INT32);
   1049   INFER_OK(op, "[4,5]", "[d0_0,d0_1,4]");
   1050   rebuild_node_def(DT_COMPLEX128, DT_HALF);
   1051   INFER_OK(op, "[4,5]", "[d0_0,d0_1,8]");
   1052   rebuild_node_def(DT_COMPLEX128, DT_INT8);
   1053   INFER_OK(op, "[4,5]", "[d0_0,d0_1,16]");
   1054 
   1055   // Bitcasting from a POD or quantized datatype is not allowed.
   1056   rebuild_node_def(DT_STRING, DT_INT32);
   1057   INFER_ERROR("one of the type sizes is zero", op, "[1,2,3]");
   1058   rebuild_node_def(DT_INT32, DT_STRING);
   1059   INFER_ERROR("one of the type sizes is zero", op, "[1,2,3]");
   1060 }
   1061 
   1062 TEST(ArrayOpsTest, Squeeze_ShapeFn) {
   1063   ShapeInferenceTestOp op("Squeeze");
   1064 
   1065   auto rebuild_node_def = [&op](const std::vector<int32>& squeeze_dims) {
   1066     TF_ASSERT_OK(NodeDefBuilder("test", "Squeeze")
   1067                      .Input("input", 0, DT_FLOAT)
   1068                      .Attr("squeeze_dims", squeeze_dims)
   1069                      .Finalize(&op.node_def));
   1070   };
   1071 
   1072   // Default squeeze_dims = []
   1073   rebuild_node_def({});
   1074 
   1075   // No valid shape provided, so output is unknown.
   1076   INFER_OK(op, "?", "?");
   1077 
   1078   INFER_OK(op, "[1,4,1,5,1]", "[d0_1,d0_3]");
   1079 
   1080   // Squeezing all dimensions, but see some unknown values.
   1081   INFER_OK(op, "[1,?,1,?,1]", "?");
   1082 
   1083   // Test simple squeeze of an explicit dimension
   1084   rebuild_node_def({1});
   1085   INFER_OK(op, "[4,1,5]", "[d0_0,d0_2]");
   1086   // Squeezing unknown dim explicitly, assumes it's 1 at runtime.
   1087   INFER_OK(op, "[4,?,5]", "[d0_0,d0_2]");
   1088 
   1089   // Attempt to squeeze non-one dimension
   1090   INFER_ERROR("Can not squeeze dim[1]", op, "[4,6,5]");
   1091 
   1092   // Squeeze multiple dimensions
   1093   rebuild_node_def({1, 2});
   1094   INFER_OK(op, "[4,1,1,5]", "[d0_0,d0_3]");
   1095   rebuild_node_def({1, -2});
   1096   INFER_OK(op, "[4,1,1,5]", "[d0_0,d0_3]");
   1097 
   1098   // Negative squeeze dim
   1099   rebuild_node_def({-2});
   1100   INFER_OK(op, "[4,1,5]", "[d0_0,d0_2]");
   1101 
   1102   // Test validation of squeeze dimensions
   1103   rebuild_node_def({-4});
   1104   INFER_ERROR("not in [-3,3)", op, "[1,2,3]");
   1105   rebuild_node_def({3});
   1106   INFER_ERROR("not in [-3,3)", op, "[1,2,3]");
   1107 }
   1108 
   1109 TEST(ArrayOpsTest, ReverseSequence_ShapeFn) {
   1110   ShapeInferenceTestOp op("ReverseSequence");
   1111   auto rebuild_node_def = [&op](const int32 seq_dim, const int32 batch_dim) {
   1112     TF_ASSERT_OK(NodeDefBuilder("test", "ReverseSequence")
   1113                      .Input("input", 0, DT_FLOAT)
   1114                      .Input("seq_lengths", 1, DT_INT64)
   1115                      .Attr("seq_dim", seq_dim)
   1116                      .Attr("batch_dim", batch_dim)
   1117                      .Finalize(&op.node_def));
   1118   };
   1119 
   1120   rebuild_node_def(1, 2);
   1121   // No valid shape provided, so output is unknown.
   1122   INFER_OK(op, "?;[10]", "?");
   1123 
   1124   // Bad rank for seq_lengths
   1125   INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;[10,10]");
   1126 
   1127   // Validate seq_dim and batch_dim
   1128   rebuild_node_def(1, 4);
   1129   INFER_ERROR("batch_dim must be < input rank", op, "[1,2,3];[3]");
   1130   rebuild_node_def(4, 1);
   1131   INFER_ERROR("seq_dim must be < input rank", op, "[1,2,3];[3]");
   1132 
   1133   rebuild_node_def(1, 2);
   1134   INFER_OK(op, "[1,2,3];[3]", "[d0_0,d0_1,d0_2]");
   1135   // Resolves uncertainty on batch dimension by merging.
   1136   INFER_OK(op, "[1,2,?];[3]", "[d0_0,d0_1,d1_0]");
   1137   INFER_OK(op, "[1,2,3];[?]", "[d0_0,d0_1,d0_2]");
   1138 }
   1139 
   1140 TEST(ArrayOpsTest, Split_ShapeFn) {
   1141   ShapeInferenceTestOp op("Split");
   1142   op.input_tensors.resize(2);
   1143 
   1144   // No value for split_dim and no input.
   1145   TF_ASSERT_OK(NodeDefBuilder("test", "Split")
   1146                    .Input("split_dim", 0, DT_INT32)
   1147                    .Input("value", 1, DT_FLOAT)
   1148                    .Attr("num_split", 2)
   1149                    .Finalize(&op.node_def));
   1150   INFER_OK(op, "?;?", "?;?");
   1151   // If the rank is known, we know the rank of each output.
   1152   INFER_OK(op, "?;[?,?]", "[?,?];[?,?]");
   1153 
   1154   // split_dim is unknown but other inputs are known.
   1155   INFER_OK(op, "?;[1,4]", "[?,?];[?,?]");
   1156 
   1157   // split_dim is known.
   1158   Tensor split_dim = test::AsTensor<int32>({1, 2});
   1159   op.input_tensors[0] = &split_dim;
   1160   INFER_ERROR("Input must be scalar but has rank 1", op, "[?];[?,?]");
   1161   split_dim = test::AsScalar<int32>(1);
   1162   INFER_OK(op, "?;?", "?;?");
   1163   INFER_OK(op, "?;[?,?]", "[d1_0,?];[d1_0,?]");
   1164   INFER_OK(op, "?;[1,4]", "[d1_0,2];[d1_0,2]");
   1165   INFER_OK(op, "?;[1,?]", "[d1_0,?];[d1_0,?]");
   1166   INFER_ERROR("Dimension size must be evenly divisible by 2 but is 5", op,
   1167               "?;[1,5]");
   1168 
   1169   // split_dim too large.
   1170   split_dim = test::AsScalar<int32>(3);
   1171   INFER_ERROR(
   1172       "Dimension size, given by scalar input 3 must be in range [-3, 3)", op,
   1173       "?;[1,4,8]");
   1174 
   1175   // Negative split_dim.
   1176   split_dim = test::AsScalar<int32>(-1);
   1177   INFER_OK(op, "?;?", "?;?");
   1178   INFER_OK(op, "?;[?,?]", "[d1_0,?];[d1_0,?]");
   1179   INFER_OK(op, "?;[1,?]", "[d1_0,?];[d1_0,?]");
   1180   INFER_OK(op, "?;[1,4]", "[d1_0,2];[d1_0,2]");
   1181   INFER_OK(op, "?;[1,4,8]", "[d1_0,d1_1,4];[d1_0,d1_1,4]");
   1182   split_dim = test::AsScalar<int32>(-2);
   1183   INFER_OK(op, "?;[1,4,8]", "[d1_0,2,d1_2];[d1_0,2,d1_2]");
   1184   split_dim = test::AsScalar<int32>(-4);
   1185   INFER_ERROR(
   1186       "Dimension size, given by scalar input -4 must be in range [-3, 3)", op,
   1187       "?;[1,4,8]");
   1188 }
   1189 
   1190 TEST(ArrayOpsTest, Tile_ShapeFn) {
   1191   ShapeInferenceTestOp op("Tile");
   1192   op.input_tensors.resize(2);
   1193 
   1194   // No value for split_dim and no input.
   1195   TF_ASSERT_OK(NodeDefBuilder("test", "Tile")
   1196                    .Input("input", 0, DT_FLOAT)
   1197                    .Input("multiples", 1, DT_INT32)
   1198                    .Finalize(&op.node_def));
   1199 
   1200   // If both are unknown, output is unknown.
   1201   INFER_OK(op, "?;?", "?");
   1202 
   1203   // If multiples rank is unknown but input is, output rank is known.
   1204   INFER_OK(op, "[2,3,1,4];?", "[?,?,?,?]");
   1205 
   1206   // Bad rank for 'multiples'
   1207   INFER_ERROR("Shape must be rank 1 but is rank 2", op, "[2,3,1,4];[4,1]");
   1208 
   1209   // No multiples tensor available, but output rank is known from multiples.
   1210   INFER_OK(op, "?;[4]", "[?,?,?,?]");
   1211 
   1212   // Test a tile of a 4D input.
   1213   Tensor multiples = test::AsTensor<int32>({2, 3, 4, 5});
   1214   op.input_tensors[1] = &multiples;
   1215   INFER_OK(op, "[2,3,1,4];[4]", "[4,9,4,20]");
   1216   // Test 64-bit tensor type
   1217   multiples = test::AsTensor<int64>({2, 3, 4, 5});
   1218   INFER_OK(op, "[2,3,1,4];[4]", "[4,9,4,20]");
   1219 }
   1220 
   1221 TEST(ArrayOpsTest, EditDistance_ShapeFn) {
   1222   ShapeInferenceTestOp op("EditDistance");
   1223   op.input_tensors.resize(6);
   1224 
   1225   // If the shape tensors are not available, the output shape is unknown.
   1226   INFER_OK(op, "[?,?];[?];[4];[?,?];[?];[4]", "?");
   1227 
   1228   Tensor hypothesis_shape = test::AsTensor<int64>({2, 30, 4, 50});
   1229   op.input_tensors[2] = &hypothesis_shape;
   1230   Tensor truth_shape = test::AsTensor<int64>({20, 3, 40, 5});
   1231   op.input_tensors[5] = &truth_shape;
   1232   INFER_OK(op, "[?,?];[?];[4];[?,?];[?];[4]", "[20,30,40]");
   1233 
   1234   // Shape elements don't match
   1235   hypothesis_shape = test::AsTensor<int64>({2});
   1236   op.input_tensors[2] = &hypothesis_shape;
   1237   INFER_ERROR("Num elements of hypothesis_shape does not match truth_shape", op,
   1238               "[?,?];[?];[1];[?,?];[?];[4]");
   1239 }
   1240 
   1241 TEST(ArrayOpsTest, OneHot_ShapeFn) {
   1242   ShapeInferenceTestOp op("OneHot");
   1243   op.input_tensors.resize(4);
   1244   auto set_axis = [&op](int axis) {
   1245     TF_ASSERT_OK(NodeDefBuilder("test", "OneHot")
   1246                      .Input("indices", 0, DT_FLOAT)
   1247                      .Input("depth", 1, DT_INT32)
   1248                      .Input("on_value", 2, DT_FLOAT)
   1249                      .Input("off_value", 3, DT_FLOAT)
   1250                      .Attr("axis", axis)
   1251                      .Finalize(&op.node_def));
   1252   };
   1253 
   1254   // Invalid axis value.
   1255   set_axis(-2);
   1256   INFER_ERROR("axis must be >= -1", op, "?;?;?;?");
   1257   set_axis(1);
   1258 
   1259   // If indices shape is unknown, we return an unknown shape.
   1260   INFER_OK(op, "?;[];?;?", "?");
   1261 
   1262   // Depth must be scalar.
   1263   Tensor depth = test::AsTensor<int32>({1, 2});
   1264   op.input_tensors[1] = &depth;
   1265   INFER_ERROR("Input must be scalar but has rank 1", op, "?;[2];?;?");
   1266 
   1267   // Full information is available.
   1268   depth = test::AsScalar<int32>(2);
   1269   INFER_OK(op, "[1,3,4];[];?;?", "[d0_0,2,d0_1,d0_2]");
   1270   set_axis(-1);
   1271   INFER_OK(op, "[1,3,4];[];?;?", "[d0_0,d0_1,d0_2,2]");
   1272 }
   1273 
   1274 TEST(ArrayOpsTest, ExtractImagePatchesShapeTest) {
   1275   ShapeInferenceTestOp op("ExtractImagePatches");
   1276   auto set_op = [&op](const std::vector<int32>& ksizes,
   1277                       const std::vector<int32>& strides,
   1278                       const std::vector<int32>& rates, const string& padding) {
   1279     TF_ASSERT_OK(NodeDefBuilder("test", "ExtractImagePatches")
   1280                      .Input("input", 0, DT_FLOAT)
   1281                      .Attr("ksizes", ksizes)
   1282                      .Attr("strides", strides)
   1283                      .Attr("rates", rates)
   1284                      .Attr("padding", padding)
   1285                      .Finalize(&op.node_def));
   1286   };
   1287 
   1288   // Just tests that the ksize calculation with rates works.  Most of
   1289   // the other code is boilerplate that is tested by a variety of
   1290   // other ops.
   1291   //
   1292   // ksizes is 2x2.  rate rows and cols is 2, so ksize_rows and
   1293   // cols are changed to be 2 + (2 - 1) = 3.  7x7 input with 3x3
   1294   // filter and 1x1 stride gives a 5x5 output.
   1295   set_op({1, 2, 2, 1}, {1, 1, 1, 1}, {1, 2, 2, 1}, "VALID");
   1296   INFER_OK(op, "[1,7,7,2]", "[d0_0,5,5,8]");
   1297   // With ksizes as 1x1, the output depth is now exactly the last value of the
   1298   // input and output spatial is reduced as well.
   1299   set_op({1, 1, 1, 1}, {1, 1, 1, 1}, {1, 2, 2, 1}, "VALID");
   1300   INFER_OK(op, "[1,7,7,2]", "[d0_0,7,7,d0_3]");
   1301 
   1302   // Bad ksize rank
   1303   set_op({1, 2, 2, 1, 1}, {1, 1, 1, 1}, {1, 2, 2, 1}, "VALID");
   1304   INFER_ERROR(
   1305       "ExtractImagePatches requires the ksizes attribute to contain 4 values, "
   1306       "but got: 5",
   1307       op, "[1,7,7,2]");
   1308 }
   1309 
   1310 TEST(ArrayOpsTest, QuantizeAndDequantizeV2_ShapeFn) {
   1311   ShapeInferenceTestOp op("QuantizeAndDequantizeV2");
   1312   INFER_OK(op, "?;?;?", "in0");
   1313   INFER_OK(op, "[];?;?", "in0");
   1314   INFER_OK(op, "[1,2,?,4,5];?;?", "in0");
   1315 
   1316   INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1,2,?,4,5];[1];[]");
   1317   INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1,2,?,4,5];[];[1]");
   1318   INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1,2,?,4,5];[1];[1]");
   1319 }
   1320 
   1321 TEST(ArrayOpsTest, SpaceToBatch_ShapeFn) {
   1322   ShapeInferenceTestOp op("SpaceToBatch");
   1323   op.input_tensors.resize(2);
   1324   TF_ASSERT_OK(NodeDefBuilder("test", "SpaceToBatch")
   1325                    .Input("input", 0, DT_FLOAT)
   1326                    .Input("paddings", 1, DT_INT32)
   1327                    .Attr("block_size", 2)
   1328                    .Finalize(&op.node_def));
   1329 
   1330   // Paddings not known, but batch size can be computed.
   1331   INFER_OK(op, "[1,10,10,3];[2,2]", "[4,?,?,d0_3]");
   1332 
   1333   // Unknown paddings means width and height.
   1334   INFER_OK(op, "[1,10,10,3];?", "[4,?,?,d0_3]");
   1335 
   1336   // Paddings not correct shape
   1337   INFER_ERROR("rank", op, "[1,10,10,3];[4]");
   1338   INFER_ERROR("3 and 2", op, "[1,10,10,3];[2,3]");
   1339 
   1340   Tensor paddings = test::AsTensor<int32>({4, 2, 2, 4}, {{2, 2}});
   1341   op.input_tensors[1] = &paddings;
   1342   INFER_OK(op, "[1,10,10,3];[2,2]", "[4,8,8,d0_3]");
   1343   paddings = test::AsTensor<int64>({4, 2, 2, 4}, {{2, 2}});
   1344   INFER_OK(op, "[1,10,10,3];[2,2]", "[4,8,8,d0_3]");
   1345 
   1346   // Bad paddings values
   1347   paddings = test::AsTensor<int32>({1, 2, 3, 4}, {{2, 2}});
   1348   op.input_tensors[1] = &paddings;
   1349   INFER_ERROR("Dimension size must be evenly divisible by 2 but is 13", op,
   1350               "[1,10,10,3];[2,2]");
   1351 
   1352   // Negative paddsings
   1353   paddings = test::AsTensor<int32>({1, -2, 3, 4}, {{2, 2}});
   1354   op.input_tensors[1] = &paddings;
   1355   INFER_ERROR("cannot be negative", op, "[1,10,10,3];[2,2]");
   1356 }
   1357 
   1358 TEST(ArrayOpsTest, SpaceToBatchND_ShapeFn) {
   1359   ShapeInferenceTestOp op("SpaceToBatchND");
   1360   op.input_tensors.resize(3);
   1361   TF_ASSERT_OK(NodeDefBuilder("test", "SpaceToBatchND")
   1362                    .Input("input", 0, DT_FLOAT)
   1363                    .Input("block_shape", 1, DT_INT32)
   1364                    .Input("paddings", 2, DT_INT32)
   1365                    .Finalize(&op.node_def));
   1366 
   1367   // Verify that input shape and paddings shape can be unknown.
   1368   INFER_OK(op, "?;[2];?", "?");
   1369 
   1370   // Only number of input dimensions is known.
   1371   INFER_OK(op, "[?,?,?,?];[2];?", "[?,?,?,d0_3]");
   1372 
   1373   // Dimensions are partially known.
   1374   INFER_OK(op, "[?,?,?,2];[2];?", "[?,?,?,d0_3]");
   1375 
   1376   {
   1377     // Dimensions are partially known, block_shape known.
   1378     Tensor block_shape = test::AsTensor<int32>({2, 3});
   1379     op.input_tensors[1] = &block_shape;
   1380     INFER_OK(op, "[3,?,?,2];[2];?", "[18,?,?,d0_3]");
   1381 
   1382     // Dimensions are partially known, block_shape and paddings known.
   1383     {
   1384       Tensor paddings = test::AsTensor<int32>({1, 1, 0, 1}, {{2, 2}});
   1385       op.input_tensors[2] = &paddings;
   1386       INFER_OK(op, "[3,?,2,2];[2];[2,2]", "[18,?,1,d0_3]");
   1387       op.input_tensors[2] = nullptr;
   1388     }
   1389 
   1390     // Dimensions are fully known, block_shape and paddings are known.
   1391     {
   1392       Tensor paddings = test::AsTensor<int32>({1, 1, 0, 0}, {{2, 2}});
   1393       op.input_tensors[2] = &paddings;
   1394       INFER_OK(op, "[3,2,3,2];[2];[2,2]", "[18,2,1,d0_3]");
   1395       op.input_tensors[2] = nullptr;
   1396     }
   1397 
   1398     op.input_tensors[1] = nullptr;
   1399   }
   1400 
   1401   INFER_ERROR("block_shape must have rank 1", op, "?;[1,1];?");
   1402   INFER_ERROR("block_shape must have known size", op, "?;[?];?");
   1403 
   1404   {
   1405     Tensor block_shape = test::AsTensor<int32>({0, 2});
   1406     op.input_tensors[1] = &block_shape;
   1407     INFER_ERROR("block_shape must be positive", op, "[1,2,2];[2];[2,2]");
   1408     op.input_tensors[1] = nullptr;
   1409   }
   1410 
   1411   {
   1412     Tensor block_shape = test::AsTensor<int32>({1, 1});
   1413     op.input_tensors[1] = &block_shape;
   1414     Tensor paddings = test::AsTensor<int32>({0, -1, 0, 0}, {{2, 2}});
   1415     op.input_tensors[2] = &paddings;
   1416     INFER_ERROR("paddings cannot be negative", op, "[1,2,2];[2];[2,2]");
   1417     op.input_tensors[1] = nullptr;
   1418     op.input_tensors[2] = nullptr;
   1419   }
   1420 
   1421   {
   1422     Tensor block_shape = test::AsTensor<int32>({3, 3});
   1423     op.input_tensors[1] = &block_shape;
   1424     Tensor paddings = test::AsTensor<int32>({0, 0, 0, 0}, {{2, 2}});
   1425     op.input_tensors[2] = &paddings;
   1426     INFER_ERROR("divisible", op, "[1,2,3,1];[2];[2,2]");
   1427     op.input_tensors[1] = nullptr;
   1428     op.input_tensors[2] = nullptr;
   1429   }
   1430 
   1431   INFER_ERROR("rank", op, "[1,3,3,1];[2];[1]");
   1432   INFER_ERROR("shape", op, "[1,3,3,1];[2];[1,2]");
   1433 }
   1434 
   1435 TEST(ArrayOpsTest, BatchToSpace_ShapeFn) {
   1436   ShapeInferenceTestOp op("BatchToSpace");
   1437   op.input_tensors.resize(2);
   1438   TF_ASSERT_OK(NodeDefBuilder("test", "BatchToSpace")
   1439                    .Input("input", 0, DT_FLOAT)
   1440                    .Input("crops", 1, DT_INT32)
   1441                    .Attr("block_size", 2)
   1442                    .Finalize(&op.node_def));
   1443 
   1444   // croppings not known, but batch size can be computed.
   1445   INFER_OK(op, "[4,8,8,3];[2,2]", "[1,?,?,d0_3]");
   1446 
   1447   // block_size not compatible with batch size
   1448   INFER_ERROR("Dimension size must be evenly divisible by", op,
   1449               "[5,8,8,3];[2,2]");
   1450 
   1451   // Unknown croppings means unknown width and height.
   1452   INFER_OK(op, "[4,8,8,3];?", "[1,?,?,d0_3]");
   1453 
   1454   // croppings not correct shape
   1455   INFER_ERROR("rank", op, "[4,8,8,3];[4]");
   1456   INFER_ERROR("3 and 2", op, "[4,8,8,3];[2,3]");
   1457 
   1458   Tensor croppings = test::AsTensor<int64>({4, 2, 2, 4}, {{2, 2}});
   1459   op.input_tensors[1] = &croppings;
   1460   INFER_OK(op, "[4,8,8,3];[2,2]", "[1,10,10,d0_3]");
   1461 
   1462   // Bad croppings values
   1463   croppings = test::AsTensor<int32>({100, 2, 3, 4}, {{2, 2}});
   1464   op.input_tensors[1] = &croppings;
   1465   INFER_ERROR("Negative dimension size caused by subtracting", op,
   1466               "[4,8,8,3];[2,2]");
   1467   croppings = test::AsTensor<int32>({1, 2, 3, 400}, {{2, 2}});
   1468   op.input_tensors[1] = &croppings;
   1469   INFER_ERROR("Negative dimension size caused by subtracting", op,
   1470               "[4,8,8,3];[2,2]");
   1471 
   1472   // Negative paddsings
   1473   croppings = test::AsTensor<int32>({1, -2, 3, 4}, {{2, 2}});
   1474   op.input_tensors[1] = &croppings;
   1475   INFER_ERROR("cannot be negative", op, "[4,8,8,3];[2,2]");
   1476 }
   1477 
   1478 TEST(ArrayOpsTest, BatchToSpaceND_ShapeFn) {
   1479   ShapeInferenceTestOp op("BatchToSpaceND");
   1480   op.input_tensors.resize(3);
   1481   TF_ASSERT_OK(NodeDefBuilder("test", "BatchToSpaceND")
   1482                    .Input("input", 0, DT_FLOAT)
   1483                    .Input("block_shape", 1, DT_INT32)
   1484                    .Input("crops", 2, DT_INT32)
   1485                    .Finalize(&op.node_def));
   1486 
   1487   // Verify that input shape and crops shape can be unknown.
   1488   INFER_OK(op, "?;[2];?", "?");
   1489 
   1490   // Only number of input dimensions is known.
   1491   INFER_OK(op, "[?,?,?,?];[2];?", "[?,?,?,d0_3]");
   1492 
   1493   {
   1494     // Dimensions are partially known, block_shape known.
   1495     Tensor block_shape = test::AsTensor<int32>({2, 3});
   1496     op.input_tensors[1] = &block_shape;
   1497     INFER_OK(op, "[?,?,?,2];[2];?", "[?,?,?,d0_3]");
   1498 
   1499     INFER_OK(op, "[18,?,?,2];[2];?", "[3,?,?,d0_3]");
   1500 
   1501     // Dimensions are partially known, block_shape and crops known.
   1502     {
   1503       Tensor crops = test::AsTensor<int32>({1, 1, 0, 1}, {{2, 2}});
   1504       op.input_tensors[2] = &crops;
   1505       INFER_OK(op, "[18,?,2,2];[2];[2,2]", "[3,?,5,d0_3]");
   1506       op.input_tensors[2] = nullptr;
   1507     }
   1508 
   1509     // Dimensions are fully known, block_shape and crops are known.
   1510     {
   1511       Tensor crops = test::AsTensor<int32>({1, 1, 0, 0}, {{2, 2}});
   1512       op.input_tensors[2] = &crops;
   1513       INFER_OK(op, "[18,2,1,2];[2];[2,2]", "[3,2,3,d0_3]");
   1514       op.input_tensors[2] = nullptr;
   1515     }
   1516 
   1517     op.input_tensors[1] = nullptr;
   1518   }
   1519 
   1520   INFER_ERROR("block_shape must have rank 1", op, "?;[1,1];?");
   1521   INFER_ERROR("block_shape must have known size", op, "?;[?];?");
   1522   INFER_ERROR("rank", op, "[2,2];[2];[2,2]");
   1523   INFER_ERROR("rank", op, "[2,2,3];[3];[3,2]");
   1524 
   1525   {
   1526     Tensor block_shape = test::AsTensor<int32>({0, 2});
   1527     op.input_tensors[1] = &block_shape;
   1528     INFER_ERROR("block_shape must be positive", op, "[1,2,2];[2];[2,2]");
   1529     op.input_tensors[1] = nullptr;
   1530   }
   1531 
   1532   {
   1533     Tensor block_shape = test::AsTensor<int32>({1, 1});
   1534     op.input_tensors[1] = &block_shape;
   1535     Tensor paddings = test::AsTensor<int32>({0, -1, 0, 0}, {{2, 2}});
   1536     op.input_tensors[2] = &paddings;
   1537     INFER_ERROR("crops cannot be negative", op, "[1,2,2];[2];[2,2]");
   1538     op.input_tensors[1] = nullptr;
   1539     op.input_tensors[2] = nullptr;
   1540   }
   1541 
   1542   // The amount to crop exceeds the padded size.
   1543   {
   1544     Tensor block_shape = test::AsTensor<int32>({2, 2});
   1545     op.input_tensors[1] = &block_shape;
   1546     Tensor crops = test::AsTensor<int32>({3, 2, 0, 0}, {{2, 2}});
   1547     op.input_tensors[2] = &crops;
   1548     INFER_ERROR("Negative", op, "[4,2,3,1];[2];[2,2]");
   1549     op.input_tensors[1] = nullptr;
   1550     op.input_tensors[2] = nullptr;
   1551   }
   1552 
   1553   // The batch size is not divisible by the product of the block_shape.
   1554   {
   1555     Tensor block_shape = test::AsTensor<int32>({2, 3});
   1556     op.input_tensors[1] = &block_shape;
   1557     INFER_ERROR("divisible", op, "[3,1,1,1];[2];[2,2]");
   1558     op.input_tensors[1] = nullptr;
   1559   }
   1560 }
   1561 
   1562 TEST(ArrayOpsTest, SpaceToDepth_ShapeFn) {
   1563   ShapeInferenceTestOp op("SpaceToDepth");
   1564   TF_ASSERT_OK(NodeDefBuilder("test", "SpaceToDepth")
   1565                    .Input("input", 0, DT_FLOAT)
   1566                    .Attr("block_size", 2)
   1567                    .Finalize(&op.node_def));
   1568 
   1569   INFER_OK(op, "[1,2,4,4]", "[d0_0,1,2,16]");
   1570 
   1571   // block_size not compatible with space
   1572   INFER_ERROR("Dimension size must be evenly divisible by 2 but is 3", op,
   1573               "[1,3,8,4]");
   1574   INFER_ERROR("Dimension size must be evenly divisible by 2 but is 5", op,
   1575               "[1,2,5,4]");
   1576 
   1577   // Unknown depth --> Unknown depth.
   1578   INFER_OK(op, "[1,2,4,?]", "[d0_0,1,2,?]");
   1579 }
   1580 
   1581 TEST(ArrayOpsTest, DepthToSpace_ShapeFn) {
   1582   ShapeInferenceTestOp op("DepthToSpace");
   1583   TF_ASSERT_OK(NodeDefBuilder("test", "DepthToSpace")
   1584                    .Input("input", 0, DT_FLOAT)
   1585                    .Attr("block_size", 2)
   1586                    .Finalize(&op.node_def));
   1587 
   1588   INFER_OK(op, "[1,1,2,16]", "[d0_0,2,4,4]");
   1589 
   1590   // Bad depth
   1591   INFER_ERROR("Dimension size must be evenly divisible by 4 but is 15", op,
   1592               "[1,1,2,15]");
   1593 
   1594   // Unknown depth --> Unknown depth.
   1595   INFER_OK(op, "[1,2,4,?]", "[d0_0,4,8,?]");
   1596 
   1597   // Check another block size.
   1598   TF_ASSERT_OK(NodeDefBuilder("test", "DepthToSpace")
   1599                    .Input("input", 0, DT_FLOAT)
   1600                    .Attr("block_size", 10)
   1601                    .Finalize(&op.node_def));
   1602   INFER_OK(op, "[1,1,2,200]", "[d0_0,10,20,2]");
   1603 }
   1604 
   1605 TEST(ArrayOpsTest, Slice_ShapeFn) {
   1606   ShapeInferenceTestOp op("Slice");
   1607   TF_ASSERT_OK(NodeDefBuilder("test", "Slice")
   1608                    .Input("input", 0, DT_FLOAT)
   1609                    .Input("begin", 1, DT_INT64)
   1610                    .Input("sizes", 2, DT_INT64)
   1611                    .Finalize(&op.node_def));
   1612 
   1613   // Known rank of input and shape of begin/sizes, but unknown values.
   1614   // The best we know is the rank of the output.
   1615   INFER_OK(op, "[2,3,4,5];[4];[4]", "[?,?,?,?]");
   1616 
   1617   // Unknown shape of begin/sizes, we still know the rank.
   1618   INFER_OK(op, "[2,3,4,5];[?];[?]", "[?,?,?,?]");
   1619   // Unknown all around
   1620   INFER_OK(op, "?;[?];[?]", "?");
   1621   // Can infer based on begin
   1622   INFER_OK(op, "?;[4];[?]", "[?,?,?,?]");
   1623 
   1624   // Bad rank of begin, sizes
   1625   INFER_ERROR("must be rank 1", op, "[2,3,4,5];[2,3];[3]");
   1626   INFER_ERROR("must be rank 1", op, "[2,3,4,5];[2];[3,4]");
   1627   // Length of begin doesn't match input rank
   1628   INFER_ERROR("must be rank 2", op, "[2,3,4,5];[2];[2]");
   1629 
   1630   // Tests with known values.
   1631   op.input_tensors.resize(3);
   1632   Tensor begin = test::AsTensor<int32>({0, 1, 2, 1});
   1633   Tensor sizes = test::AsTensor<int32>({1, 2, 1, 3});
   1634   op.input_tensors[1] = &begin;
   1635   op.input_tensors[2] = &sizes;
   1636   INFER_OK(op, "[2,3,4,5];[4];[4]", "[1,2,1,3]");
   1637 
   1638   // -1 in sizes means "get the rest"
   1639   sizes = test::AsTensor<int32>({-1, -1, 1, -1});
   1640   INFER_OK(op, "[2,3,4,5];[4];[4]", "[d0_0,2,1,4]");
   1641 
   1642   begin = test::AsTensor<int32>({0, 1, 2, 6});
   1643   sizes = test::AsTensor<int32>({-1, -1, -1, -1});
   1644   INFER_ERROR("Negative dimension size", op, "[2,3,4,5];[4];[4]");
   1645 
   1646   begin = test::AsTensor<int32>({0, 1, 2, 5});
   1647   sizes = test::AsTensor<int32>({-1, -1, -1, -2});
   1648   INFER_ERROR("cannot be < -1", op, "[2,3,4,5];[4];[4]");
   1649 }
   1650 
   1651 TEST(ArrayOpsTest, StridedSlice_ShapeFn) {
   1652   ShapeInferenceTestOp op("StridedSlice");
   1653   TF_ASSERT_OK(NodeDefBuilder("test", "StridedSlice")
   1654                    .Input("input", 0, DT_FLOAT)
   1655                    .Input("begin", 1, DT_INT32)
   1656                    .Input("end", 2, DT_INT32)
   1657                    .Input("strides", 3, DT_INT32)
   1658                    .Attr("shrink_axis_mask", 1)
   1659                    .Finalize(&op.node_def));
   1660   op.input_tensors.resize(4);
   1661   Tensor strides = test::AsTensor<int32>({1});
   1662   op.input_tensors[3] = &strides;
   1663   // Slicing on the 0-th dimension.
   1664   INFER_OK(op, "[2,3,4,5];[1];[1];[1]", "[3,4,5]");
   1665   // Slicing on the 0-th dimension. This time some of the result dimension is 0.
   1666   INFER_OK(op, "[2,0,3,4];[1];[1];[1]", "[0,3,4]");
   1667 }
   1668 
   1669 TEST(ArrayOpsTest, StridedSliceGrad_ShapeFn) {
   1670   ShapeInferenceTestOp op("StridedSliceGrad");
   1671   op.input_tensors.resize(5);
   1672   INFER_OK(op, "?;?;?;?;?", "?");
   1673   INFER_OK(op, "[?];?;?;?;?", "?");
   1674   INFER_OK(op, "[4];?;?;?;?", "[?,?,?,?]");
   1675 
   1676   Tensor in_t = test::AsTensor<int32>({1, 2, 3, 4});
   1677   op.input_tensors[0] = &in_t;
   1678   INFER_OK(op, "[4];?;?;?;?", "[1,2,3,4]");
   1679 }
   1680 
   1681 TEST(ArrayOpsTest, UnchangedWithQuantizationScalars_ShapeFn) {
   1682   for (const char* op_name : {"Dequantize", "FakeQuantWithMinMaxVars"}) {
   1683     ShapeInferenceTestOp op(op_name);
   1684 
   1685     INFER_OK(op, "?;?;?", "in0");
   1686     INFER_OK(op, "[1,?,3];[];[]", "in0");
   1687 
   1688     // Rank check scalars.
   1689     INFER_ERROR("be rank 0", op, "[1,?,3];[1];[]");
   1690     INFER_ERROR("be rank 0", op, "[1,?,3];[];[1]");
   1691   }
   1692 }
   1693 
   1694 TEST(ArrayOpsTest, FakeQuantWithMinMaxVarsPerChannel) {
   1695   ShapeInferenceTestOp op("FakeQuantWithMinMaxVarsPerChannel");
   1696 
   1697   INFER_OK(op, "?;?;?", "in0");
   1698   INFER_OK(op, "[?];?;?", "in0");
   1699   INFER_OK(op, "[1,?,3];[3];[3]", "in0");
   1700   INFER_OK(op, "[3];[3];[3]", "in0");
   1701 
   1702   // Rank check vectors.
   1703   INFER_ERROR("be rank 1", op, "[1,?,3];[1];[]");
   1704   INFER_ERROR("be rank 1", op, "[1,?,3];[];[1]");
   1705 
   1706   // Vectors must match each other, and match last dim of input.
   1707   INFER_ERROR("must be equal", op, "[1,?,3];[2];[?]");
   1708   INFER_ERROR("must be equal", op, "[1,?,3];[?];[2]");
   1709   INFER_ERROR("must be equal", op, "[1,?,?];[1];[2]");
   1710   INFER_ERROR("must be equal", op, "[5];[4];[?]");
   1711 }
   1712 
   1713 TEST(ArrayOpsTest, FakeQuantWithMinMaxVarsPerChannelGradient) {
   1714   ShapeInferenceTestOp op("FakeQuantWithMinMaxVarsPerChannelGradient");
   1715 
   1716   INFER_OK(op, "?;?;?;?", "in0;[?];[?]");
   1717   INFER_OK(op, "[3];[3];[3];[3]", "in0;in3;in3");
   1718   INFER_OK(op, "[1,3];[1,3];[3];[3]", "in0;in3;in3");
   1719   INFER_OK(op, "[1,2,3,4];[1,2,3,4];[4];[4]", "in0;in3;in3");
   1720 
   1721   // Rank check vectors.
   1722   INFER_ERROR("be equal rank", op, "[1,?,3];[1,?,3];[3];[]");
   1723   INFER_ERROR("be rank 1", op, "[1,?,3];[1,?,3];[];[3]");
   1724   INFER_ERROR("be at least rank 1", op, "[];[];[1];[1]");
   1725   INFER_ERROR("be at most rank 4", op, "[1,2,3,4,5];[1,2,3,4,5];[1];[1]");
   1726 
   1727   // Vectors must match each other, and match last dim of input.
   1728   INFER_ERROR("must be equal", op, "[1,3];[1,3];[2];[3]");
   1729   INFER_ERROR("must be equal", op, "[1,3];[1,3];[3];[2]");
   1730 }
   1731 
   1732 TEST(ArrayOpsTest, QuantizedConcat_ShapeFn) {
   1733   ShapeInferenceTestOp op("QuantizedConcat");
   1734   auto set_n = [&op](int n) {
   1735     std::vector<NodeDefBuilder::NodeOut> src_list;
   1736     std::vector<NodeDefBuilder::NodeOut> limit_list;
   1737     for (int i = 0; i < n; ++i) {
   1738       src_list.emplace_back("a", 0, DT_QUINT8);
   1739       limit_list.emplace_back("b", 0, DT_FLOAT);
   1740     }
   1741     TF_ASSERT_OK(NodeDefBuilder("test", "QuantizedConcat")
   1742                      .Input({"concat_dim", 0, DT_INT32})
   1743                      .Input(src_list)
   1744                      .Input(limit_list)
   1745                      .Input(limit_list)
   1746                      .Attr("N", n)
   1747                      .Finalize(&op.node_def));
   1748   };
   1749 
   1750   // Confirm dimension[0] of the input (the concat_dim) is a scalar.
   1751   set_n(1);
   1752   INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1];?;?;?");
   1753 
   1754   // Last 2*<N> are all scalars.
   1755   set_n(2);
   1756   INFER_ERROR("must be rank 0", op, "[];?;?;?;?;?;[1]");
   1757   INFER_ERROR("must be rank 0", op, "[];?;?;?;?;[1];?");
   1758   INFER_ERROR("must be rank 0", op, "[];?;?;?;[1];?;?");
   1759   INFER_ERROR("must be rank 0", op, "[];?;?;[1];?;?;?");
   1760 
   1761   // First is concat dim; next N must be compatible for concat.
   1762   set_n(2);
   1763   INFER_ERROR("must be rank 2", op, "[];[1,2];[1,2,3];?;?;?;?");
   1764   INFER_OK(op, "[];[1,2];[1,3];?;?;?;?", "[?,?];[];[]");
   1765 
   1766   // Test when the concat_dim tensor is known. The concatenated dimension is
   1767   // summed across all input tensors, and other dimensions are merged.
   1768   Tensor concat_dim_t;
   1769   op.input_tensors.push_back(&concat_dim_t);
   1770   set_n(2);
   1771   concat_dim_t = test::AsScalar(0);  // Sum dim 0, merge the other two dims.
   1772   INFER_OK(op, "[];[100,2,?];[10,?,3];?;?;?;?", "[110,d1_1,d2_2];[];[]");
   1773   INFER_ERROR("Dimension 1 in both shapes must be equal, but are 5 and 3", op,
   1774               "[];[100,2,5];[10,?,3];?;?;?;?");
   1775   // Note that other cases of concat are covered in the Concat tests.
   1776 }
   1777 
   1778 TEST(StateOpsTest, _ParallelConcatStart_ShapeFn) {
   1779   ShapeInferenceTestOp op("_ParallelConcatStart");
   1780   TensorShape shape({1, 2, 3});
   1781   TensorShapeProto shape_proto;
   1782   shape.AsProto(&shape_proto);
   1783   TF_ASSERT_OK(NodeDefBuilder("test", "_ParallelConcatStart")
   1784                    .Attr("shape", shape_proto)
   1785                    .Attr("dtype", DT_FLOAT)
   1786                    .Finalize(&op.node_def));
   1787   INFER_OK(op, "", "[1,2,3]");
   1788 }
   1789 
   1790 }  // end namespace tensorflow
   1791