IVGCVSW-3263 - Add End to End tests for SpaceToDepth on Ref

Change-Id: I35d1c06b34ca160895f902255a69b87b711275b7
Signed-off-by: Keith Davis <keith.davis@arm.com>
diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt
index 7819cfe..caf2dd3 100644
--- a/src/backends/backendsCommon/test/CMakeLists.txt
+++ b/src/backends/backendsCommon/test/CMakeLists.txt
@@ -45,6 +45,7 @@
     RuntimeTestImpl.hpp
     SoftmaxTestImpl.hpp
     SpaceToDepthTestImpl.hpp
+    SpaceToDepthEndToEndTestImpl.hpp
     SplitterEndToEndTestImpl.hpp
     SplitterTestImpl.hpp
     StridedSliceTestImpl.hpp
diff --git a/src/backends/backendsCommon/test/SpaceToDepthEndToEndTestImpl.hpp b/src/backends/backendsCommon/test/SpaceToDepthEndToEndTestImpl.hpp
new file mode 100644
index 0000000..456af4c
--- /dev/null
+++ b/src/backends/backendsCommon/test/SpaceToDepthEndToEndTestImpl.hpp
@@ -0,0 +1,106 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include "ResolveType.hpp"
+#include "DataLayoutIndexed.hpp"
+#include "EndToEndTestImpl.hpp"
+
+#include "armnn/INetwork.hpp"
+
+#include "backendsCommon/test/CommonTestUtils.hpp"
+
+#include <Permute.hpp>
+#include <boost/test/unit_test.hpp>
+
+#include <vector>
+
+namespace
+{
+template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+void PermuteDataToNCHW(const std::vector<armnn::BackendId>& backends,
+                       const armnn::DataLayout& dataLayout,
+                       TensorInfo& tensorInfo,
+                       std::vector<T>& data)
+{
+    const armnn::PermutationVector NHWCToNCHW = {0, 2, 3, 1};
+
+    tensorInfo = armnnUtils::Permuted(tensorInfo, NHWCToNCHW);
+
+    std::vector<T> tmp(data.size());
+    armnnUtils::Permute(tensorInfo.GetShape(), NHWCToNCHW, data.data(), tmp.data(), sizeof(T));
+
+    data = tmp;
+}
+
+template<typename armnn::DataType DataType>
+armnn::INetworkPtr CreateSpaceToDepthNetwork(const armnn::TensorShape& inputShape,
+                                             const armnn::TensorShape& outputShape,
+                                             const armnn::DataLayout dataLayout,
+                                             unsigned int blockSize,
+                                             const float qScale = 1.0f,
+                                             const int32_t qOffset = 0)
+{
+    using namespace armnn;
+    // Builds up the structure of the network.
+    INetworkPtr net(INetwork::Create());
+
+    TensorInfo inputTensorInfo(inputShape, DataType, qScale, qOffset);
+
+    armnnUtils::DataLayoutIndexed dimensionIndices(dataLayout);
+    if (inputShape[dimensionIndices.GetHeightIndex()] % blockSize!=0
+        || inputShape[dimensionIndices.GetWidthIndex()] % blockSize!=0)
+    {
+        throw InvalidArgumentException("Input shape must be divisible by block size in all spatial dimensions");
+    }
+
+    SpaceToDepthDescriptor spaceToDepthDesc;
+    spaceToDepthDesc.m_BlockSize = blockSize;
+    spaceToDepthDesc.m_DataLayout = dataLayout;
+
+    IConnectableLayer* SpaceToDepth = net->AddSpaceToDepthLayer(spaceToDepthDesc, "SpaceToDepth");
+    IConnectableLayer* input        = net->AddInputLayer(0, "input");
+    Connect(input, SpaceToDepth, inputTensorInfo, 0, 0);
+
+    TensorInfo outputTensorInfo(outputShape, DataType, qScale, qOffset);
+    IConnectableLayer* output = net->AddOutputLayer(0, "output");
+    Connect(SpaceToDepth, output, outputTensorInfo, 0, 0);
+
+    return net;
+}
+
+void SpaceToDepthEndToEnd(const std::vector<armnn::BackendId>& backends,
+                          const armnn::DataLayout& dataLayout,
+                          TensorInfo& inputTensorInfo,
+                          TensorInfo& outputTensorInfo,
+                          std::vector<float>& inputData,
+                          std::vector<float>& expectedOutputData,
+                          const unsigned int blockSize)
+{
+    using namespace armnn;
+
+    if (dataLayout == armnn::DataLayout::NCHW){
+        PermuteDataToNCHW<armnn::DataType::Float32>(backends, dataLayout, inputTensorInfo, inputData);
+        PermuteDataToNCHW<armnn::DataType::Float32>(backends, dataLayout, outputTensorInfo, expectedOutputData);
+    }
+
+    // Builds up the structure of the network
+    INetworkPtr net = CreateSpaceToDepthNetwork<armnn::DataType::Float32>(inputTensorInfo.GetShape(),
+                                                           outputTensorInfo.GetShape(),
+                                                           dataLayout,
+                                                           blockSize);
+
+    BOOST_TEST_CHECKPOINT("Create a network");
+
+    std::map<int, std::vector<float>> inputTensorData = { { 0, inputData } };
+    std::map<int, std::vector<float>> expectedOutputTensorData = { { 0, expectedOutputData } };
+
+    EndToEndLayerTestImpl<armnn::DataType::Float32, armnn::DataType::Float32>(move(net),
+                                                                              inputTensorData,
+                                                               expectedOutputTensorData,
+                                                               backends);
+}
+
+} // anonymous namespace
diff --git a/src/backends/reference/test/RefEndToEndTests.cpp b/src/backends/reference/test/RefEndToEndTests.cpp
index 885773d..be73116 100644
--- a/src/backends/reference/test/RefEndToEndTests.cpp
+++ b/src/backends/reference/test/RefEndToEndTests.cpp
@@ -10,6 +10,7 @@
 #include <backendsCommon/test/GatherEndToEndTestImpl.hpp>
 #include <backendsCommon/test/ConcatTestImpl.hpp>
 #include <backendsCommon/test/ArithmeticTestImpl.hpp>
+#include <backendsCommon/test/SpaceToDepthEndToEndTestImpl.hpp>
 #include <backendsCommon/test/SplitterEndToEndTestImpl.hpp>
 
 #include <boost/test/unit_test.hpp>
@@ -641,6 +642,123 @@
                                                                           1.0f, 1, 0.01f, 0, 0.5f, 0);
 }
 
+BOOST_AUTO_TEST_CASE(RefSpaceToDepthNHWCEndToEndTest1)
+{
+    const unsigned int blockSize = 2;
+
+    armnn::TensorShape inputShape{1, 2, 2, 1};
+    armnn::TensorInfo inputTensorInfo(inputShape, armnn::DataType::Float32);
+
+    armnn::TensorShape outputShape{1, 1, 1, 4};
+    armnn::TensorInfo outputTensorInfo(outputShape, armnn::DataType::Float32);
+
+    std::vector<float> inputData = std::vector<float>(
+    {
+        1.0f, 2.0f, 3.0f, 4.0f
+    });
+
+    std::vector<float> expectedOutputData = std::vector<float>(
+    {
+        1.0f, 2.0f, 3.0f, 4.0f
+    });
+
+    SpaceToDepthEndToEnd(defaultBackends,
+                        armnn::DataLayout::NHWC,
+                        inputTensorInfo,
+                        outputTensorInfo,
+                        inputData,
+                        expectedOutputData,
+                        blockSize);
+}
+
+BOOST_AUTO_TEST_CASE(RefSpaceToDepthNCHWEndToEndTest1)
+{
+    const unsigned int blockSize = 2;
+
+    armnn::TensorShape inputShape{1, 2, 2, 1};
+    armnn::TensorInfo inputTensorInfo(inputShape, armnn::DataType::Float32);
+
+    armnn::TensorShape outputShape{1, 1, 1, 4};
+    armnn::TensorInfo outputTensorInfo(outputShape, armnn::DataType::Float32);
+
+    std::vector<float> inputData = std::vector<float>(
+    {
+        1.0f, 2.0f, 3.0f, 4.0f
+    });
+
+    std::vector<float> expectedOutputData = std::vector<float>(
+    {
+        1.0f, 2.0f, 3.0f, 4.0f
+    });
+
+    SpaceToDepthEndToEnd(defaultBackends,
+                        armnn::DataLayout::NCHW,
+                        inputTensorInfo,
+                        outputTensorInfo,
+                        inputData,
+                        expectedOutputData,
+                        blockSize);
+}
+
+BOOST_AUTO_TEST_CASE(RefSpaceToDepthNHWCEndToEndTest2)
+{
+    const unsigned int blockSize = 2;
+
+    armnn::TensorShape inputShape{1, 2, 2, 2};
+    armnn::TensorShape outputShape{1, 1, 1, 8};
+
+    armnn::TensorInfo outputTensorInfo(outputShape, armnn::DataType::Float32);
+    armnn::TensorInfo inputTensorInfo(inputShape, armnn::DataType::Float32);
+
+    std::vector<float> inputData = std::vector<float>(
+    {
+        1.4f, 2.3f, 3.2f, 4.1f, 5.4f, 6.3f, 7.2f, 8.1f
+    });
+
+    std::vector<float> expectedOutputData = std::vector<float>(
+    {
+        1.4f, 2.3f, 3.2f, 4.1f, 5.4f, 6.3f, 7.2f, 8.1f
+    });
+
+    SpaceToDepthEndToEnd(defaultBackends,
+                        armnn::DataLayout::NHWC,
+                        inputTensorInfo,
+                        outputTensorInfo,
+                        inputData,
+                        expectedOutputData,
+                        blockSize);
+}
+
+BOOST_AUTO_TEST_CASE(RefSpaceToDepthNCHWEndToEndTest2)
+{
+    const unsigned int blockSize = 2;
+
+    armnn::TensorShape inputShape{1, 2, 2, 2};
+    armnn::TensorShape outputShape{1, 1, 1, 8};
+
+    armnn::TensorInfo inputTensorInfo(inputShape, armnn::DataType::Float32);
+    armnn::TensorInfo outputTensorInfo(outputShape, armnn::DataType::Float32);
+
+
+    std::vector<float> inputData = std::vector<float>(
+    {
+        1.4f, 2.3f, 3.2f, 4.1f, 5.4f, 6.3f, 7.2f, 8.1f
+    });
+
+    std::vector<float> expectedOutputData = std::vector<float>(
+    {
+        1.4f, 2.3f, 3.2f, 4.1f, 5.4f, 6.3f, 7.2f, 8.1f
+    });
+
+    SpaceToDepthEndToEnd(defaultBackends,
+                        armnn::DataLayout::NCHW,
+                        inputTensorInfo,
+                        outputTensorInfo,
+                        inputData,
+                        expectedOutputData,
+                        blockSize);
+}
+
 BOOST_AUTO_TEST_CASE(RefSplitter1dEndToEndTest)
 {
     Splitter1dEndToEnd<armnn::DataType::Float32>(defaultBackends);