blob: 148c51de2e7bb76721b94dc1014402147de90909 [file] [log] [blame]
//
// Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
#include "Tile.hpp"
#include "Encoders.hpp"
#include <numeric>
#include <armnn/backends/WorkloadData.hpp>
#include <armnn/Logging.hpp>
namespace armnn
{
// Converts a flatten index into a multi-dimensional coordinate.
std::vector<uint32_t> IndexToCoordinates(std::vector<uint32_t>& shape, uint32_t index)
{
std::vector<uint32_t> coordinates;
// Iterating through dimensions starting from the last dimension to the first
for (std::size_t i = shape.size() - 1; i < shape.size(); --i)
{
// Coordinate is found by getting the index and modulus it by the current dimension size
// shape of dimension = dimension size
coordinates.insert(coordinates.begin(), index % shape[i]);
// Pass the index to next iteration making index = index / size of the current dimension
index = index/shape[i];
}
return coordinates;
}
// Convert a multidimensional coordinate to a flattened index.
uint32_t CoordinatesToIndex(TensorShape& shape, std::vector<uint32_t>& coordinates)
{
uint32_t index = 0;
uint32_t base = 1;
uint32_t rank = shape.GetNumDimensions();
for (uint32_t i = rank; i > 0; --i)
{
index = index + coordinates[i - 1] * base;
base = base * shape[i - 1];
}
return index;
}
void Tile(const TileDescriptor& params,
const TensorInfo& inputInfo,
Decoder<float>& inputDecoder,
Encoder<float>& outputEncoder)
{
// Input and output will always have same rank
uint32_t rank = inputInfo.GetNumDimensions();
TensorShape inputShape = inputInfo.GetShape();
std::vector<uint32_t> outputShape(rank);
for (uint32_t i = 0; i < rank; ++i)
{
outputShape[i] = inputShape[i] * params.m_Multiples[i];
}
// If all values of multiples are 1, then return the input
if ( std::adjacent_find( params.m_Multiples.begin(), params.m_Multiples.end(),
std::not_equal_to<>() ) == params.m_Multiples.end() && params.m_Multiples[0] == 1)
{
for (uint32_t idx = 0; idx < inputInfo.GetNumElements(); ++idx)
{
float inputValue = inputDecoder.Get();
++inputDecoder;
outputEncoder.Set(inputValue);
++outputEncoder;
}
return;
}
std::vector<float> inputData = inputDecoder.DecodeTensor(inputInfo.GetShape());
std::vector<float> outputData;
auto outputNumElements = inputData.size() * static_cast<uint32_t>(std::accumulate(begin(params.m_Multiples),
end(params.m_Multiples),
1,
std::multiplies<>()));
outputData.reserve(outputNumElements);
for (uint32_t outputIndex = 0; outputIndex < outputNumElements; ++outputIndex)
{
std::vector<uint32_t> outputCoords = IndexToCoordinates(outputShape, outputIndex);
// Converting output coordinates to input coordinates using modulus
std::vector<uint32_t> inputCoordinates;
inputCoordinates.reserve(rank);
for (uint32_t i = 0; i < rank; ++i)
{
inputCoordinates.push_back(outputCoords[i] % inputShape[i]);
}
uint32_t inputIndex = CoordinatesToIndex(inputShape, inputCoordinates);
outputEncoder[outputIndex];
outputEncoder.Set(inputData[inputIndex]);
}
}
} // namespace armnn