xref: /aosp_15_r20/external/armnn/src/backends/reference/workloads/Concatenate.cpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "Concatenate.hpp"
7 #include "RefWorkloadUtils.hpp"
8 #include "Decoders.hpp"
9 #include "Encoders.hpp"
10 
11 namespace armnn
12 {
13 
Concatenate(const ConcatQueueDescriptor & data,std::vector<ITensorHandle * > inputs,std::vector<ITensorHandle * > outputs)14 void Concatenate(const ConcatQueueDescriptor &data,
15                  std::vector<ITensorHandle*> inputs,
16                  std::vector<ITensorHandle*> outputs)
17 {
18     const TensorInfo& outputInfo0 = GetTensorInfo(outputs[0]);
19 
20     std::unique_ptr<Encoder<float>> encoderPtr = MakeEncoder<float>(outputInfo0, outputs[0]->Map());
21     Encoder<float>& encoder = *encoderPtr;
22 
23     for (unsigned int index = 0 ; index < outputInfo0.GetNumElements(); ++index)
24     {
25         unsigned int indices[MaxNumOfTensorDimensions] = { 0 };
26 
27         unsigned int indexRemainder = index;
28         unsigned int dimensionStride = outputInfo0.GetNumElements();
29 
30         for (unsigned int i = 0; i < outputInfo0.GetNumDimensions(); i++)
31         {
32             dimensionStride /= outputInfo0.GetShape()[i];
33             indices[i] = indexRemainder / dimensionStride; // Use integer division to round down.
34             indexRemainder -= indices[i] * dimensionStride;
35         }
36 
37         for (unsigned int viewIdx = 0; viewIdx < data.m_ViewOrigins.size(); ++viewIdx)
38         {
39             ConcatQueueDescriptor::ViewOrigin const& view = data.m_ViewOrigins[viewIdx];
40 
41             //Split view extents are defined by the size of (the corresponding) input tensor.
42             const TensorInfo& inputInfo = GetTensorInfo(inputs[viewIdx]);
43             ARMNN_ASSERT(inputInfo.GetNumDimensions() == outputInfo0.GetNumDimensions());
44 
45             // Check all dimensions to see if this element is inside the given input view.
46             bool insideView = true;
47             for (unsigned int i = 0; i < inputInfo.GetNumDimensions(); i++)
48             {
49                 if (indices[i] < view.m_Origin[i])
50                 {
51                     insideView = false;
52                 }
53                 if (indices[i] >= view.m_Origin[i] + inputInfo.GetShape()[i])
54                 {
55                     insideView = false;
56                 }
57             }
58 
59             if (insideView)
60             {
61                 std::unique_ptr<Decoder<float>> decoderPtr =
62                     MakeDecoder<float>(inputInfo,inputs[viewIdx]->Map());
63                 Decoder<float>& decoder = *decoderPtr;
64                 unsigned int inIndex = 0;
65                 unsigned int dimensionStride = 1;
66 
67                 for (unsigned int i = inputInfo.GetNumDimensions(); i-- > 0;)
68                 {
69                     inIndex += dimensionStride * (indices[i] - view.m_Origin[i]);
70                     dimensionStride *= inputInfo.GetShape()[i];
71                 }
72                 decoder += inIndex;
73                 encoder.Set(decoder.Get());
74 
75                 //What should we do if input views overlap on the output tensor?
76                 //We could error, take the average, or shm else...
77                 //For now just stop after finding first view (input) that matches.
78                 break;
79             }
80         }
81         ++encoder;
82     }
83 }
84 
85 } //namespace armnn
86