text: import itertools
  import unittest
  import warnings
  
  import chainer
  import numpy
  import pytest
  
  import chainerx
  import chainerx.testing
  
  from chainerx_tests import array_utils
  from chainerx_tests import dtype_utils
  from chainerx_tests import op_utils
  
  
  def powerset(iterable):
      "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
      s = list(iterable)  # allows duplicate elements
      return list(itertools.chain(*[itertools.combinations(s, r)
                                    for r in range(len(s)+1)]))
  
  
  # Value for parameterization to represent an unspecified (default) argument.
  class _UnspecifiedType(object):
      def __repr__(self):
          return '<Unspecified>'
  
  
  _unspecified = _UnspecifiedType()
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('mode', ['module', 'transpose', 'T'])
  class TestTranspose(op_utils.NumpyOpTest):
  
      def setup(self, shape, dtype):
          # Skip backward/double-backward tests for int dtypes
          if numpy.dtype(dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
          self.shape = shape
          self.dtype = dtype
  
      def generate_inputs(self):
          shape = self.shape
          dtype = self.dtype
          a = array_utils.create_dummy_ndarray(numpy, shape, dtype)
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          mode = self.mode
          if mode == 'module':
              b = xp.transpose(a)
          elif mode == 'transpose':
              b = a.transpose()
          elif mode == 'T':
              b = a.T
          else:
              assert False
          return b,
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shape,axes', [
      ((1,), 0),
      ((1,), (0,)),
      ((2,), (0,)),
      ((2, 3), (1, 0)),
      ((2, 3), (-2, -1)),
      ((2, 3, 1), (2, 0, 1)),
      ((2, 3, 1), (2, -3, 1)),
  ])
  @chainer.testing.parameterize_pytest('is_module', [True, False])
  class TestTransposeAxes(op_utils.NumpyOpTest):
  
      def setup(self, dtype):
          # Skip backward/double-backward tests for int dtypes
          if numpy.dtype(dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
  
          self.dtype = dtype
  
      def generate_inputs(self):
          shape = self.shape
          dtype = self.dtype
          a = array_utils.create_dummy_ndarray(numpy, shape, dtype)
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          axes = self.axes
          if self.is_module:
              b = xp.transpose(a, axes)
          else:
              b = a.transpose(axes)
          return b,
  
  
  @pytest.mark.parametrize('shape,axes', [
      ((), (0,)),
      ((1,), (1,)),
      ((2, 3), (1,)),
      ((2, 3), (1, 0, 2)),
  ])
  def test_transpose_invalid_axes(shape, axes):
      a = array_utils.create_dummy_ndarray(chainerx, shape, 'float32')
      with pytest.raises(chainerx.DimensionError):
          chainerx.transpose(a, axes)
      with pytest.raises(chainerx.DimensionError):
          a.transpose(axes)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('in_shape,axis,start', [
      # various axis
      ((2, 3, 4), 0, _unspecified),
      ((2, 3, 4), 1, _unspecified),
      ((2, 3, 4), 2, _unspecified),
      ((2, 3, 4), -1, _unspecified),
      ((2, 3, 4), -3, _unspecified),
      # with start
      ((2, 3, 4), 1, 0),
      ((2, 3, 4), 1, 1),
      ((2, 3, 4), 1, 2),
      ((2, 3, 4), 1, 3),
      ((2, 3, 4), 1, -1),
      ((2, 3, 4), 1, -2),
      ((2, 3, 4), 1, -3),
      ((2, 3, 4), 2, 3),
      ((2, 3, 4), 2, 0),
      ((2, 3, 4), 0, 3),
      ((2, 3, 4), 0, 0),
      # single dim
      ((1,), 0, _unspecified),
      ((1,), -1, _unspecified),
      # zero-length dims
      ((0,), 0, _unspecified),
      ((0,), 0, 0),
      ((0,), 0, 1),
      ((0,), -1, _unspecified),
      ((2, 0, 3), 1, _unspecified),
      ((2, 0, 3), -2, _unspecified),
  ])
  class TestRollaxis(op_utils.NumpyOpTest):
  
      def setup(self, dtype):
          # Skip backward/double-backward tests for int dtypes
          if numpy.dtype(dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
  
          self.dtype = dtype
  
      def generate_inputs(self):
          in_shape = self.in_shape
          dtype = self.dtype
          a = array_utils.create_dummy_ndarray(numpy, in_shape, dtype)
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          axis = self.axis
          start = self.axis
          if start is _unspecified:
              b = xp.rollaxis(a, axis)
          else:
              b = xp.rollaxis(a, axis, start)
          return b,
  
  
  @pytest.mark.parametrize('in_shape,axis,start', [
      # out of bounds axis
      ((2, 3, 4), 3, _unspecified),
      ((2, 3, 4), -4, _unspecified),
      # out of bounds start
      ((2, 3, 4), 2, 4),
      ((2, 3, 4), 2, -4),
      # empty shape
      ((), 0, _unspecified),
      ((), -1, _unspecified),
  ])
  def test_rollaxis_invalid(in_shape, axis, start):
      a = array_utils.create_dummy_ndarray(chainerx, in_shape, 'float32')
      with pytest.raises(chainerx.DimensionError):
          if start is _unspecified:
              chainerx.rollaxis(a, axis)
          else:
              chainerx.rollaxis(a, axis, start)
  
  
  _reshape_shape = [
      ((), ()),
      ((0,), (0,)),
      ((1,), (1,)),
      ((5,), (5,)),
      ((2, 3), (2, 3)),
      ((1,), ()),
      ((), (1,)),
      ((1, 1), ()),
      ((), (1, 1)),
      ((6,), (2, 3)),
      ((2, 3), (6,)),
      ((2, 0, 3), (5, 0, 7)),
      ((5,), (1, 1, 5, 1, 1)),
      ((1, 1, 5, 1, 1), (5,)),
      ((2, 3), (3, 2)),
      ((2, 3, 4), (3, 4, 2)),
      ((2, 3, 4), (3, -1, 2)),
      ((2, 3, 4), (3, -3, 2)),  # -3 is treated as a -1 and is valid.
      ((2, 0, 3), (-1,)),  # Empty to inferred.
      ((2, 0, 3), (-1, 4)),  # Empty to inferred.
      ((2, 0, 3), (4, -1)),  # Empty to inferred.
      ((2, 0, 3), (4, -1, 5)),  # Empty to inferred.
  ]
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('a_shape,b_shape', _reshape_shape)
  @chainer.testing.parameterize_pytest('shape_type', [tuple, list])
  @chainer.testing.parameterize_pytest('contiguous', ['C', None])
  @chainer.testing.parameterize_pytest('is_module', [True, False])
  class TestReshape(op_utils.NumpyOpTest):
  
      def generate_inputs(self):
          a = array_utils.shaped_arange(self.a_shape, 'float64')
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          b_shape = self.b_shape
          shape_type = self.shape_type
          if self.is_module:
              b = xp.reshape(a, shape_type(b_shape))
          else:
              b = a.reshape(shape_type(b_shape))
          return b,
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('a_shape,b_shape', _reshape_shape)
  @chainer.testing.parameterize_pytest('shape_type', [tuple, list])
  @chainer.testing.parameterize_pytest('contiguous', ['C', None])
  @chainer.testing.parameterize_pytest('is_module', [True, False])
  class TestReshapeCopied(op_utils.NumpyOpTest):
  
      skip_backward_test = True
      skip_double_backward_test = True
  
      def generate_inputs(self):
          a = array_utils.shaped_arange(self.a_shape, 'float64')
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          b_shape = self.b_shape
          shape_type = self.shape_type
          if self.is_module:
              b = xp.reshape(a, shape_type(b_shape))
          else:
              b = a.reshape(shape_type(b_shape))
          if xp is chainerx:
              copied = (
                  a._debug_data_memory_address
                  != b._debug_data_memory_address)
          else:
              copied = a.ctypes.data != b.ctypes.data
          if copied:
              if xp is chainerx:
                  assert b.is_contiguous
              else:
                  assert b.flags.c_contiguous
  
          return xp.asarray(copied),
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('is_module', [True, False])
  @chainer.testing.parameterize_pytest('a_shape,b_shape', _reshape_shape)
  @chainer.testing.parameterize_pytest('contiguous', ['C', None])
  class TestReshapeArg(op_utils.NumpyOpTest):
  
      forward_accept_errors = (TypeError, chainerx.ChainerxError)
  
      def setup(self):
          if self.is_module and len(self.b_shape) > 1:
              # Skipping tests where the 'order' argument is unintentionally
              # given a shape value, since numpy won't raise any errors in this
              # case which you might expect at first.
              raise unittest.SkipTest(
                  'NumPy won\'t raise error for unintentional argument '
                  'unpacking')
  
      def generate_inputs(self):
          a = array_utils.shaped_arange(self.a_shape, 'float64')
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          b_shape = self.b_shape
          if self.is_module:
              # TypeError/chainerx.ChainerxError in case b_shape is empty.
              b = xp.reshape(a, *b_shape)
          else:
              # TypeError/chainerx.ChainerxError in case b_shape is empty.
              b = a.reshape(*b_shape)
  
          if xp is chainerx:
              if self.contiguous == 'C':
                  assert b.is_contiguous
                  assert (a._debug_data_memory_address
                          == b._debug_data_memory_address), (
                              'Reshape must be done without copy')
          return b,
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('a_shape,b_shape', _reshape_shape)
  class TestFlatten(op_utils.NumpyOpTest):
  
      forward_accept_errors = (TypeError, chainerx.ChainerxError)
      check_numpy_strides_compliance = False
  
      def generate_inputs(self):
          a = array_utils.shaped_arange(self.a_shape, 'float64')
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          b = a.flatten()
          return b,
  
  
  @pytest.mark.parametrize('shape1,shape2', [
      ((), (0,)),
      ((), (2,)),
      ((), (1, 2,)),
      ((0,), (1,)),
      ((0,), (1, 1, 1)),
      ((2, 3), (2, 3, 2)),
      ((2, 3, 4), (2, 3, 5)),
  ])
  def test_reshape_invalid(shape1, shape2):
      def check(a_shape, b_shape):
          a = array_utils.create_dummy_ndarray(chainerx, a_shape, 'float32')
          with pytest.raises(chainerx.DimensionError):
              a.reshape(b_shape)
  
      check(shape1, shape2)
      check(shape2, shape1)
  
  
  @pytest.mark.parametrize('shape1,shape2', [
      ((2, 3, 4), (5, -1, 3)),  # Not divisible.
      ((2, 3, 4), (-1, -1, 3)),  # More than one dimension cannot be inferred.
      ((2, 3, 4), (-2, 4, -1)),
      ((2, 0, 4), (-1, 0)),  # Empty to ambiguous.
      ((2, 0, 4), (0, -1)),  # Empty to ambiguous.
      ((2, 0, 4), (0, -1, 2)),  # Empty to ambiguous.
  ])
  def test_reshape_invalid_cannot_infer(shape1, shape2):
      a = array_utils.create_dummy_ndarray(chainerx, shape1, 'float32')
      with pytest.raises(chainerx.DimensionError):
          a.reshape(shape2)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shape,axis', [
      ((), None),
      ((0,), None),
      ((1,), None),
      ((1, 1), None),
      ((1, 0, 1), None),
      ((3,), None),
      ((3, 1), None),
      ((1, 3), None),
      ((2, 0, 3), None),
      ((2, 4, 3), None),
      ((2, 1, 3), 1),
      ((2, 1, 3), -2),
      ((1, 2, 1, 3, 1, 1, 4), None),
      ((1, 2, 1, 3, 1, 1, 4), (2, 0, 4)),
      ((1, 2, 1, 3, 1, 1, 4), (-2, 0, 4)),
  ])
  @chainer.testing.parameterize_pytest('is_module', [True, False])
  class TestSqueeze(op_utils.NumpyOpTest):
  
      def generate_inputs(self):
          a = array_utils.shaped_arange(self.shape, 'float32')
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          axis = self.axis
          if self.is_module:
              b = xp.squeeze(a, axis)
          else:
              b = a.squeeze(axis)
          return b,
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(chainerx.DimensionError, ValueError))
  @pytest.mark.parametrize('shape,axis', [
      ((2, 1, 3), 0),
      ((2, 1, 3), -1),
      ((2, 1, 3), (1, 2)),
      ((2, 1, 3), (1, -1)),
      ((2, 1, 3), (1, 1)),
  ])
  def test_squeeze_invalid(is_module, xp, shape, axis):
      a = xp.ones(shape, 'float32')
      if is_module:
          return xp.squeeze(a, axis)
      else:
          return a.squeeze(axis)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('src_shape,dst_shape', [
      ((), ()),
      ((1,), (2,)),
      ((1, 1), (2, 2)),
      ((1, 1), (1, 2)),
      ((2,), (3, 2)),
  ])
  class TestBroadcastTo(op_utils.NumpyOpTest):
  
      def generate_inputs(self):
          a = array_utils.shaped_arange(self.src_shape, 'float32')
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          b = xp.broadcast_to(a, self.dst_shape)
          return b,
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(chainerx.DimensionError, ValueError))
  @pytest.mark.parametrize(('src_shape,dst_shape'), [
      ((3,), (2,)),
      ((3,), (3, 2)),
      ((1, 3), (3, 2)),
      ((3,), [2]),  # shape as a list instead of tuple
  ])
  def test_broadcast_to_invalid(xp, src_shape, dst_shape):
      a = xp.ones(src_shape, 'float32')
      return xp.broadcast_to(a, dst_shape)
  
  
  def _make_inputs(shapes, dtypes):
      # Generates input ndarrays.
      assert isinstance(shapes, (list, tuple))
      assert isinstance(dtypes, (list, tuple))
      assert len(shapes) == len(dtypes)
  
      inputs = []
      for i, (shape, dtype) in enumerate(zip(shapes, dtypes)):
          size = array_utils.total_size(shape)
          a = numpy.arange(i * 100, i * 100 + size)
          a = a.reshape(shape)
          a = a.astype(dtype)
          inputs.append(a)
  
      assert len(inputs) > 0
      return tuple(inputs)
  
  
  class JoinTestBase(op_utils.NumpyOpTest):
  
      chx_expected_dtype = None
      dtypes = None
  
      def setup(self):
          # Skip backward/double-backward tests for int dtypes
          if any(numpy.dtype(dt).kind != 'f' for dt in self.dtypes):
              self.skip_backward_test = True
              self.skip_double_backward_test = True
  
          # TODO(niboshi): Fix strides for 0-size inputs
          if any(0 in shape for shape in self.shapes):
              self.check_numpy_strides_compliance = False
  
          if any(dt == 'float16' for dt in self.dtypes):
              self.check_backward_options.update({'rtol': 1e-3, 'atol': 1e-3})
  
      def generate_inputs(self):
          return _make_inputs(self.shapes, self.dtypes)
  
      def join(self, inputs, xp):
          # Calls and returns the result of joining routines e.g. xp.concatenate,
          # xp.stack and xp.vstack.
          raise NotImplementedError()
  
      def forward_xp(self, inputs, xp):
          b = self.join(inputs, xp)
          if self.chx_expected_dtype is not None:
              b = dtype_utils.cast_if_numpy_array(xp, b, self.chx_expected_dtype)
          return b,
  
  
  class ConcatenateTestBase(JoinTestBase):
  
      axis = None
  
      def join(self, inputs, xp):
          if self.axis is _unspecified:
              b = xp.concatenate(inputs)
          else:
              b = xp.concatenate(inputs, self.axis)
          return b
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shapes,axis', [
      ([(0,)], 0),
      ([(1,)], 0),
      ([(0,), (0,)], 0),
      ([(0,), (1,)], 0),
      ([(1,), (1,)], 0),
      ([(0, 0,), (0, 0,)], 0),
      ([(0, 0,), (0, 0,)], 1),
      ([(1, 0,), (1, 0,)], 0),
      ([(1, 0,), (1, 0,)], 1),
      ([(1, 0,), (1, 0,)], 2),
      ([(3, 4, 5)], 0),
      ([(2, 3, 1), (2, 3, 1)], 1),
      ([(2, 3, 2), (2, 4, 2), (2, 3, 2)], 1),
      ([(2, 3, 2), (2, 4, 2), (3, 3, 2)], 1),
      ([(4, 10), (5, 10)], 0),
      ([(4, 10), (4, 8)], 0),
      ([(4, 4), (5,)], 0),
      ([(4, 4), (4,)], 0),
      ([(2, 3), (2, 3)], 10),
      ([(2, 3), (2, 3)], -1),
      ([(2, 3), (2, 3)], None),
      ([(2, 3), (4, 5)], None),
      ([(2, 3), (4, 5, 1)], None),
      ([(2, 3), (4, 5, 1), (4,)], None),
      ([(2, 3), (2, 3)], _unspecified),
      ([(2, 3), (4, 5)], _unspecified),
  ])
  class TestConcatenate(ConcatenateTestBase):
  
      forward_accept_errors = (chainerx.DimensionError, ValueError)
  
      def setup(self):
          self.dtypes = ['float32'] * len(self.shapes)
          super().setup()
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shapes,axis', [
      ([(0,), (0,)], 0),
      ([(0,), (1,)], 0),
      ([(1,), (1,)], 0),
      ([(0, 0,), (0, 0,)], 0),
      ([(0, 0,), (0, 0,)], 1),
      ([(1, 0,), (1, 0,)], 0),
      ([(1, 0,), (1, 0,)], 1),
      ([(2, 3, 1), (2, 3, 1)], 1),
      ([(4, 10), (5, 10)], 0),
      ([(2, 3), (2, 3)], None),
      ([(2, 3), (4, 5)], None),
      ([(2, 3), (4, 5, 1)], None),
      ([(2, 3), (2, 3)], _unspecified),
  ])
  @chainer.testing.parameterize_pytest(
      'dtypes,chx_expected_dtype', dtype_utils.result_dtypes_two_arrays)
  class TestConcatenateTwoArraysMixedDtypes(ConcatenateTestBase):
      pass
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shapes,axis', [
      ([(0,), (0,), (0,)], 0),
      ([(0,), (1,), (1,)], 0),
      ([(2, 3, 2), (2, 4, 2), (2, 3, 2)], 1),
      ([(2, 3), (4, 5), (4, 2)], None),
      ([(2, 3), (4, 5, 1), (4,)], None),
      ([(2, 3), (2, 3), (1, 3)], _unspecified),
  ])
  @chainer.testing.parameterize_pytest(
      'dtypes,chx_expected_dtype', dtype_utils.result_dtypes_three_arrays)
  class TestConcatenateThreeArraysMixedDtypes(ConcatenateTestBase):
      pass
  
  
  def test_concatenate_insufficient_inputs():
      with pytest.raises(chainerx.DimensionError):
          chainerx.concatenate([])
  
  
  class StackTestBase(JoinTestBase):
  
      axis = None
  
      def join(self, inputs, xp):
          if self.axis is None:
              b = xp.stack(inputs)
          else:
              b = xp.stack(inputs, self.axis)
          return b
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shapes,axis', [
      ([(0,)], -1),
      ([(0,)], 0),
      ([(0,)], 1),
      ([(0,)], 2),
      ([(1,)], -1),
      ([(1,)], 0),
      ([(1,)], 1),
      ([(1,)], 2),
      ([(0,), (0,)], 0),
      ([(0,), (0,)], 1),
      ([(0, 0,), (0, 0,)], 0),
      ([(0, 0,), (0, 0,)], 1),
      ([(1, 0,), (1, 0,)], 0),
      ([(1, 0,), (1, 0,)], 1),
      ([(1, 0,), (1, 0,)], 2),
      ([(2, 3,), (2, 3,)], None),
      ([(2, 3,), (2, 3,)], 1),
      ([(2, 3,), (2, 3,)], -1),
      ([(3, 4, 5), (3, 4, 5), (3, 4, 5)], None),
      ([(3, 4, 5), (3, 4, 5), (3, 4, 5)], 0),
      ([(3, 4, 5), (3, 4, 5), (3, 4, 5)], 1),
      ([(3, 4, 5), (3, 4, 5), (3, 4, 5)], 2),
      ([(3, 4, 5), (3, 4, 5), (3, 4, 5)], 3),
      ([(3, 4, 5), (3, 4, 5), (3, 4, 5)], 4),
      ([(3, 4, 5), (3, 4, 5), (3, 4, 5)], -1),
      ([(2, 3, 2), (2, 4, 2), (2, 3, 2)], 1),
  ])
  class TestStack(StackTestBase):
  
      forward_accept_errors = (chainerx.DimensionError, ValueError)
  
      def setup(self):
          self.dtypes = ['float32'] * len(self.shapes)
          super().setup()
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shape,axis', [
      ((0,), 0),
      ((0,), 1),
      ((0, 0), 0),
      ((0, 0), 1),
      ((1, 0), 0),
      ((1, 0), 1),
      ((1, 0), 2),
      ((2, 3), None),
      ((2, 3), 1),
      ((2, 3), -1),
  ])
  @chainer.testing.parameterize_pytest(
      'dtypes,chx_expected_dtype', dtype_utils.result_dtypes_two_arrays)
  class TestStackTwoArraysMixedDtypes(StackTestBase):
  
      def setup(self):
          self.shapes = (self.shape, self.shape)
          super().setup()
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shape,axis', [
      ((3, 4, 5), None),
      ((3, 4, 5), 0),
      ((3, 4, 5), 1),
      ((3, 4, 5), 2),
      ((3, 4, 5), 3),
      ((3, 4, 5), -1),
  ])
  @chainer.testing.parameterize_pytest(
      'dtypes,chx_expected_dtype', dtype_utils.result_dtypes_three_arrays)
  class TestStackThreeArraysMixedDtypes(StackTestBase):
  
      def setup(self):
          self.shapes = (self.shape, self.shape, self.shape)
          super().setup()
  
  
  def test_stack_insufficient_inputs():
      with pytest.raises(chainerx.DimensionError):
          chainerx.stack([])
      with pytest.raises(chainerx.DimensionError):
          chainerx.stack([], 0)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shape,indices_or_sections,axis', [
      ((2,), 1, 0),
      ((2,), [], 0),
      ((2,), [1, 2], 0),
      ((2,), [-5, -3], 0),
      ((2, 4), 1, 0),
      ((2, 4), 2, 1),
      ((2, 4), 2, -1),
      ((2, 4, 6), [], 0),
      ((2, 4, 6), [2, 4], 2),
      ((2, 4, 6), [2, -3], 2),
      ((2, 4, 6), [2, 8], 2),
      ((2, 4, 6), [4, 2], 2),
      ((2, 4, 6), [1, 3], -2),
      ((6,), numpy.array([1, 2]), 0),  # indices with 1-d numpy array
      ((6,), numpy.array([2]), 0),  # indices with (1,)-shape numpy array
      ((6,), numpy.array(2), 0),  # sections numpy scalar
      ((6,), numpy.array(2.0), 0),  # sections with numpy scalar, float
      ((6,), 2.0, 0),  # float type sections, without fraction
      # indices with empty numpy indices
      ((6,), numpy.array([], numpy.int32), 0),
      ((6,), numpy.array([], numpy.float64), 0),
  ])
  class TestSplit(op_utils.NumpyOpTest):
  
      def setup(self):
          # TODO(niboshi): There's a bug in backward of split() in which the
          # gradient shape differs from the input if indices are not in the
          # sorted order. Fix this.
          indices_or_sections = self.indices_or_sections
          if (isinstance(indices_or_sections, list) and
                  sorted(indices_or_sections) != indices_or_sections):
              self.skip_backward_test = True
              self.skip_double_backward_test = True
  
      def generate_inputs(self):
          a = array_utils.create_dummy_ndarray(numpy, self.shape, 'float32')
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          b = xp.split(a, self.indices_or_sections, self.axis)
          assert isinstance(b, list)
          return tuple(b)
  
  
  @pytest.mark.parametrize_device(['native:0', 'cuda:0'])
  @pytest.mark.parametrize('shape,indices_or_sections,axis', [
      ((7, 0), [2, 5], 0),
      ((0, 6), 3, 1),
  ])
  def test_split_zero_sized_no_offset(device, shape, indices_or_sections, axis):
      # An (sub-)array of size 0 should always have 0 offset.
      a = chainerx.random.uniform(-1, 1, shape)
      assert a.offset == 0  # Test pre-condition.
      b = chainerx.split(a, indices_or_sections, axis)
      assert all(bi.offset == 0 for bi in b)
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(
          chainerx.DimensionError, IndexError, ValueError, TypeError,
          ZeroDivisionError))
  @pytest.mark.parametrize('shape,indices_or_sections,axis', [
      ((), 1, 0),
      ((2,), 3, 0),
      ((2, 4), 0, 0),
      ((2, 4), -1, 1),
      ((2, 4), 1, 2),  # Axis out of range.
      ((2, 4), 3, 1),  # Uneven split.
      ((6,), [2.0], 0),  # float type indices
      ((6,), 2.1, 0),  # float type sections, with fraction
      # indices with (1,)-shape numpy array, float
      ((6,), numpy.array([2.0]), 0),
      # sections with numpy scalar, float with fraction
      ((6,), numpy.array(2.1), 0),
      ((2,), [1, 2.0], 0),  # indices with mixed type
      ((6,), '2', 0),  # Invalid type
      # indices with empty numpy indices
      ((6,), numpy.array([[], []], numpy.int32), 0),
      ((6,), numpy.array([[], []], numpy.float64), 0),
  ])
  def test_split_invalid(xp, shape, indices_or_sections, axis):
      a = array_utils.create_dummy_ndarray(xp, shape, 'float32')
      return xp.split(a, indices_or_sections, axis)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shape,indices_or_sections', [
      ((2, 4, 6), []),
      ((2, 4, 6), [2, 4]),
      ((2, 4, 6), [2, -3]),
      ((2, 4, 6), [2, 8]),
      ((2, 4, 6), [4, 2]),
      ((2, 4, 6), [1, 3]),
      ((2, 4, 5), [1, -3]),
      ((2, 4, 8), [2, 5]),
      ((2, 4, 10), [1, 4]),
      ((2, 4, 6), numpy.array([1, 2])),  # indices with 1-d numpy array
      ((2, 4, 6), numpy.array([2])),  # indices with (1,)-shape numpy array
      ((2, 4, 8), numpy.array(2)),  # sections numpy scalar
      ((2, 4, 6, 8), numpy.array(2.0)),  # sections with numpy scalar, float
      ((2, 4, 6, 8), 2.0),  # float type sections, without fraction
      # indices with empty numpy indices
      ((2, 4, 8, 10), numpy.array([], numpy.int32)),
      ((2, 4, 5, 10), numpy.array([], numpy.float64)),
  ])
  class TestDSplit(op_utils.NumpyOpTest):
  
      def setup(self):
          # TODO(niboshi): There's a bug in backward of split() in which the
          # gradient shape differs from the input if indices are not in the
          # sorted order. Fix this.
          indices_or_sections = self.indices_or_sections
          if (isinstance(indices_or_sections, list) and
                  sorted(indices_or_sections) != indices_or_sections):
              self.skip_backward_test = True
              self.skip_double_backward_test = True
  
      def generate_inputs(self):
          a = array_utils.create_dummy_ndarray(numpy, self.shape, 'float32')
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          b = xp.dsplit(a, self.indices_or_sections)
          assert isinstance(b, list)
          return tuple(b)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shape,indices_or_sections', [
      ((6, 4, 2), [1, 2, 4]),
      ((6, 4, 2), [2, 4, 6]),
      ((6, 4, 2), [1, 5, 7]),
      ((6, 4, 2), [2, -3, -5]),
      ((6, 4, 2), [2, 8, 10]),
      ((8, 6, 4, 2), [2, 4, 4, 6]),
      ((8, 6, 4, 2), [2, 6, 6, 8]),
      ((8, 6, 4, 2), [1, 4, 4, 6]),
      ((8, 6, 4, 2), [1, 4, 5, 6]),
      ((8, 6, 6, 4, 4, 2), [1, 3, 5, 7]),
      # indices with 1-d numpy array
      ((8, 6, 4, 2), numpy.array([1, 2, 3])),
      # indices with (4,)-shape numpy array
      ((8, 6, 4, 2), numpy.array([1, 2, 3, 4])),
      ((8, 8, 6, 6, 4, 2), numpy.array([1, 2, 3], numpy.int32)),
  ])
  class TestVSplit(op_utils.NumpyOpTest):
  
      def setup(self):
          # TODO(ishanrai05): There's a bug in backward of split() in which the
          # gradient shape differs from the input if indices are not in the
          # sorted order. Fix this.
          indices_or_sections = self.indices_or_sections
          if (isinstance(indices_or_sections, list) and
                  sorted(indices_or_sections) != indices_or_sections):
              self.skip_backward_test = True
              self.skip_double_backward_test = True
  
      def generate_inputs(self):
          a = array_utils.create_dummy_ndarray(numpy, self.shape, 'float32')
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          b = xp.vsplit(a, self.indices_or_sections)
          assert isinstance(b, list)
          return tuple(b)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shape,indices_or_sections', [
      ((2,), []),
      ((2, 4), 2),
      ((2, 4), [2, -3]),
      ((2, 6, 4), [2, 8]),
      ((2, 8, 4), [2, 5]),
      ((2, 5, 4), [1, -3]),
      ((2, 10, 4), [1, 4]),
      ((2, 6, 4), [4, 2, 1]),
      ((2, 6, 4), [1, 3, -2]),
      ((2, 6, 4), numpy.array([1, 2])),  # indices with 1-d numpy array
      ((2, 6, 4), numpy.array([2])),  # indices with (1,)-shape numpy array
      ((2, 8, 4), numpy.array(2)),  # sections numpy scalar
      ((2, 6, 4, 8), numpy.array(2.0)),  # sections with numpy scalar, float
      ((2, 6, 4, 8), 2.0),  # float type sections, without fraction
      # indices with empty numpy indices
      ((2, 8, 4, 10), numpy.array([], numpy.int32)),
      ((2, 5, 4, 10), numpy.array([], numpy.float64)),
  ])
  class TestHSplit(op_utils.NumpyOpTest):
  
      def setup(self):
          # TODO(ishanrai05): There's a bug in backward of split() in which the
          # gradient shape differs from the input if indices are not in the
          # sorted order. Fix this.
          indices_or_sections = self.indices_or_sections
          if (isinstance(indices_or_sections, list) and
                  sorted(indices_or_sections) != indices_or_sections):
              self.skip_backward_test = True
              self.skip_double_backward_test = True
  
      def generate_inputs(self):
          a = array_utils.create_dummy_ndarray(numpy, self.shape, 'float32')
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          b = xp.hsplit(a, self.indices_or_sections)
          assert isinstance(b, list)
          return tuple(b)
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(
          chainerx.DimensionError, IndexError, ValueError, TypeError,
          ZeroDivisionError))
  @pytest.mark.parametrize('shape,indices_or_sections', [
      ((), 1),  # Empty Shape
      ((2,), 0),  # Zero Section
      ((2, 6, 4), -1),  # Negative section
      ((2, 6, 4), 3),  # Uneven split
      ((2, 6, 4), [2.0]),  # float type indices
      ((2, 6, 4), 3.1),  # float type section with fraction
      ((2, 6, 4), '4'),  # Invalid type
  ])
  def test_hsplit_invalid(xp, shape, indices_or_sections):
      a = array_utils.create_dummy_ndarray(xp, shape, 'float32')
      return xp.hsplit(a, indices_or_sections)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shape,axis1,axis2', [
      ((1, 1), 0, 1),
      ((2, 4), -1, 1),
      ((1, 2, 2), 0, 1),
      ((1, 2, 3, 4), 0, 2),
      ((3, 2, 1, 2, 3), 0, 4),
      ((1, 2, 4, 3, 1), 0, -2),
      ((1, 2, 4, 2, 1), 0, 0),
      ((1, 3, 3, 1), -1, -4),
  ])
  @chainer.testing.parameterize_pytest('is_module', [True, False])
  class TestSwapaxes(op_utils.NumpyOpTest):
  
      def setup(self, dtype):
          # Skip backward/double-backward tests for int dtypes
          if numpy.dtype(dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
          self.dtype = dtype
  
      def generate_inputs(self):
          a = array_utils.create_dummy_ndarray(numpy, self.shape, self.dtype)
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          if self.is_module:
              b = xp.swapaxes(a, self.axis1, self.axis2)
          else:
              b = a.swapaxes(self.axis1, self.axis2)
          return b,
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(
          chainerx.DimensionError, numpy.AxisError))
  @pytest.mark.parametrize('shape,axis1,axis2', [
      # Axis out of range.
      ((), 1, 0),
      ((2,), 3, 0),
      ((2, 4), 1, 2),
      ((1, 1, 2), -1, -4)
  ])
  def test_swap_invalid(xp, shape, axis1, axis2):
      a = array_utils.create_dummy_ndarray(xp, shape, 'float32')
      return xp.swapaxes(a, axis1, axis2)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('shape,repeats,axis', [
      ((4,), 1, None),
      ((4,), 2, None),
      ((4, 2), 2, None),
      ((4,), 1, 0),
      ((4,), 2, 0),
      ((4,), (1,), None),
      ((4,), (2,), None),
      ((4, 2), (2,), None),
      ((4,), (1,), 0),
      ((4,), (2,), 0),
      ((2,), (1, 2), 0),
      ((2,), (0, 2), 0),
      ((4, 2), 2, 0),
      ((4, 2), 2, 1),
      ((4, 2), 2, -1),
      ((4, 2), 2, -2),
      ((2, 4), (1, 2), 0),
      ((4, 2), (1, 2), 1),
      ((2, 4), [1, 2], 0),
      ((4, 2), [1, 2], 1),
      ((2, 4), numpy.array([1, 2]), numpy.array(0)),
      ((4, 2), numpy.array([1, 2]), numpy.array(1)),
  ])
  @chainer.testing.parameterize_pytest('is_module', [True, False])
  class TestRepeat(op_utils.NumpyOpTest):
  
      def setup(self, dtype):
          # Skip backward/double-backward tests for int dtypes
          if numpy.dtype(dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
          self.dtype = dtype
  
          if dtype == 'float16':
              self.check_backward_options.update({'rtol': 1e-3, 'atol': 1e-3})
  
      def generate_inputs(self):
          a = array_utils.create_dummy_ndarray(numpy, self.shape, self.dtype)
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          if self.is_module:
              b = xp.repeat(a, self.repeats, self.axis)
          else:
              b = a.repeat(self.repeats, self.axis)
          return b,
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(
          chainerx.DimensionError, ValueError))
  @pytest.mark.parametrize('shape,repeats,axis', [
      # Axis out of range.
      ((1,), 1, 1),
      ((1, 1), (1, 2), 0),
      ((1, 1), (1, -2), 0),
      ((1, 1), (1, 2), -3),
      ((1, 1), (1, 2), 2),
  ])
  def test_repeat_invalid(xp, shape, repeats, axis):
      a = array_utils.create_dummy_ndarray(xp, shape, 'float32')
      return xp.repeat(a, repeats, axis)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize(*(
      chainer.testing.product({
          'shape': [(2, 2, 2)],
          'axis': [*range(3 + 1)] + [*range(-1, -3 - 1, -1)],
      })
      + chainer.testing.product({
          'shape': [(3, 3, 2, 3, 3)],
          'axis': [*range(5 + 1)] + [*range(-1, -5 - 1, -1)],
      })
      + chainer.testing.product({
          'shape': [(3, 0, 2, 0, 3)],
          'axis': [*range(5 + 1)] + [*range(-1, -5 - 1, -1)],
      })
      + chainer.testing.product({
          'shape': [(1, 2, 3, 1, 3, 3)],
          'axis': [*range(6 + 1)] + [*range(-1, -6 - 1, -1)],
      })
      + chainer.testing.product({
          'shape': [(3, 4, 5, 2, 3, 5)],
          'axis': [*range(6 + 1)] + [*range(-1, -6 - 1, -1)],
      })
      + chainer.testing.product({
          'shape': [(1,)],
          'axis': [*range(1 + 1)] + [*range(-1, -1 - 1, -1)],
      })
  ))
  @chainer.testing.parameterize_pytest('is_contiguous', [True, False])
  class TestExpandDims(op_utils.NumpyOpTest):
  
      # TODO(kshitij12345): Remove this when fixed
      check_numpy_strides_compliance = False
  
      def setup(self, dtype):
          # Skip backward/double-backward tests for int dtypes
          if numpy.dtype(dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
          self.dtype = dtype
  
          if dtype == 'float16':
              self.check_backward_options.update({'rtol': 1e-3, 'atol': 1e-3})
  
      def generate_inputs(self):
          a = array_utils.create_dummy_ndarray(numpy, self.shape, self.dtype)
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
  
          if self.is_contiguous:
              a = a.copy()
  
          y = xp.expand_dims(a, self.axis)
  
          # Result should be a view, not a copy.
          if xp is chainerx:
              assert y.data_ptr == a.data_ptr
  
          return y,
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(
          chainerx.DimensionError, numpy.AxisError, DeprecationWarning))
  @pytest.mark.parametrize('shape,axis', [
      # Axis out of range.
      ((), 1),
      ((2,), 3),
      ((2,), -3),
      ((2, 4), 4),
      ((1, 1, 2), -4)
  ])
  def test_expand_dims_invalid(xp, shape, axis):
      with warnings.catch_warnings():
          warnings.simplefilter('error', DeprecationWarning)
          a = array_utils.create_dummy_ndarray(xp, shape, 'float32')
          return xp.expand_dims(a, axis)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize(*(
      # Single axis and None
      chainer.testing.product({
          'shape': [()],
          'axis': [*range(0)] + [None] + [*range(-0, -0, -1)],
      })
      + chainer.testing.product({
          'shape': [(0,)],
          'axis': [*range(1)] + [None] + [*range(-1, -1, -1)],
      })
      + chainer.testing.product({
          'shape': [(2, 2, 2)],
          'axis': [*range(3)] + [None] + [*range(-1, -3, -1)],
      })
      + chainer.testing.product({
          'shape': [(3, 3, 2, 3, 3)],
          'axis': [*range(5)] + [None] + [*range(-1, -5, -1)],
      })
      + chainer.testing.product({
          'shape': [(3, 0, 2, 0, 3)],
          'axis': [*range(5)] + [None] + [*range(-1, -5, -1)],
      })
      + chainer.testing.product({
          'shape': [(1, 2, 3, 1, 3, 3)],
          'axis': [*range(6)] + [None] + [*range(-1, -6, -1)],
      })
      + chainer.testing.product({
          'shape': [(3, 4, 5, 2, 3, 5)],
          'axis': [*range(6)] + [None] + [*range(-1, -6, -1)],
      })
      + chainer.testing.product({
          'shape': [(1,)],
          'axis': [*range(1)] + [None] + [*range(-1, -1, -1)],
      })
      # Multiple axes
      + chainer.testing.product({
          'shape': [(1, 3, 4)],
          'axis': powerset([*range(3)]) + powerset([*range(-1, -3, -1)]),
      })
      + chainer.testing.product({
          'shape': [(3, 0, 2)],
          'axis': powerset([*range(3)]) + powerset([*range(-1, -3, -1)]),
      })
      + chainer.testing.product({
          'shape': [(1,)],
          'axis': powerset([*range(1)]) + powerset([*range(-1, -1, -1)]),
      })
      + chainer.testing.product({
          'shape': [(0,)],
          'axis': powerset([*range(1)]) + powerset([*range(-1, -1, -1)]),
      })
  ))
  @chainer.testing.parameterize_pytest('contiguous', ['C', None])
  class TestFlip(op_utils.NumpyOpTest):
  
      def setup(self, dtype):
          # TODO(kshitij12345) : Remove when #6621 is in.
          if numpy.dtype(dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
          self.dtype = dtype
  
          if dtype == 'float16':
              self.check_backward_options.update({'rtol': 1e-3, 'atol': 1e-3})
  
      def generate_inputs(self):
          a = array_utils.uniform(self.shape, self.dtype)
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          return xp.flip(a, self.axis),
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(
          chainerx.DimensionError, numpy.AxisError))
  @pytest.mark.parametrize('shape,axis', [
      # Axis out of range.
      ((), 1),
      ((2,), 3),
      ((2,), -3),
      ((2, 4), 4),
      ((1, 1, 2), -4),
      ((1, 1, 2), (0, 4)),
      ((1, 1, 2), (0, -6)),
  ])
  def test_flip_invalid(xp, shape, axis):
      a = array_utils.create_dummy_ndarray(xp, shape, 'float32')
      return xp.flip(a, axis)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize(*(
      chainer.testing.product({
          'shape': [(2, 2, 2)],
      })
      + chainer.testing.product({
          'shape': [(2, 1, 3)],
      })
      + chainer.testing.product({
          'shape': [(0, 1, 3, 4)],
      })
      + chainer.testing.product({
          'shape': [(1, 0, 3, 4)],
      })
      + chainer.testing.product({
          'shape': [(1, 0, 3, 4, 0)],
      })
  ))
  @chainer.testing.parameterize_pytest('contiguous', ['C', None])
  @chainer.testing.parameterize_pytest('func_name', [
      'fliplr',
      'flipud'
  ])
  class TestFlipLRUD(op_utils.NumpyOpTest):
  
      def setup(self, dtype):
          # TODO(kshitij12345) : Remove when #6621 is in.
          if numpy.dtype(dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
          self.dtype = dtype
  
          if dtype == 'float16':
              self.check_backward_options.update({'rtol': 1e-3, 'atol': 1e-3})
  
      def generate_inputs(self):
          a = array_utils.uniform(self.shape, self.dtype)
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          if self.func_name == 'fliplr':
              b = xp.fliplr(a)
          elif self.func_name == 'flipud':
              b = xp.flipud(a)
          return b,
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(
          chainerx.DimensionError, ValueError))
  @pytest.mark.parametrize('shape', [
      (),
      (1,),
      (10,),
  ])
  def test_fliplr_invalid(xp, shape):
      a = array_utils.create_dummy_ndarray(xp, shape, 'float32')
      return xp.fliplr(a)
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(
          chainerx.DimensionError, ValueError))
  @pytest.mark.parametrize('shape', [
      (),
  ])
  def test_flipud_invalid(xp, shape):
      a = array_utils.create_dummy_ndarray(xp, shape, 'float32')
      return xp.flipud(a)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize(*(
      chainer.testing.product({'shapes': [
          [(1,)],
          [(0,), (0,)],
          [(0, 0,), (0, 0,)],
          [(1, 0,), (1, 0,)],
          [(3, 4, 5), (3, 4, 5), (3, 4, 5)],
          [(2, 3, 2), (2, 3, 2), (2, 3, 2)],
          [(1, 0, 1), (1, 0, 1), (1, 0, 1)],
          [(2, 0, 0), (2, 0, 0), (2, 0, 0)],
          [(1, 0, 1, 0), (1, 0, 1, 0), (1, 0, 1, 0)],
          [(0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)],
          [(2, 2, 2, 2), (2, 2, 2, 2), (2, 2, 2, 2)],
      ], 'func_name': [
          'hstack', 'vstack', 'dstack'
      ],
          'dtype': chainerx.testing.dtypes.all_dtypes
      })
  ))
  class TestHVDStack(op_utils.NumpyOpTest):
  
      dtypes = None
  
      def setup(self):
          if numpy.dtype(self.dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
  
      def generate_inputs(self):
          return _make_inputs(self.shapes, [self.dtype] * len(self.shapes))
  
      def forward_xp(self, inputs, xp):
          if self.func_name == 'hstack':
              y = xp.hstack(inputs)
          elif self.func_name == 'vstack':
              y = xp.vstack(inputs)
          elif self.func_name == 'dstack':
              y = xp.dstack(inputs)
  
          return y,
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(
          chainerx.DimensionError, ValueError))
  @pytest.mark.parametrize('shape', [
      [(2, 1), (1, 2)],
      [(1, 1, 1), (2, 3, 4)],
      [(2, 1, 4), (1, 4, 5)],
      [(1, 1, 2), (3, 5, 8)]
  ])
  @pytest.mark.parametrize('func_name', [
      'hstack', 'vstack', 'dstack'
  ])
  def test_hvdstack_invalid_shapes(func_name, xp, shape):
      inputs = _make_inputs(shape, ['float32'] * len(shape))
      inputs = [xp.array(a) for a in inputs]
  
      if func_name == 'hstack':
          b = xp.hstack(inputs)
      elif func_name == 'vstack':
          b = xp.vstack(inputs)
      elif func_name == 'dstack':
          b = xp.dstack(inputs)
  
      return b
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(
          chainerx.DimensionError, ValueError))
  @pytest.mark.parametrize('func_name', [
      'hstack', 'vstack', 'dstack'
  ])
  def test_hvdstack_invalid_empty(func_name, xp):
      inputs = []
      if func_name == 'hstack':
          output = xp.hstack(inputs)
      elif func_name == 'vstack':
          output = xp.vstack(inputs)
      elif func_name == 'dstack':
          output = xp.dstack(inputs)
  
      return output
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize(*(
      chainer.testing.product({'shapes': [
          (1,),
          (1, 1),
          (1, 1, 1),
          (2, 2, 2, 2),
      ],
          'dtype': chainerx.testing.dtypes.all_dtypes
      })
  ))
  class TestAtLeast2d(op_utils.NumpyOpTest):
  
      dtypes = None
  
      def setup(self):
          if numpy.dtype(self.dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
  
      def generate_inputs(self):
          a = numpy.random.uniform(0, 1, self.shapes).astype(self.dtype)
          return a,
  
      def forward_xp(self, input, xp):
          x, = input
          y = xp.atleast_2d(x)
          return y,
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize(*(
      chainer.testing.product({'shapes': [
          (1,),
          (1, 1),
          (1, 1, 1),
          (2, 2, 2, 2),
      ],
          'dtype': chainerx.testing.dtypes.all_dtypes
      })
  ))
  class TestAtLeast3d(op_utils.NumpyOpTest):
  
      dtypes = None
  
      def setup(self):
          if numpy.dtype(self.dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
  
      def generate_inputs(self):
          a = numpy.random.uniform(0, 1, self.shapes).astype(self.dtype)
          return a,
  
      def forward_xp(self, input, xp):
          x, = input
          y = xp.atleast_3d(x)
          return y,
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize(*(
      # sequence args
      chainer.testing.product({'arr_shape': [
          (1, 2, 3)
      ],
          'src': list(itertools.permutations(range(3), 3)),
          'dst': list(itertools.permutations(range(3), 3)),
          'dtype': chainerx.testing.dtypes.all_dtypes
      }) + chainer.testing.product({'arr_shape': [
          (1, 2, 3)
      ],
          'src': list(itertools.permutations(range(3), 2)),
          'dst': list(itertools.permutations(range(3), 2)),
          'dtype': chainerx.testing.dtypes.all_dtypes
      })
      + chainer.testing.product({'arr_shape': [
          (1, 2, 3)
      ],
          'src': list(itertools.permutations(range(3), 1)),
          'dst': list(itertools.permutations(range(3), 1)),
          'dtype': chainerx.testing.dtypes.all_dtypes
      })
      # negative axis
      + chainer.testing.product({'arr_shape': [
          (1, 2, 3)
      ],
          'src': list(itertools.permutations(range(0, -3, -1), 3)),
          'dst': list(itertools.permutations(range(0, -3, -1), 3)),
          'dtype': chainerx.testing.dtypes.all_dtypes
      }) + chainer.testing.product({'arr_shape': [
          (1, 2, 3)
      ],
          'src': list(itertools.permutations(range(0, -3, -1), 2)),
          'dst': list(itertools.permutations(range(0, -3, -1), 2)),
          'dtype': chainerx.testing.dtypes.all_dtypes
      })
      + chainer.testing.product({'arr_shape': [
          (1, 2, 3)
      ],
          'src': list(itertools.permutations(range(0, -3, -1), 1)),
          'dst': list(itertools.permutations(range(0, -3, -1), 1)),
          'dtype': chainerx.testing.dtypes.all_dtypes
      })
      # empty
      + chainer.testing.product({'arr_shape': [
          (1, 2, 3)
      ],
          'src': [()],
          'dst': [()],
          'dtype': chainerx.testing.dtypes.all_dtypes
      })
      # integer args
      + chainer.testing.product({'arr_shape': [
          (1, 2, 3)
      ],
          'src': list(range(3)),
          'dst': list(range(3)),
          'dtype': chainerx.testing.dtypes.all_dtypes
      })
  ))
  class TestMoveaxis(op_utils.NumpyOpTest):
  
      dtypes = None
  
      def setup(self):
          if numpy.dtype(self.dtype).kind != 'f':
              self.skip_backward_test = True
              self.skip_double_backward_test = True
  
      def generate_inputs(self):
          a = numpy.random.uniform(0, 1, self.arr_shape).astype(self.dtype)
          return a,
  
      def forward_xp(self, input, xp):
          x, = input
          y = xp.moveaxis(x, self.src, self.dst)
          return y,
  
  
  @chainerx.testing.numpy_chainerx_array_equal(
      accept_error=(
          chainerx.DimensionError, ValueError))
  @pytest.mark.parametrize('shape,source,dst', [
      # differing src, dst
      ((1, 2, 3), (1, 2), (2,)),
      # out of bounds
      ((1, 2, 3), (1, 4), (2, 0)),
      ((1, 2, 3), (1, 2), (-4, 0)),
      # duplicate
      ((1, 2, 3), (1, 1), (2, 0)),
      ((1, 2, 3), (1, 2), (2, 2)),
  ])
  def test_moveaxis_invalid(xp, shape, source, dst):
      a = array_utils.uniform(shape, 'float')
      a = xp.array(a)
      return xp.moveaxis(a, source, dst)
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize(*(
      chainer.testing.product({'dst_shape,src_shape,where_shape': [
          # Same Shapes
          ((2, 3), (2, 3), (2, 3)),
          # Broadcast Shapes
          ((2, 3), (1, 3), (1, 3)),
          ((2, 3), (2, 1), (1, 3)),
          ((2, 3), (2, 3), (1, 3)),
          ((4, 5), (4, 1), (1, 5)),
          ((1, 4, 5), (1, 4, 1), (1, 1, 5)),
          ((2, 3), (2, 3), (2, 3)),
          # Omit where
          ((2, 3), (2, 3), None),
      ],
          'in_dtypes,out_dtype': dtype_utils.result_numeric_dtypes_two_arrays,
          'casting': ['no'],
      })
  ))
  class TestCopyTo(op_utils.NumpyOpTest):
  
      skip_backward_test = True
      skip_double_backward_test = True
      check_numpy_strides_compliance = False
  
      forward_accept_errors = (TypeError, chainerx.DtypeError)
  
      def generate_inputs(self):
          dst_dtype, src_dtype = self.in_dtypes
  
          dst = array_utils.uniform(self.dst_shape, dst_dtype)
          src = array_utils.uniform(self.src_shape, src_dtype)
          where = array_utils.uniform(
              self.where_shape if self.where_shape is not None else (1,),
              'float32', 0, 1) > 0.5
  
          return dst, src, where
  
      def forward_xp(self, inputs, xp):
          dst, src, where = inputs
  
          if xp is chainerx:
              dst = dst.as_grad_stopped().copy()
              src = src.as_grad_stopped()
              where = where.as_grad_stopped()
          else:
              dst = dst.copy()
  
          kwargs = {}
          if self.casting is not None:
              kwargs['casting'] = self.casting
          if self.where_shape is not None:
              kwargs['where'] = where
  
          xp.copyto(dst, src, **kwargs)
  
          return dst,
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize(*(
      chainer.testing.product({
          'where': [True, False, 2, 1.2],
      })
  ))
  class TestCopyToScalarWhere(op_utils.NumpyOpTest):
  
      skip_backward_test = True
      skip_double_backward_test = True
      check_numpy_strides_compliance = False
  
      def generate_inputs(self):
          dst = array_utils.uniform((2, 3), 'float32')
          src = array_utils.uniform((2, 3), 'float32')
  
          return dst, src
  
      def forward_xp(self, inputs, xp):
          dst, src = inputs
  
          if xp is chainerx:
              dst = dst.as_grad_stopped().copy()
              src = src.as_grad_stopped()
          else:
              dst = dst.copy()
  
          xp.copyto(dst, src, casting='no', where=self.where)
  
          return dst,
  
  
  def test_copyto_invalid_casting():
      a = array_utils.create_dummy_ndarray(chainerx, (2, 3), 'float32')
      b = array_utils.create_dummy_ndarray(chainerx, (3,), 'float32')
      with pytest.raises(ValueError):
          chainerx.copyto(a, b, casting='some_invalid_casting')
  
  
  @op_utils.op_test(['native:0', 'cuda:0'])
  @chainer.testing.parameterize_pytest('a_shape,b_shape', _reshape_shape)
  @chainer.testing.parameterize_pytest('is_module', [True, False])
  class TestRavel(op_utils.NumpyOpTest):
  
      forward_accept_errors = (TypeError, chainerx.ChainerxError)
      check_numpy_strides_compliance = False
  
      def generate_inputs(self):
          a = array_utils.shaped_arange(self.a_shape, 'float64')
          return a,
  
      def forward_xp(self, inputs, xp):
          a, = inputs
          if self.is_module:
              b = xp.ravel(a)
          else:
              b = a.ravel()
          return b,
  