• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 array_ops."""
16from __future__ import absolute_import
17from __future__ import division
18from __future__ import print_function
19
20import re
21import time
22import unittest
23
24import numpy as np
25
26from tensorflow.python.client import session
27from tensorflow.python.eager import context
28from tensorflow.python.eager import def_function
29from tensorflow.python.framework import constant_op
30from tensorflow.python.framework import dtypes
31from tensorflow.python.framework import errors
32from tensorflow.python.framework import errors_impl
33from tensorflow.python.framework import ops
34from tensorflow.python.framework import sparse_tensor
35from tensorflow.python.framework import tensor_shape
36from tensorflow.python.framework import tensor_spec
37from tensorflow.python.framework import test_ops
38from tensorflow.python.framework import test_util
39from tensorflow.python.ops import array_ops
40from tensorflow.python.ops import gen_array_ops
41from tensorflow.python.ops import gradients_impl
42from tensorflow.python.ops import init_ops
43from tensorflow.python.ops import math_ops
44from tensorflow.python.ops import resource_variable_ops
45from tensorflow.python.ops import state_ops
46from tensorflow.python.ops import variable_scope
47from tensorflow.python.ops import variables
48from tensorflow.python.platform import test as test_lib
49
50
51@test_util.run_all_in_graph_and_eager_modes
52class BatchMatrixTransposeTest(test_util.TensorFlowTestCase):
53
54  def testNonBatchMatrix(self):
55    matrix = [[1, 2, 3], [4, 5, 6]]  # Shape (2, 3)
56    expected_transposed = [[1, 4], [2, 5], [3, 6]]  # Shape (3, 2)
57    transposed = array_ops.matrix_transpose(matrix)
58    self.assertEqual((3, 2), transposed.get_shape())
59    self.assertAllEqual(expected_transposed, transposed)
60
61  def testConjugate(self):
62    m = [[1 + 1j, 2 + 2j, 3 + 3j], [4 + 4j, 5 + 5j, 6 + 6j]]
63    expected_transposed = [[1 - 1j, 4 - 4j], [2 - 2j, 5 - 5j], [3 - 3j, 6 - 6j]]
64    matrix = ops.convert_to_tensor(m)
65    transposed = array_ops.matrix_transpose(matrix, conjugate=True)
66    self.assertEqual((3, 2), transposed.get_shape())
67    self.assertAllEqual(expected_transposed, transposed)
68
69  def testBatchMatrix(self):
70    matrix_0 = [[1, 2, 3], [4, 5, 6]]
71    matrix_0_t = [[1, 4], [2, 5], [3, 6]]
72    matrix_1 = [[11, 22, 33], [44, 55, 66]]
73    matrix_1_t = [[11, 44], [22, 55], [33, 66]]
74    batch_matrix = [matrix_0, matrix_1]  # Shape (2, 2, 3)
75    expected_transposed = [matrix_0_t, matrix_1_t]  # Shape (2, 3, 2)
76    transposed = array_ops.matrix_transpose(batch_matrix)
77    self.assertEqual((2, 3, 2), transposed.get_shape())
78    self.assertAllEqual(expected_transposed, transposed)
79
80  def testNonBatchMatrixDynamicallyDefined(self):
81    # needs explicit `constant` because lists are not automatically
82    # converted to sensors when applying `transpose` below
83    matrix = constant_op.constant([[1, 2, 3], [4, 5, 6]])  # Shape (2, 3)
84    expected_transposed = [[1, 4], [2, 5], [3, 6]]  # Shape (3, 2)
85    @def_function.function(input_signature=
86                           [tensor_spec.TensorSpec
87                            (shape=None, dtype=dtypes.int32)])
88    def transpose(matrix):
89      self.assertIs(matrix.shape.ndims, None)
90      return array_ops.matrix_transpose(matrix)
91    self.assertAllEqual(expected_transposed, transpose(matrix))
92
93  def testBatchMatrixDynamicallyDefined(self):
94    matrix_0 = [[1, 2, 3], [4, 5, 6]]
95    matrix_0_t = [[1, 4], [2, 5], [3, 6]]
96    matrix_1 = [[11, 22, 33], [44, 55, 66]]
97    matrix_1_t = [[11, 44], [22, 55], [33, 66]]
98    # needs explicit `constant` because lists are not automatically
99    # converted to sensors when applying `transpose` below
100    batch_matrix = constant_op.constant([matrix_0, matrix_1])  # Shape (2, 2, 3)
101    expected_transposed = [matrix_0_t, matrix_1_t]  # Shape (2, 3, 2)
102    @def_function.function(input_signature=
103                           [tensor_spec.TensorSpec
104                            (shape=None, dtype=dtypes.int32)])
105    def transpose(matrix):
106      self.assertIs(matrix.shape.ndims, None)
107      return array_ops.matrix_transpose(matrix)
108    self.assertAllEqual(expected_transposed, transpose(batch_matrix))
109
110  def testTensorWithStaticRankLessThanTwoRaisesBecauseNotAMatrix(self):
111    vector = [1, 2, 3]
112    with self.assertRaisesRegexp(ValueError, "should be a "):
113      array_ops.matrix_transpose(vector)
114
115
116class BooleanMaskTest(test_util.TensorFlowTestCase):
117
118  def setUp(self):
119    self.rng = np.random.RandomState(42)
120
121  def CheckVersusNumpy(self, ndims_mask, arr_shape, make_mask=None, axis=None):
122    """Check equivalence between boolean_mask and numpy masking."""
123    if make_mask is None:
124      make_mask = lambda shape: self.rng.randint(0, 2, size=shape).astype(bool)
125    arr = np.random.rand(*arr_shape)
126    mask = make_mask(arr_shape[:ndims_mask])
127    if axis is not None:
128      mask = make_mask(arr_shape[axis:ndims_mask + axis])
129    if axis is None or axis == 0:
130      masked_arr = arr[mask]
131    elif axis == 1:
132      masked_arr = arr[:, mask]
133    elif axis == 2:
134      masked_arr = arr[:, :, mask]
135    with self.cached_session():
136      masked_tensor = array_ops.boolean_mask(arr, mask, axis=axis)
137
138      # Leading dimension size of masked_tensor is always unknown until runtime
139      # since we don't how many elements will be kept.
140      leading = 1 if axis is None else axis + 1
141      self.assertAllEqual(masked_tensor.get_shape()[leading:],
142                          masked_arr.shape[leading:])
143
144      self.assertAllClose(masked_arr, masked_tensor.eval())
145
146  @test_util.run_deprecated_v1
147  def testMaskDim1ArrDim2Axis1(self):
148    ndims_mask = 1
149    for arr_shape in [(1, 1), (2, 2), (2, 5)]:
150      self.CheckVersusNumpy(ndims_mask, arr_shape, axis=1)
151
152  @test_util.run_deprecated_v1
153  def testMaskDim2ArrDim2Axis1(self):
154    ndims_mask = 2
155    for arr_shape in [(1, 1), (2, 2), (2, 5)]:
156      self.CheckVersusNumpy(ndims_mask, arr_shape, axis=1)
157
158  @test_util.run_deprecated_v1
159  def testMaskDim1ArrDim1(self):
160    ndims_mask = 1
161    for arr_shape in [(1,), (2,), (3,), (10,)]:
162      self.CheckVersusNumpy(ndims_mask, arr_shape)
163
164  @test_util.run_deprecated_v1
165  def testMaskDim1ArrDim2(self):
166    ndims_mask = 1
167    for arr_shape in [(1, 1), (2, 2), (2, 5)]:
168      self.CheckVersusNumpy(ndims_mask, arr_shape)
169
170  @test_util.run_deprecated_v1
171  def testMaskDim2ArrDim2(self):
172    ndims_mask = 2
173    for arr_shape in [(1, 1), (2, 2), (2, 5)]:
174      self.CheckVersusNumpy(ndims_mask, arr_shape)
175
176  @test_util.run_deprecated_v1
177  def testMaskDim2ArrDim3(self):
178    ndims_mask = 2
179    for arr_shape in [(1, 1, 1), (1, 2, 2), (2, 2, 1)]:
180      self.CheckVersusNumpy(ndims_mask, arr_shape)
181
182  @test_util.run_deprecated_v1
183  def testEmptyInput2D(self):
184    mask = np.array([True, False])
185    arr = np.array([[], []]).astype(np.float32)
186    numpy_result = arr[mask]
187    tf_result = array_ops.boolean_mask(arr, mask)
188    self.assertAllEqual(numpy_result.shape[1:], tf_result.get_shape()[1:])
189    with self.cached_session():
190      self.assertAllClose(numpy_result, tf_result.eval())
191
192  def testEmptyInput1D(self):
193    mask = np.array([]).astype(bool)
194    arr = np.array([]).astype(np.float32)
195    numpy_result = arr[mask]
196    tf_result = array_ops.boolean_mask(arr, mask)
197    self.assertAllEqual(numpy_result.shape[1:], tf_result.get_shape()[1:])
198    with self.cached_session():
199      self.assertAllClose(numpy_result, tf_result.eval())
200
201  @test_util.run_deprecated_v1
202  def testEmptyOutput(self):
203    make_mask = lambda shape: np.zeros(shape, dtype=bool)
204    for ndims_mask in range(1, 4):
205      for ndims_arr in range(ndims_mask, ndims_mask + 3):
206        for _ in range(3):
207          arr_shape = np.random.randint(1, 5, size=ndims_arr)
208          self.CheckVersusNumpy(ndims_mask, arr_shape, make_mask=make_mask)
209
210  @test_util.run_deprecated_v1
211  def testWorksWithDimensionsEqualToNoneDuringGraphBuild(self):
212    # The rank of the mask tensor must be specified. This is explained
213    # in the docstring as well.
214    with self.cached_session() as sess:
215      ph_tensor = array_ops.placeholder(dtypes.int32, shape=None)
216      ph_mask = array_ops.placeholder(dtypes.bool, shape=[None])
217
218      arr = np.array([[1, 2], [3, 4]])
219      mask = np.array([False, True])
220
221      masked_tensor = sess.run(
222          array_ops.boolean_mask(ph_tensor, ph_mask),
223          feed_dict={
224              ph_tensor: arr,
225              ph_mask: mask
226          })
227      np.testing.assert_allclose(masked_tensor, arr[mask])
228
229  @test_util.run_deprecated_v1
230  def testMaskDimensionsSetToNoneRaises(self):
231    # The rank of the mask tensor must be specified. This is explained
232    # in the docstring as well.
233    with self.cached_session():
234      tensor = array_ops.placeholder(dtypes.int32, shape=[None, 2])
235      mask = array_ops.placeholder(dtypes.bool, shape=None)
236      with self.assertRaisesRegexp(ValueError, "dimensions must be specified"):
237        array_ops.boolean_mask(tensor, mask)
238
239  def testMaskHasMoreDimsThanTensorRaises(self):
240    mask = [[True, True], [False, False]]
241    tensor = [1, 2, 3, 4]
242    with self.cached_session():
243      with self.assertRaisesRegexp(ValueError, "incompatible"):
244        array_ops.boolean_mask(tensor, mask).eval()
245
246  def testMaskIsScalarRaises(self):
247    mask = True
248    tensor = 1
249    with self.cached_session():
250      with self.assertRaisesRegexp(ValueError, "mask.*scalar"):
251        array_ops.boolean_mask(tensor, mask).eval()
252
253  def testMaskShapeDifferentThanFirstPartOfTensorShapeRaises(self):
254    mask = [True, True, True]
255    tensor = [[1, 2], [3, 4]]
256    with self.cached_session():
257      with self.assertRaisesRegexp(ValueError, "incompatible"):
258        array_ops.boolean_mask(tensor, mask).eval()
259
260
261@test_util.run_all_in_graph_and_eager_modes
262class OperatorShapeTest(test_util.TensorFlowTestCase):
263
264  def testExpandScalar(self):
265    scalar = "hello"
266    scalar_expanded = array_ops.expand_dims(scalar, [0])
267    self.assertEqual(scalar_expanded.get_shape(), (1,))
268
269  def testSqueezeScalar(self):
270    scalar = "hello"
271    scalar_squeezed = array_ops.squeeze(scalar, ())
272    self.assertEqual(scalar_squeezed.get_shape(), ())
273
274  def testSqueezeMatrix(self):
275    matrix = [[1, 2, 3]]
276    matrix_squeezed = array_ops.squeeze(matrix, [0])
277    self.assertEqual(matrix_squeezed.get_shape(), (3))
278
279    with self.assertRaisesRegexp(
280        Exception, "Can not squeeze dim.1., expected a dimension of 1, got 3"):
281      matrix_squeezed = array_ops.squeeze(matrix, [1])
282
283  def testSqueezeScalarDim(self):
284    matrix = [[1, 2, 3]]
285    matrix_squeezed = array_ops.squeeze(matrix, 0)
286    self.assertEqual(matrix_squeezed.get_shape(), (3))
287
288  def testExpandDimsWithNonScalarDim(self):
289    with self.assertRaisesRegexp(Exception,
290                                 "must be a tensor with a single value"):
291      array_ops.expand_dims(1, axis=[0, 1])
292
293
294class ReverseV2Test(test_util.TensorFlowTestCase):
295
296  @test_util.run_deprecated_v1
297  def testReverse0DimAuto(self):
298    x_np = 4
299    for use_gpu in [False, True]:
300      with self.cached_session(use_gpu=use_gpu):
301        x_tf = array_ops.reverse_v2(x_np, []).eval()
302        self.assertAllEqual(x_tf, x_np)
303
304  def _reverse1DimAuto(self, np_dtype):
305    x_np = np.array([1, 200, 3, 40, 5], dtype=np_dtype)
306
307    for use_gpu in [False, True]:
308      for axis_dtype in [dtypes.int32, dtypes.int64]:
309        with self.cached_session(use_gpu=use_gpu):
310          x_tf = array_ops.reverse_v2(x_np,
311                                      constant_op.constant(
312                                          [0], dtype=axis_dtype)).eval()
313          self.assertAllEqual(x_tf, np.asarray(x_np)[::-1])
314
315  def _reverse2DimAuto(self, np_dtype):
316    x_np = np.array([[1, 200, 3], [4, 5, 60]], dtype=np_dtype)
317
318    for reverse_f in [array_ops.reverse_v2, array_ops.reverse]:
319      for use_gpu in [False, True]:
320        for axis_dtype in [dtypes.int32, dtypes.int64]:
321          with self.cached_session(use_gpu=use_gpu):
322            x_tf_1 = reverse_f(x_np, constant_op.constant(
323                [0], dtype=axis_dtype)).eval()
324            x_tf_2 = reverse_f(x_np, constant_op.constant(
325                [-2], dtype=axis_dtype)).eval()
326            x_tf_3 = reverse_f(x_np, constant_op.constant(
327                [1], dtype=axis_dtype)).eval()
328            x_tf_4 = reverse_f(x_np, constant_op.constant(
329                [-1], dtype=axis_dtype)).eval()
330            x_tf_5 = reverse_f(x_np,
331                               constant_op.constant([1, 0],
332                                                    dtype=axis_dtype)).eval()
333            self.assertAllEqual(x_tf_1, np.asarray(x_np)[::-1, :])
334            self.assertAllEqual(x_tf_2, np.asarray(x_np)[::-1, :])
335            self.assertAllEqual(x_tf_3, np.asarray(x_np)[:, ::-1])
336            self.assertAllEqual(x_tf_4, np.asarray(x_np)[:, ::-1])
337            self.assertAllEqual(x_tf_5, np.asarray(x_np)[::-1, ::-1])
338
339  # This test covers the axis validation in the shape function
340  # (no eval())
341  @test_util.run_deprecated_v1
342  def testInvalidAxis(self):
343    x_np = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)
344    with self.assertRaisesRegexp(ValueError,
345                                 "is out of valid range"):
346      array_ops.reverse_v2(x_np, [-30])
347    with self.assertRaisesRegexp(ValueError,
348                                 "is out of valid range"):
349      array_ops.reverse_v2(x_np, [2])
350    with self.assertRaisesRegexp(ValueError,
351                                 "axis 0 specified more than once"):
352      array_ops.reverse_v2(x_np, [0, -2])
353
354  # This is the version of reverse that uses axis indices rather than
355  # bool tensors
356  # TODO(b/32254538): Change this test to use array_ops.reverse
357  #
358  # Note: this test passes placeholder as constant axis is validated
359  # in shape function (see testInvalidAxis)
360  @test_util.run_deprecated_v1
361  def testInvalid(self):
362    x_np = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)
363    axis = array_ops.placeholder(dtypes.int32)
364    with self.cached_session():
365      with self.assertRaisesRegexp(errors_impl.InvalidArgumentError,
366                                   "is out of valid range"):
367        array_ops.reverse_v2(x_np, axis).eval(feed_dict={axis: [-30]})
368      with self.assertRaisesRegexp(errors_impl.InvalidArgumentError,
369                                   "is out of valid range"):
370        array_ops.reverse_v2(x_np, axis).eval(feed_dict={axis: [2]})
371      with self.assertRaisesRegexp(errors_impl.InvalidArgumentError,
372                                   "axis 0 specified more than once"):
373        array_ops.reverse_v2(x_np, axis).eval(feed_dict={axis: [0, -2]})
374
375  @test_util.run_deprecated_v1
376  def testReverse1DimAuto(self):
377    for dtype in [
378        np.uint8, np.int8, np.uint16, np.int16, np.int32, np.int64, np.bool,
379        np.float16, np.float32, np.float64, np.complex64, np.complex128,
380        np.array(b"").dtype.type
381    ]:
382      self._reverse1DimAuto(dtype)
383
384  @test_util.run_deprecated_v1
385  def testReverse2DimAuto(self):
386    for dtype in [
387        np.uint8, np.int8, np.uint16, np.int16, np.int32, np.int64, np.bool,
388        np.float16, np.float32, np.float64, np.complex64, np.complex128,
389        np.array(b"").dtype.type
390    ]:
391      self._reverse2DimAuto(dtype)
392
393  @test_util.run_deprecated_v1
394  def testUnknownDims(self):
395    reverse_v2 = array_ops.reverse_v2
396    data_t = array_ops.placeholder(dtypes.float32)
397    axis_known_t = array_ops.placeholder(dtypes.int32, shape=[3])
398    reverse_known_t = reverse_v2(data_t, axis_known_t)
399    # Unlike V1 we cannot know this anymore
400    self.assertEqual(None, reverse_known_t.get_shape().ndims)
401
402    axis_unknown_t = array_ops.placeholder(dtypes.int32)
403    reverse_unknown_t = reverse_v2(data_t, axis_unknown_t)
404    self.assertIs(None, reverse_unknown_t.get_shape().ndims)
405
406    data_2d_t = array_ops.placeholder(dtypes.float32, shape=[None, None])
407    axis_2d_t = array_ops.placeholder(dtypes.int32, shape=[3])
408    reverse_2d_t = reverse_v2(data_2d_t, axis_2d_t)
409    self.assertEqual(2, reverse_2d_t.get_shape().ndims)
410
411  @test_util.run_deprecated_v1
412  def testReverseRowsOf3Channels(self):
413    """Tests optimized code for reversing rows with last dim size = 3."""
414    with self.session(use_gpu=True):
415      for reverse_f in [array_ops.reverse_v2, array_ops.reverse]:
416        for outer_size in (1, 2):
417          for middle_size in list(range(50)) + [100000]:
418            x_np = np.reshape(
419                np.arange(outer_size * middle_size * 3, dtype=np.float32),
420                newshape=(outer_size, middle_size, 3))
421            x_tf = reverse_f(x_np, [1]).eval()
422            np_answer = x_np[:, ::-1, :]
423            self.assertAllEqual(x_tf, np_answer)
424
425  @test_util.run_deprecated_v1
426  def testReverseRowsOf4Channels(self):
427    with self.session(use_gpu=True):
428      for reverse_f in [array_ops.reverse_v2, array_ops.reverse]:
429        for outer_size in (1, 2):
430          for middle_size in list(range(50)) + [100000]:
431            x_np = np.reshape(
432                np.arange(outer_size * middle_size * 4, dtype=np.float32),
433                newshape=(outer_size, middle_size, 4))
434            x_tf = reverse_f(x_np, [1]).eval()
435            np_answer = x_np[:, ::-1, :]
436            self.assertAllEqual(x_tf, np_answer)
437
438  def testReverseColumnsOf3Channels(self):
439    with self.session(use_gpu=True):
440      for reverse_f in [array_ops.reverse_v2, array_ops.reverse]:
441        for outer_size in list(range(50)) + [100000]:
442          for middle_size in (1, 2):
443            x_np = np.reshape(
444                np.arange(outer_size * middle_size * 3, dtype=np.float32),
445                newshape=(outer_size, middle_size, 3))
446            x_tf = reverse_f(x_np, [0]).eval()
447            np_answer = x_np[::-1, :, :]
448            self.assertAllEqual(x_tf, np_answer)
449
450
451class MeshgridTest(test_util.TensorFlowTestCase):
452
453  def _compareDiff(self, x, y, use_gpu):
454    for index in ("ij", "xy"):
455      numpy_out = np.meshgrid(x, y, indexing=index)
456      tf_out = array_ops.meshgrid(x, y, indexing=index)
457      with self.cached_session(use_gpu=use_gpu):
458        for xx, yy in zip(numpy_out, tf_out):
459          self.assertAllEqual(xx, yy.eval())
460
461  def _compareDiffType(self, n, np_dtype, use_gpu):
462    inputs = []
463    for index in ("ij", "xy"):
464      for _ in range(n):
465        x = np.linspace(-10, 10, 5).astype(np_dtype)
466        if np_dtype in (np.complex64, np.complex128):
467          x += 1j
468        inputs.append(x)
469      numpy_out = np.meshgrid(*inputs, indexing=index)
470      with self.cached_session(use_gpu=use_gpu):
471        tf_out = array_ops.meshgrid(*inputs, indexing=index)
472        for x_np, x_tf in zip(numpy_out, tf_out):
473          self.assertAllEqual(x_np, x_tf.eval())
474
475  @test_util.run_deprecated_v1
476  def testCompare(self):
477    for t in (np.float16, np.float32, np.float64, np.int32, np.int64,
478              np.complex64, np.complex128):
479      self._compareDiffType(2, t, False)
480      self._compareDiffType(3, t, False)
481
482      x = [1, 2, 3]
483      y = [4, 5]
484
485      a = [[1, 1], [1, 1]]
486
487      self._compareDiff(x, y, False)
488      self._compareDiff(x, a, False)
489
490
491class StridedSliceChecker(object):
492  """Check a given tensor against the numpy result."""
493
494  REF_TENSOR = np.arange(1, 19, dtype=np.float32).reshape(3, 2, 3)
495  REF_TENSOR_ALIGNED = np.arange(1, 97, dtype=np.float32).reshape(3, 4, 8)
496
497  def __init__(self, test, x, tensor_type=dtypes.int32, check_type_infer=True):
498    self.x_np = np.array(x).astype(tensor_type.as_numpy_dtype)
499    if tensor_type.is_bool:
500      self.x_np = np.array(x % 3).astype(np.bool)
501    # Give the value a non-zero imaginary component for complex types.
502    if tensor_type.is_complex:
503      self.x_np -= 1j * self.x_np
504    self.test = test
505    self.x = constant_op.constant(self.x_np, dtype=tensor_type)
506    self.check_type_infer = check_type_infer
507
508  def __getitem__(self, spec):
509    op = self.x.__getitem__(spec)
510
511    def eval_if_tensor(x):
512      try:
513        return x.eval()
514      except AttributeError:
515        return x
516
517    if isinstance(spec, bool) or \
518      (isinstance(spec, ops.Tensor) and spec.dtype == dtypes.bool) or \
519      (isinstance(spec, np.ndarray) and spec.dtype == bool) or \
520      (isinstance(spec, (list, tuple)) and np.asarray(spec).dtype == bool):
521      tensor = op.eval()
522      np_spec = eval_if_tensor(spec)
523      self.test.assertAllEqual(self.x_np[np_spec], tensor)
524      return tensor
525
526    if not isinstance(spec, (list, tuple)):
527      spec = [spec]
528
529    tensor = op.eval()
530
531    # Make a numpy spec that pre-evals the tensors
532    np_specs = []
533
534    for s in spec:
535      if isinstance(s, slice):
536        start = eval_if_tensor(s.start)
537        stop = eval_if_tensor(s.stop)
538        step = eval_if_tensor(s.step)
539        np_specs.append(slice(start, stop, step))
540      else:
541        np_specs.append(eval_if_tensor(s))
542
543    self.test.assertAllEqual(self.x_np[tuple(np_specs)], tensor)
544    if self.check_type_infer:
545      self.test.assertAllEqual(tensor.shape, op.get_shape())
546    return tensor
547
548
549STRIDED_SLICE_TYPES = [
550    dtypes.int32, dtypes.int64, dtypes.int16, dtypes.int8, dtypes.float32,
551    dtypes.float64, dtypes.complex64, dtypes.complex128, dtypes.bool
552]
553
554
555class StridedSliceTest(test_util.TensorFlowTestCase):
556  """Test the strided slice operation with variants of slices."""
557
558  @test_util.run_deprecated_v1
559  def test_basic_slice(self):
560    for tensor_type in STRIDED_SLICE_TYPES:
561      with self.cached_session(use_gpu=True):
562        checker = StridedSliceChecker(
563            self, StridedSliceChecker.REF_TENSOR, tensor_type=tensor_type)
564        _ = checker[:, :, :]
565        # Various ways of representing identity slice
566        _ = checker[:, :, :]
567        _ = checker[::, ::, ::]
568        _ = checker[::1, ::1, ::1]
569        # Not zero slice
570        _ = checker[::1, ::5, ::2]
571        # Reverse in each dimension independently
572        _ = checker[::-1, :, :]
573        _ = checker[:, ::-1, :]
574        _ = checker[:, :, ::-1]
575        ## negative index tests i.e. n-2 in first component
576        _ = checker[-2::-1, :, ::1]
577        # negative index tests i.e. n-2 in first component, non-unit stride
578        _ = checker[-2::-1, :, ::2]
579
580        # Check rank-0 examples
581        checker2 = StridedSliceChecker(self, 5, tensor_type=tensor_type)
582        _ = checker2[None]
583        _ = checker2[...]
584        _ = checker2[tuple()]
585
586  def testInt64GPU(self):
587    if not test_util.is_gpu_available():
588      self.skipTest("No GPU available")
589
590    with test_util.force_gpu():
591      x = constant_op.constant([1., 2., 3.])
592      begin = constant_op.constant([2], dtype=dtypes.int64)
593      end = constant_op.constant([3], dtype=dtypes.int64)
594      strides = constant_op.constant([1], dtype=dtypes.int64)
595      s = array_ops.strided_slice(x, begin, end, strides)
596      self.assertAllEqual([3.], self.evaluate(s))
597
598  @test_util.assert_no_new_pyobjects_executing_eagerly
599  @test_util.assert_no_garbage_created
600  def testTensorSliceEagerMemory(self):
601    with context.eager_mode():
602      inputs = constant_op.constant(
603          [[[1], [2], [3], [4]]], dtype=dtypes.float32)
604      # Tests that slicing an EagerTensor doesn't leak memory
605      inputs[0]  # pylint: disable=pointless-statement
606
607  @test_util.assert_no_new_pyobjects_executing_eagerly
608  @test_util.assert_no_garbage_created
609  def testVariableSliceEagerMemory(self):
610    with context.eager_mode():
611      v = variables.Variable([1., 2.])
612      v[0]  # pylint: disable=pointless-statement
613
614  @test_util.run_deprecated_v1
615  def testDegenerateSlices(self):
616    with self.session(use_gpu=True):
617      checker = StridedSliceChecker(self, StridedSliceChecker.REF_TENSOR)
618      # degenerate by offering a forward interval with a negative stride
619      _ = checker[0:-1:-1, :, :]
620      # degenerate with a reverse interval with a positive stride
621      _ = checker[-1:0, :, :]
622      # empty interval in every dimension
623      _ = checker[-1:0, 2:2, 2:3:-1]
624      # empty first dimension only (used to break for aligned tensors).
625      checker = StridedSliceChecker(self,
626                                    StridedSliceChecker.REF_TENSOR_ALIGNED)
627      _ = checker[1:0]
628
629  @test_util.run_deprecated_v1
630  def testEllipsis(self):
631    with self.session(use_gpu=True):
632      raw = [[[[[1, 2], [3, 4], [5, 6]]], [[[7, 8], [9, 10], [11, 12]]]]]
633      checker = StridedSliceChecker(self, raw)
634
635      _ = checker[0:]
636      # implicit ellipsis
637      _ = checker[0:, ...]
638      # ellipsis alone
639      _ = checker[...]
640      # ellipsis at end
641      _ = checker[0:1, ...]
642      # ellipsis at begin
643      _ = checker[..., 0:1]
644      # ellipsis at middle
645      _ = checker[0:1, ..., 0:1]
646      # multiple ellipses not allowed
647      with self.assertRaisesRegexp(ValueError, "Multiple ellipses"):
648        _ = checker[..., :, ...].eval()
649
650  @test_util.run_deprecated_v1
651  def testShrink(self):
652    with self.session(use_gpu=True):
653      raw = [[[[[1, 2, 4, 5], [5, 6, 7, 8], [9, 10, 11, 12]]],
654              [[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]]]]
655      checker = StridedSliceChecker(self, raw)
656      _ = checker[:, :, :, :, 3]
657      _ = checker[..., 3]
658      _ = checker[:, 0]
659      _ = checker[:, :, 0]
660
661  @test_util.run_deprecated_v1
662  def testBothNewAxisAndShrink(self):
663    with self.session(use_gpu=True):
664      ones = array_ops.placeholder(shape=[2, 2], dtype=dtypes.int16)
665      self.assertAllEqual(
666          ones[array_ops.newaxis, :, 0].eval(
667              feed_dict={ones: [[1, 1], [1, 1]]}),
668          [[1, 1]])
669
670  @test_util.run_deprecated_v1
671  def testTensorIndexing(self):
672    with self.session(use_gpu=True):
673      raw = [[[[[1, 2, 4, 5], [5, 6, 7, 8], [9, 10, 11, 12]]],
674              [[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]]]]
675      checker = StridedSliceChecker(self, raw, check_type_infer=False)
676      bar = constant_op.constant(2)
677      bar2 = constant_op.constant(3)
678      _ = checker[..., bar:bar2]
679      _ = checker[..., bar]
680      _ = checker[..., 3]
681      _ = checker[..., 2 ** 64 // 2**63]  # Test longs in Python 2
682
683  def testTensorIndexingTypeError(self):
684    with self.session(use_gpu=True):
685      checker = StridedSliceChecker(self, StridedSliceChecker.REF_TENSOR)
686      expected = re.escape(array_ops._SLICE_TYPE_ERROR)
687      with self.assertRaisesRegexp(TypeError, expected):
688        _ = checker["foo"]
689      with self.assertRaisesRegexp(TypeError, expected):
690        _ = checker[constant_op.constant("foo")]
691      with self.assertRaisesRegexp(TypeError, expected):
692        _ = checker[0.0]
693      with self.assertRaisesRegexp(TypeError, expected):
694        _ = checker[constant_op.constant(0.0)]
695      with self.assertRaisesRegexp(TypeError, expected):
696        _ = checker[constant_op.constant([1, 2, 3])]
697      with self.assertRaisesRegexp(TypeError, expected):
698        _ = checker[[2.1, -0.7, 1.5]]
699
700  @test_util.run_deprecated_v1
701  def testExpand(self):
702    with self.session(use_gpu=True):
703      raw = [[[[[1, 2, 4, 5], [5, 6, 7, 8], [9, 10, 11, 12]]],
704              [[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]]]]
705      checker = StridedSliceChecker(self, raw)
706      # new axis (followed by implicit ellipsis)
707      _ = checker[np.newaxis]
708      # newaxis after ellipsis
709      _ = checker[..., np.newaxis]
710      # newaxis in between ellipsis and explicit range
711      _ = checker[..., np.newaxis, :]
712      _ = checker[:, ..., np.newaxis, :, :]
713      # Reverse final dimension with new axis
714      _ = checker[:, :, np.newaxis, :, 2::-1]
715      # Ellipsis in middle of two newaxis
716      _ = checker[np.newaxis, ..., np.newaxis]
717
718  @test_util.run_deprecated_v1
719  def testExpandVariable(self):
720    with self.session(use_gpu=True):
721      x = variables.Variable(7, dtype=dtypes.int32)
722      x.initializer.run()
723      y = x[None].eval()
724      self.assertEqual(y.shape, (1,))
725      self.assertAllEqual(y, (7,))
726
727  @test_util.run_deprecated_v1
728  def testOptimizedCases(self):
729    with self.session(use_gpu=True):
730      checker = StridedSliceChecker(self,
731                                    StridedSliceChecker.REF_TENSOR_ALIGNED)
732      # Identity
733      _ = checker[:]
734      # Identity
735      _ = checker[...]
736      # Identity
737      _ = checker[np.newaxis, ..., np.newaxis]
738      # First axis slice
739      _ = checker[1:]
740      # First axis slice
741      _ = checker[np.newaxis, 1:]
742
743  def testMasks(self):
744    with self.session(use_gpu=True):
745      scalar = np.array(0)
746      # Test tensor type mask
747      checker = StridedSliceChecker(self, StridedSliceChecker.REF_TENSOR)
748      _ = checker[checker.x > 2]
749      _ = checker[checker.x <= 5]
750      _ = checker[ops.convert_to_tensor(scalar)]
751
752      # Test numpy array type mask
753      raw = np.array([[[[[1, 2, 4, 5], [5, 6, 7, 8], [9, 10, 11, 12]]],
754                       [[[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23,
755                                                              24]]]]])
756      checker1 = StridedSliceChecker(self, raw)
757      _ = checker1[raw >= 4]
758      _ = checker1[raw < 19]
759      _ = checker1[scalar]
760
761      # Test boolean and non boolean cases
762      mask = np.array([True, False, True])
763      raw1 = np.array([[1, 2, 4, 5], [5, 6, 7, 8], [9, 10, 11, 12]])
764      checker2 = StridedSliceChecker(self, raw1)
765      _ = checker2[mask]
766      _ = checker2[ops.convert_to_tensor(mask)]
767
768
769class StridedSliceShapeChecker(object):
770
771  def __init__(self, x):
772    self.x = x
773
774  def __getitem__(self, spec):
775    op = self.x.__getitem__(spec)
776    return op.get_shape()
777
778
779class StridedSliceShapeTest(test_util.TensorFlowTestCase):
780  """Test the shape inference of StridedSliceShapes."""
781
782  @test_util.run_deprecated_v1
783  def testUnknown(self):
784    with self.session(use_gpu=True):
785      uncertain_tensor = array_ops.placeholder(dtypes.float32)
786      a = StridedSliceShapeChecker(uncertain_tensor)
787      a_slice_shape = a[...]
788      self.assertAllEqual(a_slice_shape.ndims, None)
789
790  def tensorShapeEqual(self, x, y):
791    self.assertTrue(x is not None and y is not None or x is None and y is None)
792    self.assertEqual(x.as_list(), y.as_list())
793
794  @test_util.run_deprecated_v1
795  def testTensorShapeUncertain(self):
796    with self.session(use_gpu=True):
797      uncertain_tensor = array_ops.placeholder(
798          dtypes.float32, shape=(5, None, 7))
799      a = StridedSliceShapeChecker(uncertain_tensor)
800      self.tensorShapeEqual(a[3:5], tensor_shape.TensorShape([2, None, 7]))
801      self.tensorShapeEqual(a[3:5, :, 4], tensor_shape.TensorShape([2, None]))
802      self.tensorShapeEqual(a[3:5, 3:4, 4], tensor_shape.TensorShape([2, None]))
803      self.tensorShapeEqual(a[3:5, :, 5:10],
804                            tensor_shape.TensorShape([2, None, 2]))
805      self.tensorShapeEqual(a[3:5, :, 50:3],
806                            tensor_shape.TensorShape([2, None, 0]))
807      self.tensorShapeEqual(a[3:5, :, array_ops.newaxis, 50:3,],
808                            tensor_shape.TensorShape([2, None, 1, 0]))
809      self.tensorShapeEqual(a[1:5:2, :, array_ops.newaxis, 50:3,],
810                            tensor_shape.TensorShape([2, None, 1, 0]))
811      self.tensorShapeEqual(a[:5:3, :, array_ops.newaxis, 50:3,],
812                            tensor_shape.TensorShape([2, None, 1, 0]))
813      self.tensorShapeEqual(a[:2:3, :, array_ops.newaxis, 50:3,],
814                            tensor_shape.TensorShape([1, None, 1, 0]))
815      self.tensorShapeEqual(a[::-1, :, array_ops.newaxis, ::-2],
816                            tensor_shape.TensorShape([5, None, 1, 4]))
817
818  @test_util.run_deprecated_v1
819  def testTensorValuedIndexShape(self):
820    with self.session(use_gpu=True):
821      defined_shape_tensor = array_ops.placeholder(
822          dtypes.float32, shape=(5, 3, 7))
823      index_value = array_ops.placeholder(dtypes.int32, shape=())
824      a = StridedSliceShapeChecker(defined_shape_tensor)
825      self.tensorShapeEqual(a[index_value], tensor_shape.TensorShape([3, 7]))
826      self.tensorShapeEqual(a[index_value, ::-1],
827                            tensor_shape.TensorShape([3, 7]))
828      self.tensorShapeEqual(a[index_value, ::-2],
829                            tensor_shape.TensorShape([2, 7]))
830      other_scalar = array_ops.placeholder(dtypes.int32, shape=())
831      self.tensorShapeEqual(a[index_value, other_scalar:2],
832                            tensor_shape.TensorShape([None, 7]))
833
834
835class GradSliceChecker(object):
836  """Tests that we can compute a gradient for var^2."""
837
838  def __init__(self, test, sess, var, varnp):
839    self.test = test
840    self.sess = sess
841    self.val = var * var
842    self.var = var
843    self.varnp = varnp
844
845  def __getitem__(self, spec):
846    slice_var = self.var[spec]
847    slice_val = self.val[spec]
848
849    # compute analytic 2nd derivative
850    analytic_grad2 = 2 * slice_val
851
852    dy = variables.Variable(
853        array_ops.ones_like(slice_var, dtype=dtypes.float32))
854    assign = dy.assign(slice_var)
855    slice_val_grad, = gradients_impl.gradients(slice_val, self.var, grad_ys=dy)
856    slice_val_grad2, = gradients_impl.gradients(
857        slice_val_grad, dy, grad_ys=self.var)
858    self.sess.run(assign)
859    slice_val_grad_evaled, slice_val_grad2_evaled = (
860        self.sess.run([slice_val_grad, slice_val_grad2]))
861    analytic_grad2_evaled = analytic_grad2.eval()
862    self.test.assertAllEqual(slice_val_grad2_evaled, analytic_grad2_evaled)
863
864    # compute analytic gradient for slice
865    np_val_grad = (2 * self.varnp * self.varnp)
866    np_sliceval_grad = np.zeros(self.var.get_shape())
867    if isinstance(spec, ops.Tensor):
868      spec = self.sess.run([spec])
869    np_sliceval_grad[spec] = np_val_grad[spec]
870    # verify gradient
871    self.test.assertAllEqual(slice_val_grad_evaled, np_sliceval_grad)
872
873
874class StridedSliceGradTest(test_util.TensorFlowTestCase):
875  """Test that strided slice's custom gradient produces correct gradients."""
876
877  @test_util.run_deprecated_v1
878  def testGradient(self):
879    with self.session(use_gpu=True) as sess:
880      var = variables.Variable(
881          array_ops.reshape(
882              math_ops.range(1, 97, 1, dtype=dtypes.float32), shape=(6, 4, 4)))
883      init = variables.global_variables_initializer()
884      sess.run(init)
885
886      raw = np.array(range(1, 97, 1)).reshape((6, 4, 4))
887      grad = GradSliceChecker(self, sess, var, raw)
888      _ = grad[2:6:2, 1:3, 1:3]
889      _ = grad[3:0:-2, 1:3, 1:3]
890      _ = grad[3:0:-2, array_ops.newaxis, 1:3, 2, array_ops.newaxis]
891      _ = grad[3:0:-2, 1:3, 2]
892      _ = grad[:, -1, :]
893      _ = grad[:, -2, :]
894      with self.assertRaisesRegexp(ValueError, "out of bounds"):
895        _ = grad[:, -200, :]
896      with self.assertRaisesRegexp(ValueError, "out of bounds"):
897        _ = grad[:, 200, :]
898
899      # Test numpy array type mask
900      _ = grad[raw > 51]
901      # Test tensor type mask
902      _ = grad[ops.convert_to_tensor(raw) <= 76]
903
904  def testGradientZero(self):
905    with self.session(use_gpu=True) as sess:
906      var = variables.Variable(8.)
907      init = variables.global_variables_initializer()
908      sess.run(init)
909      grad = GradSliceChecker(self, sess, var, np.array(8))
910      _ = grad[tuple()]
911
912  @test_util.run_deprecated_v1
913  def testInt64Indices(self):
914    with self.session(use_gpu=True) as sess:
915      a = math_ops.range(3, dtype=dtypes.float32)
916      index = constant_op.constant(1, dtype=dtypes.int64)
917      b = 2. * a[index]
918      grad, = gradients_impl.gradients(b, a)
919      self.assertAllEqual(self.evaluate(grad), [0., 2., 0.])
920
921
922class StridedSliceGradTypeTest(test_util.TensorFlowTestCase):
923  """Test varied index types and host located memory."""
924
925  @test_util.run_deprecated_v1
926  def testHostVsDevice(self):
927    with self.session(use_gpu=True) as sess:
928      var2 = variables.Variable(
929          array_ops.reshape(
930              math_ops.cast(math_ops.range(1, 5, 1), dtypes.float32),
931              shape=(4, 1, 1)))
932      varshape = variables.Variable([6, 4, 4], dtype=dtypes.int32)
933      self.evaluate(variables.global_variables_initializer())
934      begin = constant_op.constant([0, 0, 0])
935      end = constant_op.constant([4, 1, 1])
936      strides = constant_op.constant([1, 1, 1])
937      foo = array_ops.strided_slice_grad(varshape, begin, end, strides, var2)
938      sess.run(foo)
939
940  @test_util.run_deprecated_v1
941  def testInt64Shape(self):
942    with self.session(use_gpu=True) as sess:
943      original_dy = array_ops.reshape(
944          math_ops.cast(math_ops.range(1, 5, 1), dtypes.float32),
945          shape=(4, 1, 1))
946      original_shape = constant_op.constant([6, 4, 4], dtype=dtypes.int64)
947      self.evaluate(variables.global_variables_initializer())
948      begin = constant_op.constant([0, 0, 0], dtype=dtypes.int64)
949      end = constant_op.constant([4, 1, 1], dtype=dtypes.int64)
950      strides = constant_op.constant([1, 1, 1], dtype=dtypes.int64)
951      dx = array_ops.strided_slice_grad(original_shape, begin, end, strides,
952                                        original_dy)
953      sess.run(dx)
954
955  @test_util.run_deprecated_v1
956  def testMixedIndexTypes(self):
957    with self.session(use_gpu=True) as sess:
958      original_dy = array_ops.reshape(
959          math_ops.cast(math_ops.range(1, 5, 1), dtypes.float32),
960          shape=(4, 1, 1))
961      original_shape = constant_op.constant([6, 4, 4], dtype=dtypes.int64)
962      self.evaluate(variables.global_variables_initializer())
963      begin = constant_op.constant([0, 0, 0], dtype=dtypes.int32)
964      end = constant_op.constant([4, 1, 1], dtype=dtypes.int64)
965      strides = constant_op.constant([1, 1, 1], dtype=dtypes.int64)
966      with self.assertRaisesRegexp(
967          TypeError, "Input 'begin' of 'StridedSliceGrad' Op has type int32"
968          " that does not match type int64 of argument 'shape'"):
969        dx = array_ops.strided_slice_grad(original_shape, begin, end, strides,
970                                          original_dy)
971        sess.run(dx)
972
973
974class BenchmarkSlice(object):
975
976  def __init__(self, tensor):
977    self.tensor = tensor
978
979  def __getitem__(self, x):
980    return self.tensor[x]
981
982
983class StridedSliceBenchmark(test_lib.Benchmark):
984  """Benchmark new strided slice operation on non-trivial case."""
985
986  def run_and_time(self, slice_op):
987    variables.global_variables_initializer().run()
988    for _ in range(10):
989      _ = slice_op.eval()
990    iters = 1000
991    t0 = time.time()
992    for _ in range(iters):
993      slice_op.eval()
994    t1 = time.time()
995    self.report_benchmark(iters=iters, wall_time=(t1 - t0) / 1000.0)
996
997  def make_variable(self):
998    n = 256
999    shape = (n, n, n)
1000    items = n**3
1001    var = variables.Variable(
1002        array_ops.reshape(math_ops.linspace(1., float(items), items), shape),
1003        dtype=dtypes.float32)
1004    return var
1005
1006  def benchmark_strided_slice_skip(self):
1007    with session.Session():
1008      var = self.make_variable()
1009      helper = BenchmarkSlice(var)
1010      slice_op = helper[::2, ::1, ::2]
1011      self.run_and_time(slice_op)
1012
1013  def benchmark_strided_slice_easy(self):
1014    with session.Session():
1015      var = self.make_variable()
1016      helper = BenchmarkSlice(var)
1017      slice_op = helper[3::1, 3::1, 3::1]
1018      self.run_and_time(slice_op)
1019
1020  def benchmark_slice_easy(self):
1021    with session.Session():
1022      var = self.make_variable()
1023      slice_op = var[3::1, 3::1, 3::1]
1024      self.run_and_time(slice_op)
1025
1026
1027class StridedSliceAssignChecker(object):
1028
1029  def __init__(self, test, x, tensor_type=dtypes.float32, use_resource=False):
1030    self.tensor_type = tensor_type
1031    self.test = test
1032    self._use_resource = use_resource
1033
1034    self.x_np = np.array(x).astype(tensor_type.as_numpy_dtype)
1035    # Give the value a non-zero imaginary component for complex types.
1036    if tensor_type.is_complex:
1037      self.x_np -= 1j * self.x_np
1038    self.x = constant_op.constant(self.x_np, dtype=tensor_type)
1039
1040  def __setitem__(self, index, value):
1041    value = np.array(value).astype(self.tensor_type.as_numpy_dtype)
1042    # Give the value a non-zero imaginary component for complex types.
1043    if self.tensor_type.is_complex:
1044      value -= 1j * value
1045
1046    with self.test.test_session(use_gpu=True) as sess:
1047      if self._use_resource:
1048        var = resource_variable_ops.ResourceVariable(self.x)
1049      else:
1050        var = variables.Variable(self.x)
1051      sess.run(variables.variables_initializer([var]))
1052      val = sess.run(var[index].assign(value))
1053      # val_copy is used to check that tf.assign works equivalently to the
1054      # assign method above.
1055      val_copy = sess.run(state_ops.assign(var[index], value))
1056      valnp = np.copy(self.x_np)
1057      valnp[index] = np.array(value)
1058      self.test.assertAllEqual(val, valnp)
1059      self.test.assertAllEqual(val_copy, valnp)
1060
1061
1062class SliceAssignTest(test_util.TensorFlowTestCase):
1063
1064  @test_util.run_deprecated_v1
1065  def testInvalidSlice(self):
1066    with self.cached_session() as sess:
1067      foo = constant_op.constant([1, 2, 3])
1068      with self.assertRaisesRegexp(ValueError, "Sliced assignment"
1069                                   " is only supported for variables"):
1070        bar = foo[:2].assign(constant_op.constant([1, 2]))
1071        sess.run(bar)
1072
1073  def doTestSliceAssign(self, use_resource):
1074    for dtype in STRIDED_SLICE_TYPES:
1075      checker = StridedSliceAssignChecker(
1076          self, [[1, 2, 3], [4, 5, 6]],
1077          use_resource=use_resource,
1078          tensor_type=dtype)
1079      # Check if equal
1080      checker[:] = [[10, 20, 30], [40, 50, 60]]
1081      # Check trivial (1,1) shape tensor
1082      checker[1:2, 1:2] = [[66]]
1083      # shrinks shape changes
1084      checker[1:2, 1] = [66]
1085      checker[1, 1:2] = [66]
1086      checker[1, 1] = 66
1087      # newaxis shape changes
1088      checker[:, None, :] = [[[10, 20, 30]], [[40, 50, 50]]]
1089      # shrink and newaxis
1090      checker[None, None, 0, 0:1] = [[[99]]]
1091      # Non unit strides
1092      checker[::1, ::-2] = [[3, 33], [4, 44]]
1093      # degenerate interval
1094      checker[8:10, 0] = []
1095      checker[8:10, 8:10] = [[]]
1096    # Assign vector to scalar (rank-0) using newaxis
1097    checker2 = StridedSliceAssignChecker(self, 222)
1098    checker2[()] = 6  # no indices
1099    checker2[...] = 6  # ellipsis
1100    checker2[None] = [6]  # new axis
1101
1102  @test_util.run_deprecated_v1
1103  @test_util.disable_xla("b/123559667")
1104  def testSliceAssign(self):
1105    self.doTestSliceAssign(use_resource=False)
1106
1107  @test_util.run_deprecated_v1
1108  @test_util.disable_xla("b/123559667")
1109  def testSliceAssignResource(self):
1110    self.doTestSliceAssign(use_resource=True)
1111
1112  @test_util.run_deprecated_v1
1113  def testUninitialized(self):
1114    with self.assertRaisesRegexp(
1115        errors.FailedPreconditionError,
1116        "Attempting to use uninitialized value Variable"):
1117      with self.cached_session() as sess:
1118        v = variables.VariableV1([1, 2])
1119        sess.run(v[:].assign([1, 2]))
1120
1121  def testTypeError(self):
1122    init_val = constant_op.constant([1, 2], dtype=dtypes.int32)
1123    too_small_val = constant_op.constant([3, 4], dtype=dtypes.int8)
1124    too_large_val = constant_op.constant([3, 4], dtype=dtypes.int64)
1125    v = variables.VariableV1(init_val)
1126    with self.assertRaises(TypeError):
1127      v[:].assign(too_small_val)
1128    with self.assertRaises(TypeError):
1129      v[:].assign(too_large_val)
1130
1131  @test_util.run_deprecated_v1
1132  def testTypeErrorResource(self):
1133    init_val = constant_op.constant([1, 2], dtype=dtypes.int32)
1134    too_small_val = constant_op.constant([3, 4], dtype=dtypes.int8)
1135    too_large_val = constant_op.constant([3, 4], dtype=dtypes.int64)
1136    v = resource_variable_ops.ResourceVariable(init_val)
1137    with self.cached_session() as sess:
1138      self.evaluate(v.initializer)
1139      with self.assertRaises(ValueError):
1140        sess.run(v[:].assign(too_large_val))
1141      with self.assertRaises(ValueError):
1142        sess.run(v[:].assign(too_small_val))
1143
1144
1145class ShapeSizeRankTest(test_util.TensorFlowTestCase):
1146
1147  @test_util.run_in_graph_and_eager_modes
1148  def testDenseShape(self):
1149    t_value = [[0, 42], [24, 0]]
1150    self.assertAllEqual((2, 2), self.evaluate(array_ops.shape(t_value)))
1151    self.assertEqual(4, self.evaluate(array_ops.size(t_value)))
1152    self.assertEqual(2, self.evaluate(array_ops.rank(t_value)))
1153
1154    t = constant_op.constant(t_value)
1155    self.assertAllEqual((2, 2), self.evaluate(array_ops.shape(t)))
1156    self.assertEqual(4, self.evaluate(array_ops.size(t)))
1157    self.assertEqual(2, self.evaluate(array_ops.rank(t)))
1158
1159  @test_util.run_in_graph_and_eager_modes
1160  def testSparseShape(self):
1161    sp_value = sparse_tensor.SparseTensorValue(
1162        indices=((0, 1), (1, 0)), values=(42, 24), dense_shape=(2, 2))
1163    self.assertAllEqual((2, 2), self.evaluate(array_ops.shape(sp_value)))
1164    self.assertEqual(4, self.evaluate(array_ops.size(sp_value)))
1165    self.assertEqual(2, self.evaluate(array_ops.rank(sp_value)))
1166
1167    sp = sparse_tensor.SparseTensor.from_value(sp_value)
1168    self.assertAllEqual((2, 2), self.evaluate(array_ops.shape(sp)))
1169    self.assertEqual(4, self.evaluate(array_ops.size(sp)))
1170    self.assertEqual(2, self.evaluate(array_ops.rank(sp)))
1171
1172  @test_util.run_in_graph_and_eager_modes
1173  def testSizeDtype(self):
1174    tensor = [1]
1175    self.assertEqual(dtypes.int32, self.evaluate(array_ops.size(tensor)).dtype)
1176    self.assertEqual(
1177        dtypes.int64,
1178        self.evaluate(array_ops.size(tensor, out_type=dtypes.int64)).dtype)
1179
1180
1181class SequenceMaskTest(test_util.TensorFlowTestCase):
1182
1183  def testExceptions(self):
1184    with self.cached_session():
1185      with self.assertRaisesRegexp(ValueError, "maxlen must be scalar"):
1186        array_ops.sequence_mask([10, 20], [10, 20])
1187
1188  @test_util.run_deprecated_v1
1189  def testOneDimensionalWithMaxlen(self):
1190    with self.cached_session():
1191      res = array_ops.sequence_mask(constant_op.constant([1, 3, 2]), 5)
1192      self.assertAllEqual(res.get_shape(), [3, 5])
1193      self.assertAllEqual(
1194          res.eval(),
1195          [[True, False, False, False, False], [True, True, True, False, False],
1196           [True, True, False, False, False]])
1197
1198  @test_util.run_deprecated_v1
1199  def testOneDimensionalDtypeWithoutMaxlen(self):
1200    with self.cached_session():
1201      # test dtype and default maxlen:
1202      res = array_ops.sequence_mask(constant_op.constant([0, 1, 4]),
1203                                    dtype=dtypes.float32)
1204      self.assertAllEqual(res.get_shape().as_list(), [3, 4])
1205      self.assertAllEqual(
1206          res.eval(),
1207          [[0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]])
1208
1209  @test_util.run_deprecated_v1
1210  def testOneDimensionalWithoutMaxlen(self):
1211    with self.cached_session():
1212      res = array_ops.sequence_mask(
1213          constant_op.constant([0, 1, 4]))
1214      self.assertAllEqual(res.get_shape().as_list(), [3, 4])
1215      self.assertAllEqual(
1216          res.eval(),
1217          [[False, False, False, False],
1218           [True, False, False, False],
1219           [True, True, True, True]])
1220
1221  def testTwoDimensional(self):
1222    with self.cached_session():
1223      res = array_ops.sequence_mask(constant_op.constant([[1, 3, 2]]), 5)
1224      self.assertAllEqual(res.get_shape(), [1, 3, 5])
1225      self.assertAllEqual(res.eval(), [[[True, False, False, False, False], [
1226          True, True, True, False, False
1227      ], [True, True, False, False, False]]])
1228
1229      # test dtype and default maxlen:
1230      res = array_ops.sequence_mask(
1231          constant_op.constant([[0, 1, 4], [1, 2, 3]]), dtype=dtypes.float32)
1232      self.assertAllEqual(res.get_shape().as_list(), [2, 3, 4])
1233      self.assertAllEqual(
1234          res.eval(),
1235          [[[0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]],
1236           [[1.0, 0.0, 0.0, 0.0], [1.0, 1.0, 0.0, 0.0], [1.0, 1.0, 1.0, 0.0]]])
1237
1238  @test_util.run_deprecated_v1
1239  def testUnknownShape(self):
1240    lengths = array_ops.placeholder(dtype=dtypes.int32)
1241    res = array_ops.sequence_mask(lengths)
1242    self.assertEqual(res.shape, None)
1243
1244  @test_util.run_deprecated_v1
1245  def testDtypes(self):
1246
1247    def check_dtypes(lengths_dtype, maxlen_dtype):
1248      res = array_ops.sequence_mask(
1249          constant_op.constant([1, 3, 2], dtype=lengths_dtype),
1250          constant_op.constant(5, dtype=maxlen_dtype))
1251      self.assertAllEqual(res.get_shape(), [3, 5])
1252      self.assertAllEqual(
1253          res.eval(),
1254          [[True, False, False, False, False], [True, True, True, False, False],
1255           [True, True, False, False, False]])
1256
1257    with self.cached_session():
1258      check_dtypes(dtypes.int32, dtypes.int32)
1259      check_dtypes(dtypes.int32, dtypes.int64)
1260      check_dtypes(dtypes.int64, dtypes.int32)
1261      check_dtypes(dtypes.int64, dtypes.int64)
1262
1263
1264class ConcatSliceResourceTest(test_util.TensorFlowTestCase):
1265
1266  @test_util.run_in_graph_and_eager_modes
1267  @test_util.run_deprecated_v1
1268  def testConcatSlice(self):
1269    r1 = test_ops.stub_resource_handle_op(container="a", shared_name="b")
1270    r2 = test_ops.stub_resource_handle_op(container="a", shared_name="c")
1271    c = array_ops.stack([r1, r2])
1272    s = array_ops.strided_slice(c, [1], [2])
1273    self.evaluate(test_ops.resource_create_op(s))
1274    with self.assertRaises(errors.AlreadyExistsError):
1275      self.evaluate(test_ops.resource_create_op(r2))
1276
1277
1278class IdentityTest(test_util.TensorFlowTestCase):
1279
1280  def testEagerIdentity(self):
1281    with context.eager_mode():
1282      ctx = context.context()
1283      if not ctx.num_gpus():
1284        self.skipTest("No GPUs found")
1285
1286      def _test(x, y, device):
1287        self.assertAllEqual(x.numpy(), y.numpy())
1288        self.assertTrue(device in y.device.lower())
1289
1290      with test_util.force_gpu():
1291        a = constant_op.constant([[2], [3]], dtype=dtypes.float32)
1292      with test_util.force_gpu():
1293        b = array_ops.identity(a)
1294        _test(a, b, "gpu")
1295      with test_util.force_cpu():
1296        c = array_ops.identity(b)
1297        _test(b, c, "cpu")
1298      with test_util.force_cpu():
1299        d = array_ops.identity(c)
1300        _test(c, d, "cpu")
1301      with test_util.force_gpu():
1302        e = array_ops.identity(d)
1303        _test(d, e, "gpu")
1304
1305
1306class PadTest(test_util.TensorFlowTestCase):
1307
1308  def testEager(self):
1309    with context.eager_mode():
1310      t = constant_op.constant([[1, 2, 3], [4, 5, 6]])
1311      paddings = constant_op.constant([[
1312          1,
1313          1,
1314      ], [2, 2]])
1315      padded = array_ops.pad(t, paddings, "CONSTANT")
1316      self.assertAllEqual(padded.numpy(),
1317                          [[0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 2, 3, 0, 0],
1318                           [0, 0, 4, 5, 6, 0, 0], [0, 0, 0, 0, 0, 0, 0]])
1319
1320
1321class InvertPermutationTest(test_util.TensorFlowTestCase):
1322
1323  @test_util.run_deprecated_v1
1324  def testInvertPermutation(self):
1325    for dtype in [dtypes.int32, dtypes.int64]:
1326      with self.cached_session(use_gpu=True):
1327        x = constant_op.constant([3, 4, 0, 2, 1], dtype=dtype)
1328        y = array_ops.invert_permutation(x)
1329        self.assertAllEqual(y.get_shape(), [5])
1330        self.assertAllEqual(y.eval(), [2, 4, 3, 0, 1])
1331
1332
1333class UnravelIndexTest(test_util.TensorFlowTestCase):
1334
1335  # TODO(b/73086570): Reenable test.
1336  @unittest.skip("Test does not pass internally.")
1337  def testUnravelIndex(self):
1338    with self.cached_session():
1339      for dtype in [dtypes.int32, dtypes.int64]:
1340        indices_1 = constant_op.constant(1621, dtype=dtype)
1341        dims_1 = constant_op.constant([6, 7, 8, 9], dtype=dtype)
1342        out_1 = array_ops.unravel_index(indices_1, dims_1)
1343        self.assertAllEqual(out_1.eval(), [3, 1, 4, 1])
1344
1345        indices_2 = constant_op.constant([1621], dtype=dtype)
1346        dims_2 = constant_op.constant([6, 7, 8, 9], dtype=dtype)
1347        out_2 = array_ops.unravel_index(indices_2, dims_2)
1348        self.assertAllEqual(out_2.eval(), [[3], [1], [4], [1]])
1349
1350        indices_3 = constant_op.constant([22, 41, 37], dtype=dtype)
1351        dims_3 = constant_op.constant([7, 6], dtype=dtype)
1352        out_3 = array_ops.unravel_index(indices_3, dims_3)
1353        self.assertAllEqual(out_3.eval(), [[3, 6, 6], [4, 5, 1]])
1354
1355
1356class GuaranteeConstOpTest(test_util.TensorFlowTestCase):
1357
1358  @test_util.run_deprecated_v1
1359  def testSimple(self):
1360    with self.cached_session():
1361      a = array_ops.constant(10)
1362      guarantee_a = array_ops.guarantee_const(a)
1363      self.assertEqual(10, guarantee_a.eval())
1364
1365  @test_util.run_deprecated_v1
1366  def testVariables(self):
1367    with self.cached_session() as sess:
1368      for use_resource in [False, True]:
1369        a = variable_scope.get_variable(
1370            "var_{}".format(use_resource), [],
1371            initializer=init_ops.constant_initializer(10.0),
1372            use_resource=use_resource)
1373        guarantee_a = array_ops.guarantee_const(a)
1374        self.evaluate(variables.global_variables_initializer())
1375        self.assertEqual(10.0, guarantee_a.eval())
1376
1377  @test_util.run_deprecated_v1
1378  def testResourceRejection(self):
1379    with self.cached_session() as sess:
1380      a = variable_scope.get_variable(
1381          "resource_var", [],
1382          initializer=init_ops.constant_initializer(10.0),
1383          use_resource=True)
1384      guarantee_a = array_ops.guarantee_const(a.handle)
1385      self.evaluate(variables.global_variables_initializer())
1386      with self.assertRaisesWithPredicateMatch(errors.InvalidArgumentError,
1387                                               "cannot be a resource variable"):
1388        guarantee_a.eval()
1389
1390
1391class SnapshotOpTest(test_util.TensorFlowTestCase):
1392
1393  @test_util.run_deprecated_v1
1394  def testInvertPermutation(self):
1395    for dtype in [dtypes.int32, dtypes.int64, dtypes.float32, dtypes.float64]:
1396      with self.cached_session(use_gpu=True):
1397        x = constant_op.constant([0, 1, 2, 3], dtype=dtype)
1398        y = gen_array_ops.snapshot(x)
1399        self.assertAllEqual(y.eval(), [0, 1, 2, 3])
1400
1401
1402@test_util.run_all_in_graph_and_eager_modes
1403class SortedSearchTest(test_util.TensorFlowTestCase):
1404
1405  def testUpperBoundFloatHandCoded(self):
1406    cdf = np.array([0, .2, .5, .6, .8, 1.], dtype=np.float32)
1407    arr = np.array([.04, .99, .53, .58, .31, .01, .79, .8, .21],
1408                   dtype=np.float32)
1409    result = np.searchsorted(cdf, arr, side="right")
1410    tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="right"))
1411    self.assertAllEqual(result, tf_result)
1412
1413  def testUpperBoundFloatRandomNd(self):
1414    dim_size = 7
1415    for d in range(1, 5):
1416      shape = [dim_size] * d
1417      cdf = np.cumsum(
1418          np.random.uniform(size=shape).astype(np.float32), axis=(d - 1))
1419      arr = np.random.uniform(size=shape).astype(np.float32) * dim_size
1420
1421      tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="right"))
1422
1423      cdf = cdf.reshape([-1, dim_size])
1424      arr = arr.reshape([-1, dim_size])
1425      result = np.zeros(arr.shape, dtype=np.int32)
1426      for i in range(dim_size**(d - 1)):
1427        result[i, :] = np.searchsorted(cdf[i, :], arr[i, :], side="right")
1428
1429      result = result.reshape(shape)
1430
1431      self.assertAllEqual(result, tf_result)
1432
1433  def testUpperBoundFloatUneven(self):
1434    batch_size = 7
1435    size_search_array = 1000
1436    size_values = 47
1437    cdf = np.cumsum(
1438        np.random.uniform(size=[batch_size, size_search_array]).astype(
1439            np.float32),
1440        axis=1)
1441    arr = np.random.uniform(size=[batch_size, size_values]).astype(
1442        np.float32) * size_search_array
1443
1444    tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="right"))
1445
1446    result = np.zeros(arr.shape, dtype=np.int32)
1447    for i in range(batch_size):
1448      result[i, :] = np.searchsorted(cdf[i, :], arr[i, :], side="right")
1449
1450    self.assertAllEqual(result, tf_result)
1451
1452  def testLowerBoundFloatHandCoded(self):
1453    cdf = np.array([0, .2, .5, .6, .8, 1.], dtype=np.float32)
1454    arr = np.array([.04, .99, .53, .58, .31, .01, .79, .8, .21],
1455                   dtype=np.float32)
1456    result = np.searchsorted(cdf, arr, side="left")
1457    tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="left"))
1458    self.assertAllEqual(result, tf_result)
1459
1460  def testLowerBoundFloatRandomNd(self):
1461    dim_size = 7
1462    for d in range(1, 5):
1463      shape = [dim_size] * d
1464      cdf = np.cumsum(
1465          np.random.uniform(size=shape).astype(np.float32), axis=(d - 1))
1466      arr = np.random.uniform(size=shape).astype(np.float32) * dim_size
1467
1468      tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="left"))
1469
1470      cdf = cdf.reshape([-1, dim_size])
1471      arr = arr.reshape([-1, dim_size])
1472      result = np.zeros(arr.shape, dtype=np.int32)
1473      for i in range(dim_size**(d - 1)):
1474        result[i, :] = np.searchsorted(cdf[i, :], arr[i, :], side="left")
1475
1476      result = result.reshape(shape)
1477
1478      self.assertAllEqual(result, tf_result)
1479
1480  def testLowerBoundFloatUneven(self):
1481    batch_size = 7
1482    size_search_array = 1000
1483    size_values = 47
1484    cdf = np.cumsum(
1485        np.random.uniform(size=[batch_size, size_search_array]).astype(
1486            np.float32),
1487        axis=1)
1488    arr = np.random.uniform(size=[batch_size, size_values]).astype(
1489        np.float32) * size_search_array
1490
1491    tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="left"))
1492
1493    result = np.zeros(arr.shape, dtype=np.int32)
1494    for i in range(batch_size):
1495      result[i, :] = np.searchsorted(cdf[i, :], arr[i, :], side="left")
1496
1497    self.assertAllEqual(result, tf_result)
1498
1499  def testUpperBoundIntHandCoded(self):
1500    cdf = np.array([0, 20, 50, 60, 80, 100], dtype=np.int64)
1501    arr = np.array([4, 99, 53, 58, 31, 1, 79, 8, 21], dtype=np.int64)
1502    result = np.searchsorted(cdf, arr, side="right")
1503    tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="right"))
1504    self.assertAllEqual(result, tf_result)
1505
1506  def testUpperBoundIntRandomNd(self):
1507    dim_size = 7
1508    for d in range(1, 5):
1509      shape = [dim_size] * d
1510      cdf = np.cumsum(
1511          np.random.randint(low=0, high=10, size=shape).astype(np.int64),
1512          axis=(d - 1))
1513      arr = np.random.randint(
1514          low=0, high=10 * dim_size, size=shape).astype(np.int64)
1515
1516      tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="right"))
1517
1518      cdf = cdf.reshape([-1, dim_size])
1519      arr = arr.reshape([-1, dim_size])
1520      result = np.zeros(arr.shape, dtype=np.int32)
1521      for i in range(dim_size**(d - 1)):
1522        result[i, :] = np.searchsorted(cdf[i, :], arr[i, :], side="right")
1523
1524      result = result.reshape(shape)
1525
1526      self.assertAllEqual(result, tf_result)
1527
1528  def testUpperBoundIntUneven(self):
1529    batch_size = 7
1530    size_search_array = 1000
1531    size_values = 47
1532    cdf = np.cumsum(
1533        np.random.randint(low=0, high=10,
1534                          size=[batch_size,
1535                                size_search_array]).astype(np.int64),
1536        axis=1)
1537    arr = np.random.randint(
1538        low=0, high=10 * size_search_array, size=[batch_size,
1539                                                  size_values]).astype(np.int64)
1540
1541    tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="right"))
1542
1543    result = np.zeros(arr.shape, dtype=np.int32)
1544    for i in range(batch_size):
1545      result[i, :] = np.searchsorted(cdf[i, :], arr[i, :], side="right")
1546
1547    self.assertAllEqual(result, tf_result)
1548
1549  def testLowerBoundIntHandCoded(self):
1550    cdf = np.array([0, 20, 50, 60, 80, 100], dtype=np.int64)
1551    arr = np.array([4, 99, 53, 58, 31, 1, 79, 8, 21], dtype=np.int64)
1552    result = np.searchsorted(cdf, arr, side="left")
1553    tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="left"))
1554    self.assertAllEqual(result, tf_result)
1555
1556  def testLowerBoundIntRandomNd(self):
1557    dim_size = 7
1558    for d in range(1, 5):
1559      shape = [dim_size] * d
1560      cdf = np.cumsum(
1561          np.random.randint(low=0, high=10, size=shape).astype(np.int64),
1562          axis=(d - 1))
1563      arr = np.random.randint(
1564          low=0, high=10 * dim_size, size=shape).astype(np.int64)
1565
1566      tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="left"))
1567
1568      cdf = cdf.reshape([-1, dim_size])
1569      arr = arr.reshape([-1, dim_size])
1570      result = np.zeros(arr.shape, dtype=np.int32)
1571      for i in range(dim_size**(d - 1)):
1572        result[i, :] = np.searchsorted(cdf[i, :], arr[i, :], side="left")
1573
1574      result = result.reshape(shape)
1575
1576      self.assertAllEqual(result, tf_result)
1577
1578  def testLowerBoundIntUneven(self):
1579    batch_size = 7
1580    size_search_array = 1000
1581    size_values = 47
1582    cdf = np.cumsum(
1583        np.random.randint(low=0, high=10,
1584                          size=[batch_size,
1585                                size_search_array]).astype(np.int64),
1586        axis=1)
1587    arr = np.random.randint(
1588        low=0, high=10 * size_search_array, size=[batch_size,
1589                                                  size_values]).astype(np.int64)
1590
1591    tf_result = self.evaluate(array_ops.searchsorted(cdf, arr, side="left"))
1592
1593    result = np.zeros(arr.shape, dtype=np.int32)
1594    for i in range(batch_size):
1595      result[i, :] = np.searchsorted(cdf[i, :], arr[i, :], side="left")
1596
1597    self.assertAllEqual(result, tf_result)
1598
1599
1600if __name__ == "__main__":
1601  test_lib.main()
1602