# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # ruff: noqa: RUF005 """TVM operator pixel shuffle compute.""" import tvm def pixel_shuffle(data, upscale_factor, name="PixelShuffle"): """PixelShuffle operator that rearranges elements in a tensor of shape [..., C * r * r, H, W] to [..., C, H * r, W * r]. Parameters ---------- data : tvm.te.Tensor N-D input tensor with at least 3 dimensions. Channel must be at index -3. upscale_factor : int The upscale factor (r). name : str Name of the output tensor. Returns ------- output : tvm.te.Tensor Pixel shuffled tensor with shape [..., C, H*r, W*r] """ assert isinstance(upscale_factor, int) and upscale_factor > 0 ndim = len(data.shape) assert ndim >= 3, "Input must be at least 3D" upscale_factor_const = tvm.tirx.const(upscale_factor, "int32") c_in, h_in, w_in = data.shape[-3], data.shape[-2], data.shape[-1] c_out = tvm.tirx.floordiv(c_in, upscale_factor_const * upscale_factor_const) h_out = h_in * upscale_factor_const w_out = w_in * upscale_factor_const out_shape = list(data.shape[:-3]) + [c_out, h_out, w_out] def _compute(*indices): batch_indices = indices[:-3] c_out_idx, h_out_idx, w_out_idx = indices[-3], indices[-2], indices[-1] h_idx = tvm.tirx.floordiv(h_out_idx, upscale_factor_const) h_offset = h_out_idx % upscale_factor_const w_idx = tvm.tirx.floordiv(w_out_idx, upscale_factor_const) w_offset = w_out_idx % upscale_factor_const c_in_idx = ( (c_out_idx * upscale_factor_const * upscale_factor_const) + (h_offset * upscale_factor_const) + w_offset ) index_tuple = batch_indices + (c_in_idx, h_idx, w_idx) return data[index_tuple] return tvm.te.compute(out_shape, _compute, name=name)