Home | History | Annotate | Download | only in kernel_tests
      1 # Copyright 2015 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 """Tests for Python ops defined in sparse_ops."""
     16 
     17 from __future__ import absolute_import
     18 from __future__ import division
     19 from __future__ import print_function
     20 
     21 import numpy as np
     22 
     23 from tensorflow.python.framework import constant_op
     24 from tensorflow.python.framework import dtypes
     25 from tensorflow.python.framework import sparse_tensor
     26 from tensorflow.python.framework import test_util
     27 from tensorflow.python.ops import array_ops
     28 from tensorflow.python.ops import gradient_checker
     29 from tensorflow.python.ops import nn_ops
     30 from tensorflow.python.ops import sparse_ops
     31 from tensorflow.python.ops import variables
     32 import tensorflow.python.ops.sparse_grad  # pylint: disable=unused-import
     33 from tensorflow.python.platform import googletest
     34 from tensorflow.python.platform import test
     35 
     36 
     37 # TODO(zongheng): it'd be great to factor out this function and various random
     38 # SparseTensor gen funcs.
     39 def _sparsify(x, thresh=0.5, index_dtype=np.int64):
     40   x[x < thresh] = 0
     41 
     42   non_zero = np.where(x)
     43   x_indices = np.vstack(non_zero).astype(index_dtype).T
     44   x_values = x[non_zero]
     45   x_shape = x.shape
     46 
     47   return sparse_tensor.SparseTensor(
     48       indices=x_indices, values=x_values, dense_shape=x_shape), len(x_values)
     49 
     50 
     51 class SparseToIndicatorTest(test_util.TensorFlowTestCase):
     52 
     53   def _SparseTensor_5x6(self, dtype):
     54     ind = np.array([[0, 0], [1, 0], [1, 3], [1, 4], [3, 2], [3, 3]])
     55     val = np.array([0, 10, 13, 14, 32, 33])
     56     shape = np.array([5, 6])
     57     return sparse_tensor.SparseTensor(
     58         constant_op.constant(ind, dtypes.int64),
     59         constant_op.constant(val, dtype),
     60         constant_op.constant(shape, dtypes.int64))
     61 
     62   def _SparseTensor_2x3x4(self, dtype):
     63     # Includes two entries with the form [1, 1, x] : 150.
     64     ind = np.array([[0, 0, 1], [0, 1, 0], [0, 1, 2], [1, 0, 3], [1, 1, 0],
     65                     [1, 1, 1], [1, 1, 2], [1, 2, 2]])
     66     val = np.array([1, 10, 12, 103, 150, 149, 150, 122])
     67     shape = np.array([2, 3, 4])
     68     return sparse_tensor.SparseTensor(
     69         constant_op.constant(ind, dtypes.int64),
     70         constant_op.constant(val, dtype),
     71         constant_op.constant(shape, dtypes.int64))
     72 
     73   def testInt32(self):
     74     with self.test_session(use_gpu=False):
     75       sp_input = self._SparseTensor_5x6(dtypes.int32)
     76       output = sparse_ops.sparse_to_indicator(sp_input, 50).eval()
     77 
     78       expected_output = np.zeros((5, 50), dtype=np.bool)
     79       expected_trues = ((0, 0), (1, 10), (1, 13), (1, 14), (3, 32), (3, 33))
     80       for expected_true in expected_trues:
     81         expected_output[expected_true] = True
     82 
     83       self.assertAllEqual(output, expected_output)
     84 
     85   def testInt64(self):
     86     with self.test_session(use_gpu=False):
     87       sp_input = self._SparseTensor_5x6(dtypes.int64)
     88       output = sparse_ops.sparse_to_indicator(sp_input, 50).eval()
     89 
     90       expected_output = np.zeros((5, 50), dtype=np.bool)
     91       expected_trues = [(0, 0), (1, 10), (1, 13), (1, 14), (3, 32), (3, 33)]
     92       for expected_true in expected_trues:
     93         expected_output[expected_true] = True
     94 
     95       self.assertAllEqual(output, expected_output)
     96 
     97   def testHigherRank(self):
     98     with self.test_session(use_gpu=False):
     99       sp_input = self._SparseTensor_2x3x4(dtypes.int64)
    100       output = sparse_ops.sparse_to_indicator(sp_input, 200).eval()
    101 
    102       expected_output = np.zeros((2, 3, 200), dtype=np.bool)
    103       expected_trues = [(0, 0, 1), (0, 1, 10), (0, 1, 12), (1, 0, 103),
    104                         (1, 1, 149), (1, 1, 150), (1, 2, 122)]
    105       for expected_true in expected_trues:
    106         expected_output[expected_true] = True
    107 
    108       self.assertAllEqual(output, expected_output)
    109 
    110 
    111 class SparseMergeTest(test_util.TensorFlowTestCase):
    112 
    113   def _SparseTensorValue_3x50(self, indices_dtype, values_dtype):
    114     # NOTE: This input is intentionally not sorted to validate the
    115     # already_sorted flag below.
    116     ind = np.array([[0, 0], [1, 0], [1, 2], [2, 0], [2, 1], [1, 1]])
    117     # NB: these are not sorted
    118     indices = np.array([0, 13, 10, 33, 32, 14])
    119     values = np.array([-3, 4, 1, 9, 5, 1])
    120     shape = np.array([3, 3])
    121     indices = sparse_tensor.SparseTensorValue(
    122         np.array(ind, np.int64),
    123         np.array(indices, indices_dtype), np.array(shape, np.int64))
    124     values = sparse_tensor.SparseTensorValue(
    125         np.array(ind, np.int64),
    126         np.array(values, values_dtype), np.array(shape, np.int64))
    127     return indices, values
    128 
    129   def _SparseTensor_3x50(self, indices_dtype, values_dtype):
    130     indices, values = self._SparseTensorValue_3x50(indices_dtype, values_dtype)
    131     return (sparse_tensor.SparseTensor.from_value(indices),
    132             sparse_tensor.SparseTensor.from_value(values))
    133 
    134   def _AssertResultsSorted(self, output, vocab_size):
    135     self.assertAllEqual(output.indices,
    136                         [[0, 0], [1, 10], [1, 13], [1, 14], [2, 32], [2, 33]])
    137     self.assertAllEqual(output.values, [-3, 1, 4, 1, 5, 9])
    138     self.assertAllEqual(output.dense_shape, [3, vocab_size])
    139 
    140   def _AssertResultsNotSorted(self, output, vocab_size):
    141     self.assertAllEqual(output.indices,
    142                         [[0, 0], [1, 13], [1, 10], [2, 33], [2, 32], [1, 14]])
    143     self.assertAllEqual(output.values, [-3, 4, 1, 9, 5, 1])
    144     self.assertAllEqual(output.dense_shape, [3, vocab_size])
    145 
    146   def testInt32AndFloat32(self):
    147     vocab_size = 50
    148     indices_v, values_v = self._SparseTensorValue_3x50(np.int32, np.float32)
    149     with self.test_session(use_gpu=False) as sess:
    150       for indices in (indices_v,
    151                       sparse_tensor.SparseTensor.from_value(indices_v)):
    152         for values in (values_v,
    153                        sparse_tensor.SparseTensor.from_value(values_v)):
    154           sp_output = sparse_ops.sparse_merge(indices, values, vocab_size)
    155 
    156           output = sess.run(sp_output)
    157           self._AssertResultsSorted(output, vocab_size)
    158 
    159   def testInt64AndFloat32(self):
    160     vocab_size = 50
    161     with self.test_session(use_gpu=False) as sess:
    162       indices, values = self._SparseTensor_3x50(np.int64, np.float32)
    163       sp_output = sparse_ops.sparse_merge(indices, values, vocab_size)
    164 
    165       output = sess.run(sp_output)
    166       self._AssertResultsSorted(output, vocab_size)
    167 
    168   def testInt64AndFloat64(self):
    169     vocab_size = 50
    170     with self.test_session(use_gpu=False) as sess:
    171       indices, values = self._SparseTensor_3x50(np.int64, np.float64)
    172       sp_output = sparse_ops.sparse_merge(indices, values, vocab_size)
    173 
    174       output = sess.run(sp_output)
    175       self._AssertResultsSorted(output, vocab_size)
    176 
    177   def testInt32AndFloat32NonCanonicalOrder(self):
    178     vocab_size = 50
    179     with self.test_session(use_gpu=False) as sess:
    180       indices, values = self._SparseTensor_3x50(np.int32, np.float32)
    181       sp_output = sparse_ops.sparse_merge(
    182           indices, values, vocab_size, already_sorted=True)
    183 
    184       output = sess.run(sp_output)
    185       self._AssertResultsNotSorted(output, vocab_size)
    186 
    187   def testInt64AndFloat32NonCanonicalOrder(self):
    188     vocab_size = 50
    189     with self.test_session(use_gpu=False) as sess:
    190       indices, values = self._SparseTensor_3x50(np.int64, np.float32)
    191       sp_output = sparse_ops.sparse_merge(
    192           indices, values, vocab_size, already_sorted=True)
    193 
    194       output = sess.run(sp_output)
    195       self._AssertResultsNotSorted(output, vocab_size)
    196 
    197   def testInt64AndFloat64NonCanonicalOrder(self):
    198     vocab_size = 50
    199     vocab_size_tensor = constant_op.constant(vocab_size, dtypes.int64)
    200     with self.test_session(use_gpu=False) as sess:
    201       indices, values = self._SparseTensor_3x50(np.int64, np.float64)
    202       sp_output = sparse_ops.sparse_merge(
    203           indices, values, vocab_size_tensor, already_sorted=True)
    204 
    205       output = sess.run(sp_output)
    206       self._AssertResultsNotSorted(output, vocab_size)
    207 
    208 
    209 class SparseMergeHighDimTest(test_util.TensorFlowTestCase):
    210 
    211   def _SparseTensor_3x50(self, indices_dtype, values_dtype):
    212     # NOTE: This input is intentionally not sorted to validate the
    213     # already_sorted flag below.
    214     ind = np.array([[0, 0], [1, 0], [1, 2], [2, 0], [2, 1], [1, 1]])
    215     # NB: these are not sorted
    216     indices0 = np.array([0, 13, 10, 33, 32, 14])
    217     indices1 = np.array([12, 4, 0, 0, 1, 30])
    218     values = np.array([-3, 4, 1, 9, 5, 1])
    219     shape = np.array([3, 3])
    220     indices0 = sparse_tensor.SparseTensorValue(
    221         np.array(ind, np.int64),
    222         np.array(indices0, indices_dtype), np.array(shape, np.int64))
    223     indices1 = sparse_tensor.SparseTensorValue(
    224         np.array(ind, np.int64),
    225         np.array(indices1, indices_dtype), np.array(shape, np.int64))
    226     values = sparse_tensor.SparseTensorValue(
    227         np.array(ind, np.int64),
    228         np.array(values, values_dtype), np.array(shape, np.int64))
    229     return ([sparse_tensor.SparseTensor.from_value(indices0),
    230              sparse_tensor.SparseTensor.from_value(indices1)],
    231             sparse_tensor.SparseTensor.from_value(values))
    232 
    233   def _AssertResultsSorted(self, output, vocab_size):
    234     self.assertAllEqual(
    235         output.indices,
    236         [[0, 0, 12], [1, 10, 0], [1, 13, 4], [1, 14, 30], [2, 32, 1],
    237          [2, 33, 0]])
    238     self.assertAllEqual(output.values, [-3, 1, 4, 1, 5, 9])
    239     self.assertAllEqual(output.dense_shape, [3] + vocab_size)
    240 
    241   def testInt64AndFloat32(self):
    242     vocab_size = [50, 31]
    243     with self.test_session(use_gpu=False) as sess:
    244       indices, values = self._SparseTensor_3x50(np.int64, np.float32)
    245       sp_output = sparse_ops.sparse_merge(indices, values, vocab_size)
    246 
    247       output = sess.run(sp_output)
    248       self._AssertResultsSorted(output, vocab_size)
    249 
    250   def testInt64AndFloat64(self):
    251     vocab_size = [50, 31]
    252     with self.test_session(use_gpu=False) as sess:
    253       indices, values = self._SparseTensor_3x50(np.int64, np.float64)
    254       sp_output = sparse_ops.sparse_merge(indices, values, vocab_size)
    255 
    256       output = sess.run(sp_output)
    257       self._AssertResultsSorted(output, vocab_size)
    258 
    259   def testInt64AndFloat64Shape(self):
    260     vocab_size = [50, 30]
    261     with self.test_session(use_gpu=False) as sess:
    262       indices, values = self._SparseTensor_3x50(np.int64, np.float64)
    263       sp_output = sparse_ops.sparse_merge(indices, values, vocab_size)
    264 
    265       output = sess.run(sp_output)
    266       self._AssertResultsSorted(output, vocab_size)
    267 
    268 
    269 class SparseRetainTest(test_util.TensorFlowTestCase):
    270 
    271   def _SparseTensorValue_5x6(self):
    272     ind = np.array([[0, 0], [1, 0], [1, 3], [1, 4], [3, 2], [3, 3]])
    273     val = np.array([0, 10, 13, 14, 32, 33])
    274     shape = np.array([5, 6])
    275     return sparse_tensor.SparseTensorValue(
    276         np.array(ind, np.int64),
    277         np.array(val, np.int32), np.array(shape, np.int64))
    278 
    279   def _SparseTensor_5x6(self):
    280     return sparse_tensor.SparseTensor.from_value(self._SparseTensorValue_5x6())
    281 
    282   def testBasic(self):
    283     with self.test_session(use_gpu=False) as sess:
    284       for sp_input in (self._SparseTensorValue_5x6(), self._SparseTensor_5x6()):
    285         to_retain = np.array([1, 0, 0, 1, 1, 0], dtype=np.bool)
    286         sp_output = sparse_ops.sparse_retain(sp_input, to_retain)
    287 
    288         output = sess.run(sp_output)
    289 
    290         self.assertAllEqual(output.indices, [[0, 0], [1, 4], [3, 2]])
    291         self.assertAllEqual(output.values, [0, 14, 32])
    292         self.assertAllEqual(output.dense_shape, [5, 6])
    293 
    294   def testRetainNone(self):
    295     with self.test_session(use_gpu=False) as sess:
    296       sp_input = self._SparseTensor_5x6()
    297       to_retain = np.zeros((6,), dtype=np.bool)
    298       sp_output = sparse_ops.sparse_retain(sp_input, to_retain)
    299 
    300       output = sess.run(sp_output)
    301 
    302       self.assertAllEqual(output.indices, np.array([]).reshape((0, 2)))
    303       self.assertAllEqual(output.values, [])
    304       self.assertAllEqual(output.dense_shape, [5, 6])
    305 
    306   def testMismatchedRetainShape(self):
    307     with self.test_session(use_gpu=False):
    308       sp_input = self._SparseTensor_5x6()
    309       to_retain = np.array([1, 0, 0, 1, 0], dtype=np.bool)
    310       with self.assertRaises(ValueError):
    311         sparse_ops.sparse_retain(sp_input, to_retain)
    312 
    313 
    314 class SparseResetShapeTest(test_util.TensorFlowTestCase):
    315 
    316   _IND_2_5_6 = np.array(
    317       [[0, 0, 0], [0, 1, 0], [0, 1, 3], [1, 1, 4], [1, 3, 2], [1, 3, 3]],
    318       dtype=np.int64)
    319   _VAL_2_5_6 = np.array([0, 10, 13, 14, 32, 33], dtype=np.int32)
    320   _SHP_2_5_6 = np.array([2, 5, 6], dtype=np.int64)
    321 
    322   def _SparseTensor_2x5x6(self):
    323     return sparse_tensor.SparseTensor(
    324         constant_op.constant(self._IND_2_5_6, dtypes.int64),
    325         constant_op.constant(self._VAL_2_5_6, dtypes.int32),
    326         constant_op.constant(self._SHP_2_5_6, dtypes.int64))
    327 
    328   def _SparseTensor_2x5x6_Empty(self):
    329     return sparse_tensor.SparseTensor(
    330         constant_op.constant(
    331             np.empty(shape=[0, 3], dtype=np.int64), dtypes.int64),
    332         constant_op.constant(np.empty(shape=[0], dtype=np.int32), dtypes.int32),
    333         constant_op.constant(self._SHP_2_5_6, dtypes.int64))
    334 
    335   def _SparseTensorValue_2x5x6(self):
    336     return sparse_tensor.SparseTensorValue(self._IND_2_5_6, self._VAL_2_5_6,
    337                                            self._SHP_2_5_6)
    338 
    339   def testStaticShapeInfoPreservedWhenNewShapeIsProvidedAndStatic(self):
    340     sp_input = self._SparseTensor_2x5x6()
    341     new_shape = np.array([3, 6, 7], dtype=np.int64)
    342     sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape)
    343     self.assertAllEqual([3, 6, 7], sp_output.get_shape())
    344 
    345   def testBasic(self):
    346     with self.test_session(use_gpu=False) as sess:
    347       sp_input = self._SparseTensor_2x5x6()
    348       new_shape = np.array([3, 6, 7], dtype=np.int64)
    349       sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape)
    350 
    351       output = sess.run(sp_output)
    352 
    353       self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3],
    354                                            [1, 1, 4], [1, 3, 2], [1, 3, 3]])
    355       self.assertAllEqual(output.values, [0, 10, 13, 14, 32, 33])
    356       self.assertAllEqual(output.dense_shape, [3, 6, 7])
    357 
    358   def testInputUnavailableInGraphConstructionOk(self):
    359     with self.test_session(use_gpu=False) as sess:
    360       sp_input = self._SparseTensorValue_2x5x6()
    361       new_shape = np.array([3, 6, 7], dtype=np.int64)
    362       sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape)
    363 
    364       output = sess.run(sp_output)
    365 
    366       self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3],
    367                                            [1, 1, 4], [1, 3, 2], [1, 3, 3]])
    368       self.assertAllEqual(output.values, [0, 10, 13, 14, 32, 33])
    369       self.assertAllEqual(output.dense_shape, [3, 6, 7])
    370 
    371   def testFeedInputUnavailableInGraphConstructionOk(self):
    372     with self.test_session(use_gpu=False) as sess:
    373       sp_input = array_ops.sparse_placeholder(dtype=dtypes.int32)
    374       new_shape = np.array([3, 6, 7], dtype=np.int64)
    375       sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape)
    376 
    377       output = sess.run(sp_output,
    378                         feed_dict={sp_input: self._SparseTensorValue_2x5x6()})
    379 
    380       self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3],
    381                                            [1, 1, 4], [1, 3, 2], [1, 3, 3]])
    382       self.assertAllEqual(output.values, [0, 10, 13, 14, 32, 33])
    383       self.assertAllEqual(output.dense_shape, [3, 6, 7])
    384 
    385   def testTightBoundingBox(self):
    386     with self.test_session(use_gpu=False) as sess:
    387       sp_input = self._SparseTensor_2x5x6()
    388       sp_output = sparse_ops.sparse_reset_shape(sp_input)
    389 
    390       output = sess.run(sp_output)
    391 
    392       self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3],
    393                                            [1, 1, 4], [1, 3, 2], [1, 3, 3]])
    394       self.assertAllEqual(output.values, [0, 10, 13, 14, 32, 33])
    395       self.assertAllEqual(output.dense_shape, [2, 4, 5])
    396 
    397   def testTightBoundingBoxEmpty(self):
    398     with self.test_session(use_gpu=False) as sess:
    399       sp_input = self._SparseTensor_2x5x6_Empty()
    400       sp_output = sparse_ops.sparse_reset_shape(sp_input)
    401 
    402       output = sess.run(sp_output)
    403 
    404       self.assertAllEqual(output.indices.shape, [0, 3])
    405       self.assertAllEqual(output.values.shape, [0])
    406       self.assertAllEqual(output.dense_shape, [0, 0, 0])
    407 
    408   def testInvalidRank(self):
    409     with self.test_session(use_gpu=False):
    410       sp_input = self._SparseTensor_2x5x6()
    411       new_shape = np.array([3, 7], dtype=np.int64)
    412 
    413       with self.assertRaises(ValueError):
    414         sparse_ops.sparse_reset_shape(sp_input, new_shape)
    415 
    416   def testInvalidRankNewShapeUnavailableInGraphConstruction(self):
    417     with self.test_session(use_gpu=False) as sess:
    418       new_shape = array_ops.placeholder(dtype=dtypes.int64)
    419       sp_input = self._SparseTensor_2x5x6()
    420       out = sparse_ops.sparse_reset_shape(sp_input, new_shape)
    421 
    422       with self.assertRaisesOpError("x == y did not hold element-wise"):
    423         sess.run(out, feed_dict={new_shape: np.array([3, 7], dtype=np.int64)})
    424 
    425   def testInvalidDimensionSizeStatic(self):
    426     sp_input = self._SparseTensor_2x5x6()
    427     new_shape = np.array([3, 7, 5], dtype=np.int64)
    428 
    429     with self.assertRaisesRegexp(ValueError, "should have dimension sizes"):
    430       sparse_ops.sparse_reset_shape(sp_input, new_shape)
    431 
    432   def testInvalidDimensionSizeDynamic(self):
    433     with self.test_session(use_gpu=False) as sess:
    434       sp_input = self._SparseTensor_2x5x6()
    435       new_shape = array_ops.placeholder(dtype=dtypes.int32)
    436       out = sparse_ops.sparse_reset_shape(sp_input, new_shape)
    437 
    438       with self.assertRaisesOpError("x <= y did not hold element-wise"):
    439         sess.run(out, feed_dict={new_shape: [3, 7, 5]})
    440 
    441   def testInvalidDimensionSizeInputUnavailableInGraphConstruction(self):
    442     sp_input = array_ops.sparse_placeholder(dtype=dtypes.int32)
    443     with self.test_session(use_gpu=False) as sess:
    444       new_shape = np.array([3, 7, 5], dtype=np.int64)
    445       out = sparse_ops.sparse_reset_shape(sp_input, new_shape)
    446 
    447       with self.assertRaisesOpError("x <= y did not hold element-wise"):
    448         sess.run(out, feed_dict={sp_input: self._SparseTensorValue_2x5x6()})
    449 
    450 
    451 class SparseFillEmptyRowsTest(test_util.TensorFlowTestCase):
    452 
    453   def _SparseTensorValue_5x6(self, dtype=np.int32):
    454     ind = np.array([[0, 0], [1, 0], [1, 3], [1, 4], [3, 2], [3, 3]])
    455     val = np.array([0, 10, 13, 14, 32, 33])
    456     shape = np.array([5, 6])
    457     return sparse_tensor.SparseTensorValue(
    458         np.array(ind, np.int64), np.array(val, dtype), np.array(
    459             shape, np.int64))
    460 
    461   def _SparseTensor_5x6(self):
    462     return sparse_tensor.SparseTensor.from_value(self._SparseTensorValue_5x6())
    463 
    464   def _SparseTensor_String5x6(self):
    465     ind = np.array([[0, 0], [1, 0], [1, 3], [1, 4], [3, 2], [3, 3]])
    466     val = np.array(["a", "b", "c", "d", "e", "f"])
    467     shape = np.array([5, 6])
    468     return sparse_tensor.SparseTensor(
    469         constant_op.constant(ind, dtypes.int64),
    470         constant_op.constant(val, dtypes.string),
    471         constant_op.constant(shape, dtypes.int64))
    472 
    473   def _SparseTensor_2x6(self):
    474     ind = np.array([[0, 0], [1, 0], [1, 3], [1, 4]])
    475     val = np.array([0, 10, 13, 14])
    476     shape = np.array([2, 6])
    477     return sparse_tensor.SparseTensor(
    478         constant_op.constant(ind, dtypes.int64),
    479         constant_op.constant(val, dtypes.int32),
    480         constant_op.constant(shape, dtypes.int64))
    481 
    482   def testFillNumber(self):
    483     with self.test_session(use_gpu=False) as sess:
    484       for sp_input in (self._SparseTensorValue_5x6(), self._SparseTensor_5x6()):
    485         sp_output, empty_row_indicator = (
    486             sparse_ops.sparse_fill_empty_rows(sp_input, -1))
    487 
    488         output, empty_row_indicator_out = sess.run(
    489             [sp_output, empty_row_indicator])
    490 
    491         self.assertAllEqual(
    492             output.indices,
    493             [[0, 0], [1, 0], [1, 3], [1, 4], [2, 0], [3, 2], [3, 3], [4, 0]])
    494         self.assertAllEqual(output.values, [0, 10, 13, 14, -1, 32, 33, -1])
    495         self.assertAllEqual(output.dense_shape, [5, 6])
    496         self.assertAllEqual(empty_row_indicator_out,
    497                             np.array([0, 0, 1, 0, 1]).astype(np.bool))
    498 
    499   def testFillFloat(self):
    500     with self.test_session(use_gpu=False) as sess:
    501       values = constant_op.constant(
    502           [0.0, 10.0, 13.0, 14.0, 32.0, 33.0], dtype=dtypes.float64)
    503       default_value = constant_op.constant(-1.0, dtype=dtypes.float64)
    504       sp_input = sparse_tensor.SparseTensorValue(
    505           indices=np.array([[0, 0], [1, 0], [1, 3], [1, 4], [3, 2], [3, 3]]),
    506           values=values,
    507           dense_shape=np.array([5, 6]))
    508       sp_output, empty_row_indicator = (sparse_ops.sparse_fill_empty_rows(
    509           sp_input, default_value))
    510       output, empty_row_indicator_out = sess.run(
    511           [sp_output, empty_row_indicator])
    512 
    513       self.assertAllEqual(output.indices, [[0, 0], [1, 0], [1, 3], [1, 4],
    514                                            [2, 0], [3, 2], [3, 3], [4, 0]])
    515       self.assertAllClose(output.values, [0, 10, 13, 14, -1, 32, 33, -1])
    516       self.assertAllEqual(output.dense_shape, [5, 6])
    517       self.assertAllEqual(empty_row_indicator_out,
    518                           np.array([0, 0, 1, 0, 1]).astype(np.bool))
    519 
    520       values_grad_err = gradient_checker.compute_gradient_error(
    521           values, values.shape.as_list(), sp_output.values, [8], delta=1e-8)
    522       self.assertGreater(values_grad_err, 0)
    523       self.assertLess(values_grad_err, 1e-8)
    524 
    525       default_value_grad_err = gradient_checker.compute_gradient_error(
    526           default_value,
    527           default_value.shape.as_list(),
    528           sp_output.values, [8],
    529           delta=1e-8)
    530       self.assertGreater(default_value_grad_err, 0)
    531       self.assertLess(default_value_grad_err, 1e-8)
    532 
    533   def testFillString(self):
    534     with self.test_session(use_gpu=False) as sess:
    535       sp_input = self._SparseTensor_String5x6()
    536       sp_output, empty_row_indicator = (
    537           sparse_ops.sparse_fill_empty_rows(sp_input, ""))
    538 
    539       output, empty_row_indicator_out = sess.run(
    540           [sp_output, empty_row_indicator])
    541 
    542       self.assertAllEqual(
    543           output.indices,
    544           [[0, 0], [1, 0], [1, 3], [1, 4], [2, 0], [3, 2], [3, 3], [4, 0]])
    545       self.assertAllEqual(output.values,
    546                           [b"a", b"b", b"c", b"d", b"", b"e", b"f", b""])
    547       self.assertAllEqual(output.dense_shape, [5, 6])
    548       self.assertAllEqual(empty_row_indicator_out,
    549                           np.array([0, 0, 1, 0, 1]).astype(np.bool))
    550 
    551   def testNoEmptyRows(self):
    552     with self.test_session(use_gpu=False) as sess:
    553       sp_input = self._SparseTensor_2x6()
    554       sp_output, empty_row_indicator = (
    555           sparse_ops.sparse_fill_empty_rows(sp_input, -1))
    556 
    557       output, empty_row_indicator_out = sess.run(
    558           [sp_output, empty_row_indicator])
    559 
    560       self.assertAllEqual(output.indices, [[0, 0], [1, 0], [1, 3], [1, 4]])
    561       self.assertAllEqual(output.values, [0, 10, 13, 14])
    562       self.assertAllEqual(output.dense_shape, [2, 6])
    563       self.assertAllEqual(empty_row_indicator_out, np.zeros(2).astype(np.bool))
    564 
    565 
    566 class SparseAddTest(test_util.TensorFlowTestCase):
    567 
    568   def testValuesInVariable(self):
    569     indices = constant_op.constant([[1]], dtype=dtypes.int64)
    570     values = variables.Variable([1], trainable=False, dtype=dtypes.float32)
    571     shape = constant_op.constant([1], dtype=dtypes.int64)
    572 
    573     sp_input = sparse_tensor.SparseTensor(indices, values, shape)
    574     sp_output = sparse_ops.sparse_add(sp_input, sp_input)
    575 
    576     with self.test_session(use_gpu=False) as sess:
    577       sess.run(variables.global_variables_initializer())
    578       output = sess.run(sp_output)
    579       self.assertAllEqual(output.values, [2])
    580 
    581 
    582 class SparseReduceTest(test_util.TensorFlowTestCase):
    583 
    584   # [[1, ?, 2]
    585   #  [?, 3, ?]]
    586   # where ? is implicitly-zero.
    587   ind = np.array([[0, 0], [0, 2], [1, 1]]).astype(np.int64)
    588   vals = np.array([1, 1, 1]).astype(np.int32)
    589   dense_shape = np.array([2, 3]).astype(np.int64)
    590 
    591   def _compare(self, sp_t, reduction_axes, ndims, keep_dims, do_sum):
    592     densified = sparse_ops.sparse_tensor_to_dense(sp_t).eval()
    593 
    594     np_ans = densified
    595     if reduction_axes is None:
    596       if do_sum:
    597         np_ans = np.sum(np_ans, keepdims=keep_dims)
    598       else:
    599         np_ans = np.max(np_ans, keepdims=keep_dims)
    600     else:
    601       if not isinstance(reduction_axes, list):  # Single scalar.
    602         reduction_axes = [reduction_axes]
    603       reduction_axes = np.array(reduction_axes).astype(np.int32)
    604       # Handles negative axes.
    605       reduction_axes = (reduction_axes + ndims) % ndims
    606       # Loop below depends on sorted.
    607       reduction_axes.sort()
    608       for ra in reduction_axes.ravel()[::-1]:
    609         if do_sum:
    610           np_ans = np.sum(np_ans, axis=ra, keepdims=keep_dims)
    611         else:
    612           np_ans = np.max(np_ans, axis=ra, keepdims=keep_dims)
    613 
    614     with self.test_session():
    615       if do_sum:
    616         tf_dense_ans = sparse_ops.sparse_reduce_sum(sp_t, reduction_axes,
    617                                                     keep_dims)
    618       else:
    619         tf_dense_ans = sparse_ops.sparse_reduce_max(sp_t, reduction_axes,
    620                                                     keep_dims)
    621       out_dense = tf_dense_ans.eval()
    622 
    623       if do_sum:
    624         tf_sparse_ans = sparse_ops.sparse_reduce_sum_sparse(sp_t,
    625                                                             reduction_axes,
    626                                                             keep_dims)
    627       else:
    628         tf_sparse_ans = sparse_ops.sparse_reduce_max_sparse(sp_t,
    629                                                             reduction_axes,
    630                                                             keep_dims)
    631       # Convert to dense for comparison purposes.
    632       out_sparse = sparse_ops.sparse_tensor_to_dense(tf_sparse_ans).eval()
    633 
    634     self.assertAllClose(np_ans, out_dense)
    635     self.assertAllClose(np_ans, out_sparse)
    636 
    637   def _compare_all(self, sp_t, reduction_axes, ndims):
    638     self._compare(sp_t, reduction_axes, ndims, False, False)
    639     self._compare(sp_t, reduction_axes, ndims, False, True)
    640     self._compare(sp_t, reduction_axes, ndims, True, False)
    641     self._compare(sp_t, reduction_axes, ndims, True, True)
    642 
    643   def testSimpleAndRandomInputs(self):
    644     if np.__version__ == "1.13.0":
    645       self.skipTest("numpy 1.13.0 bug")
    646 
    647     sp_t = sparse_tensor.SparseTensor(self.ind, self.vals, self.dense_shape)
    648 
    649     with self.test_session(use_gpu=False):
    650       self._compare_all(sp_t, None, ndims=2)
    651       self._compare_all(sp_t, 0, ndims=2)
    652       self._compare_all(sp_t, [1], ndims=2)
    653       self._compare_all(sp_t, [0, 1], ndims=2)
    654       self._compare_all(sp_t, [1, 0], ndims=2)
    655       self._compare_all(sp_t, [-1], ndims=2)
    656       self._compare_all(sp_t, [1, -2], ndims=2)
    657 
    658     np.random.seed(1618)
    659     test_dims = [(1618, 1, 11, 7, 1), (1,), (1, 1, 1)]
    660     with self.test_session(use_gpu=False):
    661       for dims in test_dims:
    662         sp_t, unused_nnz = _sparsify(np.random.randn(*dims))
    663         # reduce all using None
    664         self._compare_all(sp_t, None, ndims=len(dims))
    665         # reduce random axes from 1D to N-D
    666         for d in range(1, len(dims) + 1):
    667           axes = np.random.choice(len(dims), size=d, replace=False).tolist()
    668           self._compare_all(sp_t, axes, ndims=len(dims))
    669 
    670   def testInvalidAxes(self):
    671     sp_t = sparse_tensor.SparseTensor(self.ind, self.vals, self.dense_shape)
    672     with self.test_session(use_gpu=False):
    673       with self.assertRaisesOpError("Invalid reduction dimension -3"):
    674         sparse_ops.sparse_reduce_sum(sp_t, -3).eval()
    675       with self.assertRaisesOpError("Invalid reduction dimension 2"):
    676         sparse_ops.sparse_reduce_sum(sp_t, 2).eval()
    677       with self.assertRaisesOpError("Invalid reduction dimension -3"):
    678         sparse_ops.sparse_reduce_max(sp_t, -3).eval()
    679       with self.assertRaisesOpError("Invalid reduction dimension 2"):
    680         sparse_ops.sparse_reduce_max(sp_t, 2).eval()
    681 
    682   def testGradient(self):
    683     if np.__version__ == "1.13.0":
    684       self.skipTest("numpy 1.13.0 bug")
    685 
    686     np.random.seed(8161)
    687     test_dims = [(11, 1, 5, 7, 1), (2, 2)]
    688     with self.test_session(use_gpu=False):
    689       for dims in test_dims:
    690         sp_t, nnz = _sparsify(np.random.randn(*dims))
    691         # reduce random axes from 1D to N-D
    692         for d in range(1, len(dims) + 1):
    693           axes = np.random.choice(len(dims), size=d, replace=False).tolist()
    694           reduced = sparse_ops.sparse_reduce_sum(sp_t, axes)
    695 
    696           err = gradient_checker.compute_gradient_error(sp_t.values, (nnz,),
    697                                                         reduced,
    698                                                         reduced.eval().shape)
    699           self.assertLess(err, 1e-3)
    700 
    701         # Tests for negative axes.
    702         reduced = sparse_ops.sparse_reduce_sum(sp_t, -1)
    703         err = gradient_checker.compute_gradient_error(sp_t.values, (nnz,),
    704                                                       reduced,
    705                                                       reduced.eval().shape)
    706         self.assertLess(err, 1e-3)
    707 
    708 
    709 class SparseMathOpsTest(test_util.TensorFlowTestCase):
    710 
    711   def _check(self, result_tensor, result_np, input_sp_t):
    712     self.assertTrue(isinstance(result_tensor, sparse_tensor.SparseTensor))
    713     self.assertTrue(isinstance(input_sp_t, sparse_tensor.SparseTensor))
    714     self.assertAllEqual(input_sp_t.indices.eval(), result_tensor.indices.eval())
    715     self.assertAllEqual(input_sp_t.dense_shape.eval(),
    716                         result_tensor.dense_shape.eval())
    717 
    718     res_densified = sparse_ops.sparse_to_dense(result_tensor.indices,
    719                                                result_tensor.dense_shape,
    720                                                result_tensor.values).eval()
    721     self.assertAllEqual(result_np, res_densified)
    722 
    723   def testCwiseDivAndMul(self):
    724     np.random.seed(1618)
    725     sp_shapes = [(10, 10, 10), (5, 5), (1618,), (3, 3, 7)]
    726     dense_shapes = [(10, 10, 1), (5, 5), (1,), (1, 7)]
    727 
    728     with self.test_session(use_gpu=False):
    729       for dtype in [np.float32, np.float64, np.int32, np.int64]:
    730         for sp_shape, dense_shape in zip(sp_shapes, dense_shapes):
    731           sp_vals_np = np.random.rand(*sp_shape).astype(dtype) + 1
    732           dense_vals_np = np.random.rand(*dense_shape).astype(dtype) + 1
    733           sp_t, unused_nnz = _sparsify(sp_vals_np, thresh=1.5)
    734           sp_t_densified = sparse_ops.sparse_tensor_to_dense(sp_t).eval()
    735           dense_t = constant_op.constant(dense_vals_np)
    736 
    737           self._check(sp_t / dense_t, sp_t_densified / dense_vals_np, sp_t)
    738           # Check commutative.
    739           self._check(sp_t * dense_t, sp_t_densified * dense_vals_np, sp_t)
    740           self._check(dense_t * sp_t, sp_t_densified * dense_vals_np, sp_t)
    741 
    742           if dtype in [np.int32, np.int64]:
    743             res = sp_t / dense_t  # should invoke "__truediv__"
    744             self.assertEqual(res.values.eval().dtype, np.float64)
    745 
    746   def testCwiseAdd(self):
    747     with self.test_session(use_gpu=False):
    748       # Identity(2) + AllOnes(2,2).  Should be equal to 2 * Identity(2).
    749       indices = [[0, 0], [1, 1]]
    750       vals = [1, 1]
    751       shape = (2, 2)
    752 
    753       sp_t = sparse_tensor.SparseTensor(indices, vals, shape)
    754       dense_t = array_ops.ones(shape, dtype=dtypes.int32)
    755       self._check(
    756           sparse_ops.sparse_dense_cwise_add(sp_t, dense_t),
    757           np.identity(2) * 2, sp_t)
    758 
    759       # Variant of above, but broadcasts the dense side.
    760       dense_t = array_ops.ones([1], dtype=dtypes.int32)
    761       self._check(
    762           sparse_ops.sparse_dense_cwise_add(sp_t, dense_t),
    763           np.identity(2) * 2, sp_t)
    764 
    765   def testGradients(self):
    766     np.random.seed(1618)
    767     sp_shapes = [(10, 10, 10), (5, 5), (1618,), (3, 3, 7)]
    768     dense_shapes = [(10, 10, 1), (5, 5), (1,), (1, 7)]
    769 
    770     with self.test_session(use_gpu=False):
    771       for dtype in [np.float32, np.float64]:
    772         for sp_shape, dense_shape in zip(sp_shapes, dense_shapes):
    773           sp_vals_np = np.random.rand(*sp_shape).astype(dtype) + 1
    774           dense_vals_np = np.random.rand(*dense_shape).astype(dtype) + 1
    775           sp_t, nnz = _sparsify(sp_vals_np, thresh=1.5)
    776           dense_t = constant_op.constant(dense_vals_np)
    777 
    778           cmul = sp_t * dense_t
    779           err = gradient_checker.compute_gradient_error([sp_t.values, dense_t],
    780                                                         [(nnz,), dense_shape],
    781                                                         cmul.values, (nnz,))
    782           self.assertLess(err, 1e-4)
    783 
    784           cdiv = sp_t / dense_t
    785           err = gradient_checker.compute_gradient_error(sp_t.values, (nnz,),
    786                                                         cdiv.values, (nnz,))
    787           self.assertLess(err, 1e-4)
    788           err = gradient_checker.compute_gradient_error(
    789               dense_t,
    790               dense_shape,
    791               cdiv.values, (nnz,),
    792               x_init_value=dense_vals_np)
    793           self.assertLess(err, 2e-4)
    794 
    795 
    796 class SparseSoftmaxTest(test_util.TensorFlowTestCase):
    797 
    798   def testEquivalentToDensified(self):
    799     np.random.seed(1618)
    800     n, m = np.random.choice(20, size=2)
    801 
    802     for dtype in [np.float32, np.float64]:
    803       sp_vals_np = np.random.rand(n, m).astype(dtype)
    804 
    805       batched_sp_t, unused_nnz1 = _sparsify(
    806           sp_vals_np.reshape((1, n, m)), thresh=0.)  # No masking.
    807 
    808       with self.test_session(use_gpu=False):
    809         densified = constant_op.constant(sp_vals_np)
    810 
    811         sp_result = sparse_ops.sparse_softmax(batched_sp_t).eval(
    812         ).values.reshape((n, m))
    813         dense_result = nn_ops.softmax(densified)
    814 
    815         self.assertAllClose(dense_result.eval(), sp_result)
    816 
    817   def testHigherRanks(self):
    818     # For the first shape:
    819     # First batch:
    820     # [?   e.]
    821     # [1.  ? ]
    822     # Second batch:
    823     # [e   ? ]
    824     # [e   e ]
    825     #
    826     # The softmax results should be:
    827     # [?   1.]     [1    ?]
    828     # [1.  ? ] and [.5  .5]
    829     # where ? means implicitly zero.
    830     #
    831     # The second shape: same input data, but with a higher-rank shape.
    832     shapes = [[2, 2, 2], [2, 1, 2, 2]]
    833     for shape in shapes:
    834       values = np.asarray(
    835           [0., np.e, 1., 0., np.e, 0., np.e, np.e]).reshape(shape)
    836       sp_t, unused_nnz = _sparsify(values, thresh=1e-2)
    837       expected_values = [1., 1., 1., .5, .5]
    838 
    839       with self.test_session(use_gpu=False):
    840         result = sparse_ops.sparse_softmax(sp_t).eval()
    841 
    842         self.assertAllEqual(expected_values, result.values)
    843         self.assertAllEqual(sp_t.indices.eval(), result.indices)
    844         self.assertAllEqual(shape, result.dense_shape)
    845 
    846   def testGradient(self):
    847     x_shape = [2, 5, 10]
    848     with self.test_session(use_gpu=False):
    849       for dtype in [np.float32, np.float64]:
    850         x_np = np.random.randn(*x_shape).astype(dtype)
    851         x_tf, nnz = _sparsify(x_np)
    852         y_tf = sparse_ops.sparse_softmax(x_tf)
    853         err = gradient_checker.compute_gradient_error(x_tf.values, (nnz,),
    854                                                       y_tf.values, (nnz,))
    855         self.assertLess(err, 1e-4)
    856 
    857 
    858 class SparseMinimumMaximumTest(test_util.TensorFlowTestCase):
    859 
    860   def _assertSparseTensorValueEqual(self, a, b):
    861     self.assertAllEqual(a.indices, b.indices)
    862     self.assertAllEqual(a.values, b.values)
    863     self.assertAllEqual(a.dense_shape, b.dense_shape)
    864 
    865   def testBasic(self):
    866     with self.test_session(use_gpu=False):
    867       # 1-D, values at index 0.
    868       sp_zero = sparse_tensor.SparseTensor([[0]], [0], [7])
    869       sp_one = sparse_tensor.SparseTensor([[0]], [1], [7])
    870       max_tf = sparse_ops.sparse_maximum(sp_zero, sp_one).eval()
    871       min_tf = sparse_ops.sparse_minimum(sp_zero, sp_one).eval()
    872       self._assertSparseTensorValueEqual(sp_one.eval(), max_tf)
    873       self._assertSparseTensorValueEqual(sp_zero.eval(), min_tf)
    874 
    875       # Values at different indices.
    876       sp_zero = sparse_tensor.SparseTensor([[0]], [0], [7])
    877       sp_zero_2 = sparse_tensor.SparseTensor([[1]], [0], [7])
    878       expected = sparse_tensor.SparseTensor([[0], [1]], [0, 0], [7])
    879       max_tf = sparse_ops.sparse_maximum(sp_zero, sp_zero_2).eval()
    880       min_tf = sparse_ops.sparse_minimum(sp_zero, sp_zero_2).eval()
    881       self._assertSparseTensorValueEqual(expected.eval(), max_tf)
    882       self._assertSparseTensorValueEqual(expected.eval(), min_tf)
    883 
    884   def testRandom(self):
    885     np.random.seed(1618)
    886     shapes = [(13,), (6, 8), (1, 7, 1)]
    887     for shape in shapes:
    888       for dtype in [np.int32, np.int64, np.float16, np.float32, np.float64]:
    889         a_np = np.random.randn(*shape).astype(dtype)
    890         b_np = np.random.randn(*shape).astype(dtype)
    891         sp_a, unused_a_nnz = _sparsify(a_np, thresh=-.5)
    892         sp_b, unused_b_nnz = _sparsify(b_np, thresh=-.5)
    893 
    894         with self.test_session(use_gpu=False):
    895           maximum_tf = sparse_ops.sparse_maximum(sp_a, sp_b)
    896           maximum_tf_densified = sparse_ops.sparse_tensor_to_dense(
    897               maximum_tf).eval()
    898           minimum_tf = sparse_ops.sparse_minimum(sp_a, sp_b)
    899           minimum_tf_densified = sparse_ops.sparse_tensor_to_dense(
    900               minimum_tf).eval()
    901 
    902           a_densified = sparse_ops.sparse_tensor_to_dense(sp_a).eval()
    903           b_densified = sparse_ops.sparse_tensor_to_dense(sp_b).eval()
    904 
    905         self.assertAllEqual(
    906             np.maximum(a_densified, b_densified), maximum_tf_densified)
    907         self.assertAllEqual(
    908             np.minimum(a_densified, b_densified), minimum_tf_densified)
    909 
    910   def testMismatchedShapes(self):
    911     with self.test_session(use_gpu=False):
    912       sp_zero = sparse_tensor.SparseTensor([[0, 0]], [0], [1, 1])
    913       sp_one = sparse_tensor.SparseTensor([[0]], [1], [2])
    914       with self.assertRaisesOpError("Operands do not have the same ranks"):
    915         sparse_ops.sparse_maximum(sp_zero, sp_one).eval()
    916 
    917       sp_zero = sparse_tensor.SparseTensor([[0]], [0], [1])
    918       sp_one = sparse_tensor.SparseTensor([[0]], [1], [2])
    919       with self.assertRaisesOpError("Operands' shapes do not match"):
    920         sparse_ops.sparse_maximum(sp_zero, sp_one).eval()
    921 
    922 
    923 class SparseTransposeTest(test.TestCase):
    924 
    925   def testTranspose(self):
    926     if np.__version__ == "1.13.0":
    927       self.skipTest("numpy 1.13.0 bug")
    928 
    929     with self.test_session(use_gpu=False):
    930       np.random.seed(1618)
    931       shapes = [np.random.randint(1, 10, size=rank) for rank in range(1, 6)]
    932       for shape in shapes:
    933         for dtype in [np.int32, np.int64, np.float32, np.float64]:
    934           dn_input = np.random.randn(*shape).astype(dtype)
    935           rank = array_ops.rank(dn_input).eval()
    936           perm = np.random.choice(rank, rank, False)
    937           sp_input, unused_a_nnz = _sparsify(dn_input)
    938           sp_trans = sparse_ops.sparse_transpose(sp_input, perm=perm)
    939           dn_trans = sparse_ops.sparse_tensor_to_dense(sp_trans).eval()
    940           expected_trans = array_ops.transpose(dn_input, perm=perm).eval()
    941           self.assertAllEqual(expected_trans.shape, sp_trans.get_shape())
    942           self.assertAllEqual(dn_trans, expected_trans)
    943 
    944 
    945 class SparsePlaceholderTest(test.TestCase):
    946 
    947   def testPlaceholder(self):
    948     foo = array_ops.sparse_placeholder(dtypes.float32, shape=(10, 47))
    949     self.assertAllEqual([10, 47], foo.get_shape())
    950     self.assertAllEqual([None, 2], foo.indices.get_shape().as_list())
    951 
    952   def testPartialShapePlaceholder(self):
    953     foo = array_ops.sparse_placeholder(dtypes.float32, shape=(None, 47))
    954     self.assertAllEqual([None, None], foo.get_shape().as_list())
    955     self.assertAllEqual([None, 2], foo.indices.get_shape().as_list())
    956 
    957   def testNoShapePlaceholder(self):
    958     foo = array_ops.sparse_placeholder(dtypes.float32, shape=None)
    959     self.assertAllEqual(None, foo.get_shape())
    960     self.assertAllEqual([None, None], foo.indices.get_shape().as_list())
    961 
    962 
    963 if __name__ == "__main__":
    964   googletest.main()
    965