// // Copyright © 2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #include "ReverseV2Impl.hpp" #include #include #include namespace armnn { // Get multi-dimensional index for input tensor std::vector ReverseGetMultIdx(const unsigned int idx, unsigned int inputRank, std::vector& elementNumInner) { std::vector indexList(inputRank); unsigned int mIdx = idx; for (unsigned int iDim = 0; iDim < inputRank; ++iDim) { indexList[iDim] = static_cast(mIdx / elementNumInner[iDim]); mIdx %= elementNumInner[iDim]; } return indexList; } // Get flattened index for output encoder unsigned int ReverseGetFlatIdx(const std::vector& idxList, unsigned int inputRank, std::vector& elementNumInner) { unsigned int idx = 0; for (unsigned int iDim = 0; iDim < inputRank; ++iDim) { idx += idxList[iDim] * elementNumInner[iDim]; } return idx; } // Relocate the coordinate to the reversed tensor unsigned int ReverseRelocateIdx(unsigned int idx, unsigned int inputRank, std::vector& axisFlag, std::vector& dimSize, std::vector& elementNumInner) { // Get the multidimensional index list for input auto inputIdxList = ReverseGetMultIdx(idx, inputRank, elementNumInner); std::vector outputIdxList(inputRank); // Relocate the input index to the output one for (unsigned int iDim = 0; iDim < inputRank; ++iDim) { if (axisFlag[iDim]) { outputIdxList[iDim] = dimSize[iDim] - inputIdxList[iDim] - 1; } else { outputIdxList[iDim] = inputIdxList[iDim]; } } // Get the 1-dimensional flattened index for output unsigned int outputIdx = ReverseGetFlatIdx(outputIdxList, inputRank, elementNumInner); return outputIdx; } void ReverseV2(const TensorInfo& inputInfo, const TensorInfo& axisInfo, Decoder& inputDecoder, Decoder& axisDecoder, Encoder& outputEncoder) { unsigned int axesRank = static_cast(axisInfo.GetNumElements()); // Empty axis and empty tensor case: copy input to output if ((axesRank == 0) || inputInfo.GetNumElements() == 0) { for (unsigned idx = 0; idx < inputInfo.GetNumElements(); idx++) { float inputValue = inputDecoder.Get(); inputDecoder += 1; outputEncoder.Set(inputValue); outputEncoder += 1; } return; } unsigned int inputRank = static_cast(inputInfo.GetNumDimensions()); std::vector axisFlag(inputRank, false); std::vector dimSize(inputRank, 0); std::vector axis(axesRank, 0); // Decode the axis information for (unsigned int i=0; i < axesRank; i++) { axis[i] = axisDecoder.Get(); axisDecoder += 1; } // Make sure the axes are positive for (int32_t axisElement: axis) { axisElement = axisElement < 0 ? axisElement + static_cast(inputRank) : axisElement; axisFlag[static_cast(axisElement)] = true; } const TensorShape &inputShape = inputInfo.GetShape(); unsigned int elementNum = inputInfo.GetNumElements(); unsigned int baseDimSize = 1; std::vector elementNumInner; // Get the number of element within the specific dimension for (unsigned int iDim = 0; iDim < inputRank; ++iDim) { dimSize[iDim] = inputShape[iDim]; baseDimSize *= dimSize[iDim]; elementNumInner.push_back(static_cast(elementNum / baseDimSize)); } // Iterate through all elements for (unsigned int idx = 0; idx < elementNum; ++idx) { float inputValue = inputDecoder.Get(); inputDecoder += 1; auto outputIdx = ReverseRelocateIdx(idx, inputRank, axisFlag, dimSize, elementNumInner); outputEncoder[outputIdx]; outputEncoder.Set(inputValue); } } } // namespace armnn