'Function to perform a fast copy transpose/dimshuffle operation.
Works just like numpy.transpose, but requires an output tensor argument.'

def copy_transpose(self, a, out, axes=None, repeat=1):

    assert (a.dtype == out.dtype)
    assert (a.size == out.size)
    assert (a.gpudata != out.gpudata)
    if (axes is None):
        axes = tuple(range((len(a.shape) - 1), (-1), (-1)))
    elif (type(axes) is not tuple):
        axes = tuple(axes)
    assert all(((out.shape[i] == a.shape[x]) for (i, x) in enumerate(axes)))
    from neon.backends.convolution import _get_copy_transpose_kernel
    kernel = _get_copy_transpose_kernel(a.dtype.str, a.shape, axes)
    args = ((kernel.args + a.strides) + out.strides)
    if (repeat > 1):
        for r in range(max((repeat // 10), 1)):
            kernel.prepared_async_call(kernel.grid, kernel.block, self.stream, out.gpudata, a.gpudata, *args)
    if ((self.bench > 1) or (repeat > 1)):
        (start, end) = _get_events()
        start.record(self.stream)
    for r in range(repeat):
        kernel.prepared_async_call(kernel.grid, kernel.block, self.stream, out.gpudata, a.gpudata, *args)
    if ((self.bench > 1) or (repeat > 1)):
        end.record(self.stream)
        end.synchronize()
        msecs = (end.time_since(start) / repeat)
        bandwidth = ((a.nbytes * 2) / ((msecs * 1024) * 1024))
        neon_logger.display(('%7.3f    msecs    %4.0f    GBps    copy_transpose' % (msecs, bandwidth)))
